1 | //===- DIEGenerator.h -------------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DIEGENERATOR_H |
10 | #define LLVM_LIB_DWARFLINKER_PARALLEL_DIEGENERATOR_H |
11 | |
12 | #include "DWARFLinkerGlobalData.h" |
13 | #include "DWARFLinkerUnit.h" |
14 | #include "llvm/CodeGen/DIE.h" |
15 | #include "llvm/Support/LEB128.h" |
16 | |
17 | namespace llvm { |
18 | namespace dwarf_linker { |
19 | namespace parallel { |
20 | |
21 | /// This class is a helper to create output DIE tree. |
22 | class DIEGenerator { |
23 | public: |
24 | DIEGenerator(BumpPtrAllocator &Allocator, DwarfUnit &CU) |
25 | : Allocator(Allocator), CU(CU) {} |
26 | |
27 | DIEGenerator(DIE *OutputDIE, BumpPtrAllocator &Allocator, DwarfUnit &CU) |
28 | : Allocator(Allocator), CU(CU), OutputDIE(OutputDIE) {} |
29 | |
30 | /// Creates a DIE of specified tag \p DieTag and \p OutOffset. |
31 | DIE *createDIE(dwarf::Tag DieTag, uint32_t OutOffset) { |
32 | OutputDIE = DIE::get(Alloc&: Allocator, Tag: DieTag); |
33 | |
34 | OutputDIE->setOffset(OutOffset); |
35 | |
36 | return OutputDIE; |
37 | } |
38 | |
39 | DIE *getDIE() { return OutputDIE; } |
40 | |
41 | /// Adds a specified \p Child to the current DIE. |
42 | void addChild(DIE *Child) { |
43 | assert(Child != nullptr); |
44 | assert(OutputDIE != nullptr); |
45 | |
46 | OutputDIE->addChild(Child); |
47 | } |
48 | |
49 | /// Adds specified scalar attribute to the current DIE. |
50 | std::pair<DIEValue &, size_t> addScalarAttribute(dwarf::Attribute Attr, |
51 | dwarf::Form AttrForm, |
52 | uint64_t Value) { |
53 | return addAttribute(Attr, AttrForm, Value: DIEInteger(Value)); |
54 | } |
55 | |
56 | /// Adds specified location attribute to the current DIE. |
57 | std::pair<DIEValue &, size_t> addLocationAttribute(dwarf::Attribute Attr, |
58 | dwarf::Form AttrForm, |
59 | ArrayRef<uint8_t> Bytes) { |
60 | DIELoc *Loc = new (Allocator) DIELoc; |
61 | for (auto Byte : Bytes) |
62 | static_cast<DIEValueList *>(Loc)->addValue( |
63 | Alloc&: Allocator, Attribute: static_cast<dwarf::Attribute>(0), Form: dwarf::DW_FORM_data1, |
64 | Value: DIEInteger(Byte)); |
65 | Loc->setSize(Bytes.size()); |
66 | |
67 | return addAttribute(Attr, AttrForm, Value&: Loc); |
68 | } |
69 | |
70 | /// Adds specified block or exprloc attribute to the current DIE. |
71 | std::pair<DIEValue &, size_t> addBlockAttribute(dwarf::Attribute Attr, |
72 | dwarf::Form AttrForm, |
73 | ArrayRef<uint8_t> Bytes) { |
74 | // The expression location data might be updated and exceed the original |
75 | // size. Check whether the new data fits into the original form. |
76 | assert((AttrForm == dwarf::DW_FORM_block) || |
77 | (AttrForm == dwarf::DW_FORM_exprloc) || |
78 | (AttrForm == dwarf::DW_FORM_block1 && Bytes.size() <= UINT8_MAX) || |
79 | (AttrForm == dwarf::DW_FORM_block2 && Bytes.size() <= UINT16_MAX) || |
80 | (AttrForm == dwarf::DW_FORM_block4 && Bytes.size() <= UINT32_MAX)); |
81 | |
82 | DIEBlock *Block = new (Allocator) DIEBlock; |
83 | for (auto Byte : Bytes) |
84 | static_cast<DIEValueList *>(Block)->addValue( |
85 | Alloc&: Allocator, Attribute: static_cast<dwarf::Attribute>(0), Form: dwarf::DW_FORM_data1, |
86 | Value: DIEInteger(Byte)); |
87 | Block->setSize(Bytes.size()); |
88 | |
89 | return addAttribute(Attr, AttrForm, Value&: Block); |
90 | } |
91 | |
92 | /// Adds specified location list attribute to the current DIE. |
93 | std::pair<DIEValue &, size_t> addLocListAttribute(dwarf::Attribute Attr, |
94 | dwarf::Form AttrForm, |
95 | uint64_t Value) { |
96 | return addAttribute(Attr, AttrForm, Value: DIELocList(Value)); |
97 | } |
98 | |
99 | /// Adds indexed string attribute. |
100 | std::pair<DIEValue &, size_t> addIndexedStringAttribute(dwarf::Attribute Attr, |
101 | dwarf::Form AttrForm, |
102 | uint64_t Idx) { |
103 | assert(AttrForm == dwarf::DW_FORM_strx); |
104 | return addAttribute(Attr, AttrForm, Value: DIEInteger(Idx)); |
105 | } |
106 | |
107 | /// Adds string attribute with dummy offset to the current DIE. |
108 | std::pair<DIEValue &, size_t> |
109 | addStringPlaceholderAttribute(dwarf::Attribute Attr, dwarf::Form AttrForm) { |
110 | assert(AttrForm == dwarf::DW_FORM_strp || |
111 | AttrForm == dwarf::DW_FORM_line_strp); |
112 | return addAttribute(Attr, AttrForm, Value: DIEInteger(0xBADDEF)); |
113 | } |
114 | |
115 | /// Adds inplace string attribute to the current DIE. |
116 | std::pair<DIEValue &, size_t> addInplaceString(dwarf::Attribute Attr, |
117 | StringRef String) { |
118 | DIEBlock *Block = new (Allocator) DIEBlock; |
119 | for (auto Byte : String.bytes()) |
120 | static_cast<DIEValueList *>(Block)->addValue( |
121 | Alloc&: Allocator, Attribute: static_cast<dwarf::Attribute>(0), Form: dwarf::DW_FORM_data1, |
122 | Value: DIEInteger(Byte)); |
123 | |
124 | static_cast<DIEValueList *>(Block)->addValue( |
125 | Alloc&: Allocator, Attribute: static_cast<dwarf::Attribute>(0), Form: dwarf::DW_FORM_data1, |
126 | Value: DIEInteger(0)); |
127 | Block->setSize(String.size() + 1); |
128 | |
129 | DIEValue &ValueRef = |
130 | *OutputDIE->addValue(Alloc&: Allocator, Attribute: Attr, Form: dwarf::DW_FORM_string, Value&: Block); |
131 | return std::pair<DIEValue &, size_t>(ValueRef, String.size() + 1); |
132 | } |
133 | |
134 | /// Creates appreviations for the current DIE. Returns value of |
135 | /// abbreviation number. Updates offsets with the size of abbreviation |
136 | /// number. |
137 | size_t finalizeAbbreviations(bool CHILDREN_yes, |
138 | OffsetsPtrVector *OffsetsList) { |
139 | // Create abbreviations for output DIE. |
140 | DIEAbbrev NewAbbrev = OutputDIE->generateAbbrev(); |
141 | if (CHILDREN_yes) |
142 | NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes); |
143 | |
144 | CU.assignAbbrev(Abbrev&: NewAbbrev); |
145 | OutputDIE->setAbbrevNumber(NewAbbrev.getNumber()); |
146 | |
147 | size_t AbbrevNumberSize = getULEB128Size(Value: OutputDIE->getAbbrevNumber()); |
148 | |
149 | // Add size of abbreviation number to the offsets. |
150 | if (OffsetsList != nullptr) { |
151 | for (uint64_t *OffsetPtr : *OffsetsList) |
152 | *OffsetPtr += AbbrevNumberSize; |
153 | } |
154 | |
155 | return AbbrevNumberSize; |
156 | } |
157 | |
158 | protected: |
159 | template <typename T> |
160 | std::pair<DIEValue &, size_t> addAttribute(dwarf::Attribute Attr, |
161 | dwarf::Form AttrForm, T &&Value) { |
162 | DIEValue &ValueRef = |
163 | *OutputDIE->addValue(Allocator, Attr, AttrForm, std::forward<T>(Value)); |
164 | unsigned ValueSize = ValueRef.sizeOf(FormParams: CU.getFormParams()); |
165 | return std::pair<DIEValue &, size_t>(ValueRef, ValueSize); |
166 | } |
167 | |
168 | // Allocator for output DIEs and values. |
169 | BumpPtrAllocator &Allocator; |
170 | |
171 | // Unit for the output DIE. |
172 | DwarfUnit &CU; |
173 | |
174 | // OutputDIE. |
175 | DIE *OutputDIE = nullptr; |
176 | }; |
177 | |
178 | } // end of namespace parallel |
179 | } // end of namespace dwarf_linker |
180 | } // end of namespace llvm |
181 | |
182 | #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DIEGENERATOR_H |
183 | |