1 //===----------------------------------------------------------------------===//
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
8 // Abstracts accessing local vs remote address spaces.
10 //===----------------------------------------------------------------------===//
12 #ifndef __ADDRESSSPACE_HPP__
13 #define __ADDRESSSPACE_HPP__
20 #include "libunwind.h"
23 #include "EHHeaderParser.hpp"
24 #include "Registers.hpp"
26 #ifndef _LIBUNWIND_USE_DLADDR
27 #if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX))
28 #define _LIBUNWIND_USE_DLADDR 1
30 #define _LIBUNWIND_USE_DLADDR 0
34 #if _LIBUNWIND_USE_DLADDR
36 #if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
37 #pragma comment(lib, "dl")
41 #if defined(_LIBUNWIND_ARM_EHABI)
42 struct EHABIIndexEntry
{
43 uint32_t functionOffset
;
50 char *getFuncNameFromTBTable(uintptr_t pc
, uint16_t &NameLen
,
57 struct dyld_unwind_sections
59 const struct mach_header
* mh
;
60 const void* dwarf_section
;
61 uintptr_t dwarf_section_length
;
62 const void* compact_unwind_section
;
63 uintptr_t compact_unwind_section_length
;
66 // In 10.7.0 or later, libSystem.dylib implements this function.
67 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections
*);
70 bool findDynamicUnwindSections(void *, unw_dynamic_unwind_sections
*);
73 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
75 // When statically linked on bare-metal, the symbols for the EH table are looked
76 // up without going through the dynamic loader.
78 // The following linker script may be used to produce the necessary sections and symbols.
79 // Unless the --eh-frame-hdr linker option is provided, the section is not generated
80 // and does not take space in the output file.
84 // __eh_frame_start = .;
86 // __eh_frame_end = .;
91 // KEEP(*(.eh_frame_hdr))
94 // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
95 // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
97 extern char __eh_frame_start
;
98 extern char __eh_frame_end
;
100 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
101 extern char __eh_frame_hdr_start
;
102 extern char __eh_frame_hdr_end
;
105 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
107 // When statically linked on bare-metal, the symbols for the EH table are looked
108 // up without going through the dynamic loader.
109 extern char __exidx_start
;
110 extern char __exidx_end
;
112 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
117 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \
118 defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
124 namespace libunwind
{
126 /// Used by findUnwindSections() to return info about needed sections.
127 struct UnwindInfoSections
{
128 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \
129 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
130 defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
131 // No dso_base for SEH.
134 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
135 size_t text_segment_length
;
137 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
138 uintptr_t dwarf_section
;
139 size_t dwarf_section_length
;
141 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
142 uintptr_t dwarf_index_section
;
143 size_t dwarf_index_section_length
;
145 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
146 uintptr_t compact_unwind_section
;
147 size_t compact_unwind_section_length
;
149 #if defined(_LIBUNWIND_ARM_EHABI)
150 uintptr_t arm_section
;
151 size_t arm_section_length
;
156 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
157 /// unwinding a thread in the same process. The wrappers compile away,
158 /// making local unwinds fast.
159 class _LIBUNWIND_HIDDEN LocalAddressSpace
{
161 typedef uintptr_t pint_t
;
162 typedef intptr_t sint_t
;
163 uint8_t get8(pint_t addr
) {
165 memcpy(&val
, (void *)addr
, sizeof(val
));
168 uint16_t get16(pint_t addr
) {
170 memcpy(&val
, (void *)addr
, sizeof(val
));
173 uint32_t get32(pint_t addr
) {
175 memcpy(&val
, (void *)addr
, sizeof(val
));
178 uint64_t get64(pint_t addr
) {
180 memcpy(&val
, (void *)addr
, sizeof(val
));
183 double getDouble(pint_t addr
) {
185 memcpy(&val
, (void *)addr
, sizeof(val
));
188 v128
getVector(pint_t addr
) {
190 memcpy(&val
, (void *)addr
, sizeof(val
));
193 uintptr_t getP(pint_t addr
);
194 uint64_t getRegister(pint_t addr
);
195 static uint64_t getULEB128(pint_t
&addr
, pint_t end
);
196 static int64_t getSLEB128(pint_t
&addr
, pint_t end
);
198 pint_t
getEncodedP(pint_t
&addr
, pint_t end
, uint8_t encoding
,
199 pint_t datarelBase
= 0);
200 bool findFunctionName(pint_t addr
, char *buf
, size_t bufLen
,
202 bool findUnwindSections(pint_t targetAddr
, UnwindInfoSections
&info
);
203 bool findOtherFDE(pint_t targetAddr
, pint_t
&fde
);
205 static LocalAddressSpace sThisAddressSpace
;
208 inline uintptr_t LocalAddressSpace::getP(pint_t addr
) {
209 #if __SIZEOF_POINTER__ == 8
216 inline uint64_t LocalAddressSpace::getRegister(pint_t addr
) {
217 #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
224 /// Read a ULEB128 into a 64-bit word.
225 inline uint64_t LocalAddressSpace::getULEB128(pint_t
&addr
, pint_t end
) {
226 const uint8_t *p
= (uint8_t *)addr
;
227 const uint8_t *pend
= (uint8_t *)end
;
234 _LIBUNWIND_ABORT("truncated uleb128 expression");
238 if (bit
>= 64 || b
<< bit
>> bit
!= b
) {
239 _LIBUNWIND_ABORT("malformed uleb128 expression");
244 } while (*p
++ >= 0x80);
249 /// Read a SLEB128 into a 64-bit word.
250 inline int64_t LocalAddressSpace::getSLEB128(pint_t
&addr
, pint_t end
) {
251 const uint8_t *p
= (uint8_t *)addr
;
252 const uint8_t *pend
= (uint8_t *)end
;
258 _LIBUNWIND_ABORT("truncated sleb128 expression");
260 result
|= (uint64_t)(byte
& 0x7f) << bit
;
262 } while (byte
& 0x80);
263 // sign extend negative numbers
264 if ((byte
& 0x40) != 0 && bit
< 64)
265 result
|= (-1ULL) << bit
;
267 return (int64_t)result
;
270 inline LocalAddressSpace::pint_t
271 LocalAddressSpace::getEncodedP(pint_t
&addr
, pint_t end
, uint8_t encoding
,
272 pint_t datarelBase
) {
273 pint_t startAddr
= addr
;
274 const uint8_t *p
= (uint8_t *)addr
;
278 switch (encoding
& 0x0F) {
284 case DW_EH_PE_uleb128
:
285 result
= (pint_t
)getULEB128(addr
, end
);
287 case DW_EH_PE_udata2
:
288 result
= get16(addr
);
292 case DW_EH_PE_udata4
:
293 result
= get32(addr
);
297 case DW_EH_PE_udata8
:
298 result
= (pint_t
)get64(addr
);
302 case DW_EH_PE_sleb128
:
303 result
= (pint_t
)getSLEB128(addr
, end
);
305 case DW_EH_PE_sdata2
:
306 // Sign extend from signed 16-bit value.
307 result
= (pint_t
)(int16_t)get16(addr
);
311 case DW_EH_PE_sdata4
:
312 // Sign extend from signed 32-bit value.
313 result
= (pint_t
)(int32_t)get32(addr
);
317 case DW_EH_PE_sdata8
:
318 result
= (pint_t
)get64(addr
);
323 _LIBUNWIND_ABORT("unknown pointer encoding");
326 // then add relative offset
327 switch (encoding
& 0x70) {
328 case DW_EH_PE_absptr
:
334 case DW_EH_PE_textrel
:
335 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
337 case DW_EH_PE_datarel
:
338 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
339 // default value of 0, and we abort in the event that someone calls this
340 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
341 if (datarelBase
== 0)
342 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
343 result
+= datarelBase
;
345 case DW_EH_PE_funcrel
:
346 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
348 case DW_EH_PE_aligned
:
349 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
352 _LIBUNWIND_ABORT("unknown pointer encoding");
356 if (encoding
& DW_EH_PE_indirect
)
357 result
= getP(result
);
362 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
364 // The ElfW() macro for pointer-size independent ELF header traversal is not
365 // provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
366 // data structures are just called Elf_XXX. Define ElfW() locally.
368 #define ElfW(type) Elf_##type
370 #if !defined(Elf_Half)
371 typedef ElfW(Half
) Elf_Half
;
373 #if !defined(Elf_Phdr)
374 typedef ElfW(Phdr
) Elf_Phdr
;
376 #if !defined(Elf_Addr)
377 typedef ElfW(Addr
) Elf_Addr
;
380 struct _LIBUNWIND_HIDDEN dl_iterate_cb_data
{
381 LocalAddressSpace
*addressSpace
;
382 UnwindInfoSections
*sects
;
383 uintptr_t targetAddr
;
386 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
387 #include "FrameHeaderCache.hpp"
389 // Typically there is one cache per process, but when libunwind is built as a
390 // hermetic static library, then each shared object may have its own cache.
391 static FrameHeaderCache TheFrameHeaderCache
;
394 static bool checkAddrInSegment(const Elf_Phdr
*phdr
, size_t image_base
,
395 dl_iterate_cb_data
*cbdata
) {
396 if (phdr
->p_type
== PT_LOAD
) {
397 uintptr_t begin
= image_base
+ phdr
->p_vaddr
;
398 uintptr_t end
= begin
+ phdr
->p_memsz
;
399 if (cbdata
->targetAddr
>= begin
&& cbdata
->targetAddr
< end
) {
400 cbdata
->sects
->dso_base
= begin
;
401 cbdata
->sects
->text_segment_length
= phdr
->p_memsz
;
408 static bool checkForUnwindInfoSegment(const Elf_Phdr
*phdr
, size_t image_base
,
409 dl_iterate_cb_data
*cbdata
) {
410 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
411 if (phdr
->p_type
== PT_GNU_EH_FRAME
) {
412 EHHeaderParser
<LocalAddressSpace
>::EHHeaderInfo hdrInfo
;
413 uintptr_t eh_frame_hdr_start
= image_base
+ phdr
->p_vaddr
;
414 cbdata
->sects
->dwarf_index_section
= eh_frame_hdr_start
;
415 cbdata
->sects
->dwarf_index_section_length
= phdr
->p_memsz
;
416 if (EHHeaderParser
<LocalAddressSpace
>::decodeEHHdr(
417 *cbdata
->addressSpace
, eh_frame_hdr_start
,
418 eh_frame_hdr_start
+ phdr
->p_memsz
, hdrInfo
)) {
419 // .eh_frame_hdr records the start of .eh_frame, but not its size.
420 // Rely on a zero terminator to find the end of the section.
421 cbdata
->sects
->dwarf_section
= hdrInfo
.eh_frame_ptr
;
422 cbdata
->sects
->dwarf_section_length
= SIZE_MAX
;
427 #elif defined(_LIBUNWIND_ARM_EHABI)
428 if (phdr
->p_type
== PT_ARM_EXIDX
) {
429 uintptr_t exidx_start
= image_base
+ phdr
->p_vaddr
;
430 cbdata
->sects
->arm_section
= exidx_start
;
431 cbdata
->sects
->arm_section_length
= phdr
->p_memsz
;
436 #error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
440 static int findUnwindSectionsByPhdr(struct dl_phdr_info
*pinfo
,
441 size_t pinfo_size
, void *data
) {
442 auto cbdata
= static_cast<dl_iterate_cb_data
*>(data
);
443 if (pinfo
->dlpi_phnum
== 0 || cbdata
->targetAddr
< pinfo
->dlpi_addr
)
445 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
446 if (TheFrameHeaderCache
.find(pinfo
, pinfo_size
, data
))
449 // Avoid warning about unused variable.
453 Elf_Addr image_base
= pinfo
->dlpi_addr
;
455 // Most shared objects seen in this callback function likely don't contain the
456 // target address, so optimize for that. Scan for a matching PT_LOAD segment
457 // first and bail when it isn't found.
458 bool found_text
= false;
459 for (Elf_Half i
= 0; i
< pinfo
->dlpi_phnum
; ++i
) {
460 if (checkAddrInSegment(&pinfo
->dlpi_phdr
[i
], image_base
, cbdata
)) {
468 // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
470 bool found_unwind
= false;
471 for (Elf_Half i
= pinfo
->dlpi_phnum
; i
> 0; i
--) {
472 const Elf_Phdr
*phdr
= &pinfo
->dlpi_phdr
[i
- 1];
473 if (checkForUnwindInfoSegment(phdr
, image_base
, cbdata
)) {
481 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
482 TheFrameHeaderCache
.add(cbdata
->sects
);
487 #endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
490 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr
,
491 UnwindInfoSections
&info
) {
493 dyld_unwind_sections dyldInfo
;
494 if (_dyld_find_unwind_sections((void *)targetAddr
, &dyldInfo
)) {
495 info
.dso_base
= (uintptr_t)dyldInfo
.mh
;
496 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
497 info
.dwarf_section
= (uintptr_t)dyldInfo
.dwarf_section
;
498 info
.dwarf_section_length
= (size_t)dyldInfo
.dwarf_section_length
;
500 info
.compact_unwind_section
= (uintptr_t)dyldInfo
.compact_unwind_section
;
501 info
.compact_unwind_section_length
= (size_t)dyldInfo
.compact_unwind_section_length
;
505 unw_dynamic_unwind_sections dynamicUnwindSectionInfo
;
506 if (findDynamicUnwindSections((void *)targetAddr
,
507 &dynamicUnwindSectionInfo
)) {
508 info
.dso_base
= dynamicUnwindSectionInfo
.dso_base
;
509 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
510 info
.dwarf_section
= (uintptr_t)dynamicUnwindSectionInfo
.dwarf_section
;
511 info
.dwarf_section_length
= dynamicUnwindSectionInfo
.dwarf_section_length
;
513 info
.compact_unwind_section
=
514 (uintptr_t)dynamicUnwindSectionInfo
.compact_unwind_section
;
515 info
.compact_unwind_section_length
=
516 dynamicUnwindSectionInfo
.compact_unwind_section_length
;
520 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
522 // Bare metal is statically linked, so no need to ask the dynamic loader
523 info
.dwarf_section_length
= (size_t)(&__eh_frame_end
- &__eh_frame_start
);
524 info
.dwarf_section
= (uintptr_t)(&__eh_frame_start
);
525 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
526 (void *)info
.dwarf_section
, (void *)info
.dwarf_section_length
);
527 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
528 info
.dwarf_index_section
= (uintptr_t)(&__eh_frame_hdr_start
);
529 info
.dwarf_index_section_length
= (size_t)(&__eh_frame_hdr_end
- &__eh_frame_hdr_start
);
530 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
531 (void *)info
.dwarf_index_section
, (void *)info
.dwarf_index_section_length
);
533 if (info
.dwarf_section_length
)
535 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
536 // Bare metal is statically linked, so no need to ask the dynamic loader
537 info
.arm_section
= (uintptr_t)(&__exidx_start
);
538 info
.arm_section_length
= (size_t)(&__exidx_end
- &__exidx_start
);
539 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
540 (void *)info
.arm_section
, (void *)info
.arm_section_length
);
541 if (info
.arm_section
&& info
.arm_section_length
)
543 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
545 HANDLE process
= GetCurrentProcess();
548 if (!EnumProcessModules(process
, mods
, sizeof(mods
), &needed
)) {
549 DWORD err
= GetLastError();
550 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
551 "returned error %d", (int)err
);
556 for (unsigned i
= 0; i
< (needed
/ sizeof(HMODULE
)); i
++) {
557 PIMAGE_DOS_HEADER pidh
= (PIMAGE_DOS_HEADER
)mods
[i
];
558 PIMAGE_NT_HEADERS pinh
= (PIMAGE_NT_HEADERS
)((BYTE
*)pidh
+ pidh
->e_lfanew
);
559 PIMAGE_FILE_HEADER pifh
= (PIMAGE_FILE_HEADER
)&pinh
->FileHeader
;
560 PIMAGE_SECTION_HEADER pish
= IMAGE_FIRST_SECTION(pinh
);
561 bool found_obj
= false;
562 bool found_hdr
= false;
564 info
.dso_base
= (uintptr_t)mods
[i
];
565 for (unsigned j
= 0; j
< pifh
->NumberOfSections
; j
++, pish
++) {
566 uintptr_t begin
= pish
->VirtualAddress
+ (uintptr_t)mods
[i
];
567 uintptr_t end
= begin
+ pish
->Misc
.VirtualSize
;
568 if (!strncmp((const char *)pish
->Name
, ".text",
569 IMAGE_SIZEOF_SHORT_NAME
)) {
570 if (targetAddr
>= begin
&& targetAddr
< end
)
572 } else if (!strncmp((const char *)pish
->Name
, ".eh_frame",
573 IMAGE_SIZEOF_SHORT_NAME
)) {
574 info
.dwarf_section
= begin
;
575 info
.dwarf_section_length
= pish
->Misc
.VirtualSize
;
578 if (found_obj
&& found_hdr
)
583 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
584 // Don't even bother, since Windows has functions that do all this stuff
589 #elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
590 // The traceback table is used for unwinding.
594 #elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
597 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr
)targetAddr
, &length
);
598 info
.arm_section_length
= (size_t)length
* sizeof(EHABIIndexEntry
);
599 if (info
.arm_section
&& info
.arm_section_length
)
601 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
602 // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
603 // `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
604 // support for _dl_find_object on other unwind formats is not implemented,
606 #if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
607 // We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
608 #if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
609 #error _dl_find_object retrieves an unexpected section type
611 // We look-up `dl_find_object` dynamically at runtime to ensure backwards
612 // compatibility with earlier version of glibc not yet providing it. On older
613 // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
614 // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
615 static decltype(_dl_find_object
) *dlFindObject
;
616 static bool dlFindObjectChecked
= false;
617 if (!dlFindObjectChecked
) {
618 dlFindObject
= reinterpret_cast<decltype(_dl_find_object
) *>(
619 dlsym(RTLD_DEFAULT
, "_dl_find_object"));
620 dlFindObjectChecked
= true;
622 // Try to find the unwind info using `dl_find_object`
623 dl_find_object findResult
;
624 if (dlFindObject
&& dlFindObject((void *)targetAddr
, &findResult
) == 0) {
625 if (findResult
.dlfo_eh_frame
== nullptr) {
626 // Found an entry for `targetAddr`, but there is no unwind info.
629 info
.dso_base
= reinterpret_cast<uintptr_t>(findResult
.dlfo_map_start
);
630 info
.text_segment_length
= static_cast<size_t>(
631 (char *)findResult
.dlfo_map_end
- (char *)findResult
.dlfo_map_start
);
633 // Record the start of PT_GNU_EH_FRAME.
634 info
.dwarf_index_section
=
635 reinterpret_cast<uintptr_t>(findResult
.dlfo_eh_frame
);
636 // `_dl_find_object` does not give us the size of PT_GNU_EH_FRAME.
637 // Setting length to `SIZE_MAX` effectively disables all range checks.
638 info
.dwarf_index_section_length
= SIZE_MAX
;
639 EHHeaderParser
<LocalAddressSpace
>::EHHeaderInfo hdrInfo
;
640 if (!EHHeaderParser
<LocalAddressSpace
>::decodeEHHdr(
641 *this, info
.dwarf_index_section
,
642 info
.dwarf_index_section
+ info
.dwarf_index_section_length
,
646 // Record the start of the FDE and use SIZE_MAX to indicate that we do
647 // not know the end address.
648 info
.dwarf_section
= hdrInfo
.eh_frame_ptr
;
649 info
.dwarf_section_length
= SIZE_MAX
;
653 dl_iterate_cb_data cb_data
= {this, &info
, targetAddr
};
654 int found
= dl_iterate_phdr(findUnwindSectionsByPhdr
, &cb_data
);
655 return static_cast<bool>(found
);
661 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr
, pint_t
&fde
) {
662 // TO DO: if OS has way to dynamically register FDEs, check that.
668 inline bool LocalAddressSpace::findFunctionName(pint_t addr
, char *buf
,
670 unw_word_t
*offset
) {
671 #if _LIBUNWIND_USE_DLADDR
673 if (dladdr((void *)addr
, &dyldInfo
)) {
674 if (dyldInfo
.dli_sname
!= NULL
) {
675 snprintf(buf
, bufLen
, "%s", dyldInfo
.dli_sname
);
676 *offset
= (addr
- (pint_t
) dyldInfo
.dli_saddr
);
682 char *funcName
= getFuncNameFromTBTable(addr
, nameLen
, offset
);
683 if (funcName
!= NULL
) {
684 snprintf(buf
, bufLen
, "%.*s", nameLen
, funcName
);
696 } // namespace libunwind
698 #endif // __ADDRESSSPACE_HPP__