1 //===- tools/dsymutil/DwarfLinker.h - Dwarf debug info linker ---*- 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_TOOLS_DSYMUTIL_DWARFLINKER_H
10 #define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
12 #include "BinaryHolder.h"
13 #include "CompileUnit.h"
15 #include "DeclContext.h"
16 #include "DwarfStreamer.h"
17 #include "LinkUtils.h"
18 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
23 /// Partial address range for debug map objects. Besides an offset, only the
24 /// HighPC is stored. The structure is stored in a map where the LowPC is the
26 struct DebugMapObjectRange
{
29 /// Offset to apply to the linked address.
32 DebugMapObjectRange(uint64_t EndPC
, int64_t Offset
)
33 : HighPC(EndPC
), Offset(Offset
) {}
35 DebugMapObjectRange() : HighPC(0), Offset(0) {}
38 /// Map LowPC to DebugMapObjectRange.
39 using RangesTy
= std::map
<uint64_t, DebugMapObjectRange
>;
40 using UnitListTy
= std::vector
<std::unique_ptr
<CompileUnit
>>;
42 /// The core of the Dwarf linking logic.
44 /// The link of the dwarf information from the object files will be
45 /// driven by the selection of 'root DIEs', which are DIEs that
46 /// describe variables or functions that are present in the linked
47 /// binary (and thus have entries in the debug map). All the debug
48 /// information that will be linked (the DIEs, but also the line
49 /// tables, ranges, ...) is derived from that set of root DIEs.
51 /// The root DIEs are identified because they contain relocations that
52 /// correspond to a debug map entry at specific places (the low_pc for
53 /// a function, the location for a variable). These relocations are
54 /// called ValidRelocs in the DwarfLinker and are gathered as a very
55 /// first step when we start processing a DebugMapObject.
58 DwarfLinker(raw_fd_ostream
&OutFile
, BinaryHolder
&BinHolder
,
60 : OutFile(OutFile
), BinHolder(BinHolder
), Options(std::move(Options
)) {}
62 /// Link the contents of the DebugMap.
63 bool link(const DebugMap
&);
65 void reportWarning(const Twine
&Warning
, const DebugMapObject
&DMO
,
66 const DWARFDie
*DIE
= nullptr) const;
69 /// Remembers the oldest and newest DWARF version we've seen in a unit.
70 void updateDwarfVersion(unsigned Version
) {
71 MaxDwarfVersion
= std::max(MaxDwarfVersion
, Version
);
72 MinDwarfVersion
= std::min(MinDwarfVersion
, Version
);
75 /// Remembers the kinds of accelerator tables we've seen in a unit.
76 void updateAccelKind(DWARFContext
&Dwarf
);
78 /// Emit warnings as Dwarf compile units to leave a trail after linking.
79 bool emitPaperTrailWarnings(const DebugMapObject
&DMO
, const DebugMap
&Map
,
80 OffsetsStringPool
&StringPool
);
82 /// Keeps track of relocations.
83 class RelocationManager
{
88 const DebugMapObject::DebugMapEntry
*Mapping
;
90 ValidReloc(uint64_t Offset
, uint32_t Size
, uint64_t Addend
,
91 const DebugMapObject::DebugMapEntry
*Mapping
)
92 : Offset(Offset
), Size(Size
), Addend(Addend
), Mapping(Mapping
) {}
94 bool operator<(const ValidReloc
&RHS
) const {
95 return Offset
< RHS
.Offset
;
99 const DwarfLinker
&Linker
;
101 /// The valid relocations for the current DebugMapObject.
102 /// This vector is sorted by relocation offset.
103 std::vector
<ValidReloc
> ValidRelocs
;
105 /// Index into ValidRelocs of the next relocation to consider. As we walk
106 /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
107 /// offset, keeping this index up to date is all we have to do to have a
108 /// cheap lookup during the root DIE selection and during DIE cloning.
109 unsigned NextValidReloc
= 0;
112 RelocationManager(DwarfLinker
&Linker
) : Linker(Linker
) {}
114 bool hasValidRelocs() const { return !ValidRelocs
.empty(); }
116 /// Reset the NextValidReloc counter.
117 void resetValidRelocs() { NextValidReloc
= 0; }
119 /// \defgroup FindValidRelocations Translate debug map into a list
120 /// of relevant relocations
123 bool findValidRelocsInDebugInfo(const object::ObjectFile
&Obj
,
124 const DebugMapObject
&DMO
);
126 bool findValidRelocs(const object::SectionRef
&Section
,
127 const object::ObjectFile
&Obj
,
128 const DebugMapObject
&DMO
);
130 void findValidRelocsMachO(const object::SectionRef
&Section
,
131 const object::MachOObjectFile
&Obj
,
132 const DebugMapObject
&DMO
);
135 bool hasValidRelocation(uint64_t StartOffset
, uint64_t EndOffset
,
136 CompileUnit::DIEInfo
&Info
);
138 bool applyValidRelocs(MutableArrayRef
<char> Data
, uint64_t BaseOffset
,
139 bool IsLittleEndian
);
142 /// Keeps track of data associated with one object during linking.
145 const object::ObjectFile
*ObjectFile
;
146 RelocationManager RelocMgr
;
147 std::unique_ptr
<DWARFContext
> DwarfContext
;
149 UnitListTy CompileUnits
;
151 LinkContext(const DebugMap
&Map
, DwarfLinker
&Linker
, DebugMapObject
&DMO
)
152 : DMO(DMO
), RelocMgr(Linker
) {
153 // Swift ASTs are not object files.
154 if (DMO
.getType() == MachO::N_AST
) {
155 ObjectFile
= nullptr;
158 auto ErrOrObj
= Linker
.loadObject(DMO
, Map
);
159 ObjectFile
= ErrOrObj
? &*ErrOrObj
: nullptr;
160 DwarfContext
= ObjectFile
? DWARFContext::create(*ObjectFile
) : nullptr;
163 /// Clear part of the context that's no longer needed when we're done with
164 /// the debug object.
166 DwarfContext
.reset(nullptr);
167 CompileUnits
.clear();
172 /// Called at the start of a debug object link.
173 void startDebugObject(LinkContext
&Context
);
175 /// Called at the end of a debug object link.
176 void endDebugObject(LinkContext
&Context
);
178 /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
181 /// Recursively walk the \p DIE tree and look for DIEs to
182 /// keep. Store that information in \p CU's DIEInfo.
184 /// The return value indicates whether the DIE is incomplete.
185 void lookForDIEsToKeep(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
186 const UnitListTy
&Units
, const DWARFDie
&DIE
,
187 const DebugMapObject
&DMO
, CompileUnit
&CU
,
190 /// If this compile unit is really a skeleton CU that points to a
191 /// clang module, register it in ClangModules and return true.
193 /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
194 /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
196 bool registerModuleReference(DWARFDie CUDie
, const DWARFUnit
&Unit
,
197 DebugMap
&ModuleMap
, const DebugMapObject
&DMO
,
199 OffsetsStringPool
&OffsetsStringPool
,
200 UniquingStringPool
&UniquingStringPoolStringPool
,
201 DeclContextTree
&ODRContexts
,
202 uint64_t ModulesEndOffset
, unsigned &UnitID
,
203 bool IsLittleEndian
, unsigned Indent
= 0,
206 /// Recursively add the debug info in this clang module .pcm
207 /// file (and all the modules imported by it in a bottom-up fashion)
209 Error
loadClangModule(DWARFDie CUDie
, StringRef FilePath
,
210 StringRef ModuleName
, uint64_t DwoId
,
211 DebugMap
&ModuleMap
, const DebugMapObject
&DMO
,
212 RangesTy
&Ranges
, OffsetsStringPool
&OffsetsStringPool
,
213 UniquingStringPool
&UniquingStringPool
,
214 DeclContextTree
&ODRContexts
, uint64_t ModulesEndOffset
,
215 unsigned &UnitID
, bool IsLittleEndian
,
216 unsigned Indent
= 0, bool Quiet
= false);
218 /// Flags passed to DwarfLinker::lookForDIEsToKeep
219 enum TraversalFlags
{
220 TF_Keep
= 1 << 0, ///< Mark the traversed DIEs as kept.
221 TF_InFunctionScope
= 1 << 1, ///< Current scope is a function scope.
222 TF_DependencyWalk
= 1 << 2, ///< Walking the dependencies of a kept DIE.
223 TF_ParentWalk
= 1 << 3, ///< Walking up the parents of a kept DIE.
224 TF_ODR
= 1 << 4, ///< Use the ODR while keeping dependents.
225 TF_SkipPC
= 1 << 5, ///< Skip all location attributes.
228 /// Mark the passed DIE as well as all the ones it depends on as kept.
229 void keepDIEAndDependencies(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
230 const UnitListTy
&Units
, const DWARFDie
&DIE
,
231 CompileUnit::DIEInfo
&MyInfo
,
232 const DebugMapObject
&DMO
, CompileUnit
&CU
,
235 unsigned shouldKeepDIE(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
236 const DWARFDie
&DIE
, const DebugMapObject
&DMO
,
237 CompileUnit
&Unit
, CompileUnit::DIEInfo
&MyInfo
,
240 /// Check if a variable describing DIE should be kept.
241 /// \returns updated TraversalFlags.
242 unsigned shouldKeepVariableDIE(RelocationManager
&RelocMgr
,
243 const DWARFDie
&DIE
, CompileUnit
&Unit
,
244 CompileUnit::DIEInfo
&MyInfo
, unsigned Flags
);
246 unsigned shouldKeepSubprogramDIE(RelocationManager
&RelocMgr
,
247 RangesTy
&Ranges
, const DWARFDie
&DIE
,
248 const DebugMapObject
&DMO
, CompileUnit
&Unit
,
249 CompileUnit::DIEInfo
&MyInfo
,
252 bool hasValidRelocation(uint32_t StartOffset
, uint32_t EndOffset
,
253 CompileUnit::DIEInfo
&Info
);
256 /// \defgroup Linking Methods used to link the debug information
262 RelocationManager
&RelocMgr
;
264 /// Allocator used for all the DIEValue objects.
265 BumpPtrAllocator
&DIEAlloc
;
267 std::vector
<std::unique_ptr
<CompileUnit
>> &CompileUnits
;
271 DIECloner(DwarfLinker
&Linker
, RelocationManager
&RelocMgr
,
272 BumpPtrAllocator
&DIEAlloc
,
273 std::vector
<std::unique_ptr
<CompileUnit
>> &CompileUnits
,
274 LinkOptions
&Options
)
275 : Linker(Linker
), RelocMgr(RelocMgr
), DIEAlloc(DIEAlloc
),
276 CompileUnits(CompileUnits
), Options(Options
) {}
278 /// Recursively clone \p InputDIE into an tree of DIE objects
279 /// where useless (as decided by lookForDIEsToKeep()) bits have been
280 /// stripped out and addresses have been rewritten according to the
283 /// \param OutOffset is the offset the cloned DIE in the output
285 /// \param PCOffset (while cloning a function scope) is the offset
286 /// applied to the entry point of the function to get the linked address.
287 /// \param Die the output DIE to use, pass NULL to create one.
288 /// \returns the root of the cloned tree or null if nothing was selected.
289 DIE
*cloneDIE(const DWARFDie
&InputDIE
, const DebugMapObject
&DMO
,
290 CompileUnit
&U
, OffsetsStringPool
&StringPool
,
291 int64_t PCOffset
, uint32_t OutOffset
, unsigned Flags
,
292 bool IsLittleEndian
, DIE
*Die
= nullptr);
294 /// Construct the output DIE tree by cloning the DIEs we
295 /// chose to keep above. If there are no valid relocs, then there's
296 /// nothing to clone/emit.
297 void cloneAllCompileUnits(DWARFContext
&DwarfContext
,
298 const DebugMapObject
&DMO
, RangesTy
&Ranges
,
299 OffsetsStringPool
&StringPool
,
300 bool IsLittleEndian
);
303 using AttributeSpec
= DWARFAbbreviationDeclaration::AttributeSpec
;
305 /// Information gathered and exchanged between the various
306 /// clone*Attributes helpers about the attributes of a particular DIE.
307 struct AttributesInfo
{
309 DwarfStringPoolEntryRef Name
, MangledName
, NameWithoutTemplate
;
311 /// Offsets in the string pool.
312 uint32_t NameOffset
= 0;
313 uint32_t MangledNameOffset
= 0;
315 /// Value of AT_low_pc in the input DIE
316 uint64_t OrigLowPc
= std::numeric_limits
<uint64_t>::max();
318 /// Value of AT_high_pc in the input DIE
319 uint64_t OrigHighPc
= 0;
321 /// Offset to apply to PC addresses inside a function.
322 int64_t PCOffset
= 0;
324 /// Does the DIE have a low_pc attribute?
325 bool HasLowPc
= false;
327 /// Does the DIE have a ranges attribute?
328 bool HasRanges
= false;
330 /// Is this DIE only a declaration?
331 bool IsDeclaration
= false;
333 AttributesInfo() = default;
336 /// Helper for cloneDIE.
337 unsigned cloneAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
338 const DebugMapObject
&DMO
, CompileUnit
&U
,
339 OffsetsStringPool
&StringPool
,
340 const DWARFFormValue
&Val
,
341 const AttributeSpec AttrSpec
, unsigned AttrSize
,
342 AttributesInfo
&AttrInfo
, bool IsLittleEndian
);
344 /// Clone a string attribute described by \p AttrSpec and add
346 /// \returns the size of the new attribute.
347 unsigned cloneStringAttribute(DIE
&Die
, AttributeSpec AttrSpec
,
348 const DWARFFormValue
&Val
, const DWARFUnit
&U
,
349 OffsetsStringPool
&StringPool
,
350 AttributesInfo
&Info
);
352 /// Clone an attribute referencing another DIE and add
354 /// \returns the size of the new attribute.
355 unsigned cloneDieReferenceAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
356 AttributeSpec AttrSpec
,
358 const DWARFFormValue
&Val
,
359 const DebugMapObject
&DMO
,
362 /// Clone a DWARF expression that may be referencing another DIE.
363 void cloneExpression(DataExtractor
&Data
, DWARFExpression Expression
,
364 const DebugMapObject
&DMO
, CompileUnit
&Unit
,
365 SmallVectorImpl
<uint8_t> &OutputBuffer
);
367 /// Clone an attribute referencing another DIE and add
369 /// \returns the size of the new attribute.
370 unsigned cloneBlockAttribute(DIE
&Die
, const DebugMapObject
&DMO
,
371 CompileUnit
&Unit
, AttributeSpec AttrSpec
,
372 const DWARFFormValue
&Val
, unsigned AttrSize
,
373 bool IsLittleEndian
);
375 /// Clone an attribute referencing another DIE and add
377 /// \returns the size of the new attribute.
378 unsigned cloneAddressAttribute(DIE
&Die
, AttributeSpec AttrSpec
,
379 const DWARFFormValue
&Val
,
380 const CompileUnit
&Unit
,
381 AttributesInfo
&Info
);
383 /// Clone a scalar attribute and add it to \p Die.
384 /// \returns the size of the new attribute.
385 unsigned cloneScalarAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
386 const DebugMapObject
&DMO
, CompileUnit
&U
,
387 AttributeSpec AttrSpec
,
388 const DWARFFormValue
&Val
, unsigned AttrSize
,
389 AttributesInfo
&Info
);
391 /// Get the potential name and mangled name for the entity
392 /// described by \p Die and store them in \Info if they are not
394 /// \returns is a name was found.
395 bool getDIENames(const DWARFDie
&Die
, AttributesInfo
&Info
,
396 OffsetsStringPool
&StringPool
, bool StripTemplate
= false);
398 /// Create a copy of abbreviation Abbrev.
399 void copyAbbrev(const DWARFAbbreviationDeclaration
&Abbrev
, bool hasODR
);
401 uint32_t hashFullyQualifiedName(DWARFDie DIE
, CompileUnit
&U
,
402 const DebugMapObject
&DMO
,
403 int RecurseDepth
= 0);
405 /// Helper for cloneDIE.
406 void addObjCAccelerator(CompileUnit
&Unit
, const DIE
*Die
,
407 DwarfStringPoolEntryRef Name
,
408 OffsetsStringPool
&StringPool
, bool SkipPubSection
);
411 /// Assign an abbreviation number to \p Abbrev
412 void AssignAbbrev(DIEAbbrev
&Abbrev
);
414 /// Compute and emit debug_ranges section for \p Unit, and
415 /// patch the attributes referencing it.
416 void patchRangesForUnit(const CompileUnit
&Unit
, DWARFContext
&Dwarf
,
417 const DebugMapObject
&DMO
) const;
419 /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had
421 void generateUnitRanges(CompileUnit
&Unit
) const;
423 /// Extract the line tables from the original dwarf, extract the relevant
424 /// parts according to the linked function ranges and emit the result in the
425 /// debug_line section.
426 void patchLineTableForUnit(CompileUnit
&Unit
, DWARFContext
&OrigDwarf
,
427 RangesTy
&Ranges
, const DebugMapObject
&DMO
);
429 /// Emit the accelerator entries for \p Unit.
430 void emitAcceleratorEntriesForUnit(CompileUnit
&Unit
);
431 void emitDwarfAcceleratorEntriesForUnit(CompileUnit
&Unit
);
432 void emitAppleAcceleratorEntriesForUnit(CompileUnit
&Unit
);
434 /// Patch the frame info for an object file and emit it.
435 void patchFrameInfoForObject(const DebugMapObject
&, RangesTy
&Ranges
,
436 DWARFContext
&, unsigned AddressSize
);
438 /// FoldingSet that uniques the abbreviations.
439 FoldingSet
<DIEAbbrev
> AbbreviationsSet
;
441 /// Storage for the unique Abbreviations.
442 /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be
443 /// changed to a vector of unique_ptrs.
444 std::vector
<std::unique_ptr
<DIEAbbrev
>> Abbreviations
;
446 /// DIELoc objects that need to be destructed (but not freed!).
447 std::vector
<DIELoc
*> DIELocs
;
449 /// DIEBlock objects that need to be destructed (but not freed!).
450 std::vector
<DIEBlock
*> DIEBlocks
;
452 /// Allocator used for all the DIEValue objects.
453 BumpPtrAllocator DIEAlloc
;
456 /// \defgroup Helpers Various helper methods.
459 bool createStreamer(const Triple
&TheTriple
, raw_fd_ostream
&OutFile
);
461 /// Attempt to load a debug object from disk.
462 ErrorOr
<const object::ObjectFile
&> loadObject(const DebugMapObject
&Obj
,
463 const DebugMap
&Map
);
466 raw_fd_ostream
&OutFile
;
467 BinaryHolder
&BinHolder
;
469 std::unique_ptr
<DwarfStreamer
> Streamer
;
470 uint64_t OutputDebugInfoSize
;
472 unsigned MaxDwarfVersion
= 0;
473 unsigned MinDwarfVersion
= std::numeric_limits
<unsigned>::max();
475 bool AtLeastOneAppleAccelTable
= false;
476 bool AtLeastOneDwarfAccelTable
= false;
478 /// The CIEs that have been emitted in the output section. The actual CIE
479 /// data serves a the key to this StringMap, this takes care of comparing the
480 /// semantics of CIEs defined in different object files.
481 StringMap
<uint32_t> EmittedCIEs
;
483 /// Offset of the last CIE that has been emitted in the output
484 /// debug_frame section.
485 uint32_t LastCIEOffset
= 0;
487 /// Apple accelerator tables.
488 AccelTable
<DWARF5AccelTableStaticData
> DebugNames
;
489 AccelTable
<AppleAccelTableStaticOffsetData
> AppleNames
;
490 AccelTable
<AppleAccelTableStaticOffsetData
> AppleNamespaces
;
491 AccelTable
<AppleAccelTableStaticOffsetData
> AppleObjc
;
492 AccelTable
<AppleAccelTableStaticTypeData
> AppleTypes
;
494 /// Mapping the PCM filename to the DwoId.
495 StringMap
<uint64_t> ClangModules
;
497 /// A list of all .swiftinterface files referenced by the debug
498 /// info, mapping Module name to path on disk. The entries need to
499 /// be uniqued and sorted and there are only few entries expected
500 /// per compile unit, which is why this is a std::map.
501 std::map
<std::string
, std::string
> ParseableSwiftInterfaces
;
503 bool ModuleCacheHintDisplayed
= false;
504 bool ArchiveHintDisplayed
= false;
507 } // end namespace dsymutil
508 } // end namespace llvm
510 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H