1//===- VariableDumper.cpp - -------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "VariableDumper.h"
11
12#include "BuiltinDumper.h"
13#include "LinePrinter.h"
14#include "llvm-pdbdump.h"
15#include "FunctionDumper.h"
16
17#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
18#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
19#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
20#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
21#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
22#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
23#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
24#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
25#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
26
27#include "llvm/Support/Format.h"
28
29using namespace llvm;
30
31VariableDumper::VariableDumper(LinePrinter &P)
32    : PDBSymDumper(true), Printer(P) {}
33
34void VariableDumper::start(const PDBSymbolData &Var) {
35  if (Var.isCompilerGenerated() && opts::ExcludeCompilerGenerated)
36    return;
37  if (Printer.IsSymbolExcluded(Var.getName()))
38    return;
39
40  auto VarType = Var.getType();
41
42  switch (auto LocType = Var.getLocationType()) {
43  case PDB_LocType::Static:
44    Printer.NewLine();
45    Printer << "data [";
46    WithColor(Printer, PDB_ColorItem::Address).get()
47        << format_hex(Var.getRelativeVirtualAddress(), 10);
48    Printer << "] ";
49    WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
50    dumpSymbolTypeAndName(*VarType, Var.getName());
51    break;
52  case PDB_LocType::Constant:
53    if (isa<PDBSymbolTypeEnum>(*VarType))
54      break;
55    Printer.NewLine();
56    Printer << "data ";
57    WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
58    dumpSymbolTypeAndName(*VarType, Var.getName());
59    Printer << " = ";
60    WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue();
61    break;
62  case PDB_LocType::ThisRel:
63    Printer.NewLine();
64    Printer << "data ";
65    WithColor(Printer, PDB_ColorItem::Offset).get()
66        << "+" << format_hex(Var.getOffset(), 4) << " ";
67    dumpSymbolTypeAndName(*VarType, Var.getName());
68    break;
69  case PDB_LocType::BitField:
70    Printer.NewLine();
71    Printer << "data ";
72    WithColor(Printer, PDB_ColorItem::Offset).get()
73        << "+" << format_hex(Var.getOffset(), 4) << " ";
74    dumpSymbolTypeAndName(*VarType, Var.getName());
75    Printer << " : ";
76    WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
77    break;
78  default:
79    Printer.NewLine();
80    Printer << "data ";
81    Printer << "unknown(" << LocType << ") ";
82    WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName();
83    break;
84  }
85}
86
87void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
88  BuiltinDumper Dumper(Printer);
89  Dumper.start(Symbol);
90}
91
92void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
93  WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
94}
95
96void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {}
97
98void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
99  auto PointeeType = Symbol.getPointeeType();
100  if (!PointeeType)
101    return;
102
103  if (auto Func = dyn_cast<PDBSymbolFunc>(PointeeType.get())) {
104    FunctionDumper NestedDumper(Printer);
105    FunctionDumper::PointerType Pointer =
106        Symbol.isReference() ? FunctionDumper::PointerType::Reference
107                             : FunctionDumper::PointerType::Pointer;
108    NestedDumper.start(*Func, Pointer);
109  } else {
110    if (Symbol.isConstType())
111      WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
112    if (Symbol.isVolatileType())
113      WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
114    PointeeType->dump(*this);
115    Printer << (Symbol.isReference() ? "&" : "*");
116  }
117}
118
119void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
120  WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
121  WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
122}
123
124void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
125  WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
126}
127
128void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
129                                           StringRef Name) {
130  if (auto *ArrayType = dyn_cast<PDBSymbolTypeArray>(&Type)) {
131    std::string IndexSpec;
132    raw_string_ostream IndexStream(IndexSpec);
133    std::unique_ptr<PDBSymbol> ElementType = ArrayType->getElementType();
134    while (auto NestedArray = dyn_cast<PDBSymbolTypeArray>(ElementType.get())) {
135      IndexStream << "[";
136      IndexStream << NestedArray->getCount();
137      IndexStream << "]";
138      ElementType = NestedArray->getElementType();
139    }
140    IndexStream << "[" << ArrayType->getCount() << "]";
141    ElementType->dump(*this);
142    WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
143    Printer << IndexStream.str();
144  } else {
145    if (!tryDumpFunctionPointer(Type, Name)) {
146      Type.dump(*this);
147      WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
148    }
149  }
150}
151
152bool VariableDumper::tryDumpFunctionPointer(const PDBSymbol &Type,
153                                            StringRef Name) {
154  // Function pointers come across as pointers to function signatures.  But the
155  // signature carries no name, so we have to handle this case separately.
156  if (auto *PointerType = dyn_cast<PDBSymbolTypePointer>(&Type)) {
157    auto PointeeType = PointerType->getPointeeType();
158    if (auto *FunctionSig =
159            dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
160      FunctionDumper Dumper(Printer);
161      FunctionDumper::PointerType PT = FunctionDumper::PointerType::Pointer;
162      if (PointerType->isReference())
163        PT = FunctionDumper::PointerType::Reference;
164      std::string NameStr(Name.begin(), Name.end());
165      Dumper.start(*FunctionSig, NameStr.c_str(), PT);
166      return true;
167    }
168  }
169  return false;
170}
171