Skip to content

Commit

Permalink
[DebugInfo] - DWARFDebugFrame: do not call abort() on errors.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Georgii Rymar committed May 15, 2020
1 parent 8b845ac commit 710d9d6
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 86 deletions.
4 changes: 2 additions & 2 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,10 @@ class DWARFContext : public DIContext {
const DWARFDebugAranges *getDebugAranges();

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

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

/// Get a pointer to the parsed DebugMacinfo information object.
const DWARFDebugMacro *getDebugMacinfo();
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ class DWARFDebugFrame {

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

/// Return whether the section has any entries.
bool empty() const { return Entries.empty(); }
Expand Down
40 changes: 28 additions & 12 deletions llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,13 +436,23 @@ void DWARFContext::dump(
}
}

if (const auto *Off = shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
DObj->getFrameSection().Data))
getDebugFrame()->dump(OS, getRegisterInfo(), *Off);
if (const Optional<uint64_t> *Off =
shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
DObj->getFrameSection().Data)) {
if (Expected<const DWARFDebugFrame *> DF = getDebugFrame())
(*DF)->dump(OS, getRegisterInfo(), *Off);
else
RecoverableErrorHandler(DF.takeError());
}

if (const auto *Off = shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
DObj->getEHFrameSection().Data))
getEHFrame()->dump(OS, getRegisterInfo(), *Off);
if (const Optional<uint64_t> *Off =
shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
DObj->getEHFrameSection().Data)) {
if (Expected<const DWARFDebugFrame *> DF = getEHFrame())
(*DF)->dump(OS, getRegisterInfo(), *Off);
else
RecoverableErrorHandler(DF.takeError());
}

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

const DWARFDebugFrame *DWARFContext::getDebugFrame() {
Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() {
if (DebugFrame)
return DebugFrame.get();

Expand All @@ -806,19 +816,25 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
// http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
DWARFDataExtractor debugFrameData(*DObj, DObj->getFrameSection(),
isLittleEndian(), DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(getArch(), false /* IsEH */));
DebugFrame->parse(debugFrameData);
auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/false);
if (Error E = DF->parse(debugFrameData))
return std::move(E);

DebugFrame.swap(DF);
return DebugFrame.get();
}

const DWARFDebugFrame *DWARFContext::getEHFrame() {
Expected<const DWARFDebugFrame *> DWARFContext::getEHFrame() {
if (EHFrame)
return EHFrame.get();

DWARFDataExtractor debugFrameData(*DObj, DObj->getEHFrameSection(),
isLittleEndian(), DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(getArch(), true /* IsEH */));
DebugFrame->parse(debugFrameData);

auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/true);
if (Error E = DF->parse(debugFrameData))
return std::move(E);
DebugFrame.swap(DF);
return DebugFrame.get();
}

Expand Down
124 changes: 60 additions & 64 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,20 +365,7 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
errs() << "\n";
}

// This is a workaround for old compilers which do not allow
// noreturn attribute usage in lambdas. Once the support for those
// compilers are phased out, we can remove this and return back to
// a ReportError lambda: [StartOffset](const char *ErrorMsg).
static void LLVM_ATTRIBUTE_NORETURN ReportError(uint64_t StartOffset,
const char *ErrorMsg) {
std::string Str;
raw_string_ostream OS(Str);
OS << format(ErrorMsg, StartOffset);
OS.flush();
report_fatal_error(Str);
}

void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {
uint64_t Offset = 0;
DenseMap<uint64_t, CIE *> CIEs;

Expand Down Expand Up @@ -427,51 +414,55 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
// Walk the augmentation string to get all the augmentation data.
for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
switch (AugmentationString[i]) {
default:
ReportError(
StartOffset,
"Unknown augmentation character in entry at %" PRIx64);
case 'L':
LSDAPointerEncoding = Data.getU8(&Offset);
break;
case 'P': {
if (Personality)
ReportError(StartOffset,
"Duplicate personality in entry at %" PRIx64);
PersonalityEncoding = Data.getU8(&Offset);
Personality = Data.getEncodedPointer(
&Offset, *PersonalityEncoding,
EHFrameAddress ? EHFrameAddress + Offset : 0);
break;
}
case 'R':
FDEPointerEncoding = Data.getU8(&Offset);
break;
case 'S':
// Current frame is a signal trampoline.
break;
case 'z':
if (i)
ReportError(StartOffset,
"'z' must be the first character at %" PRIx64);
// Parse the augmentation length first. We only parse it if
// the string contains a 'z'.
AugmentationLength = Data.getULEB128(&Offset);
StartAugmentationOffset = Offset;
EndAugmentationOffset = Offset + *AugmentationLength;
break;
case 'B':
// B-Key is used for signing functions associated with this
// augmentation string
break;
default:
return createStringError(
errc::invalid_argument,
"unknown augmentation character in entry at 0x%" PRIx64,
StartOffset);
case 'L':
LSDAPointerEncoding = Data.getU8(&Offset);
break;
case 'P': {
if (Personality)
return createStringError(
errc::invalid_argument,
"duplicate personality in entry at 0x%" PRIx64, StartOffset);
PersonalityEncoding = Data.getU8(&Offset);
Personality = Data.getEncodedPointer(
&Offset, *PersonalityEncoding,
EHFrameAddress ? EHFrameAddress + Offset : 0);
break;
}
case 'R':
FDEPointerEncoding = Data.getU8(&Offset);
break;
case 'S':
// Current frame is a signal trampoline.
break;
case 'z':
if (i)
return createStringError(
errc::invalid_argument,
"'z' must be the first character at 0x%" PRIx64, StartOffset);
// Parse the augmentation length first. We only parse it if
// the string contains a 'z'.
AugmentationLength = Data.getULEB128(&Offset);
StartAugmentationOffset = Offset;
EndAugmentationOffset = Offset + *AugmentationLength;
break;
case 'B':
// B-Key is used for signing functions associated with this
// augmentation string
break;
}
}

