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