Skip to content

Commit 710d9d6

Browse files
author
Georgii Rymar
committed
[DebugInfo] - DWARFDebugFrame: do not call abort() on errors.
Imagine we have a broken .eh_frame. Below is a possible sample output of llvm-readelf: ``` ... entry 2 { initial_location: 0x10f5 address: 0x2080 } } } .eh_frame section at offset 0x2028 address 0x2028: LLVM ERROR: Parsing entry instructions at 0 failed PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace. Stack dump: 0. Program arguments: /home/umb/LLVM/LLVM/llvm-project/build/bin/llvm-readelf -a 1 #0 0x000055f4a2ff5a1a llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/home/umb/LLVM/LLVM/llvm-project/build/bin/llvm-readelf+0x2b9a1a) ... #15 0x00007fdae5dc209b __libc_start_main /build/glibc-B9XfQf/glibc-2.28/csu/../csu/libc-start.c:342:3 #16 0x000055f4a2db746a _start (/home/umb/LLVM/LLVM/llvm-project/build/bin/llvm-readelf+0x7b46a) Aborted ``` I.e. it calls abort(), suggests to submit a bug report and exits with the code 134. This patch changes the logic to propagate errors to callers. This fixes the behavior for llvm-dwarfdump, llvm-readobj and other possible tools. Differential revision: https://reviews.llvm.org/D79165
1 parent 8b845ac commit 710d9d6

File tree

7 files changed

+126
-86
lines changed

7 files changed

+126
-86
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,10 @@ class DWARFContext : public DIContext {
277277
const DWARFDebugAranges *getDebugAranges();
278278

279279
/// Get a pointer to the parsed frame information object.
280-
const DWARFDebugFrame *getDebugFrame();
280+
Expected<const DWARFDebugFrame *> getDebugFrame();
281281

282282
/// Get a pointer to the parsed eh frame information object.
283-
const DWARFDebugFrame *getEHFrame();
283+
Expected<const DWARFDebugFrame *> getEHFrame();
284284

285285
/// Get a pointer to the parsed DebugMacinfo information object.
286286
const DWARFDebugMacro *getDebugMacinfo();

llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ class DWARFDebugFrame {
290290

291291
/// Parse the section from raw data. \p Data is assumed to contain the whole
292292
/// frame section contents to be parsed.
293-
void parse(DWARFDataExtractor Data);
293+
Error parse(DWARFDataExtractor Data);
294294

295295
/// Return whether the section has any entries.
296296
bool empty() const { return Entries.empty(); }

llvm/lib/DebugInfo/DWARF/DWARFContext.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -436,13 +436,23 @@ void DWARFContext::dump(
436436
}
437437
}
438438

439-
if (const auto *Off = shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
440-
DObj->getFrameSection().Data))
441-
getDebugFrame()->dump(OS, getRegisterInfo(), *Off);
439+
if (const Optional<uint64_t> *Off =
440+
shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
441+
DObj->getFrameSection().Data)) {
442+
if (Expected<const DWARFDebugFrame *> DF = getDebugFrame())
443+
(*DF)->dump(OS, getRegisterInfo(), *Off);
444+
else
445+
RecoverableErrorHandler(DF.takeError());
446+
}
442447

443-
if (const auto *Off = shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
444-
DObj->getEHFrameSection().Data))
445-
getEHFrame()->dump(OS, getRegisterInfo(), *Off);
448+
if (const Optional<uint64_t> *Off =
449+
shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
450+
DObj->getEHFrameSection().Data)) {
451+
if (Expected<const DWARFDebugFrame *> DF = getEHFrame())
452+
(*DF)->dump(OS, getRegisterInfo(), *Off);
453+
else
454+
RecoverableErrorHandler(DF.takeError());
455+
}
446456

447457
if (shouldDump(Explicit, ".debug_macro", DIDT_ID_DebugMacro,
448458
DObj->getMacroSection().Data)) {
@@ -791,7 +801,7 @@ const DWARFDebugAranges *DWARFContext::getDebugAranges() {
791801
return Aranges.get();
792802
}
793803

794-
const DWARFDebugFrame *DWARFContext::getDebugFrame() {
804+
Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() {
795805
if (DebugFrame)
796806
return DebugFrame.get();
797807

@@ -806,19 +816,25 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
806816
// http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
807817
DWARFDataExtractor debugFrameData(*DObj, DObj->getFrameSection(),
808818
isLittleEndian(), DObj->getAddressSize());
809-
DebugFrame.reset(new DWARFDebugFrame(getArch(), false /* IsEH */));
810-
DebugFrame->parse(debugFrameData);
819+
auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/false);
820+
if (Error E = DF->parse(debugFrameData))
821+
return std::move(E);
822+
823+
DebugFrame.swap(DF);
811824
return DebugFrame.get();
812825
}
813826

814-
const DWARFDebugFrame *DWARFContext::getEHFrame() {
827+
Expected<const DWARFDebugFrame *> DWARFContext::getEHFrame() {
815828
if (EHFrame)
816829
return EHFrame.get();
817830

818831
DWARFDataExtractor debugFrameData(*DObj, DObj->getEHFrameSection(),
819832
isLittleEndian(), DObj->getAddressSize());
820-
DebugFrame.reset(new DWARFDebugFrame(getArch(), true /* IsEH */));
821-
DebugFrame->parse(debugFrameData);
833+
834+
auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/true);
835+
if (Error E = DF->parse(debugFrameData))
836+
return std::move(E);
837+
DebugFrame.swap(DF);
822838
return DebugFrame.get();
823839
}
824840

llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp

Lines changed: 60 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -365,20 +365,7 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
365365
errs() << "\n";
366366
}
367367

