228 lines
7.6 KiB
C++
228 lines
7.6 KiB
C++
//===- 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<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(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<uint8_t> Bytes)
|
|
-> Expected<std::tuple<uint64_t, dwarf::DwarfFormat, uint64_t>> {
|
|
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<uint8_t> 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<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 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
|