Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 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 | |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 16 | #include "llvm-pdbdump.h" |
| 17 | #include "CompilandDumper.h" |
Zachary Turner | e5cb269 | 2015-05-01 20:24:26 +0000 | [diff] [blame] | 18 | #include "ExternalSymbolDumper.h" |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 19 | #include "FunctionDumper.h" |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 20 | #include "LinePrinter.h" |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 21 | #include "TypeDumper.h" |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 22 | #include "VariableDumper.h" |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 23 | |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 24 | #include "llvm/ADT/ArrayRef.h" |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 25 | #include "llvm/ADT/BitVector.h" |
| 26 | #include "llvm/ADT/DenseMap.h" |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 27 | #include "llvm/ADT/StringExtras.h" |
Zachary Turner | 8d7fa9b | 2015-02-10 22:47:14 +0000 | [diff] [blame] | 28 | #include "llvm/Config/config.h" |
Zachary Turner | a554917 | 2015-02-10 22:43:25 +0000 | [diff] [blame] | 29 | #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" |
Zachary Turner | a554917 | 2015-02-10 22:43:25 +0000 | [diff] [blame] | 30 | #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" |
Chandler Carruth | 71f308a | 2015-02-13 09:09:03 +0000 | [diff] [blame] | 31 | #include "llvm/DebugInfo/PDB/IPDBSession.h" |
| 32 | #include "llvm/DebugInfo/PDB/PDB.h" |
Zachary Turner | a554917 | 2015-02-10 22:43:25 +0000 | [diff] [blame] | 33 | #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 34 | #include "llvm/DebugInfo/PDB/PDBSymbolData.h" |
Chandler Carruth | 71f308a | 2015-02-13 09:09:03 +0000 | [diff] [blame] | 35 | #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 36 | #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" |
| 37 | #include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 38 | #include "llvm/Support/CommandLine.h" |
| 39 | #include "llvm/Support/ConvertUTF.h" |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 40 | #include "llvm/Support/FileSystem.h" |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 41 | #include "llvm/Support/Format.h" |
| 42 | #include "llvm/Support/ManagedStatic.h" |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 43 | #include "llvm/Support/MemoryBuffer.h" |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 44 | #include "llvm/Support/PrettyStackTrace.h" |
Chandler Carruth | 71f308a | 2015-02-13 09:09:03 +0000 | [diff] [blame] | 45 | #include "llvm/Support/Process.h" |
Chandler Carruth | 71f308a | 2015-02-13 09:09:03 +0000 | [diff] [blame] | 46 | #include "llvm/Support/raw_ostream.h" |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 47 | #include "llvm/Support/Signals.h" |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 48 | |
Zachary Turner | 8d7fa9b | 2015-02-10 22:47:14 +0000 | [diff] [blame] | 49 | #if defined(HAVE_DIA_SDK) |
Benjamin Kramer | 4b4a936 | 2015-10-15 09:38:45 +0000 | [diff] [blame] | 50 | #ifndef NOMINMAX |
| 51 | #define NOMINMAX |
| 52 | #endif |
Zachary Turner | a554917 | 2015-02-10 22:43:25 +0000 | [diff] [blame] | 53 | #include <Windows.h> |
Zachary Turner | 8d7fa9b | 2015-02-10 22:47:14 +0000 | [diff] [blame] | 54 | #endif |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 55 | |
| 56 | using namespace llvm; |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 57 | |
| 58 | namespace opts { |
Zachary Turner | c0acf68 | 2015-02-15 20:27:53 +0000 | [diff] [blame] | 59 | |
| 60 | enum class PDB_DumpType { ByType, ByObjFile, Both }; |
| 61 | |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 62 | cl::list<std::string> InputFilenames(cl::Positional, |
| 63 | cl::desc("<input PDB files>"), |
| 64 | cl::OneOrMore); |
| 65 | |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 66 | cl::OptionCategory TypeCategory("Symbol Type Options"); |
| 67 | cl::OptionCategory FilterCategory("Filtering Options"); |
Zachary Turner | e5cb269 | 2015-05-01 20:24:26 +0000 | [diff] [blame] | 68 | cl::OptionCategory OtherOptions("Other Options"); |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 69 | |
| 70 | cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"), |
| 71 | cl::cat(TypeCategory)); |
| 72 | cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"), |
| 73 | cl::cat(TypeCategory)); |
| 74 | cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"), |
| 75 | cl::cat(TypeCategory)); |
Zachary Turner | e5cb269 | 2015-05-01 20:24:26 +0000 | [diff] [blame] | 76 | cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"), |
| 77 | cl::cat(TypeCategory)); |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 78 | cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory)); |
| 79 | cl::opt<bool> |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 80 | All("all", cl::desc("Implies all other options in 'Symbol Types' category"), |
| 81 | cl::cat(TypeCategory)); |
Zachary Turner | f5abda2 | 2015-03-01 06:49:49 +0000 | [diff] [blame] | 82 | |
Zachary Turner | e5cb269 | 2015-05-01 20:24:26 +0000 | [diff] [blame] | 83 | cl::opt<uint64_t> LoadAddress( |
| 84 | "load-address", |
| 85 | cl::desc("Assume the module is loaded at the specified address"), |
| 86 | cl::cat(OtherOptions)); |
| 87 | |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 88 | cl::opt<bool> DumpHeaders("dump-headers", cl::desc("dump PDB headers"), |
| 89 | cl::cat(OtherOptions)); |
| 90 | cl::opt<bool> DumpStreamSizes("dump-stream-sizes", |
| 91 | cl::desc("dump PDB stream sizes"), |
| 92 | cl::cat(OtherOptions)); |
| 93 | cl::opt<bool> DumpStreamBlocks("dump-stream-blocks", |
| 94 | cl::desc("dump PDB stream blocks"), |
| 95 | cl::cat(OtherOptions)); |
| 96 | cl::opt<std::string> DumpStreamData("dump-stream", cl::desc("dump stream data"), |
| 97 | cl::cat(OtherOptions)); |
| 98 | |
Zachary Turner | f5abda2 | 2015-03-01 06:49:49 +0000 | [diff] [blame] | 99 | cl::list<std::string> |
| 100 | ExcludeTypes("exclude-types", |
| 101 | cl::desc("Exclude types by regular expression"), |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 102 | cl::ZeroOrMore, cl::cat(FilterCategory)); |
Zachary Turner | f5abda2 | 2015-03-01 06:49:49 +0000 | [diff] [blame] | 103 | cl::list<std::string> |
| 104 | ExcludeSymbols("exclude-symbols", |
| 105 | cl::desc("Exclude symbols by regular expression"), |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 106 | cl::ZeroOrMore, cl::cat(FilterCategory)); |
Zachary Turner | f5abda2 | 2015-03-01 06:49:49 +0000 | [diff] [blame] | 107 | cl::list<std::string> |
| 108 | ExcludeCompilands("exclude-compilands", |
| 109 | cl::desc("Exclude compilands by regular expression"), |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 110 | cl::ZeroOrMore, cl::cat(FilterCategory)); |
Zachary Turner | 4dddcc6 | 2015-09-29 19:49:06 +0000 | [diff] [blame] | 111 | |
| 112 | cl::list<std::string> IncludeTypes( |
| 113 | "include-types", |
| 114 | cl::desc("Include only types which match a regular expression"), |
| 115 | cl::ZeroOrMore, cl::cat(FilterCategory)); |
| 116 | cl::list<std::string> IncludeSymbols( |
| 117 | "include-symbols", |
| 118 | cl::desc("Include only symbols which match a regular expression"), |
| 119 | cl::ZeroOrMore, cl::cat(FilterCategory)); |
| 120 | cl::list<std::string> IncludeCompilands( |
| 121 | "include-compilands", |
| 122 | cl::desc("Include only compilands those which match a regular expression"), |
| 123 | cl::ZeroOrMore, cl::cat(FilterCategory)); |
| 124 | |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 125 | cl::opt<bool> ExcludeCompilerGenerated( |
| 126 | "no-compiler-generated", |
| 127 | cl::desc("Don't show compiler generated types and symbols"), |
| 128 | cl::cat(FilterCategory)); |
| 129 | cl::opt<bool> |
| 130 | ExcludeSystemLibraries("no-system-libs", |
| 131 | cl::desc("Don't show symbols from system libraries"), |
| 132 | cl::cat(FilterCategory)); |
Zachary Turner | 6532365 | 2015-03-04 06:09:53 +0000 | [diff] [blame] | 133 | cl::opt<bool> NoClassDefs("no-class-definitions", |
| 134 | cl::desc("Don't display full class definitions"), |
| 135 | cl::cat(FilterCategory)); |
| 136 | cl::opt<bool> NoEnumDefs("no-enum-definitions", |
| 137 | cl::desc("Don't display full enum definitions"), |
| 138 | cl::cat(FilterCategory)); |
Zachary Turner | 49693b4 | 2015-01-28 01:22:33 +0000 | [diff] [blame] | 139 | } |
| 140 | |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 141 | |
| 142 | static void reportError(StringRef Input, StringRef Message) { |
| 143 | if (Input == "-") |
| 144 | Input = "<stdin>"; |
| 145 | errs() << Input << ": " << Message << "\n"; |
| 146 | errs().flush(); |
| 147 | exit(1); |
| 148 | } |
| 149 | |
| 150 | static void reportError(StringRef Input, std::error_code EC) { |
| 151 | reportError(Input, EC.message()); |
| 152 | } |
| 153 | |
| 154 | static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, |
| 155 | const uint64_t Size) { |
| 156 | if (Addr + Size < Addr || Addr + Size < Size || |
| 157 | Addr + Size > uintptr_t(M.getBufferEnd()) || |
| 158 | Addr < uintptr_t(M.getBufferStart())) { |
| 159 | return std::make_error_code(std::errc::bad_address); |
| 160 | } |
| 161 | return std::error_code(); |
| 162 | } |
| 163 | |
| 164 | template <typename T> |
| 165 | static std::error_code checkOffset(MemoryBufferRef M, ArrayRef<T> AR) { |
| 166 | return checkOffset(M, uintptr_t(AR.data()), (uint64_t)AR.size() * sizeof(T)); |
| 167 | } |
| 168 | |
| 169 | static std::error_code checkOffset(MemoryBufferRef M, StringRef SR) { |
| 170 | return checkOffset(M, uintptr_t(SR.data()), SR.size()); |
| 171 | } |
| 172 | |
| 173 | // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. |
| 174 | // Returns unexpected_eof if error. |
| 175 | template <typename T> |
| 176 | static std::error_code getObject(const T *&Obj, MemoryBufferRef M, |
| 177 | const void *Ptr, |
| 178 | const uint64_t Size = sizeof(T)) { |
| 179 | uintptr_t Addr = uintptr_t(Ptr); |
| 180 | if (std::error_code EC = checkOffset(M, Addr, Size)) |
| 181 | return EC; |
| 182 | Obj = reinterpret_cast<const T *>(Addr); |
| 183 | return std::error_code(); |
| 184 | } |
| 185 | |
| 186 | static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { |
| 187 | return RoundUpToAlignment(NumBytes, BlockSize) / BlockSize; |
| 188 | } |
| 189 | |
| 190 | static uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { |
| 191 | return BlockNumber * BlockSize; |
| 192 | } |
| 193 | |
| 194 | static void dumpStructure(MemoryBufferRef M) { |
| 195 | const PDB::SuperBlock *SB; |
| 196 | if (auto EC = getObject(SB, M, M.getBufferStart())) |
| 197 | reportError(M.getBufferIdentifier(), EC); |
| 198 | |
| 199 | if (opts::DumpHeaders) { |
| 200 | outs() << "BlockSize: " << SB->BlockSize << '\n'; |
| 201 | outs() << "Unknown0: " << SB->Unknown0 << '\n'; |
| 202 | outs() << "NumBlocks: " << SB->NumBlocks << '\n'; |
| 203 | outs() << "NumDirectoryBytes: " << SB->NumDirectoryBytes << '\n'; |
| 204 | outs() << "Unknown1: " << SB->Unknown1 << '\n'; |
| 205 | outs() << "BlockMapAddr: " << SB->BlockMapAddr << '\n'; |
| 206 | } |
| 207 | |
| 208 | // We don't support blocksizes which aren't a multiple of four bytes. |
| 209 | if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) |
| 210 | reportError(M.getBufferIdentifier(), |
| 211 | std::make_error_code(std::errc::illegal_byte_sequence)); |
| 212 | |
| 213 | // We don't support directories whose sizes aren't a multiple of four bytes. |
| 214 | if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) |
| 215 | reportError(M.getBufferIdentifier(), |
| 216 | std::make_error_code(std::errc::illegal_byte_sequence)); |
| 217 | |
| 218 | // The number of blocks which comprise the directory is a simple function of |
| 219 | // the number of bytes it contains. |
| 220 | uint64_t NumDirectoryBlocks = |
| 221 | bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize); |
| 222 | if (opts::DumpHeaders) |
| 223 | outs() << "NumDirectoryBlocks: " << NumDirectoryBlocks << '\n'; |
| 224 | |
| 225 | // The block map, as we understand it, is a block which consists of a list of |
| 226 | // block numbers. |
| 227 | // It is unclear what would happen if the number of blocks couldn't fit on a |
| 228 | // single block. |
| 229 | if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) |
| 230 | reportError(M.getBufferIdentifier(), |
| 231 | std::make_error_code(std::errc::illegal_byte_sequence)); |
| 232 | |
| 233 | |
| 234 | uint64_t BlockMapOffset = (uint64_t)SB->BlockMapAddr * SB->BlockSize; |
| 235 | if (opts::DumpHeaders) |
| 236 | outs() << "BlockMapOffset: " << BlockMapOffset << '\n'; |
| 237 | |
| 238 | // The directory is not contiguous. Instead, the block map contains a |
| 239 | // contiguous list of block numbers whose contents, when concatenated in |
| 240 | // order, make up the directory. |
| 241 | auto DirectoryBlocks = |
| 242 | makeArrayRef(reinterpret_cast<const support::ulittle32_t *>( |
| 243 | M.getBufferStart() + BlockMapOffset), |
| 244 | NumDirectoryBlocks); |
| 245 | if (auto EC = checkOffset(M, DirectoryBlocks)) |
| 246 | reportError(M.getBufferIdentifier(), EC); |
| 247 | |
| 248 | if (opts::DumpHeaders) { |
| 249 | outs() << "DirectoryBlocks: ["; |
| 250 | for (const support::ulittle32_t &DirectoryBlockAddr : DirectoryBlocks) { |
| 251 | if (&DirectoryBlockAddr != &DirectoryBlocks.front()) |
| 252 | outs() << ", "; |
| 253 | outs() << DirectoryBlockAddr; |
| 254 | } |
| 255 | outs() << "]\n"; |
| 256 | } |
| 257 | |
| 258 | bool SeenNumStreams = false; |
| 259 | uint32_t NumStreams = 0; |
| 260 | std::vector<uint32_t> StreamSizes; |
| 261 | DenseMap<uint32_t, std::vector<uint32_t>> StreamMap; |
| 262 | uint32_t StreamIdx = 0; |
| 263 | uint64_t DirectoryBytesRead = 0; |
| 264 | // The structure of the directory is as follows: |
| 265 | // struct PDBDirectory { |
| 266 | // uint32_t NumStreams; |
| 267 | // uint32_t StreamSizes[NumStreams]; |
| 268 | // uint32_t StreamMap[NumStreams][]; |
| 269 | // }; |
| 270 | // |
| 271 | // Empty streams don't consume entries in the StreamMap. |
| 272 | for (uint32_t DirectoryBlockAddr : DirectoryBlocks) { |
| 273 | uint64_t DirectoryBlockOffset = |
| 274 | blockToOffset(DirectoryBlockAddr, SB->BlockSize); |
| 275 | auto DirectoryBlock = |
| 276 | makeArrayRef(reinterpret_cast<const support::ulittle32_t *>( |
| 277 | M.getBufferStart() + DirectoryBlockOffset), |
| 278 | SB->BlockSize / sizeof(support::ulittle32_t)); |
| 279 | if (auto EC = checkOffset(M, DirectoryBlock)) |
| 280 | reportError(M.getBufferIdentifier(), EC); |
| 281 | |
| 282 | // We read data out of the directory four bytes at a time. Depending on |
| 283 | // where we are in the directory, the contents may be: the number of streams |
| 284 | // in the directory, a stream's size, or a block in the stream map. |
| 285 | for (uint32_t Data : DirectoryBlock) { |
| 286 | // Don't read beyond the end of the directory. |
| 287 | if (DirectoryBytesRead == SB->NumDirectoryBytes) |
| 288 | break; |
| 289 | |
| 290 | DirectoryBytesRead += sizeof(Data); |
| 291 | |
| 292 | // This data must be the number of streams if we haven't seen it yet. |
| 293 | if (!SeenNumStreams) { |
| 294 | NumStreams = Data; |
| 295 | SeenNumStreams = true; |
| 296 | continue; |
| 297 | } |
| 298 | // This data must be a stream size if we have not seen them all yet. |
| 299 | if (StreamSizes.size() < NumStreams) { |
| 300 | // It seems like some streams have their set to -1 when their contents |
| 301 | // are not present. Treat them like empty streams for now. |
| 302 | if (Data == UINT32_MAX) |
| 303 | StreamSizes.push_back(0); |
| 304 | else |
| 305 | StreamSizes.push_back(Data); |
| 306 | continue; |
| 307 | } |
| 308 | |
| 309 | // This data must be a stream block number if we have seen all of the |
| 310 | // stream sizes. |
| 311 | std::vector<uint32_t> *StreamBlocks = nullptr; |
| 312 | // Figure out which stream this block number belongs to. |
| 313 | while (StreamIdx < NumStreams) { |
| 314 | uint64_t NumExpectedStreamBlocks = |
| 315 | bytesToBlocks(StreamSizes[StreamIdx], SB->BlockSize); |
| 316 | StreamBlocks = &StreamMap[StreamIdx]; |
| 317 | if (NumExpectedStreamBlocks > StreamBlocks->size()) |
| 318 | break; |
| 319 | ++StreamIdx; |
| 320 | } |
| 321 | // It seems this block doesn't belong to any stream? The stream is either |
| 322 | // corrupt or something more mysterious is going on. |
| 323 | if (StreamIdx == NumStreams) |
| 324 | reportError(M.getBufferIdentifier(), |
| 325 | std::make_error_code(std::errc::illegal_byte_sequence)); |
| 326 | |
| 327 | StreamBlocks->push_back(Data); |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | // We should have read exactly SB->NumDirectoryBytes bytes. |
| 332 | assert(DirectoryBytesRead == SB->NumDirectoryBytes); |
| 333 | |
| 334 | if (opts::DumpHeaders) |
| 335 | outs() << "NumStreams: " << NumStreams << '\n'; |
| 336 | if (opts::DumpStreamSizes) |
| 337 | for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) |
| 338 | outs() << "StreamSizes[" << StreamIdx << "]: " << StreamSizes[StreamIdx] |
| 339 | << '\n'; |
| 340 | |
| 341 | if (opts::DumpStreamBlocks) { |
| 342 | for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) { |
| 343 | outs() << "StreamBlocks[" << StreamIdx << "]: ["; |
| 344 | std::vector<uint32_t> &StreamBlocks = StreamMap[StreamIdx]; |
| 345 | for (uint32_t &StreamBlock : StreamBlocks) { |
| 346 | if (&StreamBlock != &StreamBlocks.front()) |
| 347 | outs() << ", "; |
| 348 | outs() << StreamBlock; |
| 349 | } |
| 350 | outs() << "]\n"; |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | StringRef DumpStreamStr = opts::DumpStreamData; |
| 355 | uint32_t DumpStreamNum; |
| 356 | if (!DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum) && |
| 357 | DumpStreamNum < NumStreams) { |
| 358 | uint32_t StreamBytesRead = 0; |
| 359 | uint32_t StreamSize = StreamSizes[DumpStreamNum]; |
| 360 | std::vector<uint32_t> &StreamBlocks = StreamMap[DumpStreamNum]; |
| 361 | for (uint32_t &StreamBlockAddr : StreamBlocks) { |
| 362 | uint64_t StreamBlockOffset = blockToOffset(StreamBlockAddr, SB->BlockSize); |
| 363 | uint32_t BytesLeftToReadInStream = StreamSize - StreamBytesRead; |
| 364 | if (BytesLeftToReadInStream == 0) |
| 365 | break; |
| 366 | |
Benjamin Kramer | 875d1bf | 2015-10-15 09:32:54 +0000 | [diff] [blame] | 367 | uint32_t BytesToReadInBlock = std::min( |
David Majnemer | 6d91aa2 | 2015-10-15 09:17:15 +0000 | [diff] [blame] | 368 | BytesLeftToReadInStream, static_cast<uint32_t>(SB->BlockSize)); |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 369 | auto StreamBlockData = |
| 370 | StringRef(M.getBufferStart() + StreamBlockOffset, BytesToReadInBlock); |
| 371 | if (auto EC = checkOffset(M, StreamBlockData)) |
| 372 | reportError(M.getBufferIdentifier(), EC); |
| 373 | |
| 374 | outs() << StreamBlockData; |
| 375 | StreamBytesRead += StreamBlockData.size(); |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 380 | static void dumpInput(StringRef Path) { |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 381 | if (opts::DumpHeaders || !opts::DumpStreamData.empty()) { |
| 382 | ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = |
| 383 | MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, |
| 384 | /*RequiresNullTerminator=*/false); |
| 385 | |
| 386 | if (std::error_code EC = ErrorOrBuffer.getError()) |
| 387 | reportError(Path, EC); |
| 388 | |
| 389 | std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get(); |
| 390 | |
| 391 | dumpStructure(Buffer->getMemBufferRef()); |
| 392 | |
| 393 | outs().flush(); |
| 394 | return; |
| 395 | } |
| 396 | |
Zachary Turner | ccf0415 | 2015-02-28 20:23:18 +0000 | [diff] [blame] | 397 | std::unique_ptr<IPDBSession> Session; |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 398 | PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session); |
Zachary Turner | ccf0415 | 2015-02-28 20:23:18 +0000 | [diff] [blame] | 399 | switch (Error) { |
| 400 | case PDB_ErrorCode::Success: |
| 401 | break; |
| 402 | case PDB_ErrorCode::NoPdbImpl: |
| 403 | outs() << "Reading PDBs is not supported on this platform.\n"; |
| 404 | return; |
| 405 | case PDB_ErrorCode::InvalidPath: |
| 406 | outs() << "Unable to load PDB at '" << Path |
| 407 | << "'. Check that the file exists and is readable.\n"; |
| 408 | return; |
| 409 | case PDB_ErrorCode::InvalidFileFormat: |
| 410 | outs() << "Unable to load PDB at '" << Path |
| 411 | << "'. The file has an unrecognized format.\n"; |
| 412 | return; |
| 413 | default: |
| 414 | outs() << "Unable to load PDB at '" << Path |
| 415 | << "'. An unknown error occured.\n"; |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 416 | return; |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 417 | } |
Zachary Turner | e5cb269 | 2015-05-01 20:24:26 +0000 | [diff] [blame] | 418 | if (opts::LoadAddress) |
| 419 | Session->setLoadAddress(opts::LoadAddress); |
Zachary Turner | 7058dfc | 2015-01-27 22:40:14 +0000 | [diff] [blame] | 420 | |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 421 | LinePrinter Printer(2, outs()); |
| 422 | |
Zachary Turner | a554917 | 2015-02-10 22:43:25 +0000 | [diff] [blame] | 423 | auto GlobalScope(Session->getGlobalScope()); |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 424 | std::string FileName(GlobalScope->getSymbolsFileName()); |
| 425 | |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 426 | WithColor(Printer, PDB_ColorItem::None).get() << "Summary for "; |
| 427 | WithColor(Printer, PDB_ColorItem::Path).get() << FileName; |
| 428 | Printer.Indent(); |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 429 | uint64_t FileSize = 0; |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 430 | |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 431 | Printer.NewLine(); |
| 432 | WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 433 | if (!sys::fs::file_size(FileName, FileSize)) { |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 434 | Printer << ": " << FileSize << " bytes"; |
| 435 | } else { |
| 436 | Printer << ": (Unable to obtain file size)"; |
| 437 | } |
| 438 | |
| 439 | Printer.NewLine(); |
| 440 | WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid"; |
| 441 | Printer << ": " << GlobalScope->getGuid(); |
| 442 | |
| 443 | Printer.NewLine(); |
| 444 | WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age"; |
| 445 | Printer << ": " << GlobalScope->getAge(); |
| 446 | |
| 447 | Printer.NewLine(); |
| 448 | WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes"; |
| 449 | Printer << ": "; |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 450 | if (GlobalScope->hasCTypes()) |
| 451 | outs() << "HasCTypes "; |
| 452 | if (GlobalScope->hasPrivateSymbols()) |
| 453 | outs() << "HasPrivateSymbols "; |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 454 | Printer.Unindent(); |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 455 | |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 456 | if (opts::Compilands) { |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 457 | Printer.NewLine(); |
| 458 | WithColor(Printer, PDB_ColorItem::SectionHeader).get() |
| 459 | << "---COMPILANDS---"; |
| 460 | Printer.Indent(); |
Zachary Turner | c074de0 | 2015-02-12 21:09:24 +0000 | [diff] [blame] | 461 | auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 462 | CompilandDumper Dumper(Printer); |
Zachary Turner | 9a818ad | 2015-02-22 22:03:38 +0000 | [diff] [blame] | 463 | while (auto Compiland = Compilands->getNext()) |
Zachary Turner | b52d08d | 2015-03-01 06:51:29 +0000 | [diff] [blame] | 464 | Dumper.start(*Compiland, false); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 465 | Printer.Unindent(); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 466 | } |
| 467 | |
| 468 | if (opts::Types) { |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 469 | Printer.NewLine(); |
| 470 | WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; |
| 471 | Printer.Indent(); |
Zachary Turner | 6532365 | 2015-03-04 06:09:53 +0000 | [diff] [blame] | 472 | TypeDumper Dumper(Printer); |
Zachary Turner | b52d08d | 2015-03-01 06:51:29 +0000 | [diff] [blame] | 473 | Dumper.start(*GlobalScope); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 474 | Printer.Unindent(); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 475 | } |
| 476 | |
| 477 | if (opts::Symbols) { |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 478 | Printer.NewLine(); |
| 479 | WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; |
| 480 | Printer.Indent(); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 481 | auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 482 | CompilandDumper Dumper(Printer); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 483 | while (auto Compiland = Compilands->getNext()) |
Zachary Turner | b52d08d | 2015-03-01 06:51:29 +0000 | [diff] [blame] | 484 | Dumper.start(*Compiland, true); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 485 | Printer.Unindent(); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 486 | } |
| 487 | |
| 488 | if (opts::Globals) { |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 489 | Printer.NewLine(); |
| 490 | WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; |
| 491 | Printer.Indent(); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 492 | { |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 493 | FunctionDumper Dumper(Printer); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 494 | auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>(); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 495 | while (auto Function = Functions->getNext()) { |
| 496 | Printer.NewLine(); |
Zachary Turner | b52d08d | 2015-03-01 06:51:29 +0000 | [diff] [blame] | 497 | Dumper.start(*Function, FunctionDumper::PointerType::None); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 498 | } |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 499 | } |
| 500 | { |
| 501 | auto Vars = GlobalScope->findAllChildren<PDBSymbolData>(); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 502 | VariableDumper Dumper(Printer); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 503 | while (auto Var = Vars->getNext()) |
Zachary Turner | b52d08d | 2015-03-01 06:51:29 +0000 | [diff] [blame] | 504 | Dumper.start(*Var); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 505 | } |
| 506 | { |
| 507 | auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>(); |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 508 | CompilandDumper Dumper(Printer); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 509 | while (auto Thunk = Thunks->getNext()) |
Zachary Turner | b52d08d | 2015-03-01 06:51:29 +0000 | [diff] [blame] | 510 | Dumper.dump(*Thunk); |
Zachary Turner | db18f5c | 2015-02-27 09:15:18 +0000 | [diff] [blame] | 511 | } |
Zachary Turner | 2d11c20 | 2015-02-27 09:15:59 +0000 | [diff] [blame] | 512 | Printer.Unindent(); |
Zachary Turner | 7058dfc | 2015-01-27 22:40:14 +0000 | [diff] [blame] | 513 | } |
Zachary Turner | e5cb269 | 2015-05-01 20:24:26 +0000 | [diff] [blame] | 514 | if (opts::Externals) { |
| 515 | Printer.NewLine(); |
| 516 | WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---"; |
| 517 | Printer.Indent(); |
| 518 | ExternalSymbolDumper Dumper(Printer); |
| 519 | Dumper.start(*GlobalScope); |
| 520 | } |
Zachary Turner | a554917 | 2015-02-10 22:43:25 +0000 | [diff] [blame] | 521 | outs().flush(); |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 522 | } |
| 523 | |
| 524 | int main(int argc_, const char *argv_[]) { |
| 525 | // Print a stack trace if we signal out. |
| 526 | sys::PrintStackTraceOnErrorSignal(); |
| 527 | PrettyStackTraceProgram X(argc_, argv_); |
| 528 | |
| 529 | SmallVector<const char *, 256> argv; |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 530 | SpecificBumpPtrAllocator<char> ArgAllocator; |
| 531 | std::error_code EC = sys::Process::GetArgumentVector( |
| 532 | argv, makeArrayRef(argv_, argc_), ArgAllocator); |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 533 | if (EC) { |
David Majnemer | 6e08126 | 2015-10-15 01:27:19 +0000 | [diff] [blame] | 534 | errs() << "error: couldn't get arguments: " << EC.message() << '\n'; |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 535 | return 1; |
| 536 | } |
| 537 | |
| 538 | llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. |
| 539 | |
| 540 | cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 541 | if (opts::All) { |
| 542 | opts::Compilands = true; |
| 543 | opts::Symbols = true; |
| 544 | opts::Globals = true; |
| 545 | opts::Types = true; |
Zachary Turner | e5cb269 | 2015-05-01 20:24:26 +0000 | [diff] [blame] | 546 | opts::Externals = true; |
Zachary Turner | 7797c72 | 2015-03-02 04:39:56 +0000 | [diff] [blame] | 547 | } |
| 548 | if (opts::ExcludeCompilerGenerated) { |
| 549 | opts::ExcludeTypes.push_back("__vc_attributes"); |
| 550 | opts::ExcludeCompilands.push_back("* Linker *"); |
| 551 | } |
| 552 | if (opts::ExcludeSystemLibraries) { |
| 553 | opts::ExcludeCompilands.push_back( |
| 554 | "f:\\binaries\\Intermediate\\vctools\\crt_bld"); |
| 555 | } |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 556 | |
Zachary Turner | 8d7fa9b | 2015-02-10 22:47:14 +0000 | [diff] [blame] | 557 | #if defined(HAVE_DIA_SDK) |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 558 | CoInitializeEx(nullptr, COINIT_MULTITHREADED); |
Zachary Turner | 8d7fa9b | 2015-02-10 22:47:14 +0000 | [diff] [blame] | 559 | #endif |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 560 | |
| 561 | std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), |
| 562 | dumpInput); |
| 563 | |
Zachary Turner | 8d7fa9b | 2015-02-10 22:47:14 +0000 | [diff] [blame] | 564 | #if defined(HAVE_DIA_SDK) |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 565 | CoUninitialize(); |
Zachary Turner | 8d7fa9b | 2015-02-10 22:47:14 +0000 | [diff] [blame] | 566 | #endif |
| 567 | |
Zachary Turner | fcb14ad | 2015-01-27 20:46:21 +0000 | [diff] [blame] | 568 | return 0; |
| 569 | } |