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/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"
19 using namespace llvm::codeview
;
21 CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks
&Callbacks
)
22 : Callbacks(Callbacks
) {}
25 static Error
visitKnownRecord(CVSymbol
&Record
,
26 SymbolVisitorCallbacks
&Callbacks
) {
27 SymbolRecordKind RK
= static_cast<SymbolRecordKind
>(Record
.kind());
29 if (auto EC
= Callbacks
.visitKnownRecord(Record
, KnownRecord
))
31 return Error::success();
34 static Error
finishVisitation(CVSymbol
&Record
,
35 SymbolVisitorCallbacks
&Callbacks
) {
36 switch (Record
.kind()) {
38 if (auto EC
= Callbacks
.visitUnknownSymbol(Record
))
41 #define SYMBOL_RECORD(EnumName, EnumVal, Name) \
43 if (auto EC = visitKnownRecord<Name>(Record, Callbacks)) \
47 #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
48 SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
49 #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
52 if (auto EC
= Callbacks
.visitSymbolEnd(Record
))
55 return Error::success();
58 Error
CVSymbolVisitor::visitSymbolRecord(CVSymbol
&Record
) {
59 if (auto EC
= Callbacks
.visitSymbolBegin(Record
))
61 return finishVisitation(Record
, Callbacks
);
64 Error
CVSymbolVisitor::visitSymbolRecord(CVSymbol
&Record
, uint32_t Offset
) {
65 if (auto EC
= Callbacks
.visitSymbolBegin(Record
, Offset
))
67 return finishVisitation(Record
, Callbacks
);
70 Error
CVSymbolVisitor::visitSymbolStream(const CVSymbolArray
&Symbols
) {
71 for (auto I
: Symbols
) {
72 if (auto EC
= visitSymbolRecord(I
))
75 return Error::success();
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()))
83 InitialOffset
+= I
.length();
85 return Error::success();
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;
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
;
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
);
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
]))
124 CVSymbol Parent
= *Symbols
.at(ParentOffsets
[StartIndex
]);
125 if (auto EC
= visitSymbolRecord(Parent
, ParentOffsets
[StartIndex
]))
129 if (auto EC
= visitSymbolRecord(Sym
, SymbolOffset
))
131 } else if (BeginOffset
<= SymEndOffset
) {
132 if (ChildrenRecurseDepth
) {
134 if (symbolEndsScope(Begin
->kind()))
136 if (ChildrenDepth
< ChildrenRecurseDepth
||
137 BeginOffset
== SymEndOffset
) {
138 if (auto EC
= visitSymbolRecord(BeginSym
, BeginOffset
))
141 if (symbolOpensScope(Begin
->kind()))
145 // Visit parents' ends.
146 if (ParentRecurseDepth
&& BeginOffset
== ParentEndOffsets
.back()) {
147 if (auto EC
= visitSymbolRecord(BeginSym
, BeginOffset
))
149 ParentEndOffsets
.pop_back();
150 --ParentRecurseDepth
;
154 return Error::success();