170 lines · cpp
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-exception6//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 15using namespace llvm;16 17DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() {18 clear();19}20 21void DWARFAbbreviationDeclarationSet::clear() {22 Offset = 0;23 FirstAbbrCode = 0;24 Decls.clear();25}26 27Error 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 55void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const {56 for (const auto &Decl : Decls)57 Decl.dump(OS);58}59 60const DWARFAbbreviationDeclaration *61DWARFAbbreviationDeclarationSet::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 75std::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 in85 // 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 104DWARFDebugAbbrev::DWARFDebugAbbrev(DataExtractor Data)105 : AbbrDeclSets(), PrevAbbrOffsetPos(AbbrDeclSets.end()), Data(Data) {}106 107Error 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 127void 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 143Expected<const DWARFAbbreviationDeclarationSet *>144DWARFDebugAbbrev::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