1 //===- tools/dsymutil/DwarfLinkerForBinary.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_TOOLS_DSYMUTIL_DWARFLINKER_H
10 #define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
12 #include "BinaryHolder.h"
14 #include "DwarfStreamer.h"
15 #include "LinkUtils.h"
16 #include "llvm/DWARFLinker/DWARFLinker.h"
17 #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
18 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
19 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
24 using UnitListTy
= std::vector
<std::unique_ptr
<CompileUnit
>>;
26 /// The core of the Dwarf linking logic.
28 /// The link of the dwarf information from the object files will be
29 /// driven by the selection of 'root DIEs', which are DIEs that
30 /// describe variables or functions that are present in the linked
31 /// binary (and thus have entries in the debug map). All the debug
32 /// information that will be linked (the DIEs, but also the line
33 /// tables, ranges, ...) is derived from that set of root DIEs.
35 /// The root DIEs are identified because they contain relocations that
36 /// correspond to a debug map entry at specific places (the low_pc for
37 /// a function, the location for a variable). These relocations are
38 /// called ValidRelocs in the DwarfLinker and are gathered as a very
39 /// first step when we start processing a DebugMapObject.
40 class DwarfLinkerForBinary
{
42 DwarfLinkerForBinary(raw_fd_ostream
&OutFile
, BinaryHolder
&BinHolder
,
44 : OutFile(OutFile
), BinHolder(BinHolder
), Options(std::move(Options
)) {}
46 /// Link the contents of the DebugMap.
47 bool link(const DebugMap
&);
49 void reportWarning(const Twine
&Warning
, const DebugMapObject
&DMO
,
50 const DWARFDie
*DIE
= nullptr) const;
52 /// Flags passed to DwarfLinker::lookForDIEsToKeep
54 TF_Keep
= 1 << 0, ///< Mark the traversed DIEs as kept.
55 TF_InFunctionScope
= 1 << 1, ///< Current scope is a function scope.
56 TF_DependencyWalk
= 1 << 2, ///< Walking the dependencies of a kept DIE.
57 TF_ParentWalk
= 1 << 3, ///< Walking up the parents of a kept DIE.
58 TF_ODR
= 1 << 4, ///< Use the ODR while keeping dependents.
59 TF_SkipPC
= 1 << 5, ///< Skip all location attributes.
63 /// Remembers the oldest and newest DWARF version we've seen in a unit.
64 void updateDwarfVersion(unsigned Version
) {
65 MaxDwarfVersion
= std::max(MaxDwarfVersion
, Version
);
66 MinDwarfVersion
= std::min(MinDwarfVersion
, Version
);
69 /// Remembers the kinds of accelerator tables we've seen in a unit.
70 void updateAccelKind(DWARFContext
&Dwarf
);
72 /// Emit warnings as Dwarf compile units to leave a trail after linking.
73 bool emitPaperTrailWarnings(const DebugMapObject
&DMO
, const DebugMap
&Map
,
74 OffsetsStringPool
&StringPool
);
76 /// Keeps track of relocations.
77 class RelocationManager
: public AddressesMap
{
82 const DebugMapObject::DebugMapEntry
*Mapping
;
84 ValidReloc(uint64_t Offset
, uint32_t Size
, uint64_t Addend
,
85 const DebugMapObject::DebugMapEntry
*Mapping
)
86 : Offset(Offset
), Size(Size
), Addend(Addend
), Mapping(Mapping
) {}
88 bool operator<(const ValidReloc
&RHS
) const {
89 return Offset
< RHS
.Offset
;
93 const DwarfLinkerForBinary
&Linker
;
95 /// The valid relocations for the current DebugMapObject.
96 /// This vector is sorted by relocation offset.
97 std::vector
<ValidReloc
> ValidRelocs
;
99 /// Index into ValidRelocs of the next relocation to consider. As we walk
100 /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
101 /// offset, keeping this index up to date is all we have to do to have a
102 /// cheap lookup during the root DIE selection and during DIE cloning.
103 unsigned NextValidReloc
= 0;
105 RangesTy AddressRanges
;
108 RelocationManager(DwarfLinkerForBinary
&Linker
,
109 const object::ObjectFile
&Obj
, const DebugMapObject
&DMO
)
111 findValidRelocsInDebugInfo(Obj
, DMO
);
113 // Iterate over the debug map entries and put all the ones that are
114 // functions (because they have a size) into the Ranges map. This map is
115 // very similar to the FunctionRanges that are stored in each unit, with 2
116 // notable differences:
118 // 1. Obviously this one is global, while the other ones are per-unit.
120 // 2. This one contains not only the functions described in the DIE
121 // tree, but also the ones that are only in the debug map.
123 // The latter information is required to reproduce dsymutil's logic while
124 // linking line tables. The cases where this information matters look like
125 // bugs that need to be investigated, but for now we need to reproduce
126 // dsymutil's behavior.
127 // FIXME: Once we understood exactly if that information is needed,
128 // maybe totally remove this (or try to use it to do a real
129 // -gline-tables-only on Darwin.
130 for (const auto &Entry
: DMO
.symbols()) {
131 const auto &Mapping
= Entry
.getValue();
132 if (Mapping
.Size
&& Mapping
.ObjectAddress
)
133 AddressRanges
[*Mapping
.ObjectAddress
] = ObjFileAddressRange(
134 *Mapping
.ObjectAddress
+ Mapping
.Size
,
135 int64_t(Mapping
.BinaryAddress
) - *Mapping
.ObjectAddress
);
138 virtual ~RelocationManager() override
{ clear(); }
140 virtual bool areRelocationsResolved() const override
{ return true; }
142 bool hasValidRelocs(bool ResetRelocsPtr
= true) override
{
145 return !ValidRelocs
.empty();
148 /// \defgroup FindValidRelocations Translate debug map into a list
149 /// of relevant relocations
152 bool findValidRelocsInDebugInfo(const object::ObjectFile
&Obj
,
153 const DebugMapObject
&DMO
);
155 bool findValidRelocs(const object::SectionRef
&Section
,
156 const object::ObjectFile
&Obj
,
157 const DebugMapObject
&DMO
);
159 void findValidRelocsMachO(const object::SectionRef
&Section
,
160 const object::MachOObjectFile
&Obj
,
161 const DebugMapObject
&DMO
);
164 bool hasValidRelocationAt(uint64_t StartOffset
, uint64_t EndOffset
,
165 CompileUnit::DIEInfo
&Info
) override
;
167 bool applyValidRelocs(MutableArrayRef
<char> Data
, uint64_t BaseOffset
,
168 bool IsLittleEndian
) override
;
170 RangesTy
&getValidAddressRanges() override
{ return AddressRanges
; }
172 void clear() override
{
173 AddressRanges
.clear();
179 /// Keeps track of data associated with one object during linking.
181 DwarfLinkerForBinary
&Linker
;
183 const object::ObjectFile
*ObjectFile
= nullptr;
184 std::unique_ptr
<RelocationManager
> RelocMgr
;
185 std::unique_ptr
<DWARFContext
> DwarfContext
;
187 UnitListTy CompileUnits
;
189 LinkContext(const DebugMap
&Map
, DwarfLinkerForBinary
&Linker
,
191 : Linker(Linker
), DMO(DMO
) {
192 // Swift ASTs are not object files.
193 if (DMO
.getType() == MachO::N_AST
) {
194 ObjectFile
= nullptr;
197 if (auto ErrOrObj
= Linker
.loadObject(DMO
, Map
)) {
198 ObjectFile
= &*ErrOrObj
;
199 DwarfContext
= DWARFContext::create(*ObjectFile
);
200 RelocMgr
.reset(new RelocationManager(Linker
, *ObjectFile
, DMO
));
204 /// Clear part of the context that's no longer needed when we're done with
205 /// the debug object.
207 DwarfContext
.reset(nullptr);
208 CompileUnits
.clear();
214 /// Called at the start of a debug object link.
215 void startDebugObject(LinkContext
&Context
);
217 /// Called at the end of a debug object link.
218 void endDebugObject(LinkContext
&Context
);
220 /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
223 /// Recursively walk the \p DIE tree and look for DIEs to
224 /// keep. Store that information in \p CU's DIEInfo.
226 /// The return value indicates whether the DIE is incomplete.
227 void lookForDIEsToKeep(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
228 const UnitListTy
&Units
, const DWARFDie
&DIE
,
229 const DebugMapObject
&DMO
, CompileUnit
&CU
,
232 /// If this compile unit is really a skeleton CU that points to a
233 /// clang module, register it in ClangModules and return true.
235 /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
236 /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
238 bool registerModuleReference(DWARFDie CUDie
, const DWARFUnit
&Unit
,
239 DebugMap
&ModuleMap
, const DebugMapObject
&DMO
,
241 OffsetsStringPool
&OffsetsStringPool
,
242 UniquingStringPool
&UniquingStringPoolStringPool
,
243 DeclContextTree
&ODRContexts
,
244 uint64_t ModulesEndOffset
, unsigned &UnitID
,
245 bool IsLittleEndian
, unsigned Indent
= 0,
248 /// Recursively add the debug info in this clang module .pcm
249 /// file (and all the modules imported by it in a bottom-up fashion)
251 Error
loadClangModule(DWARFDie CUDie
, StringRef FilePath
,
252 StringRef ModuleName
, uint64_t DwoId
,
253 DebugMap
&ModuleMap
, const DebugMapObject
&DMO
,
254 RangesTy
&Ranges
, OffsetsStringPool
&OffsetsStringPool
,
255 UniquingStringPool
&UniquingStringPool
,
256 DeclContextTree
&ODRContexts
, uint64_t ModulesEndOffset
,
257 unsigned &UnitID
, bool IsLittleEndian
,
258 unsigned Indent
= 0, bool Quiet
= false);
260 /// Mark the passed DIE as well as all the ones it depends on as kept.
261 void keepDIEAndDependencies(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
262 const UnitListTy
&Units
, const DWARFDie
&DIE
,
263 CompileUnit::DIEInfo
&MyInfo
,
264 const DebugMapObject
&DMO
, CompileUnit
&CU
,
267 unsigned shouldKeepDIE(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
268 const DWARFDie
&DIE
, const DebugMapObject
&DMO
,
269 CompileUnit
&Unit
, CompileUnit::DIEInfo
&MyInfo
,
272 /// Check if a variable describing DIE should be kept.
273 /// \returns updated TraversalFlags.
274 unsigned shouldKeepVariableDIE(RelocationManager
&RelocMgr
,
275 const DWARFDie
&DIE
, CompileUnit
&Unit
,
276 CompileUnit::DIEInfo
&MyInfo
, unsigned Flags
);
278 unsigned shouldKeepSubprogramDIE(RelocationManager
&RelocMgr
,
279 RangesTy
&Ranges
, const DWARFDie
&DIE
,
280 const DebugMapObject
&DMO
, CompileUnit
&Unit
,
281 CompileUnit::DIEInfo
&MyInfo
,
284 bool hasValidRelocation(uint32_t StartOffset
, uint32_t EndOffset
,
285 CompileUnit::DIEInfo
&Info
);
288 /// \defgroup Linking Methods used to link the debug information
293 DwarfLinkerForBinary
&Linker
;
294 RelocationManager
&RelocMgr
;
296 /// Allocator used for all the DIEValue objects.
297 BumpPtrAllocator
&DIEAlloc
;
299 std::vector
<std::unique_ptr
<CompileUnit
>> &CompileUnits
;
303 DIECloner(DwarfLinkerForBinary
&Linker
, RelocationManager
&RelocMgr
,
304 BumpPtrAllocator
&DIEAlloc
,
305 std::vector
<std::unique_ptr
<CompileUnit
>> &CompileUnits
,
306 LinkOptions
&Options
)
307 : Linker(Linker
), RelocMgr(RelocMgr
), DIEAlloc(DIEAlloc
),
308 CompileUnits(CompileUnits
), Options(Options
) {}
310 /// Recursively clone \p InputDIE into an tree of DIE objects
311 /// where useless (as decided by lookForDIEsToKeep()) bits have been
312 /// stripped out and addresses have been rewritten according to the
315 /// \param OutOffset is the offset the cloned DIE in the output
317 /// \param PCOffset (while cloning a function scope) is the offset
318 /// applied to the entry point of the function to get the linked address.
319 /// \param Die the output DIE to use, pass NULL to create one.
320 /// \returns the root of the cloned tree or null if nothing was selected.
321 DIE
*cloneDIE(const DWARFDie
&InputDIE
, const DebugMapObject
&DMO
,
322 CompileUnit
&U
, OffsetsStringPool
&StringPool
,
323 int64_t PCOffset
, uint32_t OutOffset
, unsigned Flags
,
324 bool IsLittleEndian
, DIE
*Die
= nullptr);
326 /// Construct the output DIE tree by cloning the DIEs we
327 /// chose to keep above. If there are no valid relocs, then there's
328 /// nothing to clone/emit.
329 void cloneAllCompileUnits(DWARFContext
&DwarfContext
,
330 const DebugMapObject
&DMO
, RangesTy
&Ranges
,
331 OffsetsStringPool
&StringPool
,
332 bool IsLittleEndian
);
335 using AttributeSpec
= DWARFAbbreviationDeclaration::AttributeSpec
;
337 /// Information gathered and exchanged between the various
338 /// clone*Attributes helpers about the attributes of a particular DIE.
339 struct AttributesInfo
{
341 DwarfStringPoolEntryRef Name
, MangledName
, NameWithoutTemplate
;
343 /// Offsets in the string pool.
344 uint32_t NameOffset
= 0;
345 uint32_t MangledNameOffset
= 0;
347 /// Value of AT_low_pc in the input DIE
348 uint64_t OrigLowPc
= std::numeric_limits
<uint64_t>::max();
350 /// Value of AT_high_pc in the input DIE
351 uint64_t OrigHighPc
= 0;
353 /// Offset to apply to PC addresses inside a function.
354 int64_t PCOffset
= 0;
356 /// Does the DIE have a low_pc attribute?
357 bool HasLowPc
= false;
359 /// Does the DIE have a ranges attribute?
360 bool HasRanges
= false;
362 /// Is this DIE only a declaration?
363 bool IsDeclaration
= false;
365 AttributesInfo() = default;
368 /// Helper for cloneDIE.
369 unsigned cloneAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
370 const DebugMapObject
&DMO
, CompileUnit
&U
,
371 OffsetsStringPool
&StringPool
,
372 const DWARFFormValue
&Val
,
373 const AttributeSpec AttrSpec
, unsigned AttrSize
,
374 AttributesInfo
&AttrInfo
, bool IsLittleEndian
);
376 /// Clone a string attribute described by \p AttrSpec and add
378 /// \returns the size of the new attribute.
379 unsigned cloneStringAttribute(DIE
&Die
, AttributeSpec AttrSpec
,
380 const DWARFFormValue
&Val
, const DWARFUnit
&U
,
381 OffsetsStringPool
&StringPool
,
382 AttributesInfo
&Info
);
384 /// Clone an attribute referencing another DIE and add
386 /// \returns the size of the new attribute.
387 unsigned cloneDieReferenceAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
388 AttributeSpec AttrSpec
,
390 const DWARFFormValue
&Val
,
391 const DebugMapObject
&DMO
,
394 /// Clone a DWARF expression that may be referencing another DIE.
395 void cloneExpression(DataExtractor
&Data
, DWARFExpression Expression
,
396 const DebugMapObject
&DMO
, CompileUnit
&Unit
,
397 SmallVectorImpl
<uint8_t> &OutputBuffer
);
399 /// Clone an attribute referencing another DIE and add
401 /// \returns the size of the new attribute.
402 unsigned cloneBlockAttribute(DIE
&Die
, const DebugMapObject
&DMO
,
403 CompileUnit
&Unit
, AttributeSpec AttrSpec
,
404 const DWARFFormValue
&Val
, unsigned AttrSize
,
405 bool IsLittleEndian
);
407 /// Clone an attribute referencing another DIE and add
409 /// \returns the size of the new attribute.
410 unsigned cloneAddressAttribute(DIE
&Die
, AttributeSpec AttrSpec
,
411 const DWARFFormValue
&Val
,
412 const CompileUnit
&Unit
,
413 AttributesInfo
&Info
);
415 /// Clone a scalar attribute and add it to \p Die.
416 /// \returns the size of the new attribute.
417 unsigned cloneScalarAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
418 const DebugMapObject
&DMO
, CompileUnit
&U
,
419 AttributeSpec AttrSpec
,
420 const DWARFFormValue
&Val
, unsigned AttrSize
,
421 AttributesInfo
&Info
);
423 /// Get the potential name and mangled name for the entity
424 /// described by \p Die and store them in \Info if they are not
426 /// \returns is a name was found.
427 bool getDIENames(const DWARFDie
&Die
, AttributesInfo
&Info
,
428 OffsetsStringPool
&StringPool
, bool StripTemplate
= false);
430 /// Create a copy of abbreviation Abbrev.
431 void copyAbbrev(const DWARFAbbreviationDeclaration
&Abbrev
, bool hasODR
);
433 uint32_t hashFullyQualifiedName(DWARFDie DIE
, CompileUnit
&U
,
434 const DebugMapObject
&DMO
,
435 int RecurseDepth
= 0);
437 /// Helper for cloneDIE.
438 void addObjCAccelerator(CompileUnit
&Unit
, const DIE
*Die
,
439 DwarfStringPoolEntryRef Name
,
440 OffsetsStringPool
&StringPool
, bool SkipPubSection
);
443 /// Assign an abbreviation number to \p Abbrev
444 void assignAbbrev(DIEAbbrev
&Abbrev
);
446 /// Compute and emit debug_ranges section for \p Unit, and
447 /// patch the attributes referencing it.
448 void patchRangesForUnit(const CompileUnit
&Unit
, DWARFContext
&Dwarf
,
449 const DebugMapObject
&DMO
) const;
451 /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had
453 void generateUnitRanges(CompileUnit
&Unit
) const;
455 /// Extract the line tables from the original dwarf, extract the relevant
456 /// parts according to the linked function ranges and emit the result in the
457 /// debug_line section.
458 void patchLineTableForUnit(CompileUnit
&Unit
, DWARFContext
&OrigDwarf
,
459 RangesTy
&Ranges
, const DebugMapObject
&DMO
);
461 /// Emit the accelerator entries for \p Unit.
462 void emitAcceleratorEntriesForUnit(CompileUnit
&Unit
);
463 void emitDwarfAcceleratorEntriesForUnit(CompileUnit
&Unit
);
464 void emitAppleAcceleratorEntriesForUnit(CompileUnit
&Unit
);
466 /// Patch the frame info for an object file and emit it.
467 void patchFrameInfoForObject(const DebugMapObject
&, RangesTy
&Ranges
,
468 DWARFContext
&, unsigned AddressSize
);
470 /// FoldingSet that uniques the abbreviations.
471 FoldingSet
<DIEAbbrev
> AbbreviationsSet
;
473 /// Storage for the unique Abbreviations.
474 /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be
475 /// changed to a vector of unique_ptrs.
476 std::vector
<std::unique_ptr
<DIEAbbrev
>> Abbreviations
;
478 /// DIELoc objects that need to be destructed (but not freed!).
479 std::vector
<DIELoc
*> DIELocs
;
481 /// DIEBlock objects that need to be destructed (but not freed!).
482 std::vector
<DIEBlock
*> DIEBlocks
;
484 /// Allocator used for all the DIEValue objects.
485 BumpPtrAllocator DIEAlloc
;
488 /// \defgroup Helpers Various helper methods.
491 bool createStreamer(const Triple
&TheTriple
, raw_fd_ostream
&OutFile
);
493 /// Attempt to load a debug object from disk.
494 ErrorOr
<const object::ObjectFile
&> loadObject(const DebugMapObject
&Obj
,
495 const DebugMap
&Map
);
498 raw_fd_ostream
&OutFile
;
499 BinaryHolder
&BinHolder
;
501 std::unique_ptr
<DwarfStreamer
> Streamer
;
503 unsigned MaxDwarfVersion
= 0;
504 unsigned MinDwarfVersion
= std::numeric_limits
<unsigned>::max();
506 bool AtLeastOneAppleAccelTable
= false;
507 bool AtLeastOneDwarfAccelTable
= false;
509 /// The CIEs that have been emitted in the output section. The actual CIE
510 /// data serves a the key to this StringMap, this takes care of comparing the
511 /// semantics of CIEs defined in different object files.
512 StringMap
<uint32_t> EmittedCIEs
;
514 /// Offset of the last CIE that has been emitted in the output
515 /// debug_frame section.
516 uint32_t LastCIEOffset
= 0;
518 /// Apple accelerator tables.
519 AccelTable
<DWARF5AccelTableStaticData
> DebugNames
;
520 AccelTable
<AppleAccelTableStaticOffsetData
> AppleNames
;
521 AccelTable
<AppleAccelTableStaticOffsetData
> AppleNamespaces
;
522 AccelTable
<AppleAccelTableStaticOffsetData
> AppleObjc
;
523 AccelTable
<AppleAccelTableStaticTypeData
> AppleTypes
;
525 /// Mapping the PCM filename to the DwoId.
526 StringMap
<uint64_t> ClangModules
;
528 /// A list of all .swiftinterface files referenced by the debug
529 /// info, mapping Module name to path on disk. The entries need to
530 /// be uniqued and sorted and there are only few entries expected
531 /// per compile unit, which is why this is a std::map.
532 std::map
<std::string
, std::string
> ParseableSwiftInterfaces
;
534 bool ModuleCacheHintDisplayed
= false;
535 bool ArchiveHintDisplayed
= false;
538 } // end namespace dsymutil
539 } // end namespace llvm
541 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H