diff options
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DIE.cpp | 294 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp | 70 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfFile.h | 15 | ||||
-rw-r--r-- | llvm/lib/CodeGen/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/CodeGen/DwarfGenerator.cpp | 262 | ||||
-rw-r--r-- | llvm/lib/CodeGen/DwarfGenerator.h | 231 |
7 files changed, 749 insertions, 130 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/DIE.cpp b/llvm/lib/CodeGen/AsmPrinter/DIE.cpp index 06023fcc51b..3fbb52f1380 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DIE.cpp @@ -108,6 +108,51 @@ void DIEAbbrev::print(raw_ostream &O) { LLVM_DUMP_METHOD void DIEAbbrev::dump() { print(dbgs()); } +//===----------------------------------------------------------------------===// +// DIEAbbrevSet Implementation +//===----------------------------------------------------------------------===// + +DIEAbbrevSet::~DIEAbbrevSet() { + for (DIEAbbrev *Abbrev : Abbreviations) + Abbrev->~DIEAbbrev(); +} + +DIEAbbrev &DIEAbbrevSet::uniqueAbbreviation(DIE &Die) { + + FoldingSetNodeID ID; + DIEAbbrev Abbrev = Die.generateAbbrev(); + Abbrev.Profile(ID); + + void *InsertPos; + if (DIEAbbrev *Existing = + AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) { + Die.setAbbrevNumber(Existing->getNumber()); + return *Existing; + } + + // Move the abbreviation to the heap and assign a number. + DIEAbbrev *New = new (Alloc) DIEAbbrev(std::move(Abbrev)); + Abbreviations.push_back(New); + New->setNumber(Abbreviations.size()); + Die.setAbbrevNumber(Abbreviations.size()); + + // Store it for lookup. + AbbreviationsSet.InsertNode(New, InsertPos); + return *New; +} + +void DIEAbbrevSet::Emit(const AsmPrinter *AP, MCSection *Section) const { + if (!Abbreviations.empty()) { + // Start the debug abbrev section. + AP->OutStreamer->SwitchSection(Section); + AP->emitDwarfAbbrevs(Abbreviations); + } +} + +//===----------------------------------------------------------------------===// +// DIE Implementation +//===----------------------------------------------------------------------===// + DIE *DIE::getParent() const { return Owner.dyn_cast<DIE*>(); } @@ -198,6 +243,45 @@ void DIE::dump() { print(dbgs()); } +unsigned DIE::computeOffsetsAndAbbrevs(const AsmPrinter *AP, + DIEAbbrevSet &AbbrevSet, + unsigned CUOffset) { + // Unique the abbreviation and fill in the abbreviation number so this DIE + // can be emitted. + const DIEAbbrev &Abbrev = AbbrevSet.uniqueAbbreviation(*this); + + // Set compile/type unit relative offset of this DIE. + setOffset(CUOffset); + + // Add the byte size of the abbreviation code. + CUOffset += getULEB128Size(getAbbrevNumber()); + + // Add the byte size of all the DIE attribute values. + for (const auto &V : values()) + CUOffset += V.SizeOf(AP); + + // Let the children compute their offsets and abbreviation numbers. + if (hasChildren()) { + (void)Abbrev; + assert(Abbrev.hasChildren() && "Children flag not set"); + + for (auto &Child : children()) + CUOffset = Child.computeOffsetsAndAbbrevs(AP, AbbrevSet, CUOffset); + + // Each child chain is terminated with a zero byte, adjust the offset. + CUOffset += sizeof(int8_t); + } + + // Compute the byte size of this DIE and all of its children correctly. This + // is needed so that top level DIE can help the compile unit set its length + // correctly. + setSize(CUOffset - getOffset()); + return CUOffset; +} + +//===----------------------------------------------------------------------===// +// DIEUnit Implementation +//===----------------------------------------------------------------------===// DIEUnit::DIEUnit(uint16_t V, uint8_t A, dwarf::Tag UnitTag) : Die(UnitTag), Section(nullptr), Offset(0), Length(0), Version(V), AddrSize(A) @@ -257,38 +341,65 @@ void DIEValue::dump() const { /// EmitValue - Emit integer of appropriate size. /// void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { - unsigned Size = ~0U; switch (Form) { case dwarf::DW_FORM_flag_present: // Emit something to keep the lines and comments in sync. // FIXME: Is there a better way to do this? Asm->OutStreamer->AddBlankLine(); return; - case dwarf::DW_FORM_flag: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_ref1: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_data1: Size = 1; break; - case dwarf::DW_FORM_ref2: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_data2: Size = 2; break; - case dwarf::DW_FORM_sec_offset: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_strp: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_data4: Size = 4; break; - case dwarf::DW_FORM_ref8: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_ref_sig8: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_data8: Size = 8; break; - case dwarf::DW_FORM_GNU_str_index: Asm->EmitULEB128(Integer); return; - case dwarf::DW_FORM_GNU_addr_index: Asm->EmitULEB128(Integer); return; - case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return; - case dwarf::DW_FORM_sdata: Asm->EmitSLEB128(Integer); return; + case dwarf::DW_FORM_flag: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref1: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_data1: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref2: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_data2: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_strp: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref4: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_data4: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref8: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref_sig8: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_data8: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_GNU_ref_alt: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_GNU_strp_alt: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_line_strp: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_sec_offset: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_strp_sup: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref_sup: + LLVM_FALLTHROUGH; case dwarf::DW_FORM_addr: - Size = Asm->getPointerSize(); - break; + LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_addr: - Size = SizeOf(Asm, dwarf::DW_FORM_ref_addr); - break; + Asm->OutStreamer->EmitIntValue(Integer, SizeOf(Asm, Form)); + return; + case dwarf::DW_FORM_GNU_str_index: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_GNU_addr_index: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref_udata: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_udata: + Asm->EmitULEB128(Integer); + return; + case dwarf::DW_FORM_sdata: + Asm->EmitSLEB128(Integer); + return; default: llvm_unreachable("DIE Value form not supported yet"); } - Asm->OutStreamer->EmitIntValue(Integer, Size); } /// SizeOf - Determine size of integer value in bytes. @@ -301,23 +412,47 @@ unsigned DIEInteger::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { case dwarf::DW_FORM_data1: return sizeof(int8_t); case dwarf::DW_FORM_ref2: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data2: return sizeof(int16_t); - case dwarf::DW_FORM_sec_offset: LLVM_FALLTHROUGH; - case dwarf::DW_FORM_strp: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data4: return sizeof(int32_t); case dwarf::DW_FORM_ref8: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_sig8: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data8: return sizeof(int64_t); - case dwarf::DW_FORM_GNU_str_index: return getULEB128Size(Integer); - case dwarf::DW_FORM_GNU_addr_index: return getULEB128Size(Integer); - case dwarf::DW_FORM_udata: return getULEB128Size(Integer); - case dwarf::DW_FORM_sdata: return getSLEB128Size(Integer); - case dwarf::DW_FORM_addr: - return AP->getPointerSize(); case dwarf::DW_FORM_ref_addr: if (AP->getDwarfVersion() == 2) return AP->getPointerSize(); - return sizeof(int32_t); + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_strp: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_GNU_ref_alt: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_GNU_strp_alt: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_line_strp: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_sec_offset: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_strp_sup: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref_sup: + switch (AP->OutStreamer->getContext().getDwarfFormat()) { + case dwarf::DWARF32: + return 4; + case dwarf::DWARF64: + return 8; + } + llvm_unreachable("Invalid DWARF format"); + case dwarf::DW_FORM_GNU_str_index: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_GNU_addr_index: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_ref_udata: + LLVM_FALLTHROUGH; + case dwarf::DW_FORM_udata: + return getULEB128Size(Integer); + case dwarf::DW_FORM_sdata: + return getSLEB128Size(Integer); + case dwarf::DW_FORM_addr: + return AP->getPointerSize(); default: llvm_unreachable("DIE Value form not supported yet"); } } @@ -452,6 +587,29 @@ void DIEString::print(raw_ostream &O) const { } //===----------------------------------------------------------------------===// +// DIEInlineString Implementation +//===----------------------------------------------------------------------===// +void DIEInlineString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { + if (Form == dwarf::DW_FORM_string) { + for (char ch : S) + AP->EmitInt8(ch); + AP->EmitInt8(0); + return; + } + llvm_unreachable("Expected valid string form"); +} + +unsigned DIEInlineString::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { + // Emit string bytes + NULL byte. + return S.size() + 1; +} + +LLVM_DUMP_METHOD +void DIEInlineString::print(raw_ostream &O) const { + O << "InlineString: " << S.c_str(); +} + +//===----------------------------------------------------------------------===// // DIEEntry Implementation //===----------------------------------------------------------------------===// @@ -459,33 +617,69 @@ void DIEString::print(raw_ostream &O) const { /// void DIEEntry::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { - if (Form == dwarf::DW_FORM_ref_addr) { + switch (Form) { + case dwarf::DW_FORM_ref1: + case dwarf::DW_FORM_ref2: + case dwarf::DW_FORM_ref4: + case dwarf::DW_FORM_ref8: + AP->OutStreamer->EmitIntValue(Entry->getOffset(), SizeOf(AP, Form)); + return; + + case dwarf::DW_FORM_ref_udata: + AP->EmitULEB128(Entry->getOffset()); + return; + + case dwarf::DW_FORM_ref_addr: { // Get the absolute offset for this DIE within the debug info/types section. unsigned Addr = Entry->getDebugSectionOffset(); if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) { const DwarfDebug *DD = AP->getDwarfDebug(); if (DD) - assert(!DD->useSplitDwarf() && "TODO: dwo files can't have relocations."); + assert(!DD->useSplitDwarf() && + "TODO: dwo files can't have relocations."); const DIEUnit *Unit = Entry->getUnit(); assert(Unit && "CUDie should belong to a CU."); MCSection *Section = Unit->getSection(); - assert(Section && "Must have a section if we are doing relocations"); - const MCSymbol *SectionSym = Section->getBeginSymbol(); - AP->EmitLabelPlusOffset(SectionSym, Addr, DIEEntry::getRefAddrSize(AP)); - } else - AP->OutStreamer->EmitIntValue(Addr, DIEEntry::getRefAddrSize(AP)); - } else - AP->EmitInt32(Entry->getOffset()); -} - -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); + 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::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 diff --git a/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp b/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp index 74c47d151c6..d8ecc7ccfb9 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -330,6 +330,12 @@ void DIEHash::hashAttribute(const DIEValue &Value, dwarf::Tag Tag) { addULEB128(dwarf::DW_FORM_string); addString(Value.getDIEString().getString()); break; + case DIEValue::isInlineString: + addULEB128('A'); + addULEB128(Attribute); + addULEB128(dwarf::DW_FORM_string); + addString(Value.getDIEInlineString().getString()); + break; case DIEValue::isBlock: case DIEValue::isLoc: case DIEValue::isLocList: diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp index 3179ab15420..595f1d91c4b 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/llvm/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<DwarfCompileUnit> U) { CUs.push_back(std::move(U)); @@ -98,44 +68,10 @@ unsigned DwarfFile::computeSizeAndOffsetsForUnit(DwarfUnit *TheU) { // Compute the size and offset of a DIE. The offset is relative to start of the // CU. It returns the offset after laying out the DIE. unsigned DwarfFile::computeSizeAndOffset(DIE &Die, unsigned Offset) { - // Record the abbreviation. - const DIEAbbrev &Abbrev = assignAbbrevNumber(Die); - - // Set DIE offset - Die.setOffset(Offset); - - // Start the size with the size of abbreviation code. - Offset += getULEB128Size(Die.getAbbrevNumber()); - - // Size the DIE attribute values. - for (const auto &V : Die.values()) - // Size attribute value. - Offset += V.SizeOf(Asm); - - // Size the DIE children if any. - if (Die.hasChildren()) { - (void)Abbrev; - assert(Abbrev.hasChildren() && "Children flag not set"); - - for (auto &Child : Die.children()) - Offset = computeSizeAndOffset(Child, Offset); - - // End of children marker. - Offset += sizeof(int8_t); - } - - Die.setSize(Offset - Die.getOffset()); - return Offset; + return Die.computeOffsetsAndAbbrevs(Asm, Abbrevs, Offset); } -void DwarfFile::emitAbbrevs(MCSection *Section) { - // Check to see if it is worth the effort. - if (!Abbreviations.empty()) { - // Start the debug abbrev section. - Asm->OutStreamer->SwitchSection(Section); - Asm->emitDwarfAbbrevs(Abbreviations); - } -} +void DwarfFile::emitAbbrevs(MCSection *Section) { Abbrevs.Emit(Asm, Section); } // Emit strings into a string section. void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection) { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h index b73d89b0e49..d4d2ed27727 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/llvm/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 <memory> -#include <vector> namespace llvm { class AsmPrinter; @@ -41,10 +41,7 @@ class DwarfFile { BumpPtrAllocator AbbrevAllocator; // Used to uniquely define abbreviations. - FoldingSet<DIEAbbrev> AbbreviationsSet; - - // A list of all the unique abbreviations in use. - std::vector<DIEAbbrev *> Abbreviations; + DIEAbbrevSet Abbrevs; // A pointer to all units in the section. SmallVector<std::unique_ptr<DwarfCompileUnit>, 1> CUs; @@ -65,8 +62,6 @@ class DwarfFile { public: DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA); - ~DwarfFile(); - const SmallVectorImpl<std::unique_ptr<DwarfCompileUnit>> &getUnits() { return CUs; } @@ -81,12 +76,6 @@ public: /// \returns The size of the root DIE. unsigned computeSizeAndOffsetsForUnit(DwarfUnit *TheU); - /// Define a unique number for the abbreviation. - /// - /// Compute the abbreviation for \c Die, look up its unique number, and - /// return a reference to it in the uniquing table. - DIEAbbrev &assignAbbrevNumber(DIE &Die); - /// \brief Add a unit to the list of CUs. void addUnit(std::unique_ptr<DwarfCompileUnit> U); diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 398ea88363b..22ee8e9da0f 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -17,6 +17,7 @@ add_llvm_library(LLVMCodeGen DetectDeadLanes.cpp DFAPacketizer.cpp DwarfEHPrepare.cpp + DwarfGenerator.cpp EarlyIfConversion.cpp EdgeBundles.cpp ExecutionDepsFix.cpp diff --git a/llvm/lib/CodeGen/DwarfGenerator.cpp b/llvm/lib/CodeGen/DwarfGenerator.cpp new file mode 100644 index 00000000000..1e8e6614921 --- /dev/null +++ b/llvm/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<dwarf::Attribute>(A), Form, + DIEInteger(U)); +} + +void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, + StringRef String) { + auto &DG = CU->getGenerator(); + if (Form == DW_FORM_string) { + Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, + new (DG.getAllocator()) DIEInlineString(String)); + } else { + Die->addValue( + DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, + DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String))); + } +} + +void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, + dwarfgen::DIE &RefDie) { + auto &DG = CU->getGenerator(); + Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, + DIEEntry(*RefDie.Die)); +} + +void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const void *P, + size_t S) { + auto &DG = CU->getGenerator(); + DIEBlock *Block = new (DG.getAllocator()) DIEBlock; + for (size_t I = 0; I < S; ++I) + Block->addValue(DG.getAllocator(), (dwarf::Attribute)0, + dwarf::DW_FORM_data1, DIEInteger(((uint8_t *)P)[I])); + + Block->ComputeSize(DG.getAsmPrinter()); + Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, + Block); +} + +void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) { + auto &DG = CU->getGenerator(); + assert(Form == DW_FORM_flag_present); + Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form, + DIEInteger(1)); +} + +dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) { + auto &DG = CU->getGenerator(); + return dwarfgen::DIE(CU, + &Die->addChild(llvm::DIE::get(DG.getAllocator(), Tag))); +} + +dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() { + return dwarfgen::DIE(this, &DU.getUnitDie()); +} + +//===----------------------------------------------------------------------===// +/// dwarfgen::Generator implementation. +//===----------------------------------------------------------------------===// + +dwarfgen::Generator::Generator() : Abbreviations(Allocator) {} +dwarfgen::Generator::~Generator() = default; + +llvm::Expected<std::unique_ptr<dwarfgen::Generator>> +dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) { + std::unique_ptr<dwarfgen::Generator> GenUP(new dwarfgen::Generator()); + llvm::Error error = GenUP->init(TheTriple, DwarfVersion); + if (error) + return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(error)); + return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(GenUP)); +} + +llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) { + Version = V; + std::string ErrorStr; + std::string TripleName; + + // Get the target. + const Target *TheTarget = + TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); + if (!TheTarget) + return make_error<StringError>(ErrorStr, inconvertibleErrorCode()); + + TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + MRI.reset(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return make_error<StringError>(Twine("no register info for target ") + + TripleName, + inconvertibleErrorCode()); + + MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); + if (!MAI) + return make_error<StringError>("no asm info for target " + TripleName, + inconvertibleErrorCode()); + + MOFI.reset(new MCObjectFileInfo); + MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get())); + MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, CodeModel::Default, *MC); + + MCTargetOptions Options; + MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "", Options); + if (!MAB) + return make_error<StringError>("no asm backend for target " + TripleName, + inconvertibleErrorCode()); + + MII.reset(TheTarget->createMCInstrInfo()); + if (!MII) + return make_error<StringError>("no instr info info for target " + + TripleName, + inconvertibleErrorCode()); + + MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return make_error<StringError>("no subtarget info for target " + TripleName, + inconvertibleErrorCode()); + + MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC); + if (!MCE) + return make_error<StringError>("no code emitter for target " + TripleName, + inconvertibleErrorCode()); + + Stream = make_unique<raw_svector_ostream>(FileBytes); + + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + MS = TheTarget->createMCObjectStreamer( + TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false); + if (!MS) + return make_error<StringError>("no object streamer for target " + + TripleName, + inconvertibleErrorCode()); + + // Finally create the AsmPrinter we'll use to emit the DIEs. + TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), + None)); + if (!TM) + return make_error<StringError>("no target machine for target " + TripleName, + inconvertibleErrorCode()); + + Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS))); + if (!Asm) + return make_error<StringError>("no asm printer for target " + TripleName, + inconvertibleErrorCode()); + + // Set the DWARF version correctly on all classes that we use. + MC->setDwarfVersion(Version); + Asm->setDwarfVersion(Version); + + StringPool.reset(new DwarfStringPool(Allocator, *Asm, StringRef())); + + return Error::success(); +} + +StringRef dwarfgen::Generator::generate() { + // Offset from the first CU in the debug info section is 0 initially. + unsigned SecOffset = 0; + + // Iterate over each compile unit and set the size and offsets for each + // DIE within each compile unit. All offsets are CU relative. + for (auto &CU : CompileUnits) { + // Set the absolute .debug_info offset for this compile unit. + CU->setOffset(SecOffset); + // The DIEs contain compile unit relative offsets. + unsigned CUOffset = 11; + CUOffset = CU->getUnitDIE().computeSizeAndOffsets(CUOffset); + // Update our absolute .debug_info offset. + SecOffset += CUOffset; + CU->setLength(CUOffset - 4); + } + Abbreviations.Emit(Asm.get(), MOFI->getDwarfAbbrevSection()); + StringPool->emit(*Asm, MOFI->getDwarfStrSection()); + MS->SwitchSection(MOFI->getDwarfInfoSection()); + for (auto &CU : CompileUnits) { + uint16_t Version = CU->getVersion(); + auto Length = CU->getLength(); + MC->setDwarfVersion(Version); + assert(Length != -1U); + Asm->EmitInt32(Length); + Asm->EmitInt16(Version); + Asm->EmitInt32(0); + Asm->EmitInt8(CU->getAddressSize()); + Asm->emitDwarfDIE(*CU->getUnitDIE().Die); + } + + MS->Finish(); + if (FileBytes.empty()) + return StringRef(); + return StringRef(FileBytes.data(), FileBytes.size()); +} + +bool dwarfgen::Generator::saveFile(StringRef Path) { + if (FileBytes.empty()) + return false; + std::error_code EC; + raw_fd_ostream Strm(Path, EC, sys::fs::F_None); + if (EC) + return false; + Strm.write(FileBytes.data(), FileBytes.size()); + Strm.close(); + return true; +} + +dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() { + CompileUnits.push_back(std::unique_ptr<CompileUnit>( + new CompileUnit(*this, Version, Asm->getPointerSize()))); + return *CompileUnits.back(); +} diff --git a/llvm/lib/CodeGen/DwarfGenerator.h b/llvm/lib/CodeGen/DwarfGenerator.h new file mode 100644 index 00000000000..9e7bdfb6f40 --- /dev/null +++ b/llvm/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 <memory> +#include <string> +#include <tuple> +#include <vector> + +namespace llvm { + +class AsmPrinter; +class DIE; +class DIEAbbrev; +class DwarfStringPool; +class MCAsmBackend; +class MCAsmInfo; +class MCCodeEmitter; +class MCContext; +struct MCDwarfLineTableParams; +class MCInstrInfo; +class MCObjectFileInfo; +class MCRegisterInfo; +class MCStreamer; +class MCSubtargetInfo; +class raw_fd_ostream; +class TargetMachine; +class Triple; + +namespace dwarfgen { + +class Generator; +class CompileUnit; + +/// A DWARF debug information entry class used to generate DWARF DIEs. +/// +/// This class is used to quickly generate DWARF debug information by creating +/// child DIEs or adding attributes to the current DIE. Instances of this class +/// are created from the compile unit (dwarfgen::CompileUnit::getUnitDIE()) or +/// by calling dwarfgen::DIE::addChild(...) and using the returned DIE object. +class DIE { + dwarfgen::CompileUnit *CU; + llvm::DIE *Die; + +protected: + friend class Generator; + friend class CompileUnit; + + DIE(CompileUnit *U = nullptr, llvm::DIE *D = nullptr) : CU(U), Die(D) {} + + /// Called with a compile/type unit relative offset prior to generating the + /// DWARF debug info. + /// + /// \param CUOffset the compile/type unit relative offset where the + /// abbreviation code for this DIE will be encoded. + unsigned computeSizeAndOffsets(unsigned CUOffset); + +public: + /// Add an attribute value that has no value. + /// + /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that + /// represents a user defined DWARF attribute. + /// \param Form the dwarf::Form to use when encoding the attribute. This is + /// only used with the DW_FORM_flag_present form encoding. + void addAttribute(uint16_t Attr, dwarf::Form Form); + + /// Add an attribute value to be encoded as a DIEInteger + /// + /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that + /// represents a user defined DWARF attribute. + /// \param Form the dwarf::Form to use when encoding the attribute. + /// \param U the unsigned integer to encode. + void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U); + + /// Add an attribute value to be encoded as a DIEString or DIEInlinedString. + /// + /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that + /// represents a user defined DWARF attribute. + /// \param Form the dwarf::Form to use when encoding the attribute. The form + /// must be one of DW_FORM_strp or DW_FORM_string. + /// \param String the string to encode. + void addAttribute(uint16_t Attr, dwarf::Form Form, StringRef String); + + /// Add an attribute value to be encoded as a DIEEntry. + /// + /// DIEEntry attributes refer to other llvm::DIE objects that have been + /// created. + /// + /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that + /// represents a user defined DWARF attribute. + /// \param Form the dwarf::Form to use when encoding the attribute. The form + /// must be one of DW_FORM_strp or DW_FORM_string. + /// \param RefDie the DIE that this attriute refers to. + void addAttribute(uint16_t Attr, dwarf::Form Form, dwarfgen::DIE &RefDie); + + /// Add an attribute value to be encoded as a DIEBlock. + /// + /// DIEBlock attributes refers to binary data that is stored as the + /// attribute's value. + /// + /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that + /// represents a user defined DWARF attribute. + /// \param Form the dwarf::Form to use when encoding the attribute. The form + /// must be one of DW_FORM_strp or DW_FORM_string. + /// \param P a pointer to the data to store as the attribute value. + /// \param S the size in bytes of the data pointed to by \param P. + void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S); + + /// Add a new child to this DIE object. + /// + /// \param Tag the dwarf::Tag to assing to the llvm::DIE object. + /// \returns the newly created DIE object that is now a child owned by this + /// object. + dwarfgen::DIE addChild(dwarf::Tag Tag); +}; + +/// A DWARF compile unit used to generate DWARF compile/type units. +/// +/// Instances of these classes are created by instances of the Generator +/// class. All information required to generate a DWARF compile unit is +/// contained inside this class. +class CompileUnit { + Generator &DG; + DIEUnit DU; + +public: + CompileUnit(Generator &D, uint16_t V, uint8_t A) + : DG(D), DU(V, A, dwarf::DW_TAG_compile_unit) {} + DIE getUnitDIE(); + Generator &getGenerator() { return DG; } + uint64_t getOffset() const { return DU.getDebugSectionOffset(); } + uint64_t getLength() const { return DU.getLength(); } + uint16_t getVersion() const { return DU.getDwarfVersion(); } + uint16_t getAddressSize() const { return DU.getAddressSize(); } + void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); } + void setLength(uint64_t Length) { DU.setLength(Length); } +}; + +/// A DWARF generator. +/// +/// Generate DWARF for unit tests by creating any instance of this class and +/// calling Generator::addCompileUnit(), and then getting the dwarfgen::DIE from +/// the returned compile unit and adding attributes and children to each DIE. +class Generator { + std::unique_ptr<MCRegisterInfo> MRI; + std::unique_ptr<MCAsmInfo> MAI; + std::unique_ptr<MCObjectFileInfo> MOFI; + std::unique_ptr<MCContext> MC; + MCAsmBackend *MAB; // Owned by MCStreamer + std::unique_ptr<MCInstrInfo> MII; + std::unique_ptr<MCSubtargetInfo> MSTI; + MCCodeEmitter *MCE; // Owned by MCStreamer + MCStreamer *MS; // Owned by AsmPrinter + std::unique_ptr<TargetMachine> TM; + std::unique_ptr<AsmPrinter> Asm; + std::unique_ptr<DwarfStringPool> StringPool; + std::vector<std::unique_ptr<CompileUnit>> CompileUnits; + BumpPtrAllocator Allocator; + DIEAbbrevSet Abbreviations; + + SmallString<4096> FileBytes; + /// The stream we use to generate the DWARF into as an ELF file. + std::unique_ptr<raw_svector_ostream> Stream; + /// The DWARF version to generate. + uint16_t Version; + + /// Private constructor, call Generator::Create(...) to get a DWARF generator + /// expected. + Generator(); + + /// Create the streamer and setup the output buffer. + llvm::Error init(Triple TheTriple, uint16_t DwarfVersion); + +public: + /// Create a DWARF generator or get an appropriate error. + /// + /// \param TheTriple the triple to use when creating any required support + /// classes needed to emit the DWARF. + /// \param DwarfVersion the version of DWARF to emit. + /// + /// \returns a llvm::Expected that either contains a unique_ptr to a Generator + /// or a llvm::Error. + static llvm::Expected<std::unique_ptr<Generator>> + create(Triple TheTriple, uint16_t DwarfVersion); + + ~Generator(); + + /// Generate all DWARF sections and return a memory buffer that + /// contains an ELF file that contains the DWARF. + StringRef generate(); + + /// Add a compile unit to be generated. + /// + /// \returns a dwarfgen::CompileUnit that can be used to retrieve the compile + /// unit dwarfgen::DIE that can be used to add attributes and add child DIE + /// objedts to. + dwarfgen::CompileUnit &addCompileUnit(); + + BumpPtrAllocator &getAllocator() { return Allocator; } + AsmPrinter *getAsmPrinter() const { return Asm.get(); } + DIEAbbrevSet &getAbbrevSet() { return Abbreviations; } + DwarfStringPool &getStringPool() { return *StringPool; } + + /// Save the generated DWARF file to disk. + /// + /// \param Path the path to save the ELF file to. + bool saveFile(StringRef Path); +}; + +} // end namespace dwarfgen + +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFGENERATOR_H |