1 //===------------------------- AddressSpace.hpp ---------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 // 8 // Abstracts accessing local vs remote address spaces. 9 // 10 //===----------------------------------------------------------------------===// 11 12 #ifndef __ADDRESSSPACE_HPP__ 13 #define __ADDRESSSPACE_HPP__ 14 15 #include <stdint.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sys/tree.h> 20 21 #ifndef _LIBUNWIND_USE_DLADDR 22 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) 23 #define _LIBUNWIND_USE_DLADDR 1 24 #else 25 #define _LIBUNWIND_USE_DLADDR 0 26 #endif 27 #endif 28 29 #if _LIBUNWIND_USE_DLADDR 30 #include <dlfcn.h> 31 #if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB) 32 #pragma comment(lib, "dl") 33 #endif 34 #endif 35 36 #if defined(_LIBUNWIND_ARM_EHABI) 37 struct EHABIIndexEntry { 38 uint32_t functionOffset; 39 uint32_t data; 40 }; 41 #endif 42 43 #ifdef __APPLE__ 44 #include <mach-o/getsect.h> 45 namespace libunwind { 46 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); 47 } 48 #endif 49 50 #include "libunwind.h" 51 #include "config.h" 52 #include "dwarf2.h" 53 #include "EHHeaderParser.hpp" 54 #include "Registers.hpp" 55 56 #ifdef __APPLE__ 57 58 struct dyld_unwind_sections 59 { 60 const struct mach_header* mh; 61 const void* dwarf_section; 62 uintptr_t dwarf_section_length; 63 const void* compact_unwind_section; 64 uintptr_t compact_unwind_section_length; 65 }; 66 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ 67 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ 68 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 69 // In 10.7.0 or later, libSystem.dylib implements this function. 70 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); 71 #else 72 // In 10.6.x and earlier, we need to implement this functionality. Note 73 // that this requires a newer version of libmacho (from cctools) than is 74 // present in libSystem on 10.6.x (for getsectiondata). 75 static inline bool _dyld_find_unwind_sections(void* addr, 76 dyld_unwind_sections* info) { 77 // Find mach-o image containing address. 78 Dl_info dlinfo; 79 if (!dladdr(addr, &dlinfo)) 80 return false; 81 #if __LP64__ 82 const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase; 83 #else 84 const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase; 85 #endif 86 87 // Initialize the return struct 88 info->mh = (const struct mach_header *)mh; 89 info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length); 90 info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length); 91 92 if (!info->dwarf_section) { 93 info->dwarf_section_length = 0; 94 } 95 96 if (!info->compact_unwind_section) { 97 info->compact_unwind_section_length = 0; 98 } 99 100 return true; 101 } 102 #endif 103 104 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) 105 106 // When statically linked on bare-metal, the symbols for the EH table are looked 107 // up without going through the dynamic loader. 108 109 // The following linker script may be used to produce the necessary sections and symbols. 110 // Unless the --eh-frame-hdr linker option is provided, the section is not generated 111 // and does not take space in the output file. 112 // 113 // .eh_frame : 114 // { 115 // __eh_frame_start = .; 116 // KEEP(*(.eh_frame)) 117 // __eh_frame_end = .; 118 // } 119 // 120 // .eh_frame_hdr : 121 // { 122 // KEEP(*(.eh_frame_hdr)) 123 // } 124 // 125 // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; 126 // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; 127 128 extern char __eh_frame_start; 129 extern char __eh_frame_end; 130 131 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 132 extern char __eh_frame_hdr_start; 133 extern char __eh_frame_hdr_end; 134 #endif 135 136 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) 137 138 // When statically linked on bare-metal, the symbols for the EH table are looked 139 // up without going through the dynamic loader. 140 extern char __exidx_start; 141 extern char __exidx_end; 142 143 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 144 145 // ELF-based systems may use dl_iterate_phdr() to access sections 146 // containing unwinding information. The ElfW() macro for pointer-size 147 // independent ELF header traversal is not provided by <link.h> on some 148 // systems (e.g., FreeBSD). On these systems the data structures are 149 // just called Elf_XXX. Define ElfW() locally. 150 #ifndef _WIN32 151 #include <link.h> 152 #else 153 #include <windows.h> 154 #include <psapi.h> 155 #endif 156 #if !defined(ElfW) 157 #define ElfW(type) Elf_##type 158 #endif 159 160 #endif 161 162 namespace libunwind { 163 164 /// Used by findUnwindSections() to return info about needed sections. 165 struct UnwindInfoSections { 166 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \ 167 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) 168 // No dso_base for SEH or ARM EHABI. 169 uintptr_t dso_base; 170 #endif 171 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 172 uintptr_t dwarf_section; 173 uintptr_t dwarf_section_length; 174 #endif 175 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 176 uintptr_t dwarf_index_section; 177 uintptr_t dwarf_index_section_length; 178 #endif 179 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) 180 uintptr_t compact_unwind_section; 181 uintptr_t compact_unwind_section_length; 182 #endif 183 #if defined(_LIBUNWIND_ARM_EHABI) 184 uintptr_t arm_section; 185 uintptr_t arm_section_length; 186 #endif 187 }; 188 189 class UnwindInfoSectionsCache { 190 public: 191 192 struct CacheItem { 193 CacheItem(UnwindInfoSections &uis, uintptr_t pc) 194 : m_uis(uis), m_pc(pc) { 195 } 196 CacheItem(uintptr_t pc) 197 : m_pc(pc) { 198 } 199 200 UnwindInfoSections m_uis; 201 uintptr_t m_pc; 202 203 RB_ENTRY(CacheItem) entry; 204 }; 205 206 typedef uintptr_t CacheItemKey; 207 208 int CacheCmp(struct CacheItem *c1, struct CacheItem *c2) { 209 return (c1->m_pc < c2->m_pc ? -1 : c1->m_pc > c2->m_pc); 210 } 211 212 UnwindInfoSectionsCache() { 213 m_head = RB_INITIALIZER(&head); 214 } 215 216 bool getUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) { 217 UnwindInfoSections *result = nullptr; 218 if (m_prev_req_item && m_prev_req_item->m_pc == key) 219 result = &m_prev_req_item->m_uis; 220 else { 221 struct CacheItem find(key), *res; 222 res = RB_FIND(CacheTree, &m_head, &find); 223 if (res) { 224 m_prev_req_item = res; 225 result = &res->m_uis; 226 } 227 } 228 if (result) { 229 uis = *result; 230 return true; 231 } 232 return false; 233 } 234 235 void setUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) { 236 CacheItem *p_item(new CacheItem(uis, key)); 237 RB_INSERT(CacheTree, &m_head, p_item); 238 } 239 240 private: 241 CacheItem *m_prev_req_item = nullptr; 242 RB_HEAD(CacheTree, CacheItem) m_head; 243 RB_GENERATE(CacheTree, CacheItem, entry, CacheCmp); 244 }; 245 246 /// LocalAddressSpace is used as a template parameter to UnwindCursor when 247 /// unwinding a thread in the same process. The wrappers compile away, 248 /// making local unwinds fast. 249 class _LIBUNWIND_HIDDEN LocalAddressSpace { 250 public: 251 typedef uintptr_t pint_t; 252 typedef intptr_t sint_t; 253 uint8_t get8(pint_t addr) { 254 uint8_t val; 255 memcpy(&val, (void *)addr, sizeof(val)); 256 return val; 257 } 258 uint16_t get16(pint_t addr) { 259 uint16_t val; 260 memcpy(&val, (void *)addr, sizeof(val)); 261 return val; 262 } 263 uint32_t get32(pint_t addr) { 264 uint32_t val; 265 memcpy(&val, (void *)addr, sizeof(val)); 266 return val; 267 } 268 uint64_t get64(pint_t addr) { 269 uint64_t val; 270 memcpy(&val, (void *)addr, sizeof(val)); 271 return val; 272 } 273 double getDouble(pint_t addr) { 274 double val; 275 memcpy(&val, (void *)addr, sizeof(val)); 276 return val; 277 } 278 v128 getVector(pint_t addr) { 279 v128 val; 280 memcpy(&val, (void *)addr, sizeof(val)); 281 return val; 282 } 283 uintptr_t getP(pint_t addr); 284 uint64_t getRegister(pint_t addr); 285 static uint64_t getULEB128(pint_t &addr, pint_t end); 286 static int64_t getSLEB128(pint_t &addr, pint_t end); 287 288 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 289 pint_t datarelBase = 0); 290 bool findFunctionName(pint_t addr, char *buf, size_t bufLen, 291 unw_word_t *offset); 292 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); 293 bool findOtherFDE(pint_t targetAddr, pint_t &fde); 294 295 static LocalAddressSpace sThisAddressSpace; 296 }; 297 298 inline uintptr_t LocalAddressSpace::getP(pint_t addr) { 299 #if __SIZEOF_POINTER__ == 8 300 return get64(addr); 301 #else 302 return get32(addr); 303 #endif 304 } 305 306 inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { 307 #if __SIZEOF_POINTER__ == 8 || defined(__mips64) 308 return get64(addr); 309 #else 310 return get32(addr); 311 #endif 312 } 313 314 /// Read a ULEB128 into a 64-bit word. 315 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { 316 const uint8_t *p = (uint8_t *)addr; 317 const uint8_t *pend = (uint8_t *)end; 318 uint64_t result = 0; 319 int bit = 0; 320 do { 321 uint64_t b; 322 323 if (p == pend) 324 _LIBUNWIND_ABORT("truncated uleb128 expression"); 325 326 b = *p & 0x7f; 327 328 if (bit >= 64 || b << bit >> bit != b) { 329 _LIBUNWIND_ABORT("malformed uleb128 expression"); 330 } else { 331 result |= b << bit; 332 bit += 7; 333 } 334 } while (*p++ >= 0x80); 335 addr = (pint_t) p; 336 return result; 337 } 338 339 /// Read a SLEB128 into a 64-bit word. 340 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { 341 const uint8_t *p = (uint8_t *)addr; 342 const uint8_t *pend = (uint8_t *)end; 343 int64_t result = 0; 344 int bit = 0; 345 uint8_t byte; 346 do { 347 if (p == pend) 348 _LIBUNWIND_ABORT("truncated sleb128 expression"); 349 byte = *p++; 350 result |= ((byte & 0x7f) << bit); 351 bit += 7; 352 } while (byte & 0x80); 353 // sign extend negative numbers 354 if ((byte & 0x40) != 0) 355 result |= (-1ULL) << bit; 356 addr = (pint_t) p; 357 return result; 358 } 359 360 inline LocalAddressSpace::pint_t 361 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 362 pint_t datarelBase) { 363 pint_t startAddr = addr; 364 const uint8_t *p = (uint8_t *)addr; 365 pint_t result; 366 367 if (encoding == DW_EH_PE_omit) { 368 return (pint_t)NULL; 369 } 370 371 // first get value 372 switch (encoding & 0x0F) { 373 case DW_EH_PE_ptr: 374 result = getP(addr); 375 p += sizeof(pint_t); 376 addr = (pint_t) p; 377 break; 378 case DW_EH_PE_uleb128: 379 result = (pint_t)getULEB128(addr, end); 380 break; 381 case DW_EH_PE_udata2: 382 result = get16(addr); 383 p += 2; 384 addr = (pint_t) p; 385 break; 386 case DW_EH_PE_udata4: 387 result = get32(addr); 388 p += 4; 389 addr = (pint_t) p; 390 break; 391 case DW_EH_PE_udata8: 392 result = (pint_t)get64(addr); 393 p += 8; 394 addr = (pint_t) p; 395 break; 396 case DW_EH_PE_sleb128: 397 result = (pint_t)getSLEB128(addr, end); 398 break; 399 case DW_EH_PE_sdata2: 400 // Sign extend from signed 16-bit value. 401 result = (pint_t)(int16_t)get16(addr); 402 p += 2; 403 addr = (pint_t) p; 404 break; 405 case DW_EH_PE_sdata4: 406 // Sign extend from signed 32-bit value. 407 result = (pint_t)(int32_t)get32(addr); 408 p += 4; 409 addr = (pint_t) p; 410 break; 411 case DW_EH_PE_sdata8: 412 result = (pint_t)get64(addr); 413 p += 8; 414 addr = (pint_t) p; 415 break; 416 default: 417 _LIBUNWIND_ABORT("unknown pointer encoding"); 418 } 419 420 // then add relative offset 421 switch (encoding & 0x70) { 422 case DW_EH_PE_absptr: 423 // do nothing 424 break; 425 case DW_EH_PE_pcrel: 426 result += startAddr; 427 break; 428 case DW_EH_PE_textrel: 429 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); 430 break; 431 case DW_EH_PE_datarel: 432 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a 433 // default value of 0, and we abort in the event that someone calls this 434 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. 435 if (datarelBase == 0) 436 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); 437 result += datarelBase; 438 break; 439 case DW_EH_PE_funcrel: 440 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); 441 break; 442 case DW_EH_PE_aligned: 443 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); 444 break; 445 default: 446 _LIBUNWIND_ABORT("unknown pointer encoding"); 447 break; 448 } 449 450 if (encoding & DW_EH_PE_indirect) 451 result = getP(result); 452 453 return result; 454 } 455 456 #ifdef __APPLE__ 457 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) 458 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) 459 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) 460 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) 461 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) 462 // Code inside findUnwindSections handles all these cases. 463 // 464 // Although the above ifdef chain is ugly, there doesn't seem to be a cleaner 465 // way to handle it. The generalized boolean expression is: 466 // 467 // A OR (B AND C) OR (D AND C) OR (B AND E) OR (F AND E) OR (D AND G) 468 // 469 // Running it through various boolean expression simplifiers gives expressions 470 // that don't help at all. 471 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 472 473 #if !defined(Elf_Half) 474 typedef ElfW(Half) Elf_Half; 475 #endif 476 #if !defined(Elf_Phdr) 477 typedef ElfW(Phdr) Elf_Phdr; 478 #endif 479 #if !defined(Elf_Addr) 480 typedef ElfW(Addr) Elf_Addr; 481 #endif 482 483 static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) { 484 Elf_Addr image_base = pinfo->dlpi_addr; 485 #if defined(__ANDROID__) && __ANDROID_API__ < 18 486 if (image_base == 0) { 487 // Normally, an image base of 0 indicates a non-PIE executable. On 488 // versions of Android prior to API 18, the dynamic linker reported a 489 // dlpi_addr of 0 for PIE executables. Compute the true image base 490 // using the PT_PHDR segment. 491 // See https://github.com/android/ndk/issues/505. 492 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { 493 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; 494 if (phdr->p_type == PT_PHDR) { 495 image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) - 496 phdr->p_vaddr; 497 break; 498 } 499 } 500 } 501 #endif 502 return image_base; 503 } 504 505 struct _LIBUNWIND_HIDDEN dl_iterate_cb_data { 506 LocalAddressSpace *addressSpace; 507 UnwindInfoSections *sects; 508 uintptr_t targetAddr; 509 }; 510 511 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 512 #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 513 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." 514 #endif 515 516 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) 517 #include "FrameHeaderCache.hpp" 518 519 // There should be just one of these per process. 520 static FrameHeaderCache ProcessFrameHeaderCache; 521 #endif 522 523 static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base, 524 dl_iterate_cb_data *cbdata) { 525 if (phdr->p_type == PT_LOAD) { 526 uintptr_t begin = image_base + phdr->p_vaddr; 527 uintptr_t end = begin + phdr->p_memsz; 528 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { 529 cbdata->sects->dso_base = begin; 530 cbdata->sects->dwarf_section_length = phdr->p_memsz; 531 return true; 532 } 533 } 534 return false; 535 } 536 537 static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, 538 size_t pinfo_size, void *data) { 539 auto cbdata = static_cast<dl_iterate_cb_data *>(data); 540 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr) 541 return 0; 542 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) 543 if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data)) 544 return 1; 545 #endif 546 547 Elf_Addr image_base = calculateImageBase(pinfo); 548 bool found_obj = false; 549 bool found_hdr = false; 550 551 // Third phdr is usually the executable phdr. 552 if (pinfo->dlpi_phnum > 2) 553 found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata); 554 555 // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know 556 // that there is one or more phdrs. 557 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) { 558 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1]; 559 if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) { 560 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; 561 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr; 562 cbdata->sects->dwarf_index_section = eh_frame_hdr_start; 563 cbdata->sects->dwarf_index_section_length = phdr->p_memsz; 564 found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr( 565 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, 566 hdrInfo); 567 if (found_hdr) 568 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; 569 } else if (!found_obj) { 570 found_obj = checkAddrInSegment(phdr, image_base, cbdata); 571 } 572 if (found_obj && found_hdr) { 573 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) 574 ProcessFrameHeaderCache.add(cbdata->sects); 575 #endif 576 return 1; 577 } 578 } 579 cbdata->sects->dwarf_section_length = 0; 580 return 0; 581 } 582 583 #else // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND) 584 // Given all the #ifdef's above, the code here is for 585 // defined(LIBUNWIND_ARM_EHABI) 586 587 static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, 588 void *data) { 589 auto *cbdata = static_cast<dl_iterate_cb_data *>(data); 590 bool found_obj = false; 591 bool found_hdr = false; 592 593 assert(cbdata); 594 assert(cbdata->sects); 595 596 if (cbdata->targetAddr < pinfo->dlpi_addr) 597 return 0; 598 599 Elf_Addr image_base = calculateImageBase(pinfo); 600 601 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { 602 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; 603 if (phdr->p_type == PT_LOAD) { 604 uintptr_t begin = image_base + phdr->p_vaddr; 605 uintptr_t end = begin + phdr->p_memsz; 606 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) 607 found_obj = true; 608 } else if (phdr->p_type == PT_ARM_EXIDX) { 609 uintptr_t exidx_start = image_base + phdr->p_vaddr; 610 cbdata->sects->arm_section = exidx_start; 611 cbdata->sects->arm_section_length = phdr->p_memsz; 612 found_hdr = true; 613 } 614 } 615 return found_obj && found_hdr; 616 } 617 #endif // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND) 618 #endif // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 619 620 621 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, 622 UnwindInfoSections &info) { 623 #ifdef __APPLE__ 624 dyld_unwind_sections dyldInfo; 625 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { 626 info.dso_base = (uintptr_t)dyldInfo.mh; 627 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 628 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; 629 info.dwarf_section_length = dyldInfo.dwarf_section_length; 630 #endif 631 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; 632 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; 633 return true; 634 } 635 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) 636 // Bare metal is statically linked, so no need to ask the dynamic loader 637 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); 638 info.dwarf_section = (uintptr_t)(&__eh_frame_start); 639 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", 640 (void *)info.dwarf_section, (void *)info.dwarf_section_length); 641 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 642 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start); 643 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start); 644 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p", 645 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length); 646 #endif 647 if (info.dwarf_section_length) 648 return true; 649 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) 650 // Bare metal is statically linked, so no need to ask the dynamic loader 651 info.arm_section = (uintptr_t)(&__exidx_start); 652 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); 653 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", 654 (void *)info.arm_section, (void *)info.arm_section_length); 655 if (info.arm_section && info.arm_section_length) 656 return true; 657 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) 658 HMODULE mods[1024]; 659 HANDLE process = GetCurrentProcess(); 660 DWORD needed; 661 662 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) { 663 DWORD err = GetLastError(); 664 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, " 665 "returned error %d", (int)err); 666 return false; 667 } 668 669 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) { 670 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i]; 671 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew); 672 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader; 673 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); 674 bool found_obj = false; 675 bool found_hdr = false; 676 677 info.dso_base = (uintptr_t)mods[i]; 678 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) { 679 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i]; 680 uintptr_t end = begin + pish->Misc.VirtualSize; 681 if (!strncmp((const char *)pish->Name, ".text", 682 IMAGE_SIZEOF_SHORT_NAME)) { 683 if (targetAddr >= begin && targetAddr < end) 684 found_obj = true; 685 } else if (!strncmp((const char *)pish->Name, ".eh_frame", 686 IMAGE_SIZEOF_SHORT_NAME)) { 687 info.dwarf_section = begin; 688 info.dwarf_section_length = pish->Misc.VirtualSize; 689 found_hdr = true; 690 } 691 if (found_obj && found_hdr) 692 return true; 693 } 694 } 695 return false; 696 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) 697 // Don't even bother, since Windows has functions that do all this stuff 698 // for us. 699 (void)targetAddr; 700 (void)info; 701 return true; 702 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) 703 // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After 704 // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster. 705 int length = 0; 706 info.arm_section = 707 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); 708 info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry); 709 if (info.arm_section && info.arm_section_length) 710 return true; 711 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 712 dl_iterate_cb_data cb_data = {this, &info, targetAddr}; 713 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data); 714 return static_cast<bool>(found); 715 #endif 716 717 return false; 718 } 719 720 721 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { 722 #ifdef __APPLE__ 723 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); 724 #else 725 // TO DO: if OS has way to dynamically register FDEs, check that. 726 (void)targetAddr; 727 (void)fde; 728 return false; 729 #endif 730 } 731 732 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, 733 size_t bufLen, 734 unw_word_t *offset) { 735 #if _LIBUNWIND_USE_DLADDR 736 Dl_info dyldInfo; 737 if (dladdr((void *)addr, &dyldInfo)) { 738 if (dyldInfo.dli_sname != NULL) { 739 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); 740 *offset = (addr - (pint_t) dyldInfo.dli_saddr); 741 return true; 742 } 743 } 744 #else 745 (void)addr; 746 (void)buf; 747 (void)bufLen; 748 (void)offset; 749 #endif 750 return false; 751 } 752 753 } // namespace libunwind 754 755 #endif // __ADDRESSSPACE_HPP__ 756