[llvm-pdbdump] Add support for printing source files and compilands.
authorZachary Turner <zturner@google.com>
Wed, 28 Jan 2015 00:33:00 +0000 (00:33 +0000)
committerZachary Turner <zturner@google.com>
Wed, 28 Jan 2015 00:33:00 +0000 (00:33 +0000)
This adds two command line options to llvm-pdbdump.

--source-files prints a flat list of all source files in the PDB.

--compilands prints a list of all compilands (e.g. object files)
             that the PDB knows about, and for each one, a list of
             source files that the compiland is composed of as well
             as a hash of the original source file.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@227276 91177308-0d34-0410-b5e6-96231b3b80d8

tools/llvm-pdbdump/DIAExtras.cpp
tools/llvm-pdbdump/DIAExtras.h
tools/llvm-pdbdump/llvm-pdbdump.cpp

index 68c7e57faed17fbb8811e45dbbd9c63794357f54..f08c42efc72afc278faaccaecd12cd6ebe5b07dc 100644 (file)
@@ -174,3 +174,16 @@ raw_ostream &llvm::operator<<(raw_ostream &Stream,
   outs() << " {" << llvm::format_hex((DWORD)MachineType, 2, true) << "}";
   return Stream;
 }
+
+raw_ostream &llvm::operator<<(raw_ostream &Stream, HashAlgorithm Algorithm) {
+  switch (Algorithm) {
+    PRINT_ENUM_VALUE_CASE(HashNone, "None")
+    PRINT_ENUM_VALUE_CASE(HashMD5, "MD5")
+    PRINT_ENUM_VALUE_CASE(HashSHA1, "SHA-1")
+  default:
+    outs() << "(Unknown)";
+    break;
+  }
+  outs() << " {" << (DWORD)Algorithm << "}";
+  return Stream;
+}
index 6561a09b74f7e55214fd7d65db41020dd16c139c..aeef1972dc23d0e35f5f37461dd5b9e1b98daa4f 100644 (file)
@@ -102,6 +102,8 @@ enum MachineTypeEnum {
   MachineTypeCEE = IMAGE_FILE_MACHINE_CEE,
 };
 
+enum HashAlgorithm { HashNone = 0, HashMD5 = 1, HashSHA1 = 2 };
+
 // SymTagEnum has the unfortunate property that it is not only the name of
 // the enum, but also the name of one of the values of the enum.  So that we
 // don't have to always type "enum SymTagEnum", we typedef this to a different
@@ -122,6 +124,8 @@ raw_ostream &operator<<(raw_ostream &Stream,
 raw_ostream &operator<<(raw_ostream &Stream, CV_CPU_TYPE_e CpuType);
 raw_ostream &operator<<(raw_ostream &Stream,
                         llvm::sys::windows::MachineTypeEnum CpuType);
+raw_ostream &operator<<(raw_ostream &Stream,
+                        llvm::sys::windows::HashAlgorithm Algorithm);
 }
 
 #endif
index 855691ce255b849360955f2094c7d0019f87fec4..89f885b574ec16dda58c9bec1da5aeaa0cb9f0e3 100644 (file)
@@ -51,6 +51,37 @@ cl::opt<bool> Tables("tables",
                               "debug tables in the input file"));
 cl::alias TablesShort("t", cl::desc("Alias for --tables"),
                       cl::aliasopt(Tables));
