diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -119,6 +119,10 @@ // No dso_base for SEH or ARM EHABI. uintptr_t dso_base; #endif +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) && \ + defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + uintptr_t text_segment_length; +#endif #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) uintptr_t dwarf_section; uintptr_t dwarf_section_length; @@ -410,7 +414,7 @@ uintptr_t end = begin + phdr->p_memsz; if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { cbdata->sects->dso_base = begin; - cbdata->sects->dwarf_section_length = phdr->p_memsz; + cbdata->sects->text_segment_length = phdr->p_memsz; return true; } } @@ -450,8 +454,12 @@ found_hdr = EHHeaderParser::decodeEHHdr( *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, hdrInfo); - if (found_hdr) + if (found_hdr) { + // .eh_frame_hdr records the start of .eh_frame, but not its size. + // Rely on a zero terminator to find the end of the section. cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; + cbdata->sects->dwarf_section_length = UINTPTR_MAX; + } } else if (!found_obj) { found_obj = checkAddrInSegment(phdr, image_base, cbdata); } @@ -462,7 +470,6 @@ return 1; } } - cbdata->sects->dwarf_section_length = 0; return 0; } diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp --- a/libunwind/src/DwarfParser.hpp +++ b/libunwind/src/DwarfParser.hpp @@ -136,7 +136,7 @@ }; static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, - uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, + uintptr_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); @@ -167,7 +167,7 @@ p += 8; } if (cfiLength == 0) - return "FDE has zero length"; // end marker + return "FDE has zero length"; // zero terminator uint32_t ciePointer = addressSpace.get32(p); if (ciePointer == 0) return "FDE is really a CIE"; // this is a CIE not an FDE @@ -212,11 +212,13 @@ /// 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, + uintptr_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; + const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX) + ? static_cast(-1) + : (ehSectionStart + sectionLength); while (p < ehSectionEnd) { pint_t currentCFI = p; //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); @@ -228,7 +230,7 @@ p += 8; } if (cfiLength == 0) - return false; // end marker + return false; // zero terminator uint32_t id = addressSpace.get32(p); if (id == 0) { // Skip over CIEs. diff --git a/libunwind/src/FrameHeaderCache.hpp b/libunwind/src/FrameHeaderCache.hpp --- a/libunwind/src/FrameHeaderCache.hpp +++ b/libunwind/src/FrameHeaderCache.hpp @@ -32,7 +32,7 @@ class _LIBUNWIND_HIDDEN FrameHeaderCache { struct CacheEntry { uintptr_t LowPC() { return Info.dso_base; }; - uintptr_t HighPC() { return Info.dso_base + Info.dwarf_section_length; }; + uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; }; UnwindInfoSections Info; CacheEntry *Next; }; diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -1517,7 +1517,7 @@ // 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_length, sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo); } @@ -1534,7 +1534,7 @@ if (cachedFDE != 0) { foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, - (uint32_t)sects.dwarf_section_length, + sects.dwarf_section_length, cachedFDE, &fdeInfo, &cieInfo); foundInCache = foundFDE; } @@ -1542,7 +1542,7 @@ 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, + sects.dwarf_section_length, 0, &fdeInfo, &cieInfo); } if (foundFDE) { diff --git a/libunwind/test/frameheadercache_test.pass.cpp b/libunwind/test/frameheadercache_test.pass.cpp --- a/libunwind/test/frameheadercache_test.pass.cpp +++ b/libunwind/test/frameheadercache_test.pass.cpp @@ -16,7 +16,7 @@ #include "../src/AddressSpace.hpp" #define kBaseAddr 0xFFF000 -#define kDwarfSectionLength 0xFF +#define kTextSegmentLength 0xFF using namespace libunwind; @@ -32,7 +32,7 @@ UnwindInfoSections UIS; UIS.dso_base = kBaseAddr; - UIS.dwarf_section_length = kDwarfSectionLength; + UIS.text_segment_length = kTextSegmentLength; dl_iterate_cb_data CBData; // Unused by the cache. CBData.addressSpace = nullptr; @@ -58,7 +58,7 @@ abort(); // Add enough things to the cache that the entry is evicted. for (int i = 0; i < 9; i++) { - UIS.dso_base = kBaseAddr + (kDwarfSectionLength * i); + UIS.dso_base = kBaseAddr + (kTextSegmentLength * i); FHC.add(&UIS); } CBData.targetAddr = kBaseAddr;