1 //===- DWARFContext.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_DEBUGINFO_DWARF_DWARFCONTEXT_H 10 #define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H 11 12 #include "llvm/ADT/SmallVector.h" 13 #include "llvm/ADT/StringExtras.h" 14 #include "llvm/ADT/StringMap.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/DebugInfo/DIContext.h" 17 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" 18 #include "llvm/DebugInfo/DWARF/DWARFDie.h" 19 #include "llvm/DebugInfo/DWARF/DWARFObject.h" 20 #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 21 #include "llvm/Object/Binary.h" 22 #include "llvm/Object/ObjectFile.h" 23 #include "llvm/Support/DataExtractor.h" 24 #include "llvm/Support/Error.h" 25 #include "llvm/TargetParser/Host.h" 26 #include <cstdint> 27 #include <memory> 28 #include <mutex> 29 30 namespace llvm { 31 32 class MemoryBuffer; 33 class AppleAcceleratorTable; 34 class DWARFCompileUnit; 35 class DWARFDebugAbbrev; 36 class DWARFDebugAranges; 37 class DWARFDebugFrame; 38 class DWARFDebugLoc; 39 class DWARFDebugMacro; 40 class DWARFDebugNames; 41 class DWARFGdbIndex; 42 class DWARFTypeUnit; 43 class DWARFUnitIndex; 44 45 /// DWARFContext 46 /// This data structure is the top level entity that deals with dwarf debug 47 /// information parsing. The actual data is supplied through DWARFObj. 48 class DWARFContext : public DIContext { 49 public: 50 /// DWARFContextState 51 /// This structure contains all member variables for DWARFContext that need 52 /// to be protected in multi-threaded environments. Threading support can be 53 /// enabled by setting the ThreadSafe to true when constructing a 54 /// DWARFContext to allow DWARRContext to be able to be used in a 55 /// multi-threaded environment, or not enabled to allow for maximum 56 /// performance in single threaded environments. 57 class DWARFContextState { 58 protected: 59 /// Helper enum to distinguish between macro[.dwo] and macinfo[.dwo] 60 /// section. 61 enum MacroSecType { 62 MacinfoSection, 63 MacinfoDwoSection, 64 MacroSection, 65 MacroDwoSection 66 }; 67 68 DWARFContext &D; 69 public: DWARFContextState(DWARFContext & DC)70 DWARFContextState(DWARFContext &DC) : D(DC) {} 71 virtual ~DWARFContextState() = default; 72 virtual DWARFUnitVector &getNormalUnits() = 0; 73 virtual DWARFUnitVector &getDWOUnits(bool Lazy = false) = 0; 74 virtual const DWARFDebugAbbrev *getDebugAbbrevDWO() = 0; 75 virtual const DWARFUnitIndex &getCUIndex() = 0; 76 virtual const DWARFUnitIndex &getTUIndex() = 0; 77 virtual DWARFGdbIndex &getGdbIndex() = 0; 78 virtual const DWARFDebugAbbrev *getDebugAbbrev() = 0; 79 virtual const DWARFDebugLoc *getDebugLoc() = 0; 80 virtual const DWARFDebugAranges *getDebugAranges() = 0; 81 virtual Expected<const DWARFDebugLine::LineTable *> 82 getLineTableForUnit(DWARFUnit *U, 83 function_ref<void(Error)> RecoverableErrHandler) = 0; 84 virtual void clearLineTableForUnit(DWARFUnit *U) = 0; 85 virtual Expected<const DWARFDebugFrame *> getDebugFrame() = 0; 86 virtual Expected<const DWARFDebugFrame *> getEHFrame() = 0; 87 virtual const DWARFDebugMacro *getDebugMacinfo() = 0; 88 virtual const DWARFDebugMacro *getDebugMacinfoDWO() = 0; 89 virtual const DWARFDebugMacro *getDebugMacro() = 0; 90 virtual const DWARFDebugMacro *getDebugMacroDWO() = 0; 91 virtual const DWARFDebugNames &getDebugNames() = 0; 92 virtual const AppleAcceleratorTable &getAppleNames() = 0; 93 virtual const AppleAcceleratorTable &getAppleTypes() = 0; 94 virtual const AppleAcceleratorTable &getAppleNamespaces() = 0; 95 virtual const AppleAcceleratorTable &getAppleObjC() = 0; 96 virtual std::shared_ptr<DWARFContext> 97 getDWOContext(StringRef AbsolutePath) = 0; 98 virtual const DenseMap<uint64_t, DWARFTypeUnit *> & 99 getTypeUnitMap(bool IsDWO) = 0; 100 virtual bool isThreadSafe() const = 0; 101 102 /// Parse a macro[.dwo] or macinfo[.dwo] section. 103 std::unique_ptr<DWARFDebugMacro> 104 parseMacroOrMacinfo(MacroSecType SectionType); 105 106 }; 107 friend class DWARFContextState; 108 109 private: 110 /// All important state for a DWARFContext that needs to be threadsafe needs 111 /// to go into DWARFContextState. 112 std::unique_ptr<DWARFContextState> State; 113 114 /// The maximum DWARF version of all units. 115 unsigned MaxVersion = 0; 116 117 std::function<void(Error)> RecoverableErrorHandler = 118 WithColor::defaultErrorHandler; 119 std::function<void(Error)> WarningHandler = WithColor::defaultWarningHandler; 120 121 /// Read compile units from the debug_info.dwo section (if necessary) 122 /// and type units from the debug_types.dwo section (if necessary) 123 /// and store them in DWOUnits. 124 /// If \p Lazy is true, set up to parse but don't actually parse them. 125 enum { EagerParse = false, LazyParse = true }; 126 DWARFUnitVector &getDWOUnits(bool Lazy = false); 127 128 std::unique_ptr<const DWARFObject> DObj; 129 130 // When set parses debug_info.dwo/debug_abbrev.dwo manually and populates CU 131 // Index, and TU Index for DWARF5. 132 bool ParseCUTUIndexManually = false; 133 134 public: 135 DWARFContext(std::unique_ptr<const DWARFObject> DObj, 136 std::string DWPName = "", 137 std::function<void(Error)> RecoverableErrorHandler = 138 WithColor::defaultErrorHandler, 139 std::function<void(Error)> WarningHandler = 140 WithColor::defaultWarningHandler, 141 bool ThreadSafe = false); 142 ~DWARFContext() override; 143 144 DWARFContext(DWARFContext &) = delete; 145 DWARFContext &operator=(DWARFContext &) = delete; 146 getDWARFObj()147 const DWARFObject &getDWARFObj() const { return *DObj; } 148 classof(const DIContext * DICtx)149 static bool classof(const DIContext *DICtx) { 150 return DICtx->getKind() == CK_DWARF; 151 } 152 153 /// Dump a textual representation to \p OS. If any \p DumpOffsets are present, 154 /// dump only the record at the specified offset. 155 void dump(raw_ostream &OS, DIDumpOptions DumpOpts, 156 std::array<std::optional<uint64_t>, DIDT_ID_Count> DumpOffsets); 157 dump(raw_ostream & OS,DIDumpOptions DumpOpts)158 void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override { 159 std::array<std::optional<uint64_t>, DIDT_ID_Count> DumpOffsets; 160 dump(OS, DumpOpts, DumpOffsets); 161 } 162 163 bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override; 164 165 using unit_iterator_range = DWARFUnitVector::iterator_range; 166 using compile_unit_range = DWARFUnitVector::compile_unit_range; 167 168 /// Get units from .debug_info in this context. info_section_units()169 unit_iterator_range info_section_units() { 170 DWARFUnitVector &NormalUnits = State->getNormalUnits(); 171 return unit_iterator_range(NormalUnits.begin(), 172 NormalUnits.begin() + 173 NormalUnits.getNumInfoUnits()); 174 } 175 getNormalUnitsVector()176 const DWARFUnitVector &getNormalUnitsVector() { 177 return State->getNormalUnits(); 178 } 179 180 /// Get units from .debug_types in this context. types_section_units()181 unit_iterator_range types_section_units() { 182 DWARFUnitVector &NormalUnits = State->getNormalUnits(); 183 return unit_iterator_range( 184 NormalUnits.begin() + NormalUnits.getNumInfoUnits(), NormalUnits.end()); 185 } 186 187 /// Get compile units in this context. compile_units()188 compile_unit_range compile_units() { 189 return make_filter_range(info_section_units(), isCompileUnit); 190 } 191 192 // If you want type_units(), it'll need to be a concat iterator of a filter of 193 // TUs in info_section + all the (all type) units in types_section 194 195 /// Get all normal compile/type units in this context. normal_units()196 unit_iterator_range normal_units() { 197 DWARFUnitVector &NormalUnits = State->getNormalUnits(); 198 return unit_iterator_range(NormalUnits.begin(), NormalUnits.end()); 199 } 200 201 /// Get units from .debug_info..dwo in the DWO context. dwo_info_section_units()202 unit_iterator_range dwo_info_section_units() { 203 DWARFUnitVector &DWOUnits = State->getDWOUnits(); 204 return unit_iterator_range(DWOUnits.begin(), 205 DWOUnits.begin() + DWOUnits.getNumInfoUnits()); 206 } 207 getDWOUnitsVector()208 const DWARFUnitVector &getDWOUnitsVector() { 209 return State->getDWOUnits(); 210 } 211 212 /// Get units from .debug_types.dwo in the DWO context. dwo_types_section_units()213 unit_iterator_range dwo_types_section_units() { 214 DWARFUnitVector &DWOUnits = State->getDWOUnits(); 215 return unit_iterator_range(DWOUnits.begin() + DWOUnits.getNumInfoUnits(), 216 DWOUnits.end()); 217 } 218 219 /// Get compile units in the DWO context. dwo_compile_units()220 compile_unit_range dwo_compile_units() { 221 return make_filter_range(dwo_info_section_units(), isCompileUnit); 222 } 223 224 // If you want dwo_type_units(), it'll need to be a concat iterator of a 225 // filter of TUs in dwo_info_section + all the (all type) units in 226 // dwo_types_section. 227 228 /// Get all units in the DWO context. dwo_units()229 unit_iterator_range dwo_units() { 230 DWARFUnitVector &DWOUnits = State->getDWOUnits(); 231 return unit_iterator_range(DWOUnits.begin(), DWOUnits.end()); 232 } 233 234 /// Get the number of compile units in this context. getNumCompileUnits()235 unsigned getNumCompileUnits() { 236 return State->getNormalUnits().getNumInfoUnits(); 237 } 238 239 /// Get the number of type units in this context. getNumTypeUnits()240 unsigned getNumTypeUnits() { 241 return State->getNormalUnits().getNumTypesUnits(); 242 } 243 244 /// Get the number of compile units in the DWO context. getNumDWOCompileUnits()245 unsigned getNumDWOCompileUnits() { 246 return State->getDWOUnits().getNumInfoUnits(); 247 } 248 249 /// Get the number of type units in the DWO context. getNumDWOTypeUnits()250 unsigned getNumDWOTypeUnits() { 251 return State->getDWOUnits().getNumTypesUnits(); 252 } 253 254 /// Get the unit at the specified index. getUnitAtIndex(unsigned index)255 DWARFUnit *getUnitAtIndex(unsigned index) { 256 return State->getNormalUnits()[index].get(); 257 } 258 259 /// Get the unit at the specified index for the DWO units. getDWOUnitAtIndex(unsigned index)260 DWARFUnit *getDWOUnitAtIndex(unsigned index) { 261 return State->getDWOUnits()[index].get(); 262 } 263 264 DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash); 265 DWARFTypeUnit *getTypeUnitForHash(uint16_t Version, uint64_t Hash, bool IsDWO); 266 267 /// Return the compile unit that includes an offset (relative to .debug_info). 268 DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset); 269 270 /// Get a DIE given an exact offset. 271 DWARFDie getDIEForOffset(uint64_t Offset); 272 getMaxVersion()273 unsigned getMaxVersion() { 274 // Ensure info units have been parsed to discover MaxVersion 275 info_section_units(); 276 return MaxVersion; 277 } 278 getMaxDWOVersion()279 unsigned getMaxDWOVersion() { 280 // Ensure DWO info units have been parsed to discover MaxVersion 281 dwo_info_section_units(); 282 return MaxVersion; 283 } 284 setMaxVersionIfGreater(unsigned Version)285 void setMaxVersionIfGreater(unsigned Version) { 286 if (Version > MaxVersion) 287 MaxVersion = Version; 288 } 289 290 const DWARFUnitIndex &getCUIndex(); 291 DWARFGdbIndex &getGdbIndex(); 292 const DWARFUnitIndex &getTUIndex(); 293 294 /// Get a pointer to the parsed DebugAbbrev object. 295 const DWARFDebugAbbrev *getDebugAbbrev(); 296 297 /// Get a pointer to the parsed DebugLoc object. 298 const DWARFDebugLoc *getDebugLoc(); 299 300 /// Get a pointer to the parsed dwo abbreviations object. 301 const DWARFDebugAbbrev *getDebugAbbrevDWO(); 302 303 /// Get a pointer to the parsed DebugAranges object. 304 const DWARFDebugAranges *getDebugAranges(); 305 306 /// Get a pointer to the parsed frame information object. 307 Expected<const DWARFDebugFrame *> getDebugFrame(); 308 309 /// Get a pointer to the parsed eh frame information object. 310 Expected<const DWARFDebugFrame *> getEHFrame(); 311 312 /// Get a pointer to the parsed DebugMacinfo information object. 313 const DWARFDebugMacro *getDebugMacinfo(); 314 315 /// Get a pointer to the parsed DebugMacinfoDWO information object. 316 const DWARFDebugMacro *getDebugMacinfoDWO(); 317 318 /// Get a pointer to the parsed DebugMacro information object. 319 const DWARFDebugMacro *getDebugMacro(); 320 321 /// Get a pointer to the parsed DebugMacroDWO information object. 322 const DWARFDebugMacro *getDebugMacroDWO(); 323 324 /// Get a reference to the parsed accelerator table object. 325 const DWARFDebugNames &getDebugNames(); 326 327 /// Get a reference to the parsed accelerator table object. 328 const AppleAcceleratorTable &getAppleNames(); 329 330 /// Get a reference to the parsed accelerator table object. 331 const AppleAcceleratorTable &getAppleTypes(); 332 333 /// Get a reference to the parsed accelerator table object. 334 const AppleAcceleratorTable &getAppleNamespaces(); 335 336 /// Get a reference to the parsed accelerator table object. 337 const AppleAcceleratorTable &getAppleObjC(); 338 339 /// Get a pointer to a parsed line table corresponding to a compile unit. 340 /// Report any parsing issues as warnings on stderr. 341 const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *U); 342 343 /// Get a pointer to a parsed line table corresponding to a compile unit. 344 /// Report any recoverable parsing problems using the handler. 345 Expected<const DWARFDebugLine::LineTable *> 346 getLineTableForUnit(DWARFUnit *U, 347 function_ref<void(Error)> RecoverableErrorHandler); 348 349 // Clear the line table object corresponding to a compile unit for memory 350 // management purpose. When it's referred to again, it'll be re-populated. 351 void clearLineTableForUnit(DWARFUnit *U); 352 getStringExtractor()353 DataExtractor getStringExtractor() const { 354 return DataExtractor(DObj->getStrSection(), false, 0); 355 } getStringDWOExtractor()356 DataExtractor getStringDWOExtractor() const { 357 return DataExtractor(DObj->getStrDWOSection(), false, 0); 358 } getLineStringExtractor()359 DataExtractor getLineStringExtractor() const { 360 return DataExtractor(DObj->getLineStrSection(), false, 0); 361 } 362 363 /// Wraps the returned DIEs for a given address. 364 struct DIEsForAddress { 365 DWARFCompileUnit *CompileUnit = nullptr; 366 DWARFDie FunctionDIE; 367 DWARFDie BlockDIE; 368 explicit operator bool() const { return CompileUnit != nullptr; } 369 }; 370 371 /// Get the compilation unit, the function DIE and lexical block DIE for the 372 /// given address where applicable. 373 /// TODO: change input parameter from "uint64_t Address" 374 /// into "SectionedAddress Address" 375 /// \param[in] CheckDWO If this is false then only search for address matches 376 /// in the current context's DIEs. If this is true, then each 377 /// DWARFUnit that has a DWO file will have the debug info in the 378 /// DWO file searched as well. This allows for lookups to succeed 379 /// by searching the split DWARF debug info when using the main 380 /// executable's debug info. 381 DIEsForAddress getDIEsForAddress(uint64_t Address, bool CheckDWO = false); 382 383 DILineInfo getLineInfoForAddress( 384 object::SectionedAddress Address, 385 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; 386 DILineInfo 387 getLineInfoForDataAddress(object::SectionedAddress Address) override; 388 DILineInfoTable getLineInfoForAddressRange( 389 object::SectionedAddress Address, uint64_t Size, 390 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; 391 DIInliningInfo getInliningInfoForAddress( 392 object::SectionedAddress Address, 393 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; 394 395 std::vector<DILocal> 396 getLocalsForAddress(object::SectionedAddress Address) override; 397 isLittleEndian()398 bool isLittleEndian() const { return DObj->isLittleEndian(); } getMaxSupportedVersion()399 static unsigned getMaxSupportedVersion() { return 5; } isSupportedVersion(unsigned version)400 static bool isSupportedVersion(unsigned version) { 401 return version >= 2 && version <= getMaxSupportedVersion(); 402 } 403 getSupportedAddressSizes()404 static SmallVector<uint8_t, 3> getSupportedAddressSizes() { 405 return {2, 4, 8}; 406 } isAddressSizeSupported(unsigned AddressSize)407 static bool isAddressSizeSupported(unsigned AddressSize) { 408 return llvm::is_contained(getSupportedAddressSizes(), AddressSize); 409 } 410 template <typename... Ts> checkAddressSizeSupported(unsigned AddressSize,std::error_code EC,char const * Fmt,const Ts &...Vals)411 static Error checkAddressSizeSupported(unsigned AddressSize, 412 std::error_code EC, char const *Fmt, 413 const Ts &...Vals) { 414 if (isAddressSizeSupported(AddressSize)) 415 return Error::success(); 416 std::string Buffer; 417 raw_string_ostream Stream(Buffer); 418 Stream << format(Fmt, Vals...) 419 << " has unsupported address size: " << AddressSize 420 << " (supported are "; 421 ListSeparator LS; 422 for (unsigned Size : DWARFContext::getSupportedAddressSizes()) 423 Stream << LS << Size; 424 Stream << ')'; 425 return make_error<StringError>(Buffer, EC); 426 } 427 428 std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath); 429 getRecoverableErrorHandler()430 function_ref<void(Error)> getRecoverableErrorHandler() { 431 return RecoverableErrorHandler; 432 } 433 getWarningHandler()434 function_ref<void(Error)> getWarningHandler() { return WarningHandler; } 435 436 enum class ProcessDebugRelocations { Process, Ignore }; 437 438 static std::unique_ptr<DWARFContext> 439 create(const object::ObjectFile &Obj, 440 ProcessDebugRelocations RelocAction = ProcessDebugRelocations::Process, 441 const LoadedObjectInfo *L = nullptr, std::string DWPName = "", 442 std::function<void(Error)> RecoverableErrorHandler = 443 WithColor::defaultErrorHandler, 444 std::function<void(Error)> WarningHandler = 445 WithColor::defaultWarningHandler, 446 bool ThreadSafe = false); 447 448 static std::unique_ptr<DWARFContext> 449 create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, 450 uint8_t AddrSize, bool isLittleEndian = sys::IsLittleEndianHost, 451 std::function<void(Error)> RecoverableErrorHandler = 452 WithColor::defaultErrorHandler, 453 std::function<void(Error)> WarningHandler = 454 WithColor::defaultWarningHandler, 455 bool ThreadSafe = false); 456 457 /// Get address size from CUs. 458 /// TODO: refactor compile_units() to make this const. 459 uint8_t getCUAddrSize(); 460 getArch()461 Triple::ArchType getArch() const { 462 return getDWARFObj().getFile()->getArch(); 463 } 464 465 /// Return the compile unit which contains instruction with provided 466 /// address. 467 /// TODO: change input parameter from "uint64_t Address" 468 /// into "SectionedAddress Address" 469 DWARFCompileUnit *getCompileUnitForCodeAddress(uint64_t Address); 470 471 /// Return the compile unit which contains data with the provided address. 472 /// Note: This is more expensive than `getCompileUnitForAddress`, as if 473 /// `Address` isn't found in the CU ranges (which is cheap), then it falls 474 /// back to an expensive O(n) walk of all CU's looking for data that spans the 475 /// address. 476 /// TODO: change input parameter from "uint64_t Address" into 477 /// "SectionedAddress Address" 478 DWARFCompileUnit *getCompileUnitForDataAddress(uint64_t Address); 479 480 /// Returns whether CU/TU should be populated manually. TU Index populated 481 /// manually only for DWARF5. getParseCUTUIndexManually()482 bool getParseCUTUIndexManually() const { return ParseCUTUIndexManually; } 483 484 /// Sets whether CU/TU should be populated manually. TU Index populated 485 /// manually only for DWARF5. setParseCUTUIndexManually(bool PCUTU)486 void setParseCUTUIndexManually(bool PCUTU) { ParseCUTUIndexManually = PCUTU; } 487 488 private: 489 void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die, 490 std::vector<DILocal> &Result); 491 }; 492 493 } // end namespace llvm 494 495 #endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H 496