1 /* libunwind - a platform-independent unwind library 2 Copyright (C) 2003-2005 Hewlett-Packard Co 3 Copyright (C) 2007 David Mosberger-Tang 4 Contributed by David Mosberger-Tang <dmosberger (at) gmail.com> 5 6 This file is part of libunwind. 7 8 Permission is hereby granted, free of charge, to any person obtaining 9 a copy of this software and associated documentation files (the 10 "Software"), to deal in the Software without restriction, including 11 without limitation the rights to use, copy, modify, merge, publish, 12 distribute, sublicense, and/or sell copies of the Software, and to 13 permit persons to whom the Software is furnished to do so, subject to 14 the following conditions: 15 16 The above copyright notice and this permission notice shall be 17 included in all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 26 27 #include "libunwind_i.h" 28 29 #include <stdio.h> 30 #include <sys/param.h> 31 32 #if HAVE_LZMA 33 #include <7zCrc.h> 34 #include <Xz.h> 35 #include <XzCrc64.h> 36 #endif /* HAVE_LZMA */ 37 38 // -------------------------------------------------------------------------- 39 // Functions to read elf data from memory. 40 // -------------------------------------------------------------------------- 41 extern size_t elf_w (memory_read) ( 42 struct elf_image* ei, unw_word_t addr, uint8_t* buffer, size_t bytes, bool string_read) { 43 uintptr_t end = ei->u.memory.end; 44 unw_accessors_t* a = unw_get_accessors (ei->u.memory.as); 45 if (end - addr < bytes) { 46 bytes = end - addr; 47 } 48 size_t bytes_read = 0; 49 unw_word_t data_word; 50 size_t align_bytes = addr & (sizeof(unw_word_t) - 1); 51 if (align_bytes != 0) { 52 if ((*a->access_mem) (ei->u.memory.as, addr & ~(sizeof(unw_word_t) - 1), &data_word, 53 0, ei->u.memory.as_arg) != 0) { 54 return 0; 55 } 56 size_t copy_bytes = MIN(sizeof(unw_word_t) - align_bytes, bytes); 57 memcpy (buffer, (uint8_t*) (&data_word) + align_bytes, copy_bytes); 58 if (string_read) { 59 // Check for nul terminator. 60 uint8_t* nul_terminator = memchr (buffer, '\0', copy_bytes); 61 if (nul_terminator != NULL) { 62 return nul_terminator - buffer; 63 } 64 } 65 66 addr += copy_bytes; 67 bytes_read += copy_bytes; 68 bytes -= copy_bytes; 69 buffer += copy_bytes; 70 } 71 72 size_t num_words = bytes / sizeof(unw_word_t); 73 size_t i; 74 for (i = 0; i < num_words; i++) { 75 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) { 76 return bytes_read; 77 } 78 79 memcpy (buffer, &data_word, sizeof(unw_word_t)); 80 if (string_read) { 81 // Check for nul terminator. 82 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t)); 83 if (nul_terminator != NULL) { 84 return nul_terminator - buffer + bytes_read; 85 } 86 } 87 88 addr += sizeof(unw_word_t); 89 bytes_read += sizeof(unw_word_t); 90 buffer += sizeof(unw_word_t); 91 } 92 93 size_t left_over = bytes & (sizeof(unw_word_t) - 1); 94 if (left_over) { 95 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) { 96 return bytes_read; 97 } 98 99 memcpy (buffer, &data_word, left_over); 100 if (string_read) { 101 // Check for nul terminator. 102 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t)); 103 if (nul_terminator != NULL) { 104 return nul_terminator - buffer + bytes_read; 105 } 106 } 107 108 bytes_read += left_over; 109 } 110 return bytes_read; 111 } 112 113 static bool elf_w (section_table_offset) (struct elf_image* ei, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) { 114 GET_EHDR_FIELD(ei, ehdr, e_shoff, true); 115 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); 116 GET_EHDR_FIELD(ei, ehdr, e_shnum, true); 117 118 uintptr_t size = ei->u.memory.end - ei->u.memory.start; 119 if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) { 120 Debug (1, "section table outside of image? (%lu > %lu)\n", 121 (unsigned long) (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize), 122 (unsigned long) size); 123 return false; 124 } 125 126 *offset = ehdr->e_shoff; 127 return true; 128 } 129 130 static bool elf_w (string_table_offset) ( 131 struct elf_image* ei, int section, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) { 132 GET_EHDR_FIELD(ei, ehdr, e_shoff, true); 133 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); 134 unw_word_t str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize); 135 uintptr_t size = ei->u.memory.end - ei->u.memory.start; 136 if (str_soff + ehdr->e_shentsize > size) { 137 Debug (1, "string shdr table outside of image? (%lu > %lu)\n", 138 (unsigned long) (str_soff + ehdr->e_shentsize), 139 (unsigned long) size); 140 return false; 141 } 142 143 Elf_W(Shdr) shdr; 144 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_offset); 145 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_size); 146 if (shdr.sh_offset + shdr.sh_size > size) { 147 Debug (1, "string table outside of image? (%lu > %lu)\n", 148 (unsigned long) (shdr.sh_offset + shdr.sh_size), 149 (unsigned long) size); 150 return false; 151 } 152 153 Debug (16, "strtab=0x%lx\n", (long) shdr.sh_offset); 154 *offset = shdr.sh_offset; 155 return true; 156 } 157 158 static bool elf_w (lookup_symbol_memory) ( 159 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset, 160 char* buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) { 161 Elf_W(Off) shdr_offset; 162 if (!elf_w (section_table_offset) (ei, ehdr, &shdr_offset)) { 163 return false; 164 } 165 166 GET_EHDR_FIELD(ei, ehdr, e_shnum, true); 167 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); 168 int i; 169 for (i = 0; i < ehdr->e_shnum; ++i) { 170 Elf_W(Shdr) shdr; 171 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_type); 172 switch (shdr.sh_type) { 173 case SHT_SYMTAB: 174 case SHT_DYNSYM: 175 { 176 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_link); 177 178 Elf_W(Off) strtab_offset; 179 if (!elf_w (string_table_offset) (ei, shdr.sh_link, ehdr, &strtab_offset)) { 180 continue; 181 } 182 183 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_offset); 184 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_size); 185 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_entsize); 186 187 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr.sh_offset, shdr.sh_type); 188 189 unw_word_t sym_offset; 190 unw_word_t symtab_end = shdr.sh_offset + shdr.sh_size; 191 for (sym_offset = shdr.sh_offset; 192 sym_offset < symtab_end; 193 sym_offset += shdr.sh_entsize) { 194 Elf_W(Sym) sym; 195 GET_SYM_FIELD(ei, sym_offset, &sym, st_info); 196 GET_SYM_FIELD(ei, sym_offset, &sym, st_shndx); 197 198 if (ELF_W (ST_TYPE) (sym.st_info) == STT_FUNC && sym.st_shndx != SHN_UNDEF) { 199 GET_SYM_FIELD(ei, sym_offset, &sym, st_value); 200 Elf_W(Addr) val; 201 if (tdep_get_func_addr (as, sym.st_value, &val) < 0) { 202 continue; 203 } 204 if (sym.st_shndx != SHN_ABS) { 205 val += load_offset; 206 } 207 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym.st_info); 208 209 GET_SYM_FIELD(ei, sym_offset, &sym, st_size); 210 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym.st_size) { 211 GET_SYM_FIELD(ei, sym_offset, &sym, st_name); 212 uintptr_t size = ei->u.memory.end - ei->u.memory.start; 213 Elf_W(Off) strname_offset = strtab_offset + sym.st_name; 214 if (strname_offset > size || strname_offset < strtab_offset) { 215 // Malformed elf symbol table. 216 break; 217 } 218 219 size_t bytes_read = elf_w (memory_read) ( 220 ei, ei->u.memory.start + strname_offset, 221 (uint8_t*) buf, buf_len, true); 222 if (bytes_read == 0) { 223 // Empty name, so keep checking the other symbol tables 224 // for a possible match. 225 break; 226 } 227 // Ensure the string is nul terminated, it is assumed that 228 // sizeof(buf) >= buf_len + 1. 229 buf[buf_len] = '\0'; 230 231 if (offp != NULL) { 232 *offp = ip - val; 233 } 234 return true; 235 } 236 } 237 } 238 break; 239 } 240 241 default: 242 break; 243 } 244 shdr_offset += ehdr->e_shentsize; 245 } 246 return false; 247 } 248 249 static bool elf_w (get_load_offset_memory) ( 250 struct elf_image* ei, unsigned long segbase, unsigned long mapoff, 251 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) { 252 GET_EHDR_FIELD(ei, ehdr, e_phoff, true); 253 GET_EHDR_FIELD(ei, ehdr, e_phnum, true); 254 255 unw_word_t offset = ehdr->e_phoff; 256 int i; 257 for (i = 0; i < ehdr->e_phnum; ++i) { 258 Elf_W(Phdr) phdr; 259 GET_PHDR_FIELD(ei, offset, &phdr, p_type); 260 if (phdr.p_type == PT_LOAD) { 261 GET_PHDR_FIELD(ei, offset, &phdr, p_offset); 262 if (phdr.p_offset == mapoff) { 263 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr); 264 *load_offset = segbase - phdr.p_vaddr; 265 return true; 266 } 267 } 268 offset += sizeof(Elf_W(Phdr)); 269 } 270 return false; 271 } 272 273 // -------------------------------------------------------------------------- 274 // Functions to read elf data from the mapped elf image. 275 // -------------------------------------------------------------------------- 276 static Elf_W(Shdr)* elf_w (section_table) (struct elf_image* ei) { 277 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 278 Elf_W(Off) soff = ehdr->e_shoff; 279 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->u.mapped.size) { 280 Debug (1, "section table outside of image? (%lu > %lu)\n", 281 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize), 282 (unsigned long) ei->u.mapped.size); 283 return NULL; 284 } 285 286 return (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + soff); 287 } 288 289 static char* elf_w (string_table) (struct elf_image* ei, int section) { 290 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 291 Elf_W(Off) str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize); 292 if (str_soff + ehdr->e_shentsize > ei->u.mapped.size) { 293 Debug (1, "string shdr table outside of image? (%lu > %lu)\n", 294 (unsigned long) (str_soff + ehdr->e_shentsize), 295 (unsigned long) ei->u.mapped.size); 296 return NULL; 297 } 298 Elf_W(Shdr)* str_shdr = (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + str_soff); 299 300 if (str_shdr->sh_offset + str_shdr->sh_size > ei->u.mapped.size) { 301 Debug (1, "string table outside of image? (%lu > %lu)\n", 302 (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size), 303 (unsigned long) ei->u.mapped.size); 304 return NULL; 305 } 306 307 Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset); 308 return (char*) ((uintptr_t) ei->u.mapped.image + str_shdr->sh_offset); 309 } 310 311 static bool elf_w (lookup_symbol_mapped) ( 312 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset, 313 char* buf, size_t buf_len, unw_word_t* offp) { 314 315 Elf_W(Shdr)* shdr = elf_w (section_table) (ei); 316 if (!shdr) { 317 return false; 318 } 319 320 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 321 int i; 322 for (i = 0; i < ehdr->e_shnum; ++i) { 323 switch (shdr->sh_type) { 324 case SHT_SYMTAB: 325 case SHT_DYNSYM: 326 { 327 Elf_W(Sym)* symtab = (Elf_W(Sym) *) ((char *) ei->u.mapped.image + shdr->sh_offset); 328 Elf_W(Sym)* symtab_end = (Elf_W(Sym) *) ((char *) symtab + shdr->sh_size); 329 330 char* strtab = elf_w (string_table) (ei, shdr->sh_link); 331 if (!strtab) { 332 continue; 333 } 334 335 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr->sh_offset, shdr->sh_type); 336 337 Elf_W(Sym)* sym; 338 for (sym = symtab; 339 sym < symtab_end; 340 sym = (Elf_W(Sym) *) ((char *) sym + shdr->sh_entsize)) { 341 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_shndx != SHN_UNDEF) { 342 Elf_W(Addr) val; 343 if (tdep_get_func_addr (as, sym->st_value, &val) < 0) { 344 continue; 345 } 346 if (sym->st_shndx != SHN_ABS) { 347 val += load_offset; 348 } 349 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym->st_info); 350 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym->st_size) { 351 char* str_name = strtab + sym->st_name; 352 if (str_name > (char*) ei->u.mapped.image + ei->u.mapped.size || 353 str_name < strtab) { 354 // Malformed elf symbol table. 355 break; 356 } 357 358 // Make sure we don't try and read past the end of the image. 359 uintptr_t max_size = (uintptr_t) str_name - (uintptr_t) ei->u.mapped.image; 360 if (buf_len > max_size) { 361 buf_len = max_size; 362 } 363 364 strncpy (buf, str_name, buf_len); 365 // Ensure the string is nul terminated, it is assumed that 366 // sizeof(buf) >= buf_len + 1. 367 buf[buf_len] = '\0'; 368 if (buf[0] == '\0') { 369 // Empty name, so keep checking the other symbol tables 370 // for a possible match. 371 break; 372 } 373 if (offp != NULL) { 374 *offp = ip - val; 375 } 376 return true; 377 } 378 } 379 } 380 break; 381 } 382 383 default: 384 break; 385 } 386 shdr = (Elf_W(Shdr) *) (((char *) shdr) + ehdr->e_shentsize); 387 } 388 return false; 389 } 390 391 static bool elf_w (get_load_offset_mapped) ( 392 struct elf_image *ei, unsigned long segbase, unsigned long mapoff, Elf_W(Addr)* load_offset) { 393 Elf_W(Ehdr) *ehdr = ei->u.mapped.image; 394 Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff); 395 396 int i; 397 for (i = 0; i < ehdr->e_phnum; ++i) { 398 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) { 399 *load_offset = segbase - phdr[i].p_vaddr; 400 return true; 401 } 402 } 403 return false; 404 } 405 406 static Elf_W(Addr) elf_w (get_min_vaddr_mapped) (struct elf_image *ei) { 407 Elf_W(Ehdr) *ehdr = ei->u.mapped.image; 408 Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff); 409 Elf_W(Addr) min_vaddr = ~0u; 410 int i; 411 for (i = 0; i < ehdr->e_phnum; ++i) { 412 if (phdr[i].p_type == PT_LOAD && phdr[i].p_vaddr < min_vaddr) { 413 min_vaddr = phdr[i].p_vaddr; 414 } 415 } 416 return min_vaddr; 417 } 418 419 // -------------------------------------------------------------------------- 420 421 static inline bool elf_w (lookup_symbol) ( 422 unw_addr_space_t as, unw_word_t ip, struct elf_image *ei, Elf_W(Addr) load_offset, 423 char *buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) { 424 if (!ei->valid) 425 return false; 426 427 if (buf_len <= 1) { 428 Debug (1, "lookup_symbol called with a buffer too small to hold a name %zu\n", buf_len); 429 return false; 430 } 431 432 // Leave enough space for the nul terminator. 433 buf_len--; 434 435 if (ei->mapped) { 436 return elf_w (lookup_symbol_mapped) (as, ip, ei, load_offset, buf, buf_len, offp); 437 } else { 438 return elf_w (lookup_symbol_memory) (as, ip, ei, load_offset, buf, buf_len, offp, ehdr); 439 } 440 } 441 442 static bool elf_w (get_load_offset) ( 443 struct elf_image* ei, unsigned long segbase, unsigned long mapoff, 444 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) { 445 if (ei->mapped) { 446 return elf_w (get_load_offset_mapped) (ei, segbase, mapoff, load_offset); 447 } else { 448 return elf_w (get_load_offset_memory) (ei, segbase, mapoff, ehdr, load_offset); 449 } 450 } 451 452 /* ANDROID support update. */ 453 static void* xz_alloc(void* p, size_t size) { 454 return malloc(size); 455 } 456 457 static void xz_free(void* p, void* address) { 458 free(address); 459 } 460 461 HIDDEN bool 462 elf_w (xz_decompress) (uint8_t* src, size_t src_size, 463 uint8_t** dst, size_t* dst_size) { 464 #if HAVE_LZMA 465 size_t src_offset = 0; 466 size_t dst_offset = 0; 467 size_t src_remaining; 468 size_t dst_remaining; 469 ISzAlloc alloc; 470 CXzUnpacker state; 471 ECoderStatus status; 472 alloc.Alloc = xz_alloc; 473 alloc.Free = xz_free; 474 XzUnpacker_Construct(&state, &alloc); 475 CrcGenerateTable(); 476 Crc64GenerateTable(); 477 *dst_size = 2 * src_size; 478 *dst = NULL; 479 do { 480 *dst_size *= 2; 481 *dst = realloc(*dst, *dst_size); 482 if (*dst == NULL) { 483 Debug (1, "LZMA decompression failed due to failed realloc.\n"); 484 XzUnpacker_Free(&state); 485 return false; 486 } 487 src_remaining = src_size - src_offset; 488 dst_remaining = *dst_size - dst_offset; 489 int res = XzUnpacker_Code(&state, 490 *dst + dst_offset, &dst_remaining, 491 src + src_offset, &src_remaining, 492 CODER_FINISH_ANY, &status); 493 if (res != SZ_OK) { 494 Debug (1, "LZMA decompression failed with error %d\n", res); 495 free(*dst); 496 XzUnpacker_Free(&state); 497 return false; 498 } 499 src_offset += src_remaining; 500 dst_offset += dst_remaining; 501 } while (status == CODER_STATUS_NOT_FINISHED); 502 XzUnpacker_Free(&state); 503 if (!XzUnpacker_IsStreamWasFinished(&state)) { 504 Debug (1, "LZMA decompression failed due to incomplete stream.\n"); 505 free(*dst); 506 return false; 507 } 508 *dst_size = dst_offset; 509 *dst = realloc(*dst, *dst_size); 510 return true; 511 #else 512 Debug (1, "Decompression failed - compiled without LZMA support.\n", 513 return false; 514 #endif // HAVE_LZMA 515 } 516 517 HIDDEN bool 518 elf_w (find_section_mapped) (struct elf_image *ei, const char* name, 519 uint8_t** section, size_t* size, Elf_W(Addr)* vaddr) { 520 Elf_W (Ehdr) *ehdr = ei->u.mapped.image; 521 Elf_W (Shdr) *shdr; 522 char *strtab; 523 int i; 524 525 if (!ei->valid || !ei->mapped) { 526 return false; 527 } 528 529 shdr = elf_w (section_table) (ei); 530 if (!shdr) { 531 return false; 532 } 533 534 strtab = elf_w (string_table) (ei, ehdr->e_shstrndx); 535 if (!strtab) { 536 return false; 537 } 538 539 for (i = 0; i < ehdr->e_shnum; ++i) { 540 if (strcmp (strtab + shdr->sh_name, name) == 0) { 541 if (section != NULL && size != NULL) { 542 if (shdr->sh_offset + shdr->sh_size > ei->u.mapped.size) { 543 Debug (1, "section %s outside image? (0x%lu > 0x%lu)\n", name, 544 (unsigned long) (shdr->sh_offset + shdr->sh_size), 545 (unsigned long) ei->u.mapped.size); 546 return false; 547 } 548 *section = ((uint8_t *) ei->u.mapped.image) + shdr->sh_offset; 549 *size = shdr->sh_size; 550 } 551 if (vaddr != NULL) { 552 *vaddr = shdr->sh_addr; 553 } 554 return true; 555 } 556 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); 557 } 558 return false; 559 } 560 /* ANDROID support update. */ 561 562 // Find the ELF image that contains IP and return the procedure name from 563 // the symbol table that matches the IP. 564 HIDDEN bool elf_w (get_proc_name_in_image) ( 565 unw_addr_space_t as, struct elf_image* ei, unsigned long segbase, unsigned long mapoff, 566 unw_word_t ip, char* buf, size_t buf_len, unw_word_t* offp) { 567 Elf_W(Ehdr) ehdr; 568 memset(&ehdr, 0, sizeof(ehdr)); 569 Elf_W(Addr) load_offset; 570 if (!elf_w (get_load_offset) (ei, segbase, mapoff, &ehdr, &load_offset)) { 571 return false; 572 } 573 574 if (elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp, &ehdr) != 0) { 575 return true; 576 } 577 578 // If the ELF image doesn't contain a match, look up the symbol in 579 // the MiniDebugInfo. 580 if (ei->mapped && ei->mini_debug_info_data) { 581 struct elf_image mdi; 582 mdi.mapped = true; 583 mdi.u.mapped.image = ei->mini_debug_info_data; 584 mdi.u.mapped.size = ei->mini_debug_info_size; 585 mdi.valid = elf_w (valid_object_mapped) (&mdi); 586 // The ELF file might have been relocated after the debug 587 // information has been compresses and embedded. 588 ElfW(Addr) ei_text_address, mdi_text_address; 589 if (elf_w (find_section_mapped) (ei, ".text", NULL, NULL, &ei_text_address) && 590 elf_w (find_section_mapped) (&mdi, ".text", NULL, NULL, &mdi_text_address)) { 591 load_offset += ei_text_address - mdi_text_address; 592 } 593 bool ret_val = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, buf_len, offp, &ehdr); 594 return ret_val; 595 } 596 return false; 597 } 598 599 HIDDEN bool elf_w (get_proc_name) ( 600 unw_addr_space_t as, pid_t pid, unw_word_t ip, char* buf, size_t buf_len, 601 unw_word_t* offp, void* as_arg) { 602 unsigned long segbase, mapoff; 603 struct elf_image ei; 604 605 if (tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL, as_arg) < 0) { 606 return false; 607 } 608 609 return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp); 610 } 611 612 HIDDEN bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base) { 613 if (!ei->valid) { 614 return false; 615 } 616 617 if (ei->mapped) { 618 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 619 Elf_W(Phdr)* phdr = (Elf_W(Phdr)*) ((char*) ei->u.mapped.image + ehdr->e_phoff); 620 int i; 621 for (i = 0; i < ehdr->e_phnum; ++i) { 622 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) { 623 *load_base = phdr[i].p_vaddr; 624 return true; 625 } 626 } 627 return false; 628 } else { 629 Elf_W(Ehdr) ehdr; 630 GET_EHDR_FIELD(ei, &ehdr, e_phnum, false); 631 GET_EHDR_FIELD(ei, &ehdr, e_phoff, false); 632 int i; 633 unw_word_t offset = ehdr.e_phoff; 634 for (i = 0; i < ehdr.e_phnum; ++i) { 635 Elf_W(Phdr) phdr; 636 GET_PHDR_FIELD(ei, offset, &phdr, p_type); 637 GET_PHDR_FIELD(ei, offset, &phdr, p_offset); 638 // Always use zero as the map offset for in memory maps. 639 // The dlopen of a shared library from an APK will result in a 640 // non-zero map offset which would mean we would never find the 641 // correct program header using the passed in map offset. 642 if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) { 643 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr); 644 *load_base = phdr.p_vaddr; 645 return true; 646 } 647 offset += sizeof(phdr); 648 } 649 return false; 650 } 651 return false; 652 } 653