Stephen Hines | c6ca60f | 2023-05-09 02:19:22 -0700 | [diff] [blame^] | 1 | //===- DWARFLinker.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_DWARFLINKER_DWARFLINKER_H |
| 10 | #define LLVM_DWARFLINKER_DWARFLINKER_H |
| 11 | |
| 12 | #include "llvm/ADT/AddressRanges.h" |
| 13 | #include "llvm/ADT/DenseMap.h" |
| 14 | #include "llvm/CodeGen/AccelTable.h" |
| 15 | #include "llvm/CodeGen/NonRelocatableStringpool.h" |
| 16 | #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" |
| 17 | #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
| 18 | #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" |
| 19 | #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
| 20 | #include <map> |
| 21 | |
| 22 | namespace llvm { |
| 23 | class DWARFContext; |
| 24 | class DWARFExpression; |
| 25 | class DWARFUnit; |
| 26 | class DataExtractor; |
| 27 | class DeclContextTree; |
| 28 | struct MCDwarfLineTableParams; |
| 29 | template <typename T> class SmallVectorImpl; |
| 30 | |
| 31 | enum class DwarfLinkerClient { Dsymutil, LLD, General }; |
| 32 | |
| 33 | /// The kind of accelerator tables we should emit. |
| 34 | enum class DwarfLinkerAccelTableKind : uint8_t { |
| 35 | Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc. |
| 36 | Pub, ///< .debug_pubnames, .debug_pubtypes |
| 37 | DebugNames ///< .debug_names. |
| 38 | }; |
| 39 | |
| 40 | /// AddressesMap represents information about valid addresses used |
| 41 | /// by debug information. Valid addresses are those which points to |
| 42 | /// live code sections. i.e. relocations for these addresses point |
| 43 | /// into sections which would be/are placed into resulting binary. |
| 44 | class AddressesMap { |
| 45 | public: |
| 46 | virtual ~AddressesMap(); |
| 47 | |
| 48 | /// Checks that there are valid relocations against a .debug_info |
| 49 | /// section. |
| 50 | virtual bool hasValidRelocs() = 0; |
| 51 | |
| 52 | /// Checks that the specified variable \p DIE references live code section. |
| 53 | /// Allowed kind of input die: DW_TAG_variable, DW_TAG_constant. |
| 54 | /// \returns true and sets Info.InDebugMap if it is the case. |
| 55 | virtual bool isLiveVariable(const DWARFDie &DIE, |
| 56 | CompileUnit::DIEInfo &Info) = 0; |
| 57 | |
| 58 | /// Checks that the specified subprogram \p DIE references live code section. |
| 59 | /// Allowed kind of input die: DW_TAG_subprogram, DW_TAG_label. |
| 60 | /// \returns true and sets Info.InDebugMap if it is the case. |
| 61 | virtual bool isLiveSubprogram(const DWARFDie &DIE, |
| 62 | CompileUnit::DIEInfo &Info) = 0; |
| 63 | |
| 64 | /// Apply the valid relocations to the buffer \p Data, taking into |
| 65 | /// account that Data is at \p BaseOffset in the .debug_info section. |
| 66 | /// |
| 67 | /// \returns true whether any reloc has been applied. |
| 68 | virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, |
| 69 | bool IsLittleEndian) = 0; |
| 70 | |
| 71 | /// Relocate the given address offset if a valid relocation exists. |
| 72 | virtual llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t StartOffset, |
| 73 | uint64_t EndOffset) = 0; |
| 74 | |
| 75 | /// Returns all valid functions address ranges(i.e., those ranges |
| 76 | /// which points to sections with code). |
| 77 | virtual RangesTy &getValidAddressRanges() = 0; |
| 78 | |
| 79 | /// Erases all data. |
| 80 | virtual void clear() = 0; |
| 81 | }; |
| 82 | |
| 83 | using Offset2UnitMap = DenseMap<uint64_t, CompileUnit *>; |
| 84 | |
| 85 | /// DwarfEmitter presents interface to generate all debug info tables. |
| 86 | class DwarfEmitter { |
| 87 | public: |
| 88 | virtual ~DwarfEmitter(); |
| 89 | |
| 90 | /// Emit DIE containing warnings. |
| 91 | virtual void emitPaperTrailWarningsDie(DIE &Die) = 0; |
| 92 | |
| 93 | /// Emit section named SecName with data SecData. |
| 94 | virtual void emitSectionContents(StringRef SecData, StringRef SecName) = 0; |
| 95 | |
| 96 | /// Emit the abbreviation table \p Abbrevs to the .debug_abbrev section. |
| 97 | virtual void |
| 98 | emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs, |
| 99 | unsigned DwarfVersion) = 0; |
| 100 | |
| 101 | /// Emit the string table described by \p Pool. |
| 102 | virtual void emitStrings(const NonRelocatableStringpool &Pool) = 0; |
| 103 | |
| 104 | /// Emit DWARF debug names. |
| 105 | virtual void |
| 106 | emitDebugNames(AccelTable<DWARF5AccelTableStaticData> &Table) = 0; |
| 107 | |
| 108 | /// Emit Apple namespaces accelerator table. |
| 109 | virtual void |
| 110 | emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> &Table) = 0; |
| 111 | |
| 112 | /// Emit Apple names accelerator table. |
| 113 | virtual void |
| 114 | emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &Table) = 0; |
| 115 | |
| 116 | /// Emit Apple Objective-C accelerator table. |
| 117 | virtual void |
| 118 | emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &Table) = 0; |
| 119 | |
| 120 | /// Emit Apple type accelerator table. |
| 121 | virtual void |
| 122 | emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &Table) = 0; |
| 123 | |
| 124 | /// Emit piece of .debug_ranges for \p Ranges. |
| 125 | virtual void |
| 126 | emitDwarfDebugRangesTableFragment(const CompileUnit &Unit, |
| 127 | const AddressRanges &LinkedRanges) = 0; |
| 128 | |
| 129 | /// Emit .debug_aranges entries for \p Unit and if \p DoRangesSection is true, |
| 130 | /// also emit the .debug_ranges entries for the DW_TAG_compile_unit's |
| 131 | /// DW_AT_ranges attribute. |
| 132 | virtual void emitUnitRangesEntries(CompileUnit &Unit, |
| 133 | bool DoRangesSection) = 0; |
| 134 | |
| 135 | /// Copy the .debug_line over to the updated binary while unobfuscating the |
| 136 | /// file names and directories. |
| 137 | virtual void translateLineTable(DataExtractor LineData, uint64_t Offset) = 0; |
| 138 | |
| 139 | /// Emit the line table described in \p Rows into the .debug_line section. |
| 140 | virtual void emitLineTableForUnit(MCDwarfLineTableParams Params, |
| 141 | StringRef PrologueBytes, |
| 142 | unsigned MinInstLength, |
| 143 | std::vector<DWARFDebugLine::Row> &Rows, |
| 144 | unsigned AdddressSize) = 0; |
| 145 | |
| 146 | /// Emit the .debug_pubnames contribution for \p Unit. |
| 147 | virtual void emitPubNamesForUnit(const CompileUnit &Unit) = 0; |
| 148 | |
| 149 | /// Emit the .debug_pubtypes contribution for \p Unit. |
| 150 | virtual void emitPubTypesForUnit(const CompileUnit &Unit) = 0; |
| 151 | |
| 152 | /// Emit a CIE. |
| 153 | virtual void emitCIE(StringRef CIEBytes) = 0; |
| 154 | |
| 155 | /// Emit an FDE with data \p Bytes. |
| 156 | virtual void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint64_t Address, |
| 157 | StringRef Bytes) = 0; |
| 158 | |
| 159 | /// Emit the .debug_loc contribution for \p Unit by copying the entries from |
| 160 | /// \p Dwarf and offsetting them. Update the location attributes to point to |
| 161 | /// the new entries. |
| 162 | virtual void emitLocationsForUnit( |
| 163 | const CompileUnit &Unit, DWARFContext &Dwarf, |
| 164 | std::function<void(StringRef, SmallVectorImpl<uint8_t> &)> |
| 165 | ProcessExpr) = 0; |
| 166 | |
| 167 | /// Emit the compilation unit header for \p Unit in the |
| 168 | /// .debug_info section. |
| 169 | /// |
| 170 | /// As a side effect, this also switches the current Dwarf version |
| 171 | /// of the MC layer to the one of U.getOrigUnit(). |
| 172 | virtual void emitCompileUnitHeader(CompileUnit &Unit, |
| 173 | unsigned DwarfVersion) = 0; |
| 174 | |
| 175 | /// Recursively emit the DIE tree rooted at \p Die. |
| 176 | virtual void emitDIE(DIE &Die) = 0; |
| 177 | |
| 178 | /// Emit all available macro tables(DWARFv4 and DWARFv5). |
| 179 | /// Use \p UnitMacroMap to get compilation unit by macro table offset. |
| 180 | /// Side effects: Fill \p StringPool with macro strings, update |
| 181 | /// DW_AT_macro_info, DW_AT_macros attributes for corresponding compile |
| 182 | /// units. |
| 183 | virtual void emitMacroTables(DWARFContext *Context, |
| 184 | const Offset2UnitMap &UnitMacroMap, |
| 185 | OffsetsStringPool &StringPool) = 0; |
| 186 | |
| 187 | /// Returns size of generated .debug_line section. |
| 188 | virtual uint64_t getLineSectionSize() const = 0; |
| 189 | |
| 190 | /// Returns size of generated .debug_frame section. |
| 191 | virtual uint64_t getFrameSectionSize() const = 0; |
| 192 | |
| 193 | /// Returns size of generated .debug_ranges section. |
| 194 | virtual uint64_t getRangesSectionSize() const = 0; |
| 195 | |
| 196 | /// Returns size of generated .debug_info section. |
| 197 | virtual uint64_t getDebugInfoSectionSize() const = 0; |
| 198 | |
| 199 | /// Returns size of generated .debug_macinfo section. |
| 200 | virtual uint64_t getDebugMacInfoSectionSize() const = 0; |
| 201 | |
| 202 | /// Returns size of generated .debug_macro section. |
| 203 | virtual uint64_t getDebugMacroSectionSize() const = 0; |
| 204 | }; |
| 205 | |
| 206 | using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>; |
| 207 | |
| 208 | /// this class represents DWARF information for source file |
| 209 | /// and it`s address map. |
| 210 | class DWARFFile { |
| 211 | public: |
| 212 | DWARFFile(StringRef Name, DWARFContext *Dwarf, AddressesMap *Addresses, |
| 213 | const std::vector<std::string> &Warnings) |
| 214 | : FileName(Name), Dwarf(Dwarf), Addresses(Addresses), Warnings(Warnings) { |
| 215 | } |
| 216 | |
| 217 | /// object file name. |
| 218 | StringRef FileName; |
| 219 | /// source DWARF information. |
| 220 | DWARFContext *Dwarf = nullptr; |
| 221 | /// helpful address information(list of valid address ranges, relocations). |
| 222 | AddressesMap *Addresses = nullptr; |
| 223 | /// warnings for object file. |
| 224 | const std::vector<std::string> &Warnings; |
| 225 | }; |
| 226 | |
| 227 | typedef std::function<void(const Twine &Warning, StringRef Context, |
| 228 | const DWARFDie *DIE)> |
| 229 | messageHandler; |
| 230 | typedef std::function<ErrorOr<DWARFFile &>(StringRef ContainerName, |
| 231 | StringRef Path)> |
| 232 | objFileLoader; |
| 233 | typedef std::map<std::string, std::string> swiftInterfacesMap; |
| 234 | typedef std::map<std::string, std::string> objectPrefixMap; |
| 235 | |
| 236 | typedef function_ref<void(const DWARFUnit &Unit)> CompileUnitHandler; |
| 237 | |
| 238 | /// The core of the Dwarf linking logic. |
| 239 | /// |
| 240 | /// The generation of the dwarf information from the object files will be |
| 241 | /// driven by the selection of 'root DIEs', which are DIEs that |
| 242 | /// describe variables or functions that resolves to the corresponding |
| 243 | /// code section(and thus have entries in the Addresses map). All the debug |
| 244 | /// information that will be generated(the DIEs, but also the line |
| 245 | /// tables, ranges, ...) is derived from that set of root DIEs. |
| 246 | /// |
| 247 | /// The root DIEs are identified because they contain relocations that |
| 248 | /// points to code section(the low_pc for a function, the location for |
| 249 | /// a variable). These relocations are called ValidRelocs in the |
| 250 | /// AddressesInfo and are gathered as a very first step when we start |
| 251 | /// processing a object file. |
| 252 | class DWARFLinker { |
| 253 | public: |
| 254 | DWARFLinker(DwarfEmitter *Emitter, |
| 255 | DwarfLinkerClient ClientID = DwarfLinkerClient::General) |
| 256 | : TheDwarfEmitter(Emitter), DwarfLinkerClientID(ClientID) {} |
| 257 | |
| 258 | /// Add object file to be linked. Pre-load compile unit die. Call |
| 259 | /// \p OnCUDieLoaded for each compile unit die. If specified \p File |
| 260 | /// has reference to the Clang module then such module would be |
| 261 | /// pre-loaded by \p Loader for !Update case. |
| 262 | /// |
| 263 | /// \pre NoODR, Update options should be set before call to addObjectFile. |
| 264 | void addObjectFile( |
| 265 | DWARFFile &File, objFileLoader Loader = nullptr, |
| 266 | CompileUnitHandler OnCUDieLoaded = [](const DWARFUnit &) {}); |
| 267 | |
| 268 | /// Link debug info for added objFiles. Object |
| 269 | /// files are linked all together. |
| 270 | Error link(); |
| 271 | |
| 272 | /// A number of methods setting various linking options: |
| 273 | |
| 274 | /// Allows to generate log of linking process to the standard output. |
| 275 | void setVerbosity(bool Verbose) { Options.Verbose = Verbose; } |
| 276 | |
| 277 | /// Print statistics to standard output. |
| 278 | void setStatistics(bool Statistics) { Options.Statistics = Statistics; } |
| 279 | |
| 280 | /// Verify the input DWARF. |
| 281 | void setVerifyInputDWARF(bool Verify) { Options.VerifyInputDWARF = Verify; } |
| 282 | |
| 283 | /// Do not emit linked dwarf info. |
| 284 | void setNoOutput(bool NoOut) { Options.NoOutput = NoOut; } |
| 285 | |
| 286 | /// Do not unique types according to ODR. |
| 287 | void setNoODR(bool NoODR) { Options.NoODR = NoODR; } |
| 288 | |
| 289 | /// update existing DWARF info(for the linked binary). |
| 290 | void setUpdate(bool Update) { Options.Update = Update; } |
| 291 | |
| 292 | /// Set whether to keep the enclosing function for a static variable. |
| 293 | void setKeepFunctionForStatic(bool KeepFunctionForStatic) { |
| 294 | Options.KeepFunctionForStatic = KeepFunctionForStatic; |
| 295 | } |
| 296 | |
| 297 | /// Use specified number of threads for parallel files linking. |
| 298 | void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; } |
| 299 | |
| 300 | /// Add kind of accelerator tables to be generated. |
| 301 | void addAccelTableKind(DwarfLinkerAccelTableKind Kind) { |
| 302 | assert(std::find(Options.AccelTables.begin(), Options.AccelTables.end(), |
| 303 | Kind) == Options.AccelTables.end()); |
| 304 | Options.AccelTables.emplace_back(Kind); |
| 305 | } |
| 306 | |
| 307 | /// Set prepend path for clang modules. |
| 308 | void setPrependPath(const std::string &Ppath) { Options.PrependPath = Ppath; } |
| 309 | |
| 310 | /// Set translator which would be used for strings. |
| 311 | void |
| 312 | setStringsTranslator(std::function<StringRef(StringRef)> StringsTranslator) { |
| 313 | this->StringsTranslator = StringsTranslator; |
| 314 | } |
| 315 | |
| 316 | /// Set estimated objects files amount, for preliminary data allocation. |
| 317 | void setEstimatedObjfilesAmount(unsigned ObjFilesNum) { |
| 318 | ObjectContexts.reserve(ObjFilesNum); |
| 319 | } |
| 320 | |
| 321 | /// Set warning handler which would be used to report warnings. |
| 322 | void setWarningHandler(messageHandler Handler) { |
| 323 | Options.WarningHandler = Handler; |
| 324 | } |
| 325 | |
| 326 | /// Set error handler which would be used to report errors. |
| 327 | void setErrorHandler(messageHandler Handler) { |
| 328 | Options.ErrorHandler = Handler; |
| 329 | } |
| 330 | |
| 331 | /// Set map for Swift interfaces. |
| 332 | void setSwiftInterfacesMap(swiftInterfacesMap *Map) { |
| 333 | Options.ParseableSwiftInterfaces = Map; |
| 334 | } |
| 335 | |
| 336 | /// Set prefix map for objects. |
| 337 | void setObjectPrefixMap(objectPrefixMap *Map) { |
| 338 | Options.ObjectPrefixMap = Map; |
| 339 | } |
| 340 | |
| 341 | /// Set target DWARF version. |
| 342 | Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) { |
| 343 | if (TargetDWARFVersion < 1 || TargetDWARFVersion > 5) |
| 344 | return createStringError(std::errc::invalid_argument, |
| 345 | "unsupported DWARF version: %d", |
| 346 | TargetDWARFVersion); |
| 347 | |
| 348 | Options.TargetDWARFVersion = TargetDWARFVersion; |
| 349 | return Error::success(); |
| 350 | } |
| 351 | |
| 352 | private: |
| 353 | /// Flags passed to DwarfLinker::lookForDIEsToKeep |
| 354 | enum TraversalFlags { |
| 355 | TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept. |
| 356 | TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope. |
| 357 | TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE. |
| 358 | TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE. |
| 359 | TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents. |
| 360 | TF_SkipPC = 1 << 5, ///< Skip all location attributes. |
| 361 | }; |
| 362 | |
| 363 | /// The distinct types of work performed by the work loop. |
| 364 | enum class WorklistItemType { |
| 365 | /// Given a DIE, look for DIEs to be kept. |
| 366 | LookForDIEsToKeep, |
| 367 | /// Given a DIE, look for children of this DIE to be kept. |
| 368 | LookForChildDIEsToKeep, |
| 369 | /// Given a DIE, look for DIEs referencing this DIE to be kept. |
| 370 | LookForRefDIEsToKeep, |
| 371 | /// Given a DIE, look for parent DIEs to be kept. |
| 372 | LookForParentDIEsToKeep, |
| 373 | /// Given a DIE, update its incompleteness based on whether its children are |
| 374 | /// incomplete. |
| 375 | UpdateChildIncompleteness, |
| 376 | /// Given a DIE, update its incompleteness based on whether the DIEs it |
| 377 | /// references are incomplete. |
| 378 | UpdateRefIncompleteness, |
| 379 | /// Given a DIE, mark it as ODR Canonical if applicable. |
| 380 | MarkODRCanonicalDie, |
| 381 | }; |
| 382 | |
| 383 | /// This class represents an item in the work list. The type defines what kind |
| 384 | /// of work needs to be performed when processing the current item. The flags |
| 385 | /// and info fields are optional based on the type. |
| 386 | struct WorklistItem { |
| 387 | DWARFDie Die; |
| 388 | WorklistItemType Type; |
| 389 | CompileUnit &CU; |
| 390 | unsigned Flags; |
| 391 | union { |
| 392 | const unsigned AncestorIdx; |
| 393 | CompileUnit::DIEInfo *OtherInfo; |
| 394 | }; |
| 395 | |
| 396 | WorklistItem(DWARFDie Die, CompileUnit &CU, unsigned Flags, |
| 397 | WorklistItemType T = WorklistItemType::LookForDIEsToKeep) |
| 398 | : Die(Die), Type(T), CU(CU), Flags(Flags), AncestorIdx(0) {} |
| 399 | |
| 400 | WorklistItem(DWARFDie Die, CompileUnit &CU, WorklistItemType T, |
| 401 | CompileUnit::DIEInfo *OtherInfo = nullptr) |
| 402 | : Die(Die), Type(T), CU(CU), Flags(0), OtherInfo(OtherInfo) {} |
| 403 | |
| 404 | WorklistItem(unsigned AncestorIdx, CompileUnit &CU, unsigned Flags) |
| 405 | : Type(WorklistItemType::LookForParentDIEsToKeep), CU(CU), Flags(Flags), |
| 406 | AncestorIdx(AncestorIdx) {} |
| 407 | }; |
| 408 | |
| 409 | /// Verify the given DWARF file. |
| 410 | bool verify(const DWARFFile &File); |
| 411 | |
| 412 | /// returns true if we need to translate strings. |
| 413 | bool needToTranslateStrings() { return StringsTranslator != nullptr; } |
| 414 | |
| 415 | void reportWarning(const Twine &Warning, const DWARFFile &File, |
| 416 | const DWARFDie *DIE = nullptr) const { |
| 417 | if (Options.WarningHandler != nullptr) |
| 418 | Options.WarningHandler(Warning, File.FileName, DIE); |
| 419 | } |
| 420 | |
| 421 | void reportError(const Twine &Warning, const DWARFFile &File, |
| 422 | const DWARFDie *DIE = nullptr) const { |
| 423 | if (Options.ErrorHandler != nullptr) |
| 424 | Options.ErrorHandler(Warning, File.FileName, DIE); |
| 425 | } |
| 426 | |
| 427 | /// Emit warnings as Dwarf compile units to leave a trail after linking. |
| 428 | bool emitPaperTrailWarnings(const DWARFFile &File, |
| 429 | OffsetsStringPool &StringPool); |
| 430 | |
| 431 | void copyInvariantDebugSection(DWARFContext &Dwarf); |
| 432 | |
| 433 | /// Keep information for referenced clang module: already loaded DWARF info |
| 434 | /// of the clang module and a CompileUnit of the module. |
| 435 | struct RefModuleUnit { |
| 436 | RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit) |
| 437 | : File(File), Unit(std::move(Unit)) {} |
| 438 | RefModuleUnit(RefModuleUnit &&Other) |
| 439 | : File(Other.File), Unit(std::move(Other.Unit)) {} |
| 440 | RefModuleUnit(const RefModuleUnit &) = delete; |
| 441 | |
| 442 | DWARFFile &File; |
| 443 | std::unique_ptr<CompileUnit> Unit; |
| 444 | }; |
| 445 | using ModuleUnitListTy = std::vector<RefModuleUnit>; |
| 446 | |
| 447 | /// Keeps track of data associated with one object during linking. |
| 448 | struct LinkContext { |
| 449 | DWARFFile &File; |
| 450 | UnitListTy CompileUnits; |
| 451 | ModuleUnitListTy ModuleUnits; |
| 452 | bool Skip = false; |
| 453 | |
| 454 | LinkContext(DWARFFile &File) : File(File) {} |
| 455 | |
| 456 | /// Clear part of the context that's no longer needed when we're done with |
| 457 | /// the debug object. |
| 458 | void clear() { |
| 459 | CompileUnits.clear(); |
| 460 | File.Addresses->clear(); |
| 461 | } |
| 462 | }; |
| 463 | |
| 464 | /// Called before emitting object data |
| 465 | void cleanupAuxiliarryData(LinkContext &Context); |
| 466 | |
| 467 | /// Look at the parent of the given DIE and decide whether they should be |
| 468 | /// kept. |
| 469 | void lookForParentDIEsToKeep(unsigned AncestorIdx, CompileUnit &CU, |
| 470 | unsigned Flags, |
| 471 | SmallVectorImpl<WorklistItem> &Worklist); |
| 472 | |
| 473 | /// Look at the children of the given DIE and decide whether they should be |
| 474 | /// kept. |
| 475 | void lookForChildDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, |
| 476 | unsigned Flags, |
| 477 | SmallVectorImpl<WorklistItem> &Worklist); |
| 478 | |
| 479 | /// Look at DIEs referenced by the given DIE and decide whether they should be |
| 480 | /// kept. All DIEs referenced though attributes should be kept. |
| 481 | void lookForRefDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, |
| 482 | unsigned Flags, const UnitListTy &Units, |
| 483 | const DWARFFile &File, |
| 484 | SmallVectorImpl<WorklistItem> &Worklist); |
| 485 | |
| 486 | /// Mark context corresponding to the specified \p Die as having canonical |
| 487 | /// die, if applicable. |
| 488 | void markODRCanonicalDie(const DWARFDie &Die, CompileUnit &CU); |
| 489 | |
| 490 | /// \defgroup FindRootDIEs Find DIEs corresponding to Address map entries. |
| 491 | /// |
| 492 | /// @{ |
| 493 | /// Recursively walk the \p DIE tree and look for DIEs to |
| 494 | /// keep. Store that information in \p CU's DIEInfo. |
| 495 | /// |
| 496 | /// The return value indicates whether the DIE is incomplete. |
| 497 | void lookForDIEsToKeep(AddressesMap &RelocMgr, RangesTy &Ranges, |
| 498 | const UnitListTy &Units, const DWARFDie &DIE, |
| 499 | const DWARFFile &File, CompileUnit &CU, |
| 500 | unsigned Flags); |
| 501 | |
| 502 | /// Check whether specified \p CUDie is a Clang module reference. |
| 503 | /// if \p Quiet is false then display error messages. |
| 504 | /// \return first == true if CUDie is a Clang module reference. |
| 505 | /// second == true if module is already loaded. |
| 506 | std::pair<bool, bool> isClangModuleRef(const DWARFDie &CUDie, |
| 507 | std::string &PCMFile, |
| 508 | LinkContext &Context, unsigned Indent, |
| 509 | bool Quiet); |
| 510 | |
| 511 | /// If this compile unit is really a skeleton CU that points to a |
| 512 | /// clang module, register it in ClangModules and return true. |
| 513 | /// |
| 514 | /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name |
| 515 | /// pointing to the module, and a DW_AT_gnu_dwo_id with the module |
| 516 | /// hash. |
| 517 | bool registerModuleReference(const DWARFDie &CUDie, LinkContext &Context, |
| 518 | objFileLoader Loader, |
| 519 | CompileUnitHandler OnCUDieLoaded, |
| 520 | unsigned Indent = 0); |
| 521 | |
| 522 | /// Recursively add the debug info in this clang module .pcm |
| 523 | /// file (and all the modules imported by it in a bottom-up fashion) |
| 524 | /// to ModuleUnits. |
| 525 | Error loadClangModule(objFileLoader Loader, const DWARFDie &CUDie, |
| 526 | const std::string &PCMFile, LinkContext &Context, |
| 527 | CompileUnitHandler OnCUDieLoaded, unsigned Indent = 0); |
| 528 | |
| 529 | /// Clone specified Clang module unit \p Unit. |
| 530 | Error cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit, |
| 531 | DeclContextTree &ODRContexts, |
| 532 | OffsetsStringPool &OffsetsStringPool, |
| 533 | unsigned Indent = 0); |
| 534 | |
| 535 | /// Mark the passed DIE as well as all the ones it depends on as kept. |
| 536 | void keepDIEAndDependencies(AddressesMap &RelocMgr, RangesTy &Ranges, |
| 537 | const UnitListTy &Units, const DWARFDie &DIE, |
| 538 | CompileUnit::DIEInfo &MyInfo, |
| 539 | const DWARFFile &File, CompileUnit &CU, |
| 540 | bool UseODR); |
| 541 | |
| 542 | unsigned shouldKeepDIE(AddressesMap &RelocMgr, RangesTy &Ranges, |
| 543 | const DWARFDie &DIE, const DWARFFile &File, |
| 544 | CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, |
| 545 | unsigned Flags); |
| 546 | |
| 547 | /// Check if a variable describing DIE should be kept. |
| 548 | /// \returns updated TraversalFlags. |
| 549 | unsigned shouldKeepVariableDIE(AddressesMap &RelocMgr, const DWARFDie &DIE, |
| 550 | CompileUnit::DIEInfo &MyInfo, unsigned Flags); |
| 551 | |
| 552 | unsigned shouldKeepSubprogramDIE(AddressesMap &RelocMgr, RangesTy &Ranges, |
| 553 | const DWARFDie &DIE, const DWARFFile &File, |
| 554 | CompileUnit &Unit, |
| 555 | CompileUnit::DIEInfo &MyInfo, |
| 556 | unsigned Flags); |
| 557 | |
| 558 | /// Resolve the DIE attribute reference that has been extracted in \p |
| 559 | /// RefValue. The resulting DIE might be in another CompileUnit which is |
| 560 | /// stored into \p ReferencedCU. \returns null if resolving fails for any |
| 561 | /// reason. |
| 562 | DWARFDie resolveDIEReference(const DWARFFile &File, const UnitListTy &Units, |
| 563 | const DWARFFormValue &RefValue, |
| 564 | const DWARFDie &DIE, CompileUnit *&RefCU); |
| 565 | |
| 566 | /// @} |
| 567 | |
| 568 | /// \defgroup Methods used to link the debug information |
| 569 | /// |
| 570 | /// @{ |
| 571 | |
| 572 | struct DWARFLinkerOptions; |
| 573 | |
| 574 | class DIECloner { |
| 575 | DWARFLinker &Linker; |
| 576 | DwarfEmitter *Emitter; |
| 577 | DWARFFile &ObjFile; |
| 578 | |
| 579 | /// Allocator used for all the DIEValue objects. |
| 580 | BumpPtrAllocator &DIEAlloc; |
| 581 | |
| 582 | std::vector<std::unique_ptr<CompileUnit>> &CompileUnits; |
| 583 | |
| 584 | /// Keeps mapping from offset of the macro table to corresponding |
| 585 | /// compile unit. |
| 586 | Offset2UnitMap UnitMacroMap; |
| 587 | |
| 588 | bool Update; |
| 589 | |
| 590 | public: |
| 591 | DIECloner(DWARFLinker &Linker, DwarfEmitter *Emitter, DWARFFile &ObjFile, |
| 592 | BumpPtrAllocator &DIEAlloc, |
| 593 | std::vector<std::unique_ptr<CompileUnit>> &CompileUnits, |
| 594 | bool Update) |
| 595 | : Linker(Linker), Emitter(Emitter), ObjFile(ObjFile), |
| 596 | DIEAlloc(DIEAlloc), CompileUnits(CompileUnits), Update(Update) {} |
| 597 | |
| 598 | /// Recursively clone \p InputDIE into an tree of DIE objects |
| 599 | /// where useless (as decided by lookForDIEsToKeep()) bits have been |
| 600 | /// stripped out and addresses have been rewritten according to the |
| 601 | /// address map. |
| 602 | /// |
| 603 | /// \param OutOffset is the offset the cloned DIE in the output |
| 604 | /// compile unit. |
| 605 | /// \param PCOffset (while cloning a function scope) is the offset |
| 606 | /// applied to the entry point of the function to get the linked address. |
| 607 | /// \param Die the output DIE to use, pass NULL to create one. |
| 608 | /// \returns the root of the cloned tree or null if nothing was selected. |
| 609 | DIE *cloneDIE(const DWARFDie &InputDIE, const DWARFFile &File, |
| 610 | CompileUnit &U, OffsetsStringPool &StringPool, |
| 611 | int64_t PCOffset, uint32_t OutOffset, unsigned Flags, |
| 612 | bool IsLittleEndian, DIE *Die = nullptr); |
| 613 | |
| 614 | /// Construct the output DIE tree by cloning the DIEs we |
| 615 | /// chose to keep above. If there are no valid relocs, then there's |
| 616 | /// nothing to clone/emit. |
| 617 | uint64_t cloneAllCompileUnits(DWARFContext &DwarfContext, |
| 618 | const DWARFFile &File, |
| 619 | OffsetsStringPool &StringPool, |
| 620 | bool IsLittleEndian); |
| 621 | |
| 622 | private: |
| 623 | using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec; |
| 624 | |
| 625 | /// Information gathered and exchanged between the various |
| 626 | /// clone*Attributes helpers about the attributes of a particular DIE. |
| 627 | struct AttributesInfo { |
| 628 | /// Names. |
| 629 | DwarfStringPoolEntryRef Name, MangledName, NameWithoutTemplate; |
| 630 | |
| 631 | /// Offsets in the string pool. |
| 632 | uint32_t NameOffset = 0; |
| 633 | uint32_t MangledNameOffset = 0; |
| 634 | |
| 635 | /// Value of AT_low_pc in the input DIE |
| 636 | uint64_t OrigLowPc = std::numeric_limits<uint64_t>::max(); |
| 637 | |
| 638 | /// Value of AT_high_pc in the input DIE |
| 639 | uint64_t OrigHighPc = 0; |
| 640 | |
| 641 | /// Value of DW_AT_call_return_pc in the input DIE |
| 642 | uint64_t OrigCallReturnPc = 0; |
| 643 | |
| 644 | /// Value of DW_AT_call_pc in the input DIE |
| 645 | uint64_t OrigCallPc = 0; |
| 646 | |
| 647 | /// Offset to apply to PC addresses inside a function. |
| 648 | int64_t PCOffset = 0; |
| 649 | |
| 650 | /// Does the DIE have a low_pc attribute? |
| 651 | bool HasLowPc = false; |
| 652 | |
| 653 | /// Does the DIE have a ranges attribute? |
| 654 | bool HasRanges = false; |
| 655 | |
| 656 | /// Is this DIE only a declaration? |
| 657 | bool IsDeclaration = false; |
| 658 | |
| 659 | AttributesInfo() = default; |
| 660 | }; |
| 661 | |
| 662 | /// Helper for cloneDIE. |
| 663 | unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE, |
| 664 | const DWARFFile &File, CompileUnit &U, |
| 665 | OffsetsStringPool &StringPool, |
| 666 | const DWARFFormValue &Val, |
| 667 | const AttributeSpec AttrSpec, unsigned AttrSize, |
| 668 | AttributesInfo &AttrInfo, bool IsLittleEndian); |
| 669 | |
| 670 | /// Clone a string attribute described by \p AttrSpec and add |
| 671 | /// it to \p Die. |
| 672 | /// \returns the size of the new attribute. |
| 673 | unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, |
| 674 | const DWARFFormValue &Val, const DWARFUnit &U, |
| 675 | OffsetsStringPool &StringPool, |
| 676 | AttributesInfo &Info); |
| 677 | |
| 678 | /// Clone an attribute referencing another DIE and add |
| 679 | /// it to \p Die. |
| 680 | /// \returns the size of the new attribute. |
| 681 | unsigned cloneDieReferenceAttribute(DIE &Die, const DWARFDie &InputDIE, |
| 682 | AttributeSpec AttrSpec, |
| 683 | unsigned AttrSize, |
| 684 | const DWARFFormValue &Val, |
| 685 | const DWARFFile &File, |
| 686 | CompileUnit &Unit); |
| 687 | |
| 688 | /// Clone a DWARF expression that may be referencing another DIE. |
| 689 | void cloneExpression(DataExtractor &Data, DWARFExpression Expression, |
| 690 | const DWARFFile &File, CompileUnit &Unit, |
| 691 | SmallVectorImpl<uint8_t> &OutputBuffer); |
| 692 | |
| 693 | /// Clone an attribute referencing another DIE and add |
| 694 | /// it to \p Die. |
| 695 | /// \returns the size of the new attribute. |
| 696 | unsigned cloneBlockAttribute(DIE &Die, const DWARFFile &File, |
| 697 | CompileUnit &Unit, AttributeSpec AttrSpec, |
| 698 | const DWARFFormValue &Val, unsigned AttrSize, |
| 699 | bool IsLittleEndian); |
| 700 | |
| 701 | /// Clone an attribute referencing another DIE and add |
| 702 | /// it to \p Die. |
| 703 | /// \returns the size of the new attribute. |
| 704 | unsigned cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec, |
| 705 | unsigned AttrSize, const DWARFFormValue &Val, |
| 706 | const CompileUnit &Unit, |
| 707 | AttributesInfo &Info); |
| 708 | |
| 709 | /// Clone a scalar attribute and add it to \p Die. |
| 710 | /// \returns the size of the new attribute. |
| 711 | unsigned cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE, |
| 712 | const DWARFFile &File, CompileUnit &U, |
| 713 | AttributeSpec AttrSpec, |
| 714 | const DWARFFormValue &Val, unsigned AttrSize, |
| 715 | AttributesInfo &Info); |
| 716 | |
| 717 | /// Get the potential name and mangled name for the entity |
| 718 | /// described by \p Die and store them in \Info if they are not |
| 719 | /// already there. |
| 720 | /// \returns is a name was found. |
| 721 | bool getDIENames(const DWARFDie &Die, AttributesInfo &Info, |
| 722 | OffsetsStringPool &StringPool, bool StripTemplate = false); |
| 723 | |
| 724 | uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U, |
| 725 | const DWARFFile &File, |
| 726 | int RecurseDepth = 0); |
| 727 | |
| 728 | /// Helper for cloneDIE. |
| 729 | void addObjCAccelerator(CompileUnit &Unit, const DIE *Die, |
| 730 | DwarfStringPoolEntryRef Name, |
| 731 | OffsetsStringPool &StringPool, bool SkipPubSection); |
| 732 | |
| 733 | void rememberUnitForMacroOffset(CompileUnit &Unit); |
| 734 | }; |
| 735 | |
| 736 | /// Assign an abbreviation number to \p Abbrev |
| 737 | void assignAbbrev(DIEAbbrev &Abbrev); |
| 738 | |
| 739 | /// Compute and emit .debug_ranges section for \p Unit, and |
| 740 | /// patch the attributes referencing it. |
| 741 | void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf, |
| 742 | const DWARFFile &File) const; |
| 743 | |
| 744 | /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had |
| 745 | /// one. |
| 746 | void generateUnitRanges(CompileUnit &Unit) const; |
| 747 | |
| 748 | /// Extract the line tables from the original dwarf, extract the relevant |
| 749 | /// parts according to the linked function ranges and emit the result in the |
| 750 | /// .debug_line section. |
| 751 | void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf, |
| 752 | const DWARFFile &File); |
| 753 | |
| 754 | /// Emit the accelerator entries for \p Unit. |
| 755 | void emitAcceleratorEntriesForUnit(CompileUnit &Unit); |
| 756 | |
| 757 | /// Patch the frame info for an object file and emit it. |
| 758 | void patchFrameInfoForObject(const DWARFFile &, RangesTy &Ranges, |
| 759 | DWARFContext &, unsigned AddressSize); |
| 760 | |
| 761 | /// FoldingSet that uniques the abbreviations. |
| 762 | FoldingSet<DIEAbbrev> AbbreviationsSet; |
| 763 | |
| 764 | /// Storage for the unique Abbreviations. |
| 765 | /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be |
| 766 | /// changed to a vector of unique_ptrs. |
| 767 | std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations; |
| 768 | |
| 769 | /// DIELoc objects that need to be destructed (but not freed!). |
| 770 | std::vector<DIELoc *> DIELocs; |
| 771 | |
| 772 | /// DIEBlock objects that need to be destructed (but not freed!). |
| 773 | std::vector<DIEBlock *> DIEBlocks; |
| 774 | |
| 775 | /// Allocator used for all the DIEValue objects. |
| 776 | BumpPtrAllocator DIEAlloc; |
| 777 | /// @} |
| 778 | |
| 779 | DwarfEmitter *TheDwarfEmitter; |
| 780 | std::vector<LinkContext> ObjectContexts; |
| 781 | |
| 782 | /// The CIEs that have been emitted in the output section. The actual CIE |
| 783 | /// data serves a the key to this StringMap, this takes care of comparing the |
| 784 | /// semantics of CIEs defined in different object files. |
| 785 | StringMap<uint32_t> EmittedCIEs; |
| 786 | |
| 787 | /// Offset of the last CIE that has been emitted in the output |
| 788 | /// .debug_frame section. |
| 789 | uint32_t LastCIEOffset = 0; |
| 790 | |
| 791 | /// Apple accelerator tables. |
| 792 | AccelTable<DWARF5AccelTableStaticData> DebugNames; |
| 793 | AccelTable<AppleAccelTableStaticOffsetData> AppleNames; |
| 794 | AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces; |
| 795 | AccelTable<AppleAccelTableStaticOffsetData> AppleObjc; |
| 796 | AccelTable<AppleAccelTableStaticTypeData> AppleTypes; |
| 797 | |
| 798 | /// Mapping the PCM filename to the DwoId. |
| 799 | StringMap<uint64_t> ClangModules; |
| 800 | |
| 801 | DwarfLinkerClient DwarfLinkerClientID; |
| 802 | |
| 803 | std::function<StringRef(StringRef)> StringsTranslator = nullptr; |
| 804 | |
| 805 | /// A unique ID that identifies each compile unit. |
| 806 | unsigned UniqueUnitID = 0; |
| 807 | |
| 808 | /// linking options |
| 809 | struct DWARFLinkerOptions { |
| 810 | /// DWARF version for the output. |
| 811 | uint16_t TargetDWARFVersion = 0; |
| 812 | |
| 813 | /// Generate processing log to the standard output. |
| 814 | bool Verbose = false; |
| 815 | |
| 816 | /// Print statistics. |
| 817 | bool Statistics = false; |
| 818 | |
| 819 | /// Verify the input DWARF. |
| 820 | bool VerifyInputDWARF = false; |
| 821 | |
| 822 | /// Skip emitting output |
| 823 | bool NoOutput = false; |
| 824 | |
| 825 | /// Do not unique types according to ODR |
| 826 | bool NoODR = false; |
| 827 | |
| 828 | /// Update |
| 829 | bool Update = false; |
| 830 | |
| 831 | /// Whether we want a static variable to force us to keep its enclosing |
| 832 | /// function. |
| 833 | bool KeepFunctionForStatic = false; |
| 834 | |
| 835 | /// Number of threads. |
| 836 | unsigned Threads = 1; |
| 837 | |
| 838 | /// The accelerator table kinds |
| 839 | SmallVector<DwarfLinkerAccelTableKind, 1> AccelTables; |
| 840 | |
| 841 | /// Prepend path for the clang modules. |
| 842 | std::string PrependPath; |
| 843 | |
| 844 | // warning handler |
| 845 | messageHandler WarningHandler = nullptr; |
| 846 | |
| 847 | // error handler |
| 848 | messageHandler ErrorHandler = nullptr; |
| 849 | |
| 850 | /// A list of all .swiftinterface files referenced by the debug |
| 851 | /// info, mapping Module name to path on disk. The entries need to |
| 852 | /// be uniqued and sorted and there are only few entries expected |
| 853 | /// per compile unit, which is why this is a std::map. |
| 854 | /// this is dsymutil specific fag. |
| 855 | swiftInterfacesMap *ParseableSwiftInterfaces = nullptr; |
| 856 | |
| 857 | /// A list of remappings to apply to file paths. |
| 858 | objectPrefixMap *ObjectPrefixMap = nullptr; |
| 859 | } Options; |
| 860 | }; |
| 861 | |
| 862 | } // end namespace llvm |
| 863 | |
| 864 | #endif // LLVM_DWARFLINKER_DWARFLINKER_H |