Files
clang-p2996/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
Pavel Labath d0d61a7e4c Split DWARFFormValue::getReference into four functions (#98905)
The result of the function cannot be correctly interpreted without
knowing the precise form type (a type signature needs to be looked up
very differently from a supplementary debug info reference). The
function sort of worked because the two reference types (unit-relative
and section-relative) that can be handled uniformly are also the most
common types of references, but this setup made it easy to write code
which does not support other kinds of reference (and if one tried to
support them, the result didn't look pretty --
https://github.com/llvm/llvm-project/pull/97423/files#r1676217081).

The split is based on the reference type classification from DWARFv5
(Section 7.5.5 Classes and Forms), and it should enable uniform (if
slightly more verbose) hadling. Note that this only affects users which
want more control of how (or if) the references are resolved. Users
which just want to access the referenced DIE can use the higher level
API (DWARFDie::GetAttributeValueAsReferencedDie) which returns (or will
return after #97423 is merged) the correct die for all reference types
(except for supplementary references, which we don't support right now).
2024-07-16 12:55:38 +02:00

2280 lines
91 KiB
C++

//===- llvm/unittest/DebugInfo/DWARFDebugInfoTest.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 "DwarfGenerator.h"
#include "DwarfUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
#include <string>
// AIX doesn't support debug_str_offsets or debug_addr sections
#ifdef _AIX
#define NO_SUPPORT_DEBUG_STR_OFFSETS
#define NO_SUPPORT_DEBUG_ADDR
#endif
using namespace llvm;
using namespace dwarf;
using namespace utils;
namespace {
template <uint16_t Version, class AddrType, class RefAddrType>
void TestAllForms() {
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test that we can decode all DW_FORM values correctly.
const AddrType AddrValue = (AddrType)0x0123456789abcdefULL;
const AddrType AddrxValue = (AddrType)0x4231abcd4231abcdULL;
const AddrType Addrx1Value = (AddrType)0x0000aaaabbbbccccULL;
const AddrType Addrx2Value = (AddrType)0xf00123f00456f000ULL;
const AddrType Addrx3Value = (AddrType)0xABABA000B111C222ULL;
const AddrType Addrx4Value = (AddrType)0xa1b2c3d4e5f6e5d4ULL;
const uint8_t BlockData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
const uint32_t BlockSize = sizeof(BlockData);
const RefAddrType RefAddr = 0x12345678;
const uint8_t Data1 = 0x01U;
const uint16_t Data2 = 0x2345U;
const uint32_t Data4 = 0x6789abcdU;
const uint64_t Data8 = 0x0011223344556677ULL;
const uint64_t Data8_2 = 0xAABBCCDDEEFF0011ULL;
const uint8_t Data16[16] = {1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16};
const int64_t SData = INT64_MIN;
const int64_t ICSData = INT64_MAX; // DW_FORM_implicit_const SData
const uint64_t UData[] = {UINT64_MAX - 1, UINT64_MAX - 2, UINT64_MAX - 3,
UINT64_MAX - 4, UINT64_MAX - 5, UINT64_MAX - 6,
UINT64_MAX - 7, UINT64_MAX - 8, UINT64_MAX - 9};
#define UDATA_1 18446744073709551614ULL
const uint32_t Dwarf32Values[] = {1, 2, 3, 4, 5, 6, 7, 8};
const char *StringValue = "Hello";
const char *StrpValue = "World";
const char *StrxValue = "Indexed";
const char *Strx1Value = "Indexed1";
const char *Strx2Value = "Indexed2";
const char *Strx3Value = "Indexed3";
const char *Strx4Value = "Indexed4";
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
if (Version >= 5) {
CUDie.addStrOffsetsBaseAttribute();
CUDie.addAddrBaseAttribute();
}
uint16_t Attr = DW_AT_lo_user;
//----------------------------------------------------------------------
// Test address forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_addr = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_addr, DW_FORM_addr, AddrValue);
const auto Attr_DW_FORM_addrx = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_addrx1 = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_addrx2 = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_addrx3 = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_addrx4 = static_cast<dwarf::Attribute>(Attr++);
if (Version >= 5) {
CUDie.addAttribute(Attr_DW_FORM_addrx, DW_FORM_addrx, AddrxValue);
CUDie.addAttribute(Attr_DW_FORM_addrx1, DW_FORM_addrx1, Addrx1Value);
CUDie.addAttribute(Attr_DW_FORM_addrx2, DW_FORM_addrx2, Addrx2Value);
CUDie.addAttribute(Attr_DW_FORM_addrx3, DW_FORM_addrx3, Addrx3Value);
CUDie.addAttribute(Attr_DW_FORM_addrx4, DW_FORM_addrx4, Addrx4Value);
}
//----------------------------------------------------------------------
// Test block forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_block = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_block, DW_FORM_block, BlockData, BlockSize);
const auto Attr_DW_FORM_block1 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_block1, DW_FORM_block1, BlockData, BlockSize);
const auto Attr_DW_FORM_block2 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_block2, DW_FORM_block2, BlockData, BlockSize);
const auto Attr_DW_FORM_block4 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_block4, DW_FORM_block4, BlockData, BlockSize);
// We handle data16 as a block form.
const auto Attr_DW_FORM_data16 = static_cast<dwarf::Attribute>(Attr++);
if (Version >= 5)
CUDie.addAttribute(Attr_DW_FORM_data16, DW_FORM_data16, Data16, 16);
//----------------------------------------------------------------------
// Test data forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_data1 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_data1, DW_FORM_data1, Data1);
const auto Attr_DW_FORM_data2 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_data2, DW_FORM_data2, Data2);
const auto Attr_DW_FORM_data4 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_data4, DW_FORM_data4, Data4);
const auto Attr_DW_FORM_data8 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_data8, DW_FORM_data8, Data8);
//----------------------------------------------------------------------
// Test string forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_string = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_string, DW_FORM_string, StringValue);
const auto Attr_DW_FORM_strx = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_strx1 = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_strx2 = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_strx3 = static_cast<dwarf::Attribute>(Attr++);
const auto Attr_DW_FORM_strx4 = static_cast<dwarf::Attribute>(Attr++);
if (Version >= 5) {
CUDie.addAttribute(Attr_DW_FORM_strx, DW_FORM_strx, StrxValue);
CUDie.addAttribute(Attr_DW_FORM_strx1, DW_FORM_strx1, Strx1Value);
CUDie.addAttribute(Attr_DW_FORM_strx2, DW_FORM_strx2, Strx2Value);
CUDie.addAttribute(Attr_DW_FORM_strx3, DW_FORM_strx3, Strx3Value);
CUDie.addAttribute(Attr_DW_FORM_strx4, DW_FORM_strx4, Strx4Value);
}
const auto Attr_DW_FORM_strp = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_strp, DW_FORM_strp, StrpValue);
//----------------------------------------------------------------------
// Test reference forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_ref_addr = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_ref_addr, DW_FORM_ref_addr, RefAddr);
const auto Attr_DW_FORM_ref1 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_ref1, DW_FORM_ref1, Data1);
const auto Attr_DW_FORM_ref2 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_ref2, DW_FORM_ref2, Data2);
const auto Attr_DW_FORM_ref4 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_ref4, DW_FORM_ref4, Data4);
const auto Attr_DW_FORM_ref8 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_ref8, DW_FORM_ref8, Data8);
const auto Attr_DW_FORM_ref_sig8 = static_cast<dwarf::Attribute>(Attr++);
if (Version >= 4)
CUDie.addAttribute(Attr_DW_FORM_ref_sig8, DW_FORM_ref_sig8, Data8_2);
const auto Attr_DW_FORM_ref_udata = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_ref_udata, DW_FORM_ref_udata, UData[0]);
//----------------------------------------------------------------------
// Test flag forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_flag_true = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_flag_true, DW_FORM_flag, true);
const auto Attr_DW_FORM_flag_false = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_flag_false, DW_FORM_flag, false);
const auto Attr_DW_FORM_flag_present = static_cast<dwarf::Attribute>(Attr++);
if (Version >= 4)
CUDie.addAttribute(Attr_DW_FORM_flag_present, DW_FORM_flag_present);
//----------------------------------------------------------------------
// Test SLEB128 based forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_sdata = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_sdata, DW_FORM_sdata, SData);
const auto Attr_DW_FORM_implicit_const =
static_cast<dwarf::Attribute>(Attr++);
if (Version >= 5)
CUDie.addAttribute(Attr_DW_FORM_implicit_const, DW_FORM_implicit_const,
ICSData);
//----------------------------------------------------------------------
// Test ULEB128 based forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_udata = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_udata, DW_FORM_udata, UData[0]);
//----------------------------------------------------------------------
// Test DWARF32/DWARF64 forms
//----------------------------------------------------------------------
const auto Attr_DW_FORM_GNU_ref_alt = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_GNU_ref_alt, DW_FORM_GNU_ref_alt,
Dwarf32Values[0]);
const auto Attr_DW_FORM_sec_offset = static_cast<dwarf::Attribute>(Attr++);
if (Version >= 4)
CUDie.addAttribute(Attr_DW_FORM_sec_offset, DW_FORM_sec_offset,
Dwarf32Values[1]);
//----------------------------------------------------------------------
// Add an address at the end to make sure we can decode this value
//----------------------------------------------------------------------
const auto Attr_Last = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_Last, DW_FORM_addr, AddrValue);
//----------------------------------------------------------------------
// Generate the DWARF
//----------------------------------------------------------------------
StringRef FileBytes = DG->generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
auto DieDG = U->getUnitDIE(false);
EXPECT_TRUE(DieDG.isValid());
//----------------------------------------------------------------------
// Test address forms
//----------------------------------------------------------------------
EXPECT_EQ(AddrValue, toAddress(DieDG.find(Attr_DW_FORM_addr), 0));
if (Version >= 5) {
auto ExtractedAddrxValue = toAddress(DieDG.find(Attr_DW_FORM_addrx));
EXPECT_TRUE(ExtractedAddrxValue.has_value());
EXPECT_EQ(AddrxValue, *ExtractedAddrxValue);
auto ExtractedAddrx1Value = toAddress(DieDG.find(Attr_DW_FORM_addrx1));
EXPECT_TRUE(ExtractedAddrx1Value.has_value());
EXPECT_EQ(Addrx1Value, *ExtractedAddrx1Value);
auto ExtractedAddrx2Value = toAddress(DieDG.find(Attr_DW_FORM_addrx2));
EXPECT_TRUE(ExtractedAddrx2Value.has_value());
EXPECT_EQ(Addrx2Value, *ExtractedAddrx2Value);
auto ExtractedAddrx3Value = toAddress(DieDG.find(Attr_DW_FORM_addrx3));
EXPECT_TRUE(ExtractedAddrx3Value.has_value());
EXPECT_EQ(Addrx3Value, *ExtractedAddrx3Value);
auto ExtractedAddrx4Value = toAddress(DieDG.find(Attr_DW_FORM_addrx4));
EXPECT_TRUE(ExtractedAddrx1Value.has_value());
EXPECT_EQ(Addrx4Value, *ExtractedAddrx4Value);
}
//----------------------------------------------------------------------
// Test block forms
//----------------------------------------------------------------------
std::optional<DWARFFormValue> FormValue;
ArrayRef<uint8_t> ExtractedBlockData;
std::optional<ArrayRef<uint8_t>> BlockDataOpt;
FormValue = DieDG.find(Attr_DW_FORM_block);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.has_value());
ExtractedBlockData = *BlockDataOpt;
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
FormValue = DieDG.find(Attr_DW_FORM_block1);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.has_value());
ExtractedBlockData = *BlockDataOpt;
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
FormValue = DieDG.find(Attr_DW_FORM_block2);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.has_value());
ExtractedBlockData = *BlockDataOpt;
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
FormValue = DieDG.find(Attr_DW_FORM_block4);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.has_value());
ExtractedBlockData = *BlockDataOpt;
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
// Data16 is handled like a block.
if (Version >= 5) {
FormValue = DieDG.find(Attr_DW_FORM_data16);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.has_value());
ExtractedBlockData = *BlockDataOpt;
EXPECT_EQ(ExtractedBlockData.size(), 16u);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), Data16, 16) == 0);
}
//----------------------------------------------------------------------
// Test data forms
//----------------------------------------------------------------------
EXPECT_EQ(Data1, toUnsigned(DieDG.find(Attr_DW_FORM_data1), 0));
EXPECT_EQ(Data2, toUnsigned(DieDG.find(Attr_DW_FORM_data2), 0));
EXPECT_EQ(Data4, toUnsigned(DieDG.find(Attr_DW_FORM_data4), 0));
EXPECT_EQ(Data8, toUnsigned(DieDG.find(Attr_DW_FORM_data8), 0));
//----------------------------------------------------------------------
// Test string forms
//----------------------------------------------------------------------
auto ExtractedStringValue = toString(DieDG.find(Attr_DW_FORM_string));
EXPECT_TRUE((bool)ExtractedStringValue);
EXPECT_STREQ(StringValue, *ExtractedStringValue);
if (Version >= 5) {
auto ExtractedStrxValue = toString(DieDG.find(Attr_DW_FORM_strx));
EXPECT_TRUE((bool)ExtractedStrxValue);
EXPECT_STREQ(StrxValue, *ExtractedStrxValue);
auto ExtractedStrx1Value = toString(DieDG.find(Attr_DW_FORM_strx1));
EXPECT_TRUE((bool)ExtractedStrx1Value);
EXPECT_STREQ(Strx1Value, *ExtractedStrx1Value);
auto ExtractedStrx2Value = toString(DieDG.find(Attr_DW_FORM_strx2));
EXPECT_TRUE((bool)ExtractedStrx2Value);
EXPECT_STREQ(Strx2Value, *ExtractedStrx2Value);
auto ExtractedStrx3Value = toString(DieDG.find(Attr_DW_FORM_strx3));
EXPECT_TRUE((bool)ExtractedStrx3Value);
EXPECT_STREQ(Strx3Value, *ExtractedStrx3Value);
auto ExtractedStrx4Value = toString(DieDG.find(Attr_DW_FORM_strx4));
EXPECT_TRUE((bool)ExtractedStrx4Value);
EXPECT_STREQ(Strx4Value, *ExtractedStrx4Value);
}
auto ExtractedStrpValue = toString(DieDG.find(Attr_DW_FORM_strp));
EXPECT_TRUE((bool)ExtractedStrpValue);
EXPECT_STREQ(StrpValue, *ExtractedStrpValue);
//----------------------------------------------------------------------
// Test reference forms
//----------------------------------------------------------------------
EXPECT_EQ(RefAddr,
toDebugInfoReference(DieDG.find(Attr_DW_FORM_ref_addr), 0));
EXPECT_EQ(Data1, toRelativeReference(DieDG.find(Attr_DW_FORM_ref1), 0));
EXPECT_EQ(Data2, toRelativeReference(DieDG.find(Attr_DW_FORM_ref2), 0));
EXPECT_EQ(Data4, toRelativeReference(DieDG.find(Attr_DW_FORM_ref4), 0));
EXPECT_EQ(Data8, toRelativeReference(DieDG.find(Attr_DW_FORM_ref8), 0));
if (Version >= 4) {
EXPECT_EQ(Data8_2,
toSignatureReference(DieDG.find(Attr_DW_FORM_ref_sig8), 0));
}
EXPECT_EQ(UData[0],
toRelativeReference(DieDG.find(Attr_DW_FORM_ref_udata), 0));
//----------------------------------------------------------------------
// Test flag forms
//----------------------------------------------------------------------
EXPECT_EQ(1ULL, toUnsigned(DieDG.find(Attr_DW_FORM_flag_true), 0));
EXPECT_EQ(0ULL, toUnsigned(DieDG.find(Attr_DW_FORM_flag_false), 1));
if (Version >= 4) {
EXPECT_EQ(1ULL, toUnsigned(DieDG.find(Attr_DW_FORM_flag_present), 0));
}
//----------------------------------------------------------------------
// Test SLEB128 based forms
//----------------------------------------------------------------------
EXPECT_EQ(SData, toSigned(DieDG.find(Attr_DW_FORM_sdata), 0));
if (Version >= 5) {
EXPECT_EQ(ICSData, toSigned(DieDG.find(Attr_DW_FORM_implicit_const), 0));
}
//----------------------------------------------------------------------
// Test ULEB128 based forms
//----------------------------------------------------------------------
EXPECT_EQ(UData[0], toUnsigned(DieDG.find(Attr_DW_FORM_udata), 0));
//----------------------------------------------------------------------
// Test DWARF32/DWARF64 forms
//----------------------------------------------------------------------
EXPECT_EQ(Dwarf32Values[0],
toSupplementaryReference(DieDG.find(Attr_DW_FORM_GNU_ref_alt), 0));
if (Version >= 4) {
EXPECT_EQ(Dwarf32Values[1],
toSectionOffset(DieDG.find(Attr_DW_FORM_sec_offset), 0));
}
//----------------------------------------------------------------------
// Add an address at the end to make sure we can decode this value
//----------------------------------------------------------------------
EXPECT_EQ(AddrValue, toAddress(DieDG.find(Attr_Last), 0));
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr4AllForms) {
// Test that we can decode all forms for DWARF32, version 2, with 4 byte
// addresses.
typedef uint32_t AddrType;
// DW_FORM_ref_addr are the same as the address type in DWARF32 version 2.
typedef AddrType RefAddrType;
TestAllForms<2, AddrType, RefAddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr8AllForms) {
// Test that we can decode all forms for DWARF32, version 2, with 4 byte
// addresses.
typedef uint64_t AddrType;
// DW_FORM_ref_addr are the same as the address type in DWARF32 version 2.
typedef AddrType RefAddrType;
TestAllForms<2, AddrType, RefAddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr4AllForms) {
// Test that we can decode all forms for DWARF32, version 3, with 4 byte
// addresses.
typedef uint32_t AddrType;
// DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later.
typedef uint32_t RefAddrType;
TestAllForms<3, AddrType, RefAddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr8AllForms) {
// Test that we can decode all forms for DWARF32, version 3, with 8 byte
// addresses.
typedef uint64_t AddrType;
// DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
typedef uint32_t RefAddrType;
TestAllForms<3, AddrType, RefAddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr4AllForms) {
// Test that we can decode all forms for DWARF32, version 4, with 4 byte
// addresses.
typedef uint32_t AddrType;
// DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
typedef uint32_t RefAddrType;
TestAllForms<4, AddrType, RefAddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr8AllForms) {
// Test that we can decode all forms for DWARF32, version 4, with 8 byte
// addresses.
typedef uint64_t AddrType;
// DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
typedef uint32_t RefAddrType;
TestAllForms<4, AddrType, RefAddrType>();
}
#ifdef NO_SUPPORT_DEBUG_STR_OFFSETS
TEST(DWARFDebugInfo, DISABLED_TestDWARF32Version5Addr4AllForms) {
#else
TEST(DWARFDebugInfo, TestDWARF32Version5Addr4AllForms) {
#endif
// Test that we can decode all forms for DWARF32, version 5, with 4 byte
// addresses.
typedef uint32_t AddrType;
// DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
typedef uint32_t RefAddrType;
TestAllForms<5, AddrType, RefAddrType>();
}
#ifdef NO_SUPPORT_DEBUG_STR_OFFSETS
TEST(DWARFDebugInfo, DISABLED_TestDWARF32Version5Addr8AllForms) {
#else
TEST(DWARFDebugInfo, TestDWARF32Version5Addr8AllForms) {
#endif
// Test that we can decode all forms for DWARF32, version 5, with 8 byte
// addresses.
typedef uint64_t AddrType;
// DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
typedef uint32_t RefAddrType;
TestAllForms<5, AddrType, RefAddrType>();
}
template <uint16_t Version, class AddrType> void TestChildren() {
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test that we can decode DW_FORM_ref_addr values correctly in DWARF 2 with
// 4 byte addresses. DW_FORM_ref_addr values should be 4 bytes when using
// 8 byte addresses.
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
dwarfgen::DIE SubprogramDie = CUDie.addChild(DW_TAG_subprogram);
SubprogramDie.addAttribute(DW_AT_name, DW_FORM_strp, "main");
SubprogramDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U);
SubprogramDie.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x2000U);
dwarfgen::DIE IntDie = CUDie.addChild(DW_TAG_base_type);
IntDie.addAttribute(DW_AT_name, DW_FORM_strp, "int");
IntDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_signed);
IntDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
dwarfgen::DIE ArgcDie = SubprogramDie.addChild(DW_TAG_formal_parameter);
ArgcDie.addAttribute(DW_AT_name, DW_FORM_strp, "argc");
// ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref4, IntDie);
ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, IntDie);
StringRef FileBytes = DG->generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto DieDG = U->getUnitDIE(false);
EXPECT_TRUE(DieDG.isValid());
// Verify the first child of the compile unit DIE is our subprogram.
auto SubprogramDieDG = DieDG.getFirstChild();
EXPECT_TRUE(SubprogramDieDG.isValid());
EXPECT_EQ(SubprogramDieDG.getTag(), DW_TAG_subprogram);
// Verify the first child of the subprogram is our formal parameter.
auto ArgcDieDG = SubprogramDieDG.getFirstChild();
EXPECT_TRUE(ArgcDieDG.isValid());
EXPECT_EQ(ArgcDieDG.getTag(), DW_TAG_formal_parameter);
// Verify our formal parameter has a NULL tag sibling.
auto NullDieDG = ArgcDieDG.getSibling();
EXPECT_TRUE(NullDieDG.isValid());
if (NullDieDG) {
EXPECT_EQ(NullDieDG.getTag(), DW_TAG_null);
EXPECT_TRUE(!NullDieDG.getSibling().isValid());
EXPECT_TRUE(!NullDieDG.getFirstChild().isValid());
}
// Verify the sibling of our subprogram is our integer base type.
auto IntDieDG = SubprogramDieDG.getSibling();
EXPECT_TRUE(IntDieDG.isValid());
EXPECT_EQ(IntDieDG.getTag(), DW_TAG_base_type);
// Verify the sibling of our subprogram is our integer base is a NULL tag.
NullDieDG = IntDieDG.getSibling();
EXPECT_TRUE(NullDieDG.isValid());
if (NullDieDG) {
EXPECT_EQ(NullDieDG.getTag(), DW_TAG_null);
EXPECT_TRUE(!NullDieDG.getSibling().isValid());
EXPECT_TRUE(!NullDieDG.getFirstChild().isValid());
}
// Verify the previous sibling of our subprogram is our integer base type.
IntDieDG = NullDieDG.getPreviousSibling();
EXPECT_TRUE(IntDieDG.isValid());
EXPECT_EQ(IntDieDG.getTag(), DW_TAG_base_type);
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr4Children) {
// Test that we can decode all forms for DWARF32, version 2, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestChildren<2, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr8Children) {
// Test that we can decode all forms for DWARF32, version 2, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestChildren<2, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr4Children) {
// Test that we can decode all forms for DWARF32, version 3, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestChildren<3, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr8Children) {
// Test that we can decode all forms for DWARF32, version 3, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestChildren<3, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr4Children) {
// Test that we can decode all forms for DWARF32, version 4, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestChildren<4, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr8Children) {
// Test that we can decode all forms for DWARF32, version 4, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestChildren<4, AddrType>();
}
template <uint16_t Version, class AddrType> void TestReferences() {
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test that we can decode DW_FORM_refXXX values correctly in DWARF.
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU1 = DG->addCompileUnit();
dwarfgen::CompileUnit &CU2 = DG->addCompileUnit();
dwarfgen::DIE CU1Die = CU1.getUnitDIE();
CU1Die.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
CU1Die.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
dwarfgen::DIE CU1TypeDie = CU1Die.addChild(DW_TAG_base_type);
CU1TypeDie.addAttribute(DW_AT_name, DW_FORM_strp, "int");
CU1TypeDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_signed);
CU1TypeDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
dwarfgen::DIE CU1Ref1Die = CU1Die.addChild(DW_TAG_variable);
CU1Ref1Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref1");
CU1Ref1Die.addAttribute(DW_AT_type, DW_FORM_ref1, CU1TypeDie);
dwarfgen::DIE CU1Ref2Die = CU1Die.addChild(DW_TAG_variable);
CU1Ref2Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref2");
CU1Ref2Die.addAttribute(DW_AT_type, DW_FORM_ref2, CU1TypeDie);
dwarfgen::DIE CU1Ref4Die = CU1Die.addChild(DW_TAG_variable);
CU1Ref4Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref4");
CU1Ref4Die.addAttribute(DW_AT_type, DW_FORM_ref4, CU1TypeDie);
dwarfgen::DIE CU1Ref8Die = CU1Die.addChild(DW_TAG_variable);
CU1Ref8Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref8");
CU1Ref8Die.addAttribute(DW_AT_type, DW_FORM_ref8, CU1TypeDie);
dwarfgen::DIE CU1RefAddrDie = CU1Die.addChild(DW_TAG_variable);
CU1RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU1RefAddr");
CU1RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU1TypeDie);
dwarfgen::DIE CU2Die = CU2.getUnitDIE();
CU2Die.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/foo.c");
CU2Die.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
dwarfgen::DIE CU2TypeDie = CU2Die.addChild(DW_TAG_base_type);
CU2TypeDie.addAttribute(DW_AT_name, DW_FORM_strp, "float");
CU2TypeDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_float);
CU2TypeDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
dwarfgen::DIE CU2Ref1Die = CU2Die.addChild(DW_TAG_variable);
CU2Ref1Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref1");
CU2Ref1Die.addAttribute(DW_AT_type, DW_FORM_ref1, CU2TypeDie);
dwarfgen::DIE CU2Ref2Die = CU2Die.addChild(DW_TAG_variable);
CU2Ref2Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref2");
CU2Ref2Die.addAttribute(DW_AT_type, DW_FORM_ref2, CU2TypeDie);
dwarfgen::DIE CU2Ref4Die = CU2Die.addChild(DW_TAG_variable);
CU2Ref4Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref4");
CU2Ref4Die.addAttribute(DW_AT_type, DW_FORM_ref4, CU2TypeDie);
dwarfgen::DIE CU2Ref8Die = CU2Die.addChild(DW_TAG_variable);
CU2Ref8Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref8");
CU2Ref8Die.addAttribute(DW_AT_type, DW_FORM_ref8, CU2TypeDie);
dwarfgen::DIE CU2RefAddrDie = CU2Die.addChild(DW_TAG_variable);
CU2RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU2RefAddr");
CU2RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU2TypeDie);
// Refer to a type in CU1 from CU2
dwarfgen::DIE CU2ToCU1RefAddrDie = CU2Die.addChild(DW_TAG_variable);
CU2ToCU1RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU2ToCU1RefAddr");
CU2ToCU1RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU1TypeDie);
// Refer to a type in CU2 from CU1
dwarfgen::DIE CU1ToCU2RefAddrDie = CU1Die.addChild(DW_TAG_variable);
CU1ToCU2RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU1ToCU2RefAddr");
CU1ToCU2RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU2TypeDie);
StringRef FileBytes = DG->generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 2u);
DWARFCompileUnit *U1 =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
DWARFCompileUnit *U2 =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(1));
// Get the compile unit DIE is valid.
auto Unit1DieDG = U1->getUnitDIE(false);
EXPECT_TRUE(Unit1DieDG.isValid());
auto Unit2DieDG = U2->getUnitDIE(false);
EXPECT_TRUE(Unit2DieDG.isValid());
// Verify the first child of the compile unit 1 DIE is our int base type.
auto CU1TypeDieDG = Unit1DieDG.getFirstChild();
EXPECT_TRUE(CU1TypeDieDG.isValid());
EXPECT_EQ(CU1TypeDieDG.getTag(), DW_TAG_base_type);
EXPECT_EQ(DW_ATE_signed, toUnsigned(CU1TypeDieDG.find(DW_AT_encoding), 0));
// Verify the first child of the compile unit 2 DIE is our float base type.
auto CU2TypeDieDG = Unit2DieDG.getFirstChild();
EXPECT_TRUE(CU2TypeDieDG.isValid());
EXPECT_EQ(CU2TypeDieDG.getTag(), DW_TAG_base_type);
EXPECT_EQ(DW_ATE_float, toUnsigned(CU2TypeDieDG.find(DW_AT_encoding), 0));
// Verify the sibling of the base type DIE is our Ref1 DIE and that its
// DW_AT_type points to our base type DIE.
auto CU1Ref1DieDG = CU1TypeDieDG.getSibling();
EXPECT_TRUE(CU1Ref1DieDG.isValid());
EXPECT_EQ(CU1Ref1DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU1TypeDieDG.getOffset(),
toRelativeReference(CU1Ref1DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1Ref2DieDG = CU1Ref1DieDG.getSibling();
EXPECT_TRUE(CU1Ref2DieDG.isValid());
EXPECT_EQ(CU1Ref2DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU1TypeDieDG.getOffset(),
toRelativeReference(CU1Ref2DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1Ref4DieDG = CU1Ref2DieDG.getSibling();
EXPECT_TRUE(CU1Ref4DieDG.isValid());
EXPECT_EQ(CU1Ref4DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU1TypeDieDG.getOffset(),
toRelativeReference(CU1Ref4DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1Ref8DieDG = CU1Ref4DieDG.getSibling();
EXPECT_TRUE(CU1Ref8DieDG.isValid());
EXPECT_EQ(CU1Ref8DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU1TypeDieDG.getOffset(),
toRelativeReference(CU1Ref8DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1RefAddrDieDG = CU1Ref8DieDG.getSibling();
EXPECT_TRUE(CU1RefAddrDieDG.isValid());
EXPECT_EQ(CU1RefAddrDieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU1TypeDieDG.getOffset(),
toDebugInfoReference(CU1RefAddrDieDG.find(DW_AT_type), -1ULL));
// Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its
// DW_AT_type points to our base type DIE.
auto CU1ToCU2RefAddrDieDG = CU1RefAddrDieDG.getSibling();
EXPECT_TRUE(CU1ToCU2RefAddrDieDG.isValid());
EXPECT_EQ(CU1ToCU2RefAddrDieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU2TypeDieDG.getOffset(),
toDebugInfoReference(CU1ToCU2RefAddrDieDG.find(DW_AT_type), -1ULL));
// Verify the sibling of the base type DIE is our Ref1 DIE and that its
// DW_AT_type points to our base type DIE.
auto CU2Ref1DieDG = CU2TypeDieDG.getSibling();
EXPECT_TRUE(CU2Ref1DieDG.isValid());
EXPECT_EQ(CU2Ref1DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(),
toRelativeReference(CU2Ref1DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2Ref2DieDG = CU2Ref1DieDG.getSibling();
EXPECT_TRUE(CU2Ref2DieDG.isValid());
EXPECT_EQ(CU2Ref2DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(),
toRelativeReference(CU2Ref2DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2Ref4DieDG = CU2Ref2DieDG.getSibling();
EXPECT_TRUE(CU2Ref4DieDG.isValid());
EXPECT_EQ(CU2Ref4DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(),
toRelativeReference(CU2Ref4DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2Ref8DieDG = CU2Ref4DieDG.getSibling();
EXPECT_TRUE(CU2Ref8DieDG.isValid());
EXPECT_EQ(CU2Ref8DieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(),
toRelativeReference(CU2Ref8DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2RefAddrDieDG = CU2Ref8DieDG.getSibling();
EXPECT_TRUE(CU2RefAddrDieDG.isValid());
EXPECT_EQ(CU2RefAddrDieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU2TypeDieDG.getOffset(),
toDebugInfoReference(CU2RefAddrDieDG.find(DW_AT_type), -1ULL));
// Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its
// DW_AT_type points to our base type DIE.
auto CU2ToCU1RefAddrDieDG = CU2RefAddrDieDG.getSibling();
EXPECT_TRUE(CU2ToCU1RefAddrDieDG.isValid());
EXPECT_EQ(CU2ToCU1RefAddrDieDG.getTag(), DW_TAG_variable);
EXPECT_EQ(CU1TypeDieDG.getOffset(),
toDebugInfoReference(CU2ToCU1RefAddrDieDG.find(DW_AT_type), -1ULL));
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr4References) {
// Test that we can decode all forms for DWARF32, version 2, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestReferences<2, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr8References) {
// Test that we can decode all forms for DWARF32, version 2, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestReferences<2, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr4References) {
// Test that we can decode all forms for DWARF32, version 3, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestReferences<3, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr8References) {
// Test that we can decode all forms for DWARF32, version 3, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestReferences<3, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr4References) {
// Test that we can decode all forms for DWARF32, version 4, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestReferences<4, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr8References) {
// Test that we can decode all forms for DWARF32, version 4, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestReferences<4, AddrType>();
}
template <uint16_t Version, class AddrType> void TestAddresses() {
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test the DWARF APIs related to accessing the DW_AT_low_pc and
// DW_AT_high_pc.
const bool SupportsHighPCAsOffset = Version >= 4;
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
// Create a subprogram DIE with no low or high PC.
dwarfgen::DIE SubprogramNoPC = CUDie.addChild(DW_TAG_subprogram);
SubprogramNoPC.addAttribute(DW_AT_name, DW_FORM_strp, "no_pc");
// Create a subprogram DIE with a low PC only.
dwarfgen::DIE SubprogramLowPC = CUDie.addChild(DW_TAG_subprogram);
SubprogramLowPC.addAttribute(DW_AT_name, DW_FORM_strp, "low_pc");
const uint64_t ActualLowPC = 0x1000;
const uint64_t ActualHighPC = 0x2000;
const uint64_t ActualHighPCOffset = ActualHighPC - ActualLowPC;
SubprogramLowPC.addAttribute(DW_AT_low_pc, DW_FORM_addr, ActualLowPC);
// Create a subprogram DIE with a low and high PC.
dwarfgen::DIE SubprogramLowHighPC = CUDie.addChild(DW_TAG_subprogram);
SubprogramLowHighPC.addAttribute(DW_AT_name, DW_FORM_strp, "low_high_pc");
SubprogramLowHighPC.addAttribute(DW_AT_low_pc, DW_FORM_addr, ActualLowPC);
// Encode the high PC as an offset from the low PC if supported.
if (SupportsHighPCAsOffset)
SubprogramLowHighPC.addAttribute(DW_AT_high_pc, DW_FORM_data4,
ActualHighPCOffset);
else
SubprogramLowHighPC.addAttribute(DW_AT_high_pc, DW_FORM_addr, ActualHighPC);
StringRef FileBytes = DG->generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto DieDG = U->getUnitDIE(false);
EXPECT_TRUE(DieDG.isValid());
uint64_t LowPC, HighPC, SectionIndex;
std::optional<uint64_t> OptU64;
// Verify the that our subprogram with no PC value fails appropriately when
// asked for any PC values.
auto SubprogramDieNoPC = DieDG.getFirstChild();
EXPECT_TRUE(SubprogramDieNoPC.isValid());
EXPECT_EQ(SubprogramDieNoPC.getTag(), DW_TAG_subprogram);
OptU64 = toAddress(SubprogramDieNoPC.find(DW_AT_low_pc));
EXPECT_FALSE((bool)OptU64);
OptU64 = toAddress(SubprogramDieNoPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
EXPECT_FALSE(SubprogramDieNoPC.getLowAndHighPC(LowPC, HighPC, SectionIndex));
OptU64 = toAddress(SubprogramDieNoPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
OptU64 = toUnsigned(SubprogramDieNoPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
OptU64 = SubprogramDieNoPC.getHighPC(ActualLowPC);
EXPECT_FALSE((bool)OptU64);
EXPECT_FALSE(SubprogramDieNoPC.getLowAndHighPC(LowPC, HighPC, SectionIndex));
// Verify the that our subprogram with only a low PC value succeeds when
// we ask for the Low PC, but fails appropriately when asked for the high PC
// or both low and high PC values.
auto SubprogramDieLowPC = SubprogramDieNoPC.getSibling();
EXPECT_TRUE(SubprogramDieLowPC.isValid());
EXPECT_EQ(SubprogramDieLowPC.getTag(), DW_TAG_subprogram);
OptU64 = toAddress(SubprogramDieLowPC.find(DW_AT_low_pc));
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(*OptU64, ActualLowPC);
OptU64 = toAddress(SubprogramDieLowPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
OptU64 = toUnsigned(SubprogramDieLowPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
OptU64 = SubprogramDieLowPC.getHighPC(ActualLowPC);
EXPECT_FALSE((bool)OptU64);
EXPECT_FALSE(SubprogramDieLowPC.getLowAndHighPC(LowPC, HighPC, SectionIndex));
// Verify the that our subprogram with only a low PC value succeeds when
// we ask for the Low PC, but fails appropriately when asked for the high PC
// or both low and high PC values.
auto SubprogramDieLowHighPC = SubprogramDieLowPC.getSibling();
EXPECT_TRUE(SubprogramDieLowHighPC.isValid());
EXPECT_EQ(SubprogramDieLowHighPC.getTag(), DW_TAG_subprogram);
OptU64 = toAddress(SubprogramDieLowHighPC.find(DW_AT_low_pc));
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(*OptU64, ActualLowPC);
// Get the high PC as an address. This should succeed if the high PC was
// encoded as an address and fail if the high PC was encoded as an offset.
OptU64 = toAddress(SubprogramDieLowHighPC.find(DW_AT_high_pc));
if (SupportsHighPCAsOffset) {
EXPECT_FALSE((bool)OptU64);
} else {
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(*OptU64, ActualHighPC);
}
// Get the high PC as an unsigned constant. This should succeed if the high PC
// was encoded as an offset and fail if the high PC was encoded as an address.
OptU64 = toUnsigned(SubprogramDieLowHighPC.find(DW_AT_high_pc));
if (SupportsHighPCAsOffset) {
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(*OptU64, ActualHighPCOffset);
} else {
EXPECT_FALSE((bool)OptU64);
}
OptU64 = SubprogramDieLowHighPC.getHighPC(ActualLowPC);
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(*OptU64, ActualHighPC);
EXPECT_TRUE(SubprogramDieLowHighPC.getLowAndHighPC(LowPC, HighPC, SectionIndex));
EXPECT_EQ(LowPC, ActualLowPC);
EXPECT_EQ(HighPC, ActualHighPC);
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr4Addresses) {
// Test that we can decode address values in DWARF32, version 2, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestAddresses<2, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr8Addresses) {
// Test that we can decode address values in DWARF32, version 2, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestAddresses<2, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr4Addresses) {
// Test that we can decode address values in DWARF32, version 3, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestAddresses<3, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version3Addr8Addresses) {
// Test that we can decode address values in DWARF32, version 3, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestAddresses<3, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr4Addresses) {
// Test that we can decode address values in DWARF32, version 4, with 4 byte
// addresses.
typedef uint32_t AddrType;
TestAddresses<4, AddrType>();
}
TEST(DWARFDebugInfo, TestDWARF32Version4Addr8Addresses) {
// Test that we can decode address values in DWARF32, version 4, with 8 byte
// addresses.
typedef uint64_t AddrType;
TestAddresses<4, AddrType>();
}
#ifdef NO_SUPPORT_DEBUG_STR_OFFSETS
TEST(DWARFDebugInfo, DISABLED_TestStringOffsets) {
#else
TEST(DWARFDebugInfo, TestStringOffsets) {
#endif
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
const char *String1 = "Hello";
const char *String2 = "World";
auto ExpectedDG = dwarfgen::Generator::create(Triple, 5);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
CUDie.addStrOffsetsBaseAttribute();
uint16_t Attr = DW_AT_lo_user;
// Create our strings. First we create a non-indexed reference to String1,
// followed by an indexed String2. Finally, we add an indexed reference to
// String1.
const auto Attr1 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr1, DW_FORM_strp, String1);
const auto Attr2 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr2, DW_FORM_strx, String2);
const auto Attr3 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr3, DW_FORM_strx, String1);
// Generate the DWARF
StringRef FileBytes = DG->generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
ASSERT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
ASSERT_EQ(NumCUs, 1u);
DWARFUnit *U = DwarfContext->getUnitAtIndex(0);
auto DieDG = U->getUnitDIE(false);
ASSERT_TRUE(DieDG.isValid());
ASSERT_TRUE(U->isLittleEndian() == Triple.isLittleEndian());
// Now make sure the string offsets came out properly. Attr2 should have index
// 0 (because it was the first indexed string) even though the string itself
// was added eariler.
auto Extracted1 = toString(DieDG.find(Attr1));
ASSERT_TRUE((bool)Extracted1);
EXPECT_STREQ(String1, *Extracted1);
std::optional<DWARFFormValue> Form2 = DieDG.find(Attr2);
ASSERT_TRUE((bool)Form2);
EXPECT_EQ(0u, Form2->getRawUValue());
auto Extracted2 = toString(Form2);
ASSERT_TRUE((bool)Extracted2);
EXPECT_STREQ(String2, *Extracted2);
std::optional<DWARFFormValue> Form3 = DieDG.find(Attr3);
ASSERT_TRUE((bool)Form3);
EXPECT_EQ(1u, Form3->getRawUValue());
auto Extracted3 = toString(Form3);
ASSERT_TRUE((bool)Extracted3);
EXPECT_STREQ(String1, *Extracted3);
}
#ifdef NO_SUPPORT_DEBUG_ADDR
TEST(DWARFDebugInfo, DISABLED_TestEmptyStringOffsets) {
#else
TEST(DWARFDebugInfo, TestEmptyStringOffsets) {
#endif
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
const char *String1 = "Hello";
auto ExpectedDG = dwarfgen::Generator::create(Triple, 5);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
uint16_t Attr = DW_AT_lo_user;
// We shall insert only one string. It will be referenced directly.
const auto Attr1 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr1, DW_FORM_strp, String1);
// Generate the DWARF
StringRef FileBytes = DG->generate();
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
ASSERT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
EXPECT_TRUE(
DwarfContext->getDWARFObj().getStrOffsetsSection().Data.empty());
}
TEST(DWARFDebugInfo, TestRelations) {
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test the DWARF APIs related to accessing the DW_AT_low_pc and
// DW_AT_high_pc.
uint16_t Version = 4;
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
enum class Tag: uint16_t {
A = dwarf::DW_TAG_lo_user,
B,
C,
C1,
C2,
D,
D1
};
// Scope to allow us to re-use the same DIE names
{
// Create DWARF tree that looks like:
//
// CU
// A
// B
// C
// C1
// C2
// D
// D1
dwarfgen::DIE CUDie = CU.getUnitDIE();
dwarfgen::DIE A = CUDie.addChild((dwarf::Tag)Tag::A);
A.addChild((dwarf::Tag)Tag::B);
dwarfgen::DIE C = A.addChild((dwarf::Tag)Tag::C);
dwarfgen::DIE D = A.addChild((dwarf::Tag)Tag::D);
C.addChild((dwarf::Tag)Tag::C1);
C.addChild((dwarf::Tag)Tag::C2);
D.addChild((dwarf::Tag)Tag::D1);
}
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
// The compile unit doesn't have a parent or a sibling.
auto ParentDie = CUDie.getParent();
EXPECT_FALSE(ParentDie.isValid());
auto SiblingDie = CUDie.getSibling();
EXPECT_FALSE(SiblingDie.isValid());
// Get the children of the compile unit
auto A = CUDie.getFirstChild();
auto B = A.getFirstChild();
auto C = B.getSibling();
auto D = C.getSibling();
auto Null = D.getSibling();
// Verify NULL Die is NULL and has no children or siblings
EXPECT_TRUE(Null.isNULL());
EXPECT_FALSE(Null.getSibling().isValid());
EXPECT_FALSE(Null.getFirstChild().isValid());
// Verify all children of the compile unit DIE are correct.
EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A);
EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B);
EXPECT_EQ(C.getTag(), (dwarf::Tag)Tag::C);
EXPECT_EQ(D.getTag(), (dwarf::Tag)Tag::D);
// Verify who has children
EXPECT_TRUE(A.hasChildren());
EXPECT_FALSE(B.hasChildren());
EXPECT_TRUE(C.hasChildren());
EXPECT_TRUE(D.hasChildren());
// Make sure the parent of all the children of the compile unit are the
// compile unit.
EXPECT_EQ(A.getParent(), CUDie);
// Make sure the parent of all the children of A are the A.
// B is the first child in A, so we need to verify we can get the previous
// DIE as the parent.
EXPECT_EQ(B.getParent(), A);
// C is the second child in A, so we need to make sure we can backup across
// other DIE (B) at the same level to get the correct parent.
EXPECT_EQ(C.getParent(), A);
// D is the third child of A. We need to verify we can backup across other DIE
// (B and C) including DIE that have children (D) to get the correct parent.
EXPECT_EQ(D.getParent(), A);
// Verify that a DIE with no children returns an invalid DWARFDie.
EXPECT_FALSE(B.getFirstChild().isValid());
// Verify the children of the B DIE
auto C1 = C.getFirstChild();
auto C2 = C1.getSibling();
EXPECT_TRUE(C2.getSibling().isNULL());
// Verify all children of the B DIE correctly valid or invalid.
EXPECT_EQ(C1.getTag(), (dwarf::Tag)Tag::C1);
EXPECT_EQ(C2.getTag(), (dwarf::Tag)Tag::C2);
// Make sure the parent of all the children of the B are the B.
EXPECT_EQ(C1.getParent(), C);
EXPECT_EQ(C2.getParent(), C);
// Make sure iterators work as expected.
EXPECT_THAT(std::vector<DWARFDie>(A.begin(), A.end()),
testing::ElementsAre(B, C, D));
EXPECT_THAT(std::vector<DWARFDie>(A.rbegin(), A.rend()),
testing::ElementsAre(D, C, B));
// Make sure conversion from reverse iterator works as expected.
EXPECT_EQ(A.rbegin().base(), A.end());
EXPECT_EQ(A.rend().base(), A.begin());
// Make sure iterator is bidirectional.
{
auto Begin = A.begin();
auto End = A.end();
auto It = A.begin();
EXPECT_EQ(It, Begin);
EXPECT_EQ(*It, B);
++It;
EXPECT_EQ(*It, C);
++It;
EXPECT_EQ(*It, D);
++It;
EXPECT_EQ(It, End);
--It;
EXPECT_EQ(*It, D);
--It;
EXPECT_EQ(*It, C);
--It;
EXPECT_EQ(*It, B);
EXPECT_EQ(It, Begin);
}
// Make sure reverse iterator is bidirectional.
{
auto Begin = A.rbegin();
auto End = A.rend();
auto It = A.rbegin();
EXPECT_EQ(It, Begin);
EXPECT_EQ(*It, D);
++It;
EXPECT_EQ(*It, C);
++It;
EXPECT_EQ(*It, B);
++It;
EXPECT_EQ(It, End);
--It;
EXPECT_EQ(*It, B);
--It;
EXPECT_EQ(*It, C);
--It;
EXPECT_EQ(*It, D);
EXPECT_EQ(It, Begin);
}
}
TEST(DWARFDebugInfo, TestDWARFDie) {
// Make sure a default constructed DWARFDie doesn't have any parent, sibling
// or child;
DWARFDie DefaultDie;
EXPECT_FALSE(DefaultDie.getParent().isValid());
EXPECT_FALSE(DefaultDie.getFirstChild().isValid());
EXPECT_FALSE(DefaultDie.getSibling().isValid());
}
TEST(DWARFDebugInfo, TestChildIterators) {
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test the DWARF APIs related to iterating across the children of a DIE using
// the DWARFDie::iterator class.
uint16_t Version = 4;
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
enum class Tag: uint16_t {
A = dwarf::DW_TAG_lo_user,
B,
};
// Scope to allow us to re-use the same DIE names
{
// Create DWARF tree that looks like:
//
// CU
// A
// B
auto CUDie = CU.getUnitDIE();
CUDie.addChild((dwarf::Tag)Tag::A);
CUDie.addChild((dwarf::Tag)Tag::B);
}
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
uint32_t Index;
DWARFDie A;
DWARFDie B;
// Verify the compile unit DIE's children.
Index = 0;
for (auto Die : CUDie.children()) {
switch (Index++) {
case 0: A = Die; break;
case 1: B = Die; break;
}
}
EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A);
EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B);
// Verify that A has no children by verifying that the begin and end contain
// invalid DIEs and also that the iterators are equal.
EXPECT_EQ(A.begin(), A.end());
}
TEST(DWARFDebugInfo, TestChildIteratorsOnInvalidDie) {
// Verify that an invalid DIE has no children.
DWARFDie Invalid;
auto begin = Invalid.begin();
auto end = Invalid.end();
EXPECT_FALSE(begin->isValid());
EXPECT_FALSE(end->isValid());
EXPECT_EQ(begin, end);
}
TEST(DWARFDebugInfo, TestEmptyChildren) {
const char *yamldata = "debug_abbrev:\n"
" - Table:\n"
" - Code: 0x00000001\n"
" Tag: DW_TAG_compile_unit\n"
" Children: DW_CHILDREN_yes\n"
"debug_info:\n"
" - Version: 4\n"
" AddrSize: 8\n"
" Entries:\n"
" - AbbrCode: 0x00000001\n"
" - AbbrCode: 0x00000000\n";
auto ErrOrSections = DWARFYAML::emitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
std::unique_ptr<DWARFContext> DwarfContext =
DWARFContext::create(*ErrOrSections, 8);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
// Verify that the CU Die that says it has children, but doesn't, actually
// has begin and end iterators that are equal. We want to make sure we don't
// see the Null DIEs during iteration.
EXPECT_EQ(CUDie.begin(), CUDie.end());
}
TEST(DWARFDebugInfo, TestAttributeIterators) {
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test the DWARF APIs related to iterating across all attribute values in a
// a DWARFDie.
uint16_t Version = 4;
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
const uint64_t CULowPC = 0x1000;
StringRef CUPath("/tmp/main.c");
// Scope to allow us to re-use the same DIE names
{
auto CUDie = CU.getUnitDIE();
// Encode an attribute value before an attribute with no data.
CUDie.addAttribute(DW_AT_name, DW_FORM_strp, CUPath.data());
// Encode an attribute value with no data in .debug_info/types to ensure
// the iteration works correctly.
CUDie.addAttribute(DW_AT_declaration, DW_FORM_flag_present);
// Encode an attribute value after an attribute with no data.
CUDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, CULowPC);
}
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
auto R = CUDie.attributes();
auto I = R.begin();
auto E = R.end();
ASSERT_NE(E, I);
EXPECT_EQ(I->Attr, DW_AT_name);
auto ActualCUPath = toString(I->Value);
EXPECT_EQ(CUPath, *ActualCUPath);
ASSERT_NE(E, ++I);
EXPECT_EQ(I->Attr, DW_AT_declaration);
EXPECT_EQ(1ull, *I->Value.getAsUnsignedConstant());
ASSERT_NE(E, ++I);
EXPECT_EQ(I->Attr, DW_AT_low_pc);
EXPECT_EQ(CULowPC, *I->Value.getAsAddress());
EXPECT_EQ(E, ++I);
}
TEST(DWARFDebugInfo, TestFindRecurse) {
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
uint16_t Version = 4;
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
StringRef SpecDieName = "spec";
StringRef SpecLinkageName = "spec_linkage";
StringRef AbsDieName = "abs";
// Scope to allow us to re-use the same DIE names
{
auto CUDie = CU.getUnitDIE();
auto FuncSpecDie = CUDie.addChild(DW_TAG_subprogram);
auto FuncAbsDie = CUDie.addChild(DW_TAG_subprogram);
// Put the linkage name in a second abstract origin DIE to ensure we
// recurse through more than just one DIE when looking for attributes.
auto FuncAbsDie2 = CUDie.addChild(DW_TAG_subprogram);
auto FuncDie = CUDie.addChild(DW_TAG_subprogram);
auto VarAbsDie = CUDie.addChild(DW_TAG_variable);
auto VarDie = CUDie.addChild(DW_TAG_variable);
FuncSpecDie.addAttribute(DW_AT_name, DW_FORM_strp, SpecDieName);
FuncAbsDie2.addAttribute(DW_AT_linkage_name, DW_FORM_strp, SpecLinkageName);
FuncAbsDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie);
FuncAbsDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, FuncAbsDie2);
FuncDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, FuncAbsDie);
VarAbsDie.addAttribute(DW_AT_name, DW_FORM_strp, AbsDieName);
VarDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, VarAbsDie);
}
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
auto FuncSpecDie = CUDie.getFirstChild();
auto FuncAbsDie = FuncSpecDie.getSibling();
auto FuncAbsDie2 = FuncAbsDie.getSibling();
auto FuncDie = FuncAbsDie2.getSibling();
auto VarAbsDie = FuncDie.getSibling();
auto VarDie = VarAbsDie.getSibling();
// Make sure we can't extract the name from the specification die when using
// DWARFDie::find() since it won't check the DW_AT_specification DIE.
EXPECT_FALSE(FuncDie.find(DW_AT_name));
// Make sure we can extract the name from the specification die when using
// DWARFDie::findRecursively() since it should recurse through the
// DW_AT_specification DIE.
auto NameOpt = FuncDie.findRecursively(DW_AT_name);
EXPECT_TRUE(NameOpt);
// Test the dwarf::toString() helper function.
auto StringOpt = toString(NameOpt);
EXPECT_TRUE(StringOpt);
EXPECT_EQ(SpecDieName, StringOpt.value_or(nullptr));
// Test the dwarf::toString() helper function with a default value specified.
EXPECT_EQ(SpecDieName, toString(NameOpt, nullptr));
auto LinkageNameOpt = FuncDie.findRecursively(DW_AT_linkage_name);
EXPECT_EQ(SpecLinkageName, toString(LinkageNameOpt).value_or(nullptr));
// Make sure we can't extract the name from the abstract origin die when using
// DWARFDie::find() since it won't check the DW_AT_abstract_origin DIE.
EXPECT_FALSE(VarDie.find(DW_AT_name));
// Make sure we can extract the name from the abstract origin die when using
// DWARFDie::findRecursively() since it should recurse through the
// DW_AT_abstract_origin DIE.
NameOpt = VarDie.findRecursively(DW_AT_name);
EXPECT_TRUE(NameOpt);
// Test the dwarf::toString() helper function.
StringOpt = toString(NameOpt);
EXPECT_TRUE(StringOpt);
EXPECT_EQ(AbsDieName, StringOpt.value_or(nullptr));
}
TEST(DWARFDebugInfo, TestSelfRecursiveType) {
typedef uint32_t AddrType;
Triple Triple = getDefaultTargetTripleForAddrSize(sizeof(AddrType));
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
auto ExpectedDG = dwarfgen::Generator::create(Triple, 4);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
// Create an invalid self-recursive typedef.
dwarfgen::DIE TypedefDie = CUDie.addChild(DW_TAG_typedef);
TypedefDie.addAttribute(DW_AT_name, DW_FORM_strp, "illegal");
TypedefDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, TypedefDie);
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U = cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
{
DWARFDie CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
DWARFDie TypedefDie = CUDie.getFirstChild();
// Test that getTypeSize doesn't get into an infinite loop.
EXPECT_EQ(TypedefDie.getTypeSize(sizeof(AddrType)), std::nullopt);
}
}
TEST(DWARFDebugInfo, TestDwarfToFunctions) {
// Test all of the dwarf::toXXX functions that take a
// std::optional<DWARFFormValue> and extract the values from it.
uint64_t InvalidU64 = 0xBADBADBADBADBADB;
int64_t InvalidS64 = 0xBADBADBADBADBADB;
// First test that we don't get valid values back when using an optional with
// no value.
std::optional<DWARFFormValue> FormValOpt1 = DWARFFormValue();
EXPECT_FALSE(toString(FormValOpt1).has_value());
EXPECT_FALSE(toUnsigned(FormValOpt1).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt1).has_value());
EXPECT_FALSE(toDebugInfoReference(FormValOpt1).has_value());
EXPECT_FALSE(toSignatureReference(FormValOpt1).has_value());
EXPECT_FALSE(toSupplementaryReference(FormValOpt1).has_value());
EXPECT_FALSE(toSigned(FormValOpt1).has_value());
EXPECT_FALSE(toAddress(FormValOpt1).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt1).has_value());
EXPECT_FALSE(toBlock(FormValOpt1).has_value());
EXPECT_EQ(nullptr, toString(FormValOpt1, nullptr));
EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt1, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt1, InvalidU64));
EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt1, InvalidU64));
EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt1, InvalidU64));
EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt1, InvalidU64));
EXPECT_EQ(InvalidU64, toAddress(FormValOpt1, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt1, InvalidU64));
EXPECT_EQ(InvalidS64, toSigned(FormValOpt1, InvalidS64));
// Test successful and unsuccessful address decoding.
uint64_t Address = 0x100000000ULL;
std::optional<DWARFFormValue> FormValOpt2 =
DWARFFormValue::createFromUValue(DW_FORM_addr, Address);
EXPECT_FALSE(toString(FormValOpt2).has_value());
EXPECT_FALSE(toUnsigned(FormValOpt2).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt2).has_value());
EXPECT_FALSE(toDebugInfoReference(FormValOpt2).has_value());
EXPECT_FALSE(toSignatureReference(FormValOpt2).has_value());
EXPECT_FALSE(toSupplementaryReference(FormValOpt2).has_value());
EXPECT_FALSE(toSigned(FormValOpt2).has_value());
EXPECT_TRUE(toAddress(FormValOpt2).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt2).has_value());
EXPECT_FALSE(toBlock(FormValOpt2).has_value());
EXPECT_EQ(nullptr, toString(FormValOpt2, nullptr));
EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt2, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt2, InvalidU64));
EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt2, InvalidU64));
EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt2, InvalidU64));
EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt2, InvalidU64));
EXPECT_EQ(Address, toAddress(FormValOpt2, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt2, InvalidU64));
EXPECT_EQ(InvalidS64, toSigned(FormValOpt2, InvalidU64));
// Test successful and unsuccessful unsigned constant decoding.
uint64_t UData8 = 0x1020304050607080ULL;
std::optional<DWARFFormValue> FormValOpt3 =
DWARFFormValue::createFromUValue(DW_FORM_udata, UData8);
EXPECT_FALSE(toString(FormValOpt3).has_value());
EXPECT_TRUE(toUnsigned(FormValOpt3).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt3).has_value());
EXPECT_FALSE(toDebugInfoReference(FormValOpt3).has_value());
EXPECT_FALSE(toSignatureReference(FormValOpt3).has_value());
EXPECT_FALSE(toSupplementaryReference(FormValOpt3).has_value());
EXPECT_TRUE(toSigned(FormValOpt3).has_value());
EXPECT_FALSE(toAddress(FormValOpt3).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt3).has_value());
EXPECT_FALSE(toBlock(FormValOpt3).has_value());
EXPECT_EQ(nullptr, toString(FormValOpt3, nullptr));
EXPECT_EQ(UData8, toUnsigned(FormValOpt3, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt3, InvalidU64));
EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt3, InvalidU64));
EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt3, InvalidU64));
EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt3, InvalidU64));
EXPECT_EQ(InvalidU64, toAddress(FormValOpt3, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt3, InvalidU64));
EXPECT_EQ((int64_t)UData8, toSigned(FormValOpt3, InvalidU64));
// Test successful and unsuccessful ref_addr decoding.
uint32_t RefData = 0x11223344U;
std::optional<DWARFFormValue> FormValOpt4Addr =
DWARFFormValue::createFromUValue(DW_FORM_ref_addr, RefData);
EXPECT_FALSE(toString(FormValOpt4Addr).has_value());
EXPECT_FALSE(toUnsigned(FormValOpt4Addr).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt4Addr).has_value());
EXPECT_TRUE(toDebugInfoReference(FormValOpt4Addr).has_value());
EXPECT_FALSE(toSignatureReference(FormValOpt4Addr).has_value());
EXPECT_FALSE(toSupplementaryReference(FormValOpt4Addr).has_value());
EXPECT_FALSE(toSigned(FormValOpt4Addr).has_value());
EXPECT_FALSE(toAddress(FormValOpt4Addr).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt4Addr).has_value());
EXPECT_FALSE(toBlock(FormValOpt4Addr).has_value());
EXPECT_EQ(nullptr, toString(FormValOpt4Addr, nullptr));
EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt4Addr, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt4Addr, InvalidU64));
EXPECT_EQ(RefData, toDebugInfoReference(FormValOpt4Addr, InvalidU64));
EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt4Addr, InvalidU64));
EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt4Addr, InvalidU64));
EXPECT_EQ(InvalidU64, toAddress(FormValOpt4Addr, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt4Addr, InvalidU64));
EXPECT_EQ(InvalidS64, toSigned(FormValOpt4Addr, InvalidU64));
// Test successful and unsuccessful ref_sig8 decoding.
std::optional<DWARFFormValue> FormValOpt4Sig =
DWARFFormValue::createFromUValue(DW_FORM_ref_sig8, RefData);
EXPECT_FALSE(toString(FormValOpt4Sig).has_value());
EXPECT_FALSE(toUnsigned(FormValOpt4Sig).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt4Sig).has_value());
EXPECT_FALSE(toDebugInfoReference(FormValOpt4Sig).has_value());
EXPECT_TRUE(toSignatureReference(FormValOpt4Sig).has_value());
EXPECT_FALSE(toSupplementaryReference(FormValOpt4Sig).has_value());
EXPECT_FALSE(toSigned(FormValOpt4Sig).has_value());
EXPECT_FALSE(toAddress(FormValOpt4Sig).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt4Sig).has_value());
EXPECT_FALSE(toBlock(FormValOpt4Sig).has_value());
EXPECT_EQ(nullptr, toString(FormValOpt4Sig, nullptr));
EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt4Sig, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt4Sig, InvalidU64));
EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt4Sig, InvalidU64));
EXPECT_EQ(RefData, toSignatureReference(FormValOpt4Sig, InvalidU64));
EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt4Sig, InvalidU64));
EXPECT_EQ(InvalidU64, toAddress(FormValOpt4Sig, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt4Sig, InvalidU64));
EXPECT_EQ(InvalidS64, toSigned(FormValOpt4Sig, InvalidU64));
// Test successful and unsuccessful ref_alt decoding.
// Not testing relative reference forms here, as they require a valid
// DWARFUnit object.
std::optional<DWARFFormValue> FormValOpt4Alt =
DWARFFormValue::createFromUValue(DW_FORM_GNU_ref_alt, RefData);
EXPECT_FALSE(toString(FormValOpt4Alt).has_value());
EXPECT_FALSE(toUnsigned(FormValOpt4Alt).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt4Alt).has_value());
EXPECT_FALSE(toDebugInfoReference(FormValOpt4Alt).has_value());
EXPECT_FALSE(toSignatureReference(FormValOpt4Alt).has_value());
EXPECT_TRUE(toSupplementaryReference(FormValOpt4Alt).has_value());
EXPECT_FALSE(toSigned(FormValOpt4Alt).has_value());
EXPECT_FALSE(toAddress(FormValOpt4Alt).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt4Alt).has_value());
EXPECT_FALSE(toBlock(FormValOpt4Alt).has_value());
EXPECT_EQ(nullptr, toString(FormValOpt4Alt, nullptr));
EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt4Alt, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt4Alt, InvalidU64));
EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt4Alt, InvalidU64));
EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt4Alt, InvalidU64));
EXPECT_EQ(RefData, toSupplementaryReference(FormValOpt4Alt, InvalidU64));
EXPECT_EQ(InvalidU64, toAddress(FormValOpt4Alt, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt4Alt, InvalidU64));
EXPECT_EQ(InvalidS64, toSigned(FormValOpt4Alt, InvalidU64));
// Test successful and unsuccessful signed constant decoding.
int64_t SData8 = 0x1020304050607080ULL;
std::optional<DWARFFormValue> FormValOpt5 =
DWARFFormValue::createFromSValue(DW_FORM_udata, SData8);
EXPECT_FALSE(toString(FormValOpt5).has_value());
EXPECT_TRUE(toUnsigned(FormValOpt5).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt5).has_value());
EXPECT_FALSE(toDebugInfoReference(FormValOpt5).has_value());
EXPECT_FALSE(toSignatureReference(FormValOpt5).has_value());
EXPECT_FALSE(toSupplementaryReference(FormValOpt5).has_value());
EXPECT_TRUE(toSigned(FormValOpt5).has_value());
EXPECT_FALSE(toAddress(FormValOpt5).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt5).has_value());
EXPECT_FALSE(toBlock(FormValOpt5).has_value());
EXPECT_EQ(nullptr, toString(FormValOpt5, nullptr));
EXPECT_EQ((uint64_t)SData8, toUnsigned(FormValOpt5, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt5, InvalidU64));
EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt5, InvalidU64));
EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt5, InvalidU64));
EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt5, InvalidU64));
EXPECT_EQ(InvalidU64, toAddress(FormValOpt5, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt5, InvalidU64));
EXPECT_EQ(SData8, toSigned(FormValOpt5, InvalidU64));
// Test successful and unsuccessful block decoding.
uint8_t Data[] = { 2, 3, 4 };
ArrayRef<uint8_t> Array(Data);
std::optional<DWARFFormValue> FormValOpt6 =
DWARFFormValue::createFromBlockValue(DW_FORM_block1, Array);
EXPECT_FALSE(toString(FormValOpt6).has_value());
EXPECT_FALSE(toUnsigned(FormValOpt6).has_value());
EXPECT_FALSE(toRelativeReference(FormValOpt6).has_value());
EXPECT_FALSE(toDebugInfoReference(FormValOpt6).has_value());
EXPECT_FALSE(toSignatureReference(FormValOpt6).has_value());
EXPECT_FALSE(toSupplementaryReference(FormValOpt6).has_value());
EXPECT_FALSE(toSigned(FormValOpt6).has_value());
EXPECT_FALSE(toAddress(FormValOpt6).has_value());
EXPECT_FALSE(toSectionOffset(FormValOpt6).has_value());
auto BlockOpt = toBlock(FormValOpt6);
EXPECT_TRUE(BlockOpt.has_value());
EXPECT_EQ(*BlockOpt, Array);
EXPECT_EQ(nullptr, toString(FormValOpt6, nullptr));
EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt6, InvalidU64));
EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt6, InvalidU64));
EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt6, InvalidU64));
EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt6, InvalidU64));
EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt6, InvalidU64));
EXPECT_EQ(InvalidU64, toAddress(FormValOpt6, InvalidU64));
EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt6, InvalidU64));
EXPECT_EQ(InvalidS64, toSigned(FormValOpt6, InvalidU64));
// Test
}
TEST(DWARFDebugInfo, TestFindAttrs) {
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
// Test the DWARFDie::find() and DWARFDie::findRecursively() that take an
// ArrayRef<dwarf::Attribute> value to make sure they work correctly.
uint16_t Version = 4;
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
StringRef DieMangled("_Z3fooi");
// Scope to allow us to re-use the same DIE names
{
auto CUDie = CU.getUnitDIE();
auto FuncSpecDie = CUDie.addChild(DW_TAG_subprogram);
auto FuncDie = CUDie.addChild(DW_TAG_subprogram);
FuncSpecDie.addAttribute(DW_AT_MIPS_linkage_name, DW_FORM_strp, DieMangled);
FuncDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie);
}
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
auto FuncSpecDie = CUDie.getFirstChild();
auto FuncDie = FuncSpecDie.getSibling();
// Make sure that passing in an empty attribute list behave correctly.
EXPECT_FALSE(FuncDie.find(ArrayRef<dwarf::Attribute>()).has_value());
// Make sure that passing in a list of attribute that are not contained
// in the DIE returns nothing.
EXPECT_FALSE(FuncDie.find({DW_AT_low_pc, DW_AT_entry_pc}).has_value());
const dwarf::Attribute Attrs[] = {DW_AT_linkage_name,
DW_AT_MIPS_linkage_name};
// Make sure we can't extract the linkage name attributes when using
// DWARFDie::find() since it won't check the DW_AT_specification DIE.
EXPECT_FALSE(FuncDie.find(Attrs).has_value());
// Make sure we can extract the name from the specification die when using
// DWARFDie::findRecursively() since it should recurse through the
// DW_AT_specification DIE.
auto NameOpt = FuncDie.findRecursively(Attrs);
EXPECT_TRUE(NameOpt.has_value());
EXPECT_EQ(DieMangled, toString(NameOpt, ""));
}
#ifdef NO_SUPPORT_DEBUG_ADDR
TEST(DWARFDebugInfo, DISABLED_TestImplicitConstAbbrevs) {
#else
TEST(DWARFDebugInfo, TestImplicitConstAbbrevs) {
#endif
Triple Triple = getNormalizedDefaultTargetTriple();
if (!isConfigurationSupported(Triple))
GTEST_SKIP();
uint16_t Version = 5;
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
const dwarf::Attribute Attr = DW_AT_lo_user;
const int64_t Val1 = 42;
const int64_t Val2 = 43;
auto FirstVal1DIE = CUDie.addChild(DW_TAG_class_type);
FirstVal1DIE.addAttribute(Attr, DW_FORM_implicit_const, Val1);
auto SecondVal1DIE = CUDie.addChild(DW_TAG_class_type);
SecondVal1DIE.addAttribute(Attr, DW_FORM_implicit_const, Val1);
auto Val2DIE = CUDie.addChild(DW_TAG_class_type);
Val2DIE.addAttribute(Attr, DW_FORM_implicit_const, Val2);
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
DWARFCompileUnit *U =
cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
EXPECT_TRUE((bool)U);
const auto *Abbrevs = U->getAbbreviations();
EXPECT_TRUE((bool)Abbrevs);
// Let's find implicit_const abbrevs and verify,
// that there are exactly two of them and both of them
// can be dumped correctly.
typedef decltype(Abbrevs->begin()) AbbrevIt;
AbbrevIt Val1Abbrev = Abbrevs->end();
AbbrevIt Val2Abbrev = Abbrevs->end();
for(auto it = Abbrevs->begin(); it != Abbrevs->end(); ++it) {
if (it->getNumAttributes() == 0)
continue; // root abbrev for DW_TAG_compile_unit
auto A = it->getAttrByIndex(0);
EXPECT_EQ(A, Attr);
std::optional<uint32_t> AttrIndex = it->findAttributeIndex(A);
EXPECT_TRUE((bool)AttrIndex);
EXPECT_EQ(*AttrIndex, 0u);
uint64_t OffsetVal =
it->getAttributeOffsetFromIndex(*AttrIndex, /* offset */ 0, *U);
EXPECT_TRUE(it->getAttributeValueFromOffset(*AttrIndex, OffsetVal, *U));
auto FormValue = it->getAttributeValue(/* offset */ 0, A, *U);
EXPECT_TRUE((bool)FormValue);
EXPECT_EQ(FormValue->getForm(), dwarf::DW_FORM_implicit_const);
const auto V = FormValue->getAsSignedConstant();
EXPECT_TRUE((bool)V);
auto VerifyAbbrevDump = [&V](AbbrevIt it) {
std::string S;
llvm::raw_string_ostream OS(S);
it->dump(OS);
auto FormPos = OS.str().find("DW_FORM_implicit_const");
EXPECT_NE(FormPos, std::string::npos);
auto ValPos = S.find_first_of("-0123456789", FormPos);
EXPECT_NE(ValPos, std::string::npos);
int64_t Val = std::atoll(S.substr(ValPos).c_str());
EXPECT_EQ(Val, *V);
};
switch(*V) {
case Val1:
EXPECT_EQ(Val1Abbrev, Abbrevs->end());
Val1Abbrev = it;
VerifyAbbrevDump(it);
break;
case Val2:
EXPECT_EQ(Val2Abbrev, Abbrevs->end());
Val2Abbrev = it;
VerifyAbbrevDump(it);
break;
default:
FAIL() << "Unexpected attribute value: " << *V;
}
}
// Now let's make sure that two Val1-DIEs refer to the same abbrev,
// and Val2-DIE refers to another one.
auto DieDG = U->getUnitDIE(false);
auto it = DieDG.begin();
std::multimap<int64_t, decltype(it->getAbbreviationDeclarationPtr())> DIEs;
const DWARFAbbreviationDeclaration *AbbrevPtrVal1 = nullptr;
const DWARFAbbreviationDeclaration *AbbrevPtrVal2 = nullptr;
for (; it != DieDG.end(); ++it) {
const auto *AbbrevPtr = it->getAbbreviationDeclarationPtr();
EXPECT_TRUE((bool)AbbrevPtr);
auto FormValue = it->find(Attr);
EXPECT_TRUE((bool)FormValue);
const auto V = FormValue->getAsSignedConstant();
EXPECT_TRUE((bool)V);
switch(*V) {
case Val1:
AbbrevPtrVal1 = AbbrevPtr;
break;
case Val2:
AbbrevPtrVal2 = AbbrevPtr;
break;
default:
FAIL() << "Unexpected attribute value: " << *V;
}
DIEs.insert(std::make_pair(*V, AbbrevPtr));
}
EXPECT_EQ(DIEs.count(Val1), 2u);
EXPECT_EQ(DIEs.count(Val2), 1u);
auto Val1Range = DIEs.equal_range(Val1);
for (auto it = Val1Range.first; it != Val1Range.second; ++it)
EXPECT_EQ(it->second, AbbrevPtrVal1);
EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2);
}
TEST(DWARFDebugInfo, TestDWARFDieRangeInfoContains) {
DWARFVerifier::DieRangeInfo Empty;
ASSERT_TRUE(Empty.contains(Empty));
DWARFVerifier::DieRangeInfo Ranges(
{{0x10, 0x20}, {0x30, 0x40}, {0x40, 0x50}});
ASSERT_TRUE(Ranges.contains(Empty));
ASSERT_FALSE(Ranges.contains({{{0x0f, 0x10}}}));
ASSERT_FALSE(Ranges.contains({{{0x0f, 0x20}}}));
ASSERT_FALSE(Ranges.contains({{{0x0f, 0x21}}}));
// Test ranges that start at R's start address
ASSERT_TRUE(Ranges.contains({{{0x10, 0x10}}}));
ASSERT_TRUE(Ranges.contains({{{0x10, 0x11}}}));
ASSERT_TRUE(Ranges.contains({{{0x10, 0x20}}}));
ASSERT_FALSE(Ranges.contains({{{0x10, 0x21}}}));
ASSERT_TRUE(Ranges.contains({{{0x11, 0x12}}}));
// Test ranges that start at last bytes of Range
ASSERT_TRUE(Ranges.contains({{{0x1f, 0x20}}}));
ASSERT_FALSE(Ranges.contains({{{0x1f, 0x21}}}));
// Test ranges that start after Range
ASSERT_TRUE(Ranges.contains({{{0x20, 0x20}}}));
ASSERT_FALSE(Ranges.contains({{{0x20, 0x21}}}));
ASSERT_TRUE(Ranges.contains({{{0x31, 0x32}}}));
ASSERT_TRUE(Ranges.contains({{{0x3f, 0x40}}}));
ASSERT_TRUE(Ranges.contains({{{0x10, 0x20}, {0x30, 0x40}}}));
ASSERT_TRUE(Ranges.contains({{{0x11, 0x12}, {0x31, 0x32}}}));
ASSERT_TRUE(Ranges.contains(
{{{0x11, 0x12}, {0x12, 0x13}, {0x31, 0x32}, {0x32, 0x33}}}));
ASSERT_FALSE(Ranges.contains({{{0x11, 0x12},
{0x12, 0x13},
{0x20, 0x21},
{0x31, 0x32},
{0x32, 0x33}}}));
ASSERT_FALSE(Ranges.contains(
{{{0x11, 0x12}, {0x12, 0x13}, {0x31, 0x32}, {0x32, 0x51}}}));
ASSERT_TRUE(Ranges.contains({{{0x11, 0x12}, {0x30, 0x50}}}));
ASSERT_FALSE(Ranges.contains({{{0x30, 0x51}}}));
ASSERT_FALSE(Ranges.contains({{{0x50, 0x51}}}));
}
namespace {
void AssertRangesIntersect(const DWARFAddressRange &LHS,
const DWARFAddressRange &RHS) {
ASSERT_TRUE(LHS.intersects(RHS));
ASSERT_TRUE(RHS.intersects(LHS));
}
void AssertRangesDontIntersect(const DWARFAddressRange &LHS,
const DWARFAddressRange &RHS) {
ASSERT_FALSE(LHS.intersects(RHS));
ASSERT_FALSE(RHS.intersects(LHS));
}
void AssertRangesIntersect(const DWARFVerifier::DieRangeInfo &LHS,
const DWARFAddressRangesVector &Ranges) {
DWARFVerifier::DieRangeInfo RHS(Ranges);
ASSERT_TRUE(LHS.intersects(RHS));
ASSERT_TRUE(RHS.intersects(LHS));
}
void AssertRangesDontIntersect(const DWARFVerifier::DieRangeInfo &LHS,
const DWARFAddressRangesVector &Ranges) {
DWARFVerifier::DieRangeInfo RHS(Ranges);
ASSERT_FALSE(LHS.intersects(RHS));
ASSERT_FALSE(RHS.intersects(LHS));
}
} // namespace
TEST(DWARFDebugInfo, TestDwarfRangesIntersect) {
DWARFAddressRange R(0x10, 0x20);
//----------------------------------------------------------------------
// Test ranges that start before R...
//----------------------------------------------------------------------
// Other range ends before start of R
AssertRangesDontIntersect(R, {0x00, 0x10});
// Other range end address is start of a R
AssertRangesIntersect(R, {0x00, 0x11});
// Other range end address is in R
AssertRangesIntersect(R, {0x00, 0x15});
// Other range end address is at and of R
AssertRangesIntersect(R, {0x00, 0x20});
// Other range end address is past end of R
AssertRangesIntersect(R, {0x00, 0x40});
//----------------------------------------------------------------------
// Test ranges that start at R's start address
//----------------------------------------------------------------------
// Ensure empty ranges doesn't match
AssertRangesDontIntersect(R, {0x10, 0x10});
// 1 byte of Range
AssertRangesIntersect(R, {0x10, 0x11});
// same as Range
AssertRangesIntersect(R, {0x10, 0x20});
// 1 byte past Range
AssertRangesIntersect(R, {0x10, 0x21});
//----------------------------------------------------------------------
// Test ranges that start inside Range
//----------------------------------------------------------------------
// empty in range
AssertRangesDontIntersect(R, {0x11, 0x11});
// all in Range
AssertRangesIntersect(R, {0x11, 0x1f});
// ends at end of Range
AssertRangesIntersect(R, {0x11, 0x20});
// ends past Range
AssertRangesIntersect(R, {0x11, 0x21});
//----------------------------------------------------------------------
// Test ranges that start at last bytes of Range
//----------------------------------------------------------------------
// ends at end of Range
AssertRangesIntersect(R, {0x1f, 0x20});
// ends past Range
AssertRangesIntersect(R, {0x1f, 0x21});
//----------------------------------------------------------------------
// Test ranges that start after Range
//----------------------------------------------------------------------
// empty just past in Range
AssertRangesDontIntersect(R, {0x20, 0x20});
// valid past Range
AssertRangesDontIntersect(R, {0x20, 0x21});
}
TEST(DWARFDebugInfo, TestDWARFDieRangeInfoIntersects) {
DWARFVerifier::DieRangeInfo Ranges({{0x10, 0x20}, {0x30, 0x40}});
// Test empty range
AssertRangesDontIntersect(Ranges, {});
// Test range that appears before all ranges in Ranges
AssertRangesDontIntersect(Ranges, {{0x00, 0x10}});
// Test range that appears between ranges in Ranges
AssertRangesDontIntersect(Ranges, {{0x20, 0x30}});
// Test range that appears after ranges in Ranges
AssertRangesDontIntersect(Ranges, {{0x40, 0x50}});
// Test range that start before first range
AssertRangesIntersect(Ranges, {{0x00, 0x11}});
// Test range that start at first range
AssertRangesIntersect(Ranges, {{0x10, 0x11}});
// Test range that start in first range
AssertRangesIntersect(Ranges, {{0x11, 0x12}});
// Test range that start at end of first range
AssertRangesIntersect(Ranges, {{0x1f, 0x20}});
// Test range that starts at end of first range
AssertRangesDontIntersect(Ranges, {{0x20, 0x21}});
// Test range that starts at end of first range
AssertRangesIntersect(Ranges, {{0x20, 0x31}});
// Test range that start before second range and ends before second
AssertRangesDontIntersect(Ranges, {{0x2f, 0x30}});
// Test range that start before second range and ends in second
AssertRangesIntersect(Ranges, {{0x2f, 0x31}});
// Test range that start at second range
AssertRangesIntersect(Ranges, {{0x30, 0x31}});
// Test range that start in second range
AssertRangesIntersect(Ranges, {{0x31, 0x32}});
// Test range that start at end of second range
AssertRangesIntersect(Ranges, {{0x3f, 0x40}});
// Test range that starts at end of second range
AssertRangesDontIntersect(Ranges, {{0x40, 0x41}});
AssertRangesDontIntersect(Ranges, {{0x20, 0x21}, {0x2f, 0x30}});
AssertRangesIntersect(Ranges, {{0x20, 0x21}, {0x2f, 0x31}});
}
TEST(DWARFDebugInfo, TestDWARF64UnitLength) {
static const char DebugInfoSecRaw[] =
"\xff\xff\xff\xff" // DWARF64 mark
"\x88\x77\x66\x55\x44\x33\x22\x11" // Length
"\x05\x00" // Version
"\x01" // DW_UT_compile
"\x04" // Address size
"\0\0\0\0\0\0\0\0"; // Offset Into Abbrev. Sec.
StringMap<std::unique_ptr<MemoryBuffer>> Sections;
Sections.insert(std::make_pair(
"debug_info", MemoryBuffer::getMemBuffer(StringRef(
DebugInfoSecRaw, sizeof(DebugInfoSecRaw) - 1))));
auto Context = DWARFContext::create(Sections, /* AddrSize = */ 4,
/* isLittleEndian = */ true);
const auto &Obj = Context->getDWARFObj();
Obj.forEachInfoSections([&](const DWARFSection &Sec) {
DWARFUnitHeader Header;
DWARFDataExtractor Data(Obj, Sec, /* IsLittleEndian = */ true,
/* AddressSize = */ 4);
uint64_t Offset = 0;
ASSERT_THAT_ERROR(
Header.extract(*Context, Data, &Offset, DW_SECT_INFO),
FailedWithMessage(
"DWARF unit from offset 0x00000000 incl. to offset "
"0x1122334455667794 excl. extends past section size 0x00000018"));
// Header.extract() returns false because there is not enough space
// in the section for the declared length. Anyway, we can check that
// the properties are read correctly.
ASSERT_EQ(DwarfFormat::DWARF64, Header.getFormat());
ASSERT_EQ(0x1122334455667788ULL, Header.getLength());
ASSERT_EQ(5, Header.getVersion());
ASSERT_EQ(DW_UT_compile, Header.getUnitType());
ASSERT_EQ(4, Header.getAddressByteSize());
// Check that the length can be correctly read in the unit class.
DWARFUnitVector DummyUnitVector;
DWARFSection DummySec;
DWARFCompileUnit CU(*Context, Sec, Header, /* DA = */ 0, /* RS = */ 0,
/* LocSection = */ 0, /* SS = */ StringRef(),
/* SOS = */ DummySec, /* AOS = */ 0,
/* LS = */ DummySec, /* LE = */ true,
/* isDWO= */ false, DummyUnitVector);
ASSERT_EQ(0x1122334455667788ULL, CU.getLength());
});
}
} // end anonymous namespace