if (AugmentationLength.hasValue()) {
if (Offset != EndAugmentationOffset)
ReportError(StartOffset,
"Parsing augmentation data at %" PRIx64 " failed");

return createStringError(errc::invalid_argument,
"parsing augmentation data at 0x%" PRIx64
" failed",
StartOffset);
AugmentationData = Data.getData().slice(StartAugmentationOffset,
EndAugmentationOffset);
}
Expand All @@ -496,9 +487,10 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
if (IsEH) {
// The address size is encoded in the CIE we reference.
if (!Cie)
ReportError(StartOffset, "Parsing FDE data at %" PRIx64
" failed due to missing CIE");

return createStringError(errc::invalid_argument,
"parsing FDE data at 0x%" PRIx64
" failed due to missing CIE",
StartOffset);
if (auto Val = Data.getEncodedPointer(
&Offset, Cie->getFDEPointerEncoding(),
EHFrameAddress ? EHFrameAddress + Offset : 0)) {
Expand All @@ -524,8 +516,10 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
}

if (Offset != EndAugmentationOffset)
ReportError(StartOffset,
"Parsing augmentation data at %" PRIx64 " failed");
return createStringError(errc::invalid_argument,
"parsing augmentation data at 0x%" PRIx64
" failed",
StartOffset);
}
} else {
InitialLocation = Data.getRelocatedAddress(&Offset);
Expand All @@ -538,14 +532,16 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
}

if (Error E =
Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) {
report_fatal_error(toString(std::move(E)));
}
Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))
return E;

if (Offset != EndStructureOffset)
ReportError(StartOffset,
"Parsing entry instructions at %" PRIx64 " failed");
return createStringError(
errc::invalid_argument,
"parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
}

return Error::success();
}

FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
Expand Down
7 changes: 3 additions & 4 deletions llvm/test/DebugInfo/X86/eh-frame-cie-id.s
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
# RUN: not --crash llvm-dwarfdump -debug-frame - 2>&1 | \
# RUN: FileCheck %s
# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t
# RUN: not llvm-dwarfdump -debug-frame %t 2>&1 | FileCheck %s

# CHECK: Parsing FDE data at 0 failed due to missing CIE
# CHECK: parsing FDE data at 0x0 failed due to missing CIE

.section .eh_frame,"a",@unwind
## This FDE was formerly wrongly interpreted as a CIE because its CIE pointer
Expand Down
32 changes: 30 additions & 2 deletions llvm/test/tools/llvm-readobj/ELF/unwind.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# RUN: yaml2obj %s -o %t.exe
# RUN: llvm-readobj --unwind %t.exe | FileCheck %s
# RUN: yaml2obj --docnum=1 %s -o %t1.exe
# RUN: llvm-readobj --unwind %t1.exe | FileCheck %s

# CHECK: EHFrameHeader {
# CHECK-NEXT: Address: 0x4013c0
Expand Down Expand Up @@ -215,3 +215,31 @@ ProgramHeaders:
Sections:
- Section: .eh_frame_hdr
...

## Check we report an error when the tool is unable to parse .eh_frame section.
# RUN: yaml2obj --docnum=2 %s -o %t2.exe
# RUN: not llvm-readobj --unwind %t2.exe 2>&1 | FileCheck %s -DFILE=%t2.exe --check-prefix=NO-CIE-ERR

# NO-CIE-ERR: .eh_frame section at offset 0x40 address 0x0:
# NO-CIE-ERR-NEXT: error: '[[FILE]]': parsing FDE data at 0x0 failed due to missing CIE
# NO-CIE-ERR-NOT: {{.}}

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Sections:
- Name: .eh_frame
Type: SHT_X86_64_UNWIND
## The content is generated from the following code. It has no CIE.
## See the DebugInfoX86/eh-frame-cie-id.s test case for more history.
## .section .eh_frame,"a",@unwind
## .long .Lend - .LCIEptr # Length
## .LCIEptr:
## .long 0xffffffff # CIE pointer
## .quad 0x1111abcd # Initial location
## .quad 0x00010000 # Address range
## .Lend:
Content: 14000000FFFFFFFFCDAB1111000000000000010000000000
3 changes: 2 additions & 1 deletion llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ void PrinterContext<ELFT>::printEHFrame(
ELFT::Is64Bits ? 8 : 4);
DWARFDebugFrame EHFrame(Triple::ArchType(ObjF->getArch()), /*IsEH=*/true,
/*EHFrameAddress=*/Address);
EHFrame.parse(DE);
if (Error E = EHFrame.parse(DE))
reportError(std::move(E), ObjF->getFileName());

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

0 comments on commit 710d9d6

Please sign in to comment.