1 //===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" 10 11 #include "llvm/DebugInfo/CodeView/CodeView.h" 12 #include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" 13 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" 14 #include "llvm/Support/BinaryStreamArray.h" 15 16 using namespace llvm; 17 using namespace llvm::codeview; 18 19 CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks) 20 : Callbacks(Callbacks) {} 21 22 template <typename T> 23 static Error visitKnownRecord(CVSymbol &Record, 24 SymbolVisitorCallbacks &Callbacks) { 25 SymbolRecordKind RK = static_cast<SymbolRecordKind>(Record.kind()); 26 T KnownRecord(RK); 27 if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) 28 return EC; 29 return Error::success(); 30 } 31 32 static Error finishVisitation(CVSymbol &Record, 33 SymbolVisitorCallbacks &Callbacks) { 34 switch (Record.kind()) { 35 default: 36 if (auto EC = Callbacks.visitUnknownSymbol(Record)) 37 return EC; 38 break; 39 #define SYMBOL_RECORD(EnumName, EnumVal, Name) \ 40 case EnumName: { \ 41 if (auto EC = visitKnownRecord<Name>(Record, Callbacks)) \ 42 return EC; \ 43 break; \ 44 } 45 #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ 46 SYMBOL_RECORD(EnumVal, EnumVal, AliasName) 47 #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" 48 } 49 50 if (auto EC = Callbacks.visitSymbolEnd(Record)) 51 return EC; 52 53 return Error::success(); 54 } 55 56 Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) { 57 if (auto EC = Callbacks.visitSymbolBegin(Record)) 58 return EC; 59 return finishVisitation(Record, Callbacks); 60 } 61 62 Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record, uint32_t Offset) { 63 if (auto EC = Callbacks.visitSymbolBegin(Record, Offset)) 64 return EC; 65 return finishVisitation(Record, Callbacks); 66 } 67 68 Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols) { 69 for (auto I : Symbols) { 70 if (auto EC = visitSymbolRecord(I)) 71 return EC; 72 } 73 return Error::success(); 74 } 75 76 Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols, 77 uint32_t InitialOffset) { 78 for (auto I : Symbols) { 79 if (auto EC = visitSymbolRecord(I, InitialOffset + Symbols.skew())) 80 return EC; 81 InitialOffset += I.length(); 82 } 83 return Error::success(); 84 } 85 86 Error CVSymbolVisitor::visitSymbolStreamFiltered(const CVSymbolArray &Symbols, 87 const FilterOptions &Filter) { 88 if (!Filter.SymbolOffset) 89 return visitSymbolStream(Symbols); 90 uint32_t SymbolOffset = *Filter.SymbolOffset; 91 uint32_t ParentRecurseDepth = Filter.ParentRecursiveDepth.value_or(0); 92 uint32_t ChildrenRecurseDepth = Filter.ChildRecursiveDepth.value_or(0); 93 if (!Symbols.isOffsetValid(SymbolOffset)) 94 return createStringError(inconvertibleErrorCode(), "Invalid symbol offset"); 95 CVSymbol Sym = *Symbols.at(SymbolOffset); 96 uint32_t SymEndOffset = 97 symbolOpensScope(Sym.kind()) ? getScopeEndOffset(Sym) : 0; 98 99 std::vector<uint32_t> ParentOffsets; 100 std::vector<uint32_t> ParentEndOffsets; 101 uint32_t ChildrenDepth = 0; 102 for (auto Begin = Symbols.begin(), End = Symbols.end(); Begin != End; 103 ++Begin) { 104 uint32_t BeginOffset = Begin.offset(); 105 CVSymbol BeginSym = *Begin; 106 if (BeginOffset < SymbolOffset) { 107 if (symbolOpensScope(Begin->kind())) { 108 uint32_t EndOffset = getScopeEndOffset(BeginSym); 109 if (SymbolOffset < EndOffset) { 110 ParentOffsets.push_back(BeginOffset); 111 ParentEndOffsets.push_back(EndOffset); 112 } 113 } 114 } else if (BeginOffset == SymbolOffset) { 115 // Found symbol at offset. Visit its parent up to ParentRecurseDepth. 116 if (ParentRecurseDepth >= ParentOffsets.size()) 117 ParentRecurseDepth = ParentOffsets.size(); 118 uint32_t StartIndex = ParentOffsets.size() - ParentRecurseDepth; 119 while (StartIndex < ParentOffsets.size()) { 120 if (!Symbols.isOffsetValid(ParentOffsets[StartIndex])) 121 break; 122 CVSymbol Parent = *Symbols.at(ParentOffsets[StartIndex]); 123 if (auto EC = visitSymbolRecord(Parent, ParentOffsets[StartIndex])) 124 return EC; 125 ++StartIndex; 126 } 127 if (auto EC = visitSymbolRecord(Sym, SymbolOffset)) 128 return EC; 129 } else if (BeginOffset <= SymEndOffset) { 130 if (ChildrenRecurseDepth) { 131 // Visit children. 132 if (symbolEndsScope(Begin->kind())) 133 --ChildrenDepth; 134 if (ChildrenDepth < ChildrenRecurseDepth || 135 BeginOffset == SymEndOffset) { 136 if (auto EC = visitSymbolRecord(BeginSym, BeginOffset)) 137 return EC; 138 } 139 if (symbolOpensScope(Begin->kind())) 140 ++ChildrenDepth; 141 } 142 } else { 143 // Visit parents' ends. 144 if (ParentRecurseDepth && BeginOffset == ParentEndOffsets.back()) { 145 if (auto EC = visitSymbolRecord(BeginSym, BeginOffset)) 146 return EC; 147 ParentEndOffsets.pop_back(); 148 --ParentRecurseDepth; 149 } 150 } 151 } 152 return Error::success(); 153 } 154