• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- tools/dsymutil/DwarfLinker.h - Dwarf debug info linker ---*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
11 #define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
12 
13 #include "BinaryHolder.h"
14 #include "CompileUnit.h"
15 #include "DebugMap.h"
16 #include "DeclContext.h"
17 #include "DwarfStreamer.h"
18 #include "LinkUtils.h"
19 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
20 
21 namespace llvm {
22 namespace dsymutil {
23 
24 /// Partial address range for debug map objects. Besides an offset, only the
25 /// HighPC is stored. The structure is stored in a map where the LowPC is the
26 /// key.
27 struct DebugMapObjectRange {
28   /// Function HighPC.
29   uint64_t HighPC;
30   /// Offset to apply to the linked address.
31   int64_t Offset;
32 
DebugMapObjectRangeDebugMapObjectRange33   DebugMapObjectRange(uint64_t EndPC, int64_t Offset)
34       : HighPC(EndPC), Offset(Offset) {}
35 
DebugMapObjectRangeDebugMapObjectRange36   DebugMapObjectRange() : HighPC(0), Offset(0) {}
37 };
38 
39 /// Map LowPC to DebugMapObjectRange.
40 using RangesTy = std::map<uint64_t, DebugMapObjectRange>;
41 using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>;
42 
43 /// The core of the Dwarf linking logic.
44 ///
45 /// The link of the dwarf information from the object files will be
46 /// driven by the selection of 'root DIEs', which are DIEs that
47 /// describe variables or functions that are present in the linked
48 /// binary (and thus have entries in the debug map). All the debug
49 /// information that will be linked (the DIEs, but also the line
50 /// tables, ranges, ...) is derived from that set of root DIEs.
51 ///
52 /// The root DIEs are identified because they contain relocations that
53 /// correspond to a debug map entry at specific places (the low_pc for
54 /// a function, the location for a variable). These relocations are
55 /// called ValidRelocs in the DwarfLinker and are gathered as a very
56 /// first step when we start processing a DebugMapObject.
57 class DwarfLinker {
58 public:
DwarfLinker(raw_fd_ostream & OutFile,BinaryHolder & BinHolder,const LinkOptions & Options)59   DwarfLinker(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
60               const LinkOptions &Options)
61       : OutFile(OutFile), BinHolder(BinHolder), Options(Options) {}
62 
63   /// Link the contents of the DebugMap.
64   bool link(const DebugMap &);
65 
66   void reportWarning(const Twine &Warning, const DebugMapObject &DMO,
67                      const DWARFDie *DIE = nullptr) const;
68 
69 private:
70   /// Remembers the oldest and newest DWARF version we've seen in a unit.
updateDwarfVersion(unsigned Version)71   void updateDwarfVersion(unsigned Version) {
72     MaxDwarfVersion = std::max(MaxDwarfVersion, Version);
73     MinDwarfVersion = std::min(MinDwarfVersion, Version);
74   }
75 
76   /// Remembers the kinds of accelerator tables we've seen in a unit.
77   void updateAccelKind(DWARFContext &Dwarf);
78 
79   /// Emit warnings as Dwarf compile units to leave a trail after linking.
80   bool emitPaperTrailWarnings(const DebugMapObject &DMO, const DebugMap &Map,
81                               OffsetsStringPool &StringPool);
82 
83   /// Keeps track of relocations.
84   class RelocationManager {
85     struct ValidReloc {
86       uint32_t Offset;
87       uint32_t Size;
88       uint64_t Addend;
89       const DebugMapObject::DebugMapEntry *Mapping;
90 
ValidRelocValidReloc91       ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
92                  const DebugMapObject::DebugMapEntry *Mapping)
93           : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
94 
95       bool operator<(const ValidReloc &RHS) const {
96         return Offset < RHS.Offset;
97       }
98     };
99 
100     const DwarfLinker &Linker;
101 
102     /// The valid relocations for the current DebugMapObject.
103     /// This vector is sorted by relocation offset.
104     std::vector<ValidReloc> ValidRelocs;
105 
106     /// Index into ValidRelocs of the next relocation to consider. As we walk
107     /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
108     /// offset, keeping this index up to date is all we have to do to have a
109     /// cheap lookup during the root DIE selection and during DIE cloning.
110     unsigned NextValidReloc = 0;
111 
112   public:
RelocationManager(DwarfLinker & Linker)113     RelocationManager(DwarfLinker &Linker) : Linker(Linker) {}
114 
hasValidRelocs()115     bool hasValidRelocs() const { return !ValidRelocs.empty(); }
116 
117     /// Reset the NextValidReloc counter.
resetValidRelocs()118     void resetValidRelocs() { NextValidReloc = 0; }
119 
120     /// \defgroup FindValidRelocations Translate debug map into a list
121     /// of relevant relocations
122     ///
123     /// @{
124     bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
125                                     const DebugMapObject &DMO);
126 
127     bool findValidRelocs(const object::SectionRef &Section,
128                          const object::ObjectFile &Obj,
129                          const DebugMapObject &DMO);
130 
131     void findValidRelocsMachO(const object::SectionRef &Section,
132                               const object::MachOObjectFile &Obj,
133                               const DebugMapObject &DMO);
134     /// @}
135 
136     bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
137                             CompileUnit::DIEInfo &Info);
138 
139     bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
140                           bool isLittleEndian);
141   };
142 
143   /// Keeps track of data associated with one object during linking.
144   struct LinkContext {
145     DebugMapObject &DMO;
146     const object::ObjectFile *ObjectFile;
147     RelocationManager RelocMgr;
148     std::unique_ptr<DWARFContext> DwarfContext;
149     RangesTy Ranges;
150     UnitListTy CompileUnits;
151 
LinkContextLinkContext152     LinkContext(const DebugMap &Map, DwarfLinker &Linker, DebugMapObject &DMO)
153         : DMO(DMO), RelocMgr(Linker) {
154       // Swift ASTs are not object files.
155       if (DMO.getType() == MachO::N_AST) {
156         ObjectFile = nullptr;
157         return;
158       }
159       auto ErrOrObj = Linker.loadObject(DMO, Map);
160       ObjectFile = ErrOrObj ? &*ErrOrObj : nullptr;
161       DwarfContext = ObjectFile ? DWARFContext::create(*ObjectFile) : nullptr;
162     }
163 
164     /// Clear part of the context that's no longer needed when we're done with
165     /// the debug object.
ClearLinkContext166     void Clear() {
167       DwarfContext.reset(nullptr);
168       CompileUnits.clear();
169       Ranges.clear();
170     }
171   };
172 
173   /// Called at the start of a debug object link.
174   void startDebugObject(LinkContext &Context);
175 
176   /// Called at the end of a debug object link.
177   void endDebugObject(LinkContext &Context);
178 
179   /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
180   ///
181   /// @{
182   /// Recursively walk the \p DIE tree and look for DIEs to
183   /// keep. Store that information in \p CU's DIEInfo.
184   ///
185   /// The return value indicates whether the DIE is incomplete.
186   void lookForDIEsToKeep(RelocationManager &RelocMgr, RangesTy &Ranges,
187                          const UnitListTy &Units, const DWARFDie &DIE,
188                          const DebugMapObject &DMO, CompileUnit &CU,
189                          unsigned Flags);
190 
191   /// If this compile unit is really a skeleton CU that points to a
192   /// clang module, register it in ClangModules and return true.
193   ///
194   /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
195   /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
196   /// hash.
197   bool registerModuleReference(const DWARFDie &CUDie, const DWARFUnit &Unit,
198                                DebugMap &ModuleMap, const DebugMapObject &DMO,
199                                RangesTy &Ranges,
200                                OffsetsStringPool &OffsetsStringPool,
201                                UniquingStringPool &UniquingStringPoolStringPool,
202                                DeclContextTree &ODRContexts, unsigned &UnitID,
203                                unsigned Indent = 0);
204 
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)
207   /// to Units.
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, unsigned &UnitID,
214                         unsigned Indent = 0);
215 
216   /// Flags passed to DwarfLinker::lookForDIEsToKeep
217   enum TraversalFlags {
218     TF_Keep = 1 << 0,            ///< Mark the traversed DIEs as kept.
219     TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope.
220     TF_DependencyWalk = 1 << 2,  ///< Walking the dependencies of a kept DIE.
221     TF_ParentWalk = 1 << 3,      ///< Walking up the parents of a kept DIE.
222     TF_ODR = 1 << 4,             ///< Use the ODR while keeping dependents.
223     TF_SkipPC = 1 << 5,          ///< Skip all location attributes.
224   };
225 
226   /// Mark the passed DIE as well as all the ones it depends on as kept.
227   void keepDIEAndDependencies(RelocationManager &RelocMgr, RangesTy &Ranges,
228                               const UnitListTy &Units, const DWARFDie &DIE,
229                               CompileUnit::DIEInfo &MyInfo,
230                               const DebugMapObject &DMO, CompileUnit &CU,
231                               bool UseODR);
232 
233   unsigned shouldKeepDIE(RelocationManager &RelocMgr, RangesTy &Ranges,
234                          const DWARFDie &DIE, const DebugMapObject &DMO,
235                          CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
236                          unsigned Flags);
237 
238   unsigned shouldKeepVariableDIE(RelocationManager &RelocMgr,
239                                  const DWARFDie &DIE, CompileUnit &Unit,
240                                  CompileUnit::DIEInfo &MyInfo, unsigned Flags);
241 
242   unsigned shouldKeepSubprogramDIE(RelocationManager &RelocMgr,
243                                    RangesTy &Ranges, const DWARFDie &DIE,
244                                    const DebugMapObject &DMO, CompileUnit &Unit,
245                                    CompileUnit::DIEInfo &MyInfo,
246                                    unsigned Flags);
247 
248   bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
249                           CompileUnit::DIEInfo &Info);
250   /// @}
251 
252   /// \defgroup Linking Methods used to link the debug information
253   ///
254   /// @{
255 
256   class DIECloner {
257     DwarfLinker &Linker;
258     RelocationManager &RelocMgr;
259 
260     /// Allocator used for all the DIEValue objects.
261     BumpPtrAllocator &DIEAlloc;
262 
263     std::vector<std::unique_ptr<CompileUnit>> &CompileUnits;
264     LinkOptions Options;
265 
266   public:
DIECloner(DwarfLinker & Linker,RelocationManager & RelocMgr,BumpPtrAllocator & DIEAlloc,std::vector<std::unique_ptr<CompileUnit>> & CompileUnits,LinkOptions & Options)267     DIECloner(DwarfLinker &Linker, RelocationManager &RelocMgr,
268               BumpPtrAllocator &DIEAlloc,
269               std::vector<std::unique_ptr<CompileUnit>> &CompileUnits,
270               LinkOptions &Options)
271         : Linker(Linker), RelocMgr(RelocMgr), DIEAlloc(DIEAlloc),
272           CompileUnits(CompileUnits), Options(Options) {}
273 
274     /// Recursively clone \p InputDIE into an tree of DIE objects
275     /// where useless (as decided by lookForDIEsToKeep()) bits have been
276     /// stripped out and addresses have been rewritten according to the
277     /// debug map.
278     ///
279     /// \param OutOffset is the offset the cloned DIE in the output
280     /// compile unit.
281     /// \param PCOffset (while cloning a function scope) is the offset
282     /// applied to the entry point of the function to get the linked address.
283     /// \param Die the output DIE to use, pass NULL to create one.
284     /// \returns the root of the cloned tree or null if nothing was selected.
285     DIE *cloneDIE(const DWARFDie &InputDIE, const DebugMapObject &DMO,
286                   CompileUnit &U, OffsetsStringPool &StringPool,
287                   int64_t PCOffset, uint32_t OutOffset, unsigned Flags,
288                   DIE *Die = nullptr);
289 
290     /// Construct the output DIE tree by cloning the DIEs we
291     /// chose to keep above. If there are no valid relocs, then there's
292     /// nothing to clone/emit.
293     void cloneAllCompileUnits(DWARFContext &DwarfContext,
294                               const DebugMapObject &DMO, RangesTy &Ranges,
295                               OffsetsStringPool &StringPool);
296 
297   private:
298     using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec;
299 
300     /// Information gathered and exchanged between the various
301     /// clone*Attributes helpers about the attributes of a particular DIE.
302     struct AttributesInfo {
303       /// Names.
304       DwarfStringPoolEntryRef Name, MangledName, NameWithoutTemplate;
305 
306       /// Offsets in the string pool.
307       uint32_t NameOffset = 0;
308       uint32_t MangledNameOffset = 0;
309 
310       /// Value of AT_low_pc in the input DIE
311       uint64_t OrigLowPc = std::numeric_limits<uint64_t>::max();
312 
313       /// Value of AT_high_pc in the input DIE
314       uint64_t OrigHighPc = 0;
315 
316       /// Offset to apply to PC addresses inside a function.
317       int64_t PCOffset = 0;
318 
319       /// Does the DIE have a low_pc attribute?
320       bool HasLowPc = false;
321 
322       /// Does the DIE have a ranges attribute?
323       bool HasRanges = false;
324 
325       /// Is this DIE only a declaration?
326       bool IsDeclaration = false;
327 
328       AttributesInfo() = default;
329     };
330 
331     /// Helper for cloneDIE.
332     unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE,
333                             const DebugMapObject &DMO, CompileUnit &U,
334                             OffsetsStringPool &StringPool,
335                             const DWARFFormValue &Val,
336                             const AttributeSpec AttrSpec, unsigned AttrSize,
337                             AttributesInfo &AttrInfo);
338 
339     /// Clone a string attribute described by \p AttrSpec and add
340     /// it to \p Die.
341     /// \returns the size of the new attribute.
342     unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
343                                   const DWARFFormValue &Val, const DWARFUnit &U,
344                                   OffsetsStringPool &StringPool,
345                                   AttributesInfo &Info);
346 
347     /// Clone an attribute referencing another DIE and add
348     /// it to \p Die.
349     /// \returns the size of the new attribute.
350     unsigned cloneDieReferenceAttribute(DIE &Die, const DWARFDie &InputDIE,
351                                         AttributeSpec AttrSpec,
352                                         unsigned AttrSize,
353                                         const DWARFFormValue &Val,
354                                         const DebugMapObject &DMO,
355                                         CompileUnit &Unit);
356 
357     /// Clone an attribute referencing another DIE and add
358     /// it to \p Die.
359     /// \returns the size of the new attribute.
360     unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec,
361                                  const DWARFFormValue &Val, unsigned AttrSize);
362 
363     /// Clone an attribute referencing another DIE and add
364     /// it to \p Die.
365     /// \returns the size of the new attribute.
366     unsigned cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
367                                    const DWARFFormValue &Val,
368                                    const CompileUnit &Unit,
369                                    AttributesInfo &Info);
370 
371     /// Clone a scalar attribute  and add it to \p Die.
372     /// \returns the size of the new attribute.
373     unsigned cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE,
374                                   const DebugMapObject &DMO, CompileUnit &U,
375                                   AttributeSpec AttrSpec,
376                                   const DWARFFormValue &Val, unsigned AttrSize,
377                                   AttributesInfo &Info);
378 
379     /// Get the potential name and mangled name for the entity
380     /// described by \p Die and store them in \Info if they are not
381     /// already there.
382     /// \returns is a name was found.
383     bool getDIENames(const DWARFDie &Die, AttributesInfo &Info,
384                      OffsetsStringPool &StringPool, bool StripTemplate = false);
385 
386     /// Create a copy of abbreviation Abbrev.
387     void copyAbbrev(const DWARFAbbreviationDeclaration &Abbrev, bool hasODR);
388 
389     uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U,
390                                     const DebugMapObject &DMO,
391                                     int RecurseDepth = 0);
392 
393     /// Helper for cloneDIE.
394     void addObjCAccelerator(CompileUnit &Unit, const DIE *Die,
395                             DwarfStringPoolEntryRef Name,
396                             OffsetsStringPool &StringPool, bool SkipPubSection);
397   };
398 
399   /// Assign an abbreviation number to \p Abbrev
400   void AssignAbbrev(DIEAbbrev &Abbrev);
401 
402   /// Compute and emit debug_ranges section for \p Unit, and
403   /// patch the attributes referencing it.
404   void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf,
405                           const DebugMapObject &DMO) const;
406 
407   /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had
408   /// one.
409   void generateUnitRanges(CompileUnit &Unit) const;
410 
411   /// Extract the line tables from the original dwarf, extract the relevant
412   /// parts according to the linked function ranges and emit the result in the
413   /// debug_line section.
414   void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf,
415                              RangesTy &Ranges, const DebugMapObject &DMO);
416 
417   /// Emit the accelerator entries for \p Unit.
418   void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
419   void emitDwarfAcceleratorEntriesForUnit(CompileUnit &Unit);
420   void emitAppleAcceleratorEntriesForUnit(CompileUnit &Unit);
421 
422   /// Patch the frame info for an object file and emit it.
423   void patchFrameInfoForObject(const DebugMapObject &, RangesTy &Ranges,
424                                DWARFContext &, unsigned AddressSize);
425 
426   /// FoldingSet that uniques the abbreviations.
427   FoldingSet<DIEAbbrev> AbbreviationsSet;
428 
429   /// Storage for the unique Abbreviations.
430   /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be
431   /// changed to a vector of unique_ptrs.
432   std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
433 
434   /// DIELoc objects that need to be destructed (but not freed!).
435   std::vector<DIELoc *> DIELocs;
436 
437   /// DIEBlock objects that need to be destructed (but not freed!).
438   std::vector<DIEBlock *> DIEBlocks;
439 
440   /// Allocator used for all the DIEValue objects.
441   BumpPtrAllocator DIEAlloc;
442   /// @}
443 
444   /// \defgroup Helpers Various helper methods.
445   ///
446   /// @{
447   bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile);
448 
449   /// Attempt to load a debug object from disk.
450   ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
451                                                  const DebugMap &Map);
452   /// @}
453 
454   raw_fd_ostream &OutFile;
455   BinaryHolder &BinHolder;
456   LinkOptions Options;
457   std::unique_ptr<DwarfStreamer> Streamer;
458   uint64_t OutputDebugInfoSize;
459 
460   unsigned MaxDwarfVersion = 0;
461   unsigned MinDwarfVersion = std::numeric_limits<unsigned>::max();
462 
463   bool AtLeastOneAppleAccelTable = false;
464   bool AtLeastOneDwarfAccelTable = false;
465 
466   /// The CIEs that have been emitted in the output section. The actual CIE
467   /// data serves a the key to this StringMap, this takes care of comparing the
468   /// semantics of CIEs defined in different object files.
469   StringMap<uint32_t> EmittedCIEs;
470 
471   /// Offset of the last CIE that has been emitted in the output
472   /// debug_frame section.
473   uint32_t LastCIEOffset = 0;
474 
475   /// Apple accelerator tables.
476   AccelTable<DWARF5AccelTableStaticData> DebugNames;
477   AccelTable<AppleAccelTableStaticOffsetData> AppleNames;
478   AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces;
479   AccelTable<AppleAccelTableStaticOffsetData> AppleObjc;
480   AccelTable<AppleAccelTableStaticTypeData> AppleTypes;
481 
482   /// Mapping the PCM filename to the DwoId.
483   StringMap<uint64_t> ClangModules;
484 
485   bool ModuleCacheHintDisplayed = false;
486   bool ArchiveHintDisplayed = false;
487 };
488 
489 } // end namespace dsymutil
490 } // end namespace llvm
491 
492 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
493