diff --git a/contrib/llvm/projects/libunwind/src/AddressSpace.hpp b/contrib/llvm/projects/libunwind/src/AddressSpace.hpp index 567cbdad92e2..73013c73ff71 100644 --- a/contrib/llvm/projects/libunwind/src/AddressSpace.hpp +++ b/contrib/llvm/projects/libunwind/src/AddressSpace.hpp @@ -1,593 +1,597 @@ //===------------------------- AddressSpace.hpp ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Abstracts accessing local vs remote address spaces. // //===----------------------------------------------------------------------===// #ifndef __ADDRESSSPACE_HPP__ #define __ADDRESSSPACE_HPP__ #include #include #include #include #ifndef _LIBUNWIND_IS_BAREMETAL #include #endif #ifdef __APPLE__ #include namespace libunwind { bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); } #endif #include "libunwind.h" #include "config.h" #include "dwarf2.h" #include "Registers.hpp" #if _LIBUNWIND_ARM_EHABI -#ifdef __linux__ +#if defined(__FreeBSD__) + +typedef void *_Unwind_Ptr; + +#elif defined(__linux__) typedef long unsigned int *_Unwind_Ptr; extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len); // Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system. #define dl_unwind_find_exidx __gnu_Unwind_Find_exidx #elif !defined(_LIBUNWIND_IS_BAREMETAL) #include #else // !defined(_LIBUNWIND_IS_BAREMETAL) // When statically linked on bare-metal, the symbols for the EH table are looked // up without going through the dynamic loader. struct EHTEntry { uint32_t functionOffset; uint32_t unwindOpcodes; }; extern EHTEntry __exidx_start; extern EHTEntry __exidx_end; #endif // !defined(_LIBUNWIND_IS_BAREMETAL) #endif // _LIBUNWIND_ARM_EHABI #if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__linux__) #if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX #include // Macro for machine-independent access to the ELF program headers. This // macro is not available on some systems (e.g., FreeBSD). On these // systems the data structures are just called Elf_XXX. Define ElfW() // locally. #if !defined(ElfW) #define ElfW(type) Elf_##type #endif #include "EHHeaderParser.hpp" #endif #endif namespace libunwind { /// Used by findUnwindSections() to return info about needed sections. struct UnwindInfoSections { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \ _LIBUNWIND_SUPPORT_COMPACT_UNWIND // No dso_base for ARM EHABI. uintptr_t dso_base; #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND uintptr_t dwarf_section; uintptr_t dwarf_section_length; #endif #if _LIBUNWIND_SUPPORT_DWARF_INDEX uintptr_t dwarf_index_section; uintptr_t dwarf_index_section_length; #endif #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND uintptr_t compact_unwind_section; uintptr_t compact_unwind_section_length; #endif #if _LIBUNWIND_ARM_EHABI uintptr_t arm_section; uintptr_t arm_section_length; #endif }; /// LocalAddressSpace is used as a template parameter to UnwindCursor when /// unwinding a thread in the same process. The wrappers compile away, /// making local unwinds fast. class __attribute__((visibility("hidden"))) LocalAddressSpace { public: #ifdef __LP64__ typedef uint64_t pint_t; typedef int64_t sint_t; #else typedef uint32_t pint_t; typedef int32_t sint_t; #endif uint8_t get8(pint_t addr) { uint8_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uint16_t get16(pint_t addr) { uint16_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uint32_t get32(pint_t addr) { uint32_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uint64_t get64(pint_t addr) { uint64_t val; memcpy(&val, (void *)addr, sizeof(val)); return val; } double getDouble(pint_t addr) { double val; memcpy(&val, (void *)addr, sizeof(val)); return val; } v128 getVector(pint_t addr) { v128 val; memcpy(&val, (void *)addr, sizeof(val)); return val; } uintptr_t getP(pint_t addr); static uint64_t getULEB128(pint_t &addr, pint_t end); static int64_t getSLEB128(pint_t &addr, pint_t end); pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, pint_t datarelBase = 0); bool findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset); bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); bool findOtherFDE(pint_t targetAddr, pint_t &fde); static LocalAddressSpace sThisAddressSpace; }; inline uintptr_t LocalAddressSpace::getP(pint_t addr) { #ifdef __LP64__ return get64(addr); #else return get32(addr); #endif } /// Read a ULEB128 into a 64-bit word. inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { const uint8_t *p = (uint8_t *)addr; const uint8_t *pend = (uint8_t *)end; uint64_t result = 0; int bit = 0; do { uint64_t b; if (p == pend) _LIBUNWIND_ABORT("truncated uleb128 expression"); b = *p & 0x7f; if (bit >= 64 || b << bit >> bit != b) { _LIBUNWIND_ABORT("malformed uleb128 expression"); } else { result |= b << bit; bit += 7; } } while (*p++ >= 0x80); addr = (pint_t) p; return result; } /// Read a SLEB128 into a 64-bit word. inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { const uint8_t *p = (uint8_t *)addr; const uint8_t *pend = (uint8_t *)end; int64_t result = 0; int bit = 0; uint8_t byte; do { if (p == pend) _LIBUNWIND_ABORT("truncated sleb128 expression"); byte = *p++; result |= ((byte & 0x7f) << bit); bit += 7; } while (byte & 0x80); // sign extend negative numbers if ((byte & 0x40) != 0) result |= (-1LL) << bit; addr = (pint_t) p; return result; } inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, pint_t datarelBase) { pint_t startAddr = addr; const uint8_t *p = (uint8_t *)addr; pint_t result; // first get value switch (encoding & 0x0F) { case DW_EH_PE_ptr: result = getP(addr); p += sizeof(pint_t); addr = (pint_t) p; break; case DW_EH_PE_uleb128: result = (pint_t)getULEB128(addr, end); break; case DW_EH_PE_udata2: result = get16(addr); p += 2; addr = (pint_t) p; break; case DW_EH_PE_udata4: result = get32(addr); p += 4; addr = (pint_t) p; break; case DW_EH_PE_udata8: result = (pint_t)get64(addr); p += 8; addr = (pint_t) p; break; case DW_EH_PE_sleb128: result = (pint_t)getSLEB128(addr, end); break; case DW_EH_PE_sdata2: // Sign extend from signed 16-bit value. result = (pint_t)(int16_t)get16(addr); p += 2; addr = (pint_t) p; break; case DW_EH_PE_sdata4: // Sign extend from signed 32-bit value. result = (pint_t)(int32_t)get32(addr); p += 4; addr = (pint_t) p; break; case DW_EH_PE_sdata8: result = (pint_t)get64(addr); p += 8; addr = (pint_t) p; break; default: _LIBUNWIND_ABORT("unknown pointer encoding"); } // then add relative offset switch (encoding & 0x70) { case DW_EH_PE_absptr: // do nothing break; case DW_EH_PE_pcrel: result += startAddr; break; case DW_EH_PE_textrel: _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); break; case DW_EH_PE_datarel: // DW_EH_PE_datarel is only valid in a few places, so the parameter has a // default value of 0, and we abort in the event that someone calls this // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. if (datarelBase == 0) _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); result += datarelBase; break; case DW_EH_PE_funcrel: _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); break; case DW_EH_PE_aligned: _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); break; default: _LIBUNWIND_ABORT("unknown pointer encoding"); break; } if (encoding & DW_EH_PE_indirect) result = getP(result); return result; } #ifdef __APPLE__ struct dyld_unwind_sections { const struct mach_header* mh; const void* dwarf_section; uintptr_t dwarf_section_length; const void* compact_unwind_section; uintptr_t compact_unwind_section_length; }; #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) // In 10.7.0 or later, libSystem.dylib implements this function. extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); #else // In 10.6.x and earlier, we need to implement this functionality. static inline bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) { // Find mach-o image containing address. Dl_info dlinfo; if (!dladdr(addr, &dlinfo)) return false; const mach_header *mh = (const mach_header *)dlinfo.dli_saddr; // Find dwarf unwind section in that image. unsigned long size; const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size); if (!p) return false; // Fill in return struct. info->mh = mh; info->dwarf_section = p; info->dwarf_section_length = size; info->compact_unwind_section = 0; info->compact_unwind_section_length = 0; return true; } #endif #endif inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, UnwindInfoSections &info) { #ifdef __APPLE__ dyld_unwind_sections dyldInfo; if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { info.dso_base = (uintptr_t)dyldInfo.mh; #if _LIBUNWIND_SUPPORT_DWARF_UNWIND info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; info.dwarf_section_length = dyldInfo.dwarf_section_length; #endif info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; return true; } #elif _LIBUNWIND_ARM_EHABI #ifdef _LIBUNWIND_IS_BAREMETAL // Bare metal is statically linked, so no need to ask the dynamic loader info.arm_section = (uintptr_t)(&__exidx_start); info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); #else int length = 0; info.arm_section = (uintptr_t) dl_unwind_find_exidx( (_Unwind_Ptr) targetAddr, &length); info.arm_section_length = (uintptr_t)length; #endif _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n", info.arm_section, info.arm_section_length); if (info.arm_section && info.arm_section_length) return true; #elif _LIBUNWIND_SUPPORT_DWARF_UNWIND #if _LIBUNWIND_SUPPORT_DWARF_INDEX struct dl_iterate_cb_data { LocalAddressSpace *addressSpace; UnwindInfoSections *sects; uintptr_t targetAddr; }; dl_iterate_cb_data cb_data = {this, &info, targetAddr}; int found = dl_iterate_phdr( [](struct dl_phdr_info *pinfo, size_t, void *data) -> int { auto cbdata = static_cast(data); size_t object_length; bool found_obj = false; bool found_hdr = false; assert(cbdata); assert(cbdata->sects); if (cbdata->targetAddr < pinfo->dlpi_addr) { return false; } #if !defined(Elf_Half) typedef ElfW(Half) Elf_Half; #endif #if !defined(Elf_Phdr) typedef ElfW(Phdr) Elf_Phdr; #endif for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; if (phdr->p_type == PT_LOAD) { uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; uintptr_t end = begin + phdr->p_memsz; if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { cbdata->sects->dso_base = begin; object_length = phdr->p_memsz; found_obj = true; } } else if (phdr->p_type == PT_GNU_EH_FRAME) { EHHeaderParser::EHHeaderInfo hdrInfo; uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr; cbdata->sects->dwarf_index_section = eh_frame_hdr_start; cbdata->sects->dwarf_index_section_length = phdr->p_memsz; EHHeaderParser::decodeEHHdr( *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, hdrInfo); cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; found_hdr = true; } } if (found_obj && found_hdr) { cbdata->sects->dwarf_section_length = object_length; return true; } else { return false; } }, &cb_data); return static_cast(found); #else #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." #endif #endif return false; } inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { #ifdef __APPLE__ return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); #else // TO DO: if OS has way to dynamically register FDEs, check that. (void)targetAddr; (void)fde; return false; #endif } inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset) { #ifndef _LIBUNWIND_IS_BAREMETAL Dl_info dyldInfo; if (dladdr((void *)addr, &dyldInfo)) { if (dyldInfo.dli_sname != NULL) { snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); *offset = (addr - (pint_t) dyldInfo.dli_saddr); return true; } } #endif return false; } #ifdef UNW_REMOTE /// OtherAddressSpace is used as a template parameter to UnwindCursor when /// unwinding a thread in the another process. The other process can be a /// different endianness and a different pointer size which is handled by /// the P template parameter. template class OtherAddressSpace { public: OtherAddressSpace(task_t task) : fTask(task) {} typedef typename P::uint_t pint_t; uint8_t get8(pint_t addr); uint16_t get16(pint_t addr); uint32_t get32(pint_t addr); uint64_t get64(pint_t addr); pint_t getP(pint_t addr); uint64_t getULEB128(pint_t &addr, pint_t end); int64_t getSLEB128(pint_t &addr, pint_t end); pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, pint_t datarelBase = 0); bool findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset); bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); bool findOtherFDE(pint_t targetAddr, pint_t &fde); private: void *localCopy(pint_t addr); task_t fTask; }; template uint8_t OtherAddressSpace

