diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -923,6 +923,10 @@ #endif #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + bool getInfoFromFdeCie(const typename CFI_Parser::FDE_Info &fdeInfo, + const typename CFI_Parser::CIE_Info &cieInfo, + pint_t pc, uintptr_t dso_base, + bool should_cache_result); bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, uint32_t fdeSectionOffsetHint=0); int stepWithDwarfFDE() { @@ -1472,6 +1476,36 @@ #endif #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +template +bool UnwindCursor::getInfoFromFdeCie( + const typename CFI_Parser::FDE_Info &fdeInfo, + const typename CFI_Parser::CIE_Info &cieInfo, pint_t pc, + uintptr_t dso_base, bool should_cache_result) { + typename CFI_Parser::PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, + R::getArch(), &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 = (unw_word_t)dso_base; + + if (should_cache_result) + DwarfFDECache::add(dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + return true; + } + return false; +} + template bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, @@ -1512,32 +1546,16 @@ &fdeInfo, &cieInfo); } if (foundFDE) { - typename CFI_Parser::PrologInfo prolog; - if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, - R::getArch(), &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 defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) - if (sects.dwarf_index_section == 0) - #endif - DwarfFDECache::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, - fdeInfo.fdeStart); - } + // Add to cache (to make next lookup faster) if we had no hint and there was + // no index. + bool should_cache_result = !foundInCache && (fdeSectionOffsetHint == 0); +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + if (sects.dwarf_index_section != 0) + should_cache_result = false; +#endif + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base, + should_cache_result)) return true; - } } //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc); return false; @@ -1928,58 +1946,25 @@ // 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, R::getArch(), &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; - } - } + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + if (!CFI_Parser::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, + &cieInfo) && + getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0, false)) + 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; + typename CFI_Parser::FDE_Info fdeInfo; + typename 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, R::getArch(), &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; - } - } + if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd) && + getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0, false)) + return; } } #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)