Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- DWARFLinkerCompileUnit.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_DWARFLINKER_DWARFLINKERCOMPILEUNIT_H |
||
10 | #define LLVM_DWARFLINKER_DWARFLINKERCOMPILEUNIT_H |
||
11 | |||
12 | #include "llvm/ADT/AddressRanges.h" |
||
13 | #include "llvm/ADT/DenseMap.h" |
||
14 | #include "llvm/CodeGen/DIE.h" |
||
15 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" |
||
16 | #include <optional> |
||
17 | |||
18 | namespace llvm { |
||
19 | |||
20 | class DeclContext; |
||
21 | |||
22 | /// Mapped value in the address map is the offset to apply to the |
||
23 | /// linked address. |
||
24 | using RangesTy = AddressRangesMap<int64_t>; |
||
25 | |||
26 | // FIXME: Delete this structure. |
||
27 | struct PatchLocation { |
||
28 | DIE::value_iterator I; |
||
29 | |||
30 | PatchLocation() = default; |
||
31 | PatchLocation(DIE::value_iterator I) : I(I) {} |
||
32 | |||
33 | void set(uint64_t New) const { |
||
34 | assert(I); |
||
35 | const auto &Old = *I; |
||
36 | assert(Old.getType() == DIEValue::isInteger); |
||
37 | *I = DIEValue(Old.getAttribute(), Old.getForm(), DIEInteger(New)); |
||
38 | } |
||
39 | |||
40 | uint64_t get() const { |
||
41 | assert(I); |
||
42 | return I->getDIEInteger().getValue(); |
||
43 | } |
||
44 | }; |
||
45 | |||
46 | /// Stores all information relating to a compile unit, be it in its original |
||
47 | /// instance in the object file to its brand new cloned and generated DIE tree. |
||
48 | class CompileUnit { |
||
49 | public: |
||
50 | /// Information gathered about a DIE in the object file. |
||
51 | struct DIEInfo { |
||
52 | /// Address offset to apply to the described entity. |
||
53 | int64_t AddrAdjust; |
||
54 | |||
55 | /// ODR Declaration context. |
||
56 | DeclContext *Ctxt; |
||
57 | |||
58 | /// Cloned version of that DIE. |
||
59 | DIE *Clone; |
||
60 | |||
61 | /// The index of this DIE's parent. |
||
62 | uint32_t ParentIdx; |
||
63 | |||
64 | /// Is the DIE part of the linked output? |
||
65 | bool Keep : 1; |
||
66 | |||
67 | /// Was this DIE's entity found in the map? |
||
68 | bool InDebugMap : 1; |
||
69 | |||
70 | /// Is this a pure forward declaration we can strip? |
||
71 | bool Prune : 1; |
||
72 | |||
73 | /// Does DIE transitively refer an incomplete decl? |
||
74 | bool Incomplete : 1; |
||
75 | |||
76 | /// Is DIE in the clang module scope? |
||
77 | bool InModuleScope : 1; |
||
78 | |||
79 | /// Is ODR marking done? |
||
80 | bool ODRMarkingDone : 1; |
||
81 | |||
82 | /// Is this a reference to a DIE that hasn't been cloned yet? |
||
83 | bool UnclonedReference : 1; |
||
84 | |||
85 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
||
86 | LLVM_DUMP_METHOD void dump(); |
||
87 | #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
||
88 | }; |
||
89 | |||
90 | CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR, |
||
91 | StringRef ClangModuleName) |
||
92 | : OrigUnit(OrigUnit), ID(ID), ClangModuleName(ClangModuleName) { |
||
93 | Info.resize(OrigUnit.getNumDIEs()); |
||
94 | |||
95 | auto CUDie = OrigUnit.getUnitDIE(false); |
||
96 | if (!CUDie) { |
||
97 | HasODR = false; |
||
98 | return; |
||
99 | } |
||
100 | if (auto Lang = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language))) |
||
101 | HasODR = CanUseODR && (*Lang == dwarf::DW_LANG_C_plus_plus || |
||
102 | *Lang == dwarf::DW_LANG_C_plus_plus_03 || |
||
103 | *Lang == dwarf::DW_LANG_C_plus_plus_11 || |
||
104 | *Lang == dwarf::DW_LANG_C_plus_plus_14 || |
||
105 | *Lang == dwarf::DW_LANG_ObjC_plus_plus); |
||
106 | else |
||
107 | HasODR = false; |
||
108 | } |
||
109 | |||
110 | DWARFUnit &getOrigUnit() const { return OrigUnit; } |
||
111 | |||
112 | unsigned getUniqueID() const { return ID; } |
||
113 | |||
114 | void createOutputDIE() { NewUnit.emplace(OrigUnit.getUnitDIE().getTag()); } |
||
115 | |||
116 | DIE *getOutputUnitDIE() const { |
||
117 | if (NewUnit) |
||
118 | return &const_cast<BasicDIEUnit &>(*NewUnit).getUnitDie(); |
||
119 | return nullptr; |
||
120 | } |
||
121 | |||
122 | bool hasODR() const { return HasODR; } |
||
123 | bool isClangModule() const { return !ClangModuleName.empty(); } |
||
124 | uint16_t getLanguage(); |
||
125 | /// Return the DW_AT_LLVM_sysroot of the compile unit or an empty StringRef. |
||
126 | StringRef getSysRoot(); |
||
127 | |||
128 | const std::string &getClangModuleName() const { return ClangModuleName; } |
||
129 | |||
130 | DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; } |
||
131 | const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; } |
||
132 | |||
133 | DIEInfo &getInfo(const DWARFDie &Die) { |
||
134 | unsigned Idx = getOrigUnit().getDIEIndex(Die); |
||
135 | return Info[Idx]; |
||
136 | } |
||
137 | |||
138 | uint64_t getStartOffset() const { return StartOffset; } |
||
139 | uint64_t getNextUnitOffset() const { return NextUnitOffset; } |
||
140 | void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; } |
||
141 | |||
142 | std::optional<uint64_t> getLowPc() const { return LowPc; } |
||
143 | uint64_t getHighPc() const { return HighPc; } |
||
144 | bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); } |
||
145 | |||
146 | std::optional<PatchLocation> getUnitRangesAttribute() const { |
||
147 | return UnitRangeAttribute; |
||
148 | } |
||
149 | |||
150 | const RangesTy &getFunctionRanges() const { return Ranges; } |
||
151 | |||
152 | const std::vector<PatchLocation> &getRangesAttributes() const { |
||
153 | return RangeAttributes; |
||
154 | } |
||
155 | |||
156 | const std::vector<std::pair<PatchLocation, int64_t>> & |
||
157 | getLocationAttributes() const { |
||
158 | return LocationAttributes; |
||
159 | } |
||
160 | |||
161 | /// Mark every DIE in this unit as kept. This function also |
||
162 | /// marks variables as InDebugMap so that they appear in the |
||
163 | /// reconstructed accelerator tables. |
||
164 | void markEverythingAsKept(); |
||
165 | |||
166 | /// Compute the end offset for this unit. Must be called after the CU's DIEs |
||
167 | /// have been cloned. \returns the next unit offset (which is also the |
||
168 | /// current debug_info section size). |
||
169 | uint64_t computeNextUnitOffset(uint16_t DwarfVersion); |
||
170 | |||
171 | /// Keep track of a forward reference to DIE \p Die in \p RefUnit by \p |
||
172 | /// Attr. The attribute should be fixed up later to point to the absolute |
||
173 | /// offset of \p Die in the debug_info section or to the canonical offset of |
||
174 | /// \p Ctxt if it is non-null. |
||
175 | void noteForwardReference(DIE *Die, const CompileUnit *RefUnit, |
||
176 | DeclContext *Ctxt, PatchLocation Attr); |
||
177 | |||
178 | /// Apply all fixups recorded by noteForwardReference(). |
||
179 | void fixupForwardReferences(); |
||
180 | |||
181 | /// Add the low_pc of a label that is relocated by applying |
||
182 | /// offset \p PCOffset. |
||
183 | void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset); |
||
184 | |||
185 | /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying |
||
186 | /// offset \p PCOffset. |
||
187 | void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset); |
||
188 | |||
189 | /// Keep track of a DW_AT_range attribute that we will need to patch up later. |
||
190 | void noteRangeAttribute(const DIE &Die, PatchLocation Attr); |
||
191 | |||
192 | /// Keep track of a location attribute pointing to a location list in the |
||
193 | /// debug_loc section. |
||
194 | void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset); |
||
195 | |||
196 | /// Add a name accelerator entry for \a Die with \a Name. |
||
197 | void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name); |
||
198 | |||
199 | /// Add a name accelerator entry for \a Die with \a Name. |
||
200 | void addNameAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, |
||
201 | bool SkipPubnamesSection = false); |
||
202 | |||
203 | /// Add various accelerator entries for \p Die with \p Name which is stored |
||
204 | /// in the string table at \p Offset. \p Name must be an Objective-C |
||
205 | /// selector. |
||
206 | void addObjCAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, |
||
207 | bool SkipPubnamesSection = false); |
||
208 | |||
209 | /// Add a type accelerator entry for \p Die with \p Name which is stored in |
||
210 | /// the string table at \p Offset. |
||
211 | void addTypeAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, |
||
212 | bool ObjcClassImplementation, |
||
213 | uint32_t QualifiedNameHash); |
||
214 | |||
215 | struct AccelInfo { |
||
216 | /// Name of the entry. |
||
217 | DwarfStringPoolEntryRef Name; |
||
218 | |||
219 | /// DIE this entry describes. |
||
220 | const DIE *Die; |
||
221 | |||
222 | /// Hash of the fully qualified name. |
||
223 | uint32_t QualifiedNameHash; |
||
224 | |||
225 | /// Emit this entry only in the apple_* sections. |
||
226 | bool SkipPubSection; |
||
227 | |||
228 | /// Is this an ObjC class implementation? |
||
229 | bool ObjcClassImplementation; |
||
230 | |||
231 | AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, |
||
232 | bool SkipPubSection = false) |
||
233 | : Name(Name), Die(Die), SkipPubSection(SkipPubSection) {} |
||
234 | |||
235 | AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, |
||
236 | uint32_t QualifiedNameHash, bool ObjCClassIsImplementation) |
||
237 | : Name(Name), Die(Die), QualifiedNameHash(QualifiedNameHash), |
||
238 | SkipPubSection(false), |
||
239 | ObjcClassImplementation(ObjCClassIsImplementation) {} |
||
240 | }; |
||
241 | |||
242 | const std::vector<AccelInfo> &getPubnames() const { return Pubnames; } |
||
243 | const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; } |
||
244 | const std::vector<AccelInfo> &getNamespaces() const { return Namespaces; } |
||
245 | const std::vector<AccelInfo> &getObjC() const { return ObjC; } |
||
246 | |||
247 | MCSymbol *getLabelBegin() { return LabelBegin; } |
||
248 | void setLabelBegin(MCSymbol *S) { LabelBegin = S; } |
||
249 | |||
250 | private: |
||
251 | DWARFUnit &OrigUnit; |
||
252 | unsigned ID; |
||
253 | std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. |
||
254 | std::optional<BasicDIEUnit> NewUnit; |
||
255 | MCSymbol *LabelBegin = nullptr; |
||
256 | |||
257 | uint64_t StartOffset; |
||
258 | uint64_t NextUnitOffset; |
||
259 | |||
260 | std::optional<uint64_t> LowPc; |
||
261 | uint64_t HighPc = 0; |
||
262 | |||
263 | /// A list of attributes to fixup with the absolute offset of |
||
264 | /// a DIE in the debug_info section. |
||
265 | /// |
||
266 | /// The offsets for the attributes in this array couldn't be set while |
||
267 | /// cloning because for cross-cu forward references the target DIE's offset |
||
268 | /// isn't known you emit the reference attribute. |
||
269 | std::vector< |
||
270 | std::tuple<DIE *, const CompileUnit *, DeclContext *, PatchLocation>> |
||
271 | ForwardDIEReferences; |
||
272 | |||
273 | /// The ranges in that map are the PC ranges for functions in this unit, |
||
274 | /// associated with the PC offset to apply to the addresses to get |
||
275 | /// the linked address. |
||
276 | RangesTy Ranges; |
||
277 | |||
278 | /// The DW_AT_low_pc of each DW_TAG_label. |
||
279 | SmallDenseMap<uint64_t, uint64_t, 1> Labels; |
||
280 | |||
281 | /// DW_AT_ranges attributes to patch after we have gathered |
||
282 | /// all the unit's function addresses. |
||
283 | /// @{ |
||
284 | std::vector<PatchLocation> RangeAttributes; |
||
285 | std::optional<PatchLocation> UnitRangeAttribute; |
||
286 | /// @} |
||
287 | |||
288 | /// Location attributes that need to be transferred from the |
||
289 | /// original debug_loc section to the liked one. They are stored |
||
290 | /// along with the PC offset that is to be applied to their |
||
291 | /// function's address. |
||
292 | std::vector<std::pair<PatchLocation, int64_t>> LocationAttributes; |
||
293 | |||
294 | /// Accelerator entries for the unit, both for the pub* |
||
295 | /// sections and the apple* ones. |
||
296 | /// @{ |
||
297 | std::vector<AccelInfo> Pubnames; |
||
298 | std::vector<AccelInfo> Pubtypes; |
||
299 | std::vector<AccelInfo> Namespaces; |
||
300 | std::vector<AccelInfo> ObjC; |
||
301 | /// @} |
||
302 | |||
303 | /// Is this unit subject to the ODR rule? |
||
304 | bool HasODR; |
||
305 | |||
306 | /// The DW_AT_language of this unit. |
||
307 | uint16_t Language = 0; |
||
308 | |||
309 | /// The DW_AT_LLVM_sysroot of this unit. |
||
310 | std::string SysRoot; |
||
311 | |||
312 | /// If this is a Clang module, this holds the module's name. |
||
313 | std::string ClangModuleName; |
||
314 | }; |
||
315 | |||
316 | } // end namespace llvm |
||
317 | |||
318 | #endif // LLVM_DWARFLINKER_DWARFLINKERCOMPILEUNIT_H |