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