Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -18,10 +18,11 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/DwarfStringPoolEntry.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/DwarfStringPoolEntry.h" #include "llvm/IR/InlineAsm.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" namespace llvm { @@ -134,6 +135,10 @@ /// If the target supports dwarf debug info, this pointer is non-null. DwarfDebug *DD; + /// The DWARF version that is being emitted by this object. This value will + /// be initialized automatically when the \p DD member variable is initialized + /// or by a manual call to setDwarfVersion(). + uint16_t DwarfVersion; protected: explicit AsmPrinter(TargetMachine &TM, std::unique_ptr Streamer); @@ -141,6 +146,22 @@ public: ~AsmPrinter() override; + /// Get the current DWARF version. + uint16_t getDwarfVersion() const; + /// Get the DWARF format (DWARF32 or DWARF64). + dwarf::DwarfFormat getDwarfFormat() const { + // FIXME: We currently only support DWARF32. Add DWARF64 support. + return dwarf::DWARF32; + } + /// Check if we are using split DWARF. + bool getUseSplitDwarf() const; + + /// Some AsmPrinter clients will generate DWARF without this AsmPrinter class + /// creating a DwarfDebug object. Such clients must set the DWARF version + /// manually by calling this function before emitting any DWARF objects that + /// change size with the DWARF versions. + void setDwarfVersion(uint16_t Version) { DwarfVersion = Version; } + DwarfDebug *getDwarfDebug() { return DD; } DwarfDebug *getDwarfDebug() const { return DD; } Index: include/llvm/CodeGen/DIE.h =================================================================== --- include/llvm/CodeGen/DIE.h +++ include/llvm/CodeGen/DIE.h @@ -15,11 +15,11 @@ #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/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" @@ -30,11 +30,14 @@ #include #include #include +#include namespace llvm { class AsmPrinter; +class DIE; class MCExpr; +class MCSection; class MCSymbol; class raw_ostream; @@ -81,7 +84,8 @@ public: DIEAbbrev(dwarf::Tag T, bool C) : Tag(T), Children(C) {} - + DIEAbbrev(const DIEAbbrev &RHS) = default; + DIEAbbrev(DIEAbbrev &&RHS) = default; /// Accessors. /// @{ dwarf::Tag getTag() const { return Tag; } @@ -108,6 +112,38 @@ }; //===--------------------------------------------------------------------===// +/// 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 { @@ -197,8 +233,10 @@ }; //===--------------------------------------------------------------------===// -/// 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; @@ -215,6 +253,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.) @@ -647,6 +706,27 @@ /// Set the abbreviation number for this DIE. void setAbbrevNumber(unsigned I) { AbbrevNumber = I; } + /// 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 absolute DIE + /// offset, unique its abbreviation, and return the updated offset that points + /// to the next debug info will be emitted within the .debug_info or + /// .debug_types 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 SecOffset the section (.debug_info or .debug_types) offset of the + /// first byte for this DIE. + /// \returns the debug info section offset for the debug info that follows + /// this DIE. + unsigned computeOffsetsAndAbbrevs(const AsmPrinter *AP, + DIEAbbrevSet &AbbrevSet, + unsigned SecOffset); + /// Climb up the parent chain to get the compile or type unit DIE this DIE /// belongs to. const DIE *getUnit() const; Index: include/llvm/CodeGen/DIEValue.def =================================================================== --- include/llvm/CodeGen/DIEValue.def +++ 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: include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h @@ -101,6 +101,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: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -101,7 +101,7 @@ AsmPrinter::AsmPrinter(TargetMachine &tm, std::unique_ptr Streamer) : MachineFunctionPass(ID), TM(tm), MAI(tm.getMCAsmInfo()), OutContext(Streamer->getContext()), OutStreamer(std::move(Streamer)), - LastMI(nullptr), LastFn(0), Counter(~0U) { + DwarfVersion(0), LastMI(nullptr), LastFn(0), Counter(~0U) { DD = nullptr; MMI = nullptr; LI = nullptr; @@ -124,6 +124,17 @@ } } +uint16_t AsmPrinter::getDwarfVersion() const { + // DwarfVersion is set by either having created a DebugDebug in + // doInitialization(...) or manually calling setDwarfVersion(...). + assert(DwarfVersion != 0 && "DWARF version must be initialized"); + return DwarfVersion; +} + +bool AsmPrinter::getUseSplitDwarf() const { + return DD ? DD->useSplitDwarf() : false; +} + bool AsmPrinter::isPositionIndependent() const { return TM.isPositionIndependent(); } @@ -251,6 +262,9 @@ DD = new DwarfDebug(this, &M); DD->beginModule(); Handlers.push_back(HandlerInfo(DD, DbgTimerName, DWARFGroupName)); + // Initialize the DWARF version member variable with the value from the + // DwarfDebug. + DwarfVersion = DD->getDwarfVersion(); } } Index: lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIE.cpp +++ lib/CodeGen/AsmPrinter/DIE.cpp @@ -115,6 +115,47 @@ return Abbrev; } +//===----------------------------------------------------------------------===// +// 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); + } +} + /// Climb up the parent chain to get the unit DIE to which this DIE /// belongs. const DIE *DIE::getUnit() const { @@ -203,6 +244,42 @@ } } +unsigned DIE::computeOffsetsAndAbbrevs(const AsmPrinter *AP, + DIEAbbrevSet &AbbrevSet, + unsigned SecOffset) { + // Unique the abbreviation and allow it to set the abbreviation number + // by calling DIE::setAbbrevNumber() on this object. + const DIEAbbrev &Abbrev = AbbrevSet.uniqueAbbreviation(*this); + + // Set DIE offset to the location in the section. + setOffset(SecOffset); + + // Add the byte size of the abbreviation code. + SecOffset += getULEB128Size(getAbbrevNumber()); + + // Add the byte size of all the DIE attribute values. + for (const auto &V : values()) + SecOffset += 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()) + SecOffset = Child.computeOffsetsAndAbbrevs(AP, AbbrevSet, SecOffset); + + // Each child chain is terminated with a zero byte, adjust the offset. + SecOffset += 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(SecOffset - getOffset()); + return SecOffset; +} + unsigned DIEValue::SizeOf(const AsmPrinter *AP) const { switch (Ty) { case isNone: @@ -249,26 +326,42 @@ 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_data1: + LLVM_FALLTHROUGH; 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_data2: + 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: + LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_data4: Size = 4; break; + 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: Size = 8; break; + case dwarf::DW_FORM_data8: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_addr: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref_addr: + Size = SizeOf(Asm, Form); + 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_ref_udata: + LLVM_FALLTHROUGH; case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return; case dwarf::DW_FORM_sdata: Asm->EmitSLEB128(Integer); return; - case dwarf::DW_FORM_addr: - Size = Asm->getPointerSize(); - break; - case dwarf::DW_FORM_ref_addr: - Size = SizeOf(Asm, dwarf::DW_FORM_ref_addr); - break; default: llvm_unreachable("DIE Value form not supported yet"); } Asm->OutStreamer->EmitIntValue(Integer, Size); @@ -284,8 +377,20 @@ 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_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: + // 4 bytes for DWARF32, 8 bytes for DWARF64. + return AP->getDwarfFormat() == dwarf::DWARF32 ? 4 : 8; case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data4: return sizeof(int32_t); case dwarf::DW_FORM_ref8: LLVM_FALLTHROUGH; @@ -293,12 +398,14 @@ 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_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(); case dwarf::DW_FORM_ref_addr: - if (AP->OutStreamer->getContext().getDwarfVersion() == 2) + if (AP->getDwarfVersion() == 2) return AP->getPointerSize(); return sizeof(int32_t); default: llvm_unreachable("DIE Value form not supported yet"); @@ -435,6 +542,28 @@ } //===----------------------------------------------------------------------===// +// 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 { + return S.size() + 1; // Emit string bytes + NULL byte. +} + +LLVM_DUMP_METHOD +void DIEInlineString::print(raw_ostream &O) const { + O << "InlineString: " << S.c_str(); +} + +//===----------------------------------------------------------------------===// // DIEEntry Implementation //===----------------------------------------------------------------------===// @@ -443,22 +572,28 @@ void DIEEntry::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { if (Form == dwarf::DW_FORM_ref_addr) { - const DwarfDebug *DD = AP->getDwarfDebug(); unsigned Addr = Entry->getOffset(); - assert(!DD->useSplitDwarf() && "TODO: dwo files can't have relocations."); + assert(!AP->getUseSplitDwarf() && + "TODO: dwo files can't have relocations."); // For DW_FORM_ref_addr, output the offset from beginning of debug info // section. Entry->getOffset() returns the offset from start of the // compile unit. - DwarfCompileUnit *CU = DD->lookupUnit(Entry->getUnit()); - assert(CU && "CUDie should belong to a CU."); - Addr += CU->getDebugInfoOffset(); - if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) - AP->EmitLabelPlusOffset(CU->getSectionSym(), Addr, - DIEEntry::getRefAddrSize(AP)); - else - AP->OutStreamer->EmitIntValue(Addr, DIEEntry::getRefAddrSize(AP)); - } else - AP->EmitInt32(Entry->getOffset()); + const DwarfDebug *DD = AP->getDwarfDebug(); + if (DD) { + DwarfCompileUnit *CU = DD->lookupUnit(Entry->getUnit()); + assert(CU && "CUDie should belong to a CU."); + Addr += CU->getDebugInfoOffset(); + if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) + AP->EmitLabelPlusOffset(CU->getSectionSym(), Addr, + DIEEntry::getRefAddrSize(AP)); + else + AP->OutStreamer->EmitIntValue(Addr, DIEEntry::getRefAddrSize(AP)); + return; + } + } + // Make sure we emit the correct size compile unit relative offset for + // DWARF32 or DWARF64. + AP->OutStreamer->EmitIntValue(Entry->getOffset(), SizeOf(AP, Form)); } unsigned DIEEntry::getRefAddrSize(const AsmPrinter *AP) { @@ -466,9 +601,7 @@ // 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. - const DwarfDebug *DD = AP->getDwarfDebug(); - assert(DD && "Expected Dwarf Debug info to be available"); - if (DD->getDwarfVersion() == 2) + if (AP->getDwarfVersion() == 2) return AP->getPointerSize(); return sizeof(int32_t); } Index: lib/CodeGen/AsmPrinter/DIEHash.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DIEHash.cpp +++ 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: lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.h +++ lib/CodeGen/AsmPrinter/DwarfFile.h @@ -16,6 +16,7 @@ #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 @@ -25,10 +26,10 @@ class AsmPrinter; class DbgVariable; class DwarfCompileUnit; +class DwarfStringPool; class DwarfUnit; class DIEAbbrev; class MCSymbol; -class DIE; class LexicalScope; class StringRef; class DwarfDebug; @@ -41,11 +42,8 @@ BumpPtrAllocator AbbrevAllocator; // Used to uniquely define abbreviations. - FoldingSet AbbreviationsSet; + DIEAbbrevSet Abbrevs; - // A list of all the unique abbreviations in use. - std::vector Abbreviations; - // A pointer to all units in the section. SmallVector, 1> CUs; @@ -85,7 +83,7 @@ /// /// 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); + // DIEAbbrev &assignAbbrevNumber(DIE &Die); /// \brief Add a unit to the list of CUs. void addUnit(std::unique_ptr U); Index: lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -19,38 +19,17 @@ namespace llvm { DwarfFile::DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA) - : Asm(AP), StrPool(DA, *Asm, Pref) {} + : Asm(AP), Abbrevs(AbbrevAllocator), 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); +//// Define a unique number for the abbreviation. +//// +// DIEAbbrev &DwarfFile::assignAbbrevNumber(DIE &Die) { +// return Abbrevs.uniqueAbbreviation(Die); +//} - 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; -} - void DwarfFile::addUnit(std::unique_ptr U) { CUs.push_back(std::move(U)); } @@ -98,44 +77,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: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -17,6 +17,7 @@ DetectDeadLanes.cpp DFAPacketizer.cpp DwarfEHPrepare.cpp + DwarfGenerator.cpp EarlyIfConversion.cpp EdgeBundles.cpp ExecutionDepsFix.cpp Index: lib/CodeGen/DwarfGenerator.h =================================================================== --- lib/CodeGen/DwarfGenerator.h +++ lib/CodeGen/DwarfGenerator.h @@ -0,0 +1,201 @@ +//===--- 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 +#include +#include +#include + +namespace llvm { + +class AsmPrinter; +class DIE; +class DIEAbbrev; +class DwarfGen; +class DwarfGenCU; +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; + +class DwarfGenDIE { + DwarfGenCU *CU; + DIE *Die; + +protected: + friend class DwarfGen; + DIE *ptr() { return Die; } + DIE &ref() { return *Die; } + +public: + DwarfGenDIE(DwarfGenCU *U = nullptr, DIE *D = nullptr) : CU(U), Die(D) {} + + unsigned computeSizeAndOffsets(unsigned Offset); + + void addAttribute(uint16_t A, uint16_t F); + void addAttribute(uint16_t A, uint16_t F, uint64_t U); + void addAttribute(uint16_t A, uint16_t F, StringRef String); + void addAttribute(uint16_t A, uint16_t F, DwarfGenDIE &RefDie); + void addAttribute(uint16_t A, uint16_t F, const void *P, size_t S); + DwarfGenDIE addChild(dwarf::Tag T); +}; + +//------------------------------------------------------------------------------ +/// A class that represents a DWARF compile unit. +/// +/// Instances of these classes are created by instances of the DwarfGen +/// class. All information required to generate a DWARF compile unit is +/// contained inside this class. +//------------------------------------------------------------------------------ +class DwarfGenCU { + DwarfGen &DG; + uint64_t Offset; + uint32_t Length; + const uint16_t Version; + const uint8_t AddrSize; + DIE *Die; + +public: + uint64_t getOffset() const { return Offset; } + uint64_t getLength() const { return Length; } + uint16_t getVersion() const { return Version; } + uint16_t getAddressSize() const { return AddrSize; } + DwarfGen &getDwarfGen() { return DG; } + void setOffset(uint64_t O) { Offset = O; } + void setLength(uint64_t L) { Length = L; } + DwarfGenCU(DwarfGen &D, uint16_t V, uint8_t A) + : DG(D), Offset(-1ULL), Length(-1U), Version(V), AddrSize(A), + Die(nullptr) {} + DwarfGenDIE getUnitDIE(); +}; + +//------------------------------------------------------------------------------ +/// String table class. +/// +/// This class will generate a string table with unique C strings. Calling +/// StringTable::addString(const char *) will return a uint32_t offset into the +/// string table that can be used as a DW_FORM_strp form value. After all +/// strings have been added to the table, call StringTable::getData() and use +/// that as the contents of the .debug.str section. +//------------------------------------------------------------------------------ +class StringTable { + std::string Data; + +public: + // Initialize the string table with a leading NULL byte + StringTable() : Data(1, '\0') {} + + void clear() { Data = std::string(1, '\0'); } + + // Add a string to the string table and returns its 32 bit offset. + uint32_t addString(const char *CStr) { + if (CStr && CStr[0]) { + size_t Pos = Data.find(CStr, 0); + if (Pos != std::string::npos) + return (uint32_t)Pos; + uint32_t StringOffset = Data.size(); + // Append the string including the null terminator. + Data.append(CStr, strlen(CStr) + 1); + return StringOffset; + } + return 0; + } + + llvm::StringRef getData() const { return llvm::StringRef(Data); } +}; + +/// \brief The Dwarf streaming logic +/// +/// All interactions with the MC layer that is used to build the debug +/// information binary representation are handled in this class. +class DwarfGen { + /// \defgroup MCObjects MC layer objects constructed by the streamer + /// @{ + 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; + /// \brief FoldingSet that uniques the abbreviations. + BumpPtrAllocator Allocator; + DIEAbbrevSet Abbreviations; + /// @} + + SmallString<4096> FileBytes; + /// \brief the file we stream the linked Dwarf to. + std::unique_ptr Stream; + /// The DWARF version to generate. + uint16_t Version; + +public: + DwarfGen(); + ~DwarfGen(); + /// \brief Actually create the streamer and setup the output buffer. + /// + /// This could be done directly in the constructor, but it feels + /// more natural to handle errors through return value. + bool init(Triple TheTriple, uint16_t Version); + + /// \brief Generate all DWARF sections and return a memory buffer that + /// contains the ELF file. + StringRef generate(); + + DwarfGenCU &addCompileUnit(); + + BumpPtrAllocator &getAllocator() { return Allocator; } + AsmPrinter *getAsmPrinter() const { return Asm.get(); } + DIEAbbrevSet &getAbbrevSet() { return Abbreviations; } + DwarfStringPool &getStringPool() { return *StringPool; } + /// \brief Set the current output section to debug_info and change + /// the MC Dwarf version to \p DwarfVersion. + void switchToDebugInfoSection(unsigned DwarfVersion); + + /// \brief Emit the line table described in \p Rows into the + /// debug_line section. + void emitLineTableForUnit(MCDwarfLineTableParams Params, + StringRef PrologueBytes, unsigned MinInstLength, + std::vector &Rows, + unsigned AdddressSize); + + /// Save the generated DWARF file to disk. + bool saveFile(StringRef Path); +}; + +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFGENERATOR_H Index: lib/CodeGen/DwarfGenerator.cpp =================================================================== --- lib/CodeGen/DwarfGenerator.cpp +++ lib/CodeGen/DwarfGenerator.cpp @@ -0,0 +1,255 @@ +//===--- 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/DwarfFile.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 { +bool error(const Twine &Error, const Twine &Context) { + errs() << Twine("while processing ") + Context + ":\n"; + errs() << Twine("error: ") + Error + "\n"; + return false; +} + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +/// DwarfGenDIE implementation. +//===----------------------------------------------------------------------===// +unsigned DwarfGenDIE::computeSizeAndOffsets(unsigned Offset) { + auto &DG = CU->getDwarfGen(); + return Die->computeOffsetsAndAbbrevs(DG.getAsmPrinter(), DG.getAbbrevSet(), + Offset); +} + +void DwarfGenDIE::addAttribute(uint16_t A, uint16_t F, uint64_t U) { + auto &DG = CU->getDwarfGen(); + Die->addValue(DG.getAllocator(), static_cast(A), + static_cast(F), DIEInteger(U)); +} + +void DwarfGenDIE::addAttribute(uint16_t A, uint16_t F, StringRef String) { + auto &DG = CU->getDwarfGen(); + if (F == DW_FORM_string) { + Die->addValue(DG.getAllocator(), static_cast(A), + static_cast(F), + new (DG.getAllocator()) DIEInlineString(String)); + } else { + Die->addValue( + DG.getAllocator(), static_cast(A), + static_cast(F), + DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String))); + } +} + +void DwarfGenDIE::addAttribute(uint16_t A, uint16_t F, DwarfGenDIE &RefDie) { + auto &DG = CU->getDwarfGen(); + Die->addValue(DG.getAllocator(), static_cast(A), + static_cast(F), DIEEntry(RefDie.ref())); +} + +void DwarfGenDIE::addAttribute(uint16_t A, uint16_t F, const void *P, + size_t S) { + auto &DG = CU->getDwarfGen(); + 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), + static_cast(F), Block); +} + +void DwarfGenDIE::addAttribute(uint16_t A, uint16_t F) { + auto &DG = CU->getDwarfGen(); + assert(F == DW_FORM_flag_present); + Die->addValue(DG.getAllocator(), static_cast(A), + static_cast(F), DIEInteger(1)); +} + +DwarfGenDIE DwarfGenDIE::addChild(dwarf::Tag Tag) { + auto &DG = CU->getDwarfGen(); + return DwarfGenDIE(CU, &Die->addChild(DIE::get(DG.getAllocator(), Tag))); +} + +DwarfGenDIE DwarfGenCU::getUnitDIE() { + if (Die == nullptr) + Die = DIE::get(DG.getAllocator(), DW_TAG_compile_unit); + return DwarfGenDIE(this, Die); +} + +//===----------------------------------------------------------------------===// +/// DwarfGen implementation. +//===----------------------------------------------------------------------===// + +DwarfGen::DwarfGen() : Abbreviations(Allocator) {} + +DwarfGen::~DwarfGen() = default; + +bool DwarfGen::init(Triple TheTriple, uint16_t V) { + Version = V; + std::string ErrorStr; + std::string TripleName; + StringRef Context = "dwarf streamer init"; + + // Get the target. + const Target *TheTarget = + TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); + if (!TheTarget) + return error(ErrorStr, Context); + TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + MRI.reset(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return error(Twine("no register info for target ") + TripleName, Context); + + MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); + if (!MAI) + return error("no asm info for target " + TripleName, Context); + + 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 error("no asm backend for target " + TripleName, Context); + + MII.reset(TheTarget->createMCInstrInfo()); + if (!MII) + return error("no instr info info for target " + TripleName, Context); + + MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return error("no subtarget info for target " + TripleName, Context); + + MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC); + if (!MCE) + return error("no code emitter for target " + TripleName, Context); + + Stream = llvm::make_unique(FileBytes); + + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + MS = TheTarget->createMCObjectStreamer( + TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false); + if (!MS) + return error("no object streamer for target " + TripleName, Context); + + // Finally create the AsmPrinter we'll use to emit the DIEs. + TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), + None)); + if (!TM) + return error("no target machine for target " + TripleName, Context); + + Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr(MS))); + if (!Asm) + return error("no asm printer for target " + TripleName, Context); + + // 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 true; +} + +StringRef DwarfGen::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) { + CU->setOffset(SecOffset); + SecOffset += 11; + SecOffset = CU->getUnitDIE().computeSizeAndOffsets(SecOffset); + CU->setLength(SecOffset - CU->getOffset() - 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().ref()); + } + + MS->Finish(); + if (FileBytes.empty()) + return StringRef(); + return StringRef(FileBytes.data(), FileBytes.size()); +} + +/// Save the generated DWARF file to disk. +bool DwarfGen::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; +} + +/// \brief Set the current output section to debug_info and change +/// the MC Dwarf version to \p DwarfVersion. +void DwarfGen::switchToDebugInfoSection(unsigned DwarfVersion) { + MS->SwitchSection(MOFI->getDwarfInfoSection()); + MC->setDwarfVersion(DwarfVersion); +} + +DwarfGenCU &DwarfGen::addCompileUnit() { + CompileUnits.push_back(std::unique_ptr( + new DwarfGenCU(*this, Version, Asm->getPointerSize()))); + return *CompileUnits.back(); +} Index: lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ 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: tools/dsymutil/DwarfLinker.cpp =================================================================== --- tools/dsymutil/DwarfLinker.cpp +++ tools/dsymutil/DwarfLinker.cpp @@ -660,6 +660,7 @@ void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) { MS->SwitchSection(MOFI->getDwarfInfoSection()); MC->setDwarfVersion(DwarfVersion); + Asm->setDwarfVersion(DwarfVersion); } /// \brief Emit the compilation unit header for \p Unit in the Index: unittests/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- unittests/DebugInfo/DWARF/CMakeLists.txt +++ 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: unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -0,0 +1,513 @@ +//===- 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(); + } +} + +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(); + DwarfGen DG; + Triple Triple; + if (AddrSize == 8) + Triple = llvm::Triple("x86_64--"); + else + Triple = llvm::Triple("i386--"); + + bool DwarfInitSuccess = DG.init(Triple, Version); + EXPECT_TRUE(DwarfInitSuccess); + DwarfGenCU &CU = DG.addCompileUnit(); + DwarfGenDIE 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(); + DwarfGen DG; + Triple Triple; + if (AddrSize == 8) + Triple = llvm::Triple("x86_64--"); + else + Triple = llvm::Triple("i386--"); + + bool DwarfInitSuccess = DG.init(Triple, Version); + EXPECT_TRUE(DwarfInitSuccess); + DwarfGenCU &CU = DG.addCompileUnit(); + DwarfGenDIE 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); + + DwarfGenDIE 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); + + DwarfGenDIE 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); + + DwarfGenDIE 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>(); +} + +} // end anonymous namespace