1 //===- DWARFLinkerUnit.h ----------------------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERUNIT_H
10 #define LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERUNIT_H
11 
12 #include "DWARFLinkerGlobalData.h"
13 #include "OutputSections.h"
14 #include "llvm/CodeGen/DIE.h"
15 #include "llvm/DWARFLinker/IndexedValuesMap.h"
16 #include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
17 #include "llvm/DWARFLinker/StringPool.h"
18 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
19 #include "llvm/Support/LEB128.h"
20 
21 namespace llvm {
22 namespace dwarf_linker {
23 namespace parallel {
24 
25 class DwarfUnit;
26 using MacroOffset2UnitMapTy = DenseMap<uint64_t, DwarfUnit *>;
27 
28 /// Base class for all Dwarf units(Compile unit/Type table unit).
29 class DwarfUnit : public OutputSections {
30 public:
31   virtual ~DwarfUnit() {}
32   DwarfUnit(LinkingGlobalData &GlobalData, unsigned ID,
33             StringRef ClangModuleName)
34       : OutputSections(GlobalData), ID(ID), ClangModuleName(ClangModuleName),
35         OutUnitDIE(nullptr) {}
36 
37   /// Unique id of the unit.
38   unsigned getUniqueID() const { return ID; }
39 
40   /// Returns size of this(newly generated) compile unit.
41   uint64_t getUnitSize() const { return UnitSize; }
42 
43   /// Returns this unit name.
44   StringRef getUnitName() const { return UnitName; }
45 
46   /// Return the DW_AT_LLVM_sysroot of the compile unit or an empty StringRef.
47   StringRef getSysRoot() { return SysRoot; }
48 
49   /// Return true if this compile unit is from Clang module.
50   bool isClangModule() const { return !ClangModuleName.empty(); }
51 
52   /// Return Clang module name;
53   const std::string &getClangModuleName() const { return ClangModuleName; }
54 
55   /// Return global data.
56   LinkingGlobalData &getGlobalData() { return GlobalData; }
57 
58   /// Returns true if unit is inter-connected(it references/referenced by other
59   /// unit).
60   bool isInterconnectedCU() const { return IsInterconnectedCU; }
61 
62   /// Mark this unit as inter-connected(it references/referenced by other unit).
63   void setInterconnectedCU() { IsInterconnectedCU = true; }
64 
65   /// Adds \p Abbrev into unit`s abbreviation table.
66   void assignAbbrev(DIEAbbrev &Abbrev);
67 
68   /// Returns abbreviations for this compile unit.
69   const std::vector<std::unique_ptr<DIEAbbrev>> &getAbbreviations() const {
70     return Abbreviations;
71   }
72 
73   /// Returns output unit DIE.
74   DIE *getOutUnitDIE() { return OutUnitDIE; }
75 
76   /// Set output unit DIE.
77   void setOutUnitDIE(DIE *UnitDie) {
78     OutUnitDIE = UnitDie;
79 
80     if (OutUnitDIE != nullptr)
81       UnitSize = getDebugInfoHeaderSize() + OutUnitDIE->getSize();
82   }
83 
84   /// \defgroup Methods used to emit unit's debug info:
85   ///
86   /// @{
87   /// Emit unit's abbreviations.
88   Error emitAbbreviations();
89 
90   /// Emit .debug_info section for unit DIEs.
91   Error emitDebugInfo(const Triple &TargetTriple);
92 
93   /// Emit .debug_line section.
94   Error emitDebugLine(const Triple &TargetTriple,
95                       const DWARFDebugLine::LineTable &OutLineTable);
96 
97   /// Emit the .debug_str_offsets section for current unit.
98   Error emitDebugStringOffsetSection();
99   /// @}
100 
101   /// \defgroup Methods used for reporting warnings and errors:
102   ///
103   /// @{
104   void warn(const Twine &Warning) { GlobalData.warn(Warning, getUnitName()); }
105 
106   void error(const Twine &Err) { GlobalData.warn(Err, getUnitName()); }
107   /// @}
108 
109   /// \defgroup Methods and data members used for building accelerator tables:
110   ///
111   /// @{
112 
113   enum class AccelType : uint8_t { None, Name, Namespace, ObjC, Type };
114 
115   /// This structure keeps fields which would be used for creating accelerator
116   /// table.
117   struct AccelInfo {
118     AccelInfo() {
119       AvoidForPubSections = false;
120       ObjcClassImplementation = false;
121     }
122 
123     /// Name of the entry.
124     StringEntry *String = nullptr;
125 
126     /// Output offset of the DIE this entry describes.
127     uint64_t OutOffset;
128 
129     /// Hash of the fully qualified name.
130     uint32_t QualifiedNameHash = 0;
131 
132     /// Tag of the DIE this entry describes.
133     dwarf::Tag Tag = dwarf::DW_TAG_null;
134 
135     /// Type of this accelerator record.
136     AccelType Type = AccelType::None;
137 
138     /// Avoid emitting this entry for pub sections.
139     bool AvoidForPubSections : 1;
140 
141     /// Is this an ObjC class implementation?
142     bool ObjcClassImplementation : 1;
143   };
144 
145   /// Emit .debug_pubnames and .debug_pubtypes for \p Unit.
146   void emitPubAccelerators();
147 
148   /// Enumerates accelerator data.
149   virtual void
150   forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) = 0;
151 
152   /// @}
153 
154   /// Returns index(inside .debug_str_offsets) of specified string.
155   virtual uint64_t getDebugStrIndex(const StringEntry *String) {
156     return DebugStringIndexMap.getValueIndex(String);
157   }
158 
159 protected:
160   /// Emit single abbreviation entry.
161   void emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev,
162                             SectionDescriptor &AbbrevSection);
163 
164   /// Emit single pubnames/pubtypes accelerator entry.
165   std::optional<uint64_t>
166   emitPubAcceleratorEntry(SectionDescriptor &OutSection, const AccelInfo &Info,
167                           std::optional<uint64_t> LengthOffset);
168 
169   /// Unique ID for the unit.
170   unsigned ID = 0;
171 
172   /// The name of this unit.
173   std::string UnitName;
174 
175   /// The DW_AT_LLVM_sysroot of this unit.
176   std::string SysRoot;
177 
178   /// If this is a Clang module, this holds the module's name.
179   std::string ClangModuleName;
180 
181   uint64_t UnitSize = 0;
182 
183   /// true if current unit references_to/is_referenced by other unit.
184   std::atomic<bool> IsInterconnectedCU = {false};
185 
186   /// FoldingSet that uniques the abbreviations.
187   FoldingSet<DIEAbbrev> AbbreviationsSet;
188 
189   /// Storage for the unique Abbreviations.
190   std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
191 
192   /// Output unit DIE.
193   DIE *OutUnitDIE = nullptr;
194 
195   /// Cache for file names for this unit.
196   using FileNamesCache =
197       DenseMap<uint64_t, std::pair<std::string, std::string>>;
198   FileNamesCache FileNames;
199 
200   /// Maps a string into the index inside .debug_str_offsets section.
201   IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
202 };
203 
204 inline bool isODRLanguage(uint16_t Language) {
205   switch (Language) {
206   case dwarf::DW_LANG_C_plus_plus:
207   case dwarf::DW_LANG_C_plus_plus_03:
208   case dwarf::DW_LANG_C_plus_plus_11:
209   case dwarf::DW_LANG_C_plus_plus_14:
210   case dwarf::DW_LANG_ObjC_plus_plus:
211     return true;
212   default:
213     return false;
214   };
215 
216   return false;
217 }
218 
219 } // end of namespace parallel
220 } // end of namespace dwarf_linker
221 } // end of namespace llvm
222 
223 #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERUNIT_H
224