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.
|
// No dso_base for SEH or ARM EHABI.
|
||||||
uintptr_t dso_base;
|
uintptr_t dso_base;
|
||||||
#endif
|
#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)
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
uintptr_t dwarf_section;
|
uintptr_t dwarf_section;
|
||||||
uintptr_t dwarf_section_length;
|
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;
|
uintptr_t end = begin + phdr->p_memsz;
|
||||||
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
|
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
|
||||||
cbdata->sects->dso_base = begin;
|
cbdata->sects->dso_base = begin;
|
||||||
cbdata->sects->dwarf_section_length = phdr->p_memsz;
|
cbdata->sects->text_segment_length = phdr->p_memsz;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,8 +454,12 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
||||||
found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
||||||
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
|
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
|
||||||
hdrInfo);
|
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 = hdrInfo.eh_frame_ptr;
|
||||||
|
cbdata->sects->dwarf_section_length = UINTPTR_MAX;
|
||||||
|
}
|
||||||
} else if (!found_obj) {
|
} else if (!found_obj) {
|
||||||
found_obj = checkAddrInSegment(phdr, image_base, cbdata);
|
found_obj = checkAddrInSegment(phdr, image_base, cbdata);
|
||||||
}
|
}
|
||||||
|
@ -462,7 +470,6 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cbdata->sects->dwarf_section_length = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
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);
|
CIE_Info *cieInfo);
|
||||||
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
|
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
|
||||||
FDE_Info *fdeInfo, CIE_Info *cieInfo);
|
FDE_Info *fdeInfo, CIE_Info *cieInfo);
|
||||||
|
@ -167,7 +167,7 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
|
||||||
p += 8;
|
p += 8;
|
||||||
}
|
}
|
||||||
if (cfiLength == 0)
|
if (cfiLength == 0)
|
||||||
return "FDE has zero length"; // end marker
|
return "FDE has zero length"; // zero terminator
|
||||||
uint32_t ciePointer = addressSpace.get32(p);
|
uint32_t ciePointer = addressSpace.get32(p);
|
||||||
if (ciePointer == 0)
|
if (ciePointer == 0)
|
||||||
return "FDE is really a CIE"; // this is a CIE not an FDE
|
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
|
/// Scan an eh_frame section to find an FDE for a pc
|
||||||
template <typename A>
|
template <typename A>
|
||||||
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
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) {
|
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
|
||||||
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
|
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
|
||||||
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
|
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) {
|
while (p < ehSectionEnd) {
|
||||||
pint_t currentCFI = p;
|
pint_t currentCFI = p;
|
||||||
//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)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;
|
p += 8;
|
||||||
}
|
}
|
||||||
if (cfiLength == 0)
|
if (cfiLength == 0)
|
||||||
return false; // end marker
|
return false; // zero terminator
|
||||||
uint32_t id = addressSpace.get32(p);
|
uint32_t id = addressSpace.get32(p);
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
// Skip over CIEs.
|
// Skip over CIEs.
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
class _LIBUNWIND_HIDDEN FrameHeaderCache {
|
class _LIBUNWIND_HIDDEN FrameHeaderCache {
|
||||||
struct CacheEntry {
|
struct CacheEntry {
|
||||||
uintptr_t LowPC() { return Info.dso_base; };
|
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;
|
UnwindInfoSections Info;
|
||||||
CacheEntry *Next;
|
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 compact encoding table gave offset into dwarf section, go directly there
|
||||||
if (fdeSectionOffsetHint != 0) {
|
if (fdeSectionOffsetHint != 0) {
|
||||||
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
||||||
(uint32_t)sects.dwarf_section_length,
|
sects.dwarf_section_length,
|
||||||
sects.dwarf_section + fdeSectionOffsetHint,
|
sects.dwarf_section + fdeSectionOffsetHint,
|
||||||
&fdeInfo, &cieInfo);
|
&fdeInfo, &cieInfo);
|
||||||
}
|
}
|
||||||
|
@ -1534,7 +1534,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
||||||
if (cachedFDE != 0) {
|
if (cachedFDE != 0) {
|
||||||
foundFDE =
|
foundFDE =
|
||||||
CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
||||||
(uint32_t)sects.dwarf_section_length,
|
sects.dwarf_section_length,
|
||||||
cachedFDE, &fdeInfo, &cieInfo);
|
cachedFDE, &fdeInfo, &cieInfo);
|
||||||
foundInCache = foundFDE;
|
foundInCache = foundFDE;
|
||||||
}
|
}
|
||||||
|
@ -1542,7 +1542,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
||||||
if (!foundFDE) {
|
if (!foundFDE) {
|
||||||
// Still not found, do full scan of __eh_frame section.
|
// Still not found, do full scan of __eh_frame section.
|
||||||
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_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);
|
&fdeInfo, &cieInfo);
|
||||||
}
|
}
|
||||||
if (foundFDE) {
|
if (foundFDE) {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "../src/AddressSpace.hpp"
|
#include "../src/AddressSpace.hpp"
|
||||||
|
|
||||||
#define kBaseAddr 0xFFF000
|
#define kBaseAddr 0xFFF000
|
||||||
#define kDwarfSectionLength 0xFF
|
#define kTextSegmentLength 0xFF
|
||||||
|
|
||||||
using namespace libunwind;
|
using namespace libunwind;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ int main() {
|
||||||
|
|
||||||
UnwindInfoSections UIS;
|
UnwindInfoSections UIS;
|
||||||
UIS.dso_base = kBaseAddr;
|
UIS.dso_base = kBaseAddr;
|
||||||
UIS.dwarf_section_length = kDwarfSectionLength;
|
UIS.text_segment_length = kTextSegmentLength;
|
||||||
dl_iterate_cb_data CBData;
|
dl_iterate_cb_data CBData;
|
||||||
// Unused by the cache.
|
// Unused by the cache.
|
||||||
CBData.addressSpace = nullptr;
|
CBData.addressSpace = nullptr;
|
||||||
|
@ -58,7 +58,7 @@ int main() {
|
||||||
abort();
|
abort();
|
||||||
// Add enough things to the cache that the entry is evicted.
|
// Add enough things to the cache that the entry is evicted.
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
UIS.dso_base = kBaseAddr + (kDwarfSectionLength * i);
|
UIS.dso_base = kBaseAddr + (kTextSegmentLength * i);
|
||||||
FHC.add(&UIS);
|
FHC.add(&UIS);
|
||||||
}
|
}
|
||||||
CBData.targetAddr = kBaseAddr;
|
CBData.targetAddr = kBaseAddr;
|
||||||
|
|
Loading…
Reference in New Issue