+
+cl::opt<bool> SourceFiles("source-files",
+                          cl::desc("Display a list of the source files "
+                                   "contained in the PDB"));
+cl::alias SourceFilesShort("f", cl::desc("Alias for --source-files"),
+                           cl::aliasopt(SourceFiles));
+
+cl::opt<bool> Compilands("compilands",
+                         cl::desc("Display a list of compilands (e.g. object "
+                                  "files) and their source file composition"));
+cl::alias CompilandsShort("c", cl::desc("Alias for --compilands"),
+                          cl::aliasopt(Compilands));
+}
+
+template <typename TableType>
+static HRESULT GetDiaTable(IDiaSession *Session, TableType **Table) {
+  CComPtr<IDiaEnumTables> EnumTables = nullptr;
+  HRESULT Error = S_OK;
+  if (FAILED(Error = Session->getEnumTables(&EnumTables)))
+    return Error;
+
+  for (auto CurTable : make_com_enumerator(EnumTables)) {
+    TableType *ResultTable = nullptr;
+    if (FAILED(CurTable->QueryInterface(
+            __uuidof(TableType), reinterpret_cast<void **>(&ResultTable))))
+      continue;
+
+    *Table = ResultTable;
+    return S_OK;
+  }
+  return E_FAIL;
 }
 
 static void dumpBasicFileInfo(StringRef Path, IDiaSession *Session) {
@@ -161,6 +192,94 @@ static void dumpDebugTables(IDiaSession *Session) {
   outs().flush();
 }
 
+static void dumpSourceFiles(IDiaSession *Session) {
+  CComPtr<IDiaEnumSourceFiles> EnumSourceFileList;
+  if (FAILED(GetDiaTable(Session, &EnumSourceFileList)))
+    return;
+
+  LONG SourceFileCount = 0;
+  EnumSourceFileList->get_Count(&SourceFileCount);
+
+  outs() << "Dumping source files [" << SourceFileCount << " files]\n";
+  for (auto SourceFile : make_com_enumerator(EnumSourceFileList)) {
+    CComBSTR SourceFileName;
+    if (S_OK != SourceFile->get_fileName(&SourceFileName))
+      continue;
+    outs().indent(2);
+    std::string SourceFileName8;
+    BSTRToUTF8(SourceFileName, SourceFileName8);
+    outs() << SourceFileName8 << "\n";
+  }
+  outs() << "\n";
+  outs().flush();
+}
+
+static void dumpCompilands(IDiaSession *Session) {
+  CComPtr<IDiaEnumSourceFiles> EnumSourceFileList;
+  if (FAILED(GetDiaTable(Session, &EnumSourceFileList)))
+    return;
+
+  LONG SourceFileCount = 0;
+  EnumSourceFileList->get_Count(&SourceFileCount);
+
+  CComPtr<IDiaSymbol> GlobalScope;
+  HRESULT hr = Session->get_globalScope(&GlobalScope);
+  DIASymbol GlobalScopeSymbol(GlobalScope);
+  if (S_OK != hr)
+    return;
+
+  CComPtr<IDiaEnumSymbols> EnumCompilands;
+  if (S_OK !=
+      GlobalScope->findChildren(SymTagCompiland, nullptr, nsNone,
+                                &EnumCompilands))
+    return;
+
+  LONG CompilandCount = 0;
+  EnumCompilands->get_Count(&CompilandCount);
+  outs() << "Dumping compilands [" << CompilandCount
+         << " compilands containing " << SourceFileCount << " source files]\n";
+
+  for (auto Compiland : make_com_enumerator(EnumCompilands)) {
+    DIASymbol CompilandSymbol(Compiland);
+    outs().indent(2);
+    outs() << CompilandSymbol.getName().value() << "\n";
+
+    CComPtr<IDiaEnumSourceFiles> EnumFiles;
+    if (S_OK != Session->findFile(Compiland, nullptr, nsNone, &EnumFiles))
+      continue;
+
+    for (auto SourceFile : make_com_enumerator(EnumFiles)) {
+      DWORD ChecksumType = 0;
+      DWORD ChecksumSize = 0;
+      std::vector<uint8_t> Checksum;
+      outs().indent(4);
+      SourceFile->get_checksumType(&ChecksumType);
+      if (S_OK == SourceFile->get_checksum(0, &ChecksumSize, nullptr)) {
+        Checksum.resize(ChecksumSize);
+        if (S_OK ==
+            SourceFile->get_checksum(ChecksumSize, &ChecksumSize,
+                                     &Checksum[0])) {
+          outs() << "[" << ((ChecksumType == HashMD5) ? "MD5  " : "SHA-1")
+                 << ": ";
+          for (auto byte : Checksum)
+            outs() << format_hex_no_prefix(byte, 2, true);
+          outs() << "] ";
+        }
+      }
+      CComBSTR SourceFileName;
+      if (S_OK != SourceFile->get_fileName(&SourceFileName))
+        continue;
+
+      std::string SourceFileName8;
+      BSTRToUTF8(SourceFileName, SourceFileName8);
+      outs() << SourceFileName8 << "\n";
+    }
+  }
+
+  outs() << "\n";
+  outs().flush();
+}
+
 static void dumpInput(StringRef Path) {
   SmallVector<UTF16, 128> Path16String;
   llvm::convertUTF8ToUTF16String(Path, Path16String);
@@ -173,17 +292,25 @@ static void dumpInput(StringRef Path) {
     return;
   if (FAILED(source->loadDataFromPdb(Path16)))
     return;
-  CComPtr<IDiaSession> session;
-  if (FAILED(source->openSession(&session)))
+  CComPtr<IDiaSession> Session;
+  if (FAILED(source->openSession(&Session)))
     return;
 
-  dumpBasicFileInfo(Path, session);
+  dumpBasicFileInfo(Path, Session);
   if (opts::Streams || opts::StreamData) {
-    dumpDataStreams(session);
+    dumpDataStreams(Session);
   }
 
   if (opts::Tables) {
-    dumpDebugTables(session);
+    dumpDebugTables(Session);
+  }
+
+  if (opts::SourceFiles) {
+    dumpSourceFiles(Session);
+  }
+
+  if (opts::Compilands) {
+    dumpCompilands(Session);
   }
 }