brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.5 KiB · 9106c7e Raw
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