1 //===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
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"
17 using namespace llvm::codeview
;
19 CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks
&Callbacks
)
20 : Callbacks(Callbacks
) {}
23 static Error
visitKnownRecord(CVSymbol
&Record
,
24 SymbolVisitorCallbacks
&Callbacks
) {
25 SymbolRecordKind RK
= static_cast<SymbolRecordKind
>(Record
.kind());
27 if (auto EC
= Callbacks
.visitKnownRecord(Record
, KnownRecord
))
29 return Error::success();
32 static Error
finishVisitation(CVSymbol
&Record
,
33 SymbolVisitorCallbacks
&Callbacks
) {
34 switch (Record
.kind()) {
36 if (auto EC
= Callbacks
.visitUnknownSymbol(Record
))
39 #define SYMBOL_RECORD(EnumName, EnumVal, Name) \
41 if (auto EC = visitKnownRecord<Name>(Record, Callbacks)) \
45 #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
46 SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
47 #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
50 if (auto EC
= Callbacks
.visitSymbolEnd(Record
))
53 return Error::success();
56 Error
CVSymbolVisitor::visitSymbolRecord(CVSymbol
&Record
) {
57 if (auto EC
= Callbacks
.visitSymbolBegin(Record
))
59 return finishVisitation(Record
, Callbacks
);
62 Error
CVSymbolVisitor::visitSymbolRecord(CVSymbol
&Record
, uint32_t Offset
) {
63 if (auto EC
= Callbacks
.visitSymbolBegin(Record
, Offset
))
65 return finishVisitation(Record
, Callbacks
);
68 Error
CVSymbolVisitor::visitSymbolStream(const CVSymbolArray
&Symbols
) {
69 for (auto I
: Symbols
) {
70 if (auto EC
= visitSymbolRecord(I
))
73 return Error::success();
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()))
81 InitialOffset
+= I
.length();
83 return Error::success();
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;
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
;
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
);
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
]))
122 CVSymbol Parent
= *Symbols
.at(ParentOffsets
[StartIndex
]);
123 if (auto EC
= visitSymbolRecord(Parent
, ParentOffsets
[StartIndex
]))
127 if (auto EC
= visitSymbolRecord(Sym
, SymbolOffset
))
129 } else if (BeginOffset
<= SymEndOffset
) {
130 if (ChildrenRecurseDepth
) {
132 if (symbolEndsScope(Begin
->kind()))
134 if (ChildrenDepth
< ChildrenRecurseDepth
||
135 BeginOffset
== SymEndOffset
) {
136 if (auto EC
= visitSymbolRecord(BeginSym
, BeginOffset
))
139 if (symbolOpensScope(Begin
->kind()))
143 // Visit parents' ends.
144 if (ParentRecurseDepth
&& BeginOffset
== ParentEndOffsets
.back()) {
145 if (auto EC
= visitSymbolRecord(BeginSym
, BeginOffset
))
147 ParentEndOffsets
.pop_back();
148 --ParentRecurseDepth
;
152 return Error::success();