xref: /freebsd/contrib/llvm-project/libunwind/src/AddressSpace.hpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric // Abstracts accessing local vs remote address spaces.
90b57cec5SDimitry Andric //
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #ifndef __ADDRESSSPACE_HPP__
130b57cec5SDimitry Andric #define __ADDRESSSPACE_HPP__
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include <stdint.h>
160b57cec5SDimitry Andric #include <stdio.h>
170b57cec5SDimitry Andric #include <stdlib.h>
180b57cec5SDimitry Andric #include <string.h>
190b57cec5SDimitry Andric 
20e8d8bef9SDimitry Andric #include "libunwind.h"
21e8d8bef9SDimitry Andric #include "config.h"
22e8d8bef9SDimitry Andric #include "dwarf2.h"
23e8d8bef9SDimitry Andric #include "EHHeaderParser.hpp"
24e8d8bef9SDimitry Andric #include "Registers.hpp"
25e8d8bef9SDimitry Andric 
260b57cec5SDimitry Andric #ifndef _LIBUNWIND_USE_DLADDR
2781ad6265SDimitry Andric   #if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX))
280b57cec5SDimitry Andric     #define _LIBUNWIND_USE_DLADDR 1
290b57cec5SDimitry Andric   #else
300b57cec5SDimitry Andric     #define _LIBUNWIND_USE_DLADDR 0
310b57cec5SDimitry Andric   #endif
320b57cec5SDimitry Andric #endif
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric #if _LIBUNWIND_USE_DLADDR
350b57cec5SDimitry Andric #include <dlfcn.h>
36480093f4SDimitry Andric #if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
370b57cec5SDimitry Andric #pragma comment(lib, "dl")
380b57cec5SDimitry Andric #endif
390b57cec5SDimitry Andric #endif
400b57cec5SDimitry Andric 
41c2c6a179SDimitry Andric #if defined(_LIBUNWIND_ARM_EHABI)
42c2c6a179SDimitry Andric struct EHABIIndexEntry {
43c2c6a179SDimitry Andric   uint32_t functionOffset;
44c2c6a179SDimitry Andric   uint32_t data;
45c2c6a179SDimitry Andric };
46c2c6a179SDimitry Andric #endif
47c2c6a179SDimitry Andric 
4881ad6265SDimitry Andric #if defined(_AIX)
4981ad6265SDimitry Andric namespace libunwind {
5081ad6265SDimitry Andric char *getFuncNameFromTBTable(uintptr_t pc, uint16_t &NameLen,
5181ad6265SDimitry Andric                              unw_word_t *offset);
5281ad6265SDimitry Andric }
5381ad6265SDimitry Andric #endif
5481ad6265SDimitry Andric 
550b57cec5SDimitry Andric #ifdef __APPLE__
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   struct dyld_unwind_sections
580b57cec5SDimitry Andric   {
590b57cec5SDimitry Andric     const struct mach_header*   mh;
600b57cec5SDimitry Andric     const void*                 dwarf_section;
610b57cec5SDimitry Andric     uintptr_t                   dwarf_section_length;
620b57cec5SDimitry Andric     const void*                 compact_unwind_section;
630b57cec5SDimitry Andric     uintptr_t                   compact_unwind_section_length;
640b57cec5SDimitry Andric   };
65e8d8bef9SDimitry Andric 
660b57cec5SDimitry Andric   // In 10.7.0 or later, libSystem.dylib implements this function.
670b57cec5SDimitry Andric   extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
680b57cec5SDimitry Andric 
6906c3fb27SDimitry Andric namespace libunwind {
7006c3fb27SDimitry Andric   bool findDynamicUnwindSections(void *, unw_dynamic_unwind_sections *);
7106c3fb27SDimitry Andric }
7206c3fb27SDimitry Andric 
730b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric // When statically linked on bare-metal, the symbols for the EH table are looked
760b57cec5SDimitry Andric // up without going through the dynamic loader.
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric // The following linker script may be used to produce the necessary sections and symbols.
790b57cec5SDimitry Andric // Unless the --eh-frame-hdr linker option is provided, the section is not generated
800b57cec5SDimitry Andric // and does not take space in the output file.
810b57cec5SDimitry Andric //
820b57cec5SDimitry Andric //   .eh_frame :
830b57cec5SDimitry Andric //   {
840b57cec5SDimitry Andric //       __eh_frame_start = .;
850b57cec5SDimitry Andric //       KEEP(*(.eh_frame))
860b57cec5SDimitry Andric //       __eh_frame_end = .;
870b57cec5SDimitry Andric //   }
880b57cec5SDimitry Andric //
890b57cec5SDimitry Andric //   .eh_frame_hdr :
900b57cec5SDimitry Andric //   {
910b57cec5SDimitry Andric //       KEEP(*(.eh_frame_hdr))
920b57cec5SDimitry Andric //   }
930b57cec5SDimitry Andric //
940b57cec5SDimitry Andric //   __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
950b57cec5SDimitry Andric //   __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric extern char __eh_frame_start;
980b57cec5SDimitry Andric extern char __eh_frame_end;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
1010b57cec5SDimitry Andric extern char __eh_frame_hdr_start;
1020b57cec5SDimitry Andric extern char __eh_frame_hdr_end;
1030b57cec5SDimitry Andric #endif
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric // When statically linked on bare-metal, the symbols for the EH table are looked
1080b57cec5SDimitry Andric // up without going through the dynamic loader.
1090b57cec5SDimitry Andric extern char __exidx_start;
1100b57cec5SDimitry Andric extern char __exidx_end;
1110b57cec5SDimitry Andric 
112e8d8bef9SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric #include <windows.h>
1150b57cec5SDimitry Andric #include <psapi.h>
116e8d8bef9SDimitry Andric 
117e8d8bef9SDimitry Andric #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) ||                               \
118e8d8bef9SDimitry Andric       defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
119e8d8bef9SDimitry Andric 
120e8d8bef9SDimitry Andric #include <link.h>
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric #endif
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric namespace libunwind {
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric /// Used by findUnwindSections() to return info about needed sections.
1270b57cec5SDimitry Andric struct UnwindInfoSections {
128e8d8bef9SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) ||                                \
129e8d8bef9SDimitry Andric     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) ||                              \
130e8d8bef9SDimitry Andric     defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
131e8d8bef9SDimitry Andric   // No dso_base for SEH.
1320b57cec5SDimitry Andric   uintptr_t       dso_base;
1330b57cec5SDimitry Andric #endif
134e8d8bef9SDimitry Andric #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
13504eeddc0SDimitry Andric   size_t          text_segment_length;
136e8d8bef9SDimitry Andric #endif
1370b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
1380b57cec5SDimitry Andric   uintptr_t       dwarf_section;
13904eeddc0SDimitry Andric   size_t          dwarf_section_length;
1400b57cec5SDimitry Andric #endif
1410b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
1420b57cec5SDimitry Andric   uintptr_t       dwarf_index_section;
14304eeddc0SDimitry Andric   size_t          dwarf_index_section_length;
1440b57cec5SDimitry Andric #endif
1450b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
1460b57cec5SDimitry Andric   uintptr_t       compact_unwind_section;
14704eeddc0SDimitry Andric   size_t          compact_unwind_section_length;
1480b57cec5SDimitry Andric #endif
1490b57cec5SDimitry Andric #if defined(_LIBUNWIND_ARM_EHABI)
1500b57cec5SDimitry Andric   uintptr_t       arm_section;
15104eeddc0SDimitry Andric   size_t          arm_section_length;
1520b57cec5SDimitry Andric #endif
1530b57cec5SDimitry Andric };
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric /// LocalAddressSpace is used as a template parameter to UnwindCursor when
1570b57cec5SDimitry Andric /// unwinding a thread in the same process.  The wrappers compile away,
1580b57cec5SDimitry Andric /// making local unwinds fast.
1590b57cec5SDimitry Andric class _LIBUNWIND_HIDDEN LocalAddressSpace {
1600b57cec5SDimitry Andric public:
1610b57cec5SDimitry Andric   typedef uintptr_t pint_t;
1620b57cec5SDimitry Andric   typedef intptr_t  sint_t;
1630b57cec5SDimitry Andric   uint8_t         get8(pint_t addr) {
1640b57cec5SDimitry Andric     uint8_t val;
1650b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
1660b57cec5SDimitry Andric     return val;
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric   uint16_t         get16(pint_t addr) {
1690b57cec5SDimitry Andric     uint16_t val;
1700b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
1710b57cec5SDimitry Andric     return val;
1720b57cec5SDimitry Andric   }
1730b57cec5SDimitry Andric   uint32_t         get32(pint_t addr) {
1740b57cec5SDimitry Andric     uint32_t val;
1750b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
1760b57cec5SDimitry Andric     return val;
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric   uint64_t         get64(pint_t addr) {
1790b57cec5SDimitry Andric     uint64_t val;
1800b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
1810b57cec5SDimitry Andric     return val;
1820b57cec5SDimitry Andric   }
1830b57cec5SDimitry Andric   double           getDouble(pint_t addr) {
1840b57cec5SDimitry Andric     double val;
1850b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
1860b57cec5SDimitry Andric     return val;
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric   v128             getVector(pint_t addr) {
1890b57cec5SDimitry Andric     v128 val;
1900b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
1910b57cec5SDimitry Andric     return val;
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric   uintptr_t       getP(pint_t addr);
1940b57cec5SDimitry Andric   uint64_t        getRegister(pint_t addr);
1950b57cec5SDimitry Andric   static uint64_t getULEB128(pint_t &addr, pint_t end);
1960b57cec5SDimitry Andric   static int64_t  getSLEB128(pint_t &addr, pint_t end);
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
1990b57cec5SDimitry Andric                      pint_t datarelBase = 0);
2000b57cec5SDimitry Andric   bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
2010b57cec5SDimitry Andric                         unw_word_t *offset);
2020b57cec5SDimitry Andric   bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
2030b57cec5SDimitry Andric   bool findOtherFDE(pint_t targetAddr, pint_t &fde);
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   static LocalAddressSpace sThisAddressSpace;
2060b57cec5SDimitry Andric };
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
2090b57cec5SDimitry Andric #if __SIZEOF_POINTER__ == 8
2100b57cec5SDimitry Andric   return get64(addr);
2110b57cec5SDimitry Andric #else
2120b57cec5SDimitry Andric   return get32(addr);
2130b57cec5SDimitry Andric #endif
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
2170b57cec5SDimitry Andric #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
2180b57cec5SDimitry Andric   return get64(addr);
2190b57cec5SDimitry Andric #else
2200b57cec5SDimitry Andric   return get32(addr);
2210b57cec5SDimitry Andric #endif
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric /// Read a ULEB128 into a 64-bit word.
2250b57cec5SDimitry Andric inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
2260b57cec5SDimitry Andric   const uint8_t *p = (uint8_t *)addr;
2270b57cec5SDimitry Andric   const uint8_t *pend = (uint8_t *)end;
2280b57cec5SDimitry Andric   uint64_t result = 0;
2290b57cec5SDimitry Andric   int bit = 0;
2300b57cec5SDimitry Andric   do {
2310b57cec5SDimitry Andric     uint64_t b;
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric     if (p == pend)
2340b57cec5SDimitry Andric       _LIBUNWIND_ABORT("truncated uleb128 expression");
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric     b = *p & 0x7f;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric     if (bit >= 64 || b << bit >> bit != b) {
2390b57cec5SDimitry Andric       _LIBUNWIND_ABORT("malformed uleb128 expression");
2400b57cec5SDimitry Andric     } else {
2410b57cec5SDimitry Andric       result |= b << bit;
2420b57cec5SDimitry Andric       bit += 7;
2430b57cec5SDimitry Andric     }
2440b57cec5SDimitry Andric   } while (*p++ >= 0x80);
2450b57cec5SDimitry Andric   addr = (pint_t) p;
2460b57cec5SDimitry Andric   return result;
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric /// Read a SLEB128 into a 64-bit word.
2500b57cec5SDimitry Andric inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
2510b57cec5SDimitry Andric   const uint8_t *p = (uint8_t *)addr;
2520b57cec5SDimitry Andric   const uint8_t *pend = (uint8_t *)end;
253bdd1243dSDimitry Andric   uint64_t result = 0;
2540b57cec5SDimitry Andric   int bit = 0;
2550b57cec5SDimitry Andric   uint8_t byte;
2560b57cec5SDimitry Andric   do {
2570b57cec5SDimitry Andric     if (p == pend)
2580b57cec5SDimitry Andric       _LIBUNWIND_ABORT("truncated sleb128 expression");
2590b57cec5SDimitry Andric     byte = *p++;
260e8d8bef9SDimitry Andric     result |= (uint64_t)(byte & 0x7f) << bit;
2610b57cec5SDimitry Andric     bit += 7;
2620b57cec5SDimitry Andric   } while (byte & 0x80);
2630b57cec5SDimitry Andric   // sign extend negative numbers
264e8d8bef9SDimitry Andric   if ((byte & 0x40) != 0 && bit < 64)
2650b57cec5SDimitry Andric     result |= (-1ULL) << bit;
2660b57cec5SDimitry Andric   addr = (pint_t) p;
267bdd1243dSDimitry Andric   return (int64_t)result;
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric inline LocalAddressSpace::pint_t
2710b57cec5SDimitry Andric LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
2720b57cec5SDimitry Andric                                pint_t datarelBase) {
2730b57cec5SDimitry Andric   pint_t startAddr = addr;
2740b57cec5SDimitry Andric   const uint8_t *p = (uint8_t *)addr;
2750b57cec5SDimitry Andric   pint_t result;
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   // first get value
2780b57cec5SDimitry Andric   switch (encoding & 0x0F) {
2790b57cec5SDimitry Andric   case DW_EH_PE_ptr:
2800b57cec5SDimitry Andric     result = getP(addr);
2810b57cec5SDimitry Andric     p += sizeof(pint_t);
2820b57cec5SDimitry Andric     addr = (pint_t) p;
2830b57cec5SDimitry Andric     break;
2840b57cec5SDimitry Andric   case DW_EH_PE_uleb128:
2850b57cec5SDimitry Andric     result = (pint_t)getULEB128(addr, end);
2860b57cec5SDimitry Andric     break;
2870b57cec5SDimitry Andric   case DW_EH_PE_udata2:
2880b57cec5SDimitry Andric     result = get16(addr);
2890b57cec5SDimitry Andric     p += 2;
2900b57cec5SDimitry Andric     addr = (pint_t) p;
2910b57cec5SDimitry Andric     break;
2920b57cec5SDimitry Andric   case DW_EH_PE_udata4:
2930b57cec5SDimitry Andric     result = get32(addr);
2940b57cec5SDimitry Andric     p += 4;
2950b57cec5SDimitry Andric     addr = (pint_t) p;
2960b57cec5SDimitry Andric     break;
2970b57cec5SDimitry Andric   case DW_EH_PE_udata8:
2980b57cec5SDimitry Andric     result = (pint_t)get64(addr);
2990b57cec5SDimitry Andric     p += 8;
3000b57cec5SDimitry Andric     addr = (pint_t) p;
3010b57cec5SDimitry Andric     break;
3020b57cec5SDimitry Andric   case DW_EH_PE_sleb128:
3030b57cec5SDimitry Andric     result = (pint_t)getSLEB128(addr, end);
3040b57cec5SDimitry Andric     break;
3050b57cec5SDimitry Andric   case DW_EH_PE_sdata2:
3060b57cec5SDimitry Andric     // Sign extend from signed 16-bit value.
3070b57cec5SDimitry Andric     result = (pint_t)(int16_t)get16(addr);
3080b57cec5SDimitry Andric     p += 2;
3090b57cec5SDimitry Andric     addr = (pint_t) p;
3100b57cec5SDimitry Andric     break;
3110b57cec5SDimitry Andric   case DW_EH_PE_sdata4:
3120b57cec5SDimitry Andric     // Sign extend from signed 32-bit value.
3130b57cec5SDimitry Andric     result = (pint_t)(int32_t)get32(addr);
3140b57cec5SDimitry Andric     p += 4;
3150b57cec5SDimitry Andric     addr = (pint_t) p;
3160b57cec5SDimitry Andric     break;
3170b57cec5SDimitry Andric   case DW_EH_PE_sdata8:
3180b57cec5SDimitry Andric     result = (pint_t)get64(addr);
3190b57cec5SDimitry Andric     p += 8;
3200b57cec5SDimitry Andric     addr = (pint_t) p;
3210b57cec5SDimitry Andric     break;
3220b57cec5SDimitry Andric   default:
3230b57cec5SDimitry Andric     _LIBUNWIND_ABORT("unknown pointer encoding");
3240b57cec5SDimitry Andric   }
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric   // then add relative offset
3270b57cec5SDimitry Andric   switch (encoding & 0x70) {
3280b57cec5SDimitry Andric   case DW_EH_PE_absptr:
3290b57cec5SDimitry Andric     // do nothing
3300b57cec5SDimitry Andric     break;
3310b57cec5SDimitry Andric   case DW_EH_PE_pcrel:
3320b57cec5SDimitry Andric     result += startAddr;
3330b57cec5SDimitry Andric     break;
3340b57cec5SDimitry Andric   case DW_EH_PE_textrel:
3350b57cec5SDimitry Andric     _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
3360b57cec5SDimitry Andric     break;
3370b57cec5SDimitry Andric   case DW_EH_PE_datarel:
3380b57cec5SDimitry Andric     // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
3390b57cec5SDimitry Andric     // default value of 0, and we abort in the event that someone calls this
3400b57cec5SDimitry Andric     // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
3410b57cec5SDimitry Andric     if (datarelBase == 0)
3420b57cec5SDimitry Andric       _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
3430b57cec5SDimitry Andric     result += datarelBase;
3440b57cec5SDimitry Andric     break;
3450b57cec5SDimitry Andric   case DW_EH_PE_funcrel:
3460b57cec5SDimitry Andric     _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
3470b57cec5SDimitry Andric     break;
3480b57cec5SDimitry Andric   case DW_EH_PE_aligned:
3490b57cec5SDimitry Andric     _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
3500b57cec5SDimitry Andric     break;
3510b57cec5SDimitry Andric   default:
3520b57cec5SDimitry Andric     _LIBUNWIND_ABORT("unknown pointer encoding");
3530b57cec5SDimitry Andric     break;
3540b57cec5SDimitry Andric   }
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric   if (encoding & DW_EH_PE_indirect)
3570b57cec5SDimitry Andric     result = getP(result);
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   return result;
3600b57cec5SDimitry Andric }
3610b57cec5SDimitry Andric 
362e8d8bef9SDimitry Andric #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
3635ffd83dbSDimitry Andric 
364e8d8bef9SDimitry Andric // The ElfW() macro for pointer-size independent ELF header traversal is not
365e8d8bef9SDimitry Andric // provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
366e8d8bef9SDimitry Andric // data structures are just called Elf_XXX. Define ElfW() locally.
367e8d8bef9SDimitry Andric #if !defined(ElfW)
368e8d8bef9SDimitry Andric   #define ElfW(type) Elf_##type
369e8d8bef9SDimitry Andric #endif
3705ffd83dbSDimitry Andric #if !defined(Elf_Half)
3715ffd83dbSDimitry Andric   typedef ElfW(Half) Elf_Half;
3725ffd83dbSDimitry Andric #endif
3735ffd83dbSDimitry Andric #if !defined(Elf_Phdr)
3745ffd83dbSDimitry Andric   typedef ElfW(Phdr) Elf_Phdr;
3755ffd83dbSDimitry Andric #endif
3765ffd83dbSDimitry Andric #if !defined(Elf_Addr)
3775ffd83dbSDimitry Andric   typedef ElfW(Addr) Elf_Addr;
3785ffd83dbSDimitry Andric #endif
3795ffd83dbSDimitry Andric 
3805ffd83dbSDimitry Andric struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
3815ffd83dbSDimitry Andric   LocalAddressSpace *addressSpace;
3825ffd83dbSDimitry Andric   UnwindInfoSections *sects;
3835ffd83dbSDimitry Andric   uintptr_t targetAddr;
3845ffd83dbSDimitry Andric };
3855ffd83dbSDimitry Andric 
3869ff1cc58SDimitry Andric #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
3875ffd83dbSDimitry Andric #include "FrameHeaderCache.hpp"
3885ffd83dbSDimitry Andric 
389e8d8bef9SDimitry Andric // Typically there is one cache per process, but when libunwind is built as a
390e8d8bef9SDimitry Andric // hermetic static library, then each shared object may have its own cache.
391e8d8bef9SDimitry Andric static FrameHeaderCache TheFrameHeaderCache;
39275b4d546SDimitry Andric #endif
3935ffd83dbSDimitry Andric 
3945ffd83dbSDimitry Andric static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
3955ffd83dbSDimitry Andric                                dl_iterate_cb_data *cbdata) {
3965ffd83dbSDimitry Andric   if (phdr->p_type == PT_LOAD) {
3975ffd83dbSDimitry Andric     uintptr_t begin = image_base + phdr->p_vaddr;
3985ffd83dbSDimitry Andric     uintptr_t end = begin + phdr->p_memsz;
3995ffd83dbSDimitry Andric     if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
4005ffd83dbSDimitry Andric       cbdata->sects->dso_base = begin;
401e8d8bef9SDimitry Andric       cbdata->sects->text_segment_length = phdr->p_memsz;
4025ffd83dbSDimitry Andric       return true;
4035ffd83dbSDimitry Andric     }
4045ffd83dbSDimitry Andric   }
4055ffd83dbSDimitry Andric   return false;
4065ffd83dbSDimitry Andric }
4075ffd83dbSDimitry Andric 
408e8d8bef9SDimitry Andric static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
409e8d8bef9SDimitry Andric                                       dl_iterate_cb_data *cbdata) {
410e8d8bef9SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
411e8d8bef9SDimitry Andric   if (phdr->p_type == PT_GNU_EH_FRAME) {
412e8d8bef9SDimitry Andric     EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
413e8d8bef9SDimitry Andric     uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
414e8d8bef9SDimitry Andric     cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
415e8d8bef9SDimitry Andric     cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
416e8d8bef9SDimitry Andric     if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
417*5f757f3fSDimitry Andric             *cbdata->addressSpace, eh_frame_hdr_start,
418*5f757f3fSDimitry Andric             eh_frame_hdr_start + phdr->p_memsz, hdrInfo)) {
419e8d8bef9SDimitry Andric       // .eh_frame_hdr records the start of .eh_frame, but not its size.
420e8d8bef9SDimitry Andric       // Rely on a zero terminator to find the end of the section.
421e8d8bef9SDimitry Andric       cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
42204eeddc0SDimitry Andric       cbdata->sects->dwarf_section_length = SIZE_MAX;
423e8d8bef9SDimitry Andric       return true;
424e8d8bef9SDimitry Andric     }
425e8d8bef9SDimitry Andric   }
426e8d8bef9SDimitry Andric   return false;
427e8d8bef9SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI)
428e8d8bef9SDimitry Andric   if (phdr->p_type == PT_ARM_EXIDX) {
429e8d8bef9SDimitry Andric     uintptr_t exidx_start = image_base + phdr->p_vaddr;
430e8d8bef9SDimitry Andric     cbdata->sects->arm_section = exidx_start;
431e8d8bef9SDimitry Andric     cbdata->sects->arm_section_length = phdr->p_memsz;
432e8d8bef9SDimitry Andric     return true;
433e8d8bef9SDimitry Andric   }
434e8d8bef9SDimitry Andric   return false;
435e8d8bef9SDimitry Andric #else
436e8d8bef9SDimitry Andric #error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
437e8d8bef9SDimitry Andric #endif
438e8d8bef9SDimitry Andric }
439e8d8bef9SDimitry Andric 
44016d6b3b3SDimitry Andric static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
44116d6b3b3SDimitry Andric                                     size_t pinfo_size, void *data) {
4425ffd83dbSDimitry Andric   auto cbdata = static_cast<dl_iterate_cb_data *>(data);
4435ffd83dbSDimitry Andric   if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
4445ffd83dbSDimitry Andric     return 0;
4459ff1cc58SDimitry Andric #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
446e8d8bef9SDimitry Andric   if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
4475ffd83dbSDimitry Andric     return 1;
448e8d8bef9SDimitry Andric #else
449e8d8bef9SDimitry Andric   // Avoid warning about unused variable.
450e8d8bef9SDimitry Andric   (void)pinfo_size;
45175b4d546SDimitry Andric #endif
4525ffd83dbSDimitry Andric 
453bdd1243dSDimitry Andric   Elf_Addr image_base = pinfo->dlpi_addr;
4545ffd83dbSDimitry Andric 
455e8d8bef9SDimitry Andric   // Most shared objects seen in this callback function likely don't contain the
456e8d8bef9SDimitry Andric   // target address, so optimize for that. Scan for a matching PT_LOAD segment
457e8d8bef9SDimitry Andric   // first and bail when it isn't found.
458e8d8bef9SDimitry Andric   bool found_text = false;
459e8d8bef9SDimitry Andric   for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
460e8d8bef9SDimitry Andric     if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
461e8d8bef9SDimitry Andric       found_text = true;
462e8d8bef9SDimitry Andric       break;
463e8d8bef9SDimitry Andric     }
464e8d8bef9SDimitry Andric   }
465e8d8bef9SDimitry Andric   if (!found_text)
466e8d8bef9SDimitry Andric     return 0;
4675ffd83dbSDimitry Andric 
468e8d8bef9SDimitry Andric   // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
469e8d8bef9SDimitry Andric   // backward.
470e8d8bef9SDimitry Andric   bool found_unwind = false;
4715ffd83dbSDimitry Andric   for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
4725ffd83dbSDimitry Andric     const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
473e8d8bef9SDimitry Andric     if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
474e8d8bef9SDimitry Andric       found_unwind = true;
475e8d8bef9SDimitry Andric       break;
4765ffd83dbSDimitry Andric     }
477e8d8bef9SDimitry Andric   }
478e8d8bef9SDimitry Andric   if (!found_unwind)
479e8d8bef9SDimitry Andric     return 0;
480e8d8bef9SDimitry Andric 
4819ff1cc58SDimitry Andric #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
482e8d8bef9SDimitry Andric   TheFrameHeaderCache.add(cbdata->sects);
48375b4d546SDimitry Andric #endif
4845ffd83dbSDimitry Andric   return 1;
4855ffd83dbSDimitry Andric }
4865ffd83dbSDimitry Andric 
487e8d8bef9SDimitry Andric #endif  // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
4885ffd83dbSDimitry Andric 
4895ffd83dbSDimitry Andric 
4900b57cec5SDimitry Andric inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
4910b57cec5SDimitry Andric                                                   UnwindInfoSections &info) {
4920b57cec5SDimitry Andric #ifdef __APPLE__
4930b57cec5SDimitry Andric   dyld_unwind_sections dyldInfo;
4940b57cec5SDimitry Andric   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
4950b57cec5SDimitry Andric     info.dso_base                      = (uintptr_t)dyldInfo.mh;
4960b57cec5SDimitry Andric  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
4970b57cec5SDimitry Andric     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
49804eeddc0SDimitry Andric     info.dwarf_section_length          = (size_t)dyldInfo.dwarf_section_length;
4990b57cec5SDimitry Andric  #endif
5000b57cec5SDimitry Andric     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
50104eeddc0SDimitry Andric     info.compact_unwind_section_length = (size_t)dyldInfo.compact_unwind_section_length;
5020b57cec5SDimitry Andric     return true;
5030b57cec5SDimitry Andric   }
50406c3fb27SDimitry Andric 
50506c3fb27SDimitry Andric   unw_dynamic_unwind_sections dynamicUnwindSectionInfo;
50606c3fb27SDimitry Andric   if (findDynamicUnwindSections((void *)targetAddr,
50706c3fb27SDimitry Andric                                 &dynamicUnwindSectionInfo)) {
50806c3fb27SDimitry Andric     info.dso_base = dynamicUnwindSectionInfo.dso_base;
50906c3fb27SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
51006c3fb27SDimitry Andric     info.dwarf_section = (uintptr_t)dynamicUnwindSectionInfo.dwarf_section;
51106c3fb27SDimitry Andric     info.dwarf_section_length = dynamicUnwindSectionInfo.dwarf_section_length;
51206c3fb27SDimitry Andric #endif
51306c3fb27SDimitry Andric     info.compact_unwind_section =
51406c3fb27SDimitry Andric         (uintptr_t)dynamicUnwindSectionInfo.compact_unwind_section;
51506c3fb27SDimitry Andric     info.compact_unwind_section_length =
51606c3fb27SDimitry Andric         dynamicUnwindSectionInfo.compact_unwind_section_length;
51706c3fb27SDimitry Andric     return true;
51806c3fb27SDimitry Andric   }
51906c3fb27SDimitry Andric 
5200b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
521e8d8bef9SDimitry Andric   info.dso_base = 0;
5220b57cec5SDimitry Andric   // Bare metal is statically linked, so no need to ask the dynamic loader
52304eeddc0SDimitry Andric   info.dwarf_section_length = (size_t)(&__eh_frame_end - &__eh_frame_start);
5240b57cec5SDimitry Andric   info.dwarf_section =        (uintptr_t)(&__eh_frame_start);
5250b57cec5SDimitry Andric   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
5260b57cec5SDimitry Andric                              (void *)info.dwarf_section, (void *)info.dwarf_section_length);
5270b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
5280b57cec5SDimitry Andric   info.dwarf_index_section =        (uintptr_t)(&__eh_frame_hdr_start);
52904eeddc0SDimitry Andric   info.dwarf_index_section_length = (size_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
5300b57cec5SDimitry Andric   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
5310b57cec5SDimitry Andric                              (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
5320b57cec5SDimitry Andric #endif
5330b57cec5SDimitry Andric   if (info.dwarf_section_length)
5340b57cec5SDimitry Andric     return true;
5350b57cec5SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
5360b57cec5SDimitry Andric   // Bare metal is statically linked, so no need to ask the dynamic loader
5370b57cec5SDimitry Andric   info.arm_section =        (uintptr_t)(&__exidx_start);
53804eeddc0SDimitry Andric   info.arm_section_length = (size_t)(&__exidx_end - &__exidx_start);
5390b57cec5SDimitry Andric   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
5400b57cec5SDimitry Andric                              (void *)info.arm_section, (void *)info.arm_section_length);
5410b57cec5SDimitry Andric   if (info.arm_section && info.arm_section_length)
5420b57cec5SDimitry Andric     return true;
5430b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
5440b57cec5SDimitry Andric   HMODULE mods[1024];
5450b57cec5SDimitry Andric   HANDLE process = GetCurrentProcess();
5460b57cec5SDimitry Andric   DWORD needed;
5470b57cec5SDimitry Andric 
548480093f4SDimitry Andric   if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
549480093f4SDimitry Andric     DWORD err = GetLastError();
550480093f4SDimitry Andric     _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
551480093f4SDimitry Andric                                "returned error %d", (int)err);
55281ad6265SDimitry Andric     (void)err;
5530b57cec5SDimitry Andric     return false;
554480093f4SDimitry Andric   }
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric   for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
5570b57cec5SDimitry Andric     PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
5580b57cec5SDimitry Andric     PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
5590b57cec5SDimitry Andric     PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
5600b57cec5SDimitry Andric     PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
5610b57cec5SDimitry Andric     bool found_obj = false;
5620b57cec5SDimitry Andric     bool found_hdr = false;
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric     info.dso_base = (uintptr_t)mods[i];
5650b57cec5SDimitry Andric     for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
5660b57cec5SDimitry Andric       uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
5670b57cec5SDimitry Andric       uintptr_t end = begin + pish->Misc.VirtualSize;
5680b57cec5SDimitry Andric       if (!strncmp((const char *)pish->Name, ".text",
5690b57cec5SDimitry Andric                    IMAGE_SIZEOF_SHORT_NAME)) {
5700b57cec5SDimitry Andric         if (targetAddr >= begin && targetAddr < end)
5710b57cec5SDimitry Andric           found_obj = true;
5720b57cec5SDimitry Andric       } else if (!strncmp((const char *)pish->Name, ".eh_frame",
5730b57cec5SDimitry Andric                           IMAGE_SIZEOF_SHORT_NAME)) {
5740b57cec5SDimitry Andric         info.dwarf_section = begin;
5750b57cec5SDimitry Andric         info.dwarf_section_length = pish->Misc.VirtualSize;
5760b57cec5SDimitry Andric         found_hdr = true;
5770b57cec5SDimitry Andric       }
5780b57cec5SDimitry Andric       if (found_obj && found_hdr)
5790b57cec5SDimitry Andric         return true;
5800b57cec5SDimitry Andric     }
5810b57cec5SDimitry Andric   }
5820b57cec5SDimitry Andric   return false;
5830b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
5840b57cec5SDimitry Andric   // Don't even bother, since Windows has functions that do all this stuff
5850b57cec5SDimitry Andric   // for us.
5860b57cec5SDimitry Andric   (void)targetAddr;
5870b57cec5SDimitry Andric   (void)info;
5880b57cec5SDimitry Andric   return true;
58981ad6265SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
59081ad6265SDimitry Andric   // The traceback table is used for unwinding.
59181ad6265SDimitry Andric   (void)targetAddr;
59281ad6265SDimitry Andric   (void)info;
59381ad6265SDimitry Andric   return true;
594e8d8bef9SDimitry Andric #elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
5950b57cec5SDimitry Andric   int length = 0;
5960b57cec5SDimitry Andric   info.arm_section =
5970b57cec5SDimitry Andric       (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
59804eeddc0SDimitry Andric   info.arm_section_length = (size_t)length * sizeof(EHABIIndexEntry);
5990b57cec5SDimitry Andric   if (info.arm_section && info.arm_section_length)
6000b57cec5SDimitry Andric     return true;
601e8d8bef9SDimitry Andric #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
602bdd1243dSDimitry Andric   // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
603bdd1243dSDimitry Andric   // `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
604bdd1243dSDimitry Andric   // support for _dl_find_object on other unwind formats is not implemented,
605bdd1243dSDimitry Andric   // yet.
606bdd1243dSDimitry Andric #if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
607bdd1243dSDimitry Andric   // We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
608bdd1243dSDimitry Andric #if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
609bdd1243dSDimitry Andric #error _dl_find_object retrieves an unexpected section type
610bdd1243dSDimitry Andric #endif
611bdd1243dSDimitry Andric   // We look-up `dl_find_object` dynamically at runtime to ensure backwards
612bdd1243dSDimitry Andric   // compatibility with earlier version of glibc not yet providing it. On older
613bdd1243dSDimitry Andric   // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
614bdd1243dSDimitry Andric   // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
615bdd1243dSDimitry Andric   static decltype(_dl_find_object) *dlFindObject;
616bdd1243dSDimitry Andric   static bool dlFindObjectChecked = false;
617bdd1243dSDimitry Andric   if (!dlFindObjectChecked) {
618bdd1243dSDimitry Andric     dlFindObject = reinterpret_cast<decltype(_dl_find_object) *>(
619bdd1243dSDimitry Andric         dlsym(RTLD_DEFAULT, "_dl_find_object"));
620bdd1243dSDimitry Andric     dlFindObjectChecked = true;
621bdd1243dSDimitry Andric   }
622bdd1243dSDimitry Andric   // Try to find the unwind info using `dl_find_object`
623bdd1243dSDimitry Andric   dl_find_object findResult;
624bdd1243dSDimitry Andric   if (dlFindObject && dlFindObject((void *)targetAddr, &findResult) == 0) {
625bdd1243dSDimitry Andric     if (findResult.dlfo_eh_frame == nullptr) {
626bdd1243dSDimitry Andric       // Found an entry for `targetAddr`, but there is no unwind info.
627bdd1243dSDimitry Andric       return false;
628bdd1243dSDimitry Andric     }
629bdd1243dSDimitry Andric     info.dso_base = reinterpret_cast<uintptr_t>(findResult.dlfo_map_start);
630bdd1243dSDimitry Andric     info.text_segment_length = static_cast<size_t>(
631bdd1243dSDimitry Andric         (char *)findResult.dlfo_map_end - (char *)findResult.dlfo_map_start);
632bdd1243dSDimitry Andric 
633bdd1243dSDimitry Andric     // Record the start of PT_GNU_EH_FRAME.
634bdd1243dSDimitry Andric     info.dwarf_index_section =
635bdd1243dSDimitry Andric         reinterpret_cast<uintptr_t>(findResult.dlfo_eh_frame);
636bdd1243dSDimitry Andric     // `_dl_find_object` does not give us the size of PT_GNU_EH_FRAME.
637bdd1243dSDimitry Andric     // Setting length to `SIZE_MAX` effectively disables all range checks.
638bdd1243dSDimitry Andric     info.dwarf_index_section_length = SIZE_MAX;
639bdd1243dSDimitry Andric     EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
640bdd1243dSDimitry Andric     if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
641*5f757f3fSDimitry Andric             *this, info.dwarf_index_section,
642*5f757f3fSDimitry Andric             info.dwarf_index_section + info.dwarf_index_section_length,
643bdd1243dSDimitry Andric             hdrInfo)) {
644bdd1243dSDimitry Andric       return false;
645bdd1243dSDimitry Andric     }
646bdd1243dSDimitry Andric     // Record the start of the FDE and use SIZE_MAX to indicate that we do
647bdd1243dSDimitry Andric     // not know the end address.
648bdd1243dSDimitry Andric     info.dwarf_section = hdrInfo.eh_frame_ptr;
649bdd1243dSDimitry Andric     info.dwarf_section_length = SIZE_MAX;
650bdd1243dSDimitry Andric     return true;
651bdd1243dSDimitry Andric   }
652bdd1243dSDimitry Andric #endif
6530b57cec5SDimitry Andric   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
6545ffd83dbSDimitry Andric   int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
6550b57cec5SDimitry Andric   return static_cast<bool>(found);
6560b57cec5SDimitry Andric #endif
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric   return false;
6590b57cec5SDimitry Andric }
6600b57cec5SDimitry Andric 
6610b57cec5SDimitry Andric inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
6620b57cec5SDimitry Andric   // TO DO: if OS has way to dynamically register FDEs, check that.
6630b57cec5SDimitry Andric   (void)targetAddr;
6640b57cec5SDimitry Andric   (void)fde;
6650b57cec5SDimitry Andric   return false;
6660b57cec5SDimitry Andric }
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
6690b57cec5SDimitry Andric                                                 size_t bufLen,
6700b57cec5SDimitry Andric                                                 unw_word_t *offset) {
6710b57cec5SDimitry Andric #if _LIBUNWIND_USE_DLADDR
6720b57cec5SDimitry Andric   Dl_info dyldInfo;
6730b57cec5SDimitry Andric   if (dladdr((void *)addr, &dyldInfo)) {
6740b57cec5SDimitry Andric     if (dyldInfo.dli_sname != NULL) {
6750b57cec5SDimitry Andric       snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
6760b57cec5SDimitry Andric       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
6770b57cec5SDimitry Andric       return true;
6780b57cec5SDimitry Andric     }
6790b57cec5SDimitry Andric   }
68081ad6265SDimitry Andric #elif defined(_AIX)
68181ad6265SDimitry Andric   uint16_t nameLen;
68281ad6265SDimitry Andric   char *funcName = getFuncNameFromTBTable(addr, nameLen, offset);
68381ad6265SDimitry Andric   if (funcName != NULL) {
68481ad6265SDimitry Andric     snprintf(buf, bufLen, "%.*s", nameLen, funcName);
68581ad6265SDimitry Andric     return true;
68681ad6265SDimitry Andric   }
6870b57cec5SDimitry Andric #else
6880b57cec5SDimitry Andric   (void)addr;
6890b57cec5SDimitry Andric   (void)buf;
6900b57cec5SDimitry Andric   (void)bufLen;
6910b57cec5SDimitry Andric   (void)offset;
6920b57cec5SDimitry Andric #endif
6930b57cec5SDimitry Andric   return false;
6940b57cec5SDimitry Andric }
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric } // namespace libunwind
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric #endif // __ADDRESSSPACE_HPP__
699