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