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