xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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