Factor out the checking of string tables.
[oota-llvm.git] / tools / llvm-pdbdump / llvm-pdbdump.cpp
index 855691ce255b849360955f2094c7d0019f87fec4..4a4c64b80cc18aa0cfe41ab9032cfee4782f14a6 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm-pdbdump.h"
+#include "CompilandDumper.h"
+#include "ExternalSymbolDumper.h"
+#include "FunctionDumper.h"
+#include "LinePrinter.h"
+#include "TypeDumper.h"
+#include "VariableDumper.h"
+
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Process.h"
 #include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Signals.h"
 
-#include "llvm-pdbdump.h"
-#include "COMExtras.h"
-#include "DIAExtras.h"
-#include "DIASymbol.h"
+#if defined(HAVE_DIA_SDK)
+#include <Windows.h>
+#endif
 
 using namespace llvm;
-using namespace llvm::sys::windows;
 
 namespace opts {
+
+enum class PDB_DumpType { ByType, ByObjFile, Both };
+
 cl::list<std::string> InputFilenames(cl::Positional,
                                      cl::desc("<input PDB files>"),
                                      cl::OneOrMore);
 
-cl::opt<bool> Streams("streams", cl::desc("Display data stream information"));
-cl::alias StreamsShort("s", cl::desc("Alias for --streams"),
-                       cl::aliasopt(Streams));
+cl::OptionCategory TypeCategory("Symbol Type Options");
+cl::OptionCategory FilterCategory("Filtering Options");
+cl::OptionCategory OtherOptions("Other Options");
 
-cl::opt<bool> StreamData("stream-data",
-                         cl::desc("Dumps stream record data as bytes"));
-cl::alias StreamDataShort("S", cl::desc("Alias for --stream-data"),
-                          cl::aliasopt(StreamData));
+cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
+                         cl::cat(TypeCategory));
+cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"),
+                      cl::cat(TypeCategory));
+cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
+                      cl::cat(TypeCategory));
+cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
+                        cl::cat(TypeCategory));
+cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory));
+cl::opt<bool>
+    All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
+        cl::cat(TypeCategory));
 
-cl::opt<bool> Tables("tables",
-                     cl::desc("Display summary information for all of the "
-                              "debug tables in the input file"));
-cl::alias TablesShort("t", cl::desc("Alias for --tables"),
-                      cl::aliasopt(Tables));
+cl::opt<uint64_t> LoadAddress(
+    "load-address",
+    cl::desc("Assume the module is loaded at the specified address"),
+    cl::cat(OtherOptions));
+
+cl::list<std::string>
+    ExcludeTypes("exclude-types",
+                 cl::desc("Exclude types by regular expression"),
+                 cl::ZeroOrMore, cl::cat(FilterCategory));
+cl::list<std::string>
+    ExcludeSymbols("exclude-symbols",
+                   cl::desc("Exclude symbols by regular expression"),
+                   cl::ZeroOrMore, cl::cat(FilterCategory));
+cl::list<std::string>
+    ExcludeCompilands("exclude-compilands",
+                      cl::desc("Exclude compilands by regular expression"),
+                      cl::ZeroOrMore, cl::cat(FilterCategory));
+cl::opt<bool> ExcludeCompilerGenerated(
+    "no-compiler-generated",
+    cl::desc("Don't show compiler generated types and symbols"),
+    cl::cat(FilterCategory));
+cl::opt<bool>
+    ExcludeSystemLibraries("no-system-libs",
+                           cl::desc("Don't show symbols from system libraries"),
+                           cl::cat(FilterCategory));
+cl::opt<bool> NoClassDefs("no-class-definitions",
+                          cl::desc("Don't display full class definitions"),
+                          cl::cat(FilterCategory));
+cl::opt<bool> NoEnumDefs("no-enum-definitions",
+                         cl::desc("Don't display full enum definitions"),
+                         cl::cat(FilterCategory));
 }
 
