llvm-project/llvm/unittests/DebugInfo/DWARF/DWARFDataExtractorTest.cpp
Pavel Labath 122c50d5ef Fix DWARFDataExtractor::getRelocatedValue near EOF
Summary:
If we have an (invalid) relocation which relocates bytes which partially
lie outside the range of the relocated section, the getRelocatedValue
would return confusing results. It would first read zero (because that's
what the underlying DataExtractor api does for out-of-bounds reads), and
then relocate that zero anyway.

A more appropriate behavior is to return zero straight away. This is
what this patch does.

Reviewers: dblaikie, jhenderson

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D78113
2020-04-15 12:47:57 +02:00

150 lines
5.2 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 0x4"));
}
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"));
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 0x0"));
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"));
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 0x4"));
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));
}
} // namespace