Index: include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFContext.h +++ include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -289,6 +289,11 @@ DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); }; +/// Used as a return value for a error callback passed to DWARF context. +/// Callback should return Halt if client application wants to stop +/// object parsing, or should return Continue otherwise. +enum class ErrorPolicy { Halt, Continue }; + /// DWARFContextInMemory is the simplest possible implementation of a /// DWARFContext. It assumes all content is available in memory and stores /// pointers to it. @@ -346,9 +351,15 @@ Error maybeDecompress(const object::SectionRef &Sec, StringRef Name, StringRef &Data); + /// Function used to handle default error reporting policy. Prints a error + /// message and returns true, what says context to continue object + /// parsing and ignore the error. + static ErrorPolicy defaultErrorHandler(Error E); + public: - DWARFContextInMemory(const object::ObjectFile &Obj, - const LoadedObjectInfo *L = nullptr); + DWARFContextInMemory( + const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr, + function_ref HandleError = defaultErrorHandler); DWARFContextInMemory(const StringMap> &Sections, uint8_t AddrSize, Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -870,13 +870,13 @@ Expected SymAddrOrErr = Sym->getAddress(); if (!SymAddrOrErr) - return createError("error: failed to compute symbol address: ", + return createError("failed to compute symbol address: ", SymAddrOrErr.takeError()); // Also remember what section this symbol is in for later auto SectOrErr = Sym->getSection(); if (!SectOrErr) - return createError("error: failed to get symbol section: ", + return createError("failed to get symbol section: ", SectOrErr.takeError()); RSec = *SectOrErr; @@ -937,8 +937,14 @@ return Error::success(); } -DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, - const LoadedObjectInfo *L) +ErrorPolicy DWARFContextInMemory::defaultErrorHandler(Error E) { + errs() << "error: " + toString(std::move(E)) << '\n'; + return ErrorPolicy::Continue; +} + +DWARFContextInMemory::DWARFContextInMemory( + const object::ObjectFile &Obj, const LoadedObjectInfo *L, + function_ref HandleError) : FileName(Obj.getFileName()), IsLittleEndian(Obj.isLittleEndian()), AddressSize(Obj.getBytesInAddress()) { for (const SectionRef &Section : Obj.sections()) { @@ -961,9 +967,10 @@ Section.getContents(data); if (auto Err = maybeDecompress(Section, name, data)) { - errs() << "error: failed to decompress '" + name + "', " + - toString(std::move(Err)) - << '\n'; + ErrorPolicy EP = HandleError( + createError("failed to decompress '" + name + "', ", std::move(Err))); + if (EP == ErrorPolicy::Halt) + return; continue; } @@ -1055,7 +1062,8 @@ Expected SymInfoOrErr = getSymbolInfo(Obj, Reloc, L, AddrCache); if (!SymInfoOrErr) { - errs() << toString(SymInfoOrErr.takeError()) << '\n'; + if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt) + return; continue; } @@ -1064,7 +1072,11 @@ if (V.error()) { SmallString<32> Name; Reloc.getTypeName(Name); - errs() << "error: failed to compute relocation: " << Name << "\n"; + ErrorPolicy EP = HandleError( + createError("failed to compute relocation: " + name + ", ", + errorCodeToError(object_error::parse_failed))); + if (EP == ErrorPolicy::Halt) + return; continue; } RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val}; Index: unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -15,10 +15,14 @@ #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Codegen/AsmPrinter.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/Object/ObjectFile.h" #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/ObjectYAML/DWARFYAML.h" @@ -2146,4 +2150,47 @@ "offset:"); } +TEST(DWARFDebugInfo, TestErrorReportingPolicy) { + initLLVMIfNeeded(); + auto ExpectedDG = dwarfgen::Generator::create(Triple("x86_64-pc-linux"), + 4 /*DwarfVersion*/); + if (HandleExpectedError(ExpectedDG)) + return; + dwarfgen::Generator *DG = ExpectedDG.get().get(); + AsmPrinter *AP = DG->getAsmPrinter(); + MCContext *MC = DG->getMCContext(); + + // Emit two compressed sections with broken headers. + AP->OutStreamer->SwitchSection( + MC->getELFSection(".zdebug_foo", 0 /*Type*/, 0 /*Flags*/)); + AP->OutStreamer->EmitBytes("0"); + AP->OutStreamer->SwitchSection( + MC->getELFSection(".zdebug_bar", 0 /*Type*/, 0 /*Flags*/)); + AP->OutStreamer->EmitBytes("0"); + + MemoryBufferRef FileBuffer(DG->generate(), "dwarf"); + auto Obj = object::ObjectFile::createObjectFile(FileBuffer); + EXPECT_TRUE((bool)Obj); + + // Case 1: error handler handles all errors. That allows + // DWARFContextInMemory + // to parse whole file and find both two errors we know about. + int Errors = 0; + DWARFContextInMemory Ctx1(*Obj.get(), nullptr, [&](Error E) { + ++Errors; + consumeError(std::move(E)); + return ErrorPolicy::Continue; + }); + EXPECT_TRUE(Errors == 2); + + // Case 2: error handler stops parsing of object after first error. + Errors = 0; + DWARFContextInMemory Ctx2(*Obj.get(), nullptr, [&](Error E) { + ++Errors; + consumeError(std::move(E)); + return ErrorPolicy::Halt; + }); + EXPECT_TRUE(Errors == 1); +} + } // end anonymous namespace Index: unittests/DebugInfo/DWARF/DwarfGenerator.h =================================================================== --- unittests/DebugInfo/DWARF/DwarfGenerator.h +++ unittests/DebugInfo/DWARF/DwarfGenerator.h @@ -215,6 +215,7 @@ BumpPtrAllocator &getAllocator() { return Allocator; } AsmPrinter *getAsmPrinter() const { return Asm.get(); } + MCContext *getMCContext() const { return MC.get(); } DIEAbbrevSet &getAbbrevSet() { return Abbreviations; } DwarfStringPool &getStringPool() { return *StringPool; }