1//===- llvm-pdbdump.cpp - Dump debug info from a PDB file -------*- 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// Dumps debug information present in PDB files.  This utility makes use of
11// the Microsoft Windows SDK, so will not compile or run on non-Windows
12// platforms.
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm-pdbdump.h"
17#include "CompilandDumper.h"
18#include "FunctionDumper.h"
19#include "LinePrinter.h"
20#include "TypeDumper.h"
21#include "VariableDumper.h"
22
23#include "llvm/ADT/ArrayRef.h"
24#include "llvm/ADT/StringExtras.h"
25#include "llvm/Config/config.h"
26#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
27#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
28#include "llvm/DebugInfo/PDB/IPDBSession.h"
29#include "llvm/DebugInfo/PDB/PDB.h"
30#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
31#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
32#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
33#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
34#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
35#include "llvm/Support/CommandLine.h"
36#include "llvm/Support/ConvertUTF.h"
37#include "llvm/Support/FileSystem.h"
38#include "llvm/Support/Format.h"
39#include "llvm/Support/ManagedStatic.h"
40#include "llvm/Support/PrettyStackTrace.h"
41#include "llvm/Support/Process.h"
42#include "llvm/Support/raw_ostream.h"
43#include "llvm/Support/Signals.h"
44
45#if defined(HAVE_DIA_SDK)
46#include <Windows.h>
47#endif
48
49using namespace llvm;
50
51namespace opts {
52
53enum class PDB_DumpType { ByType, ByObjFile, Both };
54
55cl::list<std::string> InputFilenames(cl::Positional,
56                                     cl::desc("<input PDB files>"),
57                                     cl::OneOrMore);
58
59cl::OptionCategory TypeCategory("Symbol Type Options");
60cl::OptionCategory FilterCategory("Filtering Options");
61
62cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
63                         cl::cat(TypeCategory));
64cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"),
65                      cl::cat(TypeCategory));
66cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
67                      cl::cat(TypeCategory));
68cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory));
69cl::opt<bool>
70    All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
71        cl::cat(TypeCategory));
72
73cl::list<std::string>
74    ExcludeTypes("exclude-types",
75                 cl::desc("Exclude types by regular expression"),
76                 cl::ZeroOrMore, cl::cat(FilterCategory));
77cl::list<std::string>
78    ExcludeSymbols("exclude-symbols",
79                   cl::desc("Exclude symbols by regular expression"),
80                   cl::ZeroOrMore, cl::cat(FilterCategory));
81cl::list<std::string>
82    ExcludeCompilands("exclude-compilands",
83                      cl::desc("Exclude compilands by regular expression"),
84                      cl::ZeroOrMore, cl::cat(FilterCategory));
85cl::opt<bool> ExcludeCompilerGenerated(
86    "no-compiler-generated",
87    cl::desc("Don't show compiler generated types and symbols"),
88    cl::cat(FilterCategory));
89cl::opt<bool>
90    ExcludeSystemLibraries("no-system-libs",
91                           cl::desc("Don't show symbols from system libraries"),
92                           cl::cat(FilterCategory));
93cl::opt<bool> NoClassDefs("no-class-definitions",
94                          cl::desc("Don't display full class definitions"),
95                          cl::cat(FilterCategory));
96cl::opt<bool> NoEnumDefs("no-enum-definitions",
97                         cl::desc("Don't display full enum definitions"),
98                         cl::cat(FilterCategory));
99}
100
101static void dumpInput(StringRef Path) {
102  std::unique_ptr<IPDBSession> Session;
103  PDB_ErrorCode Error =
104      llvm::createPDBReader(PDB_ReaderType::DIA, Path, Session);
105  switch (Error) {
106  case PDB_ErrorCode::Success:
107    break;
108  case PDB_ErrorCode::NoPdbImpl:
109    outs() << "Reading PDBs is not supported on this platform.\n";
110    return;
111  case PDB_ErrorCode::InvalidPath:
112    outs() << "Unable to load PDB at '" << Path
113           << "'.  Check that the file exists and is readable.\n";
114    return;
115  case PDB_ErrorCode::InvalidFileFormat:
116    outs() << "Unable to load PDB at '" << Path
117           << "'.  The file has an unrecognized format.\n";
118    return;
119  default:
120    outs() << "Unable to load PDB at '" << Path
121           << "'.  An unknown error occured.\n";
122    return;
123  }
124
125  LinePrinter Printer(2, outs());
126
127  auto GlobalScope(Session->getGlobalScope());
128  std::string FileName(GlobalScope->getSymbolsFileName());
129
130  WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
131  WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
132  Printer.Indent();
133  uint64_t FileSize = 0;
134
135  Printer.NewLine();
136  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
137  if (!llvm::sys::fs::file_size(FileName, FileSize)) {
138    Printer << ": " << FileSize << " bytes";
139  } else {
140    Printer << ": (Unable to obtain file size)";
141  }
142
143  Printer.NewLine();
144  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
145  Printer << ": " << GlobalScope->getGuid();
146
147  Printer.NewLine();
148  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
149  Printer << ": " << GlobalScope->getAge();
150
151  Printer.NewLine();
152  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
153  Printer << ": ";
154  if (GlobalScope->hasCTypes())
155    outs() << "HasCTypes ";
156  if (GlobalScope->hasPrivateSymbols())
157    outs() << "HasPrivateSymbols ";
158  Printer.Unindent();
159
160  if (opts::Compilands) {
161    Printer.NewLine();
162    WithColor(Printer, PDB_ColorItem::SectionHeader).get()
163        << "---COMPILANDS---";
164    Printer.Indent();
165    auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
166    CompilandDumper Dumper(Printer);
167    while (auto Compiland = Compilands->getNext())
168      Dumper.start(*Compiland, false);
169    Printer.Unindent();
170  }
171
172  if (opts::Types) {
173    Printer.NewLine();
174    WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
175    Printer.Indent();
176    TypeDumper Dumper(Printer);
177    Dumper.start(*GlobalScope);
178    Printer.Unindent();
179  }
180
181  if (opts::Symbols) {
182    Printer.NewLine();
183    WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
184    Printer.Indent();
185    auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
186    CompilandDumper Dumper(Printer);
187    while (auto Compiland = Compilands->getNext())
188      Dumper.start(*Compiland, true);
189    Printer.Unindent();
190  }
191
192  if (opts::Globals) {
193    Printer.NewLine();
194    WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
195    Printer.Indent();
196    {
197      FunctionDumper Dumper(Printer);
198      auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>();
199      while (auto Function = Functions->getNext()) {
200        Printer.NewLine();
201        Dumper.start(*Function, FunctionDumper::PointerType::None);
202      }
203    }
204    {
205      auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
206      VariableDumper Dumper(Printer);
207      while (auto Var = Vars->getNext())
208        Dumper.start(*Var);
209    }
210    {
211      auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
212      CompilandDumper Dumper(Printer);
213      while (auto Thunk = Thunks->getNext())
214        Dumper.dump(*Thunk);
215    }
216    Printer.Unindent();
217  }
218  outs().flush();
219}
220
221int main(int argc_, const char *argv_[]) {
222  // Print a stack trace if we signal out.
223  sys::PrintStackTraceOnErrorSignal();
224  PrettyStackTraceProgram X(argc_, argv_);
225
226  SmallVector<const char *, 256> argv;
227  llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
228  std::error_code EC = llvm::sys::Process::GetArgumentVector(
229      argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
230  if (EC) {
231    llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
232    return 1;
233  }
234
235  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
236
237  cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
238  if (opts::All) {
239    opts::Compilands = true;
240    opts::Symbols = true;
241    opts::Globals = true;
242    opts::Types = true;
243  }
244  if (opts::ExcludeCompilerGenerated) {
245    opts::ExcludeTypes.push_back("__vc_attributes");
246    opts::ExcludeCompilands.push_back("* Linker *");
247  }
248  if (opts::ExcludeSystemLibraries) {
249    opts::ExcludeCompilands.push_back(
250        "f:\\binaries\\Intermediate\\vctools\\crt_bld");
251  }
252
253#if defined(HAVE_DIA_SDK)
254  CoInitializeEx(nullptr, COINIT_MULTITHREADED);
255#endif
256
257  std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
258                dumpInput);
259
260#if defined(HAVE_DIA_SDK)
261  CoUninitialize();
262#endif
263
264  return 0;
265}
266