439 lines
15 KiB
C++
439 lines
15 KiB
C++
//===- llvm/unittest/DebugInfo/DWARFDebugAbbrevTest.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/DWARFDebugAbbrev.h"
|
|
#include "llvm/BinaryFormat/Dwarf.h"
|
|
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
|
#include "llvm/Support/DataExtractor.h"
|
|
#include "llvm/Support/LEB128.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
using namespace dwarf;
|
|
|
|
enum OrderKind : bool { InOrder, OutOfOrder };
|
|
|
|
void writeValidAbbreviationDeclarations(raw_ostream &OS, uint32_t FirstCode,
|
|
OrderKind Order) {
|
|
encodeULEB128(FirstCode, OS);
|
|
encodeULEB128(DW_TAG_compile_unit, OS);
|
|
OS << static_cast<uint8_t>(DW_CHILDREN_yes);
|
|
encodeULEB128(DW_AT_name, OS);
|
|
encodeULEB128(DW_FORM_strp, OS);
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(0, OS);
|
|
|
|
uint32_t SecondCode =
|
|
Order == OrderKind::InOrder ? FirstCode + 1 : FirstCode - 1;
|
|
|
|
encodeULEB128(SecondCode, OS);
|
|
encodeULEB128(DW_TAG_subprogram, OS);
|
|
OS << static_cast<uint8_t>(DW_CHILDREN_no);
|
|
encodeULEB128(DW_AT_name, OS);
|
|
encodeULEB128(DW_FORM_strp, OS);
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(0, OS);
|
|
}
|
|
|
|
void writeMalformedULEB128Value(raw_ostream &OS) {
|
|
OS << static_cast<uint8_t>(0x80);
|
|
}
|
|
|
|
void writeULEB128LargerThan64Bits(raw_ostream &OS) {
|
|
static constexpr llvm::StringRef LargeULEB128 =
|
|
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01";
|
|
OS << LargeULEB128;
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetExtractSuccess) {
|
|
SmallString<64> RawData;
|
|
raw_svector_ostream OS(RawData);
|
|
uint32_t FirstCode = 5;
|
|
|
|
writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
|
|
encodeULEB128(0, OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(AbbrevSet.extract(Data, &Offset), Succeeded());
|
|
// The Abbreviation Declarations are in order and contiguous, so we want to
|
|
// make sure that FirstAbbrCode was correctly set.
|
|
EXPECT_EQ(AbbrevSet.getFirstAbbrCode(), FirstCode);
|
|
|
|
const DWARFAbbreviationDeclaration *Abbrev5 =
|
|
AbbrevSet.getAbbreviationDeclaration(FirstCode);
|
|
ASSERT_TRUE(Abbrev5);
|
|
EXPECT_EQ(Abbrev5->getTag(), DW_TAG_compile_unit);
|
|
EXPECT_TRUE(Abbrev5->hasChildren());
|
|
EXPECT_EQ(Abbrev5->getNumAttributes(), 1u);
|
|
|
|
const DWARFAbbreviationDeclaration *Abbrev6 =
|
|
AbbrevSet.getAbbreviationDeclaration(FirstCode + 1);
|
|
ASSERT_TRUE(Abbrev6);
|
|
EXPECT_EQ(Abbrev6->getTag(), DW_TAG_subprogram);
|
|
EXPECT_FALSE(Abbrev6->hasChildren());
|
|
EXPECT_EQ(Abbrev6->getNumAttributes(), 1u);
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetExtractSuccessOutOfOrder) {
|
|
SmallString<64> RawData;
|
|
raw_svector_ostream OS(RawData);
|
|
uint32_t FirstCode = 2;
|
|
|
|
writeValidAbbreviationDeclarations(OS, FirstCode, OutOfOrder);
|
|
encodeULEB128(0, OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(AbbrevSet.extract(Data, &Offset), Succeeded());
|
|
// The declarations are out of order, ensure that FirstAbbrCode is UINT32_MAX.
|
|
EXPECT_EQ(AbbrevSet.getFirstAbbrCode(), UINT32_MAX);
|
|
|
|
const DWARFAbbreviationDeclaration *Abbrev2 =
|
|
AbbrevSet.getAbbreviationDeclaration(FirstCode);
|
|
ASSERT_TRUE(Abbrev2);
|
|
EXPECT_EQ(Abbrev2->getTag(), DW_TAG_compile_unit);
|
|
EXPECT_TRUE(Abbrev2->hasChildren());
|
|
EXPECT_EQ(Abbrev2->getNumAttributes(), 1u);
|
|
|
|
const DWARFAbbreviationDeclaration *Abbrev1 =
|
|
AbbrevSet.getAbbreviationDeclaration(FirstCode - 1);
|
|
ASSERT_TRUE(Abbrev1);
|
|
EXPECT_EQ(Abbrev1->getTag(), DW_TAG_subprogram);
|
|
EXPECT_FALSE(Abbrev1->hasChildren());
|
|
EXPECT_EQ(Abbrev1->getNumAttributes(), 1u);
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetCodeExtractionError) {
|
|
SmallString<64> RawData;
|
|
|
|
// Check for malformed ULEB128.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
writeMalformedULEB128Value(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000000: "
|
|
"malformed uleb128, extends past end"));
|
|
EXPECT_EQ(Offset, 0u);
|
|
}
|
|
|
|
RawData.clear();
|
|
// Check for ULEB128 too large to fit into a uin64_t.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
writeULEB128LargerThan64Bits(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000000: "
|
|
"uleb128 too big for uint64"));
|
|
EXPECT_EQ(Offset, 0u);
|
|
}
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetTagExtractionError) {
|
|
SmallString<64> RawData;
|
|
const uint32_t Code = 1;
|
|
|
|
// Check for malformed ULEB128.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
encodeULEB128(Code, OS);
|
|
writeMalformedULEB128Value(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
|
|
"malformed uleb128, extends past end"));
|
|
// Only the code was extracted correctly.
|
|
EXPECT_EQ(Offset, 1u);
|
|
}
|
|
|
|
RawData.clear();
|
|
// Check for ULEB128 too large to fit into a uint64_t.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
encodeULEB128(Code, OS);
|
|
writeULEB128LargerThan64Bits(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000001: "
|
|
"uleb128 too big for uint64"));
|
|
// Only the code was extracted correctly.
|
|
EXPECT_EQ(Offset, 1u);
|
|
}
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetChildExtractionError) {
|
|
SmallString<64> RawData;
|
|
const uint32_t Code = 1;
|
|
const dwarf::Tag Tag = DW_TAG_compile_unit;
|
|
|
|
// We want to make sure that we fail if we reach the end of the stream before
|
|
// reading the 'children' byte.
|
|
raw_svector_ostream OS(RawData);
|
|
encodeULEB128(Code, OS);
|
|
encodeULEB128(Tag, OS);
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage(
|
|
"unexpected end of data at offset 0x2 while reading [0x2, 0x3)"));
|
|
// The code and the tag were extracted correctly.
|
|
EXPECT_EQ(Offset, 2u);
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetAttributeExtractionError) {
|
|
SmallString<64> RawData;
|
|
const uint32_t Code = 1;
|
|
const dwarf::Tag Tag = DW_TAG_compile_unit;
|
|
const uint8_t Children = DW_CHILDREN_yes;
|
|
|
|
// Check for malformed ULEB128.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
encodeULEB128(Code, OS);
|
|
encodeULEB128(Tag, OS);
|
|
OS << Children;
|
|
writeMalformedULEB128Value(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000003: "
|
|
"malformed uleb128, extends past end"));
|
|
// The code, tag, and child byte were extracted correctly.
|
|
EXPECT_EQ(Offset, 3u);
|
|
}
|
|
|
|
RawData.clear();
|
|
// Check for ULEB128 too large to fit into a uint64_t.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
encodeULEB128(Code, OS);
|
|
encodeULEB128(Tag, OS);
|
|
OS << Children;
|
|
writeULEB128LargerThan64Bits(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000003: "
|
|
"uleb128 too big for uint64"));
|
|
// The code, tag, and child byte were extracted correctly.
|
|
EXPECT_EQ(Offset, 3u);
|
|
}
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetFormExtractionError) {
|
|
SmallString<64> RawData;
|
|
const uint32_t Code = 1;
|
|
const dwarf::Tag Tag = DW_TAG_compile_unit;
|
|
const uint8_t Children = DW_CHILDREN_yes;
|
|
const dwarf::Attribute Attr = DW_AT_name;
|
|
|
|
// Check for malformed ULEB128.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
encodeULEB128(Code, OS);
|
|
encodeULEB128(Tag, OS);
|
|
OS << Children;
|
|
encodeULEB128(Attr, OS);
|
|
writeMalformedULEB128Value(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000004: "
|
|
"malformed uleb128, extends past end"));
|
|
// The code, tag, child byte, and first attribute were extracted correctly.
|
|
EXPECT_EQ(Offset, 4u);
|
|
}
|
|
|
|
RawData.clear();
|
|
// Check for ULEB128 too large to fit into a uint64_t.
|
|
{
|
|
raw_svector_ostream OS(RawData);
|
|
encodeULEB128(Code, OS);
|
|
encodeULEB128(Tag, OS);
|
|
OS << Children;
|
|
encodeULEB128(Attr, OS);
|
|
writeULEB128LargerThan64Bits(OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
ASSERT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("unable to decode LEB128 at offset 0x00000004: "
|
|
"uleb128 too big for uint64"));
|
|
// The code, tag, child byte, and first attribute were extracted correctly.
|
|
EXPECT_EQ(Offset, 4u);
|
|
}
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetInvalidTag) {
|
|
SmallString<64> RawData;
|
|
raw_svector_ostream OS(RawData);
|
|
uint32_t FirstCode = 1;
|
|
// First, we're going to manually add good data.
|
|
writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
|
|
|
|
// Afterwards, we're going to write an Abbreviation Decl manually with an
|
|
// invalid tag.
|
|
encodeULEB128(FirstCode + 2, OS);
|
|
encodeULEB128(0, OS); // Invalid Tag
|
|
OS << static_cast<uint8_t>(DW_CHILDREN_no);
|
|
encodeULEB128(DW_AT_name, OS);
|
|
encodeULEB128(DW_FORM_strp, OS);
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(0, OS);
|
|
|
|
encodeULEB128(0, OS);
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
EXPECT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage("abbreviation declaration requires a non-null tag"));
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetInvalidAttrValidForm) {
|
|
SmallString<64> RawData;
|
|
raw_svector_ostream OS(RawData);
|
|
uint32_t FirstCode = 120;
|
|
// First, we're going to manually add good data.
|
|
writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
|
|
|
|
// Afterwards, we're going to write an Abbreviation Decl manually with an
|
|
// invalid attribute but valid form.
|
|
encodeULEB128(FirstCode - 5, OS);
|
|
encodeULEB128(DW_TAG_compile_unit, OS);
|
|
OS << static_cast<uint8_t>(DW_CHILDREN_no);
|
|
encodeULEB128(0, OS); // Invalid attribute followed by an invalid form.
|
|
encodeULEB128(DW_FORM_strp, OS);
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(0, OS);
|
|
|
|
encodeULEB128(0, OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
EXPECT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage(
|
|
"malformed abbreviation declaration attribute. Either the "
|
|
"attribute or the form is zero while the other is not"));
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetValidAttrInvalidForm) {
|
|
SmallString<64> RawData;
|
|
raw_svector_ostream OS(RawData);
|
|
uint32_t FirstCode = 120;
|
|
// First, we're going to manually add good data.
|
|
writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
|
|
|
|
// Afterwards, we're going to write an Abbreviation Decl manually with a
|
|
// valid attribute but invalid form.
|
|
encodeULEB128(FirstCode - 5, OS);
|
|
encodeULEB128(DW_TAG_compile_unit, OS);
|
|
OS << static_cast<uint8_t>(DW_CHILDREN_no);
|
|
encodeULEB128(DW_AT_name, OS);
|
|
encodeULEB128(0, OS); // Invalid form after a valid attribute.
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(0, OS);
|
|
|
|
encodeULEB128(0, OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
EXPECT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage(
|
|
"malformed abbreviation declaration attribute. Either the "
|
|
"attribute or the form is zero while the other is not"));
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetMissingTerminator) {
|
|
SmallString<64> RawData;
|
|
raw_svector_ostream OS(RawData);
|
|
uint32_t FirstCode = 120;
|
|
// First, we're going to manually add good data.
|
|
writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
|
|
|
|
// Afterwards, we're going to write an Abbreviation Decl manually without a
|
|
// termintating sequence.
|
|
encodeULEB128(FirstCode + 7, OS);
|
|
encodeULEB128(DW_TAG_compile_unit, OS);
|
|
OS << static_cast<uint8_t>(DW_CHILDREN_no);
|
|
encodeULEB128(DW_AT_name, OS);
|
|
encodeULEB128(DW_FORM_strp, OS);
|
|
|
|
uint64_t Offset = 0;
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFAbbreviationDeclarationSet AbbrevSet;
|
|
EXPECT_THAT_ERROR(
|
|
AbbrevSet.extract(Data, &Offset),
|
|
FailedWithMessage(
|
|
"abbreviation declaration attribute list was not terminated with a "
|
|
"null entry"));
|
|
}
|
|
|
|
TEST(DWARFDebugAbbrevTest, DWARFDebugAbbrevParseError) {
|
|
SmallString<64> RawData;
|
|
raw_svector_ostream OS(RawData);
|
|
const uint32_t FirstCode = 70;
|
|
// First, we're going to manually add good data.
|
|
writeValidAbbreviationDeclarations(OS, FirstCode, InOrder);
|
|
|
|
// Afterwards, we're going to write an Abbreviation Decl manually without a
|
|
// termintating sequence.
|
|
encodeULEB128(FirstCode - 1, OS);
|
|
encodeULEB128(DW_TAG_compile_unit, OS);
|
|
OS << static_cast<uint8_t>(DW_CHILDREN_no);
|
|
encodeULEB128(DW_AT_name, OS);
|
|
encodeULEB128(DW_FORM_strp, OS);
|
|
|
|
// The specific error should percolate up to the DWARFDebugAbbrev::parse().
|
|
DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t));
|
|
DWARFDebugAbbrev DebugAbbrev(Data);
|
|
EXPECT_THAT_ERROR(
|
|
DebugAbbrev.parse(),
|
|
FailedWithMessage(
|
|
"abbreviation declaration attribute list was not terminated with a "
|
|
"null entry"));
|
|
}
|