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 20 #include "libunwind.h" 21 #include "config.h" 22 #include "dwarf2.h" 23 #include "EHHeaderParser.hpp" 24 #include "Registers.hpp" 25 26 #ifndef _LIBUNWIND_USE_DLADDR 27 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) 28 #define _LIBUNWIND_USE_DLADDR 1 29 #else 30 #define _LIBUNWIND_USE_DLADDR 0 31 #endif 32 #endif 33 34 #if _LIBUNWIND_USE_DLADDR 35 #include <dlfcn.h> 36 #if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB) 37 #pragma comment(lib, "dl") 38 #endif 39 #endif 40 41 #if defined(_LIBUNWIND_ARM_EHABI) 42 struct EHABIIndexEntry { 43 uint32_t functionOffset; 44 uint32_t data; 45 }; 46 #endif 47 48 #ifdef __APPLE__ 49 50 struct dyld_unwind_sections 51 { 52 const struct mach_header* mh; 53 const void* dwarf_section; 54 uintptr_t dwarf_section_length; 55 const void* compact_unwind_section; 56 uintptr_t compact_unwind_section_length; 57 }; 58 59 // In 10.7.0 or later, libSystem.dylib implements this function. 60 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); 61 62 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) 63 64 // When statically linked on bare-metal, the symbols for the EH table are looked 65 // up without going through the dynamic loader. 66 67 // The following linker script may be used to produce the necessary sections and symbols. 68 // Unless the --eh-frame-hdr linker option is provided, the section is not generated 69 // and does not take space in the output file. 70 // 71 // .eh_frame : 72 // { 73 // __eh_frame_start = .; 74 // KEEP(*(.eh_frame)) 75 // __eh_frame_end = .; 76 // } 77 // 78 // .eh_frame_hdr : 79 // { 80 // KEEP(*(.eh_frame_hdr)) 81 // } 82 // 83 // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; 84 // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; 85 86 extern char __eh_frame_start; 87 extern char __eh_frame_end; 88 89 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 90 extern char __eh_frame_hdr_start; 91 extern char __eh_frame_hdr_end; 92 #endif 93 94 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) 95 96 // When statically linked on bare-metal, the symbols for the EH table are looked 97 // up without going through the dynamic loader. 98 extern char __exidx_start; 99 extern char __exidx_end; 100 101 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) 102 103 #include <windows.h> 104 #include <psapi.h> 105 106 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \ 107 defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) 108 109 #include <link.h> 110 111 #endif 112 113 namespace libunwind { 114 115 /// Used by findUnwindSections() to return info about needed sections. 116 struct UnwindInfoSections { 117 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \ 118 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \ 119 defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) 120 // No dso_base for SEH. 121 uintptr_t dso_base; 122 #endif 123 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) 124 uintptr_t text_segment_length; 125 #endif 126 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 127 uintptr_t dwarf_section; 128 uintptr_t dwarf_section_length; 129 #endif 130 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 131 uintptr_t dwarf_index_section; 132 uintptr_t dwarf_index_section_length; 133 #endif 134 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) 135 uintptr_t compact_unwind_section; 136 uintptr_t compact_unwind_section_length; 137 #endif 138 #if defined(_LIBUNWIND_ARM_EHABI) 139 uintptr_t arm_section; 140 uintptr_t arm_section_length; 141 #endif 142 }; 143 144 145 /// LocalAddressSpace is used as a template parameter to UnwindCursor when 146 /// unwinding a thread in the same process. The wrappers compile away, 147 /// making local unwinds fast. 148 class _LIBUNWIND_HIDDEN LocalAddressSpace { 149 public: 150 typedef uintptr_t pint_t; 151 typedef intptr_t sint_t; 152 uint8_t get8(pint_t addr) { 153 uint8_t val; 154 memcpy(&val, (void *)addr, sizeof(val)); 155 return val; 156 } 157 uint16_t get16(pint_t addr) { 158 uint16_t val; 159 memcpy(&val, (void *)addr, sizeof(val)); 160 return val; 161 } 162 uint32_t get32(pint_t addr) { 163 uint32_t val; 164 memcpy(&val, (void *)addr, sizeof(val)); 165 return val; 166 } 167 uint64_t get64(pint_t addr) { 168 uint64_t val; 169 memcpy(&val, (void *)addr, sizeof(val)); 170 return val; 171 } 172 double getDouble(pint_t addr) { 173 double val; 174 memcpy(&val, (void *)addr, sizeof(val)); 175 return val; 176 } 177 v128 getVector(pint_t addr) { 178 v128 val; 179 memcpy(&val, (void *)addr, sizeof(val)); 180 return val; 181 } 182 uintptr_t getP(pint_t addr); 183 uint64_t getRegister(pint_t addr); 184 static uint64_t getULEB128(pint_t &addr, pint_t end); 185 static int64_t getSLEB128(pint_t &addr, pint_t end); 186 187 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 188 pint_t datarelBase = 0); 189 bool findFunctionName(pint_t addr, char *buf, size_t bufLen, 190 unw_word_t *offset); 191 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); 192 bool findOtherFDE(pint_t targetAddr, pint_t &fde); 193 194 static LocalAddressSpace sThisAddressSpace; 195 }; 196 197 inline uintptr_t LocalAddressSpace::getP(pint_t addr) { 198 #if __SIZEOF_POINTER__ == 8 199 return get64(addr); 200 #else 201 return get32(addr); 202 #endif 203 } 204 205 inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { 206 #if __SIZEOF_POINTER__ == 8 || defined(__mips64) 207 return get64(addr); 208 #else 209 return get32(addr); 210 #endif 211 } 212 213 /// Read a ULEB128 into a 64-bit word. 214 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { 215 const uint8_t *p = (uint8_t *)addr; 216 const uint8_t *pend = (uint8_t *)end; 217 uint64_t result = 0; 218 int bit = 0; 219 do { 220 uint64_t b; 221 222 if (p == pend) 223 _LIBUNWIND_ABORT("truncated uleb128 expression"); 224 225 b = *p & 0x7f; 226 227 if (bit >= 64 || b << bit >> bit != b) { 228 _LIBUNWIND_ABORT("malformed uleb128 expression"); 229 } else { 230 result |= b << bit; 231 bit += 7; 232 } 233 } while (*p++ >= 0x80); 234 addr = (pint_t) p; 235 return result; 236 } 237 238 /// Read a SLEB128 into a 64-bit word. 239 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { 240 const uint8_t *p = (uint8_t *)addr; 241 const uint8_t *pend = (uint8_t *)end; 242 int64_t result = 0; 243 int bit = 0; 244 uint8_t byte; 245 do { 246 if (p == pend) 247 _LIBUNWIND_ABORT("truncated sleb128 expression"); 248 byte = *p++; 249 result |= (uint64_t)(byte & 0x7f) << bit; 250 bit += 7; 251 } while (byte & 0x80); 252 // sign extend negative numbers 253 if ((byte & 0x40) != 0 && bit < 64) 254 result |= (-1ULL) << bit; 255 addr = (pint_t) p; 256 return result; 257 } 258 259 inline LocalAddressSpace::pint_t 260 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 261 pint_t datarelBase) { 262 pint_t startAddr = addr; 263 const uint8_t *p = (uint8_t *)addr; 264 pint_t result; 265 266 // first get value 267 switch (encoding & 0x0F) { 268 case DW_EH_PE_ptr: 269 result = getP(addr); 270 p += sizeof(pint_t); 271 addr = (pint_t) p; 272 break; 273 case DW_EH_PE_uleb128: 274 result = (pint_t)getULEB128(addr, end); 275 break; 276 case DW_EH_PE_udata2: 277 result = get16(addr); 278 p += 2; 279 addr = (pint_t) p; 280 break; 281 case DW_EH_PE_udata4: 282 result = get32(addr); 283 p += 4; 284 addr = (pint_t) p; 285 break; 286 case DW_EH_PE_udata8: 287 result = (pint_t)get64(addr); 288 p += 8; 289 addr = (pint_t) p; 290 break; 291 case DW_EH_PE_sleb128: 292 result = (pint_t)getSLEB128(addr, end); 293 break; 294 case DW_EH_PE_sdata2: 295 // Sign extend from signed 16-bit value. 296 result = (pint_t)(int16_t)get16(addr); 297 p += 2; 298 addr = (pint_t) p; 299 break; 300 case DW_EH_PE_sdata4: 301 // Sign extend from signed 32-bit value. 302 result = (pint_t)(int32_t)get32(addr); 303 p += 4; 304 addr = (pint_t) p; 305 break; 306 case DW_EH_PE_sdata8: 307 result = (pint_t)get64(addr); 308 p += 8; 309 addr = (pint_t) p; 310 break; 311 default: 312 _LIBUNWIND_ABORT("unknown pointer encoding"); 313 } 314 315 // then add relative offset 316 switch (encoding & 0x70) { 317 case DW_EH_PE_absptr: 318 // do nothing 319 break; 320 case DW_EH_PE_pcrel: 321 result += startAddr; 322 break; 323 case DW_EH_PE_textrel: 324 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); 325 break; 326 case DW_EH_PE_datarel: 327 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a 328 // default value of 0, and we abort in the event that someone calls this 329 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. 330 if (datarelBase == 0) 331 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); 332 result += datarelBase; 333 break; 334 case DW_EH_PE_funcrel: 335 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); 336 break; 337 case DW_EH_PE_aligned: 338 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); 339 break; 340 default: 341 _LIBUNWIND_ABORT("unknown pointer encoding"); 342 break; 343 } 344 345 if (encoding & DW_EH_PE_indirect) 346 result = getP(result); 347 348 return result; 349 } 350 351 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) 352 353 // The ElfW() macro for pointer-size independent ELF header traversal is not 354 // provided by <link.h> on some systems (e.g., FreeBSD). On these systems the 355 // data structures are just called Elf_XXX. Define ElfW() locally. 356 #if !defined(ElfW) 357 #define ElfW(type) Elf_##type 358 #endif 359 #if !defined(Elf_Half) 360 typedef ElfW(Half) Elf_Half; 361 #endif 362 #if !defined(Elf_Phdr) 363 typedef ElfW(Phdr) Elf_Phdr; 364 #endif 365 #if !defined(Elf_Addr) 366 typedef ElfW(Addr) Elf_Addr; 367 #endif 368 369 static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) { 370 Elf_Addr image_base = pinfo->dlpi_addr; 371 #if defined(__ANDROID__) && __ANDROID_API__ < 18 372 if (image_base == 0) { 373 // Normally, an image base of 0 indicates a non-PIE executable. On 374 // versions of Android prior to API 18, the dynamic linker reported a 375 // dlpi_addr of 0 for PIE executables. Compute the true image base 376 // using the PT_PHDR segment. 377 // See https://github.com/android/ndk/issues/505. 378 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { 379 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; 380 if (phdr->p_type == PT_PHDR) { 381 image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) - 382 phdr->p_vaddr; 383 break; 384 } 385 } 386 } 387 #endif 388 return image_base; 389 } 390 391 struct _LIBUNWIND_HIDDEN dl_iterate_cb_data { 392 LocalAddressSpace *addressSpace; 393 UnwindInfoSections *sects; 394 uintptr_t targetAddr; 395 }; 396 397 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) 398 #include "FrameHeaderCache.hpp" 399 400 // Typically there is one cache per process, but when libunwind is built as a 401 // hermetic static library, then each shared object may have its own cache. 402 static FrameHeaderCache TheFrameHeaderCache; 403 #endif 404 405 static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base, 406 dl_iterate_cb_data *cbdata) { 407 if (phdr->p_type == PT_LOAD) { 408 uintptr_t begin = image_base + phdr->p_vaddr; 409 uintptr_t end = begin + phdr->p_memsz; 410 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { 411 cbdata->sects->dso_base = begin; 412 cbdata->sects->text_segment_length = phdr->p_memsz; 413 return true; 414 } 415 } 416 return false; 417 } 418 419 static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base, 420 dl_iterate_cb_data *cbdata) { 421 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 422 if (phdr->p_type == PT_GNU_EH_FRAME) { 423 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; 424 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr; 425 cbdata->sects->dwarf_index_section = eh_frame_hdr_start; 426 cbdata->sects->dwarf_index_section_length = phdr->p_memsz; 427 if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr( 428 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, 429 hdrInfo)) { 430 // .eh_frame_hdr records the start of .eh_frame, but not its size. 431 // Rely on a zero terminator to find the end of the section. 432 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; 433 cbdata->sects->dwarf_section_length = UINTPTR_MAX; 434 return true; 435 } 436 } 437 return false; 438 #elif defined(_LIBUNWIND_ARM_EHABI) 439 if (phdr->p_type == PT_ARM_EXIDX) { 440 uintptr_t exidx_start = image_base + phdr->p_vaddr; 441 cbdata->sects->arm_section = exidx_start; 442 cbdata->sects->arm_section_length = phdr->p_memsz; 443 return true; 444 } 445 return false; 446 #else 447 #error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI 448 #endif 449 } 450 451 static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, 452 size_t pinfo_size, void *data) { 453 auto cbdata = static_cast<dl_iterate_cb_data *>(data); 454 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr) 455 return 0; 456 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) 457 if (TheFrameHeaderCache.find(pinfo, pinfo_size, data)) 458 return 1; 459 #else 460 // Avoid warning about unused variable. 461 (void)pinfo_size; 462 #endif 463 464 Elf_Addr image_base = calculateImageBase(pinfo); 465 466 // Most shared objects seen in this callback function likely don't contain the 467 // target address, so optimize for that. Scan for a matching PT_LOAD segment 468 // first and bail when it isn't found. 469 bool found_text = false; 470 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) { 471 if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) { 472 found_text = true; 473 break; 474 } 475 } 476 if (!found_text) 477 return 0; 478 479 // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate 480 // backward. 481 bool found_unwind = false; 482 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) { 483 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1]; 484 if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) { 485 found_unwind = true; 486 break; 487 } 488 } 489 if (!found_unwind) 490 return 0; 491 492 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) 493 TheFrameHeaderCache.add(cbdata->sects); 494 #endif 495 return 1; 496 } 497 498 #endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) 499 500 501 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, 502 UnwindInfoSections &info) { 503 #ifdef __APPLE__ 504 dyld_unwind_sections dyldInfo; 505 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { 506 info.dso_base = (uintptr_t)dyldInfo.mh; 507 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 508 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; 509 info.dwarf_section_length = dyldInfo.dwarf_section_length; 510 #endif 511 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; 512 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; 513 return true; 514 } 515 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) 516 info.dso_base = 0; 517 // Bare metal is statically linked, so no need to ask the dynamic loader 518 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); 519 info.dwarf_section = (uintptr_t)(&__eh_frame_start); 520 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", 521 (void *)info.dwarf_section, (void *)info.dwarf_section_length); 522 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 523 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start); 524 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start); 525 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p", 526 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length); 527 #endif 528 if (info.dwarf_section_length) 529 return true; 530 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) 531 // Bare metal is statically linked, so no need to ask the dynamic loader 532 info.arm_section = (uintptr_t)(&__exidx_start); 533 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); 534 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", 535 (void *)info.arm_section, (void *)info.arm_section_length); 536 if (info.arm_section && info.arm_section_length) 537 return true; 538 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) 539 HMODULE mods[1024]; 540 HANDLE process = GetCurrentProcess(); 541 DWORD needed; 542 543 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) { 544 DWORD err = GetLastError(); 545 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, " 546 "returned error %d", (int)err); 547 return false; 548 } 549 550 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) { 551 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i]; 552 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew); 553 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader; 554 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); 555 bool found_obj = false; 556 bool found_hdr = false; 557 558 info.dso_base = (uintptr_t)mods[i]; 559 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) { 560 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i]; 561 uintptr_t end = begin + pish->Misc.VirtualSize; 562 if (!strncmp((const char *)pish->Name, ".text", 563 IMAGE_SIZEOF_SHORT_NAME)) { 564 if (targetAddr >= begin && targetAddr < end) 565 found_obj = true; 566 } else if (!strncmp((const char *)pish->Name, ".eh_frame", 567 IMAGE_SIZEOF_SHORT_NAME)) { 568 info.dwarf_section = begin; 569 info.dwarf_section_length = pish->Misc.VirtualSize; 570 found_hdr = true; 571 } 572 if (found_obj && found_hdr) 573 return true; 574 } 575 } 576 return false; 577 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) 578 // Don't even bother, since Windows has functions that do all this stuff 579 // for us. 580 (void)targetAddr; 581 (void)info; 582 return true; 583 #elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) 584 int length = 0; 585 info.arm_section = 586 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); 587 info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry); 588 if (info.arm_section && info.arm_section_length) 589 return true; 590 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) 591 dl_iterate_cb_data cb_data = {this, &info, targetAddr}; 592 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data); 593 return static_cast<bool>(found); 594 #endif 595 596 return false; 597 } 598 599 600 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { 601 // TO DO: if OS has way to dynamically register FDEs, check that. 602 (void)targetAddr; 603 (void)fde; 604 return false; 605 } 606 607 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, 608 size_t bufLen, 609 unw_word_t *offset) { 610 #if _LIBUNWIND_USE_DLADDR 611 Dl_info dyldInfo; 612 if (dladdr((void *)addr, &dyldInfo)) { 613 if (dyldInfo.dli_sname != NULL) { 614 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); 615 *offset = (addr - (pint_t) dyldInfo.dli_saddr); 616 return true; 617 } 618 } 619 #else 620 (void)addr; 621 (void)buf; 622 (void)bufLen; 623 (void)offset; 624 #endif 625 return false; 626 } 627 628 } // namespace libunwind 629 630 #endif // __ADDRESSSPACE_HPP__ 631