xref: /freebsd/contrib/llvm-project/libunwind/src/AddressSpace.hpp (revision 75b4d546cd9d9f62a5a3466e6df5629262aef7b1)
10b57cec5SDimitry Andric //===------------------------- AddressSpace.hpp ---------------------------===//
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 
200b57cec5SDimitry Andric #ifndef _LIBUNWIND_USE_DLADDR
210b57cec5SDimitry Andric   #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
220b57cec5SDimitry Andric     #define _LIBUNWIND_USE_DLADDR 1
230b57cec5SDimitry Andric   #else
240b57cec5SDimitry Andric     #define _LIBUNWIND_USE_DLADDR 0
250b57cec5SDimitry Andric   #endif
260b57cec5SDimitry Andric #endif
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #if _LIBUNWIND_USE_DLADDR
290b57cec5SDimitry Andric #include <dlfcn.h>
30480093f4SDimitry Andric #if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
310b57cec5SDimitry Andric #pragma comment(lib, "dl")
320b57cec5SDimitry Andric #endif
330b57cec5SDimitry Andric #endif
340b57cec5SDimitry Andric 
35c2c6a179SDimitry Andric #if defined(_LIBUNWIND_ARM_EHABI)
36c2c6a179SDimitry Andric struct EHABIIndexEntry {
37c2c6a179SDimitry Andric   uint32_t functionOffset;
38c2c6a179SDimitry Andric   uint32_t data;
39c2c6a179SDimitry Andric };
40c2c6a179SDimitry Andric #endif
41c2c6a179SDimitry Andric 
420b57cec5SDimitry Andric #ifdef __APPLE__
430b57cec5SDimitry Andric #include <mach-o/getsect.h>
440b57cec5SDimitry Andric namespace libunwind {
450b57cec5SDimitry Andric    bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric #endif
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric #include "libunwind.h"
500b57cec5SDimitry Andric #include "config.h"
510b57cec5SDimitry Andric #include "dwarf2.h"
520b57cec5SDimitry Andric #include "EHHeaderParser.hpp"
530b57cec5SDimitry Andric #include "Registers.hpp"
540b57cec5SDimitry 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   };
650b57cec5SDimitry Andric   #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
660b57cec5SDimitry Andric                                  && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
670b57cec5SDimitry Andric       || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
680b57cec5SDimitry Andric     // In 10.7.0 or later, libSystem.dylib implements this function.
690b57cec5SDimitry Andric     extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
700b57cec5SDimitry Andric   #else
710b57cec5SDimitry Andric     // In 10.6.x and earlier, we need to implement this functionality. Note
720b57cec5SDimitry Andric     // that this requires a newer version of libmacho (from cctools) than is
730b57cec5SDimitry Andric     // present in libSystem on 10.6.x (for getsectiondata).
740b57cec5SDimitry Andric     static inline bool _dyld_find_unwind_sections(void* addr,
750b57cec5SDimitry Andric                                                     dyld_unwind_sections* info) {
760b57cec5SDimitry Andric       // Find mach-o image containing address.
770b57cec5SDimitry Andric       Dl_info dlinfo;
780b57cec5SDimitry Andric       if (!dladdr(addr, &dlinfo))
790b57cec5SDimitry Andric         return false;
800b57cec5SDimitry Andric #if __LP64__
810b57cec5SDimitry Andric       const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
820b57cec5SDimitry Andric #else
830b57cec5SDimitry Andric       const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
840b57cec5SDimitry Andric #endif
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric       // Initialize the return struct
870b57cec5SDimitry Andric       info->mh = (const struct mach_header *)mh;
880b57cec5SDimitry Andric       info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
890b57cec5SDimitry Andric       info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric       if (!info->dwarf_section) {
920b57cec5SDimitry Andric         info->dwarf_section_length = 0;
930b57cec5SDimitry Andric       }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric       if (!info->compact_unwind_section) {
960b57cec5SDimitry Andric         info->compact_unwind_section_length = 0;
970b57cec5SDimitry Andric       }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric       return true;
1000b57cec5SDimitry Andric     }
1010b57cec5SDimitry Andric   #endif
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric // When statically linked on bare-metal, the symbols for the EH table are looked
1060b57cec5SDimitry Andric // up without going through the dynamic loader.
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric // The following linker script may be used to produce the necessary sections and symbols.
1090b57cec5SDimitry Andric // Unless the --eh-frame-hdr linker option is provided, the section is not generated
1100b57cec5SDimitry Andric // and does not take space in the output file.
1110b57cec5SDimitry Andric //
1120b57cec5SDimitry Andric //   .eh_frame :
1130b57cec5SDimitry Andric //   {
1140b57cec5SDimitry Andric //       __eh_frame_start = .;
1150b57cec5SDimitry Andric //       KEEP(*(.eh_frame))
1160b57cec5SDimitry Andric //       __eh_frame_end = .;
1170b57cec5SDimitry Andric //   }
1180b57cec5SDimitry Andric //
1190b57cec5SDimitry Andric //   .eh_frame_hdr :
1200b57cec5SDimitry Andric //   {
1210b57cec5SDimitry Andric //       KEEP(*(.eh_frame_hdr))
1220b57cec5SDimitry Andric //   }
1230b57cec5SDimitry Andric //
1240b57cec5SDimitry Andric //   __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
1250b57cec5SDimitry Andric //   __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric extern char __eh_frame_start;
1280b57cec5SDimitry Andric extern char __eh_frame_end;
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
1310b57cec5SDimitry Andric extern char __eh_frame_hdr_start;
1320b57cec5SDimitry Andric extern char __eh_frame_hdr_end;
1330b57cec5SDimitry Andric #endif
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric // When statically linked on bare-metal, the symbols for the EH table are looked
1380b57cec5SDimitry Andric // up without going through the dynamic loader.
1390b57cec5SDimitry Andric extern char __exidx_start;
1400b57cec5SDimitry Andric extern char __exidx_end;
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric // ELF-based systems may use dl_iterate_phdr() to access sections
1450b57cec5SDimitry Andric // containing unwinding information. The ElfW() macro for pointer-size
1460b57cec5SDimitry Andric // independent ELF header traversal is not provided by <link.h> on some
1470b57cec5SDimitry Andric // systems (e.g., FreeBSD). On these systems the data structures are
1480b57cec5SDimitry Andric // just called Elf_XXX. Define ElfW() locally.
1490b57cec5SDimitry Andric #ifndef _WIN32
1500b57cec5SDimitry Andric #include <link.h>
1510b57cec5SDimitry Andric #else
1520b57cec5SDimitry Andric #include <windows.h>
1530b57cec5SDimitry Andric #include <psapi.h>
1540b57cec5SDimitry Andric #endif
1550b57cec5SDimitry Andric #if !defined(ElfW)
1560b57cec5SDimitry Andric #define ElfW(type) Elf_##type
1570b57cec5SDimitry Andric #endif
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric #endif
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric namespace libunwind {
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric /// Used by findUnwindSections() to return info about needed sections.
1640b57cec5SDimitry Andric struct UnwindInfoSections {
1650b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) ||       \
1660b57cec5SDimitry Andric     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
1670b57cec5SDimitry Andric   // No dso_base for SEH or ARM EHABI.
1680b57cec5SDimitry Andric   uintptr_t       dso_base;
1690b57cec5SDimitry Andric #endif
1700b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
1710b57cec5SDimitry Andric   uintptr_t       dwarf_section;
1720b57cec5SDimitry Andric   uintptr_t       dwarf_section_length;
1730b57cec5SDimitry Andric #endif
1740b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
1750b57cec5SDimitry Andric   uintptr_t       dwarf_index_section;
1760b57cec5SDimitry Andric   uintptr_t       dwarf_index_section_length;
1770b57cec5SDimitry Andric #endif
1780b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
1790b57cec5SDimitry Andric   uintptr_t       compact_unwind_section;
1800b57cec5SDimitry Andric   uintptr_t       compact_unwind_section_length;
1810b57cec5SDimitry Andric #endif
1820b57cec5SDimitry Andric #if defined(_LIBUNWIND_ARM_EHABI)
1830b57cec5SDimitry Andric   uintptr_t       arm_section;
1840b57cec5SDimitry Andric   uintptr_t       arm_section_length;
1850b57cec5SDimitry Andric #endif
1860b57cec5SDimitry Andric };
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric /// LocalAddressSpace is used as a template parameter to UnwindCursor when
1900b57cec5SDimitry Andric /// unwinding a thread in the same process.  The wrappers compile away,
1910b57cec5SDimitry Andric /// making local unwinds fast.
1920b57cec5SDimitry Andric class _LIBUNWIND_HIDDEN LocalAddressSpace {
1930b57cec5SDimitry Andric public:
1940b57cec5SDimitry Andric   typedef uintptr_t pint_t;
1950b57cec5SDimitry Andric   typedef intptr_t  sint_t;
1960b57cec5SDimitry Andric   uint8_t         get8(pint_t addr) {
1970b57cec5SDimitry Andric     uint8_t val;
1980b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
1990b57cec5SDimitry Andric     return val;
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric   uint16_t         get16(pint_t addr) {
2020b57cec5SDimitry Andric     uint16_t val;
2030b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
2040b57cec5SDimitry Andric     return val;
2050b57cec5SDimitry Andric   }
2060b57cec5SDimitry Andric   uint32_t         get32(pint_t addr) {
2070b57cec5SDimitry Andric     uint32_t val;
2080b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
2090b57cec5SDimitry Andric     return val;
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric   uint64_t         get64(pint_t addr) {
2120b57cec5SDimitry Andric     uint64_t val;
2130b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
2140b57cec5SDimitry Andric     return val;
2150b57cec5SDimitry Andric   }
2160b57cec5SDimitry Andric   double           getDouble(pint_t addr) {
2170b57cec5SDimitry Andric     double val;
2180b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
2190b57cec5SDimitry Andric     return val;
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric   v128             getVector(pint_t addr) {
2220b57cec5SDimitry Andric     v128 val;
2230b57cec5SDimitry Andric     memcpy(&val, (void *)addr, sizeof(val));
2240b57cec5SDimitry Andric     return val;
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric   uintptr_t       getP(pint_t addr);
2270b57cec5SDimitry Andric   uint64_t        getRegister(pint_t addr);
2280b57cec5SDimitry Andric   static uint64_t getULEB128(pint_t &addr, pint_t end);
2290b57cec5SDimitry Andric   static int64_t  getSLEB128(pint_t &addr, pint_t end);
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
2320b57cec5SDimitry Andric                      pint_t datarelBase = 0);
2330b57cec5SDimitry Andric   bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
2340b57cec5SDimitry Andric                         unw_word_t *offset);
2350b57cec5SDimitry Andric   bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
2360b57cec5SDimitry Andric   bool findOtherFDE(pint_t targetAddr, pint_t &fde);
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   static LocalAddressSpace sThisAddressSpace;
2390b57cec5SDimitry Andric };
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
2420b57cec5SDimitry Andric #if __SIZEOF_POINTER__ == 8
2430b57cec5SDimitry Andric   return get64(addr);
2440b57cec5SDimitry Andric #else
2450b57cec5SDimitry Andric   return get32(addr);
2460b57cec5SDimitry Andric #endif
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
2500b57cec5SDimitry Andric #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
2510b57cec5SDimitry Andric   return get64(addr);
2520b57cec5SDimitry Andric #else
2530b57cec5SDimitry Andric   return get32(addr);
2540b57cec5SDimitry Andric #endif
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric /// Read a ULEB128 into a 64-bit word.
2580b57cec5SDimitry Andric inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
2590b57cec5SDimitry Andric   const uint8_t *p = (uint8_t *)addr;
2600b57cec5SDimitry Andric   const uint8_t *pend = (uint8_t *)end;
2610b57cec5SDimitry Andric   uint64_t result = 0;
2620b57cec5SDimitry Andric   int bit = 0;
2630b57cec5SDimitry Andric   do {
2640b57cec5SDimitry Andric     uint64_t b;
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric     if (p == pend)
2670b57cec5SDimitry Andric       _LIBUNWIND_ABORT("truncated uleb128 expression");
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric     b = *p & 0x7f;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric     if (bit >= 64 || b << bit >> bit != b) {
2720b57cec5SDimitry Andric       _LIBUNWIND_ABORT("malformed uleb128 expression");
2730b57cec5SDimitry Andric     } else {
2740b57cec5SDimitry Andric       result |= b << bit;
2750b57cec5SDimitry Andric       bit += 7;
2760b57cec5SDimitry Andric     }
2770b57cec5SDimitry Andric   } while (*p++ >= 0x80);
2780b57cec5SDimitry Andric   addr = (pint_t) p;
2790b57cec5SDimitry Andric   return result;
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric /// Read a SLEB128 into a 64-bit word.
2830b57cec5SDimitry Andric inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
2840b57cec5SDimitry Andric   const uint8_t *p = (uint8_t *)addr;
2850b57cec5SDimitry Andric   const uint8_t *pend = (uint8_t *)end;
2860b57cec5SDimitry Andric   int64_t result = 0;
2870b57cec5SDimitry Andric   int bit = 0;
2880b57cec5SDimitry Andric   uint8_t byte;
2890b57cec5SDimitry Andric   do {
2900b57cec5SDimitry Andric     if (p == pend)
2910b57cec5SDimitry Andric       _LIBUNWIND_ABORT("truncated sleb128 expression");
2920b57cec5SDimitry Andric     byte = *p++;
2930b57cec5SDimitry Andric     result |= ((byte & 0x7f) << bit);
2940b57cec5SDimitry Andric     bit += 7;
2950b57cec5SDimitry Andric   } while (byte & 0x80);
2960b57cec5SDimitry Andric   // sign extend negative numbers
2970b57cec5SDimitry Andric   if ((byte & 0x40) != 0)
2980b57cec5SDimitry Andric     result |= (-1ULL) << bit;
2990b57cec5SDimitry Andric   addr = (pint_t) p;
3000b57cec5SDimitry Andric   return result;
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric inline LocalAddressSpace::pint_t
3040b57cec5SDimitry Andric LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
3050b57cec5SDimitry Andric                                pint_t datarelBase) {
3060b57cec5SDimitry Andric   pint_t startAddr = addr;
3070b57cec5SDimitry Andric   const uint8_t *p = (uint8_t *)addr;
3080b57cec5SDimitry Andric   pint_t result;
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   // first get value
3110b57cec5SDimitry Andric   switch (encoding & 0x0F) {
3120b57cec5SDimitry Andric   case DW_EH_PE_ptr:
3130b57cec5SDimitry Andric     result = getP(addr);
3140b57cec5SDimitry Andric     p += sizeof(pint_t);
3150b57cec5SDimitry Andric     addr = (pint_t) p;
3160b57cec5SDimitry Andric     break;
3170b57cec5SDimitry Andric   case DW_EH_PE_uleb128:
3180b57cec5SDimitry Andric     result = (pint_t)getULEB128(addr, end);
3190b57cec5SDimitry Andric     break;
3200b57cec5SDimitry Andric   case DW_EH_PE_udata2:
3210b57cec5SDimitry Andric     result = get16(addr);
3220b57cec5SDimitry Andric     p += 2;
3230b57cec5SDimitry Andric     addr = (pint_t) p;
3240b57cec5SDimitry Andric     break;
3250b57cec5SDimitry Andric   case DW_EH_PE_udata4:
3260b57cec5SDimitry Andric     result = get32(addr);
3270b57cec5SDimitry Andric     p += 4;
3280b57cec5SDimitry Andric     addr = (pint_t) p;
3290b57cec5SDimitry Andric     break;
3300b57cec5SDimitry Andric   case DW_EH_PE_udata8:
3310b57cec5SDimitry Andric     result = (pint_t)get64(addr);
3320b57cec5SDimitry Andric     p += 8;
3330b57cec5SDimitry Andric     addr = (pint_t) p;
3340b57cec5SDimitry Andric     break;
3350b57cec5SDimitry Andric   case DW_EH_PE_sleb128:
3360b57cec5SDimitry Andric     result = (pint_t)getSLEB128(addr, end);
3370b57cec5SDimitry Andric     break;
3380b57cec5SDimitry Andric   case DW_EH_PE_sdata2:
3390b57cec5SDimitry Andric     // Sign extend from signed 16-bit value.
3400b57cec5SDimitry Andric     result = (pint_t)(int16_t)get16(addr);
3410b57cec5SDimitry Andric     p += 2;
3420b57cec5SDimitry Andric     addr = (pint_t) p;
3430b57cec5SDimitry Andric     break;
3440b57cec5SDimitry Andric   case DW_EH_PE_sdata4:
3450b57cec5SDimitry Andric     // Sign extend from signed 32-bit value.
3460b57cec5SDimitry Andric     result = (pint_t)(int32_t)get32(addr);
3470b57cec5SDimitry Andric     p += 4;
3480b57cec5SDimitry Andric     addr = (pint_t) p;
3490b57cec5SDimitry Andric     break;
3500b57cec5SDimitry Andric   case DW_EH_PE_sdata8:
3510b57cec5SDimitry Andric     result = (pint_t)get64(addr);
3520b57cec5SDimitry Andric     p += 8;
3530b57cec5SDimitry Andric     addr = (pint_t) p;
3540b57cec5SDimitry Andric     break;
3550b57cec5SDimitry Andric   default:
3560b57cec5SDimitry Andric     _LIBUNWIND_ABORT("unknown pointer encoding");
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   // then add relative offset
3600b57cec5SDimitry Andric   switch (encoding & 0x70) {
3610b57cec5SDimitry Andric   case DW_EH_PE_absptr:
3620b57cec5SDimitry Andric     // do nothing
3630b57cec5SDimitry Andric     break;
3640b57cec5SDimitry Andric   case DW_EH_PE_pcrel:
3650b57cec5SDimitry Andric     result += startAddr;
3660b57cec5SDimitry Andric     break;
3670b57cec5SDimitry Andric   case DW_EH_PE_textrel:
3680b57cec5SDimitry Andric     _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
3690b57cec5SDimitry Andric     break;
3700b57cec5SDimitry Andric   case DW_EH_PE_datarel:
3710b57cec5SDimitry Andric     // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
3720b57cec5SDimitry Andric     // default value of 0, and we abort in the event that someone calls this
3730b57cec5SDimitry Andric     // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
3740b57cec5SDimitry Andric     if (datarelBase == 0)
3750b57cec5SDimitry Andric       _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
3760b57cec5SDimitry Andric     result += datarelBase;
3770b57cec5SDimitry Andric     break;
3780b57cec5SDimitry Andric   case DW_EH_PE_funcrel:
3790b57cec5SDimitry Andric     _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
3800b57cec5SDimitry Andric     break;
3810b57cec5SDimitry Andric   case DW_EH_PE_aligned:
3820b57cec5SDimitry Andric     _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
3830b57cec5SDimitry Andric     break;
3840b57cec5SDimitry Andric   default:
3850b57cec5SDimitry Andric     _LIBUNWIND_ABORT("unknown pointer encoding");
3860b57cec5SDimitry Andric     break;
3870b57cec5SDimitry Andric   }
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   if (encoding & DW_EH_PE_indirect)
3900b57cec5SDimitry Andric     result = getP(result);
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   return result;
3930b57cec5SDimitry Andric }
3940b57cec5SDimitry Andric 
3955ffd83dbSDimitry Andric #ifdef __APPLE__
3965ffd83dbSDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
3975ffd83dbSDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
3985ffd83dbSDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
3995ffd83dbSDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
4005ffd83dbSDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
4015ffd83dbSDimitry Andric // Code inside findUnwindSections handles all these cases.
4025ffd83dbSDimitry Andric //
4035ffd83dbSDimitry Andric // Although the above ifdef chain is ugly, there doesn't seem to be a cleaner
4045ffd83dbSDimitry Andric // way to handle it. The generalized boolean expression is:
4055ffd83dbSDimitry Andric //
4065ffd83dbSDimitry Andric //  A OR (B AND C) OR (D AND C) OR (B AND E) OR (F AND E) OR (D AND G)
4075ffd83dbSDimitry Andric //
4085ffd83dbSDimitry Andric // Running it through various boolean expression simplifiers gives expressions
4095ffd83dbSDimitry Andric // that don't help at all.
4105ffd83dbSDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
4115ffd83dbSDimitry Andric 
4125ffd83dbSDimitry Andric #if !defined(Elf_Half)
4135ffd83dbSDimitry Andric   typedef ElfW(Half) Elf_Half;
4145ffd83dbSDimitry Andric #endif
4155ffd83dbSDimitry Andric #if !defined(Elf_Phdr)
4165ffd83dbSDimitry Andric   typedef ElfW(Phdr) Elf_Phdr;
4175ffd83dbSDimitry Andric #endif
4185ffd83dbSDimitry Andric #if !defined(Elf_Addr)
4195ffd83dbSDimitry Andric   typedef ElfW(Addr) Elf_Addr;
4205ffd83dbSDimitry Andric #endif
4215ffd83dbSDimitry Andric 
4225ffd83dbSDimitry Andric static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
4235ffd83dbSDimitry Andric   Elf_Addr image_base = pinfo->dlpi_addr;
4245ffd83dbSDimitry Andric #if defined(__ANDROID__) && __ANDROID_API__ < 18
4255ffd83dbSDimitry Andric   if (image_base == 0) {
4265ffd83dbSDimitry Andric     // Normally, an image base of 0 indicates a non-PIE executable. On
4275ffd83dbSDimitry Andric     // versions of Android prior to API 18, the dynamic linker reported a
4285ffd83dbSDimitry Andric     // dlpi_addr of 0 for PIE executables. Compute the true image base
4295ffd83dbSDimitry Andric     // using the PT_PHDR segment.
4305ffd83dbSDimitry Andric     // See https://github.com/android/ndk/issues/505.
4315ffd83dbSDimitry Andric     for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
4325ffd83dbSDimitry Andric       const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
4335ffd83dbSDimitry Andric       if (phdr->p_type == PT_PHDR) {
4345ffd83dbSDimitry Andric         image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
4355ffd83dbSDimitry Andric           phdr->p_vaddr;
4365ffd83dbSDimitry Andric         break;
4375ffd83dbSDimitry Andric       }
4385ffd83dbSDimitry Andric     }
4395ffd83dbSDimitry Andric   }
4405ffd83dbSDimitry Andric #endif
4415ffd83dbSDimitry Andric   return image_base;
4425ffd83dbSDimitry Andric }
4435ffd83dbSDimitry Andric 
4445ffd83dbSDimitry Andric struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
4455ffd83dbSDimitry Andric   LocalAddressSpace *addressSpace;
4465ffd83dbSDimitry Andric   UnwindInfoSections *sects;
4475ffd83dbSDimitry Andric   uintptr_t targetAddr;
4485ffd83dbSDimitry Andric };
4495ffd83dbSDimitry Andric 
4505ffd83dbSDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
4515ffd83dbSDimitry Andric   #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
4525ffd83dbSDimitry Andric     #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
4535ffd83dbSDimitry Andric   #endif
4545ffd83dbSDimitry Andric 
4559ff1cc58SDimitry Andric #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
4565ffd83dbSDimitry Andric #include "FrameHeaderCache.hpp"
4575ffd83dbSDimitry Andric 
4585ffd83dbSDimitry Andric // There should be just one of these per process.
4595ffd83dbSDimitry Andric static FrameHeaderCache ProcessFrameHeaderCache;
460*75b4d546SDimitry Andric #endif
4615ffd83dbSDimitry Andric 
4625ffd83dbSDimitry Andric static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
4635ffd83dbSDimitry Andric                                dl_iterate_cb_data *cbdata) {
4645ffd83dbSDimitry Andric   if (phdr->p_type == PT_LOAD) {
4655ffd83dbSDimitry Andric     uintptr_t begin = image_base + phdr->p_vaddr;
4665ffd83dbSDimitry Andric     uintptr_t end = begin + phdr->p_memsz;
4675ffd83dbSDimitry Andric     if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
4685ffd83dbSDimitry Andric       cbdata->sects->dso_base = begin;
4695ffd83dbSDimitry Andric       cbdata->sects->dwarf_section_length = phdr->p_memsz;
4705ffd83dbSDimitry Andric       return true;
4715ffd83dbSDimitry Andric     }
4725ffd83dbSDimitry Andric   }
4735ffd83dbSDimitry Andric   return false;
4745ffd83dbSDimitry Andric }
4755ffd83dbSDimitry Andric 
4765ffd83dbSDimitry Andric int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t pinfo_size,
4775ffd83dbSDimitry Andric                              void *data) {
4785ffd83dbSDimitry Andric   auto cbdata = static_cast<dl_iterate_cb_data *>(data);
4795ffd83dbSDimitry Andric   if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
4805ffd83dbSDimitry Andric     return 0;
4819ff1cc58SDimitry Andric #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
4825ffd83dbSDimitry Andric   if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data))
4835ffd83dbSDimitry Andric     return 1;
484*75b4d546SDimitry Andric #endif
4855ffd83dbSDimitry Andric 
4865ffd83dbSDimitry Andric   Elf_Addr image_base = calculateImageBase(pinfo);
4875ffd83dbSDimitry Andric   bool found_obj = false;
4885ffd83dbSDimitry Andric   bool found_hdr = false;
4895ffd83dbSDimitry Andric 
4905ffd83dbSDimitry Andric   // Third phdr is usually the executable phdr.
4915ffd83dbSDimitry Andric   if (pinfo->dlpi_phnum > 2)
4925ffd83dbSDimitry Andric     found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
4935ffd83dbSDimitry Andric 
4945ffd83dbSDimitry Andric   // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
4955ffd83dbSDimitry Andric   // that there is one or more phdrs.
4965ffd83dbSDimitry Andric   for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
4975ffd83dbSDimitry Andric     const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
4985ffd83dbSDimitry Andric     if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) {
4995ffd83dbSDimitry Andric       EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
5005ffd83dbSDimitry Andric       uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
5015ffd83dbSDimitry Andric       cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
5025ffd83dbSDimitry Andric       cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
5035ffd83dbSDimitry Andric       found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
5045ffd83dbSDimitry Andric           *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
5055ffd83dbSDimitry Andric           hdrInfo);
5065ffd83dbSDimitry Andric       if (found_hdr)
5075ffd83dbSDimitry Andric         cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
5085ffd83dbSDimitry Andric     } else if (!found_obj) {
5095ffd83dbSDimitry Andric       found_obj = checkAddrInSegment(phdr, image_base, cbdata);
5105ffd83dbSDimitry Andric     }
5115ffd83dbSDimitry Andric     if (found_obj && found_hdr) {
5129ff1cc58SDimitry Andric #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
5135ffd83dbSDimitry Andric       ProcessFrameHeaderCache.add(cbdata->sects);
514*75b4d546SDimitry Andric #endif
5155ffd83dbSDimitry Andric       return 1;
5165ffd83dbSDimitry Andric     }
5175ffd83dbSDimitry Andric   }
5185ffd83dbSDimitry Andric   cbdata->sects->dwarf_section_length = 0;
5195ffd83dbSDimitry Andric   return 0;
5205ffd83dbSDimitry Andric }
5215ffd83dbSDimitry Andric 
5225ffd83dbSDimitry Andric #else  // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
5235ffd83dbSDimitry Andric // Given all the #ifdef's above, the code here is for
5245ffd83dbSDimitry Andric // defined(LIBUNWIND_ARM_EHABI)
5255ffd83dbSDimitry Andric 
5265ffd83dbSDimitry Andric int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) {
5275ffd83dbSDimitry Andric   auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
5285ffd83dbSDimitry Andric   bool found_obj = false;
5295ffd83dbSDimitry Andric   bool found_hdr = false;
5305ffd83dbSDimitry Andric 
5315ffd83dbSDimitry Andric   assert(cbdata);
5325ffd83dbSDimitry Andric   assert(cbdata->sects);
5335ffd83dbSDimitry Andric 
5345ffd83dbSDimitry Andric   if (cbdata->targetAddr < pinfo->dlpi_addr)
5355ffd83dbSDimitry Andric     return 0;
5365ffd83dbSDimitry Andric 
5375ffd83dbSDimitry Andric   Elf_Addr image_base = calculateImageBase(pinfo);
5385ffd83dbSDimitry Andric 
5395ffd83dbSDimitry Andric   for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
5405ffd83dbSDimitry Andric     const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
5415ffd83dbSDimitry Andric     if (phdr->p_type == PT_LOAD) {
5425ffd83dbSDimitry Andric       uintptr_t begin = image_base + phdr->p_vaddr;
5435ffd83dbSDimitry Andric       uintptr_t end = begin + phdr->p_memsz;
5445ffd83dbSDimitry Andric       if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
5455ffd83dbSDimitry Andric         found_obj = true;
5465ffd83dbSDimitry Andric     } else if (phdr->p_type == PT_ARM_EXIDX) {
5475ffd83dbSDimitry Andric       uintptr_t exidx_start = image_base + phdr->p_vaddr;
5485ffd83dbSDimitry Andric       cbdata->sects->arm_section = exidx_start;
5495ffd83dbSDimitry Andric       cbdata->sects->arm_section_length = phdr->p_memsz;
5505ffd83dbSDimitry Andric       found_hdr = true;
5515ffd83dbSDimitry Andric     }
5525ffd83dbSDimitry Andric   }
5535ffd83dbSDimitry Andric   return found_obj && found_hdr;
5545ffd83dbSDimitry Andric }
5555ffd83dbSDimitry Andric #endif  // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
5565ffd83dbSDimitry Andric #endif  // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
5575ffd83dbSDimitry Andric 
5585ffd83dbSDimitry Andric 
5590b57cec5SDimitry Andric inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
5600b57cec5SDimitry Andric                                                   UnwindInfoSections &info) {
5610b57cec5SDimitry Andric #ifdef __APPLE__
5620b57cec5SDimitry Andric   dyld_unwind_sections dyldInfo;
5630b57cec5SDimitry Andric   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
5640b57cec5SDimitry Andric     info.dso_base                      = (uintptr_t)dyldInfo.mh;
5650b57cec5SDimitry Andric  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
5660b57cec5SDimitry Andric     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
5670b57cec5SDimitry Andric     info.dwarf_section_length          = dyldInfo.dwarf_section_length;
5680b57cec5SDimitry Andric  #endif
5690b57cec5SDimitry Andric     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
5700b57cec5SDimitry Andric     info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
5710b57cec5SDimitry Andric     return true;
5720b57cec5SDimitry Andric   }
5730b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
5740b57cec5SDimitry Andric   // Bare metal is statically linked, so no need to ask the dynamic loader
5750b57cec5SDimitry Andric   info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
5760b57cec5SDimitry Andric   info.dwarf_section =        (uintptr_t)(&__eh_frame_start);
5770b57cec5SDimitry Andric   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
5780b57cec5SDimitry Andric                              (void *)info.dwarf_section, (void *)info.dwarf_section_length);
5790b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
5800b57cec5SDimitry Andric   info.dwarf_index_section =        (uintptr_t)(&__eh_frame_hdr_start);
5810b57cec5SDimitry Andric   info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
5820b57cec5SDimitry Andric   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
5830b57cec5SDimitry Andric                              (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
5840b57cec5SDimitry Andric #endif
5850b57cec5SDimitry Andric   if (info.dwarf_section_length)
5860b57cec5SDimitry Andric     return true;
5870b57cec5SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
5880b57cec5SDimitry Andric   // Bare metal is statically linked, so no need to ask the dynamic loader
5890b57cec5SDimitry Andric   info.arm_section =        (uintptr_t)(&__exidx_start);
5900b57cec5SDimitry Andric   info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
5910b57cec5SDimitry Andric   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
5920b57cec5SDimitry Andric                              (void *)info.arm_section, (void *)info.arm_section_length);
5930b57cec5SDimitry Andric   if (info.arm_section && info.arm_section_length)
5940b57cec5SDimitry Andric     return true;
5950b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
5960b57cec5SDimitry Andric   HMODULE mods[1024];
5970b57cec5SDimitry Andric   HANDLE process = GetCurrentProcess();
5980b57cec5SDimitry Andric   DWORD needed;
5990b57cec5SDimitry Andric 
600480093f4SDimitry Andric   if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
601480093f4SDimitry Andric     DWORD err = GetLastError();
602480093f4SDimitry Andric     _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
603480093f4SDimitry Andric                                "returned error %d", (int)err);
6040b57cec5SDimitry Andric     return false;
605480093f4SDimitry Andric   }
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric   for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
6080b57cec5SDimitry Andric     PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
6090b57cec5SDimitry Andric     PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
6100b57cec5SDimitry Andric     PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
6110b57cec5SDimitry Andric     PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
6120b57cec5SDimitry Andric     bool found_obj = false;
6130b57cec5SDimitry Andric     bool found_hdr = false;
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric     info.dso_base = (uintptr_t)mods[i];
6160b57cec5SDimitry Andric     for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
6170b57cec5SDimitry Andric       uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
6180b57cec5SDimitry Andric       uintptr_t end = begin + pish->Misc.VirtualSize;
6190b57cec5SDimitry Andric       if (!strncmp((const char *)pish->Name, ".text",
6200b57cec5SDimitry Andric                    IMAGE_SIZEOF_SHORT_NAME)) {
6210b57cec5SDimitry Andric         if (targetAddr >= begin && targetAddr < end)
6220b57cec5SDimitry Andric           found_obj = true;
6230b57cec5SDimitry Andric       } else if (!strncmp((const char *)pish->Name, ".eh_frame",
6240b57cec5SDimitry Andric                           IMAGE_SIZEOF_SHORT_NAME)) {
6250b57cec5SDimitry Andric         info.dwarf_section = begin;
6260b57cec5SDimitry Andric         info.dwarf_section_length = pish->Misc.VirtualSize;
6270b57cec5SDimitry Andric         found_hdr = true;
6280b57cec5SDimitry Andric       }
6290b57cec5SDimitry Andric       if (found_obj && found_hdr)
6300b57cec5SDimitry Andric         return true;
6310b57cec5SDimitry Andric     }
6320b57cec5SDimitry Andric   }
6330b57cec5SDimitry Andric   return false;
6340b57cec5SDimitry Andric #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
6350b57cec5SDimitry Andric   // Don't even bother, since Windows has functions that do all this stuff
6360b57cec5SDimitry Andric   // for us.
6370b57cec5SDimitry Andric   (void)targetAddr;
6380b57cec5SDimitry Andric   (void)info;
6390b57cec5SDimitry Andric   return true;
640c2c6a179SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
641c2c6a179SDimitry Andric   // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
642c2c6a179SDimitry Andric   // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
6430b57cec5SDimitry Andric   int length = 0;
6440b57cec5SDimitry Andric   info.arm_section =
6450b57cec5SDimitry Andric       (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
646c2c6a179SDimitry Andric   info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
6470b57cec5SDimitry Andric   if (info.arm_section && info.arm_section_length)
6480b57cec5SDimitry Andric     return true;
6490b57cec5SDimitry Andric #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
6500b57cec5SDimitry Andric   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
6515ffd83dbSDimitry Andric   int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
6520b57cec5SDimitry Andric   return static_cast<bool>(found);
6530b57cec5SDimitry Andric #endif
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric   return false;
6560b57cec5SDimitry Andric }
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
6600b57cec5SDimitry Andric #ifdef __APPLE__
6610b57cec5SDimitry Andric   return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
6620b57cec5SDimitry Andric #else
6630b57cec5SDimitry Andric   // TO DO: if OS has way to dynamically register FDEs, check that.
6640b57cec5SDimitry Andric   (void)targetAddr;
6650b57cec5SDimitry Andric   (void)fde;
6660b57cec5SDimitry Andric   return false;
6670b57cec5SDimitry Andric #endif
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
6710b57cec5SDimitry Andric                                                 size_t bufLen,
6720b57cec5SDimitry Andric                                                 unw_word_t *offset) {
6730b57cec5SDimitry Andric #if _LIBUNWIND_USE_DLADDR
6740b57cec5SDimitry Andric   Dl_info dyldInfo;
6750b57cec5SDimitry Andric   if (dladdr((void *)addr, &dyldInfo)) {
6760b57cec5SDimitry Andric     if (dyldInfo.dli_sname != NULL) {
6770b57cec5SDimitry Andric       snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
6780b57cec5SDimitry Andric       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
6790b57cec5SDimitry Andric       return true;
6800b57cec5SDimitry Andric     }
6810b57cec5SDimitry Andric   }
6820b57cec5SDimitry Andric #else
6830b57cec5SDimitry Andric   (void)addr;
6840b57cec5SDimitry Andric   (void)buf;
6850b57cec5SDimitry Andric   (void)bufLen;
6860b57cec5SDimitry Andric   (void)offset;
6870b57cec5SDimitry Andric #endif
6880b57cec5SDimitry Andric   return false;
6890b57cec5SDimitry Andric }
6900b57cec5SDimitry Andric 
6910b57cec5SDimitry Andric } // namespace libunwind
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric #endif // __ADDRESSSPACE_HPP__
694