10b57cec5SDimitry Andric //===- DWARFDebugAbbrev.cpp -----------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" 100b57cec5SDimitry Andric #include "llvm/Support/Format.h" 110b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 120b57cec5SDimitry Andric #include <algorithm> 130b57cec5SDimitry Andric #include <cinttypes> 140b57cec5SDimitry Andric #include <cstdint> 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric using namespace llvm; 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() { 190b57cec5SDimitry Andric clear(); 200b57cec5SDimitry Andric } 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric void DWARFAbbreviationDeclarationSet::clear() { 230b57cec5SDimitry Andric Offset = 0; 240b57cec5SDimitry Andric FirstAbbrCode = 0; 250b57cec5SDimitry Andric Decls.clear(); 260b57cec5SDimitry Andric } 270b57cec5SDimitry Andric 2806c3fb27SDimitry Andric Error DWARFAbbreviationDeclarationSet::extract(DataExtractor Data, 298bcb0991SDimitry Andric uint64_t *OffsetPtr) { 300b57cec5SDimitry Andric clear(); 318bcb0991SDimitry Andric const uint64_t BeginOffset = *OffsetPtr; 320b57cec5SDimitry Andric Offset = BeginOffset; 330b57cec5SDimitry Andric DWARFAbbreviationDeclaration AbbrDecl; 340b57cec5SDimitry Andric uint32_t PrevAbbrCode = 0; 3506c3fb27SDimitry Andric while (true) { 3606c3fb27SDimitry Andric Expected<DWARFAbbreviationDeclaration::ExtractState> ES = 3706c3fb27SDimitry Andric AbbrDecl.extract(Data, OffsetPtr); 3806c3fb27SDimitry Andric if (!ES) 3906c3fb27SDimitry Andric return ES.takeError(); 4006c3fb27SDimitry Andric 4106c3fb27SDimitry Andric if (*ES == DWARFAbbreviationDeclaration::ExtractState::Complete) 4206c3fb27SDimitry Andric break; 4306c3fb27SDimitry Andric 440b57cec5SDimitry Andric if (FirstAbbrCode == 0) { 450b57cec5SDimitry Andric FirstAbbrCode = AbbrDecl.getCode(); 4606c3fb27SDimitry Andric } else if (PrevAbbrCode + 1 != AbbrDecl.getCode()) { 470b57cec5SDimitry Andric // Codes are not consecutive, can't do O(1) lookups. 480b57cec5SDimitry Andric FirstAbbrCode = UINT32_MAX; 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric PrevAbbrCode = AbbrDecl.getCode(); 510b57cec5SDimitry Andric Decls.push_back(std::move(AbbrDecl)); 520b57cec5SDimitry Andric } 5306c3fb27SDimitry Andric return Error::success(); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const { 570b57cec5SDimitry Andric for (const auto &Decl : Decls) 580b57cec5SDimitry Andric Decl.dump(OS); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric const DWARFAbbreviationDeclaration * 620b57cec5SDimitry Andric DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration( 630b57cec5SDimitry Andric uint32_t AbbrCode) const { 640b57cec5SDimitry Andric if (FirstAbbrCode == UINT32_MAX) { 650b57cec5SDimitry Andric for (const auto &Decl : Decls) { 660b57cec5SDimitry Andric if (Decl.getCode() == AbbrCode) 670b57cec5SDimitry Andric return &Decl; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric return nullptr; 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size()) 720b57cec5SDimitry Andric return nullptr; 730b57cec5SDimitry Andric return &Decls[AbbrCode - FirstAbbrCode]; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 76fe6060f1SDimitry Andric std::string DWARFAbbreviationDeclarationSet::getCodeRange() const { 77fe6060f1SDimitry Andric // Create a sorted list of all abbrev codes. 78fe6060f1SDimitry Andric std::vector<uint32_t> Codes; 79fe6060f1SDimitry Andric Codes.reserve(Decls.size()); 80fe6060f1SDimitry Andric for (const auto &Decl : Decls) 81fe6060f1SDimitry Andric Codes.push_back(Decl.getCode()); 82fe6060f1SDimitry Andric 8304eeddc0SDimitry Andric std::string Buffer; 84fe6060f1SDimitry Andric raw_string_ostream Stream(Buffer); 85fe6060f1SDimitry Andric // Each iteration through this loop represents a single contiguous range in 86fe6060f1SDimitry Andric // the set of codes. 87fe6060f1SDimitry Andric for (auto Current = Codes.begin(), End = Codes.end(); Current != End;) { 88fe6060f1SDimitry Andric uint32_t RangeStart = *Current; 89fe6060f1SDimitry Andric // Add the current range start. 90fe6060f1SDimitry Andric Stream << *Current; 91fe6060f1SDimitry Andric uint32_t RangeEnd = RangeStart; 92fe6060f1SDimitry Andric // Find the end of the current range. 93fe6060f1SDimitry Andric while (++Current != End && *Current == RangeEnd + 1) 94fe6060f1SDimitry Andric ++RangeEnd; 95fe6060f1SDimitry Andric // If there is more than one value in the range, add the range end too. 96fe6060f1SDimitry Andric if (RangeStart != RangeEnd) 97fe6060f1SDimitry Andric Stream << "-" << RangeEnd; 98fe6060f1SDimitry Andric // If there is at least one more range, add a separator. 99fe6060f1SDimitry Andric if (Current != End) 100fe6060f1SDimitry Andric Stream << ", "; 101fe6060f1SDimitry Andric } 102fe6060f1SDimitry Andric return Buffer; 103fe6060f1SDimitry Andric } 104fe6060f1SDimitry Andric 10506c3fb27SDimitry Andric DWARFDebugAbbrev::DWARFDebugAbbrev(DataExtractor Data) 10606c3fb27SDimitry Andric : AbbrDeclSets(), PrevAbbrOffsetPos(AbbrDeclSets.end()), Data(Data) {} 1070b57cec5SDimitry Andric 108*5f757f3fSDimitry Andric Error DWARFDebugAbbrev::parse() const { 1090b57cec5SDimitry Andric if (!Data) 110*5f757f3fSDimitry Andric return Error::success(); 1118bcb0991SDimitry Andric uint64_t Offset = 0; 1120b57cec5SDimitry Andric auto I = AbbrDeclSets.begin(); 1130b57cec5SDimitry Andric while (Data->isValidOffset(Offset)) { 1140b57cec5SDimitry Andric while (I != AbbrDeclSets.end() && I->first < Offset) 1150b57cec5SDimitry Andric ++I; 1168bcb0991SDimitry Andric uint64_t CUAbbrOffset = Offset; 1170b57cec5SDimitry Andric DWARFAbbreviationDeclarationSet AbbrDecls; 11806c3fb27SDimitry Andric if (Error Err = AbbrDecls.extract(*Data, &Offset)) { 119*5f757f3fSDimitry Andric Data = std::nullopt; 120*5f757f3fSDimitry Andric return Err; 12106c3fb27SDimitry Andric } 1220b57cec5SDimitry Andric AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls))); 1230b57cec5SDimitry Andric } 124bdd1243dSDimitry Andric Data = std::nullopt; 125*5f757f3fSDimitry Andric return Error::success(); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric void DWARFDebugAbbrev::dump(raw_ostream &OS) const { 129*5f757f3fSDimitry Andric if (Error Err = parse()) 130*5f757f3fSDimitry Andric // FIXME: We should propagate this error or otherwise display it. 131*5f757f3fSDimitry Andric llvm::consumeError(std::move(Err)); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric if (AbbrDeclSets.empty()) { 1340b57cec5SDimitry Andric OS << "< EMPTY >\n"; 1350b57cec5SDimitry Andric return; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric for (const auto &I : AbbrDeclSets) { 1390b57cec5SDimitry Andric OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first); 1400b57cec5SDimitry Andric I.second.dump(OS); 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 14406c3fb27SDimitry Andric Expected<const DWARFAbbreviationDeclarationSet *> 1450b57cec5SDimitry Andric DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const { 1460b57cec5SDimitry Andric const auto End = AbbrDeclSets.end(); 1470b57cec5SDimitry Andric if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) { 14806c3fb27SDimitry Andric return &PrevAbbrOffsetPos->second; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric const auto Pos = AbbrDeclSets.find(CUAbbrOffset); 1520b57cec5SDimitry Andric if (Pos != End) { 1530b57cec5SDimitry Andric PrevAbbrOffsetPos = Pos; 15406c3fb27SDimitry Andric return &Pos->second; 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 15706c3fb27SDimitry Andric if (!Data || CUAbbrOffset >= Data->getData().size()) 15806c3fb27SDimitry Andric return make_error<llvm::object::GenericBinaryError>( 15906c3fb27SDimitry Andric "the abbreviation offset into the .debug_abbrev section is not valid"); 16006c3fb27SDimitry Andric 1618bcb0991SDimitry Andric uint64_t Offset = CUAbbrOffset; 1620b57cec5SDimitry Andric DWARFAbbreviationDeclarationSet AbbrDecls; 16306c3fb27SDimitry Andric if (Error Err = AbbrDecls.extract(*Data, &Offset)) 16406c3fb27SDimitry Andric return std::move(Err); 16506c3fb27SDimitry Andric 1660b57cec5SDimitry Andric PrevAbbrOffsetPos = 1670b57cec5SDimitry Andric AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) 1680b57cec5SDimitry Andric .first; 1690b57cec5SDimitry Andric return &PrevAbbrOffsetPos->second; 1700b57cec5SDimitry Andric } 171