mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-11 21:45:16 +00:00
Make a DWARF generator so we can unit test DWARF APIs with gtest.
The only tests we have for the DWARF parser are the tests that use llvm-dwarfdump and expect output from textual dumps. More DWARF parser modification are coming in the next few weeks and I wanted to add tests that can verify that we can encode and decode all form types, as well as test some other basic DWARF APIs where we ask DIE objects for their children and siblings. DwarfGenerator.cpp was added in the lib/CodeGen directory. This file contains the code necessary to easily create DWARF for tests: dwarfgen::Generator DG; Triple Triple("x86_64--"); bool success = DG.init(Triple, Version); if (!success) return; 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); DWARFContextInMemory DwarfContext(*Obj.get()); This code is backed by the AsmPrinter code that emits DWARF for the actual compiler. While adding unit tests it was discovered that DIEValue that used DIEEntry as their values had bugs where DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref8, and DW_FORM_ref_udata forms were not supported. These are all now supported. Added support for DW_FORM_string so we can emit inlined C strings. Centralized the code to unique abbreviations into a new DIEAbbrevSet class and made both the dwarfgen::Generator and the llvm::DwarfFile classes use the new class. Fixed comments in the llvm::DIE class so that the Offset is known to be the compile/type unit offset. DIEInteger now supports more DW_FORM values. There are also unit tests that cover: Encoding and decoding all form types and values Encoding and decoding all reference types (DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8, DW_FORM_ref_udata, DW_FORM_ref_addr) including cross compile unit references with that go forward one compile unit and backward on compile unit. Differential Revision: https://reviews.llvm.org/D27326 llvm-svn: 289010
This commit is contained in:
parent
f4b13bac03
commit
34f25a2606
@ -15,12 +15,12 @@
|
||||
#define LLVM_LIB_CODEGEN_ASMPRINTER_DIE_H
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
@ -31,6 +31,7 @@
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -111,6 +112,37 @@ public:
|
||||
void dump();
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Helps unique DIEAbbrev objects and assigns abbreviation numbers.
|
||||
///
|
||||
/// This class will unique the DIE abbreviations for a llvm::DIE object and
|
||||
/// assign a unique abbreviation number to each unique DIEAbbrev object it
|
||||
/// finds. The resulting collection of DIEAbbrev objects can then be emitted
|
||||
/// into the .debug_abbrev section.
|
||||
class DIEAbbrevSet {
|
||||
/// The bump allocator to use when creating DIEAbbrev objects in the uniqued
|
||||
/// storage container.
|
||||
BumpPtrAllocator &Alloc;
|
||||
/// \brief FoldingSet that uniques the abbreviations.
|
||||
llvm::FoldingSet<DIEAbbrev> AbbreviationsSet;
|
||||
/// A list of all the unique abbreviations in use.
|
||||
std::vector<DIEAbbrev *> Abbreviations;
|
||||
|
||||
public:
|
||||
DIEAbbrevSet(BumpPtrAllocator &A) : Alloc(A) {}
|
||||
~DIEAbbrevSet();
|
||||
/// Generate the abbreviation declaration for a DIE and return a pointer to
|
||||
/// the generated abbreviation.
|
||||
///
|
||||
/// \param DIE the debug info entry to generate the abbreviation for.
|
||||
/// \returns A reference to the uniqued abbreviation declaration that is
|
||||
/// owned by this class.
|
||||
DIEAbbrev &uniqueAbbreviation(DIE &Die);
|
||||
|
||||
/// Print all abbreviations using the specified asm printer.
|
||||
void Emit(const AsmPrinter *AP, MCSection *Section) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// An integer value DIE.
|
||||
///
|
||||
@ -201,8 +233,9 @@ public:
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A container for string values.
|
||||
/// A container for string pool string values.
|
||||
///
|
||||
/// This class is used with the DW_FORM_strp and DW_FORM_GNU_str_index forms.
|
||||
class DIEString {
|
||||
DwarfStringPoolEntryRef S;
|
||||
|
||||
@ -218,6 +251,27 @@ public:
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A container for inline string values.
|
||||
///
|
||||
/// This class is used with the DW_FORM_string form.
|
||||
class DIEInlineString {
|
||||
std::string S;
|
||||
|
||||
public:
|
||||
explicit DIEInlineString(StringRef Str) : S(Str.str()) {}
|
||||
|
||||
~DIEInlineString() = default;
|
||||
|
||||
/// Grab the string out of the object.
|
||||
StringRef getString() const { return StringRef(S); }
|
||||
|
||||
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A pointer to another debug information entry. An instance of this class can
|
||||
/// also be used as a proxy for a debug information entry not yet defined
|
||||
@ -233,14 +287,8 @@ public:
|
||||
|
||||
DIE &getEntry() const { return *Entry; }
|
||||
|
||||
/// Returns size of a ref_addr entry.
|
||||
static unsigned getRefAddrSize(const AsmPrinter *AP);
|
||||
|
||||
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
return Form == dwarf::DW_FORM_ref_addr ? getRefAddrSize(AP)
|
||||
: sizeof(int32_t);
|
||||
}
|
||||
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
@ -595,20 +643,13 @@ class DIE : IntrusiveBackListNode, public DIEValueList {
|
||||
friend class IntrusiveBackList<DIE>;
|
||||
friend class DIEUnit;
|
||||
|
||||
/// Offset - Dwarf unit relative offset.
|
||||
///
|
||||
/// Dwarf unit relative offset.
|
||||
unsigned Offset;
|
||||
|
||||
/// Size - Size of instance + children.
|
||||
///
|
||||
/// Size of instance + children.
|
||||
unsigned Size;
|
||||
|
||||
unsigned AbbrevNumber = ~0u;
|
||||
|
||||
/// Tag - Dwarf tag code.
|
||||
///
|
||||
/// Dwarf tag code.
|
||||
dwarf::Tag Tag = (dwarf::Tag)0;
|
||||
|
||||
/// Children DIEs.
|
||||
IntrusiveBackList<DIE> Children;
|
||||
|
||||
@ -664,6 +705,25 @@ public:
|
||||
/// for this DIE.
|
||||
unsigned getDebugSectionOffset() const;
|
||||
|
||||
/// Compute the offset of this DIE and all its children.
|
||||
///
|
||||
/// This function gets called just before we are going to generate the debug
|
||||
/// information and gives each DIE a chance to figure out its CU relative DIE
|
||||
/// offset, unique its abbreviation and fill in the abbreviation code, and
|
||||
/// return the unit offset that points to where the next DIE will be emitted
|
||||
/// within the debug unit section. After this function has been called for all
|
||||
/// DIE objects, the DWARF can be generated since all DIEs will be able to
|
||||
/// properly refer to other DIE objects since all DIEs have calculated their
|
||||
/// offsets.
|
||||
///
|
||||
/// \param AP AsmPrinter to use when calculating sizes.
|
||||
/// \param AbbrevSet the abbreviation used to unique DIE abbreviations.
|
||||
/// \param CUOffset the compile/type unit relative offset in bytes.
|
||||
/// \returns the offset for the DIE that follows this DIE within the
|
||||
/// current compile/type unit.
|
||||
unsigned computeOffsetsAndAbbrevs(const AsmPrinter *AP,
|
||||
DIEAbbrevSet &AbbrevSet, unsigned CUOffset);
|
||||
|
||||
/// Climb up the parent chain to get the compile unit or type unit DIE that
|
||||
/// this DIE belongs to.
|
||||
///
|
||||
|
@ -40,6 +40,7 @@ HANDLE_DIEVALUE_SMALL(Entry)
|
||||
HANDLE_DIEVALUE_LARGE(Block)
|
||||
HANDLE_DIEVALUE_LARGE(Loc)
|
||||
HANDLE_DIEVALUE_SMALL(LocList)
|
||||
HANDLE_DIEVALUE_LARGE(InlineString)
|
||||
|
||||
#undef HANDLE_DIEVALUE
|
||||
#undef HANDLE_DIEVALUE_SMALL
|
||||
|
@ -105,6 +105,10 @@ public:
|
||||
dwarf::Attribute Attr,
|
||||
uint64_t FailValue) const;
|
||||
|
||||
int64_t getAttributeValueAsSignedConstant(const DWARFUnit *U,
|
||||
dwarf::Attribute Attr,
|
||||
int64_t FailValue) const;
|
||||
|
||||
uint64_t getAttributeValueAsUnsignedConstant(const DWARFUnit *U,
|
||||
dwarf::Attribute Attr,
|
||||
uint64_t FailValue) const;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "llvm/MC/SectionKind.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
@ -526,7 +527,10 @@ namespace llvm {
|
||||
|
||||
void setDwarfDebugProducer(StringRef S) { DwarfDebugProducer = S; }
|
||||
StringRef getDwarfDebugProducer() { return DwarfDebugProducer; }
|
||||
|
||||
dwarf::DwarfFormat getDwarfFormat() const {
|
||||
// TODO: Support DWARF64
|
||||
return dwarf::DWARF32;
|
||||
}
|
||||
void setDwarfVersion(uint16_t v) { DwarfVersion = v; }
|
||||
uint16_t getDwarfVersion() const { return DwarfVersion; }
|
||||
|
||||
|
@ -108,6 +108,51 @@ void DIEAbbrev::print(raw_ostream &O) {
|
||||
LLVM_DUMP_METHOD
|
||||
void DIEAbbrev::dump() { print(dbgs()); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIEAbbrevSet Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
DIEAbbrevSet::~DIEAbbrevSet() {
|
||||
for (DIEAbbrev *Abbrev : Abbreviations)
|
||||
Abbrev->~DIEAbbrev();
|
||||
}
|
||||
|
||||
DIEAbbrev &DIEAbbrevSet::uniqueAbbreviation(DIE &Die) {
|
||||
|
||||
FoldingSetNodeID ID;
|
||||
DIEAbbrev Abbrev = Die.generateAbbrev();
|
||||
Abbrev.Profile(ID);
|
||||
|
||||
void *InsertPos;
|
||||
if (DIEAbbrev *Existing =
|
||||
AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
|
||||
Die.setAbbrevNumber(Existing->getNumber());
|
||||
return *Existing;
|
||||
}
|
||||
|
||||
// Move the abbreviation to the heap and assign a number.
|
||||
DIEAbbrev *New = new (Alloc) DIEAbbrev(std::move(Abbrev));
|
||||
Abbreviations.push_back(New);
|
||||
New->setNumber(Abbreviations.size());
|
||||
Die.setAbbrevNumber(Abbreviations.size());
|
||||
|
||||
// Store it for lookup.
|
||||
AbbreviationsSet.InsertNode(New, InsertPos);
|
||||
return *New;
|
||||
}
|
||||
|
||||
void DIEAbbrevSet::Emit(const AsmPrinter *AP, MCSection *Section) const {
|
||||
if (!Abbreviations.empty()) {
|
||||
// Start the debug abbrev section.
|
||||
AP->OutStreamer->SwitchSection(Section);
|
||||
AP->emitDwarfAbbrevs(Abbreviations);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIE Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
DIE *DIE::getParent() const {
|
||||
return Owner.dyn_cast<DIE*>();
|
||||
}
|
||||
@ -198,6 +243,45 @@ void DIE::dump() {
|
||||
print(dbgs());
|
||||
}
|
||||
|
||||
unsigned DIE::computeOffsetsAndAbbrevs(const AsmPrinter *AP,
|
||||
DIEAbbrevSet &AbbrevSet,
|
||||
unsigned CUOffset) {
|
||||
// Unique the abbreviation and fill in the abbreviation number so this DIE
|
||||
// can be emitted.
|
||||
const DIEAbbrev &Abbrev = AbbrevSet.uniqueAbbreviation(*this);
|
||||
|
||||
// Set compile/type unit relative offset of this DIE.
|
||||
setOffset(CUOffset);
|
||||
|
||||
// Add the byte size of the abbreviation code.
|
||||
CUOffset += getULEB128Size(getAbbrevNumber());
|
||||
|
||||
// Add the byte size of all the DIE attribute values.
|
||||
for (const auto &V : values())
|
||||
CUOffset += V.SizeOf(AP);
|
||||
|
||||
// Let the children compute their offsets and abbreviation numbers.
|
||||
if (hasChildren()) {
|
||||
(void)Abbrev;
|
||||
assert(Abbrev.hasChildren() && "Children flag not set");
|
||||
|
||||
for (auto &Child : children())
|
||||
CUOffset = Child.computeOffsetsAndAbbrevs(AP, AbbrevSet, CUOffset);
|
||||
|
||||
// Each child chain is terminated with a zero byte, adjust the offset.
|
||||
CUOffset += sizeof(int8_t);
|
||||
}
|
||||
|
||||
// Compute the byte size of this DIE and all of its children correctly. This
|
||||
// is needed so that top level DIE can help the compile unit set its length
|
||||
// correctly.
|
||||
setSize(CUOffset - getOffset());
|
||||
return CUOffset;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIEUnit Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
DIEUnit::DIEUnit(uint16_t V, uint8_t A, dwarf::Tag UnitTag)
|
||||
: Die(UnitTag), Section(nullptr), Offset(0), Length(0), Version(V),
|
||||
AddrSize(A)
|
||||
@ -257,38 +341,65 @@ void DIEValue::dump() const {
|
||||
/// EmitValue - Emit integer of appropriate size.
|
||||
///
|
||||
void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const {
|
||||
unsigned Size = ~0U;
|
||||
switch (Form) {
|
||||
case dwarf::DW_FORM_flag_present:
|
||||
// Emit something to keep the lines and comments in sync.
|
||||
// FIXME: Is there a better way to do this?
|
||||
Asm->OutStreamer->AddBlankLine();
|
||||
return;
|
||||
case dwarf::DW_FORM_flag: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref1: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data1: Size = 1; break;
|
||||
case dwarf::DW_FORM_ref2: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data2: Size = 2; break;
|
||||
case dwarf::DW_FORM_sec_offset: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_strp: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data4: Size = 4; break;
|
||||
case dwarf::DW_FORM_ref8: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_sig8: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data8: Size = 8; break;
|
||||
case dwarf::DW_FORM_GNU_str_index: Asm->EmitULEB128(Integer); return;
|
||||
case dwarf::DW_FORM_GNU_addr_index: Asm->EmitULEB128(Integer); return;
|
||||
case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return;
|
||||
case dwarf::DW_FORM_sdata: Asm->EmitSLEB128(Integer); return;
|
||||
case dwarf::DW_FORM_flag:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref1:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data1:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref2:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data2:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_strp:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref4:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data4:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref8:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_sig8:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data8:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_GNU_ref_alt:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_GNU_strp_alt:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_line_strp:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_sec_offset:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_strp_sup:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_sup:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_addr:
|
||||
Size = Asm->getPointerSize();
|
||||
break;
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_addr:
|
||||
Size = SizeOf(Asm, dwarf::DW_FORM_ref_addr);
|
||||
break;
|
||||
Asm->OutStreamer->EmitIntValue(Integer, SizeOf(Asm, Form));
|
||||
return;
|
||||
case dwarf::DW_FORM_GNU_str_index:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_GNU_addr_index:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_udata:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_udata:
|
||||
Asm->EmitULEB128(Integer);
|
||||
return;
|
||||
case dwarf::DW_FORM_sdata:
|
||||
Asm->EmitSLEB128(Integer);
|
||||
return;
|
||||
default: llvm_unreachable("DIE Value form not supported yet");
|
||||
}
|
||||
Asm->OutStreamer->EmitIntValue(Integer, Size);
|
||||
}
|
||||
|
||||
/// SizeOf - Determine size of integer value in bytes.
|
||||
@ -301,23 +412,47 @@ unsigned DIEInteger::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
case dwarf::DW_FORM_data1: return sizeof(int8_t);
|
||||
case dwarf::DW_FORM_ref2: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data2: return sizeof(int16_t);
|
||||
case dwarf::DW_FORM_sec_offset: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_strp: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data4: return sizeof(int32_t);
|
||||
case dwarf::DW_FORM_ref8: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_sig8: LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_data8: return sizeof(int64_t);
|
||||
case dwarf::DW_FORM_GNU_str_index: return getULEB128Size(Integer);
|
||||
case dwarf::DW_FORM_GNU_addr_index: return getULEB128Size(Integer);
|
||||
case dwarf::DW_FORM_udata: return getULEB128Size(Integer);
|
||||
case dwarf::DW_FORM_sdata: return getSLEB128Size(Integer);
|
||||
case dwarf::DW_FORM_addr:
|
||||
return AP->getPointerSize();
|
||||
case dwarf::DW_FORM_ref_addr:
|
||||
if (AP->getDwarfVersion() == 2)
|
||||
return AP->getPointerSize();
|
||||
return sizeof(int32_t);
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_strp:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_GNU_ref_alt:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_GNU_strp_alt:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_line_strp:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_sec_offset:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_strp_sup:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_sup:
|
||||
switch (AP->OutStreamer->getContext().getDwarfFormat()) {
|
||||
case dwarf::DWARF32:
|
||||
return 4;
|
||||
case dwarf::DWARF64:
|
||||
return 8;
|
||||
}
|
||||
llvm_unreachable("Invalid DWARF format");
|
||||
case dwarf::DW_FORM_GNU_str_index:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_GNU_addr_index:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_ref_udata:
|
||||
LLVM_FALLTHROUGH;
|
||||
case dwarf::DW_FORM_udata:
|
||||
return getULEB128Size(Integer);
|
||||
case dwarf::DW_FORM_sdata:
|
||||
return getSLEB128Size(Integer);
|
||||
case dwarf::DW_FORM_addr:
|
||||
return AP->getPointerSize();
|
||||
default: llvm_unreachable("DIE Value form not supported yet");
|
||||
}
|
||||
}
|
||||
@ -451,6 +586,29 @@ void DIEString::print(raw_ostream &O) const {
|
||||
O << "String: " << S.getString();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIEInlineString Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
void DIEInlineString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
if (Form == dwarf::DW_FORM_string) {
|
||||
for (char ch : S)
|
||||
AP->EmitInt8(ch);
|
||||
AP->EmitInt8(0);
|
||||
return;
|
||||
}
|
||||
llvm_unreachable("Expected valid string form");
|
||||
}
|
||||
|
||||
unsigned DIEInlineString::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
// Emit string bytes + NULL byte.
|
||||
return S.size() + 1;
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
void DIEInlineString::print(raw_ostream &O) const {
|
||||
O << "InlineString: " << S.c_str();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIEEntry Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -459,33 +617,69 @@ void DIEString::print(raw_ostream &O) const {
|
||||
///
|
||||
void DIEEntry::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
|
||||
if (Form == dwarf::DW_FORM_ref_addr) {
|
||||
switch (Form) {
|
||||
case dwarf::DW_FORM_ref1:
|
||||
case dwarf::DW_FORM_ref2:
|
||||
case dwarf::DW_FORM_ref4:
|
||||
case dwarf::DW_FORM_ref8:
|
||||
AP->OutStreamer->EmitIntValue(Entry->getOffset(), SizeOf(AP, Form));
|
||||
return;
|
||||
|
||||
case dwarf::DW_FORM_ref_udata:
|
||||
AP->EmitULEB128(Entry->getOffset());
|
||||
return;
|
||||
|
||||
case dwarf::DW_FORM_ref_addr: {
|
||||
// Get the absolute offset for this DIE within the debug info/types section.
|
||||
unsigned Addr = Entry->getDebugSectionOffset();
|
||||
if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) {
|
||||
const DwarfDebug *DD = AP->getDwarfDebug();
|
||||
if (DD)
|
||||
assert(!DD->useSplitDwarf() && "TODO: dwo files can't have relocations.");
|
||||
assert(!DD->useSplitDwarf() &&
|
||||
"TODO: dwo files can't have relocations.");
|
||||
const DIEUnit *Unit = Entry->getUnit();
|
||||
assert(Unit && "CUDie should belong to a CU.");
|
||||
MCSection *Section = Unit->getSection();
|
||||
assert(Section && "Must have a section if we are doing relocations");
|
||||
const MCSymbol *SectionSym = Section->getBeginSymbol();
|
||||
AP->EmitLabelPlusOffset(SectionSym, Addr, DIEEntry::getRefAddrSize(AP));
|
||||
} else
|
||||
AP->OutStreamer->EmitIntValue(Addr, DIEEntry::getRefAddrSize(AP));
|
||||
} else
|
||||
AP->EmitInt32(Entry->getOffset());
|
||||
if (Section) {
|
||||
const MCSymbol *SectionSym = Section->getBeginSymbol();
|
||||
AP->EmitLabelPlusOffset(SectionSym, Addr, SizeOf(AP, Form));
|
||||
return;
|
||||
}
|
||||
}
|
||||
AP->OutStreamer->EmitIntValue(Addr, SizeOf(AP, Form));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Improper form for DIE reference");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned DIEEntry::getRefAddrSize(const AsmPrinter *AP) {
|
||||
// DWARF4: References that use the attribute form DW_FORM_ref_addr are
|
||||
// specified to be four bytes in the DWARF 32-bit format and eight bytes
|
||||
// in the DWARF 64-bit format, while DWARF Version 2 specifies that such
|
||||
// references have the same size as an address on the target system.
|
||||
if (AP->getDwarfVersion() == 2)
|
||||
return AP->getPointerSize();
|
||||
return sizeof(int32_t);
|
||||
unsigned DIEEntry::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
switch (Form) {
|
||||
case dwarf::DW_FORM_ref1:
|
||||
return 1;
|
||||
case dwarf::DW_FORM_ref2:
|
||||
return 2;
|
||||
case dwarf::DW_FORM_ref4:
|
||||
return 4;
|
||||
case dwarf::DW_FORM_ref8:
|
||||
return 8;
|
||||
case dwarf::DW_FORM_ref_udata:
|
||||
return getULEB128Size(Entry->getOffset());
|
||||
case dwarf::DW_FORM_ref_addr:
|
||||
if (AP->getDwarfVersion() == 2)
|
||||
return AP->getPointerSize();
|
||||
switch (AP->OutStreamer->getContext().getDwarfFormat()) {
|
||||
case dwarf::DWARF32:
|
||||
return 4;
|
||||
case dwarf::DWARF64:
|
||||
return 8;
|
||||
}
|
||||
llvm_unreachable("Invalid DWARF format");
|
||||
|
||||
default:
|
||||
llvm_unreachable("Improper form for DIE reference");
|
||||
}
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
|
@ -330,6 +330,12 @@ void DIEHash::hashAttribute(const DIEValue &Value, dwarf::Tag Tag) {
|
||||
addULEB128(dwarf::DW_FORM_string);
|
||||
addString(Value.getDIEString().getString());
|
||||
break;
|
||||
case DIEValue::isInlineString:
|
||||
addULEB128('A');
|
||||
addULEB128(Attribute);
|
||||
addULEB128(dwarf::DW_FORM_string);
|
||||
addString(Value.getDIEInlineString().getString());
|
||||
break;
|
||||
case DIEValue::isBlock:
|
||||
case DIEValue::isLoc:
|
||||
case DIEValue::isLocList:
|
||||
|
@ -19,37 +19,7 @@
|
||||
|
||||
namespace llvm {
|
||||
DwarfFile::DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA)
|
||||
: Asm(AP), StrPool(DA, *Asm, Pref) {}
|
||||
|
||||
DwarfFile::~DwarfFile() {
|
||||
for (DIEAbbrev *Abbrev : Abbreviations)
|
||||
Abbrev->~DIEAbbrev();
|
||||
}
|
||||
|
||||
// Define a unique number for the abbreviation.
|
||||
//
|
||||
DIEAbbrev &DwarfFile::assignAbbrevNumber(DIE &Die) {
|
||||
FoldingSetNodeID ID;
|
||||
DIEAbbrev Abbrev = Die.generateAbbrev();
|
||||
Abbrev.Profile(ID);
|
||||
|
||||
void *InsertPos;
|
||||
if (DIEAbbrev *Existing =
|
||||
AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
|
||||
Die.setAbbrevNumber(Existing->getNumber());
|
||||
return *Existing;
|
||||
}
|
||||
|
||||
// Move the abbreviation to the heap and assign a number.
|
||||
DIEAbbrev *New = new (AbbrevAllocator) DIEAbbrev(std::move(Abbrev));
|
||||
Abbreviations.push_back(New);
|
||||
New->setNumber(Abbreviations.size());
|
||||
Die.setAbbrevNumber(Abbreviations.size());
|
||||
|
||||
// Store it for lookup.
|
||||
AbbreviationsSet.InsertNode(New, InsertPos);
|
||||
return *New;
|
||||
}
|
||||
: Asm(AP), Abbrevs(AbbrevAllocator), StrPool(DA, *Asm, Pref) {}
|
||||
|
||||
void DwarfFile::addUnit(std::unique_ptr<DwarfCompileUnit> U) {
|
||||
CUs.push_back(std::move(U));
|
||||
@ -98,44 +68,10 @@ unsigned DwarfFile::computeSizeAndOffsetsForUnit(DwarfUnit *TheU) {
|
||||
// Compute the size and offset of a DIE. The offset is relative to start of the
|
||||
// CU. It returns the offset after laying out the DIE.
|
||||
unsigned DwarfFile::computeSizeAndOffset(DIE &Die, unsigned Offset) {
|
||||
// Record the abbreviation.
|
||||
const DIEAbbrev &Abbrev = assignAbbrevNumber(Die);
|
||||
|
||||
// Set DIE offset
|
||||
Die.setOffset(Offset);
|
||||
|
||||
// Start the size with the size of abbreviation code.
|
||||
Offset += getULEB128Size(Die.getAbbrevNumber());
|
||||
|
||||
// Size the DIE attribute values.
|
||||
for (const auto &V : Die.values())
|
||||
// Size attribute value.
|
||||
Offset += V.SizeOf(Asm);
|
||||
|
||||
// Size the DIE children if any.
|
||||
if (Die.hasChildren()) {
|
||||
(void)Abbrev;
|
||||
assert(Abbrev.hasChildren() && "Children flag not set");
|
||||
|
||||
for (auto &Child : Die.children())
|
||||
Offset = computeSizeAndOffset(Child, Offset);
|
||||
|
||||
// End of children marker.
|
||||
Offset += sizeof(int8_t);
|
||||
}
|
||||
|
||||
Die.setSize(Offset - Die.getOffset());
|
||||
return Offset;
|
||||
return Die.computeOffsetsAndAbbrevs(Asm, Abbrevs, Offset);
|
||||
}
|
||||
|
||||
void DwarfFile::emitAbbrevs(MCSection *Section) {
|
||||
// Check to see if it is worth the effort.
|
||||
if (!Abbreviations.empty()) {
|
||||
// Start the debug abbrev section.
|
||||
Asm->OutStreamer->SwitchSection(Section);
|
||||
Asm->emitDwarfAbbrevs(Abbreviations);
|
||||
}
|
||||
}
|
||||
void DwarfFile::emitAbbrevs(MCSection *Section) { Abbrevs.Emit(Asm, Section); }
|
||||
|
||||
// Emit strings into a string section.
|
||||
void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection) {
|
||||
|
@ -16,10 +16,10 @@
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class AsmPrinter;
|
||||
@ -41,10 +41,7 @@ class DwarfFile {
|
||||
BumpPtrAllocator AbbrevAllocator;
|
||||
|
||||
// Used to uniquely define abbreviations.
|
||||
FoldingSet<DIEAbbrev> AbbreviationsSet;
|
||||
|
||||
// A list of all the unique abbreviations in use.
|
||||
std::vector<DIEAbbrev *> Abbreviations;
|
||||
DIEAbbrevSet Abbrevs;
|
||||
|
||||
// A pointer to all units in the section.
|
||||
SmallVector<std::unique_ptr<DwarfCompileUnit>, 1> CUs;
|
||||
@ -65,8 +62,6 @@ class DwarfFile {
|
||||
public:
|
||||
DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA);
|
||||
|
||||
~DwarfFile();
|
||||
|
||||
const SmallVectorImpl<std::unique_ptr<DwarfCompileUnit>> &getUnits() {
|
||||
return CUs;
|
||||
}
|
||||
@ -81,12 +76,6 @@ public:
|
||||
/// \returns The size of the root DIE.
|
||||
unsigned computeSizeAndOffsetsForUnit(DwarfUnit *TheU);
|
||||
|
||||
/// Define a unique number for the abbreviation.
|
||||
///
|
||||
/// Compute the abbreviation for \c Die, look up its unique number, and
|
||||
/// return a reference to it in the uniquing table.
|
||||
DIEAbbrev &assignAbbrevNumber(DIE &Die);
|
||||
|
||||
/// \brief Add a unit to the list of CUs.
|
||||
void addUnit(std::unique_ptr<DwarfCompileUnit> U);
|
||||
|
||||
|
@ -17,6 +17,7 @@ add_llvm_library(LLVMCodeGen
|
||||
DetectDeadLanes.cpp
|
||||
DFAPacketizer.cpp
|
||||
DwarfEHPrepare.cpp
|
||||
DwarfGenerator.cpp
|
||||
EarlyIfConversion.cpp
|
||||
EdgeBundles.cpp
|
||||
ExecutionDepsFix.cpp
|
||||
|
262
lib/CodeGen/DwarfGenerator.cpp
Normal file
262
lib/CodeGen/DwarfGenerator.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
//===--- lib/CodeGen/DwarfGenerator.cpp -------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DwarfGenerator.h"
|
||||
#include "AsmPrinter/DwarfStringPool.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/IR/LegacyPassManagers.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCDwarf.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
|
||||
#include "llvm/PassAnalysisSupport.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace dwarf;
|
||||
|
||||
namespace {} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// dwarfgen::DIE implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
unsigned dwarfgen::DIE::computeSizeAndOffsets(unsigned Offset) {
|
||||
auto &DG = CU->getGenerator();
|
||||
return Die->computeOffsetsAndAbbrevs(DG.getAsmPrinter(), DG.getAbbrevSet(),
|
||||
Offset);
|
||||
}
|
||||
|
||||
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) {
|
||||
auto &DG = CU->getGenerator();
|
||||
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
|
||||
DIEInteger(U));
|
||||
}
|
||||
|
||||
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
|
||||
StringRef String) {
|
||||
auto &DG = CU->getGenerator();
|
||||
if (Form == DW_FORM_string) {
|
||||
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
|
||||
new (DG.getAllocator()) DIEInlineString(String));
|
||||
} else {
|
||||
Die->addValue(
|
||||
DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
|
||||
DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
|
||||
}
|
||||
}
|
||||
|
||||
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
|
||||
dwarfgen::DIE &RefDie) {
|
||||
auto &DG = CU->getGenerator();
|
||||
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
|
||||
DIEEntry(*RefDie.Die));
|
||||
}
|
||||
|
||||
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const void *P,
|
||||
size_t S) {
|
||||
auto &DG = CU->getGenerator();
|
||||
DIEBlock *Block = new (DG.getAllocator()) DIEBlock;
|
||||
for (size_t I = 0; I < S; ++I)
|
||||
Block->addValue(DG.getAllocator(), (dwarf::Attribute)0,
|
||||
dwarf::DW_FORM_data1, DIEInteger(((uint8_t *)P)[I]));
|
||||
|
||||
Block->ComputeSize(DG.getAsmPrinter());
|
||||
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
|
||||
Block);
|
||||
}
|
||||
|
||||
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) {
|
||||
auto &DG = CU->getGenerator();
|
||||
assert(Form == DW_FORM_flag_present);
|
||||
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
|
||||
DIEInteger(1));
|
||||
}
|
||||
|
||||
dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
|
||||
auto &DG = CU->getGenerator();
|
||||
return dwarfgen::DIE(CU,
|
||||
&Die->addChild(llvm::DIE::get(DG.getAllocator(), Tag)));
|
||||
}
|
||||
|
||||
dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
|
||||
return dwarfgen::DIE(this, &DU.getUnitDie());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// dwarfgen::Generator implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
dwarfgen::Generator::Generator() : Abbreviations(Allocator) {}
|
||||
dwarfgen::Generator::~Generator() = default;
|
||||
|
||||
llvm::Expected<std::unique_ptr<dwarfgen::Generator>>
|
||||
dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) {
|
||||
std::unique_ptr<dwarfgen::Generator> GenUP(new dwarfgen::Generator());
|
||||
llvm::Error error = GenUP->init(TheTriple, DwarfVersion);
|
||||
if (error)
|
||||
return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(error));
|
||||
return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(GenUP));
|
||||
}
|
||||
|
||||
llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
|
||||
Version = V;
|
||||
std::string ErrorStr;
|
||||
std::string TripleName;
|
||||
|
||||
// Get the target.
|
||||
const Target *TheTarget =
|
||||
TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
|
||||
if (!TheTarget)
|
||||
return make_error<StringError>(ErrorStr, inconvertibleErrorCode());
|
||||
|
||||
TripleName = TheTriple.getTriple();
|
||||
|
||||
// Create all the MC Objects.
|
||||
MRI.reset(TheTarget->createMCRegInfo(TripleName));
|
||||
if (!MRI)
|
||||
return make_error<StringError>(Twine("no register info for target ") +
|
||||
TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
|
||||
if (!MAI)
|
||||
return make_error<StringError>("no asm info for target " + TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
MOFI.reset(new MCObjectFileInfo);
|
||||
MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
|
||||
MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, CodeModel::Default, *MC);
|
||||
|
||||
MCTargetOptions Options;
|
||||
MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "", Options);
|
||||
if (!MAB)
|
||||
return make_error<StringError>("no asm backend for target " + TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
MII.reset(TheTarget->createMCInstrInfo());
|
||||
if (!MII)
|
||||
return make_error<StringError>("no instr info info for target " +
|
||||
TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
||||
if (!MSTI)
|
||||
return make_error<StringError>("no subtarget info for target " + TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
|
||||
if (!MCE)
|
||||
return make_error<StringError>("no code emitter for target " + TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
Stream = make_unique<raw_svector_ostream>(FileBytes);
|
||||
|
||||
MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
|
||||
MS = TheTarget->createMCObjectStreamer(
|
||||
TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll,
|
||||
MCOptions.MCIncrementalLinkerCompatible,
|
||||
/*DWARFMustBeAtTheEnd*/ false);
|
||||
if (!MS)
|
||||
return make_error<StringError>("no object streamer for target " +
|
||||
TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// Finally create the AsmPrinter we'll use to emit the DIEs.
|
||||
TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
|
||||
None));
|
||||
if (!TM)
|
||||
return make_error<StringError>("no target machine for target " + TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
|
||||
if (!Asm)
|
||||
return make_error<StringError>("no asm printer for target " + TripleName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// Set the DWARF version correctly on all classes that we use.
|
||||
MC->setDwarfVersion(Version);
|
||||
Asm->setDwarfVersion(Version);
|
||||
|
||||
StringPool.reset(new DwarfStringPool(Allocator, *Asm, StringRef()));
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
StringRef dwarfgen::Generator::generate() {
|
||||
// Offset from the first CU in the debug info section is 0 initially.
|
||||
unsigned SecOffset = 0;
|
||||
|
||||
// Iterate over each compile unit and set the size and offsets for each
|
||||
// DIE within each compile unit. All offsets are CU relative.
|
||||
for (auto &CU : CompileUnits) {
|
||||
// Set the absolute .debug_info offset for this compile unit.
|
||||
CU->setOffset(SecOffset);
|
||||
// The DIEs contain compile unit relative offsets.
|
||||
unsigned CUOffset = 11;
|
||||
CUOffset = CU->getUnitDIE().computeSizeAndOffsets(CUOffset);
|
||||
// Update our absolute .debug_info offset.
|
||||
SecOffset += CUOffset;
|
||||
CU->setLength(CUOffset - 4);
|
||||
}
|
||||
Abbreviations.Emit(Asm.get(), MOFI->getDwarfAbbrevSection());
|
||||
StringPool->emit(*Asm, MOFI->getDwarfStrSection());
|
||||
MS->SwitchSection(MOFI->getDwarfInfoSection());
|
||||
for (auto &CU : CompileUnits) {
|
||||
uint16_t Version = CU->getVersion();
|
||||
auto Length = CU->getLength();
|
||||
MC->setDwarfVersion(Version);
|
||||
assert(Length != -1U);
|
||||
Asm->EmitInt32(Length);
|
||||
Asm->EmitInt16(Version);
|
||||
Asm->EmitInt32(0);
|
||||
Asm->EmitInt8(CU->getAddressSize());
|
||||
Asm->emitDwarfDIE(*CU->getUnitDIE().Die);
|
||||
}
|
||||
|
||||
MS->Finish();
|
||||
if (FileBytes.empty())
|
||||
return StringRef();
|
||||
return StringRef(FileBytes.data(), FileBytes.size());
|
||||
}
|
||||
|
||||
bool dwarfgen::Generator::saveFile(StringRef Path) {
|
||||
if (FileBytes.empty())
|
||||
return false;
|
||||
std::error_code EC;
|
||||
raw_fd_ostream Strm(Path, EC, sys::fs::F_None);
|
||||
if (EC)
|
||||
return false;
|
||||
Strm.write(FileBytes.data(), FileBytes.size());
|
||||
Strm.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() {
|
||||
CompileUnits.push_back(std::unique_ptr<CompileUnit>(
|
||||
new CompileUnit(*this, Version, Asm->getPointerSize())));
|
||||
return *CompileUnits.back();
|
||||
}
|
231
lib/CodeGen/DwarfGenerator.h
Normal file
231
lib/CodeGen/DwarfGenerator.h
Normal file
@ -0,0 +1,231 @@
|
||||
//===--- lib/CodeGen/DwarfGenerator.h ---------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// A file that can generate DWARF debug info for unit tests.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFGENERATOR_H
|
||||
#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFGENERATOR_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class DIE;
|
||||
class DIEAbbrev;
|
||||
class DwarfStringPool;
|
||||
class MCAsmBackend;
|
||||
class MCAsmInfo;
|
||||
class MCCodeEmitter;
|
||||
class MCContext;
|
||||
struct MCDwarfLineTableParams;
|
||||
class MCInstrInfo;
|
||||
class MCObjectFileInfo;
|
||||
class MCRegisterInfo;
|
||||
class MCStreamer;
|
||||
class MCSubtargetInfo;
|
||||
class raw_fd_ostream;
|
||||
class TargetMachine;
|
||||
class Triple;
|
||||
|
||||
namespace dwarfgen {
|
||||
|
||||
class Generator;
|
||||
class CompileUnit;
|
||||
|
||||
/// A DWARF debug information entry class used to generate DWARF DIEs.
|
||||
///
|
||||
/// This class is used to quickly generate DWARF debug information by creating
|
||||
/// child DIEs or adding attributes to the current DIE. Instances of this class
|
||||
/// are created from the compile unit (dwarfgen::CompileUnit::getUnitDIE()) or
|
||||
/// by calling dwarfgen::DIE::addChild(...) and using the returned DIE object.
|
||||
class DIE {
|
||||
dwarfgen::CompileUnit *CU;
|
||||
llvm::DIE *Die;
|
||||
|
||||
protected:
|
||||
friend class Generator;
|
||||
friend class CompileUnit;
|
||||
|
||||
DIE(CompileUnit *U = nullptr, llvm::DIE *D = nullptr) : CU(U), Die(D) {}
|
||||
|
||||
/// Called with a compile/type unit relative offset prior to generating the
|
||||
/// DWARF debug info.
|
||||
///
|
||||
/// \param CUOffset the compile/type unit relative offset where the
|
||||
/// abbreviation code for this DIE will be encoded.
|
||||
unsigned computeSizeAndOffsets(unsigned CUOffset);
|
||||
|
||||
public:
|
||||
/// Add an attribute value that has no value.
|
||||
///
|
||||
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
|
||||
/// represents a user defined DWARF attribute.
|
||||
/// \param Form the dwarf::Form to use when encoding the attribute. This is
|
||||
/// only used with the DW_FORM_flag_present form encoding.
|
||||
void addAttribute(uint16_t Attr, dwarf::Form Form);
|
||||
|
||||
/// Add an attribute value to be encoded as a DIEInteger
|
||||
///
|
||||
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
|
||||
/// represents a user defined DWARF attribute.
|
||||
/// \param Form the dwarf::Form to use when encoding the attribute.
|
||||
/// \param U the unsigned integer to encode.
|
||||
void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U);
|
||||
|
||||
/// Add an attribute value to be encoded as a DIEString or DIEInlinedString.
|
||||
///
|
||||
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
|
||||
/// represents a user defined DWARF attribute.
|
||||
/// \param Form the dwarf::Form to use when encoding the attribute. The form
|
||||
/// must be one of DW_FORM_strp or DW_FORM_string.
|
||||
/// \param String the string to encode.
|
||||
void addAttribute(uint16_t Attr, dwarf::Form Form, StringRef String);
|
||||
|
||||
/// Add an attribute value to be encoded as a DIEEntry.
|
||||
///
|
||||
/// DIEEntry attributes refer to other llvm::DIE objects that have been
|
||||
/// created.
|
||||
///
|
||||
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
|
||||
/// represents a user defined DWARF attribute.
|
||||
/// \param Form the dwarf::Form to use when encoding the attribute. The form
|
||||
/// must be one of DW_FORM_strp or DW_FORM_string.
|
||||
/// \param RefDie the DIE that this attriute refers to.
|
||||
void addAttribute(uint16_t Attr, dwarf::Form Form, dwarfgen::DIE &RefDie);
|
||||
|
||||
/// Add an attribute value to be encoded as a DIEBlock.
|
||||
///
|
||||
/// DIEBlock attributes refers to binary data that is stored as the
|
||||
/// attribute's value.
|
||||
///
|
||||
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
|
||||
/// represents a user defined DWARF attribute.
|
||||
/// \param Form the dwarf::Form to use when encoding the attribute. The form
|
||||
/// must be one of DW_FORM_strp or DW_FORM_string.
|
||||
/// \param P a pointer to the data to store as the attribute value.
|
||||
/// \param S the size in bytes of the data pointed to by \param P.
|
||||
void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S);
|
||||
|
||||
/// Add a new child to this DIE object.
|
||||
///
|
||||
/// \param Tag the dwarf::Tag to assing to the llvm::DIE object.
|
||||
/// \returns the newly created DIE object that is now a child owned by this
|
||||
/// object.
|
||||
dwarfgen::DIE addChild(dwarf::Tag Tag);
|
||||
};
|
||||
|
||||
/// A DWARF compile unit used to generate DWARF compile/type units.
|
||||
///
|
||||
/// Instances of these classes are created by instances of the Generator
|
||||
/// class. All information required to generate a DWARF compile unit is
|
||||
/// contained inside this class.
|
||||
class CompileUnit {
|
||||
Generator &DG;
|
||||
DIEUnit DU;
|
||||
|
||||
public:
|
||||
CompileUnit(Generator &D, uint16_t V, uint8_t A)
|
||||
: DG(D), DU(V, A, dwarf::DW_TAG_compile_unit) {}
|
||||
DIE getUnitDIE();
|
||||
Generator &getGenerator() { return DG; }
|
||||
uint64_t getOffset() const { return DU.getDebugSectionOffset(); }
|
||||
uint64_t getLength() const { return DU.getLength(); }
|
||||
uint16_t getVersion() const { return DU.getDwarfVersion(); }
|
||||
uint16_t getAddressSize() const { return DU.getAddressSize(); }
|
||||
void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); }
|
||||
void setLength(uint64_t Length) { DU.setLength(Length); }
|
||||
};
|
||||
|
||||
/// A DWARF generator.
|
||||
///
|
||||
/// Generate DWARF for unit tests by creating any instance of this class and
|
||||
/// calling Generator::addCompileUnit(), and then getting the dwarfgen::DIE from
|
||||
/// the returned compile unit and adding attributes and children to each DIE.
|
||||
class Generator {
|
||||
std::unique_ptr<MCRegisterInfo> MRI;
|
||||
std::unique_ptr<MCAsmInfo> MAI;
|
||||
std::unique_ptr<MCObjectFileInfo> MOFI;
|
||||
std::unique_ptr<MCContext> MC;
|
||||
MCAsmBackend *MAB; // Owned by MCStreamer
|
||||
std::unique_ptr<MCInstrInfo> MII;
|
||||
std::unique_ptr<MCSubtargetInfo> MSTI;
|
||||
MCCodeEmitter *MCE; // Owned by MCStreamer
|
||||
MCStreamer *MS; // Owned by AsmPrinter
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
std::unique_ptr<AsmPrinter> Asm;
|
||||
std::unique_ptr<DwarfStringPool> StringPool;
|
||||
std::vector<std::unique_ptr<CompileUnit>> CompileUnits;
|
||||
BumpPtrAllocator Allocator;
|
||||
DIEAbbrevSet Abbreviations;
|
||||
|
||||
SmallString<4096> FileBytes;
|
||||
/// The stream we use to generate the DWARF into as an ELF file.
|
||||
std::unique_ptr<raw_svector_ostream> Stream;
|
||||
/// The DWARF version to generate.
|
||||
uint16_t Version;
|
||||
|
||||
/// Private constructor, call Generator::Create(...) to get a DWARF generator
|
||||
/// expected.
|
||||
Generator();
|
||||
|
||||
/// Create the streamer and setup the output buffer.
|
||||
llvm::Error init(Triple TheTriple, uint16_t DwarfVersion);
|
||||
|
||||
public:
|
||||
/// Create a DWARF generator or get an appropriate error.
|
||||
///
|
||||
/// \param TheTriple the triple to use when creating any required support
|
||||
/// classes needed to emit the DWARF.
|
||||
/// \param DwarfVersion the version of DWARF to emit.
|
||||
///
|
||||
/// \returns a llvm::Expected that either contains a unique_ptr to a Generator
|
||||
/// or a llvm::Error.
|
||||
static llvm::Expected<std::unique_ptr<Generator>>
|
||||
create(Triple TheTriple, uint16_t DwarfVersion);
|
||||
|
||||
~Generator();
|
||||
|
||||
/// Generate all DWARF sections and return a memory buffer that
|
||||
/// contains an ELF file that contains the DWARF.
|
||||
StringRef generate();
|
||||
|
||||
/// Add a compile unit to be generated.
|
||||
///
|
||||
/// \returns a dwarfgen::CompileUnit that can be used to retrieve the compile
|
||||
/// unit dwarfgen::DIE that can be used to add attributes and add child DIE
|
||||
/// objedts to.
|
||||
dwarfgen::CompileUnit &addCompileUnit();
|
||||
|
||||
BumpPtrAllocator &getAllocator() { return Allocator; }
|
||||
AsmPrinter *getAsmPrinter() const { return Asm.get(); }
|
||||
DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
|
||||
DwarfStringPool &getStringPool() { return *StringPool; }
|
||||
|
||||
/// Save the generated DWARF file to disk.
|
||||
///
|
||||
/// \param Path the path to save the ELF file to.
|
||||
bool saveFile(StringRef Path);
|
||||
};
|
||||
|
||||
} // end namespace dwarfgen
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFGENERATOR_H
|
@ -269,6 +269,15 @@ uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress(
|
||||
return Result.hasValue() ? Result.getValue() : FailValue;
|
||||
}
|
||||
|
||||
int64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSignedConstant(
|
||||
const DWARFUnit *U, dwarf::Attribute Attr, int64_t FailValue) const {
|
||||
DWARFFormValue FormValue;
|
||||
if (!getAttributeValue(U, Attr, FormValue))
|
||||
return FailValue;
|
||||
Optional<int64_t> Result = FormValue.getAsSignedConstant();
|
||||
return Result.hasValue() ? Result.getValue() : FailValue;
|
||||
}
|
||||
|
||||
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsignedConstant(
|
||||
const DWARFUnit *U, dwarf::Attribute Attr,
|
||||
uint64_t FailValue) const {
|
||||
|
@ -1,8 +1,16 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
DebugInfoDWARF
|
||||
CodeGen
|
||||
Core
|
||||
MC
|
||||
MIRParser
|
||||
Support
|
||||
Target
|
||||
)
|
||||
|
||||
set(DebugInfoSources
|
||||
DWARFDebugInfoTest.cpp
|
||||
DWARFFormValueTest.cpp
|
||||
)
|
||||
|
||||
|
790
unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
Normal file
790
unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
Normal file
@ -0,0 +1,790 @@
|
||||
//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "../lib/CodeGen/DwarfGenerator.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <climits>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace dwarf;
|
||||
|
||||
namespace {
|
||||
|
||||
void initLLVMIfNeeded() {
|
||||
static bool gInitialized = false;
|
||||
if (!gInitialized) {
|
||||
gInitialized = true;
|
||||
InitializeAllTargets();
|
||||
InitializeAllTargetMCs();
|
||||
InitializeAllAsmPrinters();
|
||||
InitializeAllAsmParsers();
|
||||
}
|
||||
}
|
||||
|
||||
Triple getHostTripleForAddrSize(uint8_t AddrSize) {
|
||||
Triple PT(Triple::normalize(LLVM_HOST_TRIPLE));
|
||||
|
||||
if (AddrSize == 8 && PT.isArch32Bit())
|
||||
return PT.get64BitArchVariant();
|
||||
if (AddrSize == 4 && PT.isArch64Bit())
|
||||
return PT.get32BitArchVariant();
|
||||
return PT;
|
||||
}
|
||||
|
||||
/// Take any llvm::Expected and check and handle any errors.
|
||||
///
|
||||
/// \param Expected a llvm::Excepted instance to check.
|
||||
/// \returns true if there were errors, false otherwise.
|
||||
template <typename T>
|
||||
static bool HandleExpectedError(T &Expected) {
|
||||
if (!Expected)
|
||||
return false;
|
||||
std::string ErrorMsg;
|
||||
handleAllErrors(Expected.takeError(), [&](const llvm::ErrorInfoBase &EI) {
|
||||
ErrorMsg = EI.message();
|
||||
});
|
||||
::testing::AssertionFailure() << "error: " << ErrorMsg;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <uint16_t Version, class AddrType, class RefAddrType>
|
||||
void TestAllForms() {
|
||||
// Test that we can decode all DW_FORM values correctly.
|
||||
|
||||
const uint8_t AddrSize = sizeof(AddrType);
|
||||
const AddrType AddrValue = (AddrType)0x0123456789abcdefULL;
|
||||
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 int64_t SData = INT64_MIN;
|
||||
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";
|
||||
initLLVMIfNeeded();
|
||||
Triple Triple = getHostTripleForAddrSize(AddrSize);
|
||||
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
|
||||
if (HandleExpectedError(ExpectedDG))
|
||||
return;
|
||||
dwarfgen::Generator *DG = ExpectedDG.get().get();
|
||||
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
|
||||
dwarfgen::DIE CUDie = CU.getUnitDIE();
|
||||
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);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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_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++);
|
||||
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++);
|
||||
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);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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++);
|
||||
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);
|
||||
DWARFContextInMemory DwarfContext(*Obj.get());
|
||||
uint32_t NumCUs = DwarfContext.getNumCompileUnits();
|
||||
EXPECT_EQ(NumCUs, 1u);
|
||||
DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
|
||||
auto DiePtr = U->getUnitDIE(false);
|
||||
EXPECT_TRUE(DiePtr != nullptr);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test address forms
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsAddress(U, Attr_DW_FORM_addr, 0),
|
||||
AddrValue);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test block forms
|
||||
//----------------------------------------------------------------------
|
||||
DWARFFormValue FormValue;
|
||||
ArrayRef<uint8_t> ExtractedBlockData;
|
||||
Optional<ArrayRef<uint8_t>> BlockDataOpt;
|
||||
|
||||
EXPECT_TRUE(DiePtr->getAttributeValue(U, Attr_DW_FORM_block, FormValue));
|
||||
BlockDataOpt = FormValue.getAsBlock();
|
||||
EXPECT_TRUE(BlockDataOpt.hasValue());
|
||||
ExtractedBlockData = BlockDataOpt.getValue();
|
||||
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
|
||||
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
|
||||
|
||||
EXPECT_TRUE(DiePtr->getAttributeValue(U, Attr_DW_FORM_block1, FormValue));
|
||||
BlockDataOpt = FormValue.getAsBlock();
|
||||
EXPECT_TRUE(BlockDataOpt.hasValue());
|
||||
ExtractedBlockData = BlockDataOpt.getValue();
|
||||
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
|
||||
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
|
||||
|
||||
EXPECT_TRUE(DiePtr->getAttributeValue(U, Attr_DW_FORM_block2, FormValue));
|
||||
BlockDataOpt = FormValue.getAsBlock();
|
||||
EXPECT_TRUE(BlockDataOpt.hasValue());
|
||||
ExtractedBlockData = BlockDataOpt.getValue();
|
||||
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
|
||||
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
|
||||
|
||||
EXPECT_TRUE(DiePtr->getAttributeValue(U, Attr_DW_FORM_block4, FormValue));
|
||||
BlockDataOpt = FormValue.getAsBlock();
|
||||
EXPECT_TRUE(BlockDataOpt.hasValue());
|
||||
ExtractedBlockData = BlockDataOpt.getValue();
|
||||
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
|
||||
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test data forms
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(
|
||||
DiePtr->getAttributeValueAsUnsignedConstant(U, Attr_DW_FORM_data1, 0),
|
||||
Data1);
|
||||
EXPECT_EQ(
|
||||
DiePtr->getAttributeValueAsUnsignedConstant(U, Attr_DW_FORM_data2, 0),
|
||||
Data2);
|
||||
EXPECT_EQ(
|
||||
DiePtr->getAttributeValueAsUnsignedConstant(U, Attr_DW_FORM_data4, 0),
|
||||
Data4);
|
||||
EXPECT_EQ(
|
||||
DiePtr->getAttributeValueAsUnsignedConstant(U, Attr_DW_FORM_data8, 0),
|
||||
Data8);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test string forms
|
||||
//----------------------------------------------------------------------
|
||||
const char *ExtractedStringValue =
|
||||
DiePtr->getAttributeValueAsString(U, Attr_DW_FORM_string, nullptr);
|
||||
EXPECT_TRUE(ExtractedStringValue != nullptr);
|
||||
EXPECT_TRUE(strcmp(StringValue, ExtractedStringValue) == 0);
|
||||
|
||||
const char *ExtractedStrpValue =
|
||||
DiePtr->getAttributeValueAsString(U, Attr_DW_FORM_strp, nullptr);
|
||||
EXPECT_TRUE(ExtractedStrpValue != nullptr);
|
||||
EXPECT_TRUE(strcmp(StrpValue, ExtractedStrpValue) == 0);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test reference forms
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_ref_addr, 0),
|
||||
RefAddr);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_ref1, 0),
|
||||
Data1);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_ref2, 0),
|
||||
Data2);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_ref4, 0),
|
||||
Data4);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_ref8, 0),
|
||||
Data8);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_ref_sig8, 0),
|
||||
Data8_2);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_ref_udata, 0),
|
||||
UData[0]);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test flag forms
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsUnsignedConstant(
|
||||
U, Attr_DW_FORM_flag_true, 0ULL),
|
||||
1ULL);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsUnsignedConstant(
|
||||
U, Attr_DW_FORM_flag_false, 1ULL),
|
||||
0ULL);
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsUnsignedConstant(
|
||||
U, Attr_DW_FORM_flag_present, 0ULL),
|
||||
1ULL);
|
||||
|
||||
// TODO: test Attr_DW_FORM_implicit_const extraction
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test SLEB128 based forms
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsSignedConstant(U, Attr_DW_FORM_sdata, 0),
|
||||
SData);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test ULEB128 based forms
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(
|
||||
DiePtr->getAttributeValueAsUnsignedConstant(U, Attr_DW_FORM_udata, 0),
|
||||
UData[0]);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Test DWARF32/DWARF64 forms
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(
|
||||
DiePtr->getAttributeValueAsReference(U, Attr_DW_FORM_GNU_ref_alt, 0),
|
||||
Dwarf32Values[0]);
|
||||
EXPECT_EQ(
|
||||
DiePtr->getAttributeValueAsSectionOffset(U, Attr_DW_FORM_sec_offset, 0),
|
||||
Dwarf32Values[1]);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Add an address at the end to make sure we can decode this value
|
||||
//----------------------------------------------------------------------
|
||||
EXPECT_EQ(DiePtr->getAttributeValueAsAddress(U, Attr_Last, 0), AddrValue);
|
||||
}
|
||||
|
||||
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>();
|
||||
}
|
||||
|
||||
template <uint16_t Version, class AddrType> void TestChildren() {
|
||||
// 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.
|
||||
|
||||
const uint8_t AddrSize = sizeof(AddrType);
|
||||
initLLVMIfNeeded();
|
||||
Triple Triple = getHostTripleForAddrSize(AddrSize);
|
||||
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
|
||||
if (HandleExpectedError(ExpectedDG))
|
||||
return;
|
||||
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);
|
||||
DWARFContextInMemory DwarfContext(*Obj.get());
|
||||
|
||||
// Verify the number of compile units is correct.
|
||||
uint32_t NumCUs = DwarfContext.getNumCompileUnits();
|
||||
EXPECT_EQ(NumCUs, 1u);
|
||||
DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
|
||||
|
||||
// Get the compile unit DIE is valid.
|
||||
auto DiePtr = U->getUnitDIE(false);
|
||||
EXPECT_TRUE(DiePtr != nullptr);
|
||||
// DiePtr->dump(llvm::outs(), U, UINT32_MAX);
|
||||
|
||||
// Verify the first child of the compile unit DIE is our subprogram.
|
||||
auto SubprogramDiePtr = DiePtr->getFirstChild();
|
||||
EXPECT_TRUE(SubprogramDiePtr != nullptr);
|
||||
EXPECT_EQ(SubprogramDiePtr->getTag(), DW_TAG_subprogram);
|
||||
|
||||
// Verify the first child of the subprogram is our formal parameter.
|
||||
auto ArgcDiePtr = SubprogramDiePtr->getFirstChild();
|
||||
EXPECT_TRUE(ArgcDiePtr != nullptr);
|
||||
EXPECT_EQ(ArgcDiePtr->getTag(), DW_TAG_formal_parameter);
|
||||
|
||||
// Verify our formal parameter has a NULL tag sibling.
|
||||
auto NullDiePtr = ArgcDiePtr->getSibling();
|
||||
EXPECT_TRUE(NullDiePtr != nullptr);
|
||||
if (NullDiePtr) {
|
||||
EXPECT_EQ(NullDiePtr->getTag(), DW_TAG_null);
|
||||
EXPECT_TRUE(NullDiePtr->getSibling() == nullptr);
|
||||
EXPECT_TRUE(NullDiePtr->getFirstChild() == nullptr);
|
||||
}
|
||||
|
||||
// Verify the sibling of our subprogram is our integer base type.
|
||||
auto IntDiePtr = SubprogramDiePtr->getSibling();
|
||||
EXPECT_TRUE(IntDiePtr != nullptr);
|
||||
EXPECT_EQ(IntDiePtr->getTag(), DW_TAG_base_type);
|
||||
|
||||
// Verify the sibling of our subprogram is our integer base is a NULL tag.
|
||||
NullDiePtr = IntDiePtr->getSibling();
|
||||
EXPECT_TRUE(NullDiePtr != nullptr);
|
||||
if (NullDiePtr) {
|
||||
EXPECT_EQ(NullDiePtr->getTag(), DW_TAG_null);
|
||||
EXPECT_TRUE(NullDiePtr->getSibling() == nullptr);
|
||||
EXPECT_TRUE(NullDiePtr->getFirstChild() == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
// Test that we can decode DW_FORM_refXXX values correctly in DWARF.
|
||||
|
||||
const uint8_t AddrSize = sizeof(AddrType);
|
||||
initLLVMIfNeeded();
|
||||
Triple Triple = getHostTripleForAddrSize(AddrSize);
|
||||
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
|
||||
if (HandleExpectedError(ExpectedDG))
|
||||
return;
|
||||
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);
|
||||
DWARFContextInMemory DwarfContext(*Obj.get());
|
||||
|
||||
// Verify the number of compile units is correct.
|
||||
uint32_t NumCUs = DwarfContext.getNumCompileUnits();
|
||||
EXPECT_EQ(NumCUs, 2u);
|
||||
DWARFCompileUnit *U1 = DwarfContext.getCompileUnitAtIndex(0);
|
||||
DWARFCompileUnit *U2 = DwarfContext.getCompileUnitAtIndex(1);
|
||||
|
||||
// Get the compile unit DIE is valid.
|
||||
auto Unit1DiePtr = U1->getUnitDIE(false);
|
||||
EXPECT_TRUE(Unit1DiePtr != nullptr);
|
||||
// Unit1DiePtr->dump(llvm::outs(), U1, UINT32_MAX);
|
||||
|
||||
auto Unit2DiePtr = U2->getUnitDIE(false);
|
||||
EXPECT_TRUE(Unit2DiePtr != nullptr);
|
||||
// Unit2DiePtr->dump(llvm::outs(), U2, UINT32_MAX);
|
||||
|
||||
// Verify the first child of the compile unit 1 DIE is our int base type.
|
||||
auto CU1TypeDiePtr = Unit1DiePtr->getFirstChild();
|
||||
EXPECT_TRUE(CU1TypeDiePtr != nullptr);
|
||||
EXPECT_EQ(CU1TypeDiePtr->getTag(), DW_TAG_base_type);
|
||||
EXPECT_EQ(
|
||||
CU1TypeDiePtr->getAttributeValueAsUnsignedConstant(U1, DW_AT_encoding, 0),
|
||||
DW_ATE_signed);
|
||||
|
||||
// Verify the first child of the compile unit 2 DIE is our float base type.
|
||||
auto CU2TypeDiePtr = Unit2DiePtr->getFirstChild();
|
||||
EXPECT_TRUE(CU2TypeDiePtr != nullptr);
|
||||
EXPECT_EQ(CU2TypeDiePtr->getTag(), DW_TAG_base_type);
|
||||
EXPECT_EQ(
|
||||
CU2TypeDiePtr->getAttributeValueAsUnsignedConstant(U2, DW_AT_encoding, 0),
|
||||
DW_ATE_float);
|
||||
|
||||
// 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 CU1Ref1DiePtr = CU1TypeDiePtr->getSibling();
|
||||
EXPECT_TRUE(CU1Ref1DiePtr != nullptr);
|
||||
EXPECT_EQ(CU1Ref1DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU1Ref1DiePtr->getAttributeValueAsReference(U1, DW_AT_type, -1ULL),
|
||||
CU1TypeDiePtr->getOffset());
|
||||
// Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU1.
|
||||
auto CU1Ref2DiePtr = CU1Ref1DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU1Ref2DiePtr != nullptr);
|
||||
EXPECT_EQ(CU1Ref2DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU1Ref2DiePtr->getAttributeValueAsReference(U1, DW_AT_type, -1ULL),
|
||||
CU1TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU1.
|
||||
auto CU1Ref4DiePtr = CU1Ref2DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU1Ref4DiePtr != nullptr);
|
||||
EXPECT_EQ(CU1Ref4DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU1Ref4DiePtr->getAttributeValueAsReference(U1, DW_AT_type, -1ULL),
|
||||
CU1TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU1.
|
||||
auto CU1Ref8DiePtr = CU1Ref4DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU1Ref8DiePtr != nullptr);
|
||||
EXPECT_EQ(CU1Ref8DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU1Ref8DiePtr->getAttributeValueAsReference(U1, DW_AT_type, -1ULL),
|
||||
CU1TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU1.
|
||||
auto CU1RefAddrDiePtr = CU1Ref8DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU1RefAddrDiePtr != nullptr);
|
||||
EXPECT_EQ(CU1RefAddrDiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(
|
||||
CU1RefAddrDiePtr->getAttributeValueAsReference(U1, DW_AT_type, -1ULL),
|
||||
CU1TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its
|
||||
// DW_AT_type points to our base type DIE.
|
||||
auto CU1ToCU2RefAddrDiePtr = CU1RefAddrDiePtr->getSibling();
|
||||
EXPECT_TRUE(CU1ToCU2RefAddrDiePtr != nullptr);
|
||||
EXPECT_EQ(CU1ToCU2RefAddrDiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU1ToCU2RefAddrDiePtr->getAttributeValueAsReference(U1, DW_AT_type,
|
||||
-1ULL),
|
||||
CU2TypeDiePtr->getOffset());
|
||||
|
||||
// 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 CU2Ref1DiePtr = CU2TypeDiePtr->getSibling();
|
||||
EXPECT_TRUE(CU2Ref1DiePtr != nullptr);
|
||||
EXPECT_EQ(CU2Ref1DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU2Ref1DiePtr->getAttributeValueAsReference(U2, DW_AT_type, -1ULL),
|
||||
CU2TypeDiePtr->getOffset());
|
||||
// Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU2.
|
||||
auto CU2Ref2DiePtr = CU2Ref1DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU2Ref2DiePtr != nullptr);
|
||||
EXPECT_EQ(CU2Ref2DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU2Ref2DiePtr->getAttributeValueAsReference(U2, DW_AT_type, -1ULL),
|
||||
CU2TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU2.
|
||||
auto CU2Ref4DiePtr = CU2Ref2DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU2Ref4DiePtr != nullptr);
|
||||
EXPECT_EQ(CU2Ref4DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU2Ref4DiePtr->getAttributeValueAsReference(U2, DW_AT_type, -1ULL),
|
||||
CU2TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU2.
|
||||
auto CU2Ref8DiePtr = CU2Ref4DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU2Ref8DiePtr != nullptr);
|
||||
EXPECT_EQ(CU2Ref8DiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU2Ref8DiePtr->getAttributeValueAsReference(U2, DW_AT_type, -1ULL),
|
||||
CU2TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our
|
||||
// base type DIE in CU2.
|
||||
auto CU2RefAddrDiePtr = CU2Ref8DiePtr->getSibling();
|
||||
EXPECT_TRUE(CU2RefAddrDiePtr != nullptr);
|
||||
EXPECT_EQ(CU2RefAddrDiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(
|
||||
CU2RefAddrDiePtr->getAttributeValueAsReference(U2, DW_AT_type, -1ULL),
|
||||
CU2TypeDiePtr->getOffset());
|
||||
|
||||
// Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its
|
||||
// DW_AT_type points to our base type DIE.
|
||||
auto CU2ToCU1RefAddrDiePtr = CU2RefAddrDiePtr->getSibling();
|
||||
EXPECT_TRUE(CU2ToCU1RefAddrDiePtr != nullptr);
|
||||
EXPECT_EQ(CU2ToCU1RefAddrDiePtr->getTag(), DW_TAG_variable);
|
||||
EXPECT_EQ(CU2ToCU1RefAddrDiePtr->getAttributeValueAsReference(U2, DW_AT_type,
|
||||
-1ULL),
|
||||
CU1TypeDiePtr->getOffset());
|
||||
}
|
||||
|
||||
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>();
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
Loading…
Reference in New Issue
Block a user