1 //===- DWARFLinkerCompileUnit.h ---------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
10 #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
12 #include "DWARFLinkerUnit.h"
13 #include "IndexedValuesMap.h"
14 #include "llvm/DWARFLinkerParallel/DWARFFile.h"
18 namespace dwarflinker_parallel
{
20 using OffsetToUnitTy
= function_ref
<CompileUnit
*(uint64_t Offset
)>;
22 /// Stores all information related to a compile unit, be it in its original
23 /// instance of the object file or its brand new cloned and generated DIE tree.
24 class CompileUnit
: public DwarfUnit
{
26 /// The stages of new compile unit processing.
27 enum class Stage
: uint8_t {
28 /// Created, linked with input DWARF file.
31 /// Input DWARF is loaded.
34 /// Input DWARF is analysed(DIEs pointing to the real code section are
35 /// discovered, type names are assigned if ODR is requested).
38 /// Output DWARF is generated.
41 /// Offsets inside patch records are updated.
44 /// Resources(Input DWARF, Output DWARF tree) are released.
48 CompileUnit(LinkingGlobalData
&GlobalData
, unsigned ID
,
49 StringRef ClangModuleName
, DWARFFile
&File
,
50 OffsetToUnitTy UnitFromOffset
, dwarf::FormParams Format
,
51 support::endianness Endianess
)
52 : DwarfUnit(GlobalData
, ID
, ClangModuleName
), File(File
),
53 getUnitFromOffset(UnitFromOffset
), Stage(Stage::CreatedNotLoaded
) {
54 UnitName
= File
.FileName
;
55 setOutputFormat(Format
, Endianess
);
58 CompileUnit(LinkingGlobalData
&GlobalData
, DWARFUnit
&OrigUnit
, unsigned ID
,
59 StringRef ClangModuleName
, DWARFFile
&File
,
60 OffsetToUnitTy UnitFromOffset
, dwarf::FormParams Format
,
61 support::endianness Endianess
)
62 : DwarfUnit(GlobalData
, ID
, ClangModuleName
), File(File
),
63 OrigUnit(&OrigUnit
), getUnitFromOffset(UnitFromOffset
),
64 Stage(Stage::CreatedNotLoaded
) {
65 DWARFDie CUDie
= OrigUnit
.getUnitDIE();
69 setOutputFormat(Format
, Endianess
);
71 Language
= dwarf::toUnsigned(CUDie
.find(dwarf::DW_AT_language
), 0);
72 if (const char *CUName
= CUDie
.getName(DINameKind::ShortName
))
75 UnitName
= File
.FileName
;
76 SysRoot
= dwarf::toStringRef(CUDie
.find(dwarf::DW_AT_LLVM_sysroot
)).str();
79 /// Returns stage of overall processing.
80 Stage
getStage() const { return Stage
; }
82 /// Set stage of overall processing.
83 void setStage(Stage Stage
) { this->Stage
= Stage
; }
85 /// Loads unit line table.
88 /// Returns name of the file for the \p FileIdx
89 /// from the unit`s line table.
90 StringEntry
*getFileName(unsigned FileIdx
, StringPool
&GlobalStrings
);
92 /// Returns DWARFFile containing this compile unit.
93 const DWARFFile
&getContaingFile() const { return File
; }
95 /// Load DIEs of input compilation unit. \returns true if input DIEs
96 /// successfully loaded.
99 /// Reset compile units data(results of liveness analysis, clonning)
100 /// if current stage greater than Stage::Loaded. We need to reset data
101 /// as we are going to repeat stages.
102 void maybeResetToLoadedStage();
104 /// Collect references to parseable Swift interfaces in imported
105 /// DW_TAG_module blocks.
106 void analyzeImportedModule(const DWARFDebugInfoEntry
*DieEntry
);
108 /// Navigate DWARF tree and set die properties.
109 void analyzeDWARFStructure() {
110 analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false, false);
113 /// Cleanup unneeded resources after compile unit is cloned.
114 void cleanupDataAfterClonning();
116 /// After cloning stage the output DIEs offsets are deallocated.
117 /// This method copies output offsets for referenced DIEs into DIEs patches.
118 void updateDieRefPatchesWithClonedOffsets();
120 /// Kinds of placement for the output die.
121 enum DieOutputPlacement
: uint8_t {
124 /// Corresponding DIE goes to the type table only.
125 /// NOTE: Not used yet.
128 /// Corresponding DIE goes to the plain dwarf only.
131 /// Corresponding DIE goes to type table and to plain dwarf.
132 /// NOTE: Not used yet.
135 /// Corresponding DIE needs to examine parent to determine
136 /// the point of placement.
137 /// NOTE: Not used yet.
141 /// Information gathered about source DIEs.
144 DIEInfo(const DIEInfo
&Other
) { Flags
= Other
.Flags
.load(); }
145 DIEInfo
&operator=(const DIEInfo
&Other
) {
146 Flags
= Other
.Flags
.load();
150 /// Data member keeping various flags.
151 std::atomic
<uint16_t> Flags
= {0};
153 /// \returns Placement kind for the corresponding die.
154 DieOutputPlacement
getPlacement() const {
155 return DieOutputPlacement(Flags
& 0x7);
158 /// Sets Placement kind for the corresponding die.
159 void setPlacement(DieOutputPlacement Placement
) {
160 auto InputData
= Flags
.load();
161 while (!Flags
.compare_exchange_weak(InputData
,
162 ((InputData
& ~0x7) | Placement
))) {
166 /// Unsets Placement kind for the corresponding die.
167 void unsetPlacement() {
168 auto InputData
= Flags
.load();
169 while (!Flags
.compare_exchange_weak(InputData
, (InputData
& ~0x7))) {
173 /// Sets Placement kind for the corresponding die.
174 bool setPlacementIfUnset(DieOutputPlacement Placement
) {
175 auto InputData
= Flags
.load();
176 if ((InputData
& 0x7) == NotSet
)
177 if (Flags
.compare_exchange_weak(InputData
, (InputData
| Placement
)))
183 #define SINGLE_FLAG_METHODS_SET(Name, Value) \
184 bool get##Name() const { return Flags & Value; } \
186 auto InputData = Flags.load(); \
187 while (!Flags.compare_exchange_weak(InputData, InputData | Value)) { \
190 void unset##Name() { \
191 auto InputData = Flags.load(); \
192 while (!Flags.compare_exchange_weak(InputData, InputData & ~Value)) { \
196 /// DIE is a part of the linked output.
197 SINGLE_FLAG_METHODS_SET(Keep
, 0x08)
199 /// DIE has children which are part of the linked output.
200 SINGLE_FLAG_METHODS_SET(KeepChildren
, 0x10)
202 /// DIE is referenced by other DIE.
203 SINGLE_FLAG_METHODS_SET(ReferrencedBy
, 0x20)
205 /// DIE is in module scope.
206 SINGLE_FLAG_METHODS_SET(IsInMouduleScope
, 0x40)
208 /// DIE is in function scope.
209 SINGLE_FLAG_METHODS_SET(IsInFunctionScope
, 0x80)
211 void unsetFlagsWhichSetDuringLiveAnalysis() {
212 auto InputData
= Flags
.load();
213 while (!Flags
.compare_exchange_weak(
214 InputData
, InputData
& ~(0x7 | 0x8 | 0x10 | 0x20))) {
219 void eraseData() { Flags
= 0; }
221 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
222 LLVM_DUMP_METHOD
void dump();
226 /// \defgroup Group of functions returning DIE info.
230 /// \p Idx index of the DIE.
231 /// \returns DieInfo descriptor.
232 DIEInfo
&getDIEInfo(unsigned Idx
) { return DieInfoArray
[Idx
]; }
234 /// \p Idx index of the DIE.
235 /// \returns DieInfo descriptor.
236 const DIEInfo
&getDIEInfo(unsigned Idx
) const { return DieInfoArray
[Idx
]; }
238 /// \p Idx index of the DIE.
239 /// \returns DieInfo descriptor.
240 DIEInfo
&getDIEInfo(const DWARFDebugInfoEntry
*Entry
) {
241 return DieInfoArray
[getOrigUnit().getDIEIndex(Entry
)];
244 /// \p Idx index of the DIE.
245 /// \returns DieInfo descriptor.
246 const DIEInfo
&getDIEInfo(const DWARFDebugInfoEntry
*Entry
) const {
247 return DieInfoArray
[getOrigUnit().getDIEIndex(Entry
)];
251 /// \returns PlainDieInfo descriptor.
252 DIEInfo
&getDIEInfo(const DWARFDie
&Die
) {
253 return DieInfoArray
[getOrigUnit().getDIEIndex(Die
)];
257 /// \returns PlainDieInfo descriptor.
258 const DIEInfo
&getDIEInfo(const DWARFDie
&Die
) const {
259 return DieInfoArray
[getOrigUnit().getDIEIndex(Die
)];
262 /// \p Idx index of the DIE.
263 /// \returns DieInfo descriptor.
264 uint64_t getDieOutOffset(uint32_t Idx
) {
265 return reinterpret_cast<std::atomic
<uint64_t> *>(&OutDieOffsetArray
[Idx
])
269 /// \p Idx index of the DIE.
270 /// \returns DieInfo descriptor.
271 void rememberDieOutOffset(uint32_t Idx
, uint64_t Offset
) {
272 reinterpret_cast<std::atomic
<uint64_t> *>(&OutDieOffsetArray
[Idx
])
278 /// Returns value of DW_AT_low_pc attribute.
279 std::optional
<uint64_t> getLowPc() const { return LowPc
; }
281 /// Returns value of DW_AT_high_pc attribute.
282 uint64_t getHighPc() const { return HighPc
; }
284 /// Returns true if there is a label corresponding to the specified \p Addr.
285 bool hasLabelAt(uint64_t Addr
) const { return Labels
.count(Addr
); }
287 /// Add the low_pc of a label that is relocated by applying
288 /// offset \p PCOffset.
289 void addLabelLowPc(uint64_t LabelLowPc
, int64_t PcOffset
);
291 /// Resolve the DIE attribute reference that has been extracted in \p
292 /// RefValue. The resulting DIE might be in another CompileUnit.
293 /// \returns referenced die and corresponding compilation unit.
294 /// compilation unit is null if reference could not be resolved.
295 std::optional
<std::pair
<CompileUnit
*, uint32_t>>
296 resolveDIEReference(const DWARFFormValue
&RefValue
);
299 /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying
300 /// offset \p PCOffset.
301 void addFunctionRange(uint64_t LowPC
, uint64_t HighPC
, int64_t PCOffset
);
303 /// Returns function ranges of this unit.
304 const RangesTy
&getFunctionRanges() const { return Ranges
; }
306 /// Clone and emit this compilation unit.
307 Error
cloneAndEmit(std::optional
<Triple
> TargetTriple
);
309 /// Clone and emit debug locations(.debug_loc/.debug_loclists).
310 Error
cloneAndEmitDebugLocations();
312 /// Clone and emit ranges.
313 Error
cloneAndEmitRanges();
315 /// Clone and emit debug macros(.debug_macinfo/.debug_macro).
316 Error
cloneAndEmitDebugMacro();
318 // Clone input DIE entry.
319 DIE
*cloneDIE(const DWARFDebugInfoEntry
*InputDieEntry
, uint64_t OutOffset
,
320 std::optional
<int64_t> FuncAddressAdjustment
,
321 std::optional
<int64_t> VarAddressAdjustment
,
322 BumpPtrAllocator
&Allocator
);
324 // Clone and emit line table.
325 Error
cloneAndEmitLineTable(Triple
&TargetTriple
);
327 /// Clone attribute location axpression.
328 void cloneDieAttrExpression(const DWARFExpression
&InputExpression
,
329 SmallVectorImpl
<uint8_t> &OutputExpression
,
330 SectionDescriptor
&Section
,
331 std::optional
<int64_t> VarAddressAdjustment
,
332 OffsetsPtrVector
&PatchesOffsets
);
334 /// Returns index(inside .debug_addr) of an address.
335 uint64_t getDebugAddrIndex(uint64_t Addr
) {
336 return DebugAddrIndexMap
.getValueIndex(Addr
);
339 /// Returns index(inside .debug_str_offsets) of specified string.
340 uint64_t getDebugStrIndex(const StringEntry
*String
) {
341 return DebugStringIndexMap
.getValueIndex(String
);
344 /// \defgroup Helper methods to access OrigUnit.
348 /// Returns paired compile unit from input DWARF.
349 DWARFUnit
&getOrigUnit() const {
350 assert(OrigUnit
!= nullptr);
354 const DWARFDebugInfoEntry
*
355 getFirstChildEntry(const DWARFDebugInfoEntry
*Die
) const {
356 assert(OrigUnit
!= nullptr);
357 return OrigUnit
->getFirstChildEntry(Die
);
360 const DWARFDebugInfoEntry
*
361 getSiblingEntry(const DWARFDebugInfoEntry
*Die
) const {
362 assert(OrigUnit
!= nullptr);
363 return OrigUnit
->getSiblingEntry(Die
);
366 DWARFDie
getParent(const DWARFDebugInfoEntry
*Die
) {
367 assert(OrigUnit
!= nullptr);
368 return OrigUnit
->getParent(Die
);
371 DWARFDie
getDIEAtIndex(unsigned Index
) {
372 assert(OrigUnit
!= nullptr);
373 return OrigUnit
->getDIEAtIndex(Index
);
376 const DWARFDebugInfoEntry
*getDebugInfoEntry(unsigned Index
) const {
377 assert(OrigUnit
!= nullptr);
378 return OrigUnit
->getDebugInfoEntry(Index
);
381 DWARFDie
getUnitDIE(bool ExtractUnitDIEOnly
= true) {
382 assert(OrigUnit
!= nullptr);
383 return OrigUnit
->getUnitDIE(ExtractUnitDIEOnly
);
386 DWARFDie
getDIE(const DWARFDebugInfoEntry
*Die
) {
387 assert(OrigUnit
!= nullptr);
388 return DWARFDie(OrigUnit
, Die
);
391 uint32_t getDIEIndex(const DWARFDebugInfoEntry
*Die
) const {
392 assert(OrigUnit
!= nullptr);
393 return OrigUnit
->getDIEIndex(Die
);
396 uint32_t getDIEIndex(const DWARFDie
&Die
) const {
397 assert(OrigUnit
!= nullptr);
398 return OrigUnit
->getDIEIndex(Die
);
401 std::optional
<DWARFFormValue
> find(uint32_t DieIdx
,
402 ArrayRef
<dwarf::Attribute
> Attrs
) const {
403 assert(OrigUnit
!= nullptr);
404 return find(OrigUnit
->getDebugInfoEntry(DieIdx
), Attrs
);
407 std::optional
<DWARFFormValue
> find(const DWARFDebugInfoEntry
*Die
,
408 ArrayRef
<dwarf::Attribute
> Attrs
) const {
411 auto AbbrevDecl
= Die
->getAbbreviationDeclarationPtr();
413 for (auto Attr
: Attrs
) {
414 if (auto Value
= AbbrevDecl
->getAttributeValue(Die
->getOffset(), Attr
,
422 std::optional
<uint32_t> getDIEIndexForOffset(uint64_t Offset
) {
423 return OrigUnit
->getDIEIndexForOffset(Offset
);
428 /// \defgroup Methods used for reporting warnings and errors:
432 void warn(const Twine
&Warning
, const DWARFDie
*DIE
= nullptr) {
433 GlobalData
.warn(Warning
, getUnitName(), DIE
);
436 void warn(Error Warning
, const DWARFDie
*DIE
= nullptr) {
437 handleAllErrors(std::move(Warning
), [&](ErrorInfoBase
&Info
) {
438 GlobalData
.warn(Info
.message(), getUnitName(), DIE
);
442 void warn(const Twine
&Warning
, const DWARFDebugInfoEntry
*DieEntry
) {
443 if (DieEntry
!= nullptr) {
444 DWARFDie
DIE(&getOrigUnit(), DieEntry
);
445 GlobalData
.warn(Warning
, getUnitName(), &DIE
);
449 GlobalData
.warn(Warning
, getUnitName());
452 void error(const Twine
&Err
, const DWARFDie
*DIE
= nullptr) {
453 GlobalData
.warn(Err
, getUnitName(), DIE
);
456 void error(Error Err
, const DWARFDie
*DIE
= nullptr) {
457 handleAllErrors(std::move(Err
), [&](ErrorInfoBase
&Info
) {
458 GlobalData
.error(Info
.message(), getUnitName(), DIE
);
465 /// Navigate DWARF tree recursively and set die properties.
466 void analyzeDWARFStructureRec(const DWARFDebugInfoEntry
*DieEntry
,
467 bool IsInModule
, bool IsInFunction
);
469 struct LinkedLocationExpressionsWithOffsetPatches
{
470 DWARFLocationExpression Expression
;
471 OffsetsPtrVector Patches
;
473 using LinkedLocationExpressionsVector
=
474 SmallVector
<LinkedLocationExpressionsWithOffsetPatches
>;
476 /// Emit debug locations.
477 void emitLocations(DebugSectionKind LocationSectionKind
);
479 /// Emit location list header.
480 uint64_t emitLocListHeader(SectionDescriptor
&OutLocationSection
);
482 /// Emit location list fragment.
483 uint64_t emitLocListFragment(
484 const LinkedLocationExpressionsVector
&LinkedLocationExpression
,
485 SectionDescriptor
&OutLocationSection
);
487 /// Emit the .debug_addr section fragment for current unit.
488 Error
emitDebugAddrSection();
490 /// Emit the .debug_str_offsets section for current unit.
491 Error
emitDebugStringOffsetSection();
493 /// Emit .debug_aranges.
494 void emitAranges(AddressRanges
&LinkedFunctionRanges
);
496 /// Clone and emit .debug_ranges/.debug_rnglists.
497 void cloneAndEmitRangeList(DebugSectionKind RngSectionKind
,
498 AddressRanges
&LinkedFunctionRanges
);
500 /// Emit range list header.
501 uint64_t emitRangeListHeader(SectionDescriptor
&OutRangeSection
);
503 /// Emit range list fragment.
504 void emitRangeListFragment(const AddressRanges
&LinkedRanges
,
505 SectionDescriptor
&OutRangeSection
);
507 /// Insert the new line info sequence \p Seq into the current
508 /// set of already linked line info \p Rows.
509 void insertLineSequence(std::vector
<DWARFDebugLine::Row
> &Seq
,
510 std::vector
<DWARFDebugLine::Row
> &Rows
);
512 /// Emits body for both macro sections.
513 void emitMacroTableImpl(const DWARFDebugMacro
*MacroTable
,
514 uint64_t OffsetToMacroTable
, bool hasDWARFv5Header
);
516 /// DWARFFile containing this compile unit.
519 /// Pointer to the paired compile unit from the input DWARF.
520 DWARFUnit
*OrigUnit
= nullptr;
522 /// Line table for this unit.
523 const DWARFDebugLine::LineTable
*LineTablePtr
= nullptr;
525 /// Cached resolved paths from the line table.
526 /// The key is <UniqueUnitID, FileIdx>.
527 using ResolvedPathsMap
= DenseMap
<unsigned, StringEntry
*>;
528 ResolvedPathsMap ResolvedFullPaths
;
529 StringMap
<StringEntry
*> ResolvedParentPaths
;
531 /// This field instructs compile unit to store DIE name with stripped
532 /// template parameters into the accelerator table.
533 bool CanStripTemplateName
= false;
535 /// Maps an address into the index inside .debug_addr section.
536 IndexedValuesMap
<uint64_t> DebugAddrIndexMap
;
538 /// Maps a string into the index inside .debug_str_offsets section.
539 IndexedValuesMap
<const StringEntry
*> DebugStringIndexMap
;
541 /// \defgroup Data Members accessed asinchroniously.
544 OffsetToUnitTy getUnitFromOffset
;
546 std::optional
<uint64_t> LowPc
;
549 /// The ranges in that map are the PC ranges for functions in this unit,
550 /// associated with the PC offset to apply to the addresses to get
551 /// the linked address.
553 std::mutex RangesMutex
;
555 /// The DW_AT_low_pc of each DW_TAG_label.
556 SmallDenseMap
<uint64_t, uint64_t, 1> Labels
;
557 std::mutex LabelsMutex
;
559 /// This field keeps current stage of overall compile unit processing.
560 std::atomic
<Stage
> Stage
;
562 /// DIE info indexed by DIE index.
563 SmallVector
<DIEInfo
> DieInfoArray
;
564 SmallVector
<uint64_t> OutDieOffsetArray
;
568 } // end of namespace dwarflinker_parallel
569 } // end namespace llvm
571 #endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H