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
,
59 const LinkOptions
&Options
)
60 : OutFile(OutFile
), BinHolder(BinHolder
), Options(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(uint32_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(uint32_t StartOffset
, uint32_t EndOffset
,
136 CompileUnit::DIEInfo
&Info
);
138 bool applyValidRelocs(MutableArrayRef
<char> Data
, uint32_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(const 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 unsigned Indent
= 0, bool Quiet
= false);
205 /// Recursively add the debug info in this clang module .pcm
206 /// file (and all the modules imported by it in a bottom-up fashion)
208 Error
loadClangModule(StringRef Filename
, StringRef ModulePath
,
209 StringRef ModuleName
, uint64_t DwoId
,
210 DebugMap
&ModuleMap
, const DebugMapObject
&DMO
,
211 RangesTy
&Ranges
, OffsetsStringPool
&OffsetsStringPool
,
212 UniquingStringPool
&UniquingStringPool
,
213 DeclContextTree
&ODRContexts
, uint64_t ModulesEndOffset
,
214 unsigned &UnitID
, unsigned Indent
= 0,
217 /// Flags passed to DwarfLinker::lookForDIEsToKeep
218 enum TraversalFlags
{
219 TF_Keep
= 1 << 0, ///< Mark the traversed DIEs as kept.
220 TF_InFunctionScope
= 1 << 1, ///< Current scope is a function scope.
221 TF_DependencyWalk
= 1 << 2, ///< Walking the dependencies of a kept DIE.
222 TF_ParentWalk
= 1 << 3, ///< Walking up the parents of a kept DIE.
223 TF_ODR
= 1 << 4, ///< Use the ODR while keeping dependents.
224 TF_SkipPC
= 1 << 5, ///< Skip all location attributes.
227 /// Mark the passed DIE as well as all the ones it depends on as kept.
228 void keepDIEAndDependencies(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
229 const UnitListTy
&Units
, const DWARFDie
&DIE
,
230 CompileUnit::DIEInfo
&MyInfo
,
231 const DebugMapObject
&DMO
, CompileUnit
&CU
,
234 unsigned shouldKeepDIE(RelocationManager
&RelocMgr
, RangesTy
&Ranges
,
235 const DWARFDie
&DIE
, const DebugMapObject
&DMO
,
236 CompileUnit
&Unit
, CompileUnit::DIEInfo
&MyInfo
,
239 unsigned shouldKeepVariableDIE(RelocationManager
&RelocMgr
,
240 const DWARFDie
&DIE
, CompileUnit
&Unit
,
241 CompileUnit::DIEInfo
&MyInfo
, unsigned Flags
);
243 unsigned shouldKeepSubprogramDIE(RelocationManager
&RelocMgr
,
244 RangesTy
&Ranges
, const DWARFDie
&DIE
,
245 const DebugMapObject
&DMO
, CompileUnit
&Unit
,
246 CompileUnit::DIEInfo
&MyInfo
,
249 bool hasValidRelocation(uint32_t StartOffset
, uint32_t EndOffset
,
250 CompileUnit::DIEInfo
&Info
);
253 /// \defgroup Linking Methods used to link the debug information
259 RelocationManager
&RelocMgr
;
261 /// Allocator used for all the DIEValue objects.
262 BumpPtrAllocator
&DIEAlloc
;
264 std::vector
<std::unique_ptr
<CompileUnit
>> &CompileUnits
;
268 DIECloner(DwarfLinker
&Linker
, RelocationManager
&RelocMgr
,
269 BumpPtrAllocator
&DIEAlloc
,
270 std::vector
<std::unique_ptr
<CompileUnit
>> &CompileUnits
,
271 LinkOptions
&Options
)
272 : Linker(Linker
), RelocMgr(RelocMgr
), DIEAlloc(DIEAlloc
),
273 CompileUnits(CompileUnits
), Options(Options
) {}
275 /// Recursively clone \p InputDIE into an tree of DIE objects
276 /// where useless (as decided by lookForDIEsToKeep()) bits have been
277 /// stripped out and addresses have been rewritten according to the
280 /// \param OutOffset is the offset the cloned DIE in the output
282 /// \param PCOffset (while cloning a function scope) is the offset
283 /// applied to the entry point of the function to get the linked address.
284 /// \param Die the output DIE to use, pass NULL to create one.
285 /// \returns the root of the cloned tree or null if nothing was selected.
286 DIE
*cloneDIE(const DWARFDie
&InputDIE
, const DebugMapObject
&DMO
,
287 CompileUnit
&U
, OffsetsStringPool
&StringPool
,
288 int64_t PCOffset
, uint32_t OutOffset
, unsigned Flags
,
291 /// Construct the output DIE tree by cloning the DIEs we
292 /// chose to keep above. If there are no valid relocs, then there's
293 /// nothing to clone/emit.
294 void cloneAllCompileUnits(DWARFContext
&DwarfContext
,
295 const DebugMapObject
&DMO
, RangesTy
&Ranges
,
296 OffsetsStringPool
&StringPool
);
299 using AttributeSpec
= DWARFAbbreviationDeclaration::AttributeSpec
;
301 /// Information gathered and exchanged between the various
302 /// clone*Attributes helpers about the attributes of a particular DIE.
303 struct AttributesInfo
{
305 DwarfStringPoolEntryRef Name
, MangledName
, NameWithoutTemplate
;
307 /// Offsets in the string pool.
308 uint32_t NameOffset
= 0;
309 uint32_t MangledNameOffset
= 0;
311 /// Value of AT_low_pc in the input DIE
312 uint64_t OrigLowPc
= std::numeric_limits
<uint64_t>::max();
314 /// Value of AT_high_pc in the input DIE
315 uint64_t OrigHighPc
= 0;
317 /// Offset to apply to PC addresses inside a function.
318 int64_t PCOffset
= 0;
320 /// Does the DIE have a low_pc attribute?
321 bool HasLowPc
= false;
323 /// Does the DIE have a ranges attribute?
324 bool HasRanges
= false;
326 /// Is this DIE only a declaration?
327 bool IsDeclaration
= false;
329 AttributesInfo() = default;
332 /// Helper for cloneDIE.
333 unsigned cloneAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
334 const DebugMapObject
&DMO
, CompileUnit
&U
,
335 OffsetsStringPool
&StringPool
,
336 const DWARFFormValue
&Val
,
337 const AttributeSpec AttrSpec
, unsigned AttrSize
,
338 AttributesInfo
&AttrInfo
);
340 /// Clone a string attribute described by \p AttrSpec and add
342 /// \returns the size of the new attribute.
343 unsigned cloneStringAttribute(DIE
&Die
, AttributeSpec AttrSpec
,
344 const DWARFFormValue
&Val
, const DWARFUnit
&U
,
345 OffsetsStringPool
&StringPool
,
346 AttributesInfo
&Info
);
348 /// Clone an attribute referencing another DIE and add
350 /// \returns the size of the new attribute.
351 unsigned cloneDieReferenceAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
352 AttributeSpec AttrSpec
,
354 const DWARFFormValue
&Val
,
355 const DebugMapObject
&DMO
,
358 /// Clone an attribute referencing another DIE and add
360 /// \returns the size of the new attribute.
361 unsigned cloneBlockAttribute(DIE
&Die
, AttributeSpec AttrSpec
,
362 const DWARFFormValue
&Val
, unsigned AttrSize
);
364 /// Clone an attribute referencing another DIE and add
366 /// \returns the size of the new attribute.
367 unsigned cloneAddressAttribute(DIE
&Die
, AttributeSpec AttrSpec
,
368 const DWARFFormValue
&Val
,
369 const CompileUnit
&Unit
,
370 AttributesInfo
&Info
);
372 /// Clone a scalar attribute and add it to \p Die.
373 /// \returns the size of the new attribute.
374 unsigned cloneScalarAttribute(DIE
&Die
, const DWARFDie
&InputDIE
,
375 const DebugMapObject
&DMO
, CompileUnit
&U
,
376 AttributeSpec AttrSpec
,
377 const DWARFFormValue
&Val
, unsigned AttrSize
,
378 AttributesInfo
&Info
);
380 /// Get the potential name and mangled name for the entity
381 /// described by \p Die and store them in \Info if they are not
383 /// \returns is a name was found.
384 bool getDIENames(const DWARFDie
&Die
, AttributesInfo
&Info
,
385 OffsetsStringPool
&StringPool
, bool StripTemplate
= false);
387 /// Create a copy of abbreviation Abbrev.
388 void copyAbbrev(const DWARFAbbreviationDeclaration
&Abbrev
, bool hasODR
);
390 uint32_t hashFullyQualifiedName(DWARFDie DIE
, CompileUnit
&U
,
391 const DebugMapObject
&DMO
,
392 int RecurseDepth
= 0);
394 /// Helper for cloneDIE.
395 void addObjCAccelerator(CompileUnit
&Unit
, const DIE
*Die
,
396 DwarfStringPoolEntryRef Name
,
397 OffsetsStringPool
&StringPool
, bool SkipPubSection
);
400 /// Assign an abbreviation number to \p Abbrev
401 void AssignAbbrev(DIEAbbrev
&Abbrev
);
403 /// Compute and emit debug_ranges section for \p Unit, and
404 /// patch the attributes referencing it.
405 void patchRangesForUnit(const CompileUnit
&Unit
, DWARFContext
&Dwarf
,
406 const DebugMapObject
&DMO
) const;
408 /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had
410 void generateUnitRanges(CompileUnit
&Unit
) const;
412 /// Extract the line tables from the original dwarf, extract the relevant
413 /// parts according to the linked function ranges and emit the result in the
414 /// debug_line section.
415 void patchLineTableForUnit(CompileUnit
&Unit
, DWARFContext
&OrigDwarf
,
416 RangesTy
&Ranges
, const DebugMapObject
&DMO
);
418 /// Emit the accelerator entries for \p Unit.
419 void emitAcceleratorEntriesForUnit(CompileUnit
&Unit
);
420 void emitDwarfAcceleratorEntriesForUnit(CompileUnit
&Unit
);
421 void emitAppleAcceleratorEntriesForUnit(CompileUnit
&Unit
);
423 /// Patch the frame info for an object file and emit it.
424 void patchFrameInfoForObject(const DebugMapObject
&, RangesTy
&Ranges
,
425 DWARFContext
&, unsigned AddressSize
);
427 /// FoldingSet that uniques the abbreviations.
428 FoldingSet
<DIEAbbrev
> AbbreviationsSet
;
430 /// Storage for the unique Abbreviations.
431 /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be
432 /// changed to a vector of unique_ptrs.
433 std::vector
<std::unique_ptr
<DIEAbbrev
>> Abbreviations
;
435 /// DIELoc objects that need to be destructed (but not freed!).
436 std::vector
<DIELoc
*> DIELocs
;
438 /// DIEBlock objects that need to be destructed (but not freed!).
439 std::vector
<DIEBlock
*> DIEBlocks
;
441 /// Allocator used for all the DIEValue objects.
442 BumpPtrAllocator DIEAlloc
;
445 /// \defgroup Helpers Various helper methods.
448 bool createStreamer(const Triple
&TheTriple
, raw_fd_ostream
&OutFile
);
450 /// Attempt to load a debug object from disk.
451 ErrorOr
<const object::ObjectFile
&> loadObject(const DebugMapObject
&Obj
,
452 const DebugMap
&Map
);
455 raw_fd_ostream
&OutFile
;
456 BinaryHolder
&BinHolder
;
458 std::unique_ptr
<DwarfStreamer
> Streamer
;
459 uint64_t OutputDebugInfoSize
;
461 unsigned MaxDwarfVersion
= 0;
462 unsigned MinDwarfVersion
= std::numeric_limits
<unsigned>::max();
464 bool AtLeastOneAppleAccelTable
= false;
465 bool AtLeastOneDwarfAccelTable
= false;
467 /// The CIEs that have been emitted in the output section. The actual CIE
468 /// data serves a the key to this StringMap, this takes care of comparing the
469 /// semantics of CIEs defined in different object files.
470 StringMap
<uint32_t> EmittedCIEs
;
472 /// Offset of the last CIE that has been emitted in the output
473 /// debug_frame section.
474 uint32_t LastCIEOffset
= 0;
476 /// Apple accelerator tables.
477 AccelTable
<DWARF5AccelTableStaticData
> DebugNames
;
478 AccelTable
<AppleAccelTableStaticOffsetData
> AppleNames
;
479 AccelTable
<AppleAccelTableStaticOffsetData
> AppleNamespaces
;
480 AccelTable
<AppleAccelTableStaticOffsetData
> AppleObjc
;
481 AccelTable
<AppleAccelTableStaticTypeData
> AppleTypes
;
483 /// Mapping the PCM filename to the DwoId.
484 StringMap
<uint64_t> ClangModules
;
486 bool ModuleCacheHintDisplayed
= false;
487 bool ArchiveHintDisplayed
= false;
490 } // end namespace dsymutil
491 } // end namespace llvm
493 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H