::get8(pint_t addr) { return *((uint8_t *)localCopy(addr)); } template uint16_t OtherAddressSpace

::get16(pint_t addr) { return P::E::get16(*(uint16_t *)localCopy(addr)); } template uint32_t OtherAddressSpace

::get32(pint_t addr) { return P::E::get32(*(uint32_t *)localCopy(addr)); } template uint64_t OtherAddressSpace

::get64(pint_t addr) { return P::E::get64(*(uint64_t *)localCopy(addr)); } template typename P::uint_t OtherAddressSpace

::getP(pint_t addr) { return P::getP(*(uint64_t *)localCopy(addr)); } template uint64_t OtherAddressSpace

::getULEB128(pint_t &addr, pint_t end) { uintptr_t size = (end - addr); LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); LocalAddressSpace::pint_t sladdr = laddr; uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); addr += (laddr - sladdr); return result; } template int64_t OtherAddressSpace

::getSLEB128(pint_t &addr, pint_t end) { uintptr_t size = (end - addr); LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); LocalAddressSpace::pint_t sladdr = laddr; uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); addr += (laddr - sladdr); return result; } template void *OtherAddressSpace

::localCopy(pint_t addr) { // FIX ME } template bool OtherAddressSpace

::findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset) { // FIX ME } /// unw_addr_space is the base class that abstract unw_addr_space_t type in /// libunwind.h points to. struct unw_addr_space { cpu_type_t cpuType; task_t taskPort; }; /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points /// to when examining /// a 32-bit intel process. struct unw_addr_space_i386 : public unw_addr_space { unw_addr_space_i386(task_t task) : oas(task) {} OtherAddressSpace > oas; }; /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t /// points to when examining /// a 64-bit intel process. struct unw_addr_space_x86_64 : public unw_addr_space { unw_addr_space_x86_64(task_t task) : oas(task) {} OtherAddressSpace > oas; }; /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points /// to when examining /// a 32-bit PowerPC process. struct unw_addr_space_ppc : public unw_addr_space { unw_addr_space_ppc(task_t task) : oas(task) {} OtherAddressSpace > oas; }; #endif // UNW_REMOTE } // namespace libunwind #endif // __ADDRESSSPACE_HPP__ diff --git a/contrib/llvm/projects/libunwind/src/DwarfParser.hpp b/contrib/llvm/projects/libunwind/src/DwarfParser.hpp index 26993c4e0d1b..a19f0510a37b 100644 --- a/contrib/llvm/projects/libunwind/src/DwarfParser.hpp +++ b/contrib/llvm/projects/libunwind/src/DwarfParser.hpp @@ -1,722 +1,726 @@ //===--------------------------- DwarfParser.hpp --------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Parses DWARF CFIs (FDEs and CIEs). // //===----------------------------------------------------------------------===// #ifndef __DWARF_PARSER_HPP__ #define __DWARF_PARSER_HPP__ #include #include #include #include #include "libunwind.h" #include "dwarf2.h" #include "AddressSpace.hpp" namespace libunwind { /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. /// See Dwarf Spec for details: /// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html /// template class CFI_Parser { public: typedef typename A::pint_t pint_t; /// Information encoded in a CIE (Common Information Entry) struct CIE_Info { pint_t cieStart; pint_t cieLength; pint_t cieInstructions; uint8_t pointerEncoding; uint8_t lsdaEncoding; uint8_t personalityEncoding; uint8_t personalityOffsetInCIE; pint_t personality; uint32_t codeAlignFactor; int dataAlignFactor; bool isSignalFrame; bool fdesHaveAugmentationData; uint8_t returnAddressRegister; }; /// Information about an FDE (Frame Description Entry) struct FDE_Info { pint_t fdeStart; pint_t fdeLength; pint_t fdeInstructions; pint_t pcStart; pint_t pcEnd; pint_t lsda; }; enum { kMaxRegisterNumber = 120 }; enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA, kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression }; struct RegisterLocation { RegisterSavedWhere location; int64_t value; }; /// Information about a frame layout and registers saved determined /// by "running" the dwarf FDE "instructions" struct PrologInfo { uint32_t cfaRegister; int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset int64_t cfaExpression; // CFA = expression uint32_t spExtraArgSize; uint32_t codeOffsetAtStackDecrement; bool registersInOtherRegisters; bool sameValueUsed; RegisterLocation savedRegisters[kMaxRegisterNumber]; }; struct PrologInfoStackEntry { PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) : next(n), info(i) {} PrologInfoStackEntry *next; PrologInfo info; }; static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo); static const char *decodeFDE(A &addressSpace, pint_t fdeStart, FDE_Info *fdeInfo, CIE_Info *cieInfo); static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo, pint_t upToPC, PrologInfo *results); static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); private: static bool parseInstructions(A &addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info &cieInfo, pint_t pcoffset, PrologInfoStackEntry *&rememberStack, PrologInfo *results); }; /// Parse a FDE into a CIE_Info and an FDE_Info template const char *CFI_Parser::decodeFDE(A &addressSpace, pint_t fdeStart, FDE_Info *fdeInfo, CIE_Info *cieInfo) { pint_t p = fdeStart; pint_t cfiLength = (pint_t)addressSpace.get32(p); p += 4; if (cfiLength == 0xffffffff) { // 0xffffffff means length is really next 8 bytes cfiLength = (pint_t)addressSpace.get64(p); p += 8; } if (cfiLength == 0) return "FDE has zero length"; // end marker uint32_t ciePointer = addressSpace.get32(p); if (ciePointer == 0) return "FDE is really a CIE"; // this is a CIE not an FDE pint_t nextCFI = p + cfiLength; pint_t cieStart = p - ciePointer; const char *err = parseCIE(addressSpace, cieStart, cieInfo); if (err != NULL) return err; p += 4; // parse pc begin and range pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); // parse rest of info fdeInfo->lsda = 0; // check for augmentation length if (cieInfo->fdesHaveAugmentationData) { pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); pint_t endOfAug = p + augLen; if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { // peek at value (without indirection). Zero means no lsda pint_t lsdaStart = p; if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { // reset pointer and re-parse lsda address p = lsdaStart; fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); } } p = endOfAug; } fdeInfo->fdeStart = fdeStart; fdeInfo->fdeLength = nextCFI - fdeStart; fdeInfo->fdeInstructions = p; fdeInfo->pcStart = pcStart; fdeInfo->pcEnd = pcStart + pcRange; return NULL; // success } /// Scan an eh_frame section to find an FDE for a pc template bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo) { //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; const pint_t ehSectionEnd = p + sectionLength; while (p < ehSectionEnd) { pint_t currentCFI = p; //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); pint_t cfiLength = addressSpace.get32(p); p += 4; if (cfiLength == 0xffffffff) { // 0xffffffff means length is really next 8 bytes cfiLength = (pint_t)addressSpace.get64(p); p += 8; } if (cfiLength == 0) return false; // end marker uint32_t id = addressSpace.get32(p); if (id == 0) { // skip over CIEs p += cfiLength; } else { // process FDE to see if it covers pc pint_t nextCFI = p + cfiLength; uint32_t ciePointer = addressSpace.get32(p); pint_t cieStart = p - ciePointer; // validate pointer to CIE is within section if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { p += 4; // parse pc begin and range pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); pint_t pcRange = addressSpace.getEncodedP( p, nextCFI, cieInfo->pointerEncoding & 0x0F); // test if pc is within the function this FDE covers if ((pcStart < pc) && (pc <= pcStart + pcRange)) { // parse rest of info fdeInfo->lsda = 0; // check for augmentation length if (cieInfo->fdesHaveAugmentationData) { pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); pint_t endOfAug = p + augLen; if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { // peek at value (without indirection). Zero means no lsda pint_t lsdaStart = p; if (addressSpace.getEncodedP( p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { // reset pointer and re-parse lsda address p = lsdaStart; fdeInfo->lsda = addressSpace .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); } } p = endOfAug; } fdeInfo->fdeStart = currentCFI; fdeInfo->fdeLength = nextCFI - currentCFI; fdeInfo->fdeInstructions = p; fdeInfo->pcStart = pcStart; fdeInfo->pcEnd = pcStart + pcRange; return true; } else { // pc is not in begin/range, skip this FDE } } else { // malformed CIE, now augmentation describing pc range encoding } } else { // malformed FDE. CIE is bad } p = nextCFI; } } return false; } /// Extract info from a CIE template const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo) { cieInfo->pointerEncoding = 0; cieInfo->lsdaEncoding = DW_EH_PE_omit; cieInfo->personalityEncoding = 0; cieInfo->personalityOffsetInCIE = 0; cieInfo->personality = 0; cieInfo->codeAlignFactor = 0; cieInfo->dataAlignFactor = 0; cieInfo->isSignalFrame = false; cieInfo->fdesHaveAugmentationData = false; cieInfo->cieStart = cie; pint_t p = cie; pint_t cieLength = (pint_t)addressSpace.get32(p); p += 4; pint_t cieContentEnd = p + cieLength; if (cieLength == 0xffffffff) { // 0xffffffff means length is really next 8 bytes cieLength = (pint_t)addressSpace.get64(p); p += 8; cieContentEnd = p + cieLength; } if (cieLength == 0) return NULL; // CIE ID is always 0 if (addressSpace.get32(p) != 0) return "CIE ID is not zero"; p += 4; // Version is always 1 or 3 uint8_t version = addressSpace.get8(p); if ((version != 1) && (version != 3)) return "CIE version is not 1 or 3"; ++p; // save start of augmentation string and find end pint_t strStart = p; while (addressSpace.get8(p) != 0) ++p; ++p; // parse code aligment factor cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); // parse data alignment factor cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); // parse return address register uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd); assert(raReg < 255 && "return address register too large"); cieInfo->returnAddressRegister = (uint8_t)raReg; // parse augmentation data based on augmentation string const char *result = NULL; if (addressSpace.get8(strStart) == 'z') { // parse augmentation data length addressSpace.getULEB128(p, cieContentEnd); for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { switch (addressSpace.get8(s)) { case 'z': cieInfo->fdesHaveAugmentationData = true; break; case 'P': cieInfo->personalityEncoding = addressSpace.get8(p); ++p; cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); cieInfo->personality = addressSpace .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); break; case 'L': cieInfo->lsdaEncoding = addressSpace.get8(p); ++p; break; case 'R': cieInfo->pointerEncoding = addressSpace.get8(p); ++p; break; case 'S': cieInfo->isSignalFrame = true; break; default: // ignore unknown letters break; } } } cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; cieInfo->cieInstructions = p; return result; } /// "run" the dwarf instructions and create the abstact PrologInfo for an FDE template bool CFI_Parser::parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo, pint_t upToPC, PrologInfo *results) { // clear results memset(results, '\0', sizeof(PrologInfo)); PrologInfoStackEntry *rememberStack = NULL; // parse CIE then FDE instructions return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, cieInfo, (pint_t)(-1), rememberStack, results) && parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, upToPC - fdeInfo.pcStart, rememberStack, results); } /// "run" the dwarf instructions template bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info &cieInfo, pint_t pcoffset, PrologInfoStackEntry *&rememberStack, PrologInfo *results) { const bool logDwarf = false; pint_t p = instructions; pint_t codeOffset = 0; PrologInfo initialState = *results; if (logDwarf) fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n", (uint64_t)instructionsEnd); // see Dwarf Spec, section 6.4.2 for details on unwind opcodes while ((p < instructionsEnd) && (codeOffset < pcoffset)) { uint64_t reg; uint64_t reg2; int64_t offset; uint64_t length; uint8_t opcode = addressSpace.get8(p); uint8_t operand; +#if !defined(_LIBUNWIND_NO_HEAP) PrologInfoStackEntry *entry; +#endif ++p; switch (opcode) { case DW_CFA_nop: if (logDwarf) fprintf(stderr, "DW_CFA_nop\n"); break; case DW_CFA_set_loc: codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); if (logDwarf) fprintf(stderr, "DW_CFA_set_loc\n"); break; case DW_CFA_advance_loc1: codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); p += 1; if (logDwarf) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", (uint64_t)codeOffset); break; case DW_CFA_advance_loc2: codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); p += 2; if (logDwarf) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", (uint64_t)codeOffset); break; case DW_CFA_advance_loc4: codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); p += 4; if (logDwarf) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", (uint64_t)codeOffset); break; case DW_CFA_offset_extended: reg = addressSpace.getULEB128(p, instructionsEnd); offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n"); return false; } results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = offset; if (logDwarf) fprintf(stderr, "DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, offset); break; case DW_CFA_restore_extended: reg = addressSpace.getULEB128(p, instructionsEnd); ; if (reg > kMaxRegisterNumber) { fprintf( stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n"); return false; } results->savedRegisters[reg] = initialState.savedRegisters[reg]; if (logDwarf) fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg); break; case DW_CFA_undefined: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n"); return false; } results->savedRegisters[reg].location = kRegisterUnused; if (logDwarf) fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); break; case DW_CFA_same_value: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n"); return false; } // DW_CFA_same_value unsupported // "same value" means register was stored in frame, but its current // value has not changed, so no need to restore from frame. // We model this as if the register was never saved. results->savedRegisters[reg].location = kRegisterUnused; // set flag to disable conversion to compact unwind results->sameValueUsed = true; if (logDwarf) fprintf(stderr, "DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); break; case DW_CFA_register: reg = addressSpace.getULEB128(p, instructionsEnd); reg2 = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n"); return false; } if (reg2 > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n"); return false; } results->savedRegisters[reg].location = kRegisterInRegister; results->savedRegisters[reg].value = (int64_t)reg2; // set flag to disable conversion to compact unwind results->registersInOtherRegisters = true; if (logDwarf) fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); break; +#if !defined(_LIBUNWIND_NO_HEAP) case DW_CFA_remember_state: // avoid operator new, because that would be an upward dependency entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry)); if (entry != NULL) { entry->next = rememberStack; entry->info = *results; rememberStack = entry; } else { return false; } if (logDwarf) fprintf(stderr, "DW_CFA_remember_state\n"); break; case DW_CFA_restore_state: if (rememberStack != NULL) { PrologInfoStackEntry *top = rememberStack; *results = top->info; rememberStack = top->next; free((char *)top); } else { return false; } if (logDwarf) fprintf(stderr, "DW_CFA_restore_state\n"); break; +#endif case DW_CFA_def_cfa: reg = addressSpace.getULEB128(p, instructionsEnd); offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n"); return false; } results->cfaRegister = (uint32_t)reg; results->cfaRegisterOffset = (int32_t)offset; if (logDwarf) fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset); break; case DW_CFA_def_cfa_register: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf( stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n"); return false; } results->cfaRegister = (uint32_t)reg; if (logDwarf) fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); break; case DW_CFA_def_cfa_offset: results->cfaRegisterOffset = (int32_t) addressSpace.getULEB128(p, instructionsEnd); results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; if (logDwarf) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset); break; case DW_CFA_def_cfa_expression: results->cfaRegister = 0; results->cfaExpression = (int64_t)p; length = addressSpace.getULEB128(p, instructionsEnd); p += length; if (logDwarf) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", results->cfaExpression, length); break; case DW_CFA_expression: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n"); return false; } results->savedRegisters[reg].location = kRegisterAtExpression; results->savedRegisters[reg].value = (int64_t)p; length = addressSpace.getULEB128(p, instructionsEnd); p += length; if (logDwarf) fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", reg, results->savedRegisters[reg].value, length); break; case DW_CFA_offset_extended_sf: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf( stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n"); return false; } offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = offset; if (logDwarf) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, offset); break; case DW_CFA_def_cfa_sf: reg = addressSpace.getULEB128(p, instructionsEnd); offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n"); return false; } results->cfaRegister = (uint32_t)reg; results->cfaRegisterOffset = (int32_t)offset; if (logDwarf) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg, offset); break; case DW_CFA_def_cfa_offset_sf: results->cfaRegisterOffset = (int32_t) (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; if (logDwarf) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset); break; case DW_CFA_val_offset: reg = addressSpace.getULEB128(p, instructionsEnd); offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterOffsetFromCFA; results->savedRegisters[reg].value = offset; if (logDwarf) fprintf(stderr, "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, offset); break; case DW_CFA_val_offset_sf: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n"); return false; } offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterOffsetFromCFA; results->savedRegisters[reg].value = offset; if (logDwarf) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg, offset); break; case DW_CFA_val_expression: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n"); return false; } results->savedRegisters[reg].location = kRegisterIsExpression; results->savedRegisters[reg].value = (int64_t)p; length = addressSpace.getULEB128(p, instructionsEnd); p += length; if (logDwarf) fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64 ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", reg, results->savedRegisters[reg].value, length); break; case DW_CFA_GNU_args_size: length = addressSpace.getULEB128(p, instructionsEnd); results->spExtraArgSize = (uint32_t)length; if (logDwarf) fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); break; case DW_CFA_GNU_negative_offset_extended: reg = addressSpace.getULEB128(p, instructionsEnd); if (reg > kMaxRegisterNumber) { fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf " "unwind, reg too big\n"); return false; } offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = -offset; if (logDwarf) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); break; default: operand = opcode & 0x3F; switch (opcode & 0xC0) { case DW_CFA_offset: reg = operand; offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; results->savedRegisters[reg].location = kRegisterInCFA; results->savedRegisters[reg].value = offset; if (logDwarf) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", operand, offset); break; case DW_CFA_advance_loc: codeOffset += operand * cieInfo.codeAlignFactor; if (logDwarf) fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n", (uint64_t)codeOffset); break; case DW_CFA_restore: reg = operand; results->savedRegisters[reg] = initialState.savedRegisters[reg]; if (logDwarf) fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg); break; default: if (logDwarf) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); return false; } } } return true; } } // namespace libunwind #endif // __DWARF_PARSER_HPP__ diff --git a/contrib/llvm/projects/libunwind/src/UnwindCursor.hpp b/contrib/llvm/projects/libunwind/src/UnwindCursor.hpp index 040d13e92563..90683164ff24 100644 --- a/contrib/llvm/projects/libunwind/src/UnwindCursor.hpp +++ b/contrib/llvm/projects/libunwind/src/UnwindCursor.hpp @@ -1,1338 +1,1340 @@ //===------------------------- UnwindCursor.hpp ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // C++ interface to lower levels of libuwind //===----------------------------------------------------------------------===// #ifndef __UNWINDCURSOR_HPP__ #define __UNWINDCURSOR_HPP__ #include #include #include #include #include #include #ifdef __APPLE__ #include #endif #include "config.h" #include "AddressSpace.hpp" #include "CompactUnwinder.hpp" #include "config.h" #include "DwarfInstructions.hpp" #include "EHHeaderParser.hpp" #include "libunwind.h" #include "Registers.hpp" #include "Unwind-EHABI.h" namespace libunwind { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND /// Cache of recently found FDEs. template class _LIBUNWIND_HIDDEN DwarfFDECache { typedef typename A::pint_t pint_t; public: static pint_t findFDE(pint_t mh, pint_t pc); static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); static void removeAllIn(pint_t mh); static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); private: struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; }; // These fields are all static to avoid needing an initializer. // There is only one instance of this class per process. static pthread_rwlock_t _lock; #ifdef __APPLE__ static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); static bool _registeredForDyldUnloads; #endif // Can't use std::vector<> here because this code is below libc++. static entry *_buffer; static entry *_bufferUsed; static entry *_bufferEnd; static entry _initialBuffer[64]; }; template typename DwarfFDECache::entry * DwarfFDECache::_buffer = _initialBuffer; template typename DwarfFDECache::entry * DwarfFDECache::_bufferUsed = _initialBuffer; template typename DwarfFDECache::entry * DwarfFDECache::_bufferEnd = &_initialBuffer[64]; template typename DwarfFDECache::entry DwarfFDECache::_initialBuffer[64]; template pthread_rwlock_t DwarfFDECache::_lock = PTHREAD_RWLOCK_INITIALIZER; #ifdef __APPLE__ template bool DwarfFDECache::_registeredForDyldUnloads = false; #endif template typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { pint_t result = 0; _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock)); for (entry *p = _buffer; p < _bufferUsed; ++p) { if ((mh == p->mh) || (mh == 0)) { if ((p->ip_start <= pc) && (pc < p->ip_end)) { result = p->fde; break; } } } _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); return result; } template void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde) { +#if !defined(_LIBUNWIND_NO_HEAP) _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); if (_bufferUsed >= _bufferEnd) { size_t oldSize = (size_t)(_bufferEnd - _buffer); size_t newSize = oldSize * 4; // Can't use operator new (we are below it). entry *newBuffer = (entry *)malloc(newSize * sizeof(entry)); memcpy(newBuffer, _buffer, oldSize * sizeof(entry)); if (_buffer != _initialBuffer) free(_buffer); _buffer = newBuffer; _bufferUsed = &newBuffer[oldSize]; _bufferEnd = &newBuffer[newSize]; } _bufferUsed->mh = mh; _bufferUsed->ip_start = ip_start; _bufferUsed->ip_end = ip_end; _bufferUsed->fde = fde; ++_bufferUsed; #ifdef __APPLE__ if (!_registeredForDyldUnloads) { _dyld_register_func_for_remove_image(&dyldUnloadHook); _registeredForDyldUnloads = true; } #endif _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); +#endif } template void DwarfFDECache::removeAllIn(pint_t mh) { _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); entry *d = _buffer; for (const entry *s = _buffer; s < _bufferUsed; ++s) { if (s->mh != mh) { if (d != s) *d = *s; ++d; } } _bufferUsed = d; _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); } #ifdef __APPLE__ template void DwarfFDECache::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { removeAllIn((pint_t) mh); } #endif template void DwarfFDECache::iterateCacheEntries(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); for (entry *p = _buffer; p < _bufferUsed; ++p) { (*func)(p->ip_start, p->ip_end, p->fde, p->mh); } _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); } #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND #define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND template class UnwindSectionHeader { public: UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t version() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, version)); } uint32_t commonEncodingsArraySectionOffset() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); } uint32_t commonEncodingsArrayCount() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); } uint32_t personalityArraySectionOffset() const { return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); } uint32_t personalityArrayCount() const { return _addressSpace.get32( _addr + offsetof(unwind_info_section_header, personalityArrayCount)); } uint32_t indexSectionOffset() const { return _addressSpace.get32( _addr + offsetof(unwind_info_section_header, indexSectionOffset)); } uint32_t indexCount() const { return _addressSpace.get32( _addr + offsetof(unwind_info_section_header, indexCount)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionIndexArray { public: UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); } uint32_t secondLevelPagesSectionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); } uint32_t lsdaIndexArraySectionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionRegularPageHeader { public: UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t kind() const { return _addressSpace.get32( _addr + offsetof(unwind_info_regular_second_level_page_header, kind)); } uint16_t entryPageOffset() const { return _addressSpace.get16( _addr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); } uint16_t entryCount() const { return _addressSpace.get16( _addr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionRegularArray { public: UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); } uint32_t encoding(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionCompressedPageHeader { public: UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t kind() const { return _addressSpace.get32( _addr + offsetof(unwind_info_compressed_second_level_page_header, kind)); } uint16_t entryPageOffset() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); } uint16_t entryCount() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); } uint16_t encodingsPageOffset() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); } uint16_t encodingsCount() const { return _addressSpace.get16( _addr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionCompressedArray { public: UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( _addressSpace.get32(_addr + index * sizeof(uint32_t))); } uint16_t encodingIndex(uint32_t index) const { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( _addressSpace.get32(_addr + index * sizeof(uint32_t))); } private: A &_addressSpace; typename A::pint_t _addr; }; template class UnwindSectionLsdaArray { public: UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr) : _addressSpace(addressSpace), _addr(addr) {} uint32_t functionOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); } uint32_t lsdaOffset(uint32_t index) const { return _addressSpace.get32( _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); } private: A &_addressSpace; typename A::pint_t _addr; }; #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND class _LIBUNWIND_HIDDEN AbstractUnwindCursor { public: // NOTE: provide a class specific placement deallocation function (S5.3.4 p20) // This avoids an unnecessary dependency to libc++abi. void operator delete(void *, size_t) {} virtual ~AbstractUnwindCursor() {} virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); } virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); } virtual void setReg(int, unw_word_t) { _LIBUNWIND_ABORT("setReg not implemented"); } virtual bool validFloatReg(int) { _LIBUNWIND_ABORT("validFloatReg not implemented"); } virtual unw_fpreg_t getFloatReg(int) { _LIBUNWIND_ABORT("getFloatReg not implemented"); } virtual void setFloatReg(int, unw_fpreg_t) { _LIBUNWIND_ABORT("setFloatReg not implemented"); } virtual int step() { _LIBUNWIND_ABORT("step not implemented"); } virtual void getInfo(unw_proc_info_t *) { _LIBUNWIND_ABORT("getInfo not implemented"); } virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); } virtual bool isSignalFrame() { _LIBUNWIND_ABORT("isSignalFrame not implemented"); } virtual bool getFunctionName(char *, size_t, unw_word_t *) { _LIBUNWIND_ABORT("getFunctionName not implemented"); } virtual void setInfoBasedOnIPRegister(bool = false) { _LIBUNWIND_ABORT("setInfoBasedOnIPRegister not implemented"); } virtual const char *getRegisterName(int) { _LIBUNWIND_ABORT("getRegisterName not implemented"); } #ifdef __arm__ virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); } #endif }; /// UnwindCursor contains all state (including all register values) during /// an unwind. This is normally stack allocated inside a unw_cursor_t. template class UnwindCursor : public AbstractUnwindCursor{ typedef typename A::pint_t pint_t; public: UnwindCursor(unw_context_t *context, A &as); UnwindCursor(A &as, void *threadArg); virtual ~UnwindCursor() {} virtual bool validReg(int); virtual unw_word_t getReg(int); virtual void setReg(int, unw_word_t); virtual bool validFloatReg(int); virtual unw_fpreg_t getFloatReg(int); virtual void setFloatReg(int, unw_fpreg_t); virtual int step(); virtual void getInfo(unw_proc_info_t *); virtual void jumpto(); virtual bool isSignalFrame(); virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); virtual const char *getRegisterName(int num); #ifdef __arm__ virtual void saveVFPAsX(); #endif private: #if _LIBUNWIND_ARM_EHABI bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections §s); int stepWithEHABI() { size_t len = 0; size_t off = 0; // FIXME: Calling decode_eht_entry() here is violating the libunwind // abstraction layer. const uint32_t *ehtp = decode_eht_entry(reinterpret_cast(_info.unwind_info), &off, &len); if (_Unwind_VRS_Interpret((_Unwind_Context *)this, ehtp, off, len) != _URC_CONTINUE_UNWIND) return UNW_STEP_END; return UNW_STEP_SUCCESS; } #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint=0); int stepWithDwarfFDE() { return DwarfInstructions::stepWithDwarf(_addressSpace, (pint_t)this->getReg(UNW_REG_IP), (pint_t)_info.unwind_info, _registers); } #endif #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND bool getInfoFromCompactEncodingSection(pint_t pc, const UnwindInfoSections §s); int stepWithCompactEncoding() { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND if ( compactSaysUseDwarf() ) return stepWithDwarfFDE(); #endif R dummy; return stepWithCompactEncoding(dummy); } int stepWithCompactEncoding(Registers_x86_64 &) { return CompactUnwinder_x86_64::stepWithCompactEncoding( _info.format, _info.start_ip, _addressSpace, _registers); } int stepWithCompactEncoding(Registers_x86 &) { return CompactUnwinder_x86::stepWithCompactEncoding( _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); } int stepWithCompactEncoding(Registers_ppc &) { return UNW_EINVAL; } int stepWithCompactEncoding(Registers_arm64 &) { return CompactUnwinder_arm64::stepWithCompactEncoding( _info.format, _info.start_ip, _addressSpace, _registers); } bool compactSaysUseDwarf(uint32_t *offset=NULL) const { R dummy; return compactSaysUseDwarf(dummy, offset); } bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { if (offset) *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); return true; } return false; } bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { if (offset) *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET); return true; } return false; } bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { return true; } bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { if (offset) *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET); return true; } return false; } #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if _LIBUNWIND_SUPPORT_DWARF_UNWIND compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); } compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { return UNWIND_X86_64_MODE_DWARF; } compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { return UNWIND_X86_MODE_DWARF; } compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { return 0; } compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { return UNWIND_ARM64_MODE_DWARF; } compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { return 0; } #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND A &_addressSpace; R _registers; unw_proc_info_t _info; bool _unwindInfoMissing; bool _isSignalFrame; }; template UnwindCursor::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _registers(context), _unwindInfoMissing(false), _isSignalFrame(false) { static_assert(sizeof(UnwindCursor) < sizeof(unw_cursor_t), "UnwindCursor<> does not fit in unw_cursor_t"); memset(&_info, 0, sizeof(_info)); } template UnwindCursor::UnwindCursor(A &as, void *) : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { memset(&_info, 0, sizeof(_info)); // FIXME // fill in _registers from thread arg } template bool UnwindCursor::validReg(int regNum) { return _registers.validRegister(regNum); } template unw_word_t UnwindCursor::getReg(int regNum) { return _registers.getRegister(regNum); } template void UnwindCursor::setReg(int regNum, unw_word_t value) { _registers.setRegister(regNum, (typename A::pint_t)value); } template bool UnwindCursor::validFloatReg(int regNum) { return _registers.validFloatRegister(regNum); } template unw_fpreg_t UnwindCursor::getFloatReg(int regNum) { return _registers.getFloatRegister(regNum); } template void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { _registers.setFloatRegister(regNum, value); } template void UnwindCursor::jumpto() { _registers.jumpto(); } #ifdef __arm__ template void UnwindCursor::saveVFPAsX() { _registers.saveVFPAsX(); } #endif template const char *UnwindCursor::getRegisterName(int regNum) { return _registers.getRegisterName(regNum); } template bool UnwindCursor::isSignalFrame() { return _isSignalFrame; } #if _LIBUNWIND_ARM_EHABI struct EHABIIndexEntry { uint32_t functionOffset; uint32_t data; }; template struct EHABISectionIterator { typedef EHABISectionIterator _Self; typedef std::random_access_iterator_tag iterator_category; typedef typename A::pint_t value_type; typedef typename A::pint_t* pointer; typedef typename A::pint_t& reference; typedef size_t size_type; typedef size_t difference_type; static _Self begin(A& addressSpace, const UnwindInfoSections& sects) { return _Self(addressSpace, sects, 0); } static _Self end(A& addressSpace, const UnwindInfoSections& sects) { return _Self(addressSpace, sects, sects.arm_section_length); } EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i) : _i(i), _addressSpace(&addressSpace), _sects(§s) {} _Self& operator++() { ++_i; return *this; } _Self& operator+=(size_t a) { _i += a; return *this; } _Self& operator--() { assert(_i > 0); --_i; return *this; } _Self& operator-=(size_t a) { assert(_i >= a); _i -= a; return *this; } _Self operator+(size_t a) { _Self out = *this; out._i += a; return out; } _Self operator-(size_t a) { assert(_i >= a); _Self out = *this; out._i -= a; return out; } size_t operator-(const _Self& other) { return _i - other._i; } bool operator==(const _Self& other) const { assert(_addressSpace == other._addressSpace); assert(_sects == other._sects); return _i == other._i; } typename A::pint_t operator*() const { return functionAddress(); } typename A::pint_t functionAddress() const { typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( EHABIIndexEntry, _i, functionOffset); return indexAddr + signExtendPrel31(_addressSpace->get32(indexAddr)); } typename A::pint_t dataAddress() { typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( EHABIIndexEntry, _i, data); return indexAddr; } private: size_t _i; A* _addressSpace; const UnwindInfoSections* _sects; }; template bool UnwindCursor::getInfoFromEHABISection( pint_t pc, const UnwindInfoSections §s) { EHABISectionIterator begin = EHABISectionIterator::begin(_addressSpace, sects); EHABISectionIterator end = EHABISectionIterator::end(_addressSpace, sects); EHABISectionIterator itNextPC = std::upper_bound(begin, end, pc); if (itNextPC == begin || itNextPC == end) return false; EHABISectionIterator itThisPC = itNextPC - 1; pint_t thisPC = itThisPC.functionAddress(); pint_t nextPC = itNextPC.functionAddress(); pint_t indexDataAddr = itThisPC.dataAddress(); if (indexDataAddr == 0) return false; uint32_t indexData = _addressSpace.get32(indexDataAddr); if (indexData == UNW_EXIDX_CANTUNWIND) return false; // If the high bit is set, the exception handling table entry is inline inside // the index table entry on the second word (aka |indexDataAddr|). Otherwise, // the table points at an offset in the exception handling table (section 5 EHABI). pint_t exceptionTableAddr; uint32_t exceptionTableData; bool isSingleWordEHT; if (indexData & 0x80000000) { exceptionTableAddr = indexDataAddr; // TODO(ajwong): Should this data be 0? exceptionTableData = indexData; isSingleWordEHT = true; } else { exceptionTableAddr = indexDataAddr + signExtendPrel31(indexData); exceptionTableData = _addressSpace.get32(exceptionTableAddr); isSingleWordEHT = false; } // Now we know the 3 things: // exceptionTableAddr -- exception handler table entry. // exceptionTableData -- the data inside the first word of the eht entry. // isSingleWordEHT -- whether the entry is in the index. unw_word_t personalityRoutine = 0xbadf00d; bool scope32 = false; uintptr_t lsda; // If the high bit in the exception handling table entry is set, the entry is // in compact form (section 6.3 EHABI). if (exceptionTableData & 0x80000000) { // Grab the index of the personality routine from the compact form. uint32_t choice = (exceptionTableData & 0x0f000000) >> 24; uint32_t extraWords = 0; switch (choice) { case 0: personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0; extraWords = 0; scope32 = false; lsda = isSingleWordEHT ? 0 : (exceptionTableAddr + 4); break; case 1: personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1; extraWords = (exceptionTableData & 0x00ff0000) >> 16; scope32 = false; lsda = exceptionTableAddr + (extraWords + 1) * 4; break; case 2: personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2; extraWords = (exceptionTableData & 0x00ff0000) >> 16; scope32 = true; lsda = exceptionTableAddr + (extraWords + 1) * 4; break; default: _LIBUNWIND_ABORT("unknown personality routine"); return false; } if (isSingleWordEHT) { if (extraWords != 0) { _LIBUNWIND_ABORT("index inlined table detected but pr function " "requires extra words"); return false; } } } else { pint_t personalityAddr = exceptionTableAddr + signExtendPrel31(exceptionTableData); personalityRoutine = personalityAddr; // ARM EHABI # 6.2, # 9.2 // // +---- ehtp // v // +--------------------------------------+ // | +--------+--------+--------+-------+ | // | |0| prel31 to personalityRoutine | | // | +--------+--------+--------+-------+ | // | | N | unwind opcodes | | <-- UnwindData // | +--------+--------+--------+-------+ | // | | Word 2 unwind opcodes | | // | +--------+--------+--------+-------+ | // | ... | // | +--------+--------+--------+-------+ | // | | Word N unwind opcodes | | // | +--------+--------+--------+-------+ | // | | LSDA | | <-- lsda // | | ... | | // | +--------+--------+--------+-------+ | // +--------------------------------------+ uint32_t *UnwindData = reinterpret_cast(exceptionTableAddr) + 1; uint32_t FirstDataWord = *UnwindData; size_t N = ((FirstDataWord >> 24) & 0xff); size_t NDataWords = N + 1; lsda = reinterpret_cast(UnwindData + NDataWords); } _info.start_ip = thisPC; _info.end_ip = nextPC; _info.handler = personalityRoutine; _info.unwind_info = exceptionTableAddr; _info.lsda = lsda; // flags is pr_cache.additional. See EHABI #7.2 for definition of bit 0. _info.flags = isSingleWordEHT ? 1 : 0 | scope32 ? 0x2 : 0; // Use enum? return true; } #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND template bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint) { typename CFI_Parser::FDE_Info fdeInfo; typename CFI_Parser::CIE_Info cieInfo; bool foundFDE = false; bool foundInCache = false; // If compact encoding table gave offset into dwarf section, go directly there if (fdeSectionOffsetHint != 0) { foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, (uint32_t)sects.dwarf_section_length, sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo); } #if _LIBUNWIND_SUPPORT_DWARF_INDEX if (!foundFDE && (sects.dwarf_index_section != 0)) { foundFDE = EHHeaderParser::findFDE( _addressSpace, pc, sects.dwarf_index_section, (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo); } #endif if (!foundFDE) { // otherwise, search cache of previously found FDEs. pint_t cachedFDE = DwarfFDECache::findFDE(sects.dso_base, pc); if (cachedFDE != 0) { foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, (uint32_t)sects.dwarf_section_length, cachedFDE, &fdeInfo, &cieInfo); foundInCache = foundFDE; } } if (!foundFDE) { // Still not found, do full scan of __eh_frame section. foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, (uint32_t)sects.dwarf_section_length, 0, &fdeInfo, &cieInfo); } if (foundFDE) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, &prolog)) { // Save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; _info.lsda = fdeInfo.lsda; _info.handler = cieInfo.personality; _info.gp = prolog.spExtraArgSize; _info.flags = 0; _info.format = dwarfEncoding(); _info.unwind_info = fdeInfo.fdeStart; _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; _info.extra = (unw_word_t) sects.dso_base; // Add to cache (to make next lookup faster) if we had no hint // and there was no index. if (!foundInCache && (fdeSectionOffsetHint == 0)) { #if _LIBUNWIND_SUPPORT_DWARF_INDEX if (sects.dwarf_index_section == 0) #endif DwarfFDECache::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); } return true; } } //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc); return false; } #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND template bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, const UnwindInfoSections §s) { const bool log = false; if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)sects.dso_base); const UnwindSectionHeader sectionHeader(_addressSpace, sects.compact_unwind_section); if (sectionHeader.version() != UNWIND_SECTION_VERSION) return false; // do a binary search of top level index to find page with unwind info pint_t targetFunctionOffset = pc - sects.dso_base; const UnwindSectionIndexArray topIndex(_addressSpace, sects.compact_unwind_section + sectionHeader.indexSectionOffset()); uint32_t low = 0; uint32_t high = sectionHeader.indexCount(); uint32_t last = high - 1; while (low < high) { uint32_t mid = (low + high) / 2; //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", //mid, low, high, topIndex.functionOffset(mid)); if (topIndex.functionOffset(mid) <= targetFunctionOffset) { if ((mid == last) || (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) { low = mid; break; } else { low = mid + 1; } } else { high = mid; } } const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low + 1); const pint_t secondLevelAddr = sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low); const pint_t lsdaArrayStartAddr = sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low); const pint_t lsdaArrayEndAddr = sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1); if (log) fprintf(stderr, "\tfirst level search for result index=%d " "to secondLevelAddr=0x%llX\n", low, (uint64_t) secondLevelAddr); // do a binary search of second level page index uint32_t encoding = 0; pint_t funcStart = 0; pint_t funcEnd = 0; pint_t lsda = 0; pint_t personality = 0; uint32_t pageKind = _addressSpace.get32(secondLevelAddr); if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) { // regular page UnwindSectionRegularPageHeader pageHeader(_addressSpace, secondLevelAddr); UnwindSectionRegularArray pageIndex( _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); // binary search looks for entry with e where index[e].offset <= pc < // index[e+1].offset if (log) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in " "regular page starting at secondLevelAddr=0x%llX\n", (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr); low = 0; high = pageHeader.entryCount(); while (low < high) { uint32_t mid = (low + high) / 2; if (pageIndex.functionOffset(mid) <= targetFunctionOffset) { if (mid == (uint32_t)(pageHeader.entryCount() - 1)) { // at end of table low = mid; funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; break; } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) { // next is too big, so we found it low = mid; funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base; break; } else { low = mid + 1; } } else { high = mid; } } encoding = pageIndex.encoding(low); funcStart = pageIndex.functionOffset(low) + sects.dso_base; if (pc < funcStart) { if (log) fprintf( stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); return false; } if (pc > funcEnd) { if (log) fprintf( stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); return false; } } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) { // compressed page UnwindSectionCompressedPageHeader pageHeader(_addressSpace, secondLevelAddr); UnwindSectionCompressedArray pageIndex( _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); const uint32_t targetFunctionPageOffset = (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset); // binary search looks for entry with e where index[e].offset <= pc < // index[e+1].offset if (log) fprintf(stderr, "\tbinary search of compressed page starting at " "secondLevelAddr=0x%llX\n", (uint64_t) secondLevelAddr); low = 0; last = pageHeader.entryCount() - 1; high = pageHeader.entryCount(); while (low < high) { uint32_t mid = (low + high) / 2; if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) { if ((mid == last) || (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) { low = mid; break; } else { low = mid + 1; } } else { high = mid; } } funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + sects.dso_base; if (low < last) funcEnd = pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset + sects.dso_base; else funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; if (pc < funcStart) { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " "level compressed unwind table. funcStart=0x%llX\n", (uint64_t) pc, (uint64_t) funcStart); return false; } if (pc > funcEnd) { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " "level compressed unwind table. funcEnd=0x%llX\n", (uint64_t) pc, (uint64_t) funcEnd); return false; } uint16_t encodingIndex = pageIndex.encodingIndex(low); if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) { // encoding is in common table in section header encoding = _addressSpace.get32( sects.compact_unwind_section + sectionHeader.commonEncodingsArraySectionOffset() + encodingIndex * sizeof(uint32_t)); } else { // encoding is in page specific table uint16_t pageEncodingIndex = encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount(); encoding = _addressSpace.get32(secondLevelAddr + pageHeader.encodingsPageOffset() + pageEncodingIndex * sizeof(uint32_t)); } } else { _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second " "level page\n", (uint64_t) sects.compact_unwind_section); return false; } // look up LSDA, if encoding says function has one if (encoding & UNWIND_HAS_LSDA) { UnwindSectionLsdaArray lsdaIndex(_addressSpace, lsdaArrayStartAddr); uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base); low = 0; high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) / sizeof(unwind_info_section_header_lsda_index_entry); // binary search looks for entry with exact match for functionOffset if (log) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset); while (low < high) { uint32_t mid = (low + high) / 2; if (lsdaIndex.functionOffset(mid) == funcStartOffset) { lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base; break; } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) { low = mid + 1; } else { high = mid; } } if (lsda == 0) { _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " "pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t) pc); return false; } } // extact personality routine, if encoding says function has one uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK)); if (personalityIndex != 0) { --personalityIndex; // change 1-based to zero-based index if (personalityIndex > sectionHeader.personalityArrayCount()) { _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " "but personality table has only %d entires\n", encoding, personalityIndex, sectionHeader.personalityArrayCount()); return false; } int32_t personalityDelta = (int32_t)_addressSpace.get32( sects.compact_unwind_section + sectionHeader.personalityArraySectionOffset() + personalityIndex * sizeof(uint32_t)); pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; personality = _addressSpace.getP(personalityPointer); if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " "personalityDelta=0x%08X, personality=0x%08llX\n", (uint64_t) pc, personalityDelta, (uint64_t) personality); } if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart); _info.start_ip = funcStart; _info.end_ip = funcEnd; _info.lsda = lsda; _info.handler = personality; _info.gp = 0; _info.flags = 0; _info.format = encoding; _info.unwind_info = 0; _info.unwind_info_size = 0; _info.extra = sects.dso_base; return true; } #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND template void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { pint_t pc = (pint_t)this->getReg(UNW_REG_IP); #if _LIBUNWIND_ARM_EHABI // Remove the thumb bit so the IP represents the actual instruction address. // This matches the behaviour of _Unwind_GetIP on arm. pc &= (pint_t)~0x1; #endif // If the last line of a function is a "throw" the compiler sometimes // emits no instructions after the call to __cxa_throw. This means // the return address is actually the start of the next function. // To disambiguate this, back up the pc when we know it is a return // address. if (isReturnAddress) --pc; // Ask address space object to find unwind sections for this pc. UnwindInfoSections sects; if (_addressSpace.findUnwindSections(pc, sects)) { #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND // If there is a compact unwind encoding table, look there first. if (sects.compact_unwind_section != 0) { if (this->getInfoFromCompactEncodingSection(pc, sects)) { #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // Found info in table, done unless encoding says to use dwarf. uint32_t dwarfOffset; if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) { // found info in dwarf, done return; } } #endif // If unwind table has entry, but entry says there is no unwind info, // record that we have no unwind info. if (_info.format == 0) _unwindInfoMissing = true; return; } } #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // If there is dwarf unwind info, look there next. if (sects.dwarf_section != 0) { if (this->getInfoFromDwarfSection(pc, sects)) { // found info in dwarf, done return; } } #endif #if _LIBUNWIND_ARM_EHABI // If there is ARM EHABI unwind info, look there next. if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects)) return; #endif } #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // There is no static unwind info for this pc. Look to see if an FDE was // dynamically registered for it. pint_t cachedFDE = DwarfFDECache::findFDE(0, pc); if (cachedFDE != 0) { CFI_Parser::FDE_Info fdeInfo; CFI_Parser::CIE_Info cieInfo; const char *msg = CFI_Parser::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, &cieInfo); if (msg == NULL) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, &prolog)) { // save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; _info.lsda = fdeInfo.lsda; _info.handler = cieInfo.personality; _info.gp = prolog.spExtraArgSize; // Some frameless functions need SP // altered when resuming in function. _info.flags = 0; _info.format = dwarfEncoding(); _info.unwind_info = fdeInfo.fdeStart; _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; _info.extra = 0; return; } } } // Lastly, ask AddressSpace object about platform specific ways to locate // other FDEs. pint_t fde; if (_addressSpace.findOtherFDE(pc, fde)) { CFI_Parser::FDE_Info fdeInfo; CFI_Parser::CIE_Info cieInfo; if (!CFI_Parser::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { // Double check this FDE is for a function that includes the pc. if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { typename CFI_Parser::PrologInfo prolog; if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, &prolog)) { // save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; _info.lsda = fdeInfo.lsda; _info.handler = cieInfo.personality; _info.gp = prolog.spExtraArgSize; _info.flags = 0; _info.format = dwarfEncoding(); _info.unwind_info = fdeInfo.fdeStart; _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; _info.extra = 0; return; } } } } #endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND // no unwind info, flag that we can't reliably unwind _unwindInfoMissing = true; } template int UnwindCursor::step() { // Bottom of stack is defined is when unwind info cannot be found. if (_unwindInfoMissing) return UNW_STEP_END; // Use unwinding info to modify register set as if function returned. int result; #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND result = this->stepWithCompactEncoding(); #elif _LIBUNWIND_SUPPORT_DWARF_UNWIND result = this->stepWithDwarfFDE(); #elif _LIBUNWIND_ARM_EHABI result = this->stepWithEHABI(); #else #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ _LIBUNWIND_ARM_EHABI #endif // update info based on new PC if (result == UNW_STEP_SUCCESS) { this->setInfoBasedOnIPRegister(true); if (_unwindInfoMissing) return UNW_STEP_END; if (_info.gp) setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp); } return result; } template void UnwindCursor::getInfo(unw_proc_info_t *info) { *info = _info; } template bool UnwindCursor::getFunctionName(char *buf, size_t bufLen, unw_word_t *offset) { return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP), buf, bufLen, offset); } } // namespace libunwind #endif // __UNWINDCURSOR_HPP__ diff --git a/contrib/llvm/projects/libunwind/src/UnwindRegistersSave.S b/contrib/llvm/projects/libunwind/src/UnwindRegistersSave.S index 1275c2a16175..f84b7114f777 100644 --- a/contrib/llvm/projects/libunwind/src/UnwindRegistersSave.S +++ b/contrib/llvm/projects/libunwind/src/UnwindRegistersSave.S @@ -1,457 +1,466 @@ //===------------------------ UnwindRegistersSave.S -----------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "assembly.h" .text #if defined(__i386__) # # extern int unw_getcontext(unw_context_t* thread_state) # # On entry: # + + # +-----------------------+ # + thread_state pointer + # +-----------------------+ # + return address + # +-----------------------+ <-- SP # + + # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) push %eax movl 8(%esp), %eax movl %ebx, 4(%eax) movl %ecx, 8(%eax) movl %edx, 12(%eax) movl %edi, 16(%eax) movl %esi, 20(%eax) movl %ebp, 24(%eax) movl %esp, %edx addl $8, %edx movl %edx, 28(%eax) # store what sp was at call site as esp # skip ss # skip eflags movl 4(%esp), %edx movl %edx, 40(%eax) # store return address as eip # skip cs # skip ds # skip es # skip fs # skip gs movl (%esp), %edx movl %edx, (%eax) # store original eax popl %eax xorl %eax, %eax # return UNW_ESUCCESS ret #elif defined(__x86_64__) # # extern int unw_getcontext(unw_context_t* thread_state) # # On entry: # thread_state pointer is in rdi # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) movq %rax, (%rdi) movq %rbx, 8(%rdi) movq %rcx, 16(%rdi) movq %rdx, 24(%rdi) movq %rdi, 32(%rdi) movq %rsi, 40(%rdi) movq %rbp, 48(%rdi) movq %rsp, 56(%rdi) addq $8, 56(%rdi) movq %r8, 64(%rdi) movq %r9, 72(%rdi) movq %r10, 80(%rdi) movq %r11, 88(%rdi) movq %r12, 96(%rdi) movq %r13,104(%rdi) movq %r14,112(%rdi) movq %r15,120(%rdi) movq (%rsp),%rsi movq %rsi,128(%rdi) # store return address as rip # skip rflags # skip cs # skip fs # skip gs xorl %eax, %eax # return UNW_ESUCCESS ret +# elif defined(__mips__) + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# Just trap for the time being. +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + teq $0, $0 + #elif defined(__ppc__) ; ; extern int unw_getcontext(unw_context_t* thread_state) ; ; On entry: ; thread_state pointer is in r3 ; DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) stw r0, 8(r3) mflr r0 stw r0, 0(r3) ; store lr as ssr0 stw r1, 12(r3) stw r2, 16(r3) stw r3, 20(r3) stw r4, 24(r3) stw r5, 28(r3) stw r6, 32(r3) stw r7, 36(r3) stw r8, 40(r3) stw r9, 44(r3) stw r10, 48(r3) stw r11, 52(r3) stw r12, 56(r3) stw r13, 60(r3) stw r14, 64(r3) stw r15, 68(r3) stw r16, 72(r3) stw r17, 76(r3) stw r18, 80(r3) stw r19, 84(r3) stw r20, 88(r3) stw r21, 92(r3) stw r22, 96(r3) stw r23,100(r3) stw r24,104(r3) stw r25,108(r3) stw r26,112(r3) stw r27,116(r3) stw r28,120(r3) stw r29,124(r3) stw r30,128(r3) stw r31,132(r3) ; save VRSave register mfspr r0,256 stw r0,156(r3) ; save CR registers mfcr r0 stw r0,136(r3) ; save CTR register mfctr r0 stw r0,148(r3) ; save float registers stfd f0, 160(r3) stfd f1, 168(r3) stfd f2, 176(r3) stfd f3, 184(r3) stfd f4, 192(r3) stfd f5, 200(r3) stfd f6, 208(r3) stfd f7, 216(r3) stfd f8, 224(r3) stfd f9, 232(r3) stfd f10,240(r3) stfd f11,248(r3) stfd f12,256(r3) stfd f13,264(r3) stfd f14,272(r3) stfd f15,280(r3) stfd f16,288(r3) stfd f17,296(r3) stfd f18,304(r3) stfd f19,312(r3) stfd f20,320(r3) stfd f21,328(r3) stfd f22,336(r3) stfd f23,344(r3) stfd f24,352(r3) stfd f25,360(r3) stfd f26,368(r3) stfd f27,376(r3) stfd f28,384(r3) stfd f29,392(r3) stfd f30,400(r3) stfd f31,408(r3) ; save vector registers subi r4,r1,16 rlwinm r4,r4,0,0,27 ; mask low 4-bits ; r4 is now a 16-byte aligned pointer into the red zone #define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ stvx _vec,0,r4 @\ lwz r5, 0(r4) @\ stw r5, _offset(r3) @\ lwz r5, 4(r4) @\ stw r5, _offset+4(r3) @\ lwz r5, 8(r4) @\ stw r5, _offset+8(r3) @\ lwz r5, 12(r4) @\ stw r5, _offset+12(r3) SAVE_VECTOR_UNALIGNED( v0, 424+0x000) SAVE_VECTOR_UNALIGNED( v1, 424+0x010) SAVE_VECTOR_UNALIGNED( v2, 424+0x020) SAVE_VECTOR_UNALIGNED( v3, 424+0x030) SAVE_VECTOR_UNALIGNED( v4, 424+0x040) SAVE_VECTOR_UNALIGNED( v5, 424+0x050) SAVE_VECTOR_UNALIGNED( v6, 424+0x060) SAVE_VECTOR_UNALIGNED( v7, 424+0x070) SAVE_VECTOR_UNALIGNED( v8, 424+0x080) SAVE_VECTOR_UNALIGNED( v9, 424+0x090) SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0) SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0) SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0) SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0) SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0) SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0) SAVE_VECTOR_UNALIGNED(v16, 424+0x100) SAVE_VECTOR_UNALIGNED(v17, 424+0x110) SAVE_VECTOR_UNALIGNED(v18, 424+0x120) SAVE_VECTOR_UNALIGNED(v19, 424+0x130) SAVE_VECTOR_UNALIGNED(v20, 424+0x140) SAVE_VECTOR_UNALIGNED(v21, 424+0x150) SAVE_VECTOR_UNALIGNED(v22, 424+0x160) SAVE_VECTOR_UNALIGNED(v23, 424+0x170) SAVE_VECTOR_UNALIGNED(v24, 424+0x180) SAVE_VECTOR_UNALIGNED(v25, 424+0x190) SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0) SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0) SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0) SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0) SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0) SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0) li r3, 0 ; return UNW_ESUCCESS blr #elif defined(__arm64__) || defined(__aarch64__) // // extern int unw_getcontext(unw_context_t* thread_state) // // On entry: // thread_state pointer is in x0 // .p2align 2 DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) stp x0, x1, [x0, #0x000] stp x2, x3, [x0, #0x010] stp x4, x5, [x0, #0x020] stp x6, x7, [x0, #0x030] stp x8, x9, [x0, #0x040] stp x10,x11, [x0, #0x050] stp x12,x13, [x0, #0x060] stp x14,x15, [x0, #0x070] stp x16,x17, [x0, #0x080] stp x18,x19, [x0, #0x090] stp x20,x21, [x0, #0x0A0] stp x22,x23, [x0, #0x0B0] stp x24,x25, [x0, #0x0C0] stp x26,x27, [x0, #0x0D0] stp x28,fp, [x0, #0x0E0] str lr, [x0, #0x0F0] mov x1,sp str x1, [x0, #0x0F8] str lr, [x0, #0x100] // store return address as pc // skip cpsr stp d0, d1, [x0, #0x110] stp d2, d3, [x0, #0x120] stp d4, d5, [x0, #0x130] stp d6, d7, [x0, #0x140] stp d8, d9, [x0, #0x150] stp d10,d11, [x0, #0x160] stp d12,d13, [x0, #0x170] stp d14,d15, [x0, #0x180] stp d16,d17, [x0, #0x190] stp d18,d19, [x0, #0x1A0] stp d20,d21, [x0, #0x1B0] stp d22,d23, [x0, #0x1C0] stp d24,d25, [x0, #0x1D0] stp d26,d27, [x0, #0x1E0] stp d28,d29, [x0, #0x1F0] str d30, [x0, #0x200] str d31, [x0, #0x208] mov x0, #0 // return UNW_ESUCCESS ret #elif defined(__arm__) && !defined(__APPLE__) #if !defined(__ARM_ARCH_ISA_ARM) .thumb #endif @ @ extern int unw_getcontext(unw_context_t* thread_state) @ @ On entry: @ thread_state pointer is in r0 @ @ Per EHABI #4.7 this only saves the core integer registers. @ EHABI #7.4.5 notes that in general all VRS registers should be restored @ however this is very hard to do for VFP registers because it is unknown @ to the library how many registers are implemented by the architecture. @ Instead, VFP registers are demand saved by logic external to unw_getcontext. @ .p2align 2 DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) #if !defined(__ARM_ARCH_ISA_ARM) stm r0, {r0-r7} mov r2, sp mov r3, lr str r2, [r0, #52] str r3, [r0, #56] str r3, [r0, #60] @ store return address as pc #else @ 32bit thumb-2 restrictions for stm: @ . the sp (r13) cannot be in the list @ . the pc (r15) cannot be in the list in an STM instruction stm r0, {r0-r12} str sp, [r0, #52] str lr, [r0, #56] str lr, [r0, #60] @ store return address as pc #endif #if __ARM_ARCH_ISA_THUMB == 1 @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. @ It is safe to use here though because we are about to return, and cpsr is @ not expected to be preserved. movs r0, #0 @ return UNW_ESUCCESS #else mov r0, #0 @ return UNW_ESUCCESS #endif JMP(lr) @ @ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3-d16 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy) vstmia r0, {d0-d15} JMP(lr) @ @ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3-d16 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy) vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia JMP(lr) @ @ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 .fpu vfpv3 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy) @ VFP and iwMMX instructions are only available when compiling with the flags @ that enable them. We do not want to do that in the library (because we do not @ want the compiler to generate instructions that access those) but this is @ only accessed if the personality routine needs these registers. Use of @ these registers implies they are, actually, available on the target, so @ it's ok to execute. @ So, generate the instructions using the corresponding coprocessor mnemonic. vstmia r0, {d16-d31} JMP(lr) @ @ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy) #if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8 stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8 stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8 stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8 stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8 stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8 stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8 stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8 stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8 stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8 stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8 stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 #endif JMP(lr) @ @ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values) @ @ On entry: @ values pointer is in r0 @ .p2align 2 DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) #if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX) stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4 stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 #endif JMP(lr) #elif defined(__or1k__) # # extern int unw_getcontext(unw_context_t* thread_state) # # On entry: # thread_state pointer is in r3 # DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) l.sw 0(r3), r0 l.sw 4(r3), r1 l.sw 8(r3), r2 l.sw 12(r3), r3 l.sw 16(r3), r4 l.sw 20(r3), r5 l.sw 24(r3), r6 l.sw 28(r3), r7 l.sw 32(r3), r8 l.sw 36(r3), r9 l.sw 40(r3), r10 l.sw 44(r3), r11 l.sw 48(r3), r12 l.sw 52(r3), r13 l.sw 56(r3), r14 l.sw 60(r3), r15 l.sw 64(r3), r16 l.sw 68(r3), r17 l.sw 72(r3), r18 l.sw 76(r3), r19 l.sw 80(r3), r20 l.sw 84(r3), r21 l.sw 88(r3), r22 l.sw 92(r3), r23 l.sw 96(r3), r24 l.sw 100(r3), r25 l.sw 104(r3), r26 l.sw 108(r3), r27 l.sw 112(r3), r28 l.sw 116(r3), r29 l.sw 120(r3), r30 l.sw 124(r3), r31 #endif diff --git a/contrib/llvm/projects/libunwind/src/config.h b/contrib/llvm/projects/libunwind/src/config.h index 9b246347a851..ecc0a6b4465d 100644 --- a/contrib/llvm/projects/libunwind/src/config.h +++ b/contrib/llvm/projects/libunwind/src/config.h @@ -1,127 +1,128 @@ //===----------------------------- config.h -------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Defines macros used within libuwind project. // //===----------------------------------------------------------------------===// #ifndef LIBUNWIND_CONFIG_H #define LIBUNWIND_CONFIG_H #include #include // Define static_assert() unless already defined by compiler. #ifndef __has_feature #define __has_feature(__x) 0 #endif #if !(__has_feature(cxx_static_assert)) && !defined(static_assert) #define static_assert(__b, __m) \ extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \ __attribute__( ( unused ) ); #endif // Platform specific configuration defines. #ifdef __APPLE__ #include #ifdef __cplusplus extern "C" { #endif void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn)); #ifdef __cplusplus } #endif #define _LIBUNWIND_BUILD_ZERO_COST_APIS (defined(__i386__) || \ defined(__x86_64__) || \ - defined(__arm64__)) + defined(__arm64__) || \ + defined(__mips__)) #define _LIBUNWIND_BUILD_SJLJ_APIS defined(__arm__) #define _LIBUNWIND_SUPPORT_FRAME_APIS (defined(__i386__) || \ defined(__x86_64__)) #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) #define _LIBUNWIND_ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg) #if defined(FOR_DYLD) #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0 #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 #else #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 #endif #else #include static inline void assert_rtn(const char* func, const char* file, int line, const char* msg) __attribute__ ((noreturn)); static inline void assert_rtn(const char* func, const char* file, int line, const char* msg) { fprintf(stderr, "libunwind: %s %s:%d - %s\n", func, file, line, msg); assert(false); abort(); } #define _LIBUNWIND_BUILD_ZERO_COST_APIS (defined(__i386__) || \ defined(__x86_64__) || \ defined(__arm__) || \ defined(__aarch64__)) #define _LIBUNWIND_BUILD_SJLJ_APIS 0 #define _LIBUNWIND_SUPPORT_FRAME_APIS (defined(__i386__) || \ defined(__x86_64__)) #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) #define _LIBUNWIND_ABORT(msg) assert_rtn(__func__, __FILE__, __LINE__, msg) #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND !defined(__arm__) || \ defined(__ARM_DWARF_EH__) #define _LIBUNWIND_SUPPORT_DWARF_INDEX _LIBUNWIND_SUPPORT_DWARF_UNWIND #endif // Macros that define away in non-Debug builds #ifdef NDEBUG #define _LIBUNWIND_DEBUG_LOG(msg, ...) #define _LIBUNWIND_TRACE_API(msg, ...) #define _LIBUNWIND_TRACING_UNWINDING 0 #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) #define _LIBUNWIND_LOG_NON_ZERO(x) x #else #ifdef __cplusplus extern "C" { #endif extern bool logAPIs(); extern bool logUnwinding(); #ifdef __cplusplus } #endif #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) #define _LIBUNWIND_LOG_NON_ZERO(x) \ do { \ int _err = x; \ if ( _err != 0 ) \ _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \ } while (0) #define _LIBUNWIND_TRACE_API(msg, ...) \ do { \ if ( logAPIs() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ } while(0) #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ do { \ if ( logUnwinding() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ } while(0) #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() #endif #endif // LIBUNWIND_CONFIG_H diff --git a/contrib/llvm/projects/libunwind/src/libunwind.cpp b/contrib/llvm/projects/libunwind/src/libunwind.cpp index a23dfcf7677a..f9f32f00ece2 100644 --- a/contrib/llvm/projects/libunwind/src/libunwind.cpp +++ b/contrib/llvm/projects/libunwind/src/libunwind.cpp @@ -1,376 +1,378 @@ //===--------------------------- libuwind.cpp -----------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // // // Implements unw_* functions from // //===----------------------------------------------------------------------===// #include #ifndef NDEBUG #include // getenv #endif #include #include #include "libunwind_ext.h" #include "config.h" #include #include "UnwindCursor.hpp" using namespace libunwind; /// internal object to represent this processes address space LocalAddressSpace LocalAddressSpace::sThisAddressSpace; _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; /// record the registers and stack position of the caller extern int unw_getcontext(unw_context_t *); // note: unw_getcontext() implemented in assembly /// Create a cursor of a thread in this process given 'context' recorded by /// unw_getcontext(). _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor, unw_context_t *context) { _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n", static_cast(cursor), static_cast(context)); // Use "placement new" to allocate UnwindCursor in the cursor buffer. #if defined(__i386__) new ((void *)cursor) UnwindCursor( context, LocalAddressSpace::sThisAddressSpace); #elif defined(__x86_64__) new ((void *)cursor) UnwindCursor( context, LocalAddressSpace::sThisAddressSpace); #elif defined(__ppc__) new ((void *)cursor) UnwindCursor( context, LocalAddressSpace::sThisAddressSpace); #elif defined(__arm64__) || defined(__aarch64__) new ((void *)cursor) UnwindCursor( context, LocalAddressSpace::sThisAddressSpace); #elif _LIBUNWIND_ARM_EHABI new ((void *)cursor) UnwindCursor( context, LocalAddressSpace::sThisAddressSpace); #elif defined(__or1k__) new ((void *)cursor) UnwindCursor( context, LocalAddressSpace::sThisAddressSpace); +#elif defined(__mips__) +#warning The MIPS architecture is not supported. #else #error Architecture not supported #endif AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->setInfoBasedOnIPRegister(); return UNW_ESUCCESS; } #ifdef UNW_REMOTE /// Create a cursor into a thread in another process. _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor, unw_addr_space_t as, void *arg) { // special case: unw_init_remote(xx, unw_local_addr_space, xx) if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace) return unw_init_local(cursor, NULL); //FIXME // use "placement new" to allocate UnwindCursor in the cursor buffer switch (as->cpuType) { case CPU_TYPE_I386: new ((void *)cursor) UnwindCursor >, Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); break; case CPU_TYPE_X86_64: new ((void *)cursor) UnwindCursor< OtherAddressSpace >, Registers_x86_64>( ((unw_addr_space_x86_64 *)as)->oas, arg); break; case CPU_TYPE_POWERPC: new ((void *)cursor) UnwindCursor >, Registers_ppc>( ((unw_addr_space_ppc *)as)->oas, arg); break; default: return UNW_EUNSPEC; } return UNW_ESUCCESS; } static bool is64bit(task_t task) { return false; // FIXME } /// Create an address_space object for use in examining another task. _LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) { #if __i386__ if (is64bit(task)) { unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task); as->taskPort = task; as->cpuType = CPU_TYPE_X86_64; //as->oas } else { unw_addr_space_i386 *as = new unw_addr_space_i386(task); as->taskPort = task; as->cpuType = CPU_TYPE_I386; //as->oas } #else // FIXME #endif } /// Delete an address_space object. _LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) { switch (asp->cpuType) { #if __i386__ || __x86_64__ case CPU_TYPE_I386: { unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp; delete as; } break; case CPU_TYPE_X86_64: { unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp; delete as; } break; #endif case CPU_TYPE_POWERPC: { unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp; delete as; } break; } } #endif // UNW_REMOTE /// Get value of specified register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t *value) { _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", static_cast(cursor), regNum, static_cast(value)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validReg(regNum)) { *value = co->getReg(regNum); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Set value of specified register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t value) { _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", static_cast(cursor), regNum, (long long)value); typedef LocalAddressSpace::pint_t pint_t; AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validReg(regNum)) { co->setReg(regNum, (pint_t)value); // specical case altering IP to re-find info (being called by personality // function) if (regNum == UNW_REG_IP) co->setInfoBasedOnIPRegister(false); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Get value of specified float register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_fpreg_t *value) { _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", static_cast(cursor), regNum, static_cast(value)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validFloatReg(regNum)) { *value = co->getFloatReg(regNum); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Set value of specified float register at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_fpreg_t value) { #if _LIBUNWIND_ARM_EHABI _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)\n", static_cast(cursor), regNum, value); #else _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", static_cast(cursor), regNum, value); #endif AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->validFloatReg(regNum)) { co->setFloatReg(regNum, value); return UNW_ESUCCESS; } return UNW_EBADREG; } /// Move cursor to next frame. _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->step(); } /// Get unwind info at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor, unw_proc_info_t *info) { _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n", static_cast(cursor), static_cast(info)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->getInfo(info); if (info->end_ip == 0) return UNW_ENOINFO; else return UNW_ESUCCESS; } /// Resume execution at cursor position (aka longjump). _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->jumpto(); return UNW_EUNSPEC; } /// Get name of function at cursor position in stack frame. _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf, size_t bufLen, unw_word_t *offset) { _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)\n", static_cast(cursor), static_cast(buf), static_cast(bufLen)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; if (co->getFunctionName(buf, bufLen, offset)) return UNW_ESUCCESS; else return UNW_EUNSPEC; } /// Checks if a register is a floating-point register. _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) { _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", static_cast(cursor), regNum); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->validFloatReg(regNum); } /// Checks if a register is a floating-point register. _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor, unw_regnum_t regNum) { _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n", static_cast(cursor), regNum); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->getRegisterName(regNum); } /// Checks if current frame is signal trampoline. _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->isSignalFrame(); } #ifdef __arm__ // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)\n", static_cast(cursor)); AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->saveVFPAsX(); } #endif #if _LIBUNWIND_SUPPORT_DWARF_UNWIND /// SPI: walks cached dwarf entries _LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)( unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", reinterpret_cast(func)); DwarfFDECache::iterateCacheEntries(func); } /// IPI: for __register_frame() void _unw_add_dynamic_fde(unw_word_t fde) { CFI_Parser::FDE_Info fdeInfo; CFI_Parser::CIE_Info cieInfo; const char *message = CFI_Parser::decodeFDE( LocalAddressSpace::sThisAddressSpace, (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); if (message == NULL) { // dynamically registered FDEs don't have a mach_header group they are in. // Use fde as mh_group unw_word_t mh_group = fdeInfo.fdeStart; DwarfFDECache::add((LocalAddressSpace::pint_t)mh_group, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); } else { _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); } } /// IPI: for __deregister_frame() void _unw_remove_dynamic_fde(unw_word_t fde) { // fde is own mh_group DwarfFDECache::removeAllIn((LocalAddressSpace::pint_t)fde); } #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND // Add logging hooks in Debug builds only #ifndef NDEBUG #include _LIBUNWIND_HIDDEN bool logAPIs() { // do manual lock to avoid use of _cxa_guard_acquire or initializers static bool checked = false; static bool log = false; if (!checked) { log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); checked = true; } return log; } _LIBUNWIND_HIDDEN bool logUnwinding() { // do manual lock to avoid use of _cxa_guard_acquire or initializers static bool checked = false; static bool log = false; if (!checked) { log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); checked = true; } return log; } #endif // NDEBUG