llvm.org GIT mirror llvm / 3eda006
[PDB] Support dumping injected sources via the DIA reader. Injected sources are basically a way to add actual source file content to your PDB. Presumably you could use this for shipping your source code with your debug information, but in practice I can only find this being used for embedding natvis files inside of PDBs. In order to effectively test LLVM's natvis file injection, we need a way to dump the injected sources of a PDB in a way that is authoritative (i.e. based on Microsoft's understanding of the PDB format, and not LLVM's). To this end, I've added support for dumping injected sources via DIA. I made a PDB file that used the /natvis option to generate a test case. Differential Revision: https://reviews.llvm.org/D44405 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@327428 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 1 year, 6 months ago
19 changed file(s) with 435 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //==- DIAEnumInjectedSources.h - DIA Injected Sources Enumerator -*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_PDB_DIA_DIAENUMINJECTEDSOURCES_H
10 #define LLVM_DEBUGINFO_PDB_DIA_DIAENUMINJECTEDSOURCES_H
11
12 #include "DIASupport.h"
13 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
14 #include "llvm/DebugInfo/PDB/IPDBInjectedSource.h"
15
16 namespace llvm {
17 namespace pdb {
18 class DIASession;
19
20 class DIAEnumInjectedSources : public IPDBEnumChildren {
21 public:
22 explicit DIAEnumInjectedSources(
23 const DIASession &PDBSession,
24 CComPtr DiaEnumerator);
25
26 uint32_t getChildCount() const override;
27 ChildTypePtr getChildAtIndex(uint32_t Index) const override;
28 ChildTypePtr getNext() override;
29 void reset() override;
30 DIAEnumInjectedSources *clone() const override;
31
32 private:
33 const DIASession &Session;
34 CComPtr Enumerator;
35 };
36 } // namespace pdb
37 } // namespace llvm
38
39 #endif // LLVM_DEBUGINFO_PDB_DIA_DIAENUMINJECTEDSOURCES_H
0 //===- DIAInjectedSource.h - DIA impl for IPDBInjectedSource ----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_PDB_DIA_DIAINJECTEDSOURCE_H
10 #define LLVM_DEBUGINFO_PDB_DIA_DIAINJECTEDSOURCE_H
11
12 #include "DIASupport.h"
13 #include "llvm/DebugInfo/PDB/IPDBInjectedSource.h"
14
15 namespace llvm {
16 namespace pdb {
17 class DIASession;
18
19 class DIAInjectedSource : public IPDBInjectedSource {
20 public:
21 explicit DIAInjectedSource(const DIASession &Session,
22 CComPtr DiaSourceFile);
23
24 uint32_t getCrc32() const override;
25 uint64_t getCodeByteSize() const override;
26 std::string getFileName() const override;
27 std::string getObjectFileName() const override;
28 std::string getVirtualFileName() const override;
29 PDB_SourceCompression getCompression() const override;
30 std::string getCode() const override;
31
32 private:
33 const DIASession &Session;
34 CComPtr SourceFile;
35 };
36 } // namespace pdb
37 } // namespace llvm
38
39 #endif // LLVM_DEBUGINFO_PDB_DIA_DIAINJECTEDSOURCE_H
6464 std::unique_ptr getDebugStreams() const override;
6565
6666 std::unique_ptr getEnumTables() const override;
67
68 std::unique_ptr getInjectedSources() const override;
69
6770 private:
6871 CComPtr Session;
6972 };
0 //===- DIAUtils.h - Utility functions for working with DIA ------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_PDB_DIA_DIAUTILS_H
10 #define LLVM_DEBUGINFO_PDB_DIA_DIAUTILS_H
11
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/Support/ConvertUTF.h"
14
15 template
16 std::string invokeBstrMethod(Obj &Object,
17 HRESULT (__stdcall Obj::*Func)(BSTR *)) {
18 CComBSTR Str16;
19 HRESULT Result = (Object.*Func)(&Str16);
20 if (S_OK != Result)
21 return std::string();
22
23 std::string Str8;
24 llvm::ArrayRef StrBytes(reinterpret_cast(Str16.m_str),
25 Str16.ByteLength());
26 llvm::convertUTF16ToUTF8String(StrBytes, Str8);
27 return Str8;
28 }
29
30 #endif // LLVM_DEBUGINFO_PDB_DIA_DIAUTILS_H
0 //===- IPDBInjectedSource.h - base class for PDB injected file --*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_PDB_IPDBINJECTEDSOURCE_H
10 #define LLVM_DEBUGINFO_PDB_IPDBINJECTEDSOURCE_H
11
12 #include "PDBTypes.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include
15 #include
16
17 namespace llvm {
18 class raw_ostream;
19
20 namespace pdb {
21
22 /// IPDBInjectedSource defines an interface used to represent source files
23 /// which were injected directly into the PDB file during the compilation
24 /// process. This is used, for example, to add natvis files to a PDB, but
25 /// in theory could be used to add arbitrary source code.
26 class IPDBInjectedSource {
27 public:
28 virtual ~IPDBInjectedSource();
29
30 virtual uint32_t getCrc32() const = 0;
31 virtual uint64_t getCodeByteSize() const = 0;
32 virtual std::string getFileName() const = 0;
33 virtual std::string getObjectFileName() const = 0;
34 virtual std::string getVirtualFileName() const = 0;
35 virtual PDB_SourceCompression getCompression() const = 0;
36 virtual std::string getCode() const = 0;
37 };
38 } // namespace pdb
39 } // namespace llvm
40
41 #endif // LLVM_DEBUGINFO_PDB_IPDBINJECTEDSOURCE_H
6868 virtual std::unique_ptr getDebugStreams() const = 0;
6969
7070 virtual std::unique_ptr getEnumTables() const = 0;
71
72 virtual std::unique_ptr
73 getInjectedSources() const = 0;
7174 };
7275 }
7376 }
8484
8585 std::unique_ptr getEnumTables() const override;
8686
87 std::unique_ptr getInjectedSources() const override;
88
8789 PDBFile &getPDBFile() { return *Pdb; }
8890 const PDBFile &getPDBFile() const { return *Pdb; }
8991
3333 raw_ostream &operator<<(raw_ostream &OS, const PDB_MemberAccess &Access);
3434 raw_ostream &operator<<(raw_ostream &OS, const PDB_UdtType &Type);
3535 raw_ostream &operator<<(raw_ostream &OS, const PDB_Machine &Machine);
36 raw_ostream &operator<<(raw_ostream &OS,
37 const PDB_SourceCompression &Compression);
3638
3739 raw_ostream &operator<<(raw_ostream &OS, const Variant &Value);
3840 raw_ostream &operator<<(raw_ostream &OS, const VersionInfo &Version);
2222 namespace pdb {
2323
2424 class IPDBDataStream;
25 class IPDBInjectedSource;
2526 class IPDBLineNumber;
2627 class IPDBSourceFile;
2728 class IPDBTable;
6465 using IPDBEnumDataStreams = IPDBEnumChildren;
6566 using IPDBEnumLineNumbers = IPDBEnumChildren;
6667 using IPDBEnumTables = IPDBEnumChildren;
68 using IPDBEnumInjectedSources = IPDBEnumChildren;
6769
6870 /// Specifies which PDB reader implementation is to be used. Only a value
6971 /// of PDB_ReaderType::DIA is currently supported, but Native is in the works.
130132 SH5 = 0x1A8,
131133 Thumb = 0x1C2,
132134 WceMipsV2 = 0x169
135 };
136
137 enum class PDB_SourceCompression {
138 None,
139 RunLengthEncoded,
140 Huffman,
141 LZ,
133142 };
134143
135144 /// These values correspond to the CV_call_e enumeration, and are documented
1313 add_pdb_impl_folder(DIA
1414 DIA/DIADataStream.cpp
1515 DIA/DIAEnumDebugStreams.cpp
16 DIA/DIAEnumInjectedSources.cpp
1617 DIA/DIAEnumLineNumbers.cpp
1718 DIA/DIAEnumSourceFiles.cpp
1819 DIA/DIAEnumSymbols.cpp
1920 DIA/DIAEnumTables.cpp
2021 DIA/DIAError.cpp
22 DIA/DIAInjectedSource.cpp
2123 DIA/DIALineNumber.cpp
2224 DIA/DIARawSymbol.cpp
2325 DIA/DIASession.cpp
0 //==- DIAEnumSourceFiles.cpp - DIA Source File Enumerator impl ---*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h"
10 #include "llvm/DebugInfo/PDB/DIA/DIAInjectedSource.h"
11 #include "llvm/DebugInfo/PDB/PDBSymbol.h"
12
13 using namespace llvm;
14 using namespace llvm::pdb;
15
16 DIAEnumInjectedSources::DIAEnumInjectedSources(
17 const DIASession &PDBSession,
18 CComPtr DiaEnumerator)
19 : Session(PDBSession), Enumerator(DiaEnumerator) {}
20
21 uint32_t DIAEnumInjectedSources::getChildCount() const {
22 LONG Count = 0;
23 return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0;
24 }
25
26 std::unique_ptr
27 DIAEnumInjectedSources::getChildAtIndex(uint32_t Index) const {
28 CComPtr Item;
29 if (S_OK != Enumerator->Item(Index, &Item))
30 return nullptr;
31
32 return std::unique_ptr(
33 new DIAInjectedSource(Session, Item));
34 }
35
36 std::unique_ptr DIAEnumInjectedSources::getNext() {
37 CComPtr Item;
38 ULONG NumFetched = 0;
39 if (S_OK != Enumerator->Next(1, &Item, &NumFetched))
40 return nullptr;
41
42 return std::unique_ptr(
43 new DIAInjectedSource(Session, Item));
44 }
45
46 void DIAEnumInjectedSources::reset() { Enumerator->Reset(); }
47
48 DIAEnumInjectedSources *DIAEnumInjectedSources::clone() const {
49 CComPtr EnumeratorClone;
50 if (S_OK != Enumerator->Clone(&EnumeratorClone))
51 return nullptr;
52 return new DIAEnumInjectedSources(Session, EnumeratorClone);
53 }
0 //===- DIAInjectedSource.cpp - DIA impl for IPDBInjectedSource --*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/PDB/DIA/DIAInjectedSource.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
12 #include "llvm/DebugInfo/PDB/DIA/DIASession.h"
13 #include "llvm/DebugInfo/PDB/DIA/DIAUtils.h"
14
15 using namespace llvm;
16 using namespace llvm::pdb;
17
18 DIAInjectedSource::DIAInjectedSource(const DIASession &Session,
19 CComPtr DiaSourceFile)
20 : Session(Session), SourceFile(DiaSourceFile) {}
21
22 uint32_t DIAInjectedSource::getCrc32() const {
23 DWORD Crc;
24 return (S_OK == SourceFile->get_crc(&Crc)) ? Crc : 0;
25 }
26
27 uint64_t DIAInjectedSource::getCodeByteSize() const {
28 ULONGLONG Size;
29 return (S_OK == SourceFile->get_length(&Size)) ? Size : 0;
30 }
31
32 std::string DIAInjectedSource::getFileName() const {
33 return invokeBstrMethod(*SourceFile, &IDiaInjectedSource::get_filename);
34 }
35
36 std::string DIAInjectedSource::getObjectFileName() const {
37 return invokeBstrMethod(*SourceFile, &IDiaInjectedSource::get_objectFilename);
38 }
39
40 std::string DIAInjectedSource::getVirtualFileName() const {
41 return invokeBstrMethod(*SourceFile,
42 &IDiaInjectedSource::get_virtualFilename);
43 }
44
45 PDB_SourceCompression DIAInjectedSource::getCompression() const {
46 DWORD Compression = 0;
47 if (S_OK != SourceFile->get_sourceCompression(&Compression))
48 return PDB_SourceCompression::None;
49 return static_cast(Compression);
50 }
51
52 std::string DIAInjectedSource::getCode() const {
53 DWORD DataSize;
54 if (S_OK != SourceFile->get_source(0, &DataSize, nullptr))
55 return "";
56
57 std::vector Buffer(DataSize);
58 if (S_OK != SourceFile->get_source(DataSize, &DataSize, Buffer.data()))
59 return "";
60 assert(Buffer.size() == DataSize);
61 return std::string(reinterpret_cast(Buffer.data()),
62 Buffer.size());
63 }
88 #include "llvm/DebugInfo/PDB/DIA/DIASession.h"
99 #include "llvm/ADT/STLExtras.h"
1010 #include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
11 #include "llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h"
1112 #include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"
1213 #include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"
1314 #include "llvm/DebugInfo/PDB/DIA/DIAEnumTables.h"
309310
310311 return llvm::make_unique(DiaEnumerator);
311312 }
313
314 static CComPtr
315 getEnumInjectedSources(IDiaSession &Session) {
316 CComPtr EIS;
317 CComPtr ET;
318 CComPtr Table;
319 ULONG Count = 0;
320
321 if (Session.getEnumTables(&ET) != S_OK)
322 return nullptr;
323
324 while (ET->Next(1, &Table, &Count) == S_OK && Count == 1) {
325 // There is only one table that matches the given iid
326 if (S_OK ==
327 Table->QueryInterface(__uuidof(IDiaEnumInjectedSources), (void **)&EIS))
328 break;
329 Table.Release();
330 }
331 return EIS;
332 }
333 std::unique_ptr
334 DIASession::getInjectedSources() const {
335 CComPtr Files = getEnumInjectedSources(*Session);
336 if (!Files)
337 return nullptr;
338
339 return llvm::make_unique(*this, Files);
340 }
248248 std::unique_ptr NativeSession::getEnumTables() const {
249249 return nullptr;
250250 }
251
252 std::unique_ptr
253 NativeSession::getInjectedSources() const {
254 return nullptr;
255 }
253253 return OS;
254254 }
255255
256 raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
257 const PDB_SourceCompression &Compression) {
258 switch (Compression) {
259 CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, None, OS)
260 CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, Huffman, OS)
261 CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, LZ, OS)
262 CASE_OUTPUT_ENUM_CLASS_STR(PDB_SourceCompression, RunLengthEncoded, "RLE",
263 OS)
264 }
265 return OS;
266 }
267
256268 raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const Variant &Value) {
257269 switch (Value.Type) {
258270 case PDB_VariantType::Bool:
1111 //===----------------------------------------------------------------------===//
1212
1313 #include "llvm/DebugInfo/PDB/IPDBDataStream.h"
14 #include "llvm/DebugInfo/PDB/IPDBInjectedSource.h"
1415 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
1516 #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
1617 #include "llvm/DebugInfo/PDB/IPDBSession.h"
2829 IPDBLineNumber::~IPDBLineNumber() = default;
2930
3031 IPDBTable::~IPDBTable() = default;
32
33 IPDBInjectedSource::~IPDBInjectedSource() = default;
0 ; RUN: llvm-pdbutil pretty -injected-sources -injected-source-content \
1 ; RUN: %p/Inputs/InjectedSource.pdb | FileCheck %s
2 ; RUN: llvm-pdbutil pretty -injected-sources -injected-source-content \
3 ; RUN: %p/Inputs/ClassLayoutTest.pdb | FileCheck --check-prefix=NEGATIVE %s
4
5 ; CHECK: ---INJECTED SOURCES---
6 ; CHECK-NEXT: d:\sandbox\natvistest\natvistest\test.natvis (220 bytes): obj=, vname=d:\sandbox\natvistest\natvistest\test.natvis, crc=2374979362, compression=None
7 ; CHECK-NEXT:
8 ; CHECK-NEXT:
9 ; CHECK-NEXT:
10 ; CHECK-NEXT: This is a test
11 ; CHECK-NEXT:
12 ; CHECK-NEXT:
13
14 ; NEGATIVE: ---INJECTED SOURCES---
15 ; NEGATIVE-NEXT: There are no injected sources.
4444 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
4545 #include "llvm/DebugInfo/PDB/GenericError.h"
4646 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
47 #include "llvm/DebugInfo/PDB/IPDBInjectedSource.h"
4748 #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
4849 #include "llvm/DebugInfo/PDB/IPDBSession.h"
4950 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
146147 cl::desc(""),
147148 cl::OneOrMore, cl::sub(PrettySubcommand));
148149
150 cl::opt InjectedSources("injected-sources",
151 cl::desc("Display injected sources"),
152 cl::cat(OtherOptions), cl::sub(PrettySubcommand));
153 cl::opt ShowInjectedSourceContent(
154 "injected-source-content",
155 cl::desc("When displaying an injected source, display the file content"),
156 cl::cat(OtherOptions), cl::sub(PrettySubcommand));
157
149158 cl::opt Compilands("compilands", cl::desc("Display compilands"),
150159 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
151160 cl::opt Symbols("module-syms",
839848 return getTypeLength(*F1) > getTypeLength(*F2);
840849 }
841850
851 static std::string stringOr(std::string Str, std::string IfEmpty) {
852 return (Str.empty()) ? IfEmpty : Str;
853 }
854
855 static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) {
856 auto Sources = Session.getInjectedSources();
857 if (0 == Sources->getChildCount()) {
858 Printer.printLine("There are no injected sources.");
859 return;
860 }
861
862 while (auto IS = Sources->getNext()) {
863 Printer.NewLine();
864 std::string File = stringOr(IS->getFileName(), "");
865 uint64_t Size = IS->getCodeByteSize();
866 std::string Obj = stringOr(IS->getObjectFileName(), "");
867 std::string VFName = stringOr(IS->getVirtualFileName(), "");
868 uint32_t CRC = IS->getCrc32();
869
870 std::string CompressionStr;
871 llvm::raw_string_ostream Stream(CompressionStr);
872 Stream << IS->getCompression();
873 WithColor(Printer, PDB_ColorItem::Path).get() << File;
874 Printer << " (";
875 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Size;
876 Printer << " bytes): ";
877 WithColor(Printer, PDB_ColorItem::Keyword).get() << "obj";
878 Printer << "=";
879 WithColor(Printer, PDB_ColorItem::Path).get() << Obj;
880 Printer << ", ";
881 WithColor(Printer, PDB_ColorItem::Keyword).get() << "vname";
882 Printer << "=";
883 WithColor(Printer, PDB_ColorItem::Path).get() << VFName;
884 Printer << ", ";
885 WithColor(Printer, PDB_ColorItem::Keyword).get() << "crc";
886 Printer << "=";
887 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << CRC;
888 Printer << ", ";
889 WithColor(Printer, PDB_ColorItem::Keyword).get() << "compression";
890 Printer << "=";
891 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Stream.str();
892
893 if (!opts::pretty::ShowInjectedSourceContent)
894 continue;
895
896 // Set the indent level to 0 when printing file content.
897 int Indent = Printer.getIndentLevel();
898 Printer.Unindent(Indent);
899
900 Printer.printLine(IS->getCode());
901
902 // Re-indent back to the original level.
903 Printer.Indent(Indent);
904 }
905 }
906
842907 static void dumpPretty(StringRef Path) {
843908 std::unique_ptr Session;
844909
9881053 if (opts::pretty::Lines) {
9891054 Printer.NewLine();
9901055 }
1056 if (opts::pretty::InjectedSources) {
1057 Printer.NewLine();
1058 WithColor(Printer, PDB_ColorItem::SectionHeader).get()
1059 << "---INJECTED SOURCES---";
1060 AutoIndent Indent1(Printer);
1061
1062 if (ReaderType == PDB_ReaderType::Native)
1063 Printer.printLine(
1064 "Injected sources are not supported with the native reader.");
1065 else
1066 dumpInjectedSources(Printer, *Session);
1067 }
1068
9911069 outs().flush();
9921070 }
9931071