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 = 94 Filter.ParentRecursiveDepth ? *Filter.ParentRecursiveDepth : 0; 95 uint32_t ChildrenRecurseDepth = 96 Filter.ChildRecursiveDepth ? *Filter.ChildRecursiveDepth : 0; 97 if (!Symbols.isOffsetValid(SymbolOffset)) 98 return createStringError(inconvertibleErrorCode(), "Invalid symbol offset"); 99 CVSymbol Sym = *Symbols.at(SymbolOffset); 100 uint32_t SymEndOffset = 101 symbolOpensScope(Sym.kind()) ? getScopeEndOffset(Sym) : 0; 102 103 std::vector<uint32_t> ParentOffsets; 104 std::vector<uint32_t> ParentEndOffsets; 105 uint32_t ChildrenDepth = 0; 106 for (auto Begin = Symbols.begin(), End = Symbols.end(); Begin != End; 107 ++Begin) { 108 uint32_t BeginOffset = Begin.offset(); 109 CVSymbol BeginSym = *Begin; 110 if (BeginOffset < SymbolOffset) { 111 if (symbolOpensScope(Begin->kind())) { 112 uint32_t EndOffset = getScopeEndOffset(BeginSym); 113 if (SymbolOffset < EndOffset) { 114 ParentOffsets.push_back(BeginOffset); 115 ParentEndOffsets.push_back(EndOffset); 116 } 117 } 118 } else if (BeginOffset == SymbolOffset) { 119 // Found symbol at offset. Visit its parent up to ParentRecurseDepth. 120 if (ParentRecurseDepth >= ParentOffsets.size()) 121 ParentRecurseDepth = ParentOffsets.size(); 122 uint32_t StartIndex = ParentOffsets.size() - ParentRecurseDepth; 123 while (StartIndex < ParentOffsets.size()) { 124 if (!Symbols.isOffsetValid(ParentOffsets[StartIndex])) 125 break; 126 CVSymbol Parent = *Symbols.at(ParentOffsets[StartIndex]); 127 if (auto EC = visitSymbolRecord(Parent, ParentOffsets[StartIndex])) 128 return EC; 129 ++StartIndex; 130 } 131 if (auto EC = visitSymbolRecord(Sym, SymbolOffset)) 132 return EC; 133 } else if (BeginOffset <= SymEndOffset) { 134 if (ChildrenRecurseDepth) { 135 // Visit children. 136 if (symbolEndsScope(Begin->kind())) 137 --ChildrenDepth; 138 if (ChildrenDepth < ChildrenRecurseDepth || 139 BeginOffset == SymEndOffset) { 140 if (auto EC = visitSymbolRecord(BeginSym, BeginOffset)) 141 return EC; 142 } 143 if (symbolOpensScope(Begin->kind())) 144 ++ChildrenDepth; 145 } 146 } else { 147 // Visit parents' ends. 148 if (ParentRecurseDepth && BeginOffset == ParentEndOffsets.back()) { 149 if (auto EC = visitSymbolRecord(BeginSym, BeginOffset)) 150 return EC; 151 ParentEndOffsets.pop_back(); 152 --ParentRecurseDepth; 153 } 154 } 155 } 156 return Error::success(); 157 } 158