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
DWARFAbbreviationDeclarationSet()180b57cec5SDimitry Andric DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() {
190b57cec5SDimitry Andric clear();
200b57cec5SDimitry Andric }
210b57cec5SDimitry Andric
clear()220b57cec5SDimitry Andric void DWARFAbbreviationDeclarationSet::clear() {
230b57cec5SDimitry Andric Offset = 0;
240b57cec5SDimitry Andric FirstAbbrCode = 0;
250b57cec5SDimitry Andric Decls.clear();
260b57cec5SDimitry Andric }
270b57cec5SDimitry Andric
extract(DataExtractor Data,uint64_t * OffsetPtr)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
dump(raw_ostream & OS) const560b57cec5SDimitry 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 *
getAbbreviationDeclaration(uint32_t AbbrCode) const620b57cec5SDimitry 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
getCodeRange() const76fe6060f1SDimitry 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
DWARFDebugAbbrev(DataExtractor Data)10506c3fb27SDimitry Andric DWARFDebugAbbrev::DWARFDebugAbbrev(DataExtractor Data)
10606c3fb27SDimitry Andric : AbbrDeclSets(), PrevAbbrOffsetPos(AbbrDeclSets.end()), Data(Data) {}
1070b57cec5SDimitry Andric
parse() const108*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
dump(raw_ostream & OS) const1280b57cec5SDimitry 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 *>
getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const1450b57cec5SDimitry 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