1//===- PrettyFunctionDumper.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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "PrettyFunctionDumper.h"
10#include "PrettyBuiltinDumper.h"
11
12#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
13#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
14#include "llvm/DebugInfo/PDB/IPDBSession.h"
15#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
16#include "llvm/DebugInfo/PDB/PDBExtras.h"
17#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
18#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
19#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
20#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
21#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
22#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
23#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
24#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
25#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
26#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
27#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
28#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
29#include "llvm/Support/Format.h"
30#include "llvm/Support/FormatVariadic.h"
31
32using namespace llvm;
33using namespace llvm::codeview;
34using namespace llvm::pdb;
35
36namespace {
37template <class T>
38void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer,
39                                      FunctionDumper &Dumper) {
40  uint32_t ClassParentId = Symbol.getClassParentId();
41  auto ClassParent =
42      Symbol.getSession().template getConcreteSymbolById<PDBSymbolTypeUDT>(
43          ClassParentId);
44  if (!ClassParent)
45    return;
46
47  WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName();
48  Printer << "::";
49}
50}
51
52FunctionDumper::FunctionDumper(LinePrinter &P)
53    : PDBSymDumper(true), Printer(P) {}
54
55void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol,
56                           const char *Name, PointerType Pointer) {
57  auto ReturnType = Symbol.getReturnType();
58  if (!ReturnType)
59    Printer << "<unknown-type>";
60  else
61    ReturnType->dump(*this);
62  Printer << " ";
63  uint32_t ClassParentId = Symbol.getClassParentId();
64  auto ClassParent =
65      Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
66          ClassParentId);
67
68  PDB_CallingConv CC = Symbol.getCallingConvention();
69  bool ShouldDumpCallingConvention = true;
70  if ((ClassParent && CC == CallingConvention::ThisCall) ||
71      (!ClassParent && CC == CallingConvention::NearStdCall)) {
72    ShouldDumpCallingConvention = false;
73  }
74
75  if (Pointer == PointerType::None) {
76    if (ShouldDumpCallingConvention)
77      WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
78    if (ClassParent) {
79      Printer << "(";
80      WithColor(Printer, PDB_ColorItem::Identifier).get()
81          << ClassParent->getName();
82      Printer << "::)";
83    }
84  } else {
85    Printer << "(";
86    if (ShouldDumpCallingConvention)
87      WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
88    if (ClassParent) {
89      WithColor(Printer, PDB_ColorItem::Identifier).get()
90          << ClassParent->getName();
91      Printer << "::";
92    }
93    if (Pointer == PointerType::Reference)
94      Printer << "&";
95    else
96      Printer << "*";
97    if (Name)
98      WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
99    Printer << ")";
100  }
101
102  Printer << "(";
103  if (auto ChildEnum = Symbol.getArguments()) {
104    uint32_t Index = 0;
105    while (auto Arg = ChildEnum->getNext()) {
106      Arg->dump(*this);
107      if (++Index < ChildEnum->getChildCount())
108        Printer << ", ";
109    }
110  }
111  Printer << ")";
112
113  if (Symbol.isConstType())
114    WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
115  if (Symbol.isVolatileType())
116    WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
117}
118
119void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
120  uint64_t FuncStart = Symbol.getVirtualAddress();
121  uint64_t FuncEnd = FuncStart + Symbol.getLength();
122
123  Printer << "func [";
124  WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10);
125  if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) {
126    uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart;
127    WithColor(Printer, PDB_ColorItem::Offset).get()
128        << formatv("+{0,2}", Prologue);
129  }
130  Printer << " - ";
131  WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10);
132  if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) {
133    uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress();
134    WithColor(Printer, PDB_ColorItem::Offset).get()
135        << formatv("-{0,2}", Epilogue);
136  }
137
138  WithColor(Printer, PDB_ColorItem::Comment).get()
139      << formatv(" | sizeof={0,3}", Symbol.getLength());
140  Printer << "] (";
141
142  if (Symbol.hasFramePointer()) {
143    WithColor(Printer, PDB_ColorItem::Register).get()
144        << CPURegister{Symbol.getRawSymbol().getPlatform(),
145                       Symbol.getLocalBasePointerRegisterId()};
146  } else {
147    WithColor(Printer, PDB_ColorItem::Register).get() << "FPO";
148  }
149  Printer << ") ";
150
151  if (Symbol.isVirtual() || Symbol.isPureVirtual())
152    WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual ";
153
154  auto Signature = Symbol.getSignature();
155  if (!Signature) {
156    WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
157    if (Pointer == PointerType::Pointer)
158      Printer << "*";
159    else if (Pointer == FunctionDumper::PointerType::Reference)
160      Printer << "&";
161    return;
162  }
163
164  auto ReturnType = Signature->getReturnType();
165  ReturnType->dump(*this);
166  Printer << " ";
167
168  auto ClassParent = Symbol.getClassParent();
169  CallingConvention CC = Signature->getCallingConvention();
170  if (Pointer != FunctionDumper::PointerType::None)
171    Printer << "(";
172
173  if ((ClassParent && CC != CallingConvention::ThisCall) ||
174      (!ClassParent && CC != CallingConvention::NearStdCall)) {
175    WithColor(Printer, PDB_ColorItem::Keyword).get()
176        << Signature->getCallingConvention() << " ";
177  }
178  WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
179  if (Pointer != FunctionDumper::PointerType::None) {
180    if (Pointer == PointerType::Pointer)
181      Printer << "*";
182    else if (Pointer == FunctionDumper::PointerType::Reference)
183      Printer << "&";
184    Printer << ")";
185  }
186
187  Printer << "(";
188  if (auto Arguments = Symbol.getArguments()) {
189    uint32_t Index = 0;
190    while (auto Arg = Arguments->getNext()) {
191      auto ArgType = Arg->getType();
192      ArgType->dump(*this);
193      WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
194                                                          << Arg->getName();
195      if (++Index < Arguments->getChildCount())
196        Printer << ", ";
197    }
198    if (Signature->isCVarArgs())
199      Printer << ", ...";
200  }
201  Printer << ")";
202  if (Symbol.isConstType())
203    WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
204  if (Symbol.isVolatileType())
205    WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
206  if (Symbol.isPureVirtual())
207    Printer << " = 0";
208}
209
210void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) {
211  auto ElementType = Symbol.getElementType();
212
213  ElementType->dump(*this);
214  Printer << "[";
215  WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength();
216  Printer << "]";
217}
218
219void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
220  BuiltinDumper Dumper(Printer);
221  Dumper.start(Symbol);
222}
223
224void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
225  dumpClassParentWithScopeOperator(Symbol, Printer, *this);
226  WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
227}
228
229void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
230  // PDBSymbolTypeFunctionArg is just a shim over the real argument.  Just drill
231  // through to the real thing and dump it.
232  uint32_t TypeId = Symbol.getTypeId();
233  auto Type = Symbol.getSession().getSymbolById(TypeId);
234  if (Type)
235    Type->dump(*this);
236  else
237    Printer << "<unknown-type>";
238}
239
240void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
241  dumpClassParentWithScopeOperator(Symbol, Printer, *this);
242  WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
243}
244
245void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) {
246  auto PointeeType = Symbol.getPointeeType();
247  if (!PointeeType)
248    return;
249
250  if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
251    FunctionDumper NestedDumper(Printer);
252    PointerType Pointer =
253        Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
254    NestedDumper.start(*FuncSig, nullptr, Pointer);
255  } else {
256    if (Symbol.isConstType())
257      WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
258    if (Symbol.isVolatileType())
259      WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
260    PointeeType->dump(*this);
261    Printer << (Symbol.isReference() ? "&" : "*");
262
263    if (Symbol.getRawSymbol().isRestrictedType())
264      WithColor(Printer, PDB_ColorItem::Keyword).get() << " __restrict";
265  }
266}
267
268void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) {
269  WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
270}
271