-static void dumpBasicFileInfo(StringRef Path, IDiaSession *Session) {
-  CComPtr<IDiaSymbol> GlobalScope;
-  HRESULT hr = Session->get_globalScope(&GlobalScope);
-  DIASymbol GlobalScopeSymbol(GlobalScope);
-  if (S_OK == hr)
-    GlobalScopeSymbol.getSymbolsFileName().dump("File", 0);
-  else
-    outs() << "File: " << Path << "\n";
-  HANDLE FileHandle = ::CreateFile(
-      Path.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
-      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
-  LARGE_INTEGER FileSize;
-  if (INVALID_HANDLE_VALUE != FileHandle) {
-    outs().indent(2);
-    if (::GetFileSizeEx(FileHandle, &FileSize))
-      outs() << "Size: " << FileSize.QuadPart << " bytes\n";
-    else
-      outs() << "Size: (Unable to obtain file size)\n";
-    FILETIME ModifiedTime;
-    outs().indent(2);
-    if (::GetFileTime(FileHandle, nullptr, nullptr, &ModifiedTime)) {
-      ULARGE_INTEGER TimeInteger;
-      TimeInteger.LowPart = ModifiedTime.dwLowDateTime;
-      TimeInteger.HighPart = ModifiedTime.dwHighDateTime;
-      llvm::sys::TimeValue Time;
-      Time.fromWin32Time(TimeInteger.QuadPart);
-      outs() << "Timestamp: " << Time.str() << "\n";
-    } else {
-      outs() << "Timestamp: (Unable to obtain time stamp)\n";
-    }
-    ::CloseHandle(FileHandle);
+static void dumpInput(StringRef Path) {
+  std::unique_ptr<IPDBSession> Session;
+  PDB_ErrorCode Error =
+      llvm::loadDataForPDB(PDB_ReaderType::DIA, Path, Session);
+  switch (Error) {
+  case PDB_ErrorCode::Success:
+    break;
+  case PDB_ErrorCode::NoPdbImpl:
+    outs() << "Reading PDBs is not supported on this platform.\n";
+    return;
+  case PDB_ErrorCode::InvalidPath:
+    outs() << "Unable to load PDB at '" << Path
+           << "'.  Check that the file exists and is readable.\n";
+    return;
+  case PDB_ErrorCode::InvalidFileFormat:
+    outs() << "Unable to load PDB at '" << Path
+           << "'.  The file has an unrecognized format.\n";
+    return;
+  default:
+    outs() << "Unable to load PDB at '" << Path
+           << "'.  An unknown error occured.\n";
+    return;
   }
+  if (opts::LoadAddress)
+    Session->setLoadAddress(opts::LoadAddress);
 
-  if (S_OK == hr)
-    GlobalScopeSymbol.fullDump(2);
-  outs() << "\n";
-  outs().flush();
-}
+  LinePrinter Printer(2, outs());
 
-static void dumpDataStreams(IDiaSession *Session) {
-  CComPtr<IDiaEnumDebugStreams> DebugStreams = nullptr;
-  if (FAILED(Session->getEnumDebugStreams(&DebugStreams)))
-    return;
+  auto GlobalScope(Session->getGlobalScope());
+  std::string FileName(GlobalScope->getSymbolsFileName());
 
-  LONG Count = 0;
-  if (FAILED(DebugStreams->get_Count(&Count)))
-    return;
-  outs() << "Data Streams [count=" << Count << "]\n";
-
-  std::string Name8;
-
-  for (auto Stream : make_com_enumerator(DebugStreams)) {
-    BSTR Name16;
-    if (FAILED(Stream->get_name(&Name16)))
-      continue;
-    if (BSTRToUTF8(Name16, Name8))
-      outs() << "  " << Name8;
-    ::SysFreeString(Name16);
-    if (FAILED(Stream->get_Count(&Count))) {
-      outs() << "\n";
-      continue;
-    }
+  WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
+  WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
+  Printer.Indent();
+  uint64_t FileSize = 0;
 
-    outs() << " [" << Count << " records]\n";
-    if (opts::StreamData) {
-      int RecordIndex = 0;
-      for (auto StreamRecord : make_com_data_record_enumerator(Stream)) {
-        outs() << "    Record " << RecordIndex << " [" << StreamRecord.size()
-               << " bytes]";
-        for (uint8_t byte : StreamRecord) {
-          outs() << " " << llvm::format_hex_no_prefix(byte, 2, true);
-        }
-        outs() << "\n";
-        ++RecordIndex;
-      }
-    }
+  Printer.NewLine();
+  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
+  if (!llvm::sys::fs::file_size(FileName, FileSize)) {
+    Printer << ": " << FileSize << " bytes";
+  } else {
+    Printer << ": (Unable to obtain file size)";
   }
-  outs() << "\n";
-  outs().flush();
-}
 
-static void dumpDebugTables(IDiaSession *Session) {
-  CComPtr<IDiaEnumTables> EnumTables = nullptr;
-  if (SUCCEEDED(Session->getEnumTables(&EnumTables))) {
-    LONG Count = 0;
-    if (FAILED(EnumTables->get_Count(&Count)))
-      return;
-
-    outs() << "Debug Tables [count=" << Count << "]\n";
-
-    std::string Name8;
-    for (auto Table : make_com_enumerator(EnumTables)) {
-      BSTR Name16;
-      if (FAILED(Table->get_name(&Name16)))
-        continue;
-      if (BSTRToUTF8(Name16, Name8))
-        outs() << "  " << Name8;
-      ::SysFreeString(Name16);
-      if (SUCCEEDED(Table->get_Count(&Count))) {
-        outs() << " [" << Count << " items]\n";
-      } else
-        outs() << "\n";
-    }
+  Printer.NewLine();
+  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
+  Printer << ": " << GlobalScope->getGuid();
+
+  Printer.NewLine();
+  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
+  Printer << ": " << GlobalScope->getAge();
+
+  Printer.NewLine();
+  WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
+  Printer << ": ";
+  if (GlobalScope->hasCTypes())
+    outs() << "HasCTypes ";
+  if (GlobalScope->hasPrivateSymbols())
+    outs() << "HasPrivateSymbols ";
+  Printer.Unindent();
+
+  if (opts::Compilands) {
+    Printer.NewLine();
+    WithColor(Printer, PDB_ColorItem::SectionHeader).get()
+        << "---COMPILANDS---";
+    Printer.Indent();
+    auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
+    CompilandDumper Dumper(Printer);
+    while (auto Compiland = Compilands->getNext())
+      Dumper.start(*Compiland, false);
+    Printer.Unindent();
   }
-  outs() << "\n";
-  outs().flush();
-}
 
-static void dumpInput(StringRef Path) {
-  SmallVector<UTF16, 128> Path16String;
-  llvm::convertUTF8ToUTF16String(Path, Path16String);
-  wchar_t *Path16 = reinterpret_cast<wchar_t *>(Path16String.data());
-  CComPtr<IDiaDataSource> source;
-  HRESULT hr =
-      ::CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,
-                         __uuidof(IDiaDataSource), (void **)&source);
-  if (FAILED(hr))
-    return;
-  if (FAILED(source->loadDataFromPdb(Path16)))
-    return;
-  CComPtr<IDiaSession> session;
-  if (FAILED(source->openSession(&session)))
-    return;
+  if (opts::Types) {
+    Printer.NewLine();
+    WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
+    Printer.Indent();
+    TypeDumper Dumper(Printer);
+    Dumper.start(*GlobalScope);
+    Printer.Unindent();
+  }
 
-  dumpBasicFileInfo(Path, session);
-  if (opts::Streams || opts::StreamData) {
-    dumpDataStreams(session);
+  if (opts::Symbols) {
+    Printer.NewLine();
+    WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
+    Printer.Indent();
+    auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
+    CompilandDumper Dumper(Printer);
+    while (auto Compiland = Compilands->getNext())
+      Dumper.start(*Compiland, true);
+    Printer.Unindent();
   }
 
-  if (opts::Tables) {
-    dumpDebugTables(session);
+  if (opts::Globals) {
+    Printer.NewLine();
+    WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
+    Printer.Indent();
+    {
+      FunctionDumper Dumper(Printer);
+      auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>();
+      while (auto Function = Functions->getNext()) {
+        Printer.NewLine();
+        Dumper.start(*Function, FunctionDumper::PointerType::None);
+      }
+    }
+    {
+      auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
+      VariableDumper Dumper(Printer);
+      while (auto Var = Vars->getNext())
+        Dumper.start(*Var);
+    }
+    {
+      auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
+      CompilandDumper Dumper(Printer);
+      while (auto Thunk = Thunks->getNext())
+        Dumper.dump(*Thunk);
+    }
+    Printer.Unindent();
+  }
+  if (opts::Externals) {
+    Printer.NewLine();
+    WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
+    Printer.Indent();
+    ExternalSymbolDumper Dumper(Printer);
+    Dumper.start(*GlobalScope);
   }
+  outs().flush();
 }
 
 int main(int argc_, const char *argv_[]) {
@@ -204,12 +253,32 @@ int main(int argc_, const char *argv_[]) {
   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
 
   cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
+  if (opts::All) {
+    opts::Compilands = true;
+    opts::Symbols = true;
+    opts::Globals = true;
+    opts::Types = true;
+    opts::Externals = true;
+  }
+  if (opts::ExcludeCompilerGenerated) {
+    opts::ExcludeTypes.push_back("__vc_attributes");
+    opts::ExcludeCompilands.push_back("* Linker *");
+  }
+  if (opts::ExcludeSystemLibraries) {
+    opts::ExcludeCompilands.push_back(
+        "f:\\binaries\\Intermediate\\vctools\\crt_bld");
+  }
 
+#if defined(HAVE_DIA_SDK)
   CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+#endif
 
   std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
                 dumpInput);
 
+#if defined(HAVE_DIA_SDK)
   CoUninitialize();
+#endif
+
   return 0;
 }