154 lines · cpp
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-exception6//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 16using namespace llvm;17using namespace llvm::codeview;18 19CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks)20 : Callbacks(Callbacks) {}21 22template <typename T>23static 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 32static 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 56Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) {57 if (auto EC = Callbacks.visitSymbolBegin(Record))58 return EC;59 return finishVisitation(Record, Callbacks);60}61 62Error 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 68Error 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 76Error 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 86Error 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