//===- DIEGenerator.h -------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DIEGENERATOR_H #define LLVM_LIB_DWARFLINKER_PARALLEL_DIEGENERATOR_H #include "DWARFLinkerGlobalData.h" #include "DWARFLinkerUnit.h" #include "llvm/CodeGen/DIE.h" #include "llvm/Support/LEB128.h" namespace llvm { namespace dwarf_linker { namespace parallel { /// This class is a helper to create output DIE tree. class DIEGenerator { public: DIEGenerator(BumpPtrAllocator &Allocator, DwarfUnit &CU) : Allocator(Allocator), CU(CU) {} DIEGenerator(DIE *OutputDIE, BumpPtrAllocator &Allocator, DwarfUnit &CU) : Allocator(Allocator), CU(CU), OutputDIE(OutputDIE) {} /// Creates a DIE of specified tag \p DieTag and \p OutOffset. DIE *createDIE(dwarf::Tag DieTag, uint32_t OutOffset) { OutputDIE = DIE::get(Allocator, DieTag); OutputDIE->setOffset(OutOffset); return OutputDIE; } DIE *getDIE() { return OutputDIE; } /// Adds a specified \p Child to the current DIE. void addChild(DIE *Child) { assert(Child != nullptr); assert(OutputDIE != nullptr); OutputDIE->addChild(Child); } /// Adds specified scalar attribute to the current DIE. std::pair addScalarAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm, uint64_t Value) { return addAttribute(Attr, AttrForm, DIEInteger(Value)); } /// Adds specified location attribute to the current DIE. std::pair addLocationAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm, ArrayRef Bytes) { DIELoc *Loc = new (Allocator) DIELoc; for (auto Byte : Bytes) static_cast(Loc)->addValue( Allocator, static_cast(0), dwarf::DW_FORM_data1, DIEInteger(Byte)); Loc->setSize(Bytes.size()); return addAttribute(Attr, AttrForm, Loc); } /// Adds specified block or exprloc attribute to the current DIE. std::pair addBlockAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm, ArrayRef Bytes) { // The expression location data might be updated and exceed the original // size. Check whether the new data fits into the original form. assert((AttrForm == dwarf::DW_FORM_block) || (AttrForm == dwarf::DW_FORM_exprloc) || (AttrForm == dwarf::DW_FORM_block1 && Bytes.size() <= UINT8_MAX) || (AttrForm == dwarf::DW_FORM_block2 && Bytes.size() <= UINT16_MAX) || (AttrForm == dwarf::DW_FORM_block4 && Bytes.size() <= UINT32_MAX)); DIEBlock *Block = new (Allocator) DIEBlock; for (auto Byte : Bytes) static_cast(Block)->addValue( Allocator, static_cast(0), dwarf::DW_FORM_data1, DIEInteger(Byte)); Block->setSize(Bytes.size()); return addAttribute(Attr, AttrForm, Block); } /// Adds specified location list attribute to the current DIE. std::pair addLocListAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm, uint64_t Value) { return addAttribute(Attr, AttrForm, DIELocList(Value)); } /// Adds indexed string attribute. std::pair addIndexedStringAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm, uint64_t Idx) { assert(AttrForm == dwarf::DW_FORM_strx); return addAttribute(Attr, AttrForm, DIEInteger(Idx)); } /// Adds string attribute with dummy offset to the current DIE. std::pair addStringPlaceholderAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm) { assert(AttrForm == dwarf::DW_FORM_strp || AttrForm == dwarf::DW_FORM_line_strp); return addAttribute(Attr, AttrForm, DIEInteger(0xBADDEF)); } /// Adds inplace string attribute to the current DIE. std::pair addInplaceString(dwarf::Attribute Attr, StringRef String) { DIEBlock *Block = new (Allocator) DIEBlock; for (auto Byte : String.bytes()) static_cast(Block)->addValue( Allocator, static_cast(0), dwarf::DW_FORM_data1, DIEInteger(Byte)); static_cast(Block)->addValue( Allocator, static_cast(0), dwarf::DW_FORM_data1, DIEInteger(0)); Block->setSize(String.size() + 1); DIEValue &ValueRef = *OutputDIE->addValue(Allocator, Attr, dwarf::DW_FORM_string, Block); return std::pair(ValueRef, String.size() + 1); } /// Creates appreviations for the current DIE. Returns value of /// abbreviation number. Updates offsets with the size of abbreviation /// number. size_t finalizeAbbreviations(bool CHILDREN_yes, OffsetsPtrVector *OffsetsList) { // Create abbreviations for output DIE. DIEAbbrev NewAbbrev = OutputDIE->generateAbbrev(); if (CHILDREN_yes) NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes); CU.assignAbbrev(NewAbbrev); OutputDIE->setAbbrevNumber(NewAbbrev.getNumber()); size_t AbbrevNumberSize = getULEB128Size(OutputDIE->getAbbrevNumber()); // Add size of abbreviation number to the offsets. if (OffsetsList != nullptr) { for (uint64_t *OffsetPtr : *OffsetsList) *OffsetPtr += AbbrevNumberSize; } return AbbrevNumberSize; } protected: template std::pair addAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm, T &&Value) { DIEValue &ValueRef = *OutputDIE->addValue(Allocator, Attr, AttrForm, std::forward(Value)); unsigned ValueSize = ValueRef.sizeOf(CU.getFormParams()); return std::pair(ValueRef, ValueSize); } // Allocator for output DIEs and values. BumpPtrAllocator &Allocator; // Unit for the output DIE. DwarfUnit &CU; // OutputDIE. DIE *OutputDIE = nullptr; }; } // end of namespace parallel } // end of namespace dwarf_linker } // end of namespace llvm #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DIEGENERATOR_H