forked from OSchip/llvm-project
[libunwind][DWARF] Fix end of .eh_frame calculation
* When .eh_frame is located using .eh_frame_hdr (PT_GNU_EH_FRAME), the start of .eh_frame is known, but not the size. In this case, the unwinder must rely on a terminator present at the end of .eh_frame. Set dwarf_section_length to UINTPTR_MAX to indicate this. * Add a new field, text_segment_length, that the FrameHeaderCache uses to track the size of the PT_LOAD segment indicated by dso_base. * Compute ehSectionEnd by adding sectionLength to ehSectionStart, never to fdeHint. Fixes PR46829. Differential Revision: https://reviews.llvm.org/D87750
This commit is contained in:
parent
436a43afb2
commit
fb1abe0063
|
@ -119,6 +119,10 @@ struct UnwindInfoSections {
|
|||
// 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 @@ static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
|
|||
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 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
|||
found_hdr = EHHeaderParser<LocalAddressSpace>::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 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
cbdata->sects->dwarf_section_length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ public:
|
|||
};
|
||||
|
||||
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 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
|
|||
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 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
|
|||
/// Scan an eh_frame section to find an FDE for a pc
|
||||
template <typename A>
|
||||
bool CFI_Parser<A>::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<pint_t>(-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 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
|||
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.
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -1517,7 +1517,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
|||
// If compact encoding table gave offset into dwarf section, go directly there
|
||||
if (fdeSectionOffsetHint != 0) {
|
||||
foundFDE = CFI_Parser<A>::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 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
|||
if (cachedFDE != 0) {
|
||||
foundFDE =
|
||||
CFI_Parser<A>::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 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
|||
if (!foundFDE) {
|
||||
// Still not found, do full scan of __eh_frame section.
|
||||
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
||||
(uint32_t)sects.dwarf_section_length, 0,
|
||||
sects.dwarf_section_length, 0,
|
||||
&fdeInfo, &cieInfo);
|
||||
}
|
||||
if (foundFDE) {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "../src/AddressSpace.hpp"
|
||||
|
||||
#define kBaseAddr 0xFFF000
|
||||
#define kDwarfSectionLength 0xFF
|
||||
#define kTextSegmentLength 0xFF
|
||||
|
||||
using namespace libunwind;
|
||||
|
||||
|
@ -32,7 +32,7 @@ int main() {
|
|||
|
||||
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 @@ int main() {
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue