1 //===- DWARFDebugAbbrev.cpp -----------------------------------------------===// 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 #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" 10 #include "llvm/Support/Format.h" 11 #include "llvm/Support/raw_ostream.h" 12 #include <cinttypes> 13 #include <cstdint> 14 15 using namespace llvm; 16 17 DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() { 18 clear(); 19 } 20 21 void DWARFAbbreviationDeclarationSet::clear() { 22 Offset = 0; 23 FirstAbbrCode = 0; 24 Decls.clear(); 25 } 26 27 Error DWARFAbbreviationDeclarationSet::extract(DataExtractor Data, 28 uint64_t *OffsetPtr) { 29 clear(); 30 const uint64_t BeginOffset = *OffsetPtr; 31 Offset = BeginOffset; 32 DWARFAbbreviationDeclaration AbbrDecl; 33 uint32_t PrevAbbrCode = 0; 34 while (true) { 35 Expected<DWARFAbbreviationDeclaration::ExtractState> ES = 36 AbbrDecl.extract(Data, OffsetPtr); 37 if (!ES) 38 return ES.takeError(); 39 40 if (*ES == DWARFAbbreviationDeclaration::ExtractState::Complete) 41 break; 42 43 if (FirstAbbrCode == 0) { 44 FirstAbbrCode = AbbrDecl.getCode(); 45 } else if (PrevAbbrCode + 1 != AbbrDecl.getCode()) { 46 // Codes are not consecutive, can't do O(1) lookups. 47 FirstAbbrCode = UINT32_MAX; 48 } 49 PrevAbbrCode = AbbrDecl.getCode(); 50 Decls.push_back(std::move(AbbrDecl)); 51 } 52 return Error::success(); 53 } 54 55 void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const { 56 for (const auto &Decl : Decls) 57 Decl.dump(OS); 58 } 59 60 const DWARFAbbreviationDeclaration * 61 DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration( 62 uint32_t AbbrCode) const { 63 if (FirstAbbrCode == UINT32_MAX) { 64 for (const auto &Decl : Decls) { 65 if (Decl.getCode() == AbbrCode) 66 return &Decl; 67 } 68 return nullptr; 69 } 70 if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size()) 71 return nullptr; 72 return &Decls[AbbrCode - FirstAbbrCode]; 73 } 74 75 std::string DWARFAbbreviationDeclarationSet::getCodeRange() const { 76 // Create a sorted list of all abbrev codes. 77 std::vector<uint32_t> Codes; 78 Codes.reserve(Decls.size()); 79 for (const auto &Decl : Decls) 80 Codes.push_back(Decl.getCode()); 81 82 std::string Buffer; 83 raw_string_ostream Stream(Buffer); 84 // Each iteration through this loop represents a single contiguous range in 85 // the set of codes. 86 for (auto Current = Codes.begin(), End = Codes.end(); Current != End;) { 87 uint32_t RangeStart = *Current; 88 // Add the current range start. 89 Stream << *Current; 90 uint32_t RangeEnd = RangeStart; 91 // Find the end of the current range. 92 while (++Current != End && *Current == RangeEnd + 1) 93 ++RangeEnd; 94 // If there is more than one value in the range, add the range end too. 95 if (RangeStart != RangeEnd) 96 Stream << "-" << RangeEnd; 97 // If there is at least one more range, add a separator. 98 if (Current != End) 99 Stream << ", "; 100 } 101 return Buffer; 102 } 103 104 DWARFDebugAbbrev::DWARFDebugAbbrev(DataExtractor Data) 105 : AbbrDeclSets(), PrevAbbrOffsetPos(AbbrDeclSets.end()), Data(Data) {} 106 107 Error DWARFDebugAbbrev::parse() const { 108 if (!Data) 109 return Error::success(); 110 uint64_t Offset = 0; 111 auto I = AbbrDeclSets.begin(); 112 while (Data->isValidOffset(Offset)) { 113 while (I != AbbrDeclSets.end() && I->first < Offset) 114 ++I; 115 uint64_t CUAbbrOffset = Offset; 116 DWARFAbbreviationDeclarationSet AbbrDecls; 117 if (Error Err = AbbrDecls.extract(*Data, &Offset)) { 118 Data = std::nullopt; 119 return Err; 120 } 121 AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls))); 122 } 123 Data = std::nullopt; 124 return Error::success(); 125 } 126 127 void DWARFDebugAbbrev::dump(raw_ostream &OS) const { 128 if (Error Err = parse()) 129 // FIXME: We should propagate this error or otherwise display it. 130 llvm::consumeError(std::move(Err)); 131 132 if (AbbrDeclSets.empty()) { 133 OS << "< EMPTY >\n"; 134 return; 135 } 136 137 for (const auto &I : AbbrDeclSets) { 138 OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first); 139 I.second.dump(OS); 140 } 141 } 142 143 Expected<const DWARFAbbreviationDeclarationSet *> 144 DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const { 145 const auto End = AbbrDeclSets.end(); 146 if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) { 147 return &PrevAbbrOffsetPos->second; 148 } 149 150 const auto Pos = AbbrDeclSets.find(CUAbbrOffset); 151 if (Pos != End) { 152 PrevAbbrOffsetPos = Pos; 153 return &Pos->second; 154 } 155 156 if (!Data || CUAbbrOffset >= Data->getData().size()) 157 return make_error<llvm::object::GenericBinaryError>( 158 "the abbreviation offset into the .debug_abbrev section is not valid"); 159 160 uint64_t Offset = CUAbbrOffset; 161 DWARFAbbreviationDeclarationSet AbbrDecls; 162 if (Error Err = AbbrDecls.extract(*Data, &Offset)) 163 return std::move(Err); 164 165 PrevAbbrOffsetPos = 166 AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) 167 .first; 168 return &PrevAbbrOffsetPos->second; 169 } 170