forked from OSchip/llvm-project
[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
This commit is contained in:
parent
8b845ac5ed
commit
710d9d66f8
|
@ -277,10 +277,10 @@ public:
|
|||
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();
|
||||
|
|
|
@ -290,7 +290,7 @@ public:
|
|||
|
||||
/// 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(); }
|
||||
|
|
|
@ -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)) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Reference in New Issue