Skip to content

Commit fcb14ad

Browse files
author
Zachary Turner
committedJan 27, 2015
Add llvm-pdbdump to tools.
llvm-pdbdump is a tool which can be used to dump the contents of Microsoft-generated PDB files. It makes use of the Microsoft DIA SDK, which is a COM based library designed specifically for this purpose. The initial commit of this tool dumps the raw bytes from PDB data streams. Future commits will dump more semantic information such as types, symbols, source files, etc similar to the types of information accessible via llvm-dwarfdump. Reviewed by: Aaron Ballman, Reid Kleckner, Chandler Carruth Differential Revision: http://reviews.llvm.org/D7153 llvm-svn: 227241
1 parent 9e2b763 commit fcb14ad

File tree

6 files changed

+495
-1
lines changed

6 files changed

+495
-1
lines changed
 

‎llvm/tools/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ add_llvm_tool_subdirectory(yaml2obj)
6161

6262
add_llvm_tool_subdirectory(llvm-go)
6363

64+
if(MSVC)
65+
add_llvm_tool_subdirectory(llvm-pdbdump)
66+
endif()
67+
6468
if(NOT CYGWIN AND LLVM_ENABLE_PIC)
6569
add_llvm_tool_subdirectory(lto)
6670
add_llvm_tool_subdirectory(llvm-lto)

‎llvm/tools/LLVMBuild.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
;===------------------------------------------------------------------------===;
1717

1818
[common]
19-
subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil
19+
subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-pdbdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil
2020

2121
[component_0]
2222
type = Group
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
set(MSVC_DIA_SDK_DIR "$ENV{VSINSTALLDIR}DIA SDK")
2+
3+
# Due to a bug in MSVC 2013's installation software, it is possible
4+
# for MSVC 2013 to write the DIA SDK into the Visual Studio 2012
5+
# install directory. If this happens, the installation is corrupt
6+
# and there's nothing we can do. It happens with enough frequency
7+
# though that we should handle it. We do so by simply checking that
8+
# the DIA SDK folder exists. Should this happen you will need to
9+
# uninstall VS 2012 and then re-install VS 2013.
10+
if (IS_DIRECTORY ${MSVC_DIA_SDK_DIR})
11+
set(LLVM_LINK_COMPONENTS
12+
Support
13+
)
14+
15+
include_directories(${MSVC_DIA_SDK_DIR}/include)
16+
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
17+
link_directories(${MSVC_DIA_SDK_DIR}/lib/amd64)
18+
else()
19+
link_directories(${MSVC_DIA_SDK_DIR}/lib)
20+
endif()
21+
22+
add_llvm_tool(llvm-pdbdump
23+
llvm-pdbdump.cpp
24+
)
25+
target_link_libraries(llvm-pdbdump diaguids)
26+
endif()

‎llvm/tools/llvm-pdbdump/COMExtras.h

