diff options
-rw-r--r-- | llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h | 14 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 30 | ||||
-rw-r--r-- | llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 47 | ||||
-rw-r--r-- | llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h | 1 |
4 files changed, 81 insertions, 11 deletions
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h index 4bf34d52bcb..8850104db29 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -289,6 +289,11 @@ private: 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,14 @@ class DWARFContextInMemory : public DWARFContext { Error maybeDecompress(const object::SectionRef &Sec, StringRef Name, StringRef &Data); + /// Function used to handle default error reporting policy. Prints a error + /// message and returns Continue, so DWARF context ignores 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<ErrorPolicy(Error)> HandleError = defaultErrorHandler); DWARFContextInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, uint8_t AddrSize, diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 38147946175..fdd191e0cbf 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -870,13 +870,13 @@ static Expected<SymInfo> getSymbolInfo(const object::ObjectFile &Obj, Expected<uint64_t> 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 @@ Error DWARFContextInMemory::maybeDecompress(const SectionRef &Sec, 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<ErrorPolicy(Error)> HandleError) : FileName(Obj.getFileName()), IsLittleEndian(Obj.isLittleEndian()), AddressSize(Obj.getBytesInAddress()) { for (const SectionRef &Section : Obj.sections()) { @@ -961,9 +967,10 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, 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 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, Expected<SymInfo> 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 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, 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}; diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp index bf004d6ffc2..7f6492ee6d1 100644 --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/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 @@ TEST(DWARFDebugInfo, TestDwarfVerifyCUDontShareLineTable) { "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 diff --git a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h index 76665e5193e..dd7e8709638 100644 --- a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h +++ b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h @@ -215,6 +215,7 @@ public: BumpPtrAllocator &getAllocator() { return Allocator; } AsmPrinter *getAsmPrinter() const { return Asm.get(); } + MCContext *getMCContext() const { return MC.get(); } DIEAbbrevSet &getAbbrevSet() { return Abbreviations; } DwarfStringPool &getStringPool() { return *StringPool; } |