1 //===- DWARFUnit.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_DWARFUNIT_H 10 #define LLVM_DEBUGINFO_DWARF_DWARFUNIT_H 11 12 #include "llvm/ADT/DenseSet.h" 13 #include "llvm/ADT/Optional.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/ADT/iterator_range.h" 18 #include "llvm/BinaryFormat/Dwarf.h" 19 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" 20 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" 21 #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" 22 #include "llvm/DebugInfo/DWARF/DWARFDie.h" 23 #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" 24 #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" 25 #include "llvm/Support/DataExtractor.h" 26 #include <cassert> 27 #include <cstddef> 28 #include <cstdint> 29 #include <map> 30 #include <memory> 31 #include <set> 32 #include <utility> 33 #include <vector> 34 35 namespace llvm { 36 37 class DWARFAbbreviationDeclarationSet; 38 class DWARFContext; 39 class DWARFDebugAbbrev; 40 class DWARFUnit; 41 class DWARFDebugRangeList; 42 class DWARFLocationTable; 43 class DWARFObject; 44 class raw_ostream; 45 struct DIDumpOptions; 46 struct DWARFSection; 47 48 /// Base class describing the header of any kind of "unit." Some information 49 /// is specific to certain unit types. We separate this class out so we can 50 /// parse the header before deciding what specific kind of unit to construct. 51 class DWARFUnitHeader { 52 // Offset within section. 53 uint64_t Offset = 0; 54 // Version, address size, and DWARF format. 55 dwarf::FormParams FormParams; 56 uint64_t Length = 0; 57 uint64_t AbbrOffset = 0; 58 59 // For DWO units only. 60 const DWARFUnitIndex::Entry *IndexEntry = nullptr; 61 62 // For type units only. 63 uint64_t TypeHash = 0; 64 uint64_t TypeOffset = 0; 65 66 // For v5 split or skeleton compile units only. 67 Optional<uint64_t> DWOId; 68 69 // Unit type as parsed, or derived from the section kind. 70 uint8_t UnitType = 0; 71 72 // Size as parsed. uint8_t for compactness. 73 uint8_t Size = 0; 74 75 public: 76 /// Parse a unit header from \p debug_info starting at \p offset_ptr. 77 /// Note that \p SectionKind is used as a hint to guess the unit type 78 /// for DWARF formats prior to DWARFv5. In DWARFv5 the unit type is 79 /// explicitly defined in the header and the hint is ignored. 80 bool extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, 81 uint64_t *offset_ptr, DWARFSectionKind SectionKind); 82 // For units in DWARF Package File, remember the index entry and update 83 // the abbreviation offset read by extract(). 84 bool applyIndexEntry(const DWARFUnitIndex::Entry *Entry); 85 uint64_t getOffset() const { return Offset; } 86 const dwarf::FormParams &getFormParams() const { return FormParams; } 87 uint16_t getVersion() const { return FormParams.Version; } 88 dwarf::DwarfFormat getFormat() const { return FormParams.Format; } 89 uint8_t getAddressByteSize() const { return FormParams.AddrSize; } 90 uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } 91 uint8_t getDwarfOffsetByteSize() const { 92 return FormParams.getDwarfOffsetByteSize(); 93 } 94 uint64_t getLength() const { return Length; } 95 uint64_t getAbbrOffset() const { return AbbrOffset; } 96 Optional<uint64_t> getDWOId() const { return DWOId; } 97 void setDWOId(uint64_t Id) { 98 assert((!DWOId || *DWOId == Id) && "setting DWOId to a different value"); 99 DWOId = Id; 100 } 101 const DWARFUnitIndex::Entry *getIndexEntry() const { return IndexEntry; } 102 uint64_t getTypeHash() const { return TypeHash; } 103 uint64_t getTypeOffset() const { return TypeOffset; } 104 uint8_t getUnitType() const { return UnitType; } 105 bool isTypeUnit() const { 106 return UnitType == dwarf::DW_UT_type || UnitType == dwarf::DW_UT_split_type; 107 } 108 uint8_t getSize() const { return Size; } 109 uint8_t getUnitLengthFieldByteSize() const { 110 return dwarf::getUnitLengthFieldByteSize(FormParams.Format); 111 } 112 uint64_t getNextUnitOffset() const { 113 return Offset + Length + getUnitLengthFieldByteSize(); 114 } 115 }; 116 117 const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, 118 DWARFSectionKind Kind); 119 120 bool isCompileUnit(const std::unique_ptr<DWARFUnit> &U); 121 122 /// Describe a collection of units. Intended to hold all units either from 123 /// .debug_info and .debug_types, or from .debug_info.dwo and .debug_types.dwo. 124 class DWARFUnitVector final : public SmallVector<std::unique_ptr<DWARFUnit>, 1> { 125 std::function<std::unique_ptr<DWARFUnit>(uint64_t, DWARFSectionKind, 126 const DWARFSection *, 127 const DWARFUnitIndex::Entry *)> 128 Parser; 129 int NumInfoUnits = -1; 130 131 public: 132 using UnitVector = SmallVectorImpl<std::unique_ptr<DWARFUnit>>; 133 using iterator = typename UnitVector::iterator; 134 using iterator_range = llvm::iterator_range<typename UnitVector::iterator>; 135 136 using compile_unit_range = 137 decltype(make_filter_range(std::declval<iterator_range>(), isCompileUnit)); 138 139 DWARFUnit *getUnitForOffset(uint64_t Offset) const; 140 DWARFUnit *getUnitForIndexEntry(const DWARFUnitIndex::Entry &E); 141 142 /// Read units from a .debug_info or .debug_types section. Calls made 143 /// before finishedInfoUnits() are assumed to be for .debug_info sections, 144 /// calls after finishedInfoUnits() are for .debug_types sections. Caller 145 /// must not mix calls to addUnitsForSection and addUnitsForDWOSection. 146 void addUnitsForSection(DWARFContext &C, const DWARFSection &Section, 147 DWARFSectionKind SectionKind); 148 /// Read units from a .debug_info.dwo or .debug_types.dwo section. Calls 149 /// made before finishedInfoUnits() are assumed to be for .debug_info.dwo 150 /// sections, calls after finishedInfoUnits() are for .debug_types.dwo 151 /// sections. Caller must not mix calls to addUnitsForSection and 152 /// addUnitsForDWOSection. 153 void addUnitsForDWOSection(DWARFContext &C, const DWARFSection &DWOSection, 154 DWARFSectionKind SectionKind, bool Lazy = false); 155 156 /// Add an existing DWARFUnit to this UnitVector. This is used by the DWARF 157 /// verifier to process unit separately. 158 DWARFUnit *addUnit(std::unique_ptr<DWARFUnit> Unit); 159 160 /// Returns number of all units held by this instance. 161 unsigned getNumUnits() const { return size(); } 162 /// Returns number of units from all .debug_info[.dwo] sections. 163 unsigned getNumInfoUnits() const { 164 return NumInfoUnits == -1 ? size() : NumInfoUnits; 165 } 166 /// Returns number of units from all .debug_types[.dwo] sections. 167 unsigned getNumTypesUnits() const { return size() - NumInfoUnits; } 168 /// Indicate that parsing .debug_info[.dwo] is done, and remaining units 169 /// will be from .debug_types[.dwo]. 170 void finishedInfoUnits() { NumInfoUnits = size(); } 171 172 private: 173 void addUnitsImpl(DWARFContext &Context, const DWARFObject &Obj, 174 const DWARFSection &Section, const DWARFDebugAbbrev *DA, 175 const DWARFSection *RS, const DWARFSection *LocSection, 176 StringRef SS, const DWARFSection &SOS, 177 const DWARFSection *AOS, const DWARFSection &LS, bool LE, 178 bool IsDWO, bool Lazy, DWARFSectionKind SectionKind); 179 }; 180 181 /// Represents base address of the CU. 182 /// Represents a unit's contribution to the string offsets table. 183 struct StrOffsetsContributionDescriptor { 184 uint64_t Base = 0; 185 /// The contribution size not including the header. 186 uint64_t Size = 0; 187 /// Format and version. 188 dwarf::FormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32}; 189 190 StrOffsetsContributionDescriptor(uint64_t Base, uint64_t Size, 191 uint8_t Version, dwarf::DwarfFormat Format) 192 : Base(Base), Size(Size), FormParams({Version, 0, Format}) {} 193 StrOffsetsContributionDescriptor() = default; 194 195 uint8_t getVersion() const { return FormParams.Version; } 196 dwarf::DwarfFormat getFormat() const { return FormParams.Format; } 197 uint8_t getDwarfOffsetByteSize() const { 198 return FormParams.getDwarfOffsetByteSize(); 199 } 200 /// Determine whether a contribution to the string offsets table is 201 /// consistent with the relevant section size and that its length is 202 /// a multiple of the size of one of its entries. 203 Expected<StrOffsetsContributionDescriptor> 204 validateContributionSize(DWARFDataExtractor &DA); 205 }; 206 207 class DWARFUnit { 208 DWARFContext &Context; 209 /// Section containing this DWARFUnit. 210 const DWARFSection &InfoSection; 211 212 DWARFUnitHeader Header; 213 const DWARFDebugAbbrev *Abbrev; 214 const DWARFSection *RangeSection; 215 uint64_t RangeSectionBase; 216 uint64_t LocSectionBase; 217 218 /// Location table of this unit. 219 std::unique_ptr<DWARFLocationTable> LocTable; 220 221 const DWARFSection &LineSection; 222 StringRef StringSection; 223 const DWARFSection &StringOffsetSection; 224 const DWARFSection *AddrOffsetSection; 225 DWARFUnit *SU; 226 Optional<uint64_t> AddrOffsetSectionBase; 227 bool isLittleEndian; 228 bool IsDWO; 229 const DWARFUnitVector &UnitVector; 230 231 /// Start, length, and DWARF format of the unit's contribution to the string 232 /// offsets table (DWARF v5). 233 Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution; 234 235 mutable const DWARFAbbreviationDeclarationSet *Abbrevs; 236 llvm::Optional<object::SectionedAddress> BaseAddr; 237 /// The compile unit debug information entry items. 238 std::vector<DWARFDebugInfoEntry> DieArray; 239 240 /// Map from range's start address to end address and corresponding DIE. 241 /// IntervalMap does not support range removal, as a result, we use the 242 /// std::map::upper_bound for address range lookup. 243 std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap; 244 245 /// Map from the location (interpreted DW_AT_location) of a DW_TAG_variable, 246 /// to the end address and the corresponding DIE. 247 std::map<uint64_t, std::pair<uint64_t, DWARFDie>> VariableDieMap; 248 DenseSet<uint64_t> RootsParsedForVariables; 249 250 using die_iterator_range = 251 iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>; 252 253 std::shared_ptr<DWARFUnit> DWO; 254 255 uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) { 256 auto First = DieArray.data(); 257 assert(Die >= First && Die < First + DieArray.size()); 258 return Die - First; 259 } 260 261 protected: 262 const DWARFUnitHeader &getHeader() const { return Header; } 263 264 /// Find the unit's contribution to the string offsets table and determine its 265 /// length and form. The given offset is expected to be derived from the unit 266 /// DIE's DW_AT_str_offsets_base attribute. 267 Expected<Optional<StrOffsetsContributionDescriptor>> 268 determineStringOffsetsTableContribution(DWARFDataExtractor &DA); 269 270 /// Find the unit's contribution to the string offsets table and determine its 271 /// length and form. The given offset is expected to be 0 in a dwo file or, 272 /// in a dwp file, the start of the unit's contribution to the string offsets 273 /// table section (as determined by the index table). 274 Expected<Optional<StrOffsetsContributionDescriptor>> 275 determineStringOffsetsTableContributionDWO(DWARFDataExtractor &DA); 276 277 public: 278 DWARFUnit(DWARFContext &Context, const DWARFSection &Section, 279 const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, 280 const DWARFSection *RS, const DWARFSection *LocSection, 281 StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, 282 const DWARFSection &LS, bool LE, bool IsDWO, 283 const DWARFUnitVector &UnitVector); 284 285 virtual ~DWARFUnit(); 286 287 bool isDWOUnit() const { return IsDWO; } 288 DWARFContext& getContext() const { return Context; } 289 const DWARFSection &getInfoSection() const { return InfoSection; } 290 uint64_t getOffset() const { return Header.getOffset(); } 291 const dwarf::FormParams &getFormParams() const { 292 return Header.getFormParams(); 293 } 294 uint16_t getVersion() const { return Header.getVersion(); } 295 uint8_t getAddressByteSize() const { return Header.getAddressByteSize(); } 296 uint8_t getRefAddrByteSize() const { return Header.getRefAddrByteSize(); } 297 uint8_t getDwarfOffsetByteSize() const { 298 return Header.getDwarfOffsetByteSize(); 299 } 300 /// Size in bytes of the parsed unit header. 301 uint32_t getHeaderSize() const { return Header.getSize(); } 302 uint64_t getLength() const { return Header.getLength(); } 303 dwarf::DwarfFormat getFormat() const { return Header.getFormat(); } 304 uint8_t getUnitType() const { return Header.getUnitType(); } 305 bool isTypeUnit() const { return Header.isTypeUnit(); } 306 uint64_t getAbbrOffset() const { return Header.getAbbrOffset(); } 307 uint64_t getNextUnitOffset() const { return Header.getNextUnitOffset(); } 308 const DWARFSection &getLineSection() const { return LineSection; } 309 StringRef getStringSection() const { return StringSection; } 310 const DWARFSection &getStringOffsetSection() const { 311 return StringOffsetSection; 312 } 313 314 void setSkeletonUnit(DWARFUnit *SU) { this->SU = SU; } 315 // Returns itself if not using Split DWARF, or if the unit is a skeleton unit 316 // - otherwise returns the split full unit's corresponding skeleton, if 317 // available. 318 DWARFUnit *getLinkedUnit() { return IsDWO ? SU : this; } 319 320 void setAddrOffsetSection(const DWARFSection *AOS, uint64_t Base) { 321 AddrOffsetSection = AOS; 322 AddrOffsetSectionBase = Base; 323 } 324 325 Optional<uint64_t> getAddrOffsetSectionBase() const { 326 return AddrOffsetSectionBase; 327 } 328 329 /// Recursively update address to Die map. 330 void updateAddressDieMap(DWARFDie Die); 331 332 /// Recursively update address to variable Die map. 333 void updateVariableDieMap(DWARFDie Die); 334 335 void setRangesSection(const DWARFSection *RS, uint64_t Base) { 336 RangeSection = RS; 337 RangeSectionBase = Base; 338 } 339 340 uint64_t getLocSectionBase() const { 341 return LocSectionBase; 342 } 343 344 Optional<object::SectionedAddress> 345 getAddrOffsetSectionItem(uint32_t Index) const; 346 Expected<uint64_t> getStringOffsetSectionItem(uint32_t Index) const; 347 348 DWARFDataExtractor getDebugInfoExtractor() const; 349 350 DataExtractor getStringExtractor() const { 351 return DataExtractor(StringSection, false, 0); 352 } 353 354 const DWARFLocationTable &getLocationTable() { return *LocTable; } 355 356 /// Extract the range list referenced by this compile unit from the 357 /// .debug_ranges section. If the extraction is unsuccessful, an error 358 /// is returned. Successful extraction requires that the compile unit 359 /// has already been extracted. 360 Error extractRangeList(uint64_t RangeListOffset, 361 DWARFDebugRangeList &RangeList) const; 362 void clear(); 363 364 const Optional<StrOffsetsContributionDescriptor> & 365 getStringOffsetsTableContribution() const { 366 return StringOffsetsTableContribution; 367 } 368 369 uint8_t getDwarfStringOffsetsByteSize() const { 370 assert(StringOffsetsTableContribution); 371 return StringOffsetsTableContribution->getDwarfOffsetByteSize(); 372 } 373 374 uint64_t getStringOffsetsBase() const { 375 assert(StringOffsetsTableContribution); 376 return StringOffsetsTableContribution->Base; 377 } 378 379 uint64_t getAbbreviationsOffset() const { return Header.getAbbrOffset(); } 380 381 const DWARFAbbreviationDeclarationSet *getAbbreviations() const; 382 383 static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) { 384 switch (UnitType) { 385 case dwarf::DW_UT_compile: 386 return Tag == dwarf::DW_TAG_compile_unit; 387 case dwarf::DW_UT_type: 388 return Tag == dwarf::DW_TAG_type_unit; 389 case dwarf::DW_UT_partial: 390 return Tag == dwarf::DW_TAG_partial_unit; 391 case dwarf::DW_UT_skeleton: 392 return Tag == dwarf::DW_TAG_skeleton_unit; 393 case dwarf::DW_UT_split_compile: 394 case dwarf::DW_UT_split_type: 395 return dwarf::isUnitType(Tag); 396 } 397 return false; 398 } 399 400 llvm::Optional<object::SectionedAddress> getBaseAddress(); 401 402 DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) { 403 extractDIEsIfNeeded(ExtractUnitDIEOnly); 404 if (DieArray.empty()) 405 return DWARFDie(); 406 return DWARFDie(this, &DieArray[0]); 407 } 408 409 DWARFDie getNonSkeletonUnitDIE(bool ExtractUnitDIEOnly = true) { 410 parseDWO(); 411 if (DWO) 412 return DWO->getUnitDIE(ExtractUnitDIEOnly); 413 return getUnitDIE(ExtractUnitDIEOnly); 414 } 415 416 const char *getCompilationDir(); 417 Optional<uint64_t> getDWOId() { 418 extractDIEsIfNeeded(/*CUDieOnly*/ true); 419 return getHeader().getDWOId(); 420 } 421 void setDWOId(uint64_t NewID) { Header.setDWOId(NewID); } 422 423 /// Return a vector of address ranges resulting from a (possibly encoded) 424 /// range list starting at a given offset in the appropriate ranges section. 425 Expected<DWARFAddressRangesVector> findRnglistFromOffset(uint64_t Offset); 426 427 /// Return a vector of address ranges retrieved from an encoded range 428 /// list whose offset is found via a table lookup given an index (DWARF v5 429 /// and later). 430 Expected<DWARFAddressRangesVector> findRnglistFromIndex(uint32_t Index); 431 432 /// Return a rangelist's offset based on an index. The index designates 433 /// an entry in the rangelist table's offset array and is supplied by 434 /// DW_FORM_rnglistx. 435 Optional<uint64_t> getRnglistOffset(uint32_t Index); 436 437 Optional<uint64_t> getLoclistOffset(uint32_t Index); 438 439 Expected<DWARFAddressRangesVector> collectAddressRanges(); 440 441 Expected<DWARFLocationExpressionsVector> 442 findLoclistFromOffset(uint64_t Offset); 443 444 /// Returns subprogram DIE with address range encompassing the provided 445 /// address. The pointer is alive as long as parsed compile unit DIEs are not 446 /// cleared. 447 DWARFDie getSubroutineForAddress(uint64_t Address); 448 449 /// Returns variable DIE for the address provided. The pointer is alive as 450 /// long as parsed compile unit DIEs are not cleared. 451 DWARFDie getVariableForAddress(uint64_t Address); 452 453 /// getInlinedChainForAddress - fetches inlined chain for a given address. 454 /// Returns empty chain if there is no subprogram containing address. The 455 /// chain is valid as long as parsed compile unit DIEs are not cleared. 456 void getInlinedChainForAddress(uint64_t Address, 457 SmallVectorImpl<DWARFDie> &InlinedChain); 458 459 /// Return the DWARFUnitVector containing this unit. 460 const DWARFUnitVector &getUnitVector() const { return UnitVector; } 461 462 /// Returns the number of DIEs in the unit. Parses the unit 463 /// if necessary. 464 unsigned getNumDIEs() { 465 extractDIEsIfNeeded(false); 466 return DieArray.size(); 467 } 468 469 /// Return the index of a DIE inside the unit's DIE vector. 470 /// 471 /// It is illegal to call this method with a DIE that hasn't be 472 /// created by this unit. In other word, it's illegal to call this 473 /// method on a DIE that isn't accessible by following 474 /// children/sibling links starting from this unit's getUnitDIE(). 475 uint32_t getDIEIndex(const DWARFDie &D) { 476 return getDIEIndex(D.getDebugInfoEntry()); 477 } 478 479 /// Return the DIE object at the given index. 480 DWARFDie getDIEAtIndex(unsigned Index) { 481 assert(Index < DieArray.size()); 482 return DWARFDie(this, &DieArray[Index]); 483 } 484 485 DWARFDie getParent(const DWARFDebugInfoEntry *Die); 486 DWARFDie getSibling(const DWARFDebugInfoEntry *Die); 487 DWARFDie getPreviousSibling(const DWARFDebugInfoEntry *Die); 488 DWARFDie getFirstChild(const DWARFDebugInfoEntry *Die); 489 DWARFDie getLastChild(const DWARFDebugInfoEntry *Die); 490 491 /// Return the DIE object for a given offset inside the 492 /// unit's DIE vector. 493 /// 494 /// The unit needs to have its DIEs extracted for this method to work. 495 DWARFDie getDIEForOffset(uint64_t Offset) { 496 extractDIEsIfNeeded(false); 497 auto It = 498 llvm::partition_point(DieArray, [=](const DWARFDebugInfoEntry &DIE) { 499 return DIE.getOffset() < Offset; 500 }); 501 if (It != DieArray.end() && It->getOffset() == Offset) 502 return DWARFDie(this, &*It); 503 return DWARFDie(); 504 } 505 506 uint32_t getLineTableOffset() const { 507 if (auto IndexEntry = Header.getIndexEntry()) 508 if (const auto *Contrib = IndexEntry->getContribution(DW_SECT_LINE)) 509 return Contrib->Offset; 510 return 0; 511 } 512 513 die_iterator_range dies() { 514 extractDIEsIfNeeded(false); 515 return die_iterator_range(DieArray.begin(), DieArray.end()); 516 } 517 518 virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0; 519 520 Error tryExtractDIEsIfNeeded(bool CUDieOnly); 521 522 private: 523 /// Size in bytes of the .debug_info data associated with this compile unit. 524 size_t getDebugInfoSize() const { 525 return Header.getLength() + Header.getUnitLengthFieldByteSize() - 526 getHeaderSize(); 527 } 528 529 /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it 530 /// hasn't already been done 531 void extractDIEsIfNeeded(bool CUDieOnly); 532 533 /// extractDIEsToVector - Appends all parsed DIEs to a vector. 534 void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs, 535 std::vector<DWARFDebugInfoEntry> &DIEs) const; 536 537 /// clearDIEs - Clear parsed DIEs to keep memory usage low. 538 void clearDIEs(bool KeepCUDie); 539 540 /// parseDWO - Parses .dwo file for current compile unit. Returns true if 541 /// it was actually constructed. 542 bool parseDWO(); 543 }; 544 545 inline bool isCompileUnit(const std::unique_ptr<DWARFUnit> &U) { 546 return !U->isTypeUnit(); 547 } 548 549 } // end namespace llvm 550 551 #endif // LLVM_DEBUGINFO_DWARF_DWARFUNIT_H 552