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 Change-Id: If55015165d25ecc4b530f674b481c8c7ef760a23
This commit is contained in:
		| @@ -27,6 +27,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
|  | #include <elf.h> | ||||||
| #include <inttypes.h> | #include <inttypes.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| @@ -35,14 +36,22 @@ | |||||||
| #include "debug_mapinfo.h" | #include "debug_mapinfo.h" | ||||||
| #include "malloc_debug_disable.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: | // Format of /proc/<PID>/maps: | ||||||
| //   6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so | //   6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so | ||||||
| static mapinfo_t* parse_maps_line(char* line) { | static mapinfo_t* parse_maps_line(char* line) { | ||||||
|   uintptr_t start; |   uintptr_t start; | ||||||
|   uintptr_t end; |   uintptr_t end; | ||||||
|  |   uintptr_t offset; | ||||||
|  |   char permissions[4]; | ||||||
|   int name_pos; |   int name_pos; | ||||||
|   if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start, |   if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start, | ||||||
|              &end, &name_pos) < 2) { |              &end, permissions, &offset, &name_pos) < 2) { | ||||||
|     return NULL; |     return NULL; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -59,6 +68,14 @@ static mapinfo_t* parse_maps_line(char* line) { | |||||||
|   if (mi) { |   if (mi) { | ||||||
|     mi->start = start; |     mi->start = start; | ||||||
|     mi->end = end; |     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); |     memcpy(mi->name, name, name_len); | ||||||
|     mi->name[name_len] = '\0'; |     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. | // 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) { | __LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, uintptr_t pc, uintptr_t* rel_pc) { | ||||||
|   for (; mi != NULL; mi = mi->next) { |   for (; mi != NULL; mi = mi->next) { | ||||||
|     if ((pc >= mi->start) && (pc < mi->end)) { |     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; |       return mi; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -35,6 +35,9 @@ struct mapinfo_t { | |||||||
|   struct mapinfo_t* next; |   struct mapinfo_t* next; | ||||||
|   uintptr_t start; |   uintptr_t start; | ||||||
|   uintptr_t end; |   uintptr_t end; | ||||||
|  |   uintptr_t offset; | ||||||
|  |   uintptr_t load_base; | ||||||
|  |   bool load_base_read; | ||||||
|   char name[]; |   char name[]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Christopher Ferris
					Christopher Ferris