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_LIB_DWARFLINKER_PARALLEL_DWARFLINKERCOMPILEUNIT_H |
10 | #define LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERCOMPILEUNIT_H |
11 | |
12 | #include "DWARFLinkerUnit.h" |
13 | #include "llvm/DWARFLinker/DWARFFile.h" |
14 | #include <optional> |
15 | |
16 | namespace llvm { |
17 | namespace dwarf_linker { |
18 | namespace parallel { |
19 | |
20 | using OffsetToUnitTy = function_ref<CompileUnit *(uint64_t Offset)>; |
21 | |
22 | struct AttributesInfo; |
23 | class SyntheticTypeNameBuilder; |
24 | class DIEGenerator; |
25 | class TypeUnit; |
26 | class DependencyTracker; |
27 | |
28 | class CompileUnit; |
29 | |
30 | /// This is a helper structure which keeps a debug info entry |
31 | /// with it's containing compilation unit. |
32 | struct UnitEntryPairTy { |
33 | UnitEntryPairTy() = default; |
34 | UnitEntryPairTy(CompileUnit *CU, const DWARFDebugInfoEntry *DieEntry) |
35 | : CU(CU), DieEntry(DieEntry) {} |
36 | |
37 | CompileUnit *CU = nullptr; |
38 | const DWARFDebugInfoEntry *DieEntry = nullptr; |
39 | |
40 | UnitEntryPairTy getNamespaceOrigin(); |
41 | std::optional<UnitEntryPairTy> getParent(); |
42 | }; |
43 | |
44 | enum ResolveInterCUReferencesMode : bool { |
45 | Resolve = true, |
46 | AvoidResolving = false, |
47 | }; |
48 | |
49 | /// Stores all information related to a compile unit, be it in its original |
50 | /// instance of the object file or its brand new cloned and generated DIE tree. |
51 | /// NOTE: we need alignment of at least 8 bytes as we use |
52 | /// PointerIntPair<CompileUnit *, 3> in the DependencyTracker.h |
53 | class alignas(8) CompileUnit : public DwarfUnit { |
54 | public: |
55 | /// The stages of new compile unit processing. |
56 | enum class Stage : uint8_t { |
57 | /// Created, linked with input DWARF file. |
58 | CreatedNotLoaded = 0, |
59 | |
60 | /// Input DWARF is loaded. |
61 | Loaded, |
62 | |
63 | /// Input DWARF is analysed(DIEs pointing to the real code section are |
64 | /// discovered, type names are assigned if ODR is requested). |
65 | LivenessAnalysisDone, |
66 | |
67 | /// Check if dependencies have incompatible placement. |
68 | /// If that is the case modify placement to be compatible. |
69 | UpdateDependenciesCompleteness, |
70 | |
71 | /// Type names assigned to DIEs. |
72 | TypeNamesAssigned, |
73 | |
74 | /// Output DWARF is generated. |
75 | Cloned, |
76 | |
77 | /// Offsets inside patch records are updated. |
78 | PatchesUpdated, |
79 | |
80 | /// Resources(Input DWARF, Output DWARF tree) are released. |
81 | Cleaned, |
82 | |
83 | /// Compile Unit should be skipped |
84 | Skipped |
85 | }; |
86 | |
87 | CompileUnit(LinkingGlobalData &GlobalData, unsigned ID, |
88 | StringRef ClangModuleName, DWARFFile &File, |
89 | OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format, |
90 | llvm::endianness Endianess); |
91 | |
92 | CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, unsigned ID, |
93 | StringRef ClangModuleName, DWARFFile &File, |
94 | OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format, |
95 | llvm::endianness Endianess); |
96 | |
97 | /// Returns stage of overall processing. |
98 | Stage getStage() const { return Stage; } |
99 | |
100 | /// Set stage of overall processing. |
101 | void setStage(Stage Stage) { this->Stage = Stage; } |
102 | |
103 | /// Loads unit line table. |
104 | void loadLineTable(); |
105 | |
106 | /// Returns name of the file for the \p FileIdx |
107 | /// from the unit`s line table. |
108 | StringEntry *getFileName(unsigned FileIdx, StringPool &GlobalStrings); |
109 | |
110 | /// Returns DWARFFile containing this compile unit. |
111 | const DWARFFile &getContaingFile() const { return File; } |
112 | |
113 | /// Load DIEs of input compilation unit. \returns true if input DIEs |
114 | /// successfully loaded. |
115 | bool loadInputDIEs(); |
116 | |
117 | /// Reset compile units data(results of liveness analysis, clonning) |
118 | /// if current stage greater than Stage::Loaded. We need to reset data |
119 | /// as we are going to repeat stages. |
120 | void maybeResetToLoadedStage(); |
121 | |
122 | /// Collect references to parseable Swift interfaces in imported |
123 | /// DW_TAG_module blocks. |
124 | void analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry); |
125 | |
126 | /// Navigate DWARF tree and set die properties. |
127 | void analyzeDWARFStructure() { |
128 | analyzeDWARFStructureRec(DieEntry: getUnitDIE().getDebugInfoEntry(), IsODRUnavailableFunctionScope: false); |
129 | } |
130 | |
131 | /// Cleanup unneeded resources after compile unit is cloned. |
132 | void cleanupDataAfterClonning(); |
133 | |
134 | /// After cloning stage the output DIEs offsets are deallocated. |
135 | /// This method copies output offsets for referenced DIEs into DIEs patches. |
136 | void updateDieRefPatchesWithClonedOffsets(); |
137 | |
138 | /// Search for subprograms and variables referencing live code and discover |
139 | /// dependend DIEs. Mark live DIEs, set placement for DIEs. |
140 | bool resolveDependenciesAndMarkLiveness( |
141 | bool InterCUProcessingStarted, |
142 | std::atomic<bool> &HasNewInterconnectedCUs); |
143 | |
144 | /// Check dependend DIEs for incompatible placement. |
145 | /// Make placement to be consistent. |
146 | bool updateDependenciesCompleteness(); |
147 | |
148 | /// Check DIEs to have a consistent marking(keep marking, placement marking). |
149 | void verifyDependencies(); |
150 | |
151 | /// Search for type entries and assign names. |
152 | Error assignTypeNames(TypePool &TypePoolRef); |
153 | |
154 | /// Kinds of placement for the output die. |
155 | enum DieOutputPlacement : uint8_t { |
156 | NotSet = 0, |
157 | |
158 | /// Corresponding DIE goes to the type table only. |
159 | TypeTable = 1, |
160 | |
161 | /// Corresponding DIE goes to the plain dwarf only. |
162 | PlainDwarf = 2, |
163 | |
164 | /// Corresponding DIE goes to type table and to plain dwarf. |
165 | Both = 3, |
166 | }; |
167 | |
168 | /// Information gathered about source DIEs. |
169 | struct DIEInfo { |
170 | DIEInfo() = default; |
171 | DIEInfo(const DIEInfo &Other) { Flags = Other.Flags.load(); } |
172 | DIEInfo &operator=(const DIEInfo &Other) { |
173 | Flags = Other.Flags.load(); |
174 | return *this; |
175 | } |
176 | |
177 | /// Data member keeping various flags. |
178 | std::atomic<uint16_t> Flags = {0}; |
179 | |
180 | /// \returns Placement kind for the corresponding die. |
181 | DieOutputPlacement getPlacement() const { |
182 | return DieOutputPlacement(Flags & 0x7); |
183 | } |
184 | |
185 | /// Sets Placement kind for the corresponding die. |
186 | void setPlacement(DieOutputPlacement Placement) { |
187 | auto InputData = Flags.load(); |
188 | while (!Flags.compare_exchange_weak(i1&: InputData, |
189 | i2: ((InputData & ~0x7) | Placement))) { |
190 | } |
191 | } |
192 | |
193 | /// Unsets Placement kind for the corresponding die. |
194 | void unsetPlacement() { |
195 | auto InputData = Flags.load(); |
196 | while (!Flags.compare_exchange_weak(i1&: InputData, i2: (InputData & ~0x7))) { |
197 | } |
198 | } |
199 | |
200 | /// Sets Placement kind for the corresponding die. |
201 | bool setPlacementIfUnset(DieOutputPlacement Placement) { |
202 | auto InputData = Flags.load(); |
203 | if ((InputData & 0x7) == NotSet) |
204 | if (Flags.compare_exchange_weak(i1&: InputData, i2: (InputData | Placement))) |
205 | return true; |
206 | |
207 | return false; |
208 | } |
209 | |
210 | #define SINGLE_FLAG_METHODS_SET(Name, Value) \ |
211 | bool get##Name() const { return Flags & Value; } \ |
212 | void set##Name() { \ |
213 | auto InputData = Flags.load(); \ |
214 | while (!Flags.compare_exchange_weak(InputData, InputData | Value)) { \ |
215 | } \ |
216 | } \ |
217 | void unset##Name() { \ |
218 | auto InputData = Flags.load(); \ |
219 | while (!Flags.compare_exchange_weak(InputData, InputData & ~Value)) { \ |
220 | } \ |
221 | } |
222 | |
223 | /// DIE is a part of the linked output. |
224 | SINGLE_FLAG_METHODS_SET(Keep, 0x08) |
225 | |
226 | /// DIE has children which are part of the linked output. |
227 | SINGLE_FLAG_METHODS_SET(KeepPlainChildren, 0x10) |
228 | |
229 | /// DIE has children which are part of the type table. |
230 | SINGLE_FLAG_METHODS_SET(KeepTypeChildren, 0x20) |
231 | |
232 | /// DIE is in module scope. |
233 | SINGLE_FLAG_METHODS_SET(IsInMouduleScope, 0x40) |
234 | |
235 | /// DIE is in function scope. |
236 | SINGLE_FLAG_METHODS_SET(IsInFunctionScope, 0x80) |
237 | |
238 | /// DIE is in anonymous namespace scope. |
239 | SINGLE_FLAG_METHODS_SET(IsInAnonNamespaceScope, 0x100) |
240 | |
241 | /// DIE is available for ODR type deduplication. |
242 | SINGLE_FLAG_METHODS_SET(ODRAvailable, 0x200) |
243 | |
244 | /// Track liveness for the DIE. |
245 | SINGLE_FLAG_METHODS_SET(TrackLiveness, 0x400) |
246 | |
247 | /// Track liveness for the DIE. |
248 | SINGLE_FLAG_METHODS_SET(HasAnAddress, 0x800) |
249 | |
250 | void unsetFlagsWhichSetDuringLiveAnalysis() { |
251 | auto InputData = Flags.load(); |
252 | while (!Flags.compare_exchange_weak( |
253 | i1&: InputData, i2: InputData & ~(0x7 | 0x8 | 0x10 | 0x20))) { |
254 | } |
255 | } |
256 | |
257 | /// Erase all flags. |
258 | void eraseData() { Flags = 0; } |
259 | |
260 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
261 | LLVM_DUMP_METHOD void dump(); |
262 | #endif |
263 | |
264 | bool needToPlaceInTypeTable() const { |
265 | return (getKeep() && (getPlacement() == CompileUnit::TypeTable || |
266 | getPlacement() == CompileUnit::Both)) || |
267 | getKeepTypeChildren(); |
268 | } |
269 | |
270 | bool needToKeepInPlainDwarf() const { |
271 | return (getKeep() && (getPlacement() == CompileUnit::PlainDwarf || |
272 | getPlacement() == CompileUnit::Both)) || |
273 | getKeepPlainChildren(); |
274 | } |
275 | }; |
276 | |
277 | /// \defgroup Group of functions returning DIE info. |
278 | /// |
279 | /// @{ |
280 | |
281 | /// \p Idx index of the DIE. |
282 | /// \returns DieInfo descriptor. |
283 | DIEInfo &getDIEInfo(unsigned Idx) { return DieInfoArray[Idx]; } |
284 | |
285 | /// \p Idx index of the DIE. |
286 | /// \returns DieInfo descriptor. |
287 | const DIEInfo &getDIEInfo(unsigned Idx) const { return DieInfoArray[Idx]; } |
288 | |
289 | /// \p Idx index of the DIE. |
290 | /// \returns DieInfo descriptor. |
291 | DIEInfo &getDIEInfo(const DWARFDebugInfoEntry *Entry) { |
292 | return DieInfoArray[getOrigUnit().getDIEIndex(Die: Entry)]; |
293 | } |
294 | |
295 | /// \p Idx index of the DIE. |
296 | /// \returns DieInfo descriptor. |
297 | const DIEInfo &getDIEInfo(const DWARFDebugInfoEntry *Entry) const { |
298 | return DieInfoArray[getOrigUnit().getDIEIndex(Die: Entry)]; |
299 | } |
300 | |
301 | /// \p Die |
302 | /// \returns PlainDieInfo descriptor. |
303 | DIEInfo &getDIEInfo(const DWARFDie &Die) { |
304 | return DieInfoArray[getOrigUnit().getDIEIndex(D: Die)]; |
305 | } |
306 | |
307 | /// \p Die |
308 | /// \returns PlainDieInfo descriptor. |
309 | const DIEInfo &getDIEInfo(const DWARFDie &Die) const { |
310 | return DieInfoArray[getOrigUnit().getDIEIndex(D: Die)]; |
311 | } |
312 | |
313 | /// \p Idx index of the DIE. |
314 | /// \returns DieInfo descriptor. |
315 | uint64_t getDieOutOffset(uint32_t Idx) { |
316 | return reinterpret_cast<std::atomic<uint64_t> *>(&OutDieOffsetArray[Idx]) |
317 | ->load(); |
318 | } |
319 | |
320 | /// \p Idx index of the DIE. |
321 | /// \returns type entry. |
322 | TypeEntry *getDieTypeEntry(uint32_t Idx) { |
323 | return reinterpret_cast<std::atomic<TypeEntry *> *>(&TypeEntries[Idx]) |
324 | ->load(); |
325 | } |
326 | |
327 | /// \p InputDieEntry debug info entry. |
328 | /// \returns DieInfo descriptor. |
329 | uint64_t getDieOutOffset(const DWARFDebugInfoEntry *InputDieEntry) { |
330 | return reinterpret_cast<std::atomic<uint64_t> *>( |
331 | &OutDieOffsetArray[getOrigUnit().getDIEIndex(Die: InputDieEntry)]) |
332 | ->load(); |
333 | } |
334 | |
335 | /// \p InputDieEntry debug info entry. |
336 | /// \returns type entry. |
337 | TypeEntry *getDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry) { |
338 | return reinterpret_cast<std::atomic<TypeEntry *> *>( |
339 | &TypeEntries[getOrigUnit().getDIEIndex(Die: InputDieEntry)]) |
340 | ->load(); |
341 | } |
342 | |
343 | /// \p Idx index of the DIE. |
344 | /// \returns DieInfo descriptor. |
345 | void rememberDieOutOffset(uint32_t Idx, uint64_t Offset) { |
346 | reinterpret_cast<std::atomic<uint64_t> *>(&OutDieOffsetArray[Idx]) |
347 | ->store(i: Offset); |
348 | } |
349 | |
350 | /// \p Idx index of the DIE. |
351 | /// \p Type entry. |
352 | void setDieTypeEntry(uint32_t Idx, TypeEntry *Entry) { |
353 | reinterpret_cast<std::atomic<TypeEntry *> *>(&TypeEntries[Idx]) |
354 | ->store(p: Entry); |
355 | } |
356 | |
357 | /// \p InputDieEntry debug info entry. |
358 | /// \p Type entry. |
359 | void setDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry, |
360 | TypeEntry *Entry) { |
361 | reinterpret_cast<std::atomic<TypeEntry *> *>( |
362 | &TypeEntries[getOrigUnit().getDIEIndex(Die: InputDieEntry)]) |
363 | ->store(p: Entry); |
364 | } |
365 | |
366 | /// @} |
367 | |
368 | /// Returns value of DW_AT_low_pc attribute. |
369 | std::optional<uint64_t> getLowPc() const { return LowPc; } |
370 | |
371 | /// Returns value of DW_AT_high_pc attribute. |
372 | uint64_t getHighPc() const { return HighPc; } |
373 | |
374 | /// Returns true if there is a label corresponding to the specified \p Addr. |
375 | bool hasLabelAt(uint64_t Addr) const { return Labels.count(Val: Addr); } |
376 | |
377 | /// Add the low_pc of a label that is relocated by applying |
378 | /// offset \p PCOffset. |
379 | void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset); |
380 | |
381 | /// Resolve the DIE attribute reference that has been extracted in \p |
382 | /// RefValue. The resulting DIE might be in another CompileUnit. |
383 | /// \returns referenced die and corresponding compilation unit. |
384 | /// compilation unit is null if reference could not be resolved. |
385 | std::optional<UnitEntryPairTy> |
386 | resolveDIEReference(const DWARFFormValue &RefValue, |
387 | ResolveInterCUReferencesMode CanResolveInterCUReferences); |
388 | |
389 | std::optional<UnitEntryPairTy> |
390 | resolveDIEReference(const DWARFDebugInfoEntry *DieEntry, |
391 | dwarf::Attribute Attr, |
392 | ResolveInterCUReferencesMode CanResolveInterCUReferences); |
393 | |
394 | /// @} |
395 | |
396 | /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying |
397 | /// offset \p PCOffset. |
398 | void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset); |
399 | |
400 | /// Returns function ranges of this unit. |
401 | const RangesTy &getFunctionRanges() const { return Ranges; } |
402 | |
403 | /// Clone and emit this compilation unit. |
404 | Error |
405 | cloneAndEmit(std::optional<std::reference_wrapper<const Triple>> TargetTriple, |
406 | TypeUnit *ArtificialTypeUnit); |
407 | |
408 | /// Clone and emit debug locations(.debug_loc/.debug_loclists). |
409 | Error cloneAndEmitDebugLocations(); |
410 | |
411 | /// Clone and emit ranges. |
412 | Error cloneAndEmitRanges(); |
413 | |
414 | /// Clone and emit debug macros(.debug_macinfo/.debug_macro). |
415 | Error cloneAndEmitDebugMacro(); |
416 | |
417 | // Clone input DIE entry. |
418 | std::pair<DIE *, TypeEntry *> |
419 | cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, |
420 | TypeEntry *ClonedParentTypeDIE, uint64_t OutOffset, |
421 | std::optional<int64_t> FuncAddressAdjustment, |
422 | std::optional<int64_t> VarAddressAdjustment, |
423 | BumpPtrAllocator &Allocator, TypeUnit *ArtificialTypeUnit); |
424 | |
425 | // Clone and emit line table. |
426 | Error cloneAndEmitLineTable(const Triple &TargetTriple); |
427 | |
428 | /// Clone attribute location axpression. |
429 | void cloneDieAttrExpression(const DWARFExpression &InputExpression, |
430 | SmallVectorImpl<uint8_t> &OutputExpression, |
431 | SectionDescriptor &Section, |
432 | std::optional<int64_t> VarAddressAdjustment, |
433 | OffsetsPtrVector &PatchesOffsets); |
434 | |
435 | /// Returns index(inside .debug_addr) of an address. |
436 | uint64_t getDebugAddrIndex(uint64_t Addr) { |
437 | return DebugAddrIndexMap.getValueIndex(Value: Addr); |
438 | } |
439 | |
440 | /// Returns directory and file from the line table by index. |
441 | std::optional<std::pair<StringRef, StringRef>> |
442 | getDirAndFilenameFromLineTable(const DWARFFormValue &FileIdxValue); |
443 | |
444 | /// Returns directory and file from the line table by index. |
445 | std::optional<std::pair<StringRef, StringRef>> |
446 | getDirAndFilenameFromLineTable(uint64_t FileIdx); |
447 | |
448 | /// \defgroup Helper methods to access OrigUnit. |
449 | /// |
450 | /// @{ |
451 | |
452 | /// Returns paired compile unit from input DWARF. |
453 | DWARFUnit &getOrigUnit() const { |
454 | assert(OrigUnit != nullptr); |
455 | return *OrigUnit; |
456 | } |
457 | |
458 | const DWARFDebugInfoEntry * |
459 | getFirstChildEntry(const DWARFDebugInfoEntry *Die) const { |
460 | assert(OrigUnit != nullptr); |
461 | return OrigUnit->getFirstChildEntry(Die); |
462 | } |
463 | |
464 | const DWARFDebugInfoEntry * |
465 | getSiblingEntry(const DWARFDebugInfoEntry *Die) const { |
466 | assert(OrigUnit != nullptr); |
467 | return OrigUnit->getSiblingEntry(Die); |
468 | } |
469 | |
470 | DWARFDie getParent(const DWARFDebugInfoEntry *Die) { |
471 | assert(OrigUnit != nullptr); |
472 | return OrigUnit->getParent(Die); |
473 | } |
474 | |
475 | DWARFDie getDIEAtIndex(unsigned Index) { |
476 | assert(OrigUnit != nullptr); |
477 | return OrigUnit->getDIEAtIndex(Index); |
478 | } |
479 | |
480 | const DWARFDebugInfoEntry *getDebugInfoEntry(unsigned Index) const { |
481 | assert(OrigUnit != nullptr); |
482 | return OrigUnit->getDebugInfoEntry(Index); |
483 | } |
484 | |
485 | DWARFDie getUnitDIE(bool = true) { |
486 | assert(OrigUnit != nullptr); |
487 | return OrigUnit->getUnitDIE(ExtractUnitDIEOnly); |
488 | } |
489 | |
490 | DWARFDie getDIE(const DWARFDebugInfoEntry *Die) { |
491 | assert(OrigUnit != nullptr); |
492 | return DWARFDie(OrigUnit, Die); |
493 | } |
494 | |
495 | uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) const { |
496 | assert(OrigUnit != nullptr); |
497 | return OrigUnit->getDIEIndex(Die); |
498 | } |
499 | |
500 | uint32_t getDIEIndex(const DWARFDie &Die) const { |
501 | assert(OrigUnit != nullptr); |
502 | return OrigUnit->getDIEIndex(D: Die); |
503 | } |
504 | |
505 | std::optional<DWARFFormValue> find(uint32_t DieIdx, |
506 | ArrayRef<dwarf::Attribute> Attrs) const { |
507 | assert(OrigUnit != nullptr); |
508 | return find(Die: OrigUnit->getDebugInfoEntry(Index: DieIdx), Attrs); |
509 | } |
510 | |
511 | std::optional<DWARFFormValue> find(const DWARFDebugInfoEntry *Die, |
512 | ArrayRef<dwarf::Attribute> Attrs) const { |
513 | if (!Die) |
514 | return std::nullopt; |
515 | auto AbbrevDecl = Die->getAbbreviationDeclarationPtr(); |
516 | if (AbbrevDecl) { |
517 | for (auto Attr : Attrs) { |
518 | if (auto Value = AbbrevDecl->getAttributeValue(DIEOffset: Die->getOffset(), Attr, |
519 | U: *OrigUnit)) |
520 | return Value; |
521 | } |
522 | } |
523 | return std::nullopt; |
524 | } |
525 | |
526 | std::optional<uint32_t> getDIEIndexForOffset(uint64_t Offset) { |
527 | return OrigUnit->getDIEIndexForOffset(Offset); |
528 | } |
529 | |
530 | /// @} |
531 | |
532 | /// \defgroup Methods used for reporting warnings and errors: |
533 | /// |
534 | /// @{ |
535 | |
536 | void warn(const Twine &Warning, const DWARFDie *DIE = nullptr) { |
537 | GlobalData.warn(Warning, Context: getUnitName(), DIE); |
538 | } |
539 | |
540 | void warn(Error Warning, const DWARFDie *DIE = nullptr) { |
541 | handleAllErrors(E: std::move(Warning), Handlers: [&](ErrorInfoBase &Info) { |
542 | GlobalData.warn(Warning: Info.message(), Context: getUnitName(), DIE); |
543 | }); |
544 | } |
545 | |
546 | void warn(const Twine &Warning, const DWARFDebugInfoEntry *DieEntry) { |
547 | if (DieEntry != nullptr) { |
548 | DWARFDie DIE(&getOrigUnit(), DieEntry); |
549 | GlobalData.warn(Warning, Context: getUnitName(), DIE: &DIE); |
550 | return; |
551 | } |
552 | |
553 | GlobalData.warn(Warning, Context: getUnitName()); |
554 | } |
555 | |
556 | void error(const Twine &Err, const DWARFDie *DIE = nullptr) { |
557 | GlobalData.warn(Warning: Err, Context: getUnitName(), DIE); |
558 | } |
559 | |
560 | void error(Error Err, const DWARFDie *DIE = nullptr) { |
561 | handleAllErrors(E: std::move(Err), Handlers: [&](ErrorInfoBase &Info) { |
562 | GlobalData.error(Err: Info.message(), Context: getUnitName(), DIE); |
563 | }); |
564 | } |
565 | |
566 | /// @} |
567 | |
568 | /// Save specified accelerator info \p Info. |
569 | void saveAcceleratorInfo(const DwarfUnit::AccelInfo &Info) { |
570 | AcceleratorRecords.add(Item: Info); |
571 | } |
572 | |
573 | /// Enumerates all units accelerator records. |
574 | void |
575 | forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) override { |
576 | AcceleratorRecords.forEach(Handler); |
577 | } |
578 | |
579 | /// Output unit selector. |
580 | class OutputUnitVariantPtr { |
581 | public: |
582 | OutputUnitVariantPtr(CompileUnit *U); |
583 | OutputUnitVariantPtr(TypeUnit *U); |
584 | |
585 | /// Accessor for common functionality. |
586 | DwarfUnit *operator->(); |
587 | |
588 | bool isCompileUnit(); |
589 | |
590 | bool isTypeUnit(); |
591 | |
592 | /// Returns CompileUnit if applicable. |
593 | CompileUnit *getAsCompileUnit(); |
594 | |
595 | /// Returns TypeUnit if applicable. |
596 | TypeUnit *getAsTypeUnit(); |
597 | |
598 | protected: |
599 | PointerUnion<CompileUnit *, TypeUnit *> Ptr; |
600 | }; |
601 | |
602 | private: |
603 | /// Navigate DWARF tree recursively and set die properties. |
604 | void analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry, |
605 | bool IsODRUnavailableFunctionScope); |
606 | |
607 | struct LinkedLocationExpressionsWithOffsetPatches { |
608 | DWARFLocationExpression Expression; |
609 | OffsetsPtrVector Patches; |
610 | }; |
611 | using LinkedLocationExpressionsVector = |
612 | SmallVector<LinkedLocationExpressionsWithOffsetPatches>; |
613 | |
614 | /// Emit debug locations. |
615 | void emitLocations(DebugSectionKind LocationSectionKind); |
616 | |
617 | /// Emit location list header. |
618 | uint64_t (SectionDescriptor &OutLocationSection); |
619 | |
620 | /// Emit location list fragment. |
621 | uint64_t emitLocListFragment( |
622 | const LinkedLocationExpressionsVector &LinkedLocationExpression, |
623 | SectionDescriptor &OutLocationSection); |
624 | |
625 | /// Emit the .debug_addr section fragment for current unit. |
626 | Error emitDebugAddrSection(); |
627 | |
628 | /// Emit .debug_aranges. |
629 | void emitAranges(AddressRanges &LinkedFunctionRanges); |
630 | |
631 | /// Clone and emit .debug_ranges/.debug_rnglists. |
632 | void cloneAndEmitRangeList(DebugSectionKind RngSectionKind, |
633 | AddressRanges &LinkedFunctionRanges); |
634 | |
635 | /// Emit range list header. |
636 | uint64_t (SectionDescriptor &OutRangeSection); |
637 | |
638 | /// Emit range list fragment. |
639 | void emitRangeListFragment(const AddressRanges &LinkedRanges, |
640 | SectionDescriptor &OutRangeSection); |
641 | |
642 | /// Insert the new line info sequence \p Seq into the current |
643 | /// set of already linked line info \p Rows. |
644 | void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq, |
645 | std::vector<DWARFDebugLine::Row> &Rows); |
646 | |
647 | /// Emits body for both macro sections. |
648 | void emitMacroTableImpl(const DWARFDebugMacro *MacroTable, |
649 | uint64_t OffsetToMacroTable, bool ); |
650 | |
651 | /// Creates DIE which would be placed into the "Plain" compile unit. |
652 | DIE *createPlainDIEandCloneAttributes( |
653 | const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator, |
654 | uint64_t &OutOffset, std::optional<int64_t> &FuncAddressAdjustment, |
655 | std::optional<int64_t> &VarAddressAdjustment); |
656 | |
657 | /// Creates DIE which would be placed into the "Type" compile unit. |
658 | TypeEntry *createTypeDIEandCloneAttributes( |
659 | const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator, |
660 | TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit); |
661 | |
662 | /// Create output DIE inside specified \p TypeDescriptor. |
663 | DIE *allocateTypeDie(TypeEntryBody *TypeDescriptor, |
664 | DIEGenerator &TypeDIEGenerator, dwarf::Tag DieTag, |
665 | bool IsDeclaration, bool IsParentDeclaration); |
666 | |
667 | /// Enumerate \p DieEntry children and assign names for them. |
668 | Error assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry, |
669 | SyntheticTypeNameBuilder &NameBuilder); |
670 | |
671 | /// DWARFFile containing this compile unit. |
672 | DWARFFile &File; |
673 | |
674 | /// Pointer to the paired compile unit from the input DWARF. |
675 | DWARFUnit *OrigUnit = nullptr; |
676 | |
677 | /// The DW_AT_language of this unit. |
678 | std::optional<uint16_t> Language; |
679 | |
680 | /// Line table for this unit. |
681 | const DWARFDebugLine::LineTable *LineTablePtr = nullptr; |
682 | |
683 | /// Cached resolved paths from the line table. |
684 | /// The key is <UniqueUnitID, FileIdx>. |
685 | using ResolvedPathsMap = DenseMap<unsigned, StringEntry *>; |
686 | ResolvedPathsMap ResolvedFullPaths; |
687 | StringMap<StringEntry *> ResolvedParentPaths; |
688 | |
689 | /// Maps an address into the index inside .debug_addr section. |
690 | IndexedValuesMap<uint64_t> DebugAddrIndexMap; |
691 | |
692 | std::unique_ptr<DependencyTracker> Dependencies; |
693 | |
694 | /// \defgroup Data Members accessed asinchronously. |
695 | /// |
696 | /// @{ |
697 | OffsetToUnitTy getUnitFromOffset; |
698 | |
699 | std::optional<uint64_t> LowPc; |
700 | uint64_t HighPc = 0; |
701 | |
702 | /// Flag indicating whether type de-duplication is forbidden. |
703 | bool NoODR = true; |
704 | |
705 | /// The ranges in that map are the PC ranges for functions in this unit, |
706 | /// associated with the PC offset to apply to the addresses to get |
707 | /// the linked address. |
708 | RangesTy Ranges; |
709 | std::mutex RangesMutex; |
710 | |
711 | /// The DW_AT_low_pc of each DW_TAG_label. |
712 | using LabelMapTy = SmallDenseMap<uint64_t, uint64_t, 1>; |
713 | LabelMapTy Labels; |
714 | std::mutex LabelsMutex; |
715 | |
716 | /// This field keeps current stage of overall compile unit processing. |
717 | std::atomic<Stage> Stage; |
718 | |
719 | /// DIE info indexed by DIE index. |
720 | SmallVector<DIEInfo> DieInfoArray; |
721 | SmallVector<uint64_t> OutDieOffsetArray; |
722 | SmallVector<TypeEntry *> TypeEntries; |
723 | |
724 | /// The list of accelerator records for this unit. |
725 | ArrayList<AccelInfo> AcceleratorRecords; |
726 | /// @} |
727 | }; |
728 | |
729 | /// \returns list of attributes referencing type DIEs which might be |
730 | /// deduplicated. |
731 | /// Note: it does not include DW_AT_containing_type attribute to avoid |
732 | /// infinite recursion. |
733 | ArrayRef<dwarf::Attribute> getODRAttributes(); |
734 | |
735 | } // end of namespace parallel |
736 | } // end of namespace dwarf_linker |
737 | } // end of namespace llvm |
738 | |
739 | #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERCOMPILEUNIT_H |
740 | |