Skip to content

Commit fb1abe0

Browse files
committed
[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
1 parent 436a43a commit fb1abe0

File tree

5 files changed

+24
-15
lines changed

5 files changed

+24
-15
lines changed

libunwind/src/AddressSpace.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ struct UnwindInfoSections {
119119
// No dso_base for SEH or ARM EHABI.
120120
uintptr_t dso_base;
121121
#endif
122+
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) && \
123+
defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
124+
uintptr_t text_segment_length;
125+
#endif
122126
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
123127
uintptr_t dwarf_section;
124128
uintptr_t dwarf_section_length;
@@ -410,7 +414,7 @@ static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
410414
uintptr_t end = begin + phdr->p_memsz;
411415
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
412416
cbdata->sects->dso_base = begin;
413-
cbdata->sects->dwarf_section_length = phdr->p_memsz;
417+
cbdata->sects->text_segment_length = phdr->p_memsz;
414418
return true;
415419
}
416420
}
@@ -450,8 +454,12 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
450454
found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
451455
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
452456
hdrInfo);
453-
if (found_hdr)
457+
if (found_hdr) {
458+
// .eh_frame_hdr records the start of .eh_frame, but not its size.
459+
// Rely on a zero terminator to find the end of the section.
454460
cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
461+
cbdata->sects->dwarf_section_length = UINTPTR_MAX;
462+
}
455463
} else if (!found_obj) {
456464
found_obj = checkAddrInSegment(phdr, image_base, cbdata);
457465
}
@@ -462,7 +470,6 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
462470
return 1;
463471
}
464472
}
465-
cbdata->sects->dwarf_section_length = 0;
466473
return 0;
467474
}
468475

libunwind/src/DwarfParser.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class CFI_Parser {
136136
};
137137

138138
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
139-
uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
139+
uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
140140
CIE_Info *cieInfo);
141141
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
142142
FDE_Info *fdeInfo, CIE_Info *cieInfo);
@@ -167,7 +167,7 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
167167
p += 8;
168168
}
169169
if (cfiLength == 0)
170-
return "FDE has zero length"; // end marker
170+
return "FDE has zero length"; // zero terminator
171171
uint32_t ciePointer = addressSpace.get32(p);
172172
if (ciePointer == 0)
173173
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,
212212
/// Scan an eh_frame section to find an FDE for a pc
213213
template <typename A>
214214
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
215-
uint32_t sectionLength, pint_t fdeHint,
215+
uintptr_t sectionLength, pint_t fdeHint,
216216
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
217217
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
218218
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
219-
const pint_t ehSectionEnd = p + sectionLength;
219+
const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
220+
? static_cast<pint_t>(-1)
221+
: (ehSectionStart + sectionLength);
220222
while (p < ehSectionEnd) {
221223
pint_t currentCFI = p;
222224
//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,
228230
p += 8;
229231
}
230232
if (cfiLength == 0)
231-
return false; // end marker
233+
return false; // zero terminator
232234
uint32_t id = addressSpace.get32(p);
233235
if (id == 0) {
234236
// Skip over CIEs.

libunwind/src/FrameHeaderCache.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
class _LIBUNWIND_HIDDEN FrameHeaderCache {
3333
struct CacheEntry {
3434
uintptr_t LowPC() { return Info.dso_base; };
35-
uintptr_t HighPC() { return Info.dso_base + Info.dwarf_section_length; };
35+
uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; };
3636
UnwindInfoSections Info;
3737
CacheEntry *Next;
3838
};

libunwind/src/UnwindCursor.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,7 +1517,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
15171517
// If compact encoding table gave offset into dwarf section, go directly there
15181518
if (fdeSectionOffsetHint != 0) {
15191519
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
1520-
(uint32_t)sects.dwarf_section_length,
1520+
sects.dwarf_section_length,
15211521
sects.dwarf_section + fdeSectionOffsetHint,
15221522
&fdeInfo, &cieInfo);
15231523
}
@@ -1534,15 +1534,15 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
15341534
if (cachedFDE != 0) {
15351535
foundFDE =
15361536
CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
1537-
(uint32_t)sects.dwarf_section_length,
1537+
sects.dwarf_section_length,
15381538
cachedFDE, &fdeInfo, &cieInfo);
15391539
foundInCache = foundFDE;
15401540
}
15411541
}
15421542
if (!foundFDE) {
15431543
// Still not found, do full scan of __eh_frame section.
15441544
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
1545-
(uint32_t)sects.dwarf_section_length, 0,
1545+
sects.dwarf_section_length, 0,
15461546
&fdeInfo, &cieInfo);
15471547
}
15481548
if (foundFDE) {

libunwind/test/frameheadercache_test.pass.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "../src/AddressSpace.hpp"
1717

1818
#define kBaseAddr 0xFFF000
19-
#define kDwarfSectionLength 0xFF
19+
#define kTextSegmentLength 0xFF
2020

2121
using namespace libunwind;
2222

@@ -32,7 +32,7 @@ int main() {
3232

3333
UnwindInfoSections UIS;
3434
UIS.dso_base = kBaseAddr;
35-
UIS.dwarf_section_length = kDwarfSectionLength;
35+
UIS.text_segment_length = kTextSegmentLength;
3636
dl_iterate_cb_data CBData;
3737
// Unused by the cache.
3838
CBData.addressSpace = nullptr;
@@ -58,7 +58,7 @@ int main() {
5858
abort();
5959
// Add enough things to the cache that the entry is evicted.
6060
for (int i = 0; i < 9; i++) {
61-
UIS.dso_base = kBaseAddr + (kDwarfSectionLength * i);
61+
UIS.dso_base = kBaseAddr + (kTextSegmentLength * i);
6262
FHC.add(&UIS);
6363
}
6464
CBData.targetAddr = kBaseAddr;

0 commit comments

Comments
 (0)