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 Error DWARFDebugAbbrev::parse() const { 109 if (!Data) 110 return Error::success(); 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 Data = std::nullopt; 120 return Err; 121 } 122 AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls))); 123 } 124 Data = std::nullopt; 125 return Error::success(); 126 } 127 128 void DWARFDebugAbbrev::dump(raw_ostream &OS) const { 129 if (Error Err = parse()) 130 // FIXME: We should propagate this error or otherwise display it. 131 llvm::consumeError(std::move(Err)); 132 133 if (AbbrDeclSets.empty()) { 134 OS << "< EMPTY >\n"; 135 return; 136 } 137 138 for (const auto &I : AbbrDeclSets) { 139 OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first); 140 I.second.dump(OS); 141 } 142 } 143 144 Expected<const DWARFAbbreviationDeclarationSet *> 145 DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const { 146 const auto End = AbbrDeclSets.end(); 147 if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) { 148 return &PrevAbbrOffsetPos->second; 149 } 150 151 const auto Pos = AbbrDeclSets.find(CUAbbrOffset); 152 if (Pos != End) { 153 PrevAbbrOffsetPos = Pos; 154 return &Pos->second; 155 } 156 157 if (!Data || CUAbbrOffset >= Data->getData().size()) 158 return make_error<llvm::object::GenericBinaryError>( 159 "the abbreviation offset into the .debug_abbrev section is not valid"); 160 161 uint64_t Offset = CUAbbrOffset; 162 DWARFAbbreviationDeclarationSet AbbrDecls; 163 if (Error Err = AbbrDecls.extract(*Data, &Offset)) 164 return std::move(Err); 165 166 PrevAbbrOffsetPos = 167 AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) 168 .first; 169 return &PrevAbbrOffsetPos->second; 170 } 171