[DWARFDataExtractor] Add a "truncating" constructor

Summary:
This constructor allows us to create a new DWARFDataExtractor which will
only present a subrange of an entire debug section. Since debug sections
typically consist of multiple contributions, it is expected that one
will create a new data extractor for each contribution in order to
avoid unexpectedly running off into the next one.

This is very useful for unifying the flows for detecting parse errors.
Without it, the code needs to consider two very different scenarios:
1. If there is another contribution after the current one, the
   DataExtractor functions will just start reading from there. This is
   detectable by comparing the current offset against the known
   end-of-contribution offset.
2. If this is the last contribution, the data extractor will just start
   returning zeroes (or other default values). This situation can *not*
   be detected by checking the parsing offset, as this will not be
   advanced in case of errors.

Using a truncated data extractor simplifies the code (and reduces
cognitive load) by making these two cases behave identically -- a
running off the end of a contribution will _always_ produce an EOF error
(if one uses error-aware parsing methods) or return default values.

Reviewers: dblaikie, probinson, jhenderson, ikudrin

Subscribers: aprantl, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D77556
This commit is contained in:
Pavel Labath 2020-03-23 14:20:08 +01:00
parent c2dd38f1cb
commit cc0acda782
2 changed files with 72 additions and 0 deletions

View File

@ -39,6 +39,12 @@ public:
StringRef(reinterpret_cast<const char *>(Data.data()), Data.size()),
IsLittleEndian, AddressSize) {}
/// Truncating constructor
DWARFDataExtractor(const DWARFDataExtractor &Other, size_t Length)
: DataExtractor(Other.getData().substr(0, Length), Other.isLittleEndian(),
Other.getAddressSize()),
Obj(Other.Obj), Section(Other.Section) {}
/// Extracts the DWARF "initial length" field, which can either be a 32-bit
/// value smaller than 0xfffffff0, or the value 0xffffffff followed by a
/// 64-bit length. Returns the actual length, and the DWARF format which is

View File

@ -146,4 +146,70 @@ TEST(DWARFDataExtractorTest, getInitialLength) {
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<object::ObjectFile> Obj = yaml::yaml2ObjectFile(
Storage, Yaml, [](const Twine &Err) { errs() << Err; });
ASSERT_TRUE(Obj);
std::unique_ptr<DWARFContext> 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"));
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 0x4"));
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 0x0"));
}
} // namespace