368-
// This is a workaround for old compilers which do not allow
369-
// noreturn attribute usage in lambdas. Once the support for those
370-
// compilers are phased out, we can remove this and return back to
371-
// a ReportError lambda: [StartOffset](const char *ErrorMsg).
372-
static void LLVM_ATTRIBUTE_NORETURN ReportError(uint64_t StartOffset,
373-
const char *ErrorMsg) {
374-
std::string Str;
375-
raw_string_ostream OS(Str);
376-
OS << format(ErrorMsg, StartOffset);
377-
OS.flush();
378-
report_fatal_error(Str);
379-
}
380-
381-
void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
368+
Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {
382369
uint64_t Offset = 0;
383370
DenseMap<uint64_t, CIE *> CIEs;
384371

@@ -427,51 +414,55 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
427414
// Walk the augmentation string to get all the augmentation data.
428415
for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
429416
switch (AugmentationString[i]) {
430-
default:
431-
ReportError(
432-
StartOffset,
433-
"Unknown augmentation character in entry at %" PRIx64);
434-
case 'L':
435-
LSDAPointerEncoding = Data.getU8(&Offset);
436-
break;
437-
case 'P': {
438-
if (Personality)
439-
ReportError(StartOffset,
440-
"Duplicate personality in entry at %" PRIx64);
441-
PersonalityEncoding = Data.getU8(&Offset);
442-
Personality = Data.getEncodedPointer(
443-
&Offset, *PersonalityEncoding,
444-
EHFrameAddress ? EHFrameAddress + Offset : 0);
445-
break;
446-
}
447-
case 'R':
448-
FDEPointerEncoding = Data.getU8(&Offset);
449-
break;
450-
case 'S':
451-
// Current frame is a signal trampoline.
452-
break;
453-
case 'z':
454-
if (i)
455-
ReportError(StartOffset,
456-
"'z' must be the first character at %" PRIx64);
457-
// Parse the augmentation length first. We only parse it if
458-
// the string contains a 'z'.
459-
AugmentationLength = Data.getULEB128(&Offset);
460-
StartAugmentationOffset = Offset;
461-
EndAugmentationOffset = Offset + *AugmentationLength;
462-
break;
463-
case 'B':
464-
// B-Key is used for signing functions associated with this
465-
// augmentation string
466-
break;
417+
default:
418+
return createStringError(
419+
errc::invalid_argument,
420+
"unknown augmentation character in entry at 0x%" PRIx64,
421+
StartOffset);
422+
case 'L':
423+
LSDAPointerEncoding = Data.getU8(&Offset);
424+
break;
425+
case 'P': {
426+
if (Personality)
427+
return createStringError(
428+
errc::invalid_argument,
429+
"duplicate personality in entry at 0x%" PRIx64, StartOffset);
430+
PersonalityEncoding = Data.getU8(&Offset);
431+
Personality = Data.getEncodedPointer(
432+
&Offset, *PersonalityEncoding,
433+
EHFrameAddress ? EHFrameAddress + Offset : 0);
434+
break;
435+
}
436+
case 'R':
437+
FDEPointerEncoding = Data.getU8(&Offset);
438+
break;
439+
case 'S':
440+
// Current frame is a signal trampoline.
441+
break;
442+
case 'z':
443+
if (i)
444+
return createStringError(
445+
errc::invalid_argument,
446+
"'z' must be the first character at 0x%" PRIx64, StartOffset);
447+
// Parse the augmentation length first. We only parse it if
448+
// the string contains a 'z'.
449+
AugmentationLength = Data.getULEB128(&Offset);
450+
StartAugmentationOffset = Offset;
451+
EndAugmentationOffset = Offset + *AugmentationLength;
452+
break;
453+
case 'B':
454+
// B-Key is used for signing functions associated with this
455+
// augmentation string
456+
break;
467457
}
468458
}
469459

