1 //===- PrettyFunctionDumper.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 "PrettyFunctionDumper.h"
10 #include "LinePrinter.h"
11 #include "PrettyBuiltinDumper.h"
13 #include "llvm/DebugInfo/PDB/IPDBSession.h"
14 #include "llvm/DebugInfo/PDB/PDBExtras.h"
15 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
16 #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
17 #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
18 #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
19 #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
20 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
24 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
25 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
26 #include "llvm/Support/Format.h"
27 #include "llvm/Support/FormatVariadic.h"
30 using namespace llvm::codeview
;
31 using namespace llvm::pdb
;
35 void dumpClassParentWithScopeOperator(const T
&Symbol
, LinePrinter
&Printer
,
36 FunctionDumper
&Dumper
) {
37 uint32_t ClassParentId
= Symbol
.getClassParentId();
39 Symbol
.getSession().template getConcreteSymbolById
<PDBSymbolTypeUDT
>(
44 WithColor(Printer
, PDB_ColorItem::Type
).get() << ClassParent
->getName();
49 FunctionDumper::FunctionDumper(LinePrinter
&P
)
50 : PDBSymDumper(true), Printer(P
) {}
52 void FunctionDumper::start(const PDBSymbolTypeFunctionSig
&Symbol
,
53 const char *Name
, PointerType Pointer
) {
54 auto ReturnType
= Symbol
.getReturnType();
56 Printer
<< "<unknown-type>";
58 ReturnType
->dump(*this);
60 uint32_t ClassParentId
= Symbol
.getClassParentId();
62 Symbol
.getSession().getConcreteSymbolById
<PDBSymbolTypeUDT
>(
65 PDB_CallingConv CC
= Symbol
.getCallingConvention();
66 bool ShouldDumpCallingConvention
= true;
67 if ((ClassParent
&& CC
== CallingConvention::ThisCall
) ||
68 (!ClassParent
&& CC
== CallingConvention::NearStdCall
)) {
69 ShouldDumpCallingConvention
= false;
72 if (Pointer
== PointerType::None
) {
73 if (ShouldDumpCallingConvention
)
74 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << CC
<< " ";
77 WithColor(Printer
, PDB_ColorItem::Identifier
).get()
78 << ClassParent
->getName();
83 if (ShouldDumpCallingConvention
)
84 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << CC
<< " ";
86 WithColor(Printer
, PDB_ColorItem::Identifier
).get()
87 << ClassParent
->getName();
90 if (Pointer
== PointerType::Reference
)
95 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << Name
;
100 if (auto ChildEnum
= Symbol
.getArguments()) {
102 while (auto Arg
= ChildEnum
->getNext()) {
104 if (++Index
< ChildEnum
->getChildCount())
110 if (Symbol
.isConstType())
111 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << " const";
112 if (Symbol
.isVolatileType())
113 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << " volatile";
116 void FunctionDumper::start(const PDBSymbolFunc
&Symbol
, PointerType Pointer
) {
117 uint64_t FuncStart
= Symbol
.getVirtualAddress();
118 uint64_t FuncEnd
= FuncStart
+ Symbol
.getLength();
121 WithColor(Printer
, PDB_ColorItem::Address
).get() << format_hex(FuncStart
, 10);
122 if (auto DebugStart
= Symbol
.findOneChild
<PDBSymbolFuncDebugStart
>()) {
123 uint64_t Prologue
= DebugStart
->getVirtualAddress() - FuncStart
;
124 WithColor(Printer
, PDB_ColorItem::Offset
).get()
125 << formatv("+{0,2}", Prologue
);
128 WithColor(Printer
, PDB_ColorItem::Address
).get() << format_hex(FuncEnd
, 10);
129 if (auto DebugEnd
= Symbol
.findOneChild
<PDBSymbolFuncDebugEnd
>()) {
130 uint64_t Epilogue
= FuncEnd
- DebugEnd
->getVirtualAddress();
131 WithColor(Printer
, PDB_ColorItem::Offset
).get()
132 << formatv("-{0,2}", Epilogue
);
135 WithColor(Printer
, PDB_ColorItem::Comment
).get()
136 << formatv(" | sizeof={0,3}", Symbol
.getLength());
139 if (Symbol
.hasFramePointer()) {
140 WithColor(Printer
, PDB_ColorItem::Register
).get()
141 << CPURegister
{Symbol
.getRawSymbol().getPlatform(),
142 Symbol
.getLocalBasePointerRegisterId()};
144 WithColor(Printer
, PDB_ColorItem::Register
).get() << "FPO";
148 if (Symbol
.isVirtual() || Symbol
.isPureVirtual())
149 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << "virtual ";
151 auto Signature
= Symbol
.getSignature();
153 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << Symbol
.getName();
154 if (Pointer
== PointerType::Pointer
)
156 else if (Pointer
== FunctionDumper::PointerType::Reference
)
161 auto ReturnType
= Signature
->getReturnType();
162 ReturnType
->dump(*this);
165 auto ClassParent
= Symbol
.getClassParent();
166 CallingConvention CC
= Signature
->getCallingConvention();
167 if (Pointer
!= FunctionDumper::PointerType::None
)
170 if ((ClassParent
&& CC
!= CallingConvention::ThisCall
) ||
171 (!ClassParent
&& CC
!= CallingConvention::NearStdCall
)) {
172 WithColor(Printer
, PDB_ColorItem::Keyword
).get()
173 << Signature
->getCallingConvention() << " ";
175 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << Symbol
.getName();
176 if (Pointer
!= FunctionDumper::PointerType::None
) {
177 if (Pointer
== PointerType::Pointer
)
179 else if (Pointer
== FunctionDumper::PointerType::Reference
)
185 if (auto Arguments
= Symbol
.getArguments()) {
187 while (auto Arg
= Arguments
->getNext()) {
188 auto ArgType
= Arg
->getType();
189 ArgType
->dump(*this);
190 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << " "
192 if (++Index
< Arguments
->getChildCount())
195 if (Signature
->isCVarArgs())
199 if (Symbol
.isConstType())
200 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << " const";
201 if (Symbol
.isVolatileType())
202 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << " volatile";
203 if (Symbol
.isPureVirtual())
207 void FunctionDumper::dump(const PDBSymbolTypeArray
&Symbol
) {
208 auto ElementType
= Symbol
.getElementType();
210 ElementType
->dump(*this);
212 WithColor(Printer
, PDB_ColorItem::LiteralValue
).get() << Symbol
.getLength();
216 void FunctionDumper::dump(const PDBSymbolTypeBuiltin
&Symbol
) {
217 BuiltinDumper
Dumper(Printer
);
218 Dumper
.start(Symbol
);
221 void FunctionDumper::dump(const PDBSymbolTypeEnum
&Symbol
) {
222 dumpClassParentWithScopeOperator(Symbol
, Printer
, *this);
223 WithColor(Printer
, PDB_ColorItem::Type
).get() << Symbol
.getName();
226 void FunctionDumper::dump(const PDBSymbolTypeFunctionArg
&Symbol
) {
227 // PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill
228 // through to the real thing and dump it.
229 uint32_t TypeId
= Symbol
.getTypeId();
230 auto Type
= Symbol
.getSession().getSymbolById(TypeId
);
234 Printer
<< "<unknown-type>";
237 void FunctionDumper::dump(const PDBSymbolTypeTypedef
&Symbol
) {
238 dumpClassParentWithScopeOperator(Symbol
, Printer
, *this);
239 WithColor(Printer
, PDB_ColorItem::Type
).get() << Symbol
.getName();
242 void FunctionDumper::dump(const PDBSymbolTypePointer
&Symbol
) {
243 auto PointeeType
= Symbol
.getPointeeType();
247 if (auto FuncSig
= unique_dyn_cast
<PDBSymbolTypeFunctionSig
>(PointeeType
)) {
248 FunctionDumper
NestedDumper(Printer
);
249 PointerType Pointer
=
250 Symbol
.isReference() ? PointerType::Reference
: PointerType::Pointer
;
251 NestedDumper
.start(*FuncSig
, nullptr, Pointer
);
253 if (Symbol
.isConstType())
254 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << "const ";
255 if (Symbol
.isVolatileType())
256 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << "volatile ";
257 PointeeType
->dump(*this);
258 Printer
<< (Symbol
.isReference() ? "&" : "*");
260 if (Symbol
.getRawSymbol().isRestrictedType())
261 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << " __restrict";
265 void FunctionDumper::dump(const PDBSymbolTypeUDT
&Symbol
) {
266 WithColor(Printer
, PDB_ColorItem::Type
).get() << Symbol
.getName();