//===- DWARFDataExtractorTest.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Object/ObjectFile.h" #include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; namespace { TEST(DWARFDataExtractorTest, getRelocatedValue) { StringRef Yaml = R"( !ELF FileHeader: Class: ELFCLASS32 Data: ELFDATA2LSB Type: ET_REL Machine: EM_386 Sections: - Name: .text Type: SHT_PROGBITS Size: 0x80 - Name: .debug_line Type: SHT_PROGBITS Content: '000000000000' - Name: .rel.debug_line Type: SHT_REL Info: .debug_line Relocations: - Offset: 0 Symbol: f Type: R_386_32 - Offset: 4 Symbol: f Type: R_386_32 Symbols: - Name: f Type: STT_SECTION Section: .text Value: 0x42 )"; SmallString<0> Storage; std::unique_ptr Obj = yaml::yaml2ObjectFile( Storage, Yaml, [](const Twine &Err) { errs() << Err; }); ASSERT_TRUE(Obj); std::unique_ptr Ctx = DWARFContext::create(*Obj); const DWARFObject &DObj = Ctx->getDWARFObj(); ASSERT_EQ(6u, DObj.getLineSection().Data.size()); DWARFDataExtractor Data(DObj, DObj.getLineSection(), Obj->isLittleEndian(), Obj->getBytesInAddress()); DataExtractor::Cursor C(0); EXPECT_EQ(0x42u, Data.getRelocatedAddress(C)); EXPECT_EQ(0u, Data.getRelocatedAddress(C)); EXPECT_THAT_ERROR( C.takeError(), FailedWithMessage( "unexpected end of data at offset 0x6 while reading [0x4, 0x8)")); } TEST(DWARFDataExtractorTest, getInitialLength) { auto GetWithError = [](ArrayRef Bytes) -> Expected> { DWARFDataExtractor Data(Bytes, /*IsLittleEndian=*/false, /*AddressSize=*/8); DWARFDataExtractor::Cursor C(0); uint64_t Length; dwarf::DwarfFormat Format; std::tie(Length, Format) = Data.getInitialLength(C); if (C) return std::make_tuple(Length, Format, C.tell()); EXPECT_EQ(Length, 0u); EXPECT_EQ(Format, dwarf::DWARF32); EXPECT_EQ(C.tell(), 0u); return C.takeError(); }; auto GetWithoutError = [](ArrayRef Bytes) { DWARFDataExtractor Data(Bytes, /*IsLittleEndian=*/false, /*AddressSize=*/8); uint64_t Offset = 0; uint64_t Length; dwarf::DwarfFormat Format; std::tie(Length, Format) = Data.getInitialLength(&Offset); return std::make_tuple(Length, Format, Offset); }; auto ErrorResult = std::make_tuple(0, dwarf::DWARF32, 0); // Empty data. EXPECT_THAT_EXPECTED( GetWithError({}), FailedWithMessage( "unexpected end of data at offset 0x0 while reading [0x0, 0x4)")); EXPECT_EQ(GetWithoutError({}), ErrorResult); // Not long enough for the U32 field. EXPECT_THAT_EXPECTED( GetWithError({0x00, 0x01, 0x02}), FailedWithMessage( "unexpected end of data at offset 0x3 while reading [0x0, 0x4)")); EXPECT_EQ(GetWithoutError({0x00, 0x01, 0x02}), ErrorResult); EXPECT_THAT_EXPECTED( GetWithError({0x00, 0x01, 0x02, 0x03}), HasValue(std::make_tuple(0x00010203, dwarf::DWARF32, 4))); EXPECT_EQ(GetWithoutError({0x00, 0x01, 0x02, 0x03}), std::make_tuple(0x00010203, dwarf::DWARF32, 4)); // Zeroes are not an error, but without the Error object it is hard to tell // them apart from a failed read. EXPECT_THAT_EXPECTED( GetWithError({0x00, 0x00, 0x00, 0x00}), HasValue(std::make_tuple(0x00000000, dwarf::DWARF32, 4))); EXPECT_EQ(GetWithoutError({0x00, 0x00, 0x00, 0x00}), std::make_tuple(0x00000000, dwarf::DWARF32, 4)); // Smallest invalid value. EXPECT_THAT_EXPECTED( GetWithError({0xff, 0xff, 0xff, 0xf0}), FailedWithMessage( "unsupported reserved unit length of value 0xfffffff0")); EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xf0}), ErrorResult); // DWARF64 marker without the subsequent length field. EXPECT_THAT_EXPECTED( GetWithError({0xff, 0xff, 0xff, 0xff}), FailedWithMessage( "unexpected end of data at offset 0x4 while reading [0x4, 0xc)")); EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff}), ErrorResult); // Not enough data for the U64 length. EXPECT_THAT_EXPECTED( GetWithError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03}), FailedWithMessage( "unexpected end of data at offset 0x8 while reading [0x4, 0xc)")); EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03}), ErrorResult); EXPECT_THAT_EXPECTED( GetWithError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}), HasValue(std::make_tuple(0x0001020304050607, dwarf::DWARF64, 12))); EXPECT_EQ(GetWithoutError({0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}), std::make_tuple(0x0001020304050607, dwarf::DWARF64, 12)); } TEST(DWARFDataExtractorTest, Truncation) { StringRef Yaml = R"( !ELF FileHeader: Class: ELFCLASS32 Data: ELFDATA2LSB Type: ET_REL Machine: EM_386 Sections: - Name: .text Type: SHT_PROGBITS Size: 0x80 - Name: .debug_line Type: SHT_PROGBITS Content: '616263640000000065666768' - Name: .rel.debug_line Type: SHT_REL Info: .debug_line Relocations: - Offset: 4 Symbol: f Type: R_386_32 Symbols: - Name: f Type: STT_SECTION Section: .text Value: 0x42 )"; SmallString<0> Storage; std::unique_ptr Obj = yaml::yaml2ObjectFile( Storage, Yaml, [](const Twine &Err) { errs() << Err; }); ASSERT_TRUE(Obj); std::unique_ptr Ctx = DWARFContext::create(*Obj); const DWARFObject &DObj = Ctx->getDWARFObj(); ASSERT_EQ(12u, DObj.getLineSection().Data.size()); DWARFDataExtractor Data(DObj, DObj.getLineSection(), Obj->isLittleEndian(), Obj->getBytesInAddress()); DataExtractor::Cursor C(0); EXPECT_EQ(0x64636261u, Data.getRelocatedAddress(C)); EXPECT_EQ(0x42u, Data.getRelocatedAddress(C)); EXPECT_EQ(0x68676665u, Data.getRelocatedAddress(C)); EXPECT_THAT_ERROR(C.takeError(), Succeeded()); C = DataExtractor::Cursor{0}; DWARFDataExtractor Truncated8(Data, 8); EXPECT_EQ(0x64636261u, Truncated8.getRelocatedAddress(C)); EXPECT_EQ(0x42u, Truncated8.getRelocatedAddress(C)); EXPECT_EQ(0x0u, Truncated8.getRelocatedAddress(C)); EXPECT_THAT_ERROR( C.takeError(), FailedWithMessage( "unexpected end of data at offset 0x8 while reading [0x8, 0xc)")); C = DataExtractor::Cursor{0}; DWARFDataExtractor Truncated6(Data, 6); EXPECT_EQ(0x64636261u, Truncated6.getRelocatedAddress(C)); EXPECT_EQ(0x0u, Truncated6.getRelocatedAddress(C)); EXPECT_THAT_ERROR( C.takeError(), FailedWithMessage( "unexpected end of data at offset 0x6 while reading [0x4, 0x8)")); C = DataExtractor::Cursor{0}; DWARFDataExtractor Truncated2(Data, 2); EXPECT_EQ(0x0u, Truncated2.getRelocatedAddress(C)); EXPECT_THAT_ERROR( C.takeError(), FailedWithMessage( "unexpected end of data at offset 0x2 while reading [0x0, 0x4)")); } } // namespace