Skip to content

Commit

Permalink
Make a DWARF generator so we can unit test DWARF APIs with gtest.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Greg Clayton committed Dec 8, 2016
1 parent 7fb5e34 commit 3462a42
Show file tree
Hide file tree
Showing 14 changed files with 1,646 additions and 151 deletions.
100 changes: 80 additions & 20 deletions llvm/include/llvm/CodeGen/DIE.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -31,6 +31,7 @@
#include <iterator>
#include <new>
#include <type_traits>
#include <vector>

namespace llvm {

Expand Down Expand Up @@ -111,6 +112,37 @@ class DIEAbbrev : public FoldingSetNode {
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.
///
Expand Down Expand Up @@ -201,8 +233,9 @@ class DIEDelta {
};

//===--------------------------------------------------------------------===//
/// 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;

Expand All @@ -218,6 +251,27 @@ class DIEString {
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
Expand All @@ -233,14 +287,8 @@ class DIEEntry {

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;
};
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -664,6 +705,25 @@ class DIE : IntrusiveBackListNode, public DIEValueList {
/// 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.
///
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/DIEValue.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ class DWARFDebugInfoEntryMinimal {
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;
Expand Down
6 changes: 5 additions & 1 deletion llvm/include/llvm/MC/MCContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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; }

Expand Down
Loading

0 comments on commit 3462a42

Please sign in to comment.