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;
get8(pint_t addr)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 }
get16(pint_t addr)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 }
get32(pint_t addr)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 }
get64(pint_t addr)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 }
getDouble(pint_t addr)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 }
getVector(pint_t addr)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
getP(pint_t addr)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
getRegister(pint_t addr)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.
getULEB128(pint_t & addr,pint_t end)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.
getSLEB128(pint_t & addr,pint_t end)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
getEncodedP(pint_t & addr,pint_t end,uint8_t encoding,pint_t datarelBase)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
checkAddrInSegment(const Elf_Phdr * phdr,size_t image_base,dl_iterate_cb_data * cbdata)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
checkForUnwindInfoSegment(const Elf_Phdr * phdr,size_t image_base,dl_iterate_cb_data * cbdata)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(
4175f757f3fSDimitry Andric *cbdata->addressSpace, eh_frame_hdr_start,
4185f757f3fSDimitry 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
findUnwindSectionsByPhdr(struct dl_phdr_info * pinfo,size_t pinfo_size,void * data)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
findUnwindSections(pint_t targetAddr,UnwindInfoSections & info)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(
6415f757f3fSDimitry Andric *this, info.dwarf_index_section,
6425f757f3fSDimitry 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
findOtherFDE(pint_t targetAddr,pint_t & fde)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
findFunctionName(pint_t addr,char * buf,size_t bufLen,unw_word_t * offset)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