diff options
author | Christopher Ferris <cferris@google.com> | 2015-07-16 14:49:17 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2015-07-21 10:32:28 -0700 |
commit | aa55e7ad249e49025d0507f513a6c45f8491a4e5 (patch) | |
tree | 527bb4eec55e3ecd4520b480cab97b4c7f462151 | |
parent | 43d35c356e2fbe0b022cef52445e93053c4ddbfd (diff) | |
download | bionic-aa55e7ad249e49025d0507f513a6c45f8491a4e5.zip bionic-aa55e7ad249e49025d0507f513a6c45f8491a4e5.tar.gz bionic-aa55e7ad249e49025d0507f513a6c45f8491a4e5.tar.bz2 |
Add support for non-zero vaddr in maps.
If a map has a non-zero vaddr then it needs to be added to the
computed relative offset.
Bug: 22532054
(cherry picked from commit 70b6e1daffd58ebce006d4b504cd0fb9672b6d07)
Change-Id: I1e98741d6ff3b5bbb7fc5f88cc85b27ace75ee2e
-rw-r--r-- | libc/bionic/debug_mapinfo.cpp | 70 | ||||
-rw-r--r-- | libc/bionic/debug_mapinfo.h | 3 |
2 files changed, 70 insertions, 3 deletions
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp index 698ab6b..de72cb2 100644 --- a/libc/bionic/debug_mapinfo.cpp +++ b/libc/bionic/debug_mapinfo.cpp @@ -27,6 +27,7 @@ */ #include <ctype.h> +#include <elf.h> #include <inttypes.h> #include <stdio.h> #include <string.h> @@ -35,14 +36,22 @@ #include "debug_mapinfo.h" #include "malloc_debug_disable.h" +#if defined(__LP64__) +#define Elf_W(x) Elf64_##x +#else +#define Elf_W(x) Elf32_##x +#endif + // Format of /proc/<PID>/maps: // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so static mapinfo_t* parse_maps_line(char* line) { uintptr_t start; uintptr_t end; + uintptr_t offset; + char permissions[4]; int name_pos; - if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start, - &end, &name_pos) < 2) { + if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start, + &end, permissions, &offset, &name_pos) < 2) { return NULL; } @@ -59,6 +68,14 @@ static mapinfo_t* parse_maps_line(char* line) { if (mi) { mi->start = start; mi->end = end; + mi->offset = offset; + if (permissions[0] != 'r') { + // Any unreadable map will just get a zero load base. + mi->load_base = 0; + mi->load_base_read = true; + } else { + mi->load_base_read = false; + } memcpy(mi->name, name, name_len); mi->name[name_len] = '\0'; } @@ -95,11 +112,58 @@ __LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) { } } +template<typename T> +static inline bool get_val(mapinfo_t* mi, uintptr_t addr, T* store) { + if (addr < mi->start || addr + sizeof(T) > mi->end) { + return false; + } + // Make sure the address is aligned properly. + if (addr & (sizeof(T)-1)) { + return false; + } + *store = *reinterpret_cast<T*>(addr); + return true; +} + +__LIBC_HIDDEN__ void mapinfo_read_loadbase(mapinfo_t* mi) { + mi->load_base = 0; + mi->load_base_read = true; + uintptr_t addr = mi->start; + Elf_W(Ehdr) ehdr; + if (!get_val<Elf_W(Half)>(mi, addr + offsetof(Elf_W(Ehdr), e_phnum), &ehdr.e_phnum)) { + return; + } + if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Ehdr), e_phoff), &ehdr.e_phoff)) { + return; + } + addr += ehdr.e_phoff; + for (size_t i = 0; i < ehdr.e_phnum; i++) { + Elf_W(Phdr) phdr; + if (!get_val<Elf_W(Word)>(mi, addr + offsetof(Elf_W(Phdr), p_type), &phdr.p_type)) { + return; + } + if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Phdr), p_offset), &phdr.p_offset)) { + return; + } + if (phdr.p_type == PT_LOAD && phdr.p_offset == mi->offset) { + if (!get_val<Elf_W(Addr)>(mi, addr + offsetof(Elf_W(Phdr), p_vaddr), &phdr.p_vaddr)) { + return; + } + mi->load_base = phdr.p_vaddr; + return; + } + addr += sizeof(phdr); + } +} + // Find the containing map info for the PC. __LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, uintptr_t pc, uintptr_t* rel_pc) { for (; mi != NULL; mi = mi->next) { if ((pc >= mi->start) && (pc < mi->end)) { - *rel_pc = pc - mi->start; + if (!mi->load_base_read) { + mapinfo_read_loadbase(mi); + } + *rel_pc = pc - mi->start + mi->load_base; return mi; } } diff --git a/libc/bionic/debug_mapinfo.h b/libc/bionic/debug_mapinfo.h index 926b377..af7d05d 100644 --- a/libc/bionic/debug_mapinfo.h +++ b/libc/bionic/debug_mapinfo.h @@ -35,6 +35,9 @@ struct mapinfo_t { struct mapinfo_t* next; uintptr_t start; uintptr_t end; + uintptr_t offset; + uintptr_t load_base; + bool load_base_read; char name[]; }; |