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 #ifdef HAVE_LZMA 33 #include <lzma.h> 34 #endif /* HAVE_LZMA */ 35 36 // -------------------------------------------------------------------------- 37 // Functions to read elf data from memory. 38 // -------------------------------------------------------------------------- 39 extern size_t elf_w (memory_read) ( 40 struct elf_image* ei, unw_word_t addr, uint8_t* buffer, size_t bytes, bool string_read) { 41 struct map_info* map = ei->u.memory.map; 42 unw_accessors_t* a = unw_get_accessors (ei->u.memory.as); 43 if (map->end - addr < bytes) { 44 bytes = map->end - addr; 45 } 46 size_t bytes_read = 0; 47 unw_word_t data_word; 48 size_t align_bytes = addr & (sizeof(unw_word_t) - 1); 49 if (align_bytes != 0) { 50 if ((*a->access_mem) (ei->u.memory.as, addr & ~(sizeof(unw_word_t) - 1), &data_word, 51 0, ei->u.memory.as_arg) != 0) { 52 return 0; 53 } 54 size_t copy_bytes = MIN(sizeof(unw_word_t) - align_bytes, bytes); 55 memcpy (buffer, (uint8_t*) (&data_word) + align_bytes, copy_bytes); 56 if (string_read) { 57 // Check for nul terminator. 58 uint8_t* nul_terminator = memchr (buffer, '\0', copy_bytes); 59 if (nul_terminator != NULL) { 60 return nul_terminator - buffer; 61 } 62 } 63 64 addr += copy_bytes; 65 bytes_read += copy_bytes; 66 bytes -= copy_bytes; 67 buffer += copy_bytes; 68 } 69 70 size_t num_words = bytes / sizeof(unw_word_t); 71 size_t i; 72 for (i = 0; i < num_words; i++) { 73 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) { 74 return bytes_read; 75 } 76 77 memcpy (buffer, &data_word, sizeof(unw_word_t)); 78 if (string_read) { 79 // Check for nul terminator. 80 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t)); 81 if (nul_terminator != NULL) { 82 return nul_terminator - buffer + bytes_read; 83 } 84 } 85 86 addr += sizeof(unw_word_t); 87 bytes_read += sizeof(unw_word_t); 88 buffer += sizeof(unw_word_t); 89 } 90 91 size_t left_over = bytes & (sizeof(unw_word_t) - 1); 92 if (left_over) { 93 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) { 94 return bytes_read; 95 } 96 97 memcpy (buffer, &data_word, left_over); 98 if (string_read) { 99 // Check for nul terminator. 100 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t)); 101 if (nul_terminator != NULL) { 102 return nul_terminator - buffer + bytes_read; 103 } 104 } 105 106 bytes_read += left_over; 107 } 108 return bytes_read; 109 } 110 111 static bool elf_w (section_table_offset) (struct elf_image* ei, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) { 112 GET_EHDR_FIELD(ei, ehdr, e_shoff, true); 113 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); 114 GET_EHDR_FIELD(ei, ehdr, e_shnum, true); 115 116 uintptr_t size = ei->u.memory.map->end - ei->u.memory.map->start; 117 if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) { 118 Debug (1, "section table outside of image? (%lu > %lu)\n", 119 (unsigned long) (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize), 120 (unsigned long) size); 121 return false; 122 } 123 124 *offset = ehdr->e_shoff; 125 return true; 126 } 127 128 static bool elf_w (string_table_offset) ( 129 struct elf_image* ei, int section, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) { 130 GET_EHDR_FIELD(ei, ehdr, e_shoff, true); 131 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); 132 unw_word_t str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize); 133 uintptr_t size = ei->u.memory.map->end - ei->u.memory.map->start; 134 if (str_soff + ehdr->e_shentsize > size) { 135 Debug (1, "string shdr table outside of image? (%lu > %lu)\n", 136 (unsigned long) (str_soff + ehdr->e_shentsize), 137 (unsigned long) size); 138 return false; 139 } 140 141 Elf_W(Shdr) shdr; 142 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_offset); 143 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_size); 144 if (shdr.sh_offset + shdr.sh_size > size) { 145 Debug (1, "string table outside of image? (%lu > %lu)\n", 146 (unsigned long) (shdr.sh_offset + shdr.sh_size), 147 (unsigned long) size); 148 return false; 149 } 150 151 Debug (16, "strtab=0x%lx\n", (long) shdr.sh_offset); 152 *offset = shdr.sh_offset; 153 return true; 154 } 155 156 static bool elf_w (lookup_symbol_memory) ( 157 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset, 158 char* buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) { 159 Elf_W(Off) shdr_offset; 160 if (!elf_w (section_table_offset) (ei, ehdr, &shdr_offset)) { 161 return false; 162 } 163 164 GET_EHDR_FIELD(ei, ehdr, e_shnum, true); 165 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true); 166 int i; 167 for (i = 0; i < ehdr->e_shnum; ++i) { 168 Elf_W(Shdr) shdr; 169 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_type); 170 switch (shdr.sh_type) { 171 case SHT_SYMTAB: 172 case SHT_DYNSYM: 173 { 174 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_link); 175 176 Elf_W(Off) strtab_offset; 177 if (!elf_w (string_table_offset) (ei, shdr.sh_link, ehdr, &strtab_offset)) { 178 continue; 179 } 180 181 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_offset); 182 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_size); 183 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_entsize); 184 185 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr.sh_offset, shdr.sh_type); 186 187 unw_word_t sym_offset; 188 unw_word_t symtab_end = shdr.sh_offset + shdr.sh_size; 189 for (sym_offset = shdr.sh_offset; 190 sym_offset < symtab_end; 191 sym_offset += shdr.sh_entsize) { 192 Elf_W(Sym) sym; 193 GET_SYM_FIELD(ei, sym_offset, &sym, st_info); 194 GET_SYM_FIELD(ei, sym_offset, &sym, st_shndx); 195 196 if (ELF_W (ST_TYPE) (sym.st_info) == STT_FUNC && sym.st_shndx != SHN_UNDEF) { 197 GET_SYM_FIELD(ei, sym_offset, &sym, st_value); 198 Elf_W(Addr) val; 199 if (tdep_get_func_addr (as, sym.st_value, &val) < 0) { 200 continue; 201 } 202 if (sym.st_shndx != SHN_ABS) { 203 val += load_offset; 204 } 205 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym.st_info); 206 207 GET_SYM_FIELD(ei, sym_offset, &sym, st_size); 208 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym.st_size) { 209 GET_SYM_FIELD(ei, sym_offset, &sym, st_name); 210 uintptr_t size = ei->u.memory.map->end - ei->u.memory.map->start; 211 Elf_W(Off) strname_offset = strtab_offset + sym.st_name; 212 if (strname_offset > size || strname_offset < strtab_offset) { 213 // Malformed elf symbol table. 214 break; 215 } 216 217 size_t bytes_read = elf_w (memory_read) ( 218 ei, ei->u.memory.map->start + strname_offset, 219 (uint8_t*) buf, buf_len, true); 220 if (bytes_read == 0) { 221 // Empty name, so keep checking the other symbol tables 222 // for a possible match. 223 break; 224 } 225 // Ensure the string is nul terminated, it is assumed that 226 // sizeof(buf) >= buf_len + 1. 227 buf[buf_len] = '\0'; 228 229 if (offp != NULL) { 230 *offp = ip - val; 231 } 232 return true; 233 } 234 } 235 } 236 break; 237 } 238 239 default: 240 break; 241 } 242 shdr_offset += ehdr->e_shentsize; 243 } 244 return false; 245 } 246 247 static bool elf_w (get_load_offset_memory) ( 248 struct elf_image* ei, unsigned long segbase, unsigned long mapoff, 249 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) { 250 GET_EHDR_FIELD(ei, ehdr, e_phoff, true); 251 GET_EHDR_FIELD(ei, ehdr, e_phnum, true); 252 253 unw_word_t offset = ehdr->e_phoff; 254 int i; 255 for (i = 0; i < ehdr->e_phnum; ++i) { 256 Elf_W(Phdr) phdr; 257 GET_PHDR_FIELD(ei, offset, &phdr, p_type); 258 if (phdr.p_type == PT_LOAD) { 259 GET_PHDR_FIELD(ei, offset, &phdr, p_offset); 260 if (phdr.p_offset == mapoff) { 261 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr); 262 *load_offset = segbase - phdr.p_vaddr; 263 return true; 264 } 265 } 266 offset += sizeof(Elf_W(Phdr)); 267 } 268 return false; 269 } 270 271 // -------------------------------------------------------------------------- 272 // Functions to read elf data from the mapped elf image. 273 // -------------------------------------------------------------------------- 274 static Elf_W(Shdr)* elf_w (section_table) (struct elf_image* ei) { 275 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 276 Elf_W(Off) soff = ehdr->e_shoff; 277 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->u.mapped.size) { 278 Debug (1, "section table outside of image? (%lu > %lu)\n", 279 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize), 280 (unsigned long) ei->u.mapped.size); 281 return NULL; 282 } 283 284 return (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + soff); 285 } 286 287 static char* elf_w (string_table) (struct elf_image* ei, int section) { 288 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 289 Elf_W(Off) str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize); 290 if (str_soff + ehdr->e_shentsize > ei->u.mapped.size) { 291 Debug (1, "string shdr table outside of image? (%lu > %lu)\n", 292 (unsigned long) (str_soff + ehdr->e_shentsize), 293 (unsigned long) ei->u.mapped.size); 294 return NULL; 295 } 296 Elf_W(Shdr)* str_shdr = (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + str_soff); 297 298 if (str_shdr->sh_offset + str_shdr->sh_size > ei->u.mapped.size) { 299 Debug (1, "string table outside of image? (%lu > %lu)\n", 300 (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size), 301 (unsigned long) ei->u.mapped.size); 302 return NULL; 303 } 304 305 Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset); 306 return (char*) ((uintptr_t) ei->u.mapped.image + str_shdr->sh_offset); 307 } 308 309 static bool elf_w (lookup_symbol_mapped) ( 310 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset, 311 char* buf, size_t buf_len, unw_word_t* offp) { 312 313 Elf_W(Shdr)* shdr = elf_w (section_table) (ei); 314 if (!shdr) { 315 return false; 316 } 317 318 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 319 int i; 320 for (i = 0; i < ehdr->e_shnum; ++i) { 321 switch (shdr->sh_type) { 322 case SHT_SYMTAB: 323 case SHT_DYNSYM: 324 { 325 Elf_W(Sym)* symtab = (Elf_W(Sym) *) ((char *) ei->u.mapped.image + shdr->sh_offset); 326 Elf_W(Sym)* symtab_end = (Elf_W(Sym) *) ((char *) symtab + shdr->sh_size); 327 328 char* strtab = elf_w (string_table) (ei, shdr->sh_link); 329 if (!strtab) { 330 continue; 331 } 332 333 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr->sh_offset, shdr->sh_type); 334 335 Elf_W(Sym)* sym; 336 for (sym = symtab; 337 sym < symtab_end; 338 sym = (Elf_W(Sym) *) ((char *) sym + shdr->sh_entsize)) { 339 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_shndx != SHN_UNDEF) { 340 Elf_W(Addr) val; 341 if (tdep_get_func_addr (as, sym->st_value, &val) < 0) { 342 continue; 343 } 344 if (sym->st_shndx != SHN_ABS) { 345 val += load_offset; 346 } 347 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym->st_info); 348 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym->st_size) { 349 char* str_name = strtab + sym->st_name; 350 if (str_name > (char*) ei->u.mapped.image + ei->u.mapped.size || 351 str_name < strtab) { 352 // Malformed elf symbol table. 353 break; 354 } 355 356 // Make sure we don't try and read past the end of the image. 357 uintptr_t max_size = (uintptr_t) str_name - (uintptr_t) ei->u.mapped.image; 358 if (buf_len > max_size) { 359 buf_len = max_size; 360 } 361 362 strncpy (buf, str_name, buf_len); 363 // Ensure the string is nul terminated, it is assumed that 364 // sizeof(buf) >= buf_len + 1. 365 buf[buf_len] = '\0'; 366 if (buf[0] == '\0') { 367 // Empty name, so keep checking the other symbol tables 368 // for a possible match. 369 break; 370 } 371 if (offp != NULL) { 372 *offp = ip - val; 373 } 374 return true; 375 } 376 } 377 } 378 break; 379 } 380 381 default: 382 break; 383 } 384 shdr = (Elf_W(Shdr) *) (((char *) shdr) + ehdr->e_shentsize); 385 } 386 return false; 387 } 388 389 static bool elf_w (get_load_offset_mapped) ( 390 struct elf_image *ei, unsigned long segbase, unsigned long mapoff, Elf_W(Addr)* load_offset) { 391 Elf_W(Ehdr) *ehdr = ei->u.mapped.image; 392 Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff); 393 394 int i; 395 for (i = 0; i < ehdr->e_phnum; ++i) { 396 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) { 397 *load_offset = segbase - phdr[i].p_vaddr; 398 return true; 399 } 400 } 401 return false; 402 } 403 404 // -------------------------------------------------------------------------- 405 406 static inline bool elf_w (lookup_symbol) ( 407 unw_addr_space_t as, unw_word_t ip, struct elf_image *ei, Elf_W(Addr) load_offset, 408 char *buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) { 409 if (!ei->valid) 410 return false; 411 412 if (buf_len <= 1) { 413 Debug (1, "lookup_symbol called with a buffer too small to hold a name %zu\n", buf_len); 414 return false; 415 } 416 417 // Leave enough space for the nul terminator. 418 buf_len--; 419 420 if (ei->mapped) { 421 return elf_w (lookup_symbol_mapped) (as, ip, ei, load_offset, buf, buf_len, offp); 422 } else { 423 return elf_w (lookup_symbol_memory) (as, ip, ei, load_offset, buf, buf_len, offp, ehdr); 424 } 425 } 426 427 static bool elf_w (get_load_offset) ( 428 struct elf_image* ei, unsigned long segbase, unsigned long mapoff, 429 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) { 430 if (ei->mapped) { 431 return elf_w (get_load_offset_mapped) (ei, segbase, mapoff, load_offset); 432 } else { 433 return elf_w (get_load_offset_memory) (ei, segbase, mapoff, ehdr, load_offset); 434 } 435 } 436 437 #if HAVE_LZMA 438 static size_t xz_uncompressed_size (uint8_t* compressed, size_t length) { 439 uint64_t memlimit = UINT64_MAX; 440 size_t ret = 0, pos = 0; 441 lzma_stream_flags options; 442 lzma_index *index; 443 444 if (length < LZMA_STREAM_HEADER_SIZE) { 445 return 0; 446 } 447 448 uint8_t *footer = compressed + length - LZMA_STREAM_HEADER_SIZE; 449 if (lzma_stream_footer_decode (&options, footer) != LZMA_OK) { 450 return 0; 451 } 452 453 if (length < LZMA_STREAM_HEADER_SIZE + options.backward_size) { 454 return 0; 455 } 456 457 uint8_t* indexdata = footer - options.backward_size; 458 if (lzma_index_buffer_decode (&index, &memlimit, NULL, indexdata, 459 &pos, options.backward_size) != LZMA_OK) { 460 return 0; 461 } 462 463 if (lzma_index_size (index) == options.backward_size) { 464 ret = lzma_index_uncompressed_size (index); 465 } 466 467 lzma_index_end (index, NULL); 468 return ret; 469 } 470 471 static bool elf_w (extract_minidebuginfo) (struct elf_image* ei, struct elf_image* mdi, Elf_W(Ehdr)* ehdr) { 472 Elf_W(Ehdr)* ehdr = ei->image; 473 Elf_W(Shdr)* shdr; 474 char *strtab; 475 int i; 476 uint8_t *compressed = NULL; 477 uint64_t memlimit = UINT64_MAX; /* no memory limit */ 478 size_t compressed_len, uncompressed_len; 479 480 if (!ei->valid) { 481 return false; 482 } 483 484 shdr = elf_w (section_table) (ei); 485 if (!shdr) { 486 return false; 487 } 488 489 strtab = elf_w (string_table) (ei, ehdr->e_shstrndx); 490 if (!strtab) { 491 return false; 492 } 493 494 for (i = 0; i < ehdr->e_shnum; ++i) { 495 if (strcmp (strtab + shdr->sh_name, ".gnu_debugdata") == 0) { 496 if (shdr->sh_offset + shdr->sh_size > ei->size) { 497 Debug (1, ".gnu_debugdata outside image? (0x%lu > 0x%lu)\n", 498 (unsigned long) shdr->sh_offset + shdr->sh_size, 499 (unsigned long) ei->size); 500 return false; 501 } 502 503 Debug (16, "found .gnu_debugdata at 0x%lx\n", 504 (unsigned long) shdr->sh_offset); 505 compressed = ((uint8_t *) ei->image) + shdr->sh_offset; 506 compressed_len = shdr->sh_size; 507 break; 508 } 509 510 shdr = (Elf_W(Shdr) *) (((char *) shdr) + ehdr->e_shentsize); 511 } 512 513 /* not found */ 514 if (!compressed) { 515 return false; 516 } 517 518 uncompressed_len = xz_uncompressed_size (compressed, compressed_len); 519 if (uncompressed_len == 0) { 520 Debug (1, "invalid .gnu_debugdata contents\n"); 521 return false; 522 } 523 524 mdi->size = uncompressed_len; 525 mdi->image = mmap (NULL, uncompressed_len, PROT_READ|PROT_WRITE, 526 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 527 528 if (mdi->image == MAP_FAILED) { 529 return false; 530 } 531 532 size_t in_pos = 0, out_pos = 0; 533 lzma_ret lret; 534 lret = lzma_stream_buffer_decode (&memlimit, 0, NULL, 535 compressed, &in_pos, compressed_len, 536 mdi->image, &out_pos, mdi->size); 537 if (lret != LZMA_OK) { 538 Debug (1, "LZMA decompression failed: %d\n", lret); 539 munmap (mdi->image, mdi->size); 540 return false; 541 } 542 543 return true; 544 } 545 #else 546 static bool elf_w (extract_minidebuginfo) (struct elf_image* ei, struct elf_image* mdi, Elf_W(Ehdr)* ehdr) { 547 return false; 548 } 549 #endif /* !HAVE_LZMA */ 550 551 // Find the ELF image that contains IP and return the procedure name from 552 // the symbol table that matches the IP. 553 HIDDEN bool elf_w (get_proc_name_in_image) ( 554 unw_addr_space_t as, struct elf_image* ei, unsigned long segbase, unsigned long mapoff, 555 unw_word_t ip, char* buf, size_t buf_len, unw_word_t* offp) { 556 Elf_W(Ehdr) ehdr; 557 memset(&ehdr, 0, sizeof(ehdr)); 558 Elf_W(Addr) load_offset; 559 if (!elf_w (get_load_offset) (ei, segbase, mapoff, &ehdr, &load_offset)) { 560 return false; 561 } 562 563 if (elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp, &ehdr) != 0) { 564 return true; 565 } 566 567 // If the ELF image doesn't contain a match, look up the symbol in 568 // the MiniDebugInfo. 569 struct elf_image mdi; 570 if (elf_w (extract_minidebuginfo) (ei, &mdi, &ehdr)) { 571 if (!elf_w (get_load_offset) (&mdi, segbase, mapoff, &ehdr, &load_offset)) { 572 return false; 573 } 574 if (elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, buf_len, offp, &ehdr)) { 575 munmap (mdi.u.mapped.image, mdi.u.mapped.size); 576 return true; 577 } 578 return false; 579 } 580 return false; 581 } 582 583 HIDDEN bool elf_w (get_proc_name) ( 584 unw_addr_space_t as, pid_t pid, unw_word_t ip, char* buf, size_t buf_len, 585 unw_word_t* offp, void* as_arg) { 586 unsigned long segbase, mapoff; 587 struct elf_image ei; 588 589 if (tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL, as_arg) < 0) { 590 return false; 591 } 592 593 return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp); 594 } 595 596 HIDDEN bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base) { 597 if (!ei->valid) { 598 return false; 599 } 600 601 if (ei->mapped) { 602 Elf_W(Ehdr)* ehdr = ei->u.mapped.image; 603 Elf_W(Phdr)* phdr = (Elf_W(Phdr)*) ((char*) ei->u.mapped.image + ehdr->e_phoff); 604 int i; 605 for (i = 0; i < ehdr->e_phnum; ++i) { 606 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) { 607 *load_base = phdr[i].p_vaddr; 608 return true; 609 } 610 } 611 return false; 612 } else { 613 Elf_W(Ehdr) ehdr; 614 GET_EHDR_FIELD(ei, &ehdr, e_phnum, false); 615 GET_EHDR_FIELD(ei, &ehdr, e_phoff, false); 616 int i; 617 unw_word_t offset = ehdr.e_phoff; 618 for (i = 0; i < ehdr.e_phnum; ++i) { 619 Elf_W(Phdr) phdr; 620 GET_PHDR_FIELD(ei, offset, &phdr, p_type); 621 GET_PHDR_FIELD(ei, offset, &phdr, p_offset); 622 if (phdr.p_type == PT_LOAD && phdr.p_offset == mapoff) { 623 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr); 624 *load_base = phdr.p_vaddr; 625 return true; 626 } 627 offset += sizeof(phdr); 628 } 629 return false; 630 } 631 return false; 632 } 633