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