--- /dev/null
+//===- COMExtras.h - Helper files for COM operations -------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_PDBDUMP_COMEXTRAS_H
+#define LLVM_TOOLS_LLVM_PDBDUMP_COMEXTRAS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include <tuple>
+
+namespace llvm {
+
+template <typename F> struct function_traits;
+
+#if LLVM_HAS_VARIADIC_TEMPLATES
+template <typename R, typename... Args>
+struct function_traits<R (*)(Args...)> : public function_traits<R(Args...)> {};
+
+template <typename C, typename R, typename... Args>
+struct function_traits<R (__stdcall C::*)(Args...)> {
+ using args_tuple = std::tuple<Args...>;
+};
+#else
+
+// For the sake of COM, we only need a 3 argument version and a 5 argument
+// version. We could provide 1, 2, 4, and other length of argument lists if
+// this were intended to be more generic. Alternatively, this will "just work"
+// if VS2012 support is dropped and we can use the variadic template case
+// exclusively.
+template <typename C, typename R, typename A1, typename A2, typename A3>
+struct function_traits<R (__stdcall C::*)(A1, A2, A3)> {
+ using args_tuple = std::tuple<A1, A2, A3>;
+};
+
+template <typename C, typename R, typename A1, typename A2, typename A3,
+ typename A4, typename A5>
+struct function_traits<R (__stdcall C::*)(A1, A2, A3, A4, A5)> {
+ using args_tuple = std::tuple<A1, A2, A3, A4, A5>;
+};
+#endif
+
+template <class FuncTraits, std::size_t arg> struct function_arg {
+ // Writing function_arg as a separate class that accesses the tuple from
+ // function_traits is necessary due to what appears to be a bug in MSVC.
+ // If you write a nested class inside function_traits like this:
+ // template<std::size_t ArgIndex>
+ // struct Argument
+ // {
+ // typedef typename
+ // std::tuple_element<ArgIndex, std::tuple<Args...>>::type type;
+ // };
+ // MSVC encounters a parsing error.
+ typedef
+ typename std::tuple_element<arg, typename FuncTraits::args_tuple>::type
+ type;
+};
+
+template <class T> struct remove_double_pointer {};
+template <class T> struct remove_double_pointer<T **> { typedef T type; };
+
+namespace sys {
+namespace windows {
+
+/// A helper class for allowing the use of COM enumerators in range-based
+/// for loops.
+///
+/// A common idiom in the COM world is to have an enumerator interface, say
+/// IMyEnumerator. It's responsible for enumerating over some child data type,
+/// say IChildType. You do the enumeration by calling IMyEnumerator::Next()
+/// one of whose arguments will be an IChildType**. Eventually Next() fails,
+/// indicating that there are no more items.
+///
+/// com_iterator represents a single point-in-time of this iteration. It is
+/// used by ComEnumerator to support iterating in this fashion via range-based
+/// for loops and other common C++ paradigms.
+template <class EnumeratorType, std::size_t ArgIndex> class com_iterator {
+ using FunctionTraits = function_traits<decltype(&EnumeratorType::Next)>;
+ typedef typename function_arg<FunctionTraits, ArgIndex>::type FuncArgType;
+ // FuncArgType is now something like ISomeCOMInterface **. Remove both
+ // pointers, so we can make a CComPtr<T> out of it.
+ typedef typename remove_double_pointer<FuncArgType>::type EnumDataType;
+
+ CComPtr<EnumeratorType> EnumeratorObject;
+ CComPtr<EnumDataType> CurrentItem;
+
+public:
+ typedef CComPtr<EnumDataType> value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef value_type *pointer_type;
+ typedef value_type &reference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ explicit com_iterator(CComPtr<EnumeratorType> Enumerator,
+ CComPtr<EnumDataType> Current)
+ : EnumeratorObject(Enumerator), CurrentItem(Current) {}
+ com_iterator() {}
+
+ com_iterator &operator++() {
+ // EnumeratorObject->Next() expects CurrentItem to be NULL.
+ CurrentItem.Release();
+ ULONG Count = 0;
+ HRESULT hr = EnumeratorObject->Next(1, &CurrentItem, &Count);
+ if (FAILED(hr) || Count == 0)
+ *this = com_iterator();
+
+ return *this;
+ }
+
+ value_type operator*() { return CurrentItem; }
+
+ bool operator==(const com_iterator &other) const {
+ return (EnumeratorObject == other.EnumeratorObject) &&
+ (CurrentItem == other.CurrentItem);
+ }
+
+ bool operator!=(const com_iterator &other) const { return !(*this == other); }
+
+ com_iterator &operator=(const com_iterator &other) {
+ EnumeratorObject = other.EnumeratorObject;
+ CurrentItem = other.CurrentItem;
+ return *this;
+ }
+};
+
+/// ComEnumerator implements the interfaced required for C++ to allow its use
+/// in range-based for loops. In particular, a begin() and end() method.
+/// These methods simply construct and return an appropriate ComIterator
+/// instance.
+template <class EnumeratorType, std::size_t ArgIndex> class com_enumerator {
+ typedef function_traits<decltype(&EnumeratorType::Next)> FunctionTraits;
+ typedef typename function_arg<FunctionTraits, ArgIndex>::type FuncArgType;
+ typedef typename remove_double_pointer<FuncArgType>::type EnumDataType;
+
+ CComPtr<EnumeratorType> EnumeratorObject;
+
+public:
+ com_enumerator(CComPtr<EnumeratorType> Enumerator)
+ : EnumeratorObject(Enumerator) {}
+
+ com_iterator<EnumeratorType, ArgIndex> begin() {
+ if (!EnumeratorObject)
+ return end();
+
+ EnumeratorObject->Reset();
+ ULONG Count = 0;
+ CComPtr<EnumDataType> FirstItem;
+ HRESULT hr = EnumeratorObject->Next(1, &FirstItem, &Count);
+ return (FAILED(hr) || Count == 0) ? end()
+ : com_iterator<EnumeratorType, ArgIndex>(
+ EnumeratorObject, FirstItem);
+ }
+
+ com_iterator<EnumeratorType, ArgIndex> end() {
+ return com_iterator<EnumeratorType, ArgIndex>();
+ }
+};
+
+/// A helper class for allowing the use of COM record enumerators in range-
+/// based for loops.
+///
+/// A record enumerator is almost the same as a regular enumerator, except
+/// that it returns raw byte-data instead of interfaces to other COM objects.
+/// As a result, the enumerator's Next() method has a slightly different
+/// signature, and an iterator dereferences to an ArrayRef instead of a
+/// CComPtr.
+template <class EnumeratorType> class com_data_record_iterator {
+public:
+ typedef llvm::ArrayRef<uint8_t> value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef value_type *pointer_type;
+ typedef value_type &reference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ explicit com_data_record_iterator(CComPtr<EnumeratorType> enumerator)
+ : Enumerator(enumerator), CurrentRecord(0) {
+ // Make sure we start at the beginning. If there are no records,
+ // immediately set ourselves equal to end().
+ if (enumerator)
+ enumerator->Reset();
+
+ if (!ReadNextRecord())
+ *this = com_data_record_iterator();
+ }
+ com_data_record_iterator() {}
+
+ com_data_record_iterator &operator++() {
+ ++CurrentRecord;
+ // If we can't read any more records, either because there are no more
+ // or because we encountered an error, we should compare equal to end.
+ if (!ReadNextRecord())
+ *this = com_data_record_iterator();
+ return *this;
+ }
+
+ value_type operator*() {
+ return llvm::ArrayRef<uint8_t>(RecordData.begin(), RecordData.end());
+ }
+
+ bool operator==(const com_data_record_iterator &other) const {
+ return (Enumerator == other.Enumerator) &&
+ (CurrentRecord == other.CurrentRecord);
+ }
+
+ bool operator!=(const com_data_record_iterator &other) const {
+ return !(*this == other);
+ }
+
+private:
+ bool ReadNextRecord() {
+ RecordData.clear();
+ ULONG Count = 0;
+ DWORD RequiredBufferSize;
+ HRESULT hr = Enumerator->Next(1, 0, &RequiredBufferSize, nullptr, &Count);
+ if (hr == S_OK) {
+ RecordData.resize(RequiredBufferSize);
+ DWORD BytesRead = 0;
+ hr = Enumerator->Next(1, RequiredBufferSize, &BytesRead,
+ RecordData.data(), &Count);
+ }
+ if (hr != S_OK)
+ RecordData.clear();
+ return (hr == S_OK);
+ }
+
+ CComPtr<EnumeratorType> Enumerator;
+ uint32_t CurrentRecord;
+ llvm::SmallVector<uint8_t, 32> RecordData;
+};
+
+/// Similar to ComEnumerator, com_data_record_enumerator implements the range
+/// interface for ComDataRecordIterators.
+template <class EnumeratorType> class com_data_record_enumerator {
+public:
+ com_data_record_enumerator(CComPtr<EnumeratorType> enumerator)
+ : Enumerator(enumerator) {}
+
+ com_data_record_iterator<EnumeratorType> begin() {
+ return com_data_record_iterator<EnumeratorType>(Enumerator);
+ }
+
+ com_data_record_iterator<EnumeratorType> end() {
+ LONG NumElts = 0;
+ HRESULT hr = Enumerator->get_Count(&NumElts);
+ return (FAILED(hr)) ? com_data_record_iterator<EnumeratorType>(Enumerator)
+ : com_data_record_iterator<EnumeratorType>();
+ }
+
+private:
+ CComPtr<EnumeratorType> Enumerator;
+};
+
+/// com_enumerator is a simple helper function to allow the enumerator
+/// class's type to be inferred automatically.
+/// This allows you to write simply:
+/// for (auto item : com_enumerator(MyEnumerator)) {
+/// }
+template <class EnumeratorType>
+com_enumerator<EnumeratorType, 1>
+make_com_enumerator(CComPtr<EnumeratorType> Enumerator) {
+ return com_enumerator<EnumeratorType, 1>(Enumerator);
+}
+
+/// com_data_record_enumerator is a simple helper function to allow the
+/// enumerator class's type to be inferred automatically.
+/// This allows you to write simply:
+/// for (auto item : com_data_record_enumerator(MyEnumerator)) {
+/// }
+//=============================================================================
+template <class EnumeratorType>
+com_data_record_enumerator<EnumeratorType>
+make_com_data_record_enumerator(CComPtr<EnumeratorType> Enumerator) {
+ return com_data_record_enumerator<EnumeratorType>(Enumerator);
+}
+
+} // namespace windows
+} // namespace sys
+} // namespace llvm
+
+#endif
--- /dev/null
+//===- llvm-pdbdump.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Dumps debug information present in PDB files. This utility makes use of
+// the Microsoft Windows SDK, so will not compile or run on non-Windows
+// platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#define NTDDI_VERSION NTDDI_VISTA
+#define _WIN32_WINNT _WIN32_WINNT_VISTA
+#define WINVER _WIN32_WINNT_VISTA
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include <atlbase.h>
+#include <windows.h>
+#include <dia2.h>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ConvertUTF.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/Signals.h"
+
+#include "COMExtras.h"
+
+using namespace llvm;
+using namespace llvm::sys::windows;
+
+namespace opts {
+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::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));
+}
+
+namespace {
+bool BSTRToUTF8(BSTR String16, std::string &String8) {
+ UINT ByteLength = ::SysStringByteLen(String16);
+ char *Bytes = reinterpret_cast<char *>(String16);
+ String8.clear();
+ return llvm::convertUTF16ToUTF8String(ArrayRef<char>(Bytes, ByteLength),
+ String8);
+}
+}
+
+static void dumpDataStreams(IDiaSession *session) {
+ CComPtr<IDiaEnumDebugStreams> DebugStreams = nullptr;
+ if (FAILED(session->getEnumDebugStreams(&DebugStreams)))
+ return;
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+ }
+ 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::Streams || opts::StreamData) {
+ dumpDataStreams(session);
+ }
+}
+
+int main(int argc_, const char *argv_[]) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc_, argv_);
+
+ SmallVector<const char *, 256> argv;
+ llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
+ std::error_code EC = llvm::sys::Process::GetArgumentVector(
+ argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
+ if (EC) {
+ llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
+ return 1;
+ }
+
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
+
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+
+ std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
+ dumpInput);
+
+ CoUninitialize();
+ return 0;
+}