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 bool 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 (AbbrDecl.extract(Data, OffsetPtr)) { 36 if (FirstAbbrCode == 0) { 37 FirstAbbrCode = AbbrDecl.getCode(); 38 } else { 39 if (PrevAbbrCode + 1 != AbbrDecl.getCode()) { 40 // Codes are not consecutive, can't do O(1) lookups. 41 FirstAbbrCode = UINT32_MAX; 42 } 43 } 44 PrevAbbrCode = AbbrDecl.getCode(); 45 Decls.push_back(std::move(AbbrDecl)); 46 } 47 return BeginOffset != *OffsetPtr; 48 } 49 50 void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const { 51 for (const auto &Decl : Decls) 52 Decl.dump(OS); 53 } 54 55 const DWARFAbbreviationDeclaration * 56 DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration( 57 uint32_t AbbrCode) const { 58 if (FirstAbbrCode == UINT32_MAX) { 59 for (const auto &Decl : Decls) { 60 if (Decl.getCode() == AbbrCode) 61 return &Decl; 62 } 63 return nullptr; 64 } 65 if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size()) 66 return nullptr; 67 return &Decls[AbbrCode - FirstAbbrCode]; 68 } 69 70 std::string DWARFAbbreviationDeclarationSet::getCodeRange() const { 71 // Create a sorted list of all abbrev codes. 72 std::vector<uint32_t> Codes; 73 Codes.reserve(Decls.size()); 74 for (const auto &Decl : Decls) 75 Codes.push_back(Decl.getCode()); 76 77 std::string Buffer; 78 raw_string_ostream Stream(Buffer); 79 // Each iteration through this loop represents a single contiguous range in 80 // the set of codes. 81 for (auto Current = Codes.begin(), End = Codes.end(); Current != End;) { 82 uint32_t RangeStart = *Current; 83 // Add the current range start. 84 Stream << *Current; 85 uint32_t RangeEnd = RangeStart; 86 // Find the end of the current range. 87 while (++Current != End && *Current == RangeEnd + 1) 88 ++RangeEnd; 89 // If there is more than one value in the range, add the range end too. 90 if (RangeStart != RangeEnd) 91 Stream << "-" << RangeEnd; 92 // If there is at least one more range, add a separator. 93 if (Current != End) 94 Stream << ", "; 95 } 96 return Buffer; 97 } 98 99 DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); } 100 101 void DWARFDebugAbbrev::clear() { 102 AbbrDeclSets.clear(); 103 PrevAbbrOffsetPos = AbbrDeclSets.end(); 104 } 105 106 void DWARFDebugAbbrev::extract(DataExtractor Data) { 107 clear(); 108 this->Data = Data; 109 } 110 111 void DWARFDebugAbbrev::parse() const { 112 if (!Data) 113 return; 114 uint64_t Offset = 0; 115 auto I = AbbrDeclSets.begin(); 116 while (Data->isValidOffset(Offset)) { 117 while (I != AbbrDeclSets.end() && I->first < Offset) 118 ++I; 119 uint64_t CUAbbrOffset = Offset; 120 DWARFAbbreviationDeclarationSet AbbrDecls; 121 if (!AbbrDecls.extract(*Data, &Offset)) 122 break; 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 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 uint64_t Offset = CUAbbrOffset; 157 DWARFAbbreviationDeclarationSet AbbrDecls; 158 if (!AbbrDecls.extract(*Data, &Offset)) 159 return nullptr; 160 PrevAbbrOffsetPos = 161 AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) 162 .first; 163 return &PrevAbbrOffsetPos->second; 164 } 165 166 return nullptr; 167 } 168