+286
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
//===- COMExtras.h - Helper files for COM operations -------------*- 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+
#ifndef LLVM_TOOLS_LLVM_PDBDUMP_COMEXTRAS_H
11+
#define LLVM_TOOLS_LLVM_PDBDUMP_COMEXTRAS_H
12+
13+
#include "llvm/ADT/ArrayRef.h"
14+
#include "llvm/ADT/SmallVector.h"
15+
16+
#include <tuple>
17+
18+
namespace llvm {
19+
20+
template <typename F> struct function_traits;
21+
22+
#if LLVM_HAS_VARIADIC_TEMPLATES
23+
template <typename R, typename... Args>
24+
struct function_traits<R (*)(Args...)> : public function_traits<R(Args...)> {};
25+
26+
template <typename C, typename R, typename... Args>
27+
struct function_traits<R (__stdcall C::*)(Args...)> {
28+
using args_tuple = std::tuple<Args...>;
29+
};
30+
#else
31+
32+
// For the sake of COM, we only need a 3 argument version and a 5 argument
33+
// version. We could provide 1, 2, 4, and other length of argument lists if
34+
// this were intended to be more generic. Alternatively, this will "just work"
35+
// if VS2012 support is dropped and we can use the variadic template case
36+
// exclusively.
37+
template <typename C, typename R, typename A1, typename A2, typename A3>
38+
struct function_traits<R (__stdcall C::*)(A1, A2, A3)> {
39+
using args_tuple = std::tuple<A1, A2, A3>;
40+
};
41+
42+
template <typename C, typename R, typename A1, typename A2, typename A3,
43+
typename A4, typename A5>
44+
struct function_traits<R (__stdcall C::*)(A1, A2, A3, A4, A5)> {
45+
using args_tuple = std::tuple<A1, A2, A3, A4, A5>;
46+
};
47+
#endif
48+
49+
template <class FuncTraits, std::size_t arg> struct function_arg {
50+
// Writing function_arg as a separate class that accesses the tuple from
51+
// function_traits is necessary due to what appears to be a bug in MSVC.
52+
// If you write a nested class inside function_traits like this:
53+
// template<std::size_t ArgIndex>
54+
// struct Argument
55+
// {
56+
// typedef typename
57+
// std::tuple_element<ArgIndex, std::tuple<Args...>>::type type;
58+
// };
59+
// MSVC encounters a parsing error.
60+
typedef
61+
typename std::tuple_element<arg, typename FuncTraits::args_tuple>::type
62+
type;
63+
};
64+
65+
template <class T> struct remove_double_pointer {};
66+
template <class T> struct remove_double_pointer<T **> { typedef T type; };
67+
68+
namespace sys {
69+
namespace windows {
70+
71+
/// A helper class for allowing the use of COM enumerators in range-based
72+
/// for loops.
73+
///
74+
/// A common idiom in the COM world is to have an enumerator interface, say
75+
/// IMyEnumerator. It's responsible for enumerating over some child data type,
76+
/// say IChildType. You do the enumeration by calling IMyEnumerator::Next()
77+
/// one of whose arguments will be an IChildType**. Eventually Next() fails,
78+
/// indicating that there are no more items.
79+
///
80+
/// com_iterator represents a single point-in-time of this iteration. It is
81+
/// used by ComEnumerator to support iterating in this fashion via range-based
82+
/// for loops and other common C++ paradigms.
83+
template <class EnumeratorType, std::size_t ArgIndex> class com_iterator {
84+
using FunctionTraits = function_traits<decltype(&EnumeratorType::Next)>;
85+
typedef typename function_arg<FunctionTraits, ArgIndex>::type FuncArgType;
86+
// FuncArgType is now something like ISomeCOMInterface **. Remove both
87+
// pointers, so we can make a CComPtr<T> out of it.
88+
typedef typename remove_double_pointer<FuncArgType>::type EnumDataType;
89+
90+
CComPtr<EnumeratorType> EnumeratorObject;
91+
CComPtr<EnumDataType> CurrentItem;
92+
93+
public:
94+
typedef CComPtr<EnumDataType> value_type;
95+
typedef std::ptrdiff_t difference_type;
96+
typedef value_type *pointer_type;
97+
typedef value_type &reference_type;
98+
typedef std::forward_iterator_tag iterator_category;
99+
100+
explicit com_iterator(CComPtr<EnumeratorType> Enumerator,
101+
CComPtr<EnumDataType> Current)
102+
: EnumeratorObject(Enumerator), CurrentItem(Current) {}
103+
com_iterator() {}
104+
105+
com_iterator &operator++() {
106+
// EnumeratorObject->Next() expects CurrentItem to be NULL.
107+
CurrentItem.Release();
108+
ULONG Count = 0;
109+
HRESULT hr = EnumeratorObject->Next(1, &CurrentItem, &Count);
110+
if (FAILED(hr) || Count == 0)
111+
*this = com_iterator();
112+
113+
return *this;
114+
}
115+
116+
value_type operator*() { return CurrentItem; }
117+
118+
bool operator==(const com_iterator &other) const {
119+
return (EnumeratorObject == other.EnumeratorObject) &&
120+
(CurrentItem == other.CurrentItem);
121+
}
122+
123+
bool operator!=(const com_iterator &other) const { return !(*this == other); }
124+
125+
com_iterator &operator=(const com_iterator &other) {
126+
EnumeratorObject = other.EnumeratorObject;
127+
CurrentItem = other.CurrentItem;
128+
return *this;
129+
}
130+
};
131+
132+
/// ComEnumerator implements the interfaced required for C++ to allow its use
133+
/// in range-based for loops. In particular, a begin() and end() method.
134+
/// These methods simply construct and return an appropriate ComIterator
135+
/// instance.
136+
template <class EnumeratorType, std::size_t ArgIndex> class com_enumerator {
137+
typedef function_traits<decltype(&EnumeratorType::Next)> FunctionTraits;
138+
typedef typename function_arg<FunctionTraits, ArgIndex>::type FuncArgType;
139+
typedef typename remove_double_pointer<FuncArgType>::type EnumDataType;
140+
141+
CComPtr<EnumeratorType> EnumeratorObject;
142+
143+
public:
144+
com_enumerator(CComPtr<EnumeratorType> Enumerator)
145+
: EnumeratorObject(Enumerator) {}
146+
147+
com_iterator<EnumeratorType, ArgIndex> begin() {
148+
if (!EnumeratorObject)
149+
return end();
150+
151+
EnumeratorObject->Reset();
152+
ULONG Count = 0;
153+
CComPtr<EnumDataType> FirstItem;
154+
HRESULT hr = EnumeratorObject->Next(1, &FirstItem, &Count);
155+
return (FAILED(hr) || Count == 0) ? end()
156+
: com_iterator<EnumeratorType, ArgIndex>(
157+
EnumeratorObject, FirstItem);
158+
}
159+
160+
com_iterator<EnumeratorType, ArgIndex> end() {
161+
return com_iterator<EnumeratorType, ArgIndex>();
162+
}
163+
};
164+
165+
/// A helper class for allowing the use of COM record enumerators in range-
166+
/// based for loops.
167+
///
168+
/// A record enumerator is almost the same as a regular enumerator, except
169+
/// that it returns raw byte-data instead of interfaces to other COM objects.
170+
/// As a result, the enumerator's Next() method has a slightly different
171+
/// signature, and an iterator dereferences to an ArrayRef instead of a
172+
/// CComPtr.
173+
template <class EnumeratorType> class com_data_record_iterator {
174+
public:
175+
typedef llvm::ArrayRef<uint8_t> value_type;
176+
typedef std::ptrdiff_t difference_type;
177+
typedef value_type *pointer_type;
178+
typedef value_type &reference_type;
179+
typedef std::forward_iterator_tag iterator_category;
180+
181+
explicit com_data_record_iterator(CComPtr<EnumeratorType> enumerator)
182+
: Enumerator(enumerator), CurrentRecord(0) {
183+
// Make sure we start at the beginning. If there are no records,
184+
// immediately set ourselves equal to end().
185+
if (enumerator)
186+
enumerator->Reset();
187+
188+
if (!ReadNextRecord())
189+
*this = com_data_record_iterator();
190+
}
191+
com_data_record_iterator() {}
192+
193+
com_data_record_iterator &operator++() {
194+
++CurrentRecord;
195+
// If we can't read any more records, either because there are no more
196+
// or because we encountered an error, we should compare equal to end.
197+
if (!ReadNextRecord())
198+
*this = com_data_record_iterator();
199+
return *this;
200+
}
201+
202+
value_type operator*() {
203+
return llvm::ArrayRef<uint8_t>(RecordData.begin(), RecordData.end());
204+
}
205+
206+
bool operator==(const com_data_record_iterator &other) const {
207+
return (Enumerator == other.Enumerator) &&
208+
(CurrentRecord == other.CurrentRecord);
209+
}
210+
211+
bool operator!=(const com_data_record_iterator &other) const {
212+
return !(*this == other);
213+
}
214+
215+
private:
216+
bool ReadNextRecord() {
217+
RecordData.clear();
218+
ULONG Count = 0;
219+
DWORD RequiredBufferSize;
220+
HRESULT hr = Enumerator->Next(1, 0, &RequiredBufferSize, nullptr, &Count);
221+
if (hr == S_OK) {
222+
RecordData.resize(RequiredBufferSize);
223+
DWORD BytesRead = 0;
224+
hr = Enumerator->Next(1, RequiredBufferSize, &BytesRead,
225+
RecordData.data(), &Count);
226+
}
227+
if (hr != S_OK)
228+
RecordData.clear();
229+
return (hr == S_OK);
230+
}
231+
232+
CComPtr<EnumeratorType> Enumerator;
233+
uint32_t CurrentRecord;
234+
llvm::SmallVector<uint8_t, 32> RecordData;
235+
};
236+
237+
/// Similar to ComEnumerator, com_data_record_enumerator implements the range
238+
/// interface for ComDataRecordIterators.
239+
template <class EnumeratorType> class com_data_record_enumerator {
240+
public:
241+
com_data_record_enumerator(CComPtr<EnumeratorType> enumerator)
242+
: Enumerator(enumerator) {}
243+
244+
com_data_record_iterator<EnumeratorType> begin() {
245+
return com_data_record_iterator<EnumeratorType>(Enumerator);
246+
}
247+
248+
com_data_record_iterator<EnumeratorType> end() {
249+
LONG NumElts = 0;
250+
HRESULT hr = Enumerator->get_Count(&NumElts);
251+
return (FAILED(hr)) ? com_data_record_iterator<EnumeratorType>(Enumerator)
252+
: com_data_record_iterator<EnumeratorType>();
253+
}
254+
255+
private:
256+
CComPtr<EnumeratorType> Enumerator;
257+
};
258+
259+
/// com_enumerator is a simple helper function to allow the enumerator
260+
/// class's type to be inferred automatically.
261+
/// This allows you to write simply:
262+
/// for (auto item : com_enumerator(MyEnumerator)) {
263+
/// }
264+
template <class EnumeratorType>
265+
com_enumerator<EnumeratorType, 1>
266+
make_com_enumerator(CComPtr<EnumeratorType> Enumerator) {
267+
return com_enumerator<EnumeratorType, 1>(Enumerator);
268+
}
269+
270+
/// com_data_record_enumerator is a simple helper function to allow the
271+
/// enumerator class's type to be inferred automatically.
272+
/// This allows you to write simply:
273+
/// for (auto item : com_data_record_enumerator(MyEnumerator)) {
274+
/// }
275+
//=============================================================================
276+
template <class EnumeratorType>
277+
com_data_record_enumerator<EnumeratorType>
278+
make_com_data_record_enumerator(CComPtr<EnumeratorType> Enumerator) {
279+
return com_data_record_enumerator<EnumeratorType>(Enumerator);
280+
}
281+
282+
} // namespace windows
283+
} // namespace sys
284+
} // namespace llvm
285+
286+
#endif

‎llvm/tools/llvm-pdbdump/LLVMBuild.txt

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
;===- ./tools/llvm-pdbdump/LLVMBuild.txt -----------------------*- Conf -*--===;
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+
; This is an LLVMBuild description file for the components in this subdirectory.
11+
;
12+
; For more information on the LLVMBuild system, please see:
13+
;
14+
; http://llvm.org/docs/LLVMBuild.html
15+
;
16+
;===------------------------------------------------------------------------===;
17+
18+
[component_0]
19+
type = Tool
20+
name = llvm-pdbdump
21+
parent = Tools
22+
required_libraries =
23+

0 commit comments

Comments
 (0)
Please sign in to comment.