[llvm] r289010 - Make a DWARF generator so we can unit test DWARF APIs with gtest.
David Blaikie via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 12 14:19:06 PST 2016
On Wed, Dec 7, 2016 at 5:14 PM Greg Clayton via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> Author: gclayton
> Date: Wed Dec 7 19:03:48 2016
> New Revision: 289010
>
> URL: http://llvm.org/viewvc/llvm-project?rev=289010&view=rev
> Log:
> 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
>
> Added:
> llvm/trunk/lib/CodeGen/DwarfGenerator.cpp
> llvm/trunk/lib/CodeGen/DwarfGenerator.h
> llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
> Modified:
> llvm/trunk/include/llvm/CodeGen/DIE.h
> llvm/trunk/include/llvm/CodeGen/DIEValue.def
> llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
> llvm/trunk/include/llvm/MC/MCContext.h
> llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp
> llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp
> llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp
> llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h
> llvm/trunk/lib/CodeGen/CMakeLists.txt
> llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
> llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt
>
> Modified: llvm/trunk/include/llvm/CodeGen/DIE.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/DIE.h?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/DIE.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/DIE.h Wed Dec 7 19:03:48 2016
> @@ -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 {
>
> @@ -112,6 +113,37 @@ public:
> };
>
>
> //===--------------------------------------------------------------------===//
> +/// 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.
> ///
> class DIEInteger {
> @@ -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;
>
> @@ -219,6 +252,27 @@ public:
> };
>
>
> //===--------------------------------------------------------------------===//
> +/// 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
> /// (ie. types.)
> @@ -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, publi
> 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.
> ///
>
> Modified: llvm/trunk/include/llvm/CodeGen/DIEValue.def
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/DIEValue.def?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/DIEValue.def (original)
> +++ llvm/trunk/include/llvm/CodeGen/DIEValue.def Wed Dec 7 19:03:48 2016
> @@ -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
>
> Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
> (original)
> +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h Wed Dec
> 7 19:03:48 2016
> @@ -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;
>
> Modified: llvm/trunk/include/llvm/MC/MCContext.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCContext.h?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/MC/MCContext.h (original)
> +++ llvm/trunk/include/llvm/MC/MCContext.h Wed Dec 7 19:03:48 2016
> @@ -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; }
>
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp Wed Dec 7 19:03:48 2016
> @@ -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 AsmPri
> 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");
> }
> }
> @@ -452,6 +587,29 @@ void DIEString::print(raw_ostream &O) co
> }
>
>
> //===----------------------------------------------------------------------===//
> +// 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);
>
Use AsmPrinter::OutStreamer::EmitBytes here,perhaps? That's what
DwarfStringPool does? (I Think the AsmPrinter Emit* functions are just
helpers - you don't have to use them if they aern't helping)
> + 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) co
> ///
> 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
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp Wed Dec 7 19:03:48 2016
> @@ -330,6 +330,12 @@ void DIEHash::hashAttribute(const DIEVal
> 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:
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp Wed Dec 7 19:03:48
> 2016
> @@ -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::computeSizeAndOffset
> // 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) {
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h Wed Dec 7 19:03:48 2016
> @@ -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);
>
>
> Modified: llvm/trunk/lib/CodeGen/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/CMakeLists.txt (original)
> +++ llvm/trunk/lib/CodeGen/CMakeLists.txt Wed Dec 7 19:03:48 2016
> @@ -17,6 +17,7 @@ add_llvm_library(LLVMCodeGen
> DetectDeadLanes.cpp
> DFAPacketizer.cpp
> DwarfEHPrepare.cpp
> + DwarfGenerator.cpp
> EarlyIfConversion.cpp
> EdgeBundles.cpp
> ExecutionDepsFix.cpp
>
> Added: llvm/trunk/lib/CodeGen/DwarfGenerator.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/DwarfGenerator.cpp?rev=289010&view=auto
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/DwarfGenerator.cpp (added)
> +++ llvm/trunk/lib/CodeGen/DwarfGenerator.cpp Wed Dec 7 19:03:48 2016
> @@ -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();
> +}
>
> Added: llvm/trunk/lib/CodeGen/DwarfGenerator.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/DwarfGenerator.h?rev=289010&view=auto
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/DwarfGenerator.h (added)
> +++ llvm/trunk/lib/CodeGen/DwarfGenerator.h Wed Dec 7 19:03:48 2016
> @@ -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
>
> Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp Wed Dec 7
> 19:03:48 2016
> @@ -269,6 +269,15 @@ uint64_t DWARFDebugInfoEntryMinimal::get
> 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 {
>
> Modified: llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt?rev=289010&r1=289009&r2=289010&view=diff
>
> ==============================================================================
> --- llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt (original)
> +++ llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt Wed Dec 7
> 19:03:48 2016
> @@ -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
> )
>
>
> Added: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp?rev=289010&view=auto
>
> ==============================================================================
> --- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp (added)
> +++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp Wed Dec 7
> 19:03:48 2016
> @@ -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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20161212/909fd2d6/attachment-0001.html>
More information about the llvm-commits
mailing list