Index: include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFContext.h +++ include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -346,9 +346,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 bool 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) +bool DWARFContextInMemory::defaultErrorHandler(Error E) { + errs() << "error: " + toString(std::move(E)) << '\n'; + return true; +} + +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,9 @@ Section.getContents(data); if (auto Err = maybeDecompress(Section, name, data)) { - errs() << "error: failed to decompress '" + name + "', " + - toString(std::move(Err)) - << '\n'; + if (!HandleError(createError("failed to decompress '" + name + "', ", + std::move(Err)))) + return; continue; } @@ -1055,7 +1061,8 @@ Expected SymInfoOrErr = getSymbolInfo(Obj, Reloc, L, AddrCache); if (!SymInfoOrErr) { - errs() << toString(SymInfoOrErr.takeError()) << '\n'; + if (!HandleError(SymInfoOrErr.takeError())) + return; continue; } @@ -1064,7 +1071,10 @@ if (V.error()) { SmallString<32> Name; Reloc.getTypeName(Name); - errs() << "error: failed to compute relocation: " << Name << "\n"; + if (!HandleError( + createError("failed to compute relocation: " + name + ", ", + errorCodeToError(object_error::parse_failed)))) + return; continue; } RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val}; Index: unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -812,10 +812,10 @@ dwarfgen::Generator *DG = ExpectedDG.get().get(); dwarfgen::CompileUnit &CU = DG->addCompileUnit(); dwarfgen::DIE CUDie = CU.getUnitDIE(); - + CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c"); CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C); - + // Create a subprogram DIE with no low or high PC. dwarfgen::DIE SubprogramNoPC = CUDie.addChild(DW_TAG_subprogram); SubprogramNoPC.addAttribute(DW_AT_name, DW_FORM_strp, "no_pc"); @@ -838,18 +838,18 @@ ActualHighPCOffset); else SubprogramLowHighPC.addAttribute(DW_AT_high_pc, DW_FORM_addr, ActualHighPC); - + StringRef FileBytes = DG->generate(); MemoryBufferRef FileBuffer(FileBytes, "dwarf"); auto Obj = object::ObjectFile::createObjectFile(FileBuffer); EXPECT_TRUE((bool)Obj); DWARFContextInMemory DwarfContext(*Obj.get()); - + // Verify the number of compile units is correct. uint32_t NumCUs = DwarfContext.getNumCompileUnits(); EXPECT_EQ(NumCUs, 1u); DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0); - + // Get the compile unit DIE is valid. auto DieDG = U->getUnitDIE(false); EXPECT_TRUE(DieDG.isValid()); @@ -873,7 +873,7 @@ OptU64 = SubprogramDieNoPC.getHighPC(ActualLowPC); EXPECT_FALSE((bool)OptU64); EXPECT_FALSE(SubprogramDieNoPC.getLowAndHighPC(LowPC, HighPC, SectionIndex)); - + // Verify the that our subprogram with only a low PC value succeeds when // we ask for the Low PC, but fails appropriately when asked for the high PC // or both low and high PC values. @@ -974,7 +974,7 @@ // Test the DWARF APIs related to accessing the DW_AT_low_pc and // DW_AT_high_pc. uint16_t Version = 4; - + const uint8_t AddrSize = sizeof(void *); initLLVMIfNeeded(); Triple Triple = getHostTripleForAddrSize(AddrSize); @@ -983,7 +983,7 @@ return; dwarfgen::Generator *DG = ExpectedDG.get().get(); dwarfgen::CompileUnit &CU = DG->addCompileUnit(); - + enum class Tag: uint16_t { A = dwarf::DW_TAG_lo_user, B, @@ -1020,34 +1020,34 @@ auto Obj = object::ObjectFile::createObjectFile(FileBuffer); EXPECT_TRUE((bool)Obj); DWARFContextInMemory DwarfContext(*Obj.get()); - + // Verify the number of compile units is correct. uint32_t NumCUs = DwarfContext.getNumCompileUnits(); EXPECT_EQ(NumCUs, 1u); DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0); - + // Get the compile unit DIE is valid. auto CUDie = U->getUnitDIE(false); EXPECT_TRUE(CUDie.isValid()); - + // The compile unit doesn't have a parent or a sibling. auto ParentDie = CUDie.getParent(); EXPECT_FALSE(ParentDie.isValid()); auto SiblingDie = CUDie.getSibling(); EXPECT_FALSE(SiblingDie.isValid()); - + // Get the children of the compile unit auto A = CUDie.getFirstChild(); auto B = A.getFirstChild(); auto C = B.getSibling(); auto D = C.getSibling(); auto Null = D.getSibling(); - + // Verify NULL Die is NULL and has no children or siblings EXPECT_TRUE(Null.isNULL()); EXPECT_FALSE(Null.getSibling().isValid()); EXPECT_FALSE(Null.getFirstChild().isValid()); - + // Verify all children of the compile unit DIE are correct. EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A); EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B); @@ -1063,7 +1063,7 @@ // Make sure the parent of all the children of the compile unit are the // compile unit. EXPECT_EQ(A.getParent(), CUDie); - + // Make sure the parent of all the children of A are the A. // B is the first child in A, so we need to verify we can get the previous // DIE as the parent. @@ -1082,7 +1082,7 @@ auto C1 = C.getFirstChild(); auto C2 = C1.getSibling(); EXPECT_TRUE(C2.getSibling().isNULL()); - + // Verify all children of the B DIE correctly valid or invalid. EXPECT_EQ(C1.getTag(), (dwarf::Tag)Tag::C1); EXPECT_EQ(C2.getTag(), (dwarf::Tag)Tag::C2); @@ -1105,7 +1105,7 @@ // Test the DWARF APIs related to iterating across the children of a DIE using // the DWARFDie::iterator class. uint16_t Version = 4; - + const uint8_t AddrSize = sizeof(void *); initLLVMIfNeeded(); Triple Triple = getHostTripleForAddrSize(AddrSize); @@ -1114,12 +1114,12 @@ return; dwarfgen::Generator *DG = ExpectedDG.get().get(); dwarfgen::CompileUnit &CU = DG->addCompileUnit(); - + enum class Tag: uint16_t { A = dwarf::DW_TAG_lo_user, B, }; - + // Scope to allow us to re-use the same DIE names { // Create DWARF tree that looks like: @@ -1131,24 +1131,24 @@ CUDie.addChild((dwarf::Tag)Tag::A); CUDie.addChild((dwarf::Tag)Tag::B); } - + MemoryBufferRef FileBuffer(DG->generate(), "dwarf"); auto Obj = object::ObjectFile::createObjectFile(FileBuffer); EXPECT_TRUE((bool)Obj); DWARFContextInMemory DwarfContext(*Obj.get()); - + // Verify the number of compile units is correct. uint32_t NumCUs = DwarfContext.getNumCompileUnits(); EXPECT_EQ(NumCUs, 1u); DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0); - + // Get the compile unit DIE is valid. auto CUDie = U->getUnitDIE(false); EXPECT_TRUE(CUDie.isValid()); uint32_t Index; DWARFDie A; DWARFDie B; - + // Verify the compile unit DIE's children. Index = 0; for (auto Die : CUDie.children()) { @@ -1157,7 +1157,7 @@ case 1: B = Die; break; } } - + EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A); EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B); @@ -1206,7 +1206,7 @@ // Get the compile unit DIE is valid. auto CUDie = U->getUnitDIE(false); EXPECT_TRUE(CUDie.isValid()); - + // Verify that the CU Die that says it has children, but doesn't, actually // has begin and end iterators that are equal. We want to make sure we don't // see the Null DIEs during iteration. @@ -1217,7 +1217,7 @@ // Test the DWARF APIs related to iterating across all attribute values in a // a DWARFDie. uint16_t Version = 4; - + const uint8_t AddrSize = sizeof(void *); initLLVMIfNeeded(); Triple Triple = getHostTripleForAddrSize(AddrSize); @@ -1228,7 +1228,7 @@ dwarfgen::CompileUnit &CU = DG->addCompileUnit(); const uint64_t CULowPC = 0x1000; StringRef CUPath("/tmp/main.c"); - + // Scope to allow us to re-use the same DIE names { auto CUDie = CU.getUnitDIE(); @@ -1240,44 +1240,44 @@ // Encode an attribute value after an attribute with no data. CUDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, CULowPC); } - + MemoryBufferRef FileBuffer(DG->generate(), "dwarf"); auto Obj = object::ObjectFile::createObjectFile(FileBuffer); EXPECT_TRUE((bool)Obj); DWARFContextInMemory DwarfContext(*Obj.get()); - + // Verify the number of compile units is correct. uint32_t NumCUs = DwarfContext.getNumCompileUnits(); EXPECT_EQ(NumCUs, 1u); DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0); - + // Get the compile unit DIE is valid. auto CUDie = U->getUnitDIE(false); EXPECT_TRUE(CUDie.isValid()); - + auto R = CUDie.attributes(); auto I = R.begin(); auto E = R.end(); - + ASSERT_NE(E, I); EXPECT_EQ(I->Attr, DW_AT_name); auto ActualCUPath = I->Value.getAsCString(); EXPECT_EQ(CUPath, *ActualCUPath); - + ASSERT_NE(E, ++I); EXPECT_EQ(I->Attr, DW_AT_declaration); EXPECT_EQ(1ull, *I->Value.getAsUnsignedConstant()); - + ASSERT_NE(E, ++I); EXPECT_EQ(I->Attr, DW_AT_low_pc); EXPECT_EQ(CULowPC, *I->Value.getAsAddress()); - + EXPECT_EQ(E, ++I); } TEST(DWARFDebugInfo, TestFindRecurse) { uint16_t Version = 4; - + const uint8_t AddrSize = sizeof(void *); initLLVMIfNeeded(); Triple Triple = getHostTripleForAddrSize(AddrSize); @@ -1286,7 +1286,7 @@ return; dwarfgen::Generator *DG = ExpectedDG.get().get(); dwarfgen::CompileUnit &CU = DG->addCompileUnit(); - + StringRef SpecDieName = "spec"; StringRef SpecLinkageName = "spec_linkage"; StringRef AbsDieName = "abs"; @@ -1305,21 +1305,21 @@ VarAbsDie.addAttribute(DW_AT_name, DW_FORM_strp, AbsDieName); VarDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, VarAbsDie); } - + MemoryBufferRef FileBuffer(DG->generate(), "dwarf"); auto Obj = object::ObjectFile::createObjectFile(FileBuffer); EXPECT_TRUE((bool)Obj); DWARFContextInMemory DwarfContext(*Obj.get()); - + // Verify the number of compile units is correct. uint32_t NumCUs = DwarfContext.getNumCompileUnits(); EXPECT_EQ(NumCUs, 1u); DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0); - + // Get the compile unit DIE is valid. auto CUDie = U->getUnitDIE(false); EXPECT_TRUE(CUDie.isValid()); - + auto FuncSpecDie = CUDie.getFirstChild(); auto FuncAbsDie = FuncSpecDie.getSibling(); auto FuncDie = FuncAbsDie.getSibling(); @@ -1344,11 +1344,11 @@ auto LinkageNameOpt = FuncDie.findRecursively(DW_AT_linkage_name); EXPECT_EQ(SpecLinkageName, toString(LinkageNameOpt).getValueOr(nullptr)); - + // Make sure we can't extract the name from the abstract origin die when using // DWARFDie::find() since it won't check the DW_AT_abstract_origin DIE. EXPECT_FALSE(VarDie.find(DW_AT_name)); - + // Make sure we can extract the name from the abstract origin die when using // DWARFDie::findRecursively() since it should recurse through the // DW_AT_abstract_origin DIE. @@ -1408,7 +1408,7 @@ FormVal.setForm(DW_FORM_udata); FormVal.setUValue(UData8); FormValOpt = FormVal; - + EXPECT_FALSE(toString(FormValOpt).hasValue()); EXPECT_TRUE(toUnsigned(FormValOpt).hasValue()); EXPECT_FALSE(toReference(FormValOpt).hasValue()); @@ -1428,7 +1428,7 @@ FormVal.setForm(DW_FORM_ref_addr); FormVal.setUValue(RefData); FormValOpt = FormVal; - + EXPECT_FALSE(toString(FormValOpt).hasValue()); EXPECT_FALSE(toUnsigned(FormValOpt).hasValue()); EXPECT_TRUE(toReference(FormValOpt).hasValue()); @@ -1448,7 +1448,7 @@ FormVal.setForm(DW_FORM_udata); FormVal.setSValue(SData8); FormValOpt = FormVal; - + EXPECT_FALSE(toString(FormValOpt).hasValue()); EXPECT_TRUE(toUnsigned(FormValOpt).hasValue()); EXPECT_FALSE(toReference(FormValOpt).hasValue()); @@ -1469,7 +1469,7 @@ FormVal.setForm(DW_FORM_block1); FormVal.setBlockValue(Array); FormValOpt = FormVal; - + EXPECT_FALSE(toString(FormValOpt).hasValue()); EXPECT_FALSE(toUnsigned(FormValOpt).hasValue()); EXPECT_FALSE(toReference(FormValOpt).hasValue()); @@ -1493,7 +1493,7 @@ // Test the DWARFDie::find() and DWARFDie::findRecursively() that take an // ArrayRef value to make sure they work correctly. uint16_t Version = 4; - + const uint8_t AddrSize = sizeof(void *); initLLVMIfNeeded(); Triple Triple = getHostTripleForAddrSize(AddrSize); @@ -1502,7 +1502,7 @@ return; dwarfgen::Generator *DG = ExpectedDG.get().get(); dwarfgen::CompileUnit &CU = DG->addCompileUnit(); - + StringRef DieMangled("_Z3fooi"); // Scope to allow us to re-use the same DIE names { @@ -1512,21 +1512,21 @@ FuncSpecDie.addAttribute(DW_AT_MIPS_linkage_name, DW_FORM_strp, DieMangled); FuncDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie); } - + MemoryBufferRef FileBuffer(DG->generate(), "dwarf"); auto Obj = object::ObjectFile::createObjectFile(FileBuffer); EXPECT_TRUE((bool)Obj); DWARFContextInMemory DwarfContext(*Obj.get()); - + // Verify the number of compile units is correct. uint32_t NumCUs = DwarfContext.getNumCompileUnits(); EXPECT_EQ(NumCUs, 1u); DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0); - + // Get the compile unit DIE is valid. auto CUDie = U->getUnitDIE(false); EXPECT_TRUE(CUDie.isValid()); - + auto FuncSpecDie = CUDie.getFirstChild(); auto FuncDie = FuncSpecDie.getSibling(); @@ -1543,7 +1543,7 @@ // Make sure we can't extract the linkage name attributes when using // DWARFDie::find() since it won't check the DW_AT_specification DIE. EXPECT_FALSE(FuncDie.find(Attrs).hasValue()); - + // Make sure we can extract the name from the specification die when using // DWARFDie::findRecursively() since it should recurse through the // DW_AT_specification DIE. @@ -2073,38 +2073,38 @@ - '' - /tmp/main.c - /tmp/foo.c - debug_abbrev: + debug_abbrev: - Code: 0x00000001 Tag: DW_TAG_compile_unit Children: DW_CHILDREN_no - Attributes: + Attributes: - Attribute: DW_AT_name Form: DW_FORM_strp - Attribute: DW_AT_stmt_list Form: DW_FORM_sec_offset - debug_info: - - Length: + debug_info: + - Length: TotalLength: 16 Version: 4 AbbrOffset: 0 AddrSize: 8 - Entries: + Entries: - AbbrCode: 0x00000001 - Values: + Values: - Value: 0x0000000000000001 - Value: 0x0000000000000000 - - Length: + - Length: TotalLength: 16 Version: 4 AbbrOffset: 0 AddrSize: 8 - Entries: + Entries: - AbbrCode: 0x00000001 - Values: + Values: - Value: 0x000000000000000D - Value: 0x0000000000000000 - debug_line: - - Length: + debug_line: + - Length: TotalLength: 60 Version: 2 PrologueLength: 34 @@ -2114,14 +2114,14 @@ LineRange: 14 OpcodeBase: 13 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] - IncludeDirs: + IncludeDirs: - /tmp - Files: + Files: - Name: main.c DirIdx: 1 ModTime: 0 Length: 0 - Opcodes: + Opcodes: - Opcode: DW_LNS_extended_op ExtLen: 9 SubOpcode: DW_LNE_set_address @@ -2146,4 +2146,98 @@ "offset:"); } +TEST(DWARFDebugInfo, TestErrorReportingPolicy) { + // Data contains bytes of object file generated by yaml2obj tool. + // YAML contains description of object with two broken compressed + // sections. + // To produce Data array next commands and following yaml file was used: + // yaml2obj test.s -o test.o + // xxd -i test.o + // + // !ELF + // FileHeader: + // Class: ELFCLASS64 + // Data: ELFDATA2LSB + // Type: ET_REL + // Machine: EM_X86_64 + // Sections: + // -Name: .zdebug_foo + // Type: SHT_PROGBITS + // Content: "00000000" + // -Name: .zdebug_bar + // Type: SHT_PROGBITS + // Content: "00000000" + // + const unsigned char Data[] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x2e, 0x7a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x62, 0x61, + 0x72, 0x00, 0x2e, 0x7a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x66, 0x6f, + 0x6f, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, + 0x2e, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x79, 0x6d, + 0x74, 0x61, 0x62, 0x00}; + const size_t Size = sizeof(Data) / sizeof(Data[0]); + + MemoryBufferRef FileBuffer(StringRef((char *)Data, Size), "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 true; + }); + 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 false; + }); + EXPECT_TRUE(Errors == 1); +} + } // end anonymous namespace