Index: llvm/trunk/include/llvm/CodeGen/DIE.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/DIE.h +++ llvm/trunk/include/llvm/CodeGen/DIE.h @@ -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 #include #include +#include namespace llvm { @@ -112,6 +113,37 @@ }; //===--------------------------------------------------------------------===// +/// 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 AbbreviationsSet; + /// A list of all the unique abbreviations in use. + std::vector 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 @@ }; //===--------------------------------------------------------------------===// -/// 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 @@ }; //===--------------------------------------------------------------------===// +/// 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 @@ 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 @@ friend class IntrusiveBackList; 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 Children; @@ -664,6 +705,25 @@ /// 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. /// Index: llvm/trunk/include/llvm/CodeGen/DIEValue.def =================================================================== --- llvm/trunk/include/llvm/CodeGen/DIEValue.def +++ llvm/trunk/include/llvm/CodeGen/DIEValue.def @@ -40,6 +40,7 @@ HANDLE_DIEVALUE_LARGE(Block) HANDLE_DIEVALUE_LARGE(Loc) HANDLE_DIEVALUE_SMALL(LocList) +HANDLE_DIEVALUE_LARGE(InlineString) #undef HANDLE_DIEVALUE #undef HANDLE_DIEVALUE_SMALL Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h @@ -105,6 +105,10 @@ 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; Index: llvm/trunk/include/llvm/MC/MCContext.h =================================================================== --- llvm/trunk/include/llvm/MC/MCContext.h +++ llvm/trunk/include/llvm/MC/MCContext.h @@ -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 #include @@ -526,7 +527,10 @@ 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; } Index: llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp @@ -108,6 +108,51 @@ 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(); } @@ -198,6 +243,45 @@ 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 @@ /// 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 @@ 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 @@ } //===----------------------------------------------------------------------===// +// 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 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 Index: llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -330,6 +330,12 @@ 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: Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -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 -#include namespace llvm { class AsmPrinter; @@ -41,10 +41,7 @@ BumpPtrAllocator AbbrevAllocator; // Used to uniquely define abbreviations. - FoldingSet AbbreviationsSet; - - // A list of all the unique abbreviations in use. - std::vector Abbreviations; + DIEAbbrevSet Abbrevs; // A pointer to all units in the section. SmallVector, 1> CUs; @@ -65,8 +62,6 @@ public: DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA); - ~DwarfFile(); - const SmallVectorImpl> &getUnits() { return CUs; } @@ -81,12 +76,6 @@ /// \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 U); Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -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 U) { CUs.push_back(std::move(U)); @@ -98,44 +68,10 @@ // 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) { Index: llvm/trunk/lib/CodeGen/CMakeLists.txt =================================================================== --- llvm/trunk/lib/CodeGen/CMakeLists.txt +++ llvm/trunk/lib/CodeGen/CMakeLists.txt @@ -17,6 +17,7 @@ DetectDeadLanes.cpp DFAPacketizer.cpp DwarfEHPrepare.cpp + DwarfGenerator.cpp EarlyIfConversion.cpp EdgeBundles.cpp ExecutionDepsFix.cpp Index: llvm/trunk/lib/CodeGen/DwarfGenerator.h =================================================================== --- llvm/trunk/lib/CodeGen/DwarfGenerator.h +++ llvm/trunk/lib/CodeGen/DwarfGenerator.h @@ -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 +#include +#include +#include + +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 MRI; + std::unique_ptr MAI; + std::unique_ptr MOFI; + std::unique_ptr MC; + MCAsmBackend *MAB; // Owned by MCStreamer + std::unique_ptr MII; + std::unique_ptr MSTI; + MCCodeEmitter *MCE; // Owned by MCStreamer + MCStreamer *MS; // Owned by AsmPrinter + std::unique_ptr TM; + std::unique_ptr Asm; + std::unique_ptr StringPool; + std::vector> CompileUnits; + BumpPtrAllocator Allocator; + DIEAbbrevSet Abbreviations; + + SmallString<4096> FileBytes; + /// The stream we use to generate the DWARF into as an ELF file. + std::unique_ptr 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> + 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 Index: llvm/trunk/lib/CodeGen/DwarfGenerator.cpp =================================================================== --- llvm/trunk/lib/CodeGen/DwarfGenerator.cpp +++ llvm/trunk/lib/CodeGen/DwarfGenerator.cpp @@ -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(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(A), Form, + new (DG.getAllocator()) DIEInlineString(String)); + } else { + Die->addValue( + DG.getAllocator(), static_cast(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(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(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(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> +dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) { + std::unique_ptr GenUP(new dwarfgen::Generator()); + llvm::Error error = GenUP->init(TheTriple, DwarfVersion); + if (error) + return Expected>(std::move(error)); + return Expected>(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(ErrorStr, inconvertibleErrorCode()); + + TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + MRI.reset(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return make_error(Twine("no register info for target ") + + TripleName, + inconvertibleErrorCode()); + + MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); + if (!MAI) + return make_error("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("no asm backend for target " + TripleName, + inconvertibleErrorCode()); + + MII.reset(TheTarget->createMCInstrInfo()); + if (!MII) + return make_error("no instr info info for target " + + TripleName, + inconvertibleErrorCode()); + + MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return make_error("no subtarget info for target " + TripleName, + inconvertibleErrorCode()); + + MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC); + if (!MCE) + return make_error("no code emitter for target " + TripleName, + inconvertibleErrorCode()); + + Stream = make_unique(FileBytes); + + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + MS = TheTarget->createMCObjectStreamer( + TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false); + if (!MS) + return make_error("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("no target machine for target " + TripleName, + inconvertibleErrorCode()); + + Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr(MS))); + if (!Asm) + return make_error("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( + new CompileUnit(*this, Version, Asm->getPointerSize()))); + return *CompileUnits.back(); +} Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -269,6 +269,15 @@ 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 Result = FormValue.getAsSignedConstant(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsignedConstant( const DWARFUnit *U, dwarf::Attribute Attr, uint64_t FailValue) const { Index: llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt +++ llvm/trunk/unittests/DebugInfo/DWARF/CMakeLists.txt @@ -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 ) Index: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -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 + +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 +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 +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(Attr++); + CUDie.addAttribute(Attr_DW_FORM_addr, DW_FORM_addr, AddrValue); + + //---------------------------------------------------------------------- + // Test block forms + //---------------------------------------------------------------------- + const auto Attr_DW_FORM_block = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_block, DW_FORM_block, BlockData, BlockSize); + + const auto Attr_DW_FORM_block1 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_block1, DW_FORM_block1, BlockData, BlockSize); + + const auto Attr_DW_FORM_block2 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_block2, DW_FORM_block2, BlockData, BlockSize); + + const auto Attr_DW_FORM_block4 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_block4, DW_FORM_block4, BlockData, BlockSize); + + //---------------------------------------------------------------------- + // Test data forms + //---------------------------------------------------------------------- + const auto Attr_DW_FORM_data1 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_data1, DW_FORM_data1, Data1); + + const auto Attr_DW_FORM_data2 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_data2, DW_FORM_data2, Data2); + + const auto Attr_DW_FORM_data4 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_data4, DW_FORM_data4, Data4); + + const auto Attr_DW_FORM_data8 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_data8, DW_FORM_data8, Data8); + + //---------------------------------------------------------------------- + // Test string forms + //---------------------------------------------------------------------- + const auto Attr_DW_FORM_string = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_string, DW_FORM_string, StringValue); + + const auto Attr_DW_FORM_strp = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_strp, DW_FORM_strp, StrpValue); + + //---------------------------------------------------------------------- + // Test reference forms + //---------------------------------------------------------------------- + const auto Attr_DW_FORM_ref_addr = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_ref_addr, DW_FORM_ref_addr, RefAddr); + + const auto Attr_DW_FORM_ref1 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_ref1, DW_FORM_ref1, Data1); + + const auto Attr_DW_FORM_ref2 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_ref2, DW_FORM_ref2, Data2); + + const auto Attr_DW_FORM_ref4 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_ref4, DW_FORM_ref4, Data4); + + const auto Attr_DW_FORM_ref8 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_ref8, DW_FORM_ref8, Data8); + + const auto Attr_DW_FORM_ref_sig8 = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_ref_sig8, DW_FORM_ref_sig8, Data8_2); + + const auto Attr_DW_FORM_ref_udata = static_cast(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(Attr++); + CUDie.addAttribute(Attr_DW_FORM_flag_true, DW_FORM_flag, true); + + const auto Attr_DW_FORM_flag_false = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_flag_false, DW_FORM_flag, false); + + const auto Attr_DW_FORM_flag_present = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_flag_present, DW_FORM_flag_present); + + //---------------------------------------------------------------------- + // Test SLEB128 based forms + //---------------------------------------------------------------------- + const auto Attr_DW_FORM_sdata = static_cast(Attr++); + CUDie.addAttribute(Attr_DW_FORM_sdata, DW_FORM_sdata, SData); + + //---------------------------------------------------------------------- + // Test ULEB128 based forms + //---------------------------------------------------------------------- + const auto Attr_DW_FORM_udata = static_cast(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(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(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(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 ExtractedBlockData; + Optional> 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 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 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