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