| //===- 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_DWARFLINKERPARALLEL_DIEGENERATOR_H |
| #define LLVM_LIB_DWARFLINKERPARALLEL_DIEGENERATOR_H |
| |
| #include "DWARFLinkerGlobalData.h" |
| #include "DWARFLinkerUnit.h" |
| #include "llvm/CodeGen/DIE.h" |
| #include "llvm/Support/LEB128.h" |
| |
| namespace llvm { |
| namespace dwarflinker_parallel { |
| |
| /// This class is a helper to create output DIE tree. |
| class DIEGenerator { |
| public: |
| DIEGenerator(BumpPtrAllocator &Allocator, DwarfUnit &CU) |
| : Allocator(Allocator), CU(CU) {} |
| |
| /// 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; |
| } |
| |
| /// 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<DIEValue &, size_t> 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<DIEValue &, size_t> addLocationAttribute(dwarf::Attribute Attr, |
| dwarf::Form AttrForm, |
| ArrayRef<uint8_t> Bytes) { |
| DIELoc *Loc = new (Allocator) DIELoc; |
| for (auto Byte : Bytes) |
| static_cast<DIEValueList *>(Loc)->addValue( |
| Allocator, static_cast<dwarf::Attribute>(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<DIEValue &, size_t> addBlockAttribute(dwarf::Attribute Attr, |
| dwarf::Form AttrForm, |
| ArrayRef<uint8_t> 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<DIEValueList *>(Block)->addValue( |
| Allocator, static_cast<dwarf::Attribute>(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<DIEValue &, size_t> addLocListAttribute(dwarf::Attribute Attr, |
| dwarf::Form AttrForm, |
| uint64_t Value) { |
| return addAttribute(Attr, AttrForm, DIELocList(Value)); |
| } |
| |
| /// Adds indexed string attribute. |
| std::pair<DIEValue &, size_t> 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<DIEValue &, size_t> |
| 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<DIEValue &, size_t> addInplaceString(dwarf::Attribute Attr, |
| StringRef String) { |
| DIEBlock *Block = new (Allocator) DIEBlock; |
| for (auto Byte : String.bytes()) |
| static_cast<DIEValueList *>(Block)->addValue( |
| Allocator, static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1, |
| DIEInteger(Byte)); |
| |
| static_cast<DIEValueList *>(Block)->addValue( |
| Allocator, static_cast<dwarf::Attribute>(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<DIEValue &, size_t>(ValueRef, String.size() + 1); |
| } |
| |
| /// Creates appreviations for the current DIE. Returns value of |
| /// abbreviation number. |
| size_t finalizeAbbreviations(bool CHILDREN_yes) { |
| // 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()); |
| |
| return getULEB128Size(OutputDIE->getAbbrevNumber()); |
| } |
| |
| protected: |
| template <typename T> |
| std::pair<DIEValue &, size_t> addAttribute(dwarf::Attribute Attr, |
| dwarf::Form AttrForm, T &&Value) { |
| DIEValue &ValueRef = |
| *OutputDIE->addValue(Allocator, Attr, AttrForm, std::forward<T>(Value)); |
| unsigned ValueSize = ValueRef.sizeOf(CU.getFormParams()); |
| return std::pair<DIEValue &, size_t>(ValueRef, ValueSize); |
| } |
| |
| // Allocator for output DIEs and values. |
| BumpPtrAllocator &Allocator; |
| |
| // Unit for the output DIE. |
| DwarfUnit &CU; |
| |
| // OutputDIE. |
| DIE *OutputDIE = nullptr; |
| }; |
| |
| } // end of namespace dwarflinker_parallel |
| } // end namespace llvm |
| |
| #endif // LLVM_LIB_DWARFLINKERPARALLEL_DIEGENERATOR_H |