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