10d840744SZachary Turner //===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===//
20d840744SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60d840744SZachary Turner //
70d840744SZachary Turner //===----------------------------------------------------------------------===//
80d840744SZachary Turner
90d840744SZachary Turner #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
100d840744SZachary Turner
1181cde474Sserge-sans-paille #include "llvm/DebugInfo/CodeView/CodeView.h"
1281cde474Sserge-sans-paille #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
13a6487249SZequan Wu #include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
140d840744SZachary Turner #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
1581cde474Sserge-sans-paille #include "llvm/Support/BinaryStreamArray.h"
1681cde474Sserge-sans-paille #include "llvm/Support/ErrorHandling.h"
170d840744SZachary Turner
180d840744SZachary Turner using namespace llvm;
190d840744SZachary Turner using namespace llvm::codeview;
200d840744SZachary Turner
CVSymbolVisitor(SymbolVisitorCallbacks & Callbacks)210d840744SZachary Turner CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks)
220d840744SZachary Turner : Callbacks(Callbacks) {}
230d840744SZachary Turner
240d840744SZachary Turner template <typename T>
visitKnownRecord(CVSymbol & Record,SymbolVisitorCallbacks & Callbacks)250d840744SZachary Turner static Error visitKnownRecord(CVSymbol &Record,
260d840744SZachary Turner SymbolVisitorCallbacks &Callbacks) {
27e10d0041SReid Kleckner SymbolRecordKind RK = static_cast<SymbolRecordKind>(Record.kind());
280d840744SZachary Turner T KnownRecord(RK);
290d840744SZachary Turner if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
300d840744SZachary Turner return EC;
310d840744SZachary Turner return Error::success();
320d840744SZachary Turner }
330d840744SZachary Turner
finishVisitation(CVSymbol & Record,SymbolVisitorCallbacks & Callbacks)34af8c75a8SZachary Turner static Error finishVisitation(CVSymbol &Record,
35af8c75a8SZachary Turner SymbolVisitorCallbacks &Callbacks) {
36e10d0041SReid Kleckner switch (Record.kind()) {
370d840744SZachary Turner default:
380d840744SZachary Turner if (auto EC = Callbacks.visitUnknownSymbol(Record))
390d840744SZachary Turner return EC;
400d840744SZachary Turner break;
410d840744SZachary Turner #define SYMBOL_RECORD(EnumName, EnumVal, Name) \
420d840744SZachary Turner case EnumName: { \
430d840744SZachary Turner if (auto EC = visitKnownRecord<Name>(Record, Callbacks)) \
440d840744SZachary Turner return EC; \
450d840744SZachary Turner break; \
460d840744SZachary Turner }
470d840744SZachary Turner #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
480d840744SZachary Turner SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
49d427383cSZachary Turner #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
500d840744SZachary Turner }
510d840744SZachary Turner
520d840744SZachary Turner if (auto EC = Callbacks.visitSymbolEnd(Record))
530d840744SZachary Turner return EC;
540d840744SZachary Turner
550d840744SZachary Turner return Error::success();
560d840744SZachary Turner }
570d840744SZachary Turner
visitSymbolRecord(CVSymbol & Record)58af8c75a8SZachary Turner Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) {
59af8c75a8SZachary Turner if (auto EC = Callbacks.visitSymbolBegin(Record))
60af8c75a8SZachary Turner return EC;
61af8c75a8SZachary Turner return finishVisitation(Record, Callbacks);
62af8c75a8SZachary Turner }
63af8c75a8SZachary Turner
visitSymbolRecord(CVSymbol & Record,uint32_t Offset)64af8c75a8SZachary Turner Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record, uint32_t Offset) {
65af8c75a8SZachary Turner if (auto EC = Callbacks.visitSymbolBegin(Record, Offset))
66af8c75a8SZachary Turner return EC;
67af8c75a8SZachary Turner return finishVisitation(Record, Callbacks);
68af8c75a8SZachary Turner }
69af8c75a8SZachary Turner
visitSymbolStream(const CVSymbolArray & Symbols)700d840744SZachary Turner Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols) {
710d840744SZachary Turner for (auto I : Symbols) {
720d840744SZachary Turner if (auto EC = visitSymbolRecord(I))
730d840744SZachary Turner return EC;
740d840744SZachary Turner }
750d840744SZachary Turner return Error::success();
760d840744SZachary Turner }
77af8c75a8SZachary Turner
visitSymbolStream(const CVSymbolArray & Symbols,uint32_t InitialOffset)78af8c75a8SZachary Turner Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols,
79af8c75a8SZachary Turner uint32_t InitialOffset) {
80af8c75a8SZachary Turner for (auto I : Symbols) {
81579264bdSZachary Turner if (auto EC = visitSymbolRecord(I, InitialOffset + Symbols.skew()))
82af8c75a8SZachary Turner return EC;
83af8c75a8SZachary Turner InitialOffset += I.length();
84af8c75a8SZachary Turner }
85af8c75a8SZachary Turner return Error::success();
86af8c75a8SZachary Turner }
87a6487249SZequan Wu
visitSymbolStreamFiltered(const CVSymbolArray & Symbols,const FilterOptions & Filter)88a6487249SZequan Wu Error CVSymbolVisitor::visitSymbolStreamFiltered(const CVSymbolArray &Symbols,
89a6487249SZequan Wu const FilterOptions &Filter) {
90a6487249SZequan Wu if (!Filter.SymbolOffset)
91a6487249SZequan Wu return visitSymbolStream(Symbols);
92a6487249SZequan Wu uint32_t SymbolOffset = *Filter.SymbolOffset;
93*129b531cSKazu Hirata uint32_t ParentRecurseDepth = Filter.ParentRecursiveDepth.value_or(0);
94*129b531cSKazu Hirata uint32_t ChildrenRecurseDepth = Filter.ChildRecursiveDepth.value_or(0);
95a6487249SZequan Wu if (!Symbols.isOffsetValid(SymbolOffset))
96a6487249SZequan Wu return createStringError(inconvertibleErrorCode(), "Invalid symbol offset");
97a6487249SZequan Wu CVSymbol Sym = *Symbols.at(SymbolOffset);
98a6487249SZequan Wu uint32_t SymEndOffset =
99a6487249SZequan Wu symbolOpensScope(Sym.kind()) ? getScopeEndOffset(Sym) : 0;
100a6487249SZequan Wu
101a6487249SZequan Wu std::vector<uint32_t> ParentOffsets;
102a6487249SZequan Wu std::vector<uint32_t> ParentEndOffsets;
103a6487249SZequan Wu uint32_t ChildrenDepth = 0;
104a6487249SZequan Wu for (auto Begin = Symbols.begin(), End = Symbols.end(); Begin != End;
105a6487249SZequan Wu ++Begin) {
106a6487249SZequan Wu uint32_t BeginOffset = Begin.offset();
107a6487249SZequan Wu CVSymbol BeginSym = *Begin;
108a6487249SZequan Wu if (BeginOffset < SymbolOffset) {
109a6487249SZequan Wu if (symbolOpensScope(Begin->kind())) {
110a6487249SZequan Wu uint32_t EndOffset = getScopeEndOffset(BeginSym);
111a6487249SZequan Wu if (SymbolOffset < EndOffset) {
112a6487249SZequan Wu ParentOffsets.push_back(BeginOffset);
113a6487249SZequan Wu ParentEndOffsets.push_back(EndOffset);
114a6487249SZequan Wu }
115a6487249SZequan Wu }
116a6487249SZequan Wu } else if (BeginOffset == SymbolOffset) {
117a6487249SZequan Wu // Found symbol at offset. Visit its parent up to ParentRecurseDepth.
118a6487249SZequan Wu if (ParentRecurseDepth >= ParentOffsets.size())
119a6487249SZequan Wu ParentRecurseDepth = ParentOffsets.size();
120a6487249SZequan Wu uint32_t StartIndex = ParentOffsets.size() - ParentRecurseDepth;
121a6487249SZequan Wu while (StartIndex < ParentOffsets.size()) {
122a6487249SZequan Wu if (!Symbols.isOffsetValid(ParentOffsets[StartIndex]))
123a6487249SZequan Wu break;
124a6487249SZequan Wu CVSymbol Parent = *Symbols.at(ParentOffsets[StartIndex]);
125a6487249SZequan Wu if (auto EC = visitSymbolRecord(Parent, ParentOffsets[StartIndex]))
126a6487249SZequan Wu return EC;
127a6487249SZequan Wu ++StartIndex;
128a6487249SZequan Wu }
129a6487249SZequan Wu if (auto EC = visitSymbolRecord(Sym, SymbolOffset))
130a6487249SZequan Wu return EC;
131a6487249SZequan Wu } else if (BeginOffset <= SymEndOffset) {
132a6487249SZequan Wu if (ChildrenRecurseDepth) {
133a6487249SZequan Wu // Visit children.
134a6487249SZequan Wu if (symbolEndsScope(Begin->kind()))
135a6487249SZequan Wu --ChildrenDepth;
136a6487249SZequan Wu if (ChildrenDepth < ChildrenRecurseDepth ||
137a6487249SZequan Wu BeginOffset == SymEndOffset) {
138a6487249SZequan Wu if (auto EC = visitSymbolRecord(BeginSym, BeginOffset))
139a6487249SZequan Wu return EC;
140a6487249SZequan Wu }
141a6487249SZequan Wu if (symbolOpensScope(Begin->kind()))
142a6487249SZequan Wu ++ChildrenDepth;
143a6487249SZequan Wu }
144a6487249SZequan Wu } else {
145a6487249SZequan Wu // Visit parents' ends.
146a6487249SZequan Wu if (ParentRecurseDepth && BeginOffset == ParentEndOffsets.back()) {
147a6487249SZequan Wu if (auto EC = visitSymbolRecord(BeginSym, BeginOffset))
148a6487249SZequan Wu return EC;
149a6487249SZequan Wu ParentEndOffsets.pop_back();
150a6487249SZequan Wu --ParentRecurseDepth;
151a6487249SZequan Wu }
152a6487249SZequan Wu }
153a6487249SZequan Wu }
154a6487249SZequan Wu return Error::success();
155a6487249SZequan Wu }
156