470460
if (AugmentationLength.hasValue()) {
471461
if (Offset != EndAugmentationOffset)
472-
ReportError(StartOffset,
473-
"Parsing augmentation data at %" PRIx64 " failed");
474-
462+
return createStringError(errc::invalid_argument,
463+
"parsing augmentation data at 0x%" PRIx64
464+
" failed",
465+
StartOffset);
475466
AugmentationData = Data.getData().slice(StartAugmentationOffset,
476467
EndAugmentationOffset);
477468
}
@@ -496,9 +487,10 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
496487
if (IsEH) {
497488
// The address size is encoded in the CIE we reference.
498489
if (!Cie)
499-
ReportError(StartOffset, "Parsing FDE data at %" PRIx64
500-
" failed due to missing CIE");
501-
490+
return createStringError(errc::invalid_argument,
491+
"parsing FDE data at 0x%" PRIx64
492+
" failed due to missing CIE",
493+
StartOffset);
502494
if (auto Val = Data.getEncodedPointer(
503495
&Offset, Cie->getFDEPointerEncoding(),
504496
EHFrameAddress ? EHFrameAddress + Offset : 0)) {
@@ -524,8 +516,10 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
524516
}
525517

526518
if (Offset != EndAugmentationOffset)
527-
ReportError(StartOffset,
528-
"Parsing augmentation data at %" PRIx64 " failed");
519+
return createStringError(errc::invalid_argument,
520+
"parsing augmentation data at 0x%" PRIx64
521+
" failed",
522+
StartOffset);
529523
}
530524
} else {
531525
InitialLocation = Data.getRelocatedAddress(&Offset);
@@ -538,14 +532,16 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
538532
}
539533

540534
if (Error E =
541-
Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) {
542-
report_fatal_error(toString(std::move(E)));
543-
}
535+
Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))
536+
return E;
544537

545538
if (Offset != EndStructureOffset)
546-
ReportError(StartOffset,
547-
"Parsing entry instructions at %" PRIx64 " failed");
539+
return createStringError(
540+
errc::invalid_argument,
541+
"parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
548542
}
543+
544+
return Error::success();
549545
}
550546

551547
FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {

llvm/test/DebugInfo/X86/eh-frame-cie-id.s

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
2-
# RUN: not --crash llvm-dwarfdump -debug-frame - 2>&1 | \
3-
# RUN: FileCheck %s
1+
# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t
2+
# RUN: not llvm-dwarfdump -debug-frame %t 2>&1 | FileCheck %s
43

5-
# CHECK: Parsing FDE data at 0 failed due to missing CIE
4+
# CHECK: parsing FDE data at 0x0 failed due to missing CIE
65

76
.section .eh_frame,"a",@unwind
87
## This FDE was formerly wrongly interpreted as a CIE because its CIE pointer

llvm/test/tools/llvm-readobj/ELF/unwind.test

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# RUN: yaml2obj %s -o %t.exe
2-
# RUN: llvm-readobj --unwind %t.exe | FileCheck %s
1+
# RUN: yaml2obj --docnum=1 %s -o %t1.exe
2+
# RUN: llvm-readobj --unwind %t1.exe | FileCheck %s
33

44
# CHECK: EHFrameHeader {
55
# CHECK-NEXT: Address: 0x4013c0
@@ -215,3 +215,31 @@ ProgramHeaders:
215215
Sections:
216216
- Section: .eh_frame_hdr
217217
...
218+
219+
## Check we report an error when the tool is unable to parse .eh_frame section.
220+
# RUN: yaml2obj --docnum=2 %s -o %t2.exe
221+
# RUN: not llvm-readobj --unwind %t2.exe 2>&1 | FileCheck %s -DFILE=%t2.exe --check-prefix=NO-CIE-ERR
222+
223+
# NO-CIE-ERR: .eh_frame section at offset 0x40 address 0x0:
224+
# NO-CIE-ERR-NEXT: error: '[[FILE]]': parsing FDE data at 0x0 failed due to missing CIE
225+
# NO-CIE-ERR-NOT: {{.}}
226+
227+
--- !ELF
228+
FileHeader:
229+
Class: ELFCLASS64
230+
Data: ELFDATA2LSB
231+
Type: ET_REL
232+
Machine: EM_X86_64
233+
Sections:
234+
- Name: .eh_frame
235+
Type: SHT_X86_64_UNWIND
236+
## The content is generated from the following code. It has no CIE.
237+
## See the DebugInfoX86/eh-frame-cie-id.s test case for more history.
238+
## .section .eh_frame,"a",@unwind
239+
## .long .Lend - .LCIEptr # Length
240+
## .LCIEptr:
241+
## .long 0xffffffff # CIE pointer
242+
## .quad 0x1111abcd # Initial location
243+
## .quad 0x00010000 # Address range
244+
## .Lend:
245+
Content: 14000000FFFFFFFFCDAB1111000000000000010000000000

llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ void PrinterContext<ELFT>::printEHFrame(
191191
ELFT::Is64Bits ? 8 : 4);
192192
DWARFDebugFrame EHFrame(Triple::ArchType(ObjF->getArch()), /*IsEH=*/true,
193193
/*EHFrameAddress=*/Address);
194-
EHFrame.parse(DE);
194+
if (Error E = EHFrame.parse(DE))
195+
reportError(std::move(E), ObjF->getFileName());
195196

196197
for (const auto &Entry : EHFrame) {
197198
if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) {

0 commit comments

Comments
 (0)