[PDB] Resubmit "Support embedding natvis files in PDBs."
authorZachary Turner <zturner@google.com>
Fri, 23 Mar 2018 19:57:25 +0000 (19:57 +0000)
committerZachary Turner <zturner@google.com>
Fri, 23 Mar 2018 19:57:25 +0000 (19:57 +0000)
This was reverted several times due to what ultimately turned out
to be incompatibilities in our serialized hash table format.

Several changes went in prior to this to fix those issues since
they were more fundamental and independent of supporting injected
sources, so now that those are fixed this change should hopefully
pass.

llvm-svn: 328363

17 files changed:
lld/COFF/Config.h
lld/COFF/Driver.cpp
lld/COFF/Options.td
lld/COFF/PDB.cpp
lld/test/COFF/Inputs/generic.yaml [new file with mode: 0644]
lld/test/COFF/Inputs/natvis-1.natvis [new file with mode: 0644]
lld/test/COFF/Inputs/natvis-2.natvis [new file with mode: 0644]
lld/test/COFF/Inputs/natvis-3.natvis [new file with mode: 0644]
lld/test/COFF/pdb-natvis.test [new file with mode: 0644]
lld/test/lit.cfg.py
lld/test/lit.site.cfg.py.in
llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h
llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h
llvm/include/llvm/DebugInfo/PDB/Native/RawConstants.h
llvm/include/llvm/DebugInfo/PDB/Native/RawTypes.h
llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp

index 31fb2f2..1a03a24 100644 (file)
@@ -99,6 +99,7 @@ struct Configuration {
   bool DebugGHashes = false;
   bool ShowTiming = false;
   unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+  std::vector<std::string> NatvisFiles;
   llvm::SmallString<128> PDBPath;
   std::vector<llvm::StringRef> Argv;
 
index 5fb56e4..91a29be 100644 (file)
@@ -933,9 +933,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
 
   // Handle /pdb
   bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash);
-  if (ShouldCreatePDB)
+  if (ShouldCreatePDB) {
     if (auto *Arg = Args.getLastArg(OPT_pdb))
       Config->PDBPath = Arg->getValue();
+    if (Args.hasArg(OPT_natvis))
+      Config->NatvisFiles = Args.getAllArgValues(OPT_natvis);
+  }
 
   // Handle /noentry
   if (Args.hasArg(OPT_noentry)) {
index 7373619..243671d 100644 (file)
@@ -45,6 +45,7 @@ def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
 def opt     : P<"opt", "Control optimizations">;
 def order   : P<"order", "Put functions in order">;
 def out     : P<"out", "Path to file to write output">;
+def natvis : P<"natvis", "Path to natvis file to embed in the PDB">;
 def pdb : P<"pdb", "PDB file path">;
 def section : P<"section", "Specify section attributes">;
 def stack   : P<"stack", "Size of the stack">;
@@ -162,7 +163,6 @@ def delay : QF<"delay">;
 def errorreport : QF<"errorreport">;
 def idlout : QF<"idlout">;
 def maxilksize : QF<"maxilksize">;
-def natvis : QF<"natvis">;
 def pdbaltpath : QF<"pdbaltpath">;
 def tlbid : QF<"tlbid">;
 def tlbout : QF<"tlbout">;
index 2287dda..0fee03d 100644 (file)
@@ -95,6 +95,9 @@ public:
   /// Emit the basic PDB structure: initial streams, headers, etc.
   void initialize(const llvm::codeview::DebugInfo &BuildId);
 
+  /// Add natvis files specified on the command line.
+  void addNatvisFiles();
+
   /// Link CodeView from each object file in the symbol table into the PDB.
   void addObjectsToPDB();
 
@@ -966,6 +969,18 @@ void PDBLinker::addObjectsToPDB() {
   }
 }
 
+void PDBLinker::addNatvisFiles() {
+  for (StringRef File : Config->NatvisFiles) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> DataOrErr =
+        MemoryBuffer::getFile(File);
+    if (!DataOrErr) {
+      warn("Cannot open input file: " + File);
+      continue;
+    }
+    Builder.addInjectedSource(File, std::move(*DataOrErr));
+  }
+}
+
 static void addCommonLinkerModuleSymbols(StringRef Path,
                                          pdb::DbiModuleDescriptorBuilder &Mod,
                                          BumpPtrAllocator &Allocator) {
@@ -1043,9 +1058,11 @@ void coff::createPDB(SymbolTable *Symtab,
                      const llvm::codeview::DebugInfo &BuildId) {
   ScopedTimer T1(TotalPdbLinkTimer);
   PDBLinker PDB(Symtab);
+
   PDB.initialize(BuildId);
   PDB.addObjectsToPDB();
   PDB.addSections(OutputSections, SectionTable);
+  PDB.addNatvisFiles();
 
   ScopedTimer T2(DiskCommitTimer);
   PDB.commit();
diff --git a/lld/test/COFF/Inputs/generic.yaml b/lld/test/COFF/Inputs/generic.yaml
new file mode 100644 (file)
index 0000000..88c8765
--- /dev/null
@@ -0,0 +1,282 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC1831C0C7442414000000004889542408894C24044883C418C3
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0104010004220000'
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     04000000F10000002F0000002D003C1101000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F1000000760000002A0047110000000000000000000000001C000000000000000000000003100000000000000000006D61696E000D003E117400000001006172676300120045114F0100000400000017000000000005000D003E110010000001006172677600120045114F01000008000000170000000000050002004F110000F20000002800000000000000000000001C00000000000000020000001C00000000000000020000001700000003000000F40000001800000001000000100139E9A066A1995A99DD01F5A392F26D7C0000F30000003000000000443A5C7372635C6C6C766D6275696C645C636C5C52656C656173655C7836345C67656E657269632E63707000000000
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [  ]
+              Machine:         X64
+              FrontendMajor:   7
+              FrontendMinor:   0
+              FrontendBuild:   0
+              FrontendQFE:     0
+              BackendMajor:    7000
+              BackendMinor:    0
+              BackendBuild:    0
+              BackendQFE:      0
+              Version:         'clang version 7.0.0 '
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              CodeSize:        28
+              DbgStart:        0
+              DbgEnd:          0
+              FunctionType:    4099
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_LOCAL
+            LocalSym:
+              Type:            116
+              Flags:           [ IsParameter ]
+              VarName:         argc
+          - Kind:            S_DEFRANGE_REGISTER_REL
+            DefRangeRegisterRelSym:
+              Register:        335
+              Flags:           0
+              BasePointerOffset: 4
+              Range:
+                OffsetStart:     23
+                ISectStart:      0
+                Range:           5
+              Gaps:
+          - Kind:            S_LOCAL
+            LocalSym:
+              Type:            4096
+              Flags:           [ IsParameter ]
+              VarName:         argv
+          - Kind:            S_DEFRANGE_REGISTER_REL
+            DefRangeRegisterRelSym:
+              Register:        335
+              Flags:           0
+              BasePointerOffset: 8
+              Range:
+                OffsetStart:     23
+                ISectStart:      0
+                Range:           5
+              Gaps:
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        28
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'D:\src\llvmbuild\cl\Release\x64\generic.cpp'
+            Lines:
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     false
+                EndDelta:        0
+              - Offset:          23
+                LineStart:       3
+                IsStatement:     false
+                EndDelta:        0
+            Columns:
+      - !FileChecksums
+        Checksums:
+          - FileName:        'D:\src\llvmbuild\cl\Release\x64\generic.cpp'
+            Kind:            MD5
+            Checksum:        39E9A066A1995A99DD01F5A392F26D7C
+      - !StringTable
+        Strings:
+          - 'D:\src\llvmbuild\cl\Release\x64\generic.cpp'
+          - ''
+          - ''
+          - ''
+    Relocations:
+      - VirtualAddress:  100
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  104
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  139
+        SymbolName:      .text
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  143
+        SymbolName:      .text
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  174
+        SymbolName:      .text
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  178
+        SymbolName:      .text
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  196
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  200
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     040000000A000210700600000C0001000E0001120200000074000000001000000E0008107400000000000200011000001200011600000000021000006D61696E00F3F2F1
+    Types:
+      - Kind:            LF_POINTER
+        Pointer:
+          ReferentType:    1648
+          Attrs:           65548
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [ 116, 4096 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  2
+          ArgumentList:    4097
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4098
+          Name:            main
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000001C00000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        594448369
+      Number:          1
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1192424177
+      Number:          4
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          48
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        149686238
+      Number:          5
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          324
+      NumberOfRelocations: 8
+      NumberOfLinenumbers: 0
+      CheckSum:        4196717433
+      Number:          6
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          68
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        485351071
+      Number:          7
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        722740324
+      Number:          8
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/lld/test/COFF/Inputs/natvis-1.natvis b/lld/test/COFF/Inputs/natvis-1.natvis
new file mode 100644 (file)
index 0000000..8797a36
--- /dev/null
@@ -0,0 +1 @@
+1st Natvis Test
diff --git a/lld/test/COFF/Inputs/natvis-2.natvis b/lld/test/COFF/Inputs/natvis-2.natvis
new file mode 100644 (file)
index 0000000..50ba443
--- /dev/null
@@ -0,0 +1 @@
+Second Natvis Test
diff --git a/lld/test/COFF/Inputs/natvis-3.natvis b/lld/test/COFF/Inputs/natvis-3.natvis
new file mode 100644 (file)
index 0000000..a10b1a1
--- /dev/null
@@ -0,0 +1 @@
+Third Natvis Test
diff --git a/lld/test/COFF/pdb-natvis.test b/lld/test/COFF/pdb-natvis.test
new file mode 100644 (file)
index 0000000..2db68b6
--- /dev/null
@@ -0,0 +1,26 @@
+REQUIRES: diasdk
+
+RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj
+RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/natvis-1.natvis \
+RUN:   /NATVIS:%p/Inputs/natvis-2.natvis /NATVIS:%p/Inputs/natvis-3.natvis /OUT:%t.exe \
+RUN:   /PDB:%t.pdb
+RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \
+RUN:   --check-prefix=CHECK-FIRST %s
+RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \
+RUN:   --check-prefix=CHECK-SECOND %s
+RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \
+RUN:   --check-prefix=CHECK-THIRD %s
+
+RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/test2.natvis \
+RUN:   /OUT:%t.exe /PDB:%t.pdb 2>&1 | FileCheck --check-prefix=CHECK-MISSING %s
+
+CHECK-FIRST:      {{.*}}natvis-1.natvis (16 bytes): obj=<null>, vname={{.*}}natvis-1.natvis, crc=355285096, compression=None
+CHECK-FIRST-NEXT: 1st Natvis Test
+
+CHECK-SECOND:      {{.*}}natvis-2.natvis (19 bytes): obj=<null>, vname={{.*}}natvis-2.natvis, crc=4252640062, compression=None
+CHECK-SECOND-NEXT: Second Natvis Test
+
+CHECK-THIRD:      {{.*}}natvis-3.natvis (18 bytes): obj=<null>, vname={{.*}}natvis-3.natvis, crc=2069719849, compression=None
+CHECK-THIRD-NEXT: Third Natvis Test
+
+CHECK-MISSING: Cannot open input file: {{.*}}test2.natvis
\ No newline at end of file
index e7c2589..8fd1a60 100644 (file)
@@ -85,6 +85,9 @@ if (lit.util.which('cvtres', config.environment['PATH'])) or \
 if (config.llvm_libxml2_enabled == '1'):
     config.available_features.add('libxml2')
 
+if config.have_dia_sdk:
+    config.available_features.add("diasdk")
+
 tar_executable = lit.util.which('tar', config.environment['PATH'])
 if tar_executable:
     tar_version = subprocess.Popen(
index 50593f7..764ab83 100644 (file)
@@ -1,5 +1,8 @@
 @LIT_SITE_CFG_IN_HEADER@
 
+import lit.util
+
+config.have_dia_sdk = lit.util.pythonize_bool("@LLVM_ENABLE_DIA_SDK@")
 config.llvm_src_root = "@LLVM_SOURCE_DIR@"
 config.llvm_obj_root = "@LLVM_BINARY_DIR@"
 config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
index 2604306..58dda71 100644 (file)
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
 
 #include <memory>
 #include <vector>
@@ -55,12 +57,33 @@ public:
 
   Expected<uint32_t> getNamedStreamIndex(StringRef Name) const;
   Error addNamedStream(StringRef Name, StringRef Data);
+  void addInjectedSource(StringRef Name, std::unique_ptr<MemoryBuffer> Buffer);
 
 private:
+  struct InjectedSourceDescriptor {
+    // The full name of the stream that contains the contents of this injected
+    // source.  This is built as a concatenation of the literal "/src/files"
+    // plus the "vname".
+    std::string StreamName;
+
+    // The exact name of the file name as specified by the user.
+    uint32_t NameIndex;
+
+    // The string table index of the "vname" of the file.  As far as we
+    // understand, this is the same as the name, except it is lowercased and
+    // forward slashes are converted to backslashes.
+    uint32_t VNameIndex;
+    std::unique_ptr<MemoryBuffer> Content;
+  };
+
   Expected<msf::MSFLayout> finalizeMsfLayout();
   Expected<uint32_t> allocateNamedStream(StringRef Name, uint32_t Size);
 
   void commitFpm(WritableBinaryStream &MsfBuffer, const msf::MSFLayout &Layout);
+  void commitInjectedSources(WritableBinaryStream &MsfBuffer,
+                             const msf::MSFLayout &Layout);
+  void commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
+                            const msf::MSFLayout &Layout);
 
   BumpPtrAllocator &Allocator;
 
@@ -72,6 +95,11 @@ private:
   std::unique_ptr<TpiStreamBuilder> Ipi;
 
   PDBStringTableBuilder Strings;
+  StringTableHashTraits InjectedSourceHashTraits;
+  HashTable<SrcHeaderBlockEntry, StringTableHashTraits> InjectedSourceTable;
+
+  SmallVector<InjectedSourceDescriptor, 2> InjectedSources;
+
   NamedStreamMap NamedStreams;
   DenseMap<uint32_t, std::string> NamedStreamData;
 };
index 1af99ad..0f81c18 100644 (file)
@@ -31,6 +31,16 @@ struct MSFLayout;
 namespace pdb {
 
 class PDBFileBuilder;
+class PDBStringTableBuilder;
+
+struct StringTableHashTraits {
+  PDBStringTableBuilder *Table;
+
+  explicit StringTableHashTraits(PDBStringTableBuilder &Table);
+  uint32_t hashLookupKey(StringRef S) const;
+  StringRef storageKeyToLookupKey(uint32_t Offset) const;
+  uint32_t lookupKeyToStorageKey(StringRef S);
+};
 
 class PDBStringTableBuilder {
 public:
index bb1d097..fbbd331 100644 (file)
@@ -32,6 +32,8 @@ enum PdbRaw_ImplVer : uint32_t {
   PdbImplVC140 = 20140508,
 };
 
+enum class PdbRaw_SrcHeaderBlockVer : uint32_t { SrcVerOne = 19980827 };
+
 enum class PdbRaw_FeatureSig : uint32_t {
   VC110 = PdbImplVC110,
   VC140 = PdbImplVC140,
index 8cc0836..5cc8821 100644 (file)
@@ -328,6 +328,34 @@ struct PDBStringTableHeader {
 
 const uint32_t PDBStringTableSignature = 0xEFFEEFFE;
 
+/// The header preceding the /src/headerblock stream.
+struct SrcHeaderBlockHeader {
+  support::ulittle32_t Version; // PdbRaw_SrcHeaderBlockVer enumeration.
+  support::ulittle32_t Size;    // Size of entire stream.
+  uint64_t FileTime;            // Time stamp (Windows FILETIME format).
+  support::ulittle32_t Age;     // Age
+  uint8_t Padding[44];          // Pad to 64 bytes.
+};
+static_assert(sizeof(SrcHeaderBlockHeader) == 64, "Incorrect struct size!");
+
+/// A single file record entry within the /src/headerblock stream.
+struct SrcHeaderBlockEntry {
+  support::ulittle32_t Size;     // Record Length.
+  support::ulittle32_t Version;  // PdbRaw_SrcHeaderBlockVer enumeration.
+  support::ulittle32_t CRC;      // CRC of the original file contents.
+  support::ulittle32_t FileSize; // Size of original source file.
+  support::ulittle32_t FileNI;   // String table index of file name.
+  support::ulittle32_t ObjNI;    // String table index of object name.
+  support::ulittle32_t VFileNI;  // String table index of virtual file name.
+  uint8_t Compression;           // PDB_SourceCompression enumeration.
+  uint8_t IsVirtual;             // Is this a virtual file (injected)?
+  short Padding;                 // Pad to 4 bytes.
+  char Reserved[8];
+};
+
+constexpr int I = sizeof(SrcHeaderBlockEntry);
+static_assert(sizeof(SrcHeaderBlockEntry) == 40, "Incorrect struct size!");
+
 } // namespace pdb
 } // namespace llvm
 
index 38bba9e..7704858 100644 (file)
@@ -24,6 +24,8 @@
 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
 #include "llvm/Support/BinaryStream.h"
 #include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/JamCRC.h"
+#include "llvm/Support/Path.h"
 
 using namespace llvm;
 using namespace llvm::codeview;
@@ -32,7 +34,8 @@ using namespace llvm::pdb;
 using namespace llvm::support;
 
 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
-    : Allocator(Allocator) {}
+    : Allocator(Allocator), InjectedSourceHashTraits(Strings),
+      InjectedSourceTable(2, InjectedSourceHashTraits) {}
 
 PDBFileBuilder::~PDBFileBuilder() {}
 
@@ -97,6 +100,28 @@ Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
   return Error::success();
 }
 
+void PDBFileBuilder::addInjectedSource(StringRef Name,
+                                       std::unique_ptr<MemoryBuffer> Buffer) {
+  // Stream names must be exact matches, since they get looked up in a hash
+  // table and the hash value is dependent on the exact contents of the string.
+  // link.exe lowercases a path and converts / to \, so we must do the same.
+  SmallString<64> VName;
+  sys::path::native(Name.lower(), VName);
+
+  uint32_t NI = getStringTableBuilder().insert(Name);
+  uint32_t VNI = getStringTableBuilder().insert(VName);
+
+  InjectedSourceDescriptor Desc;
+  Desc.Content = std::move(Buffer);
+  Desc.NameIndex = NI;
+  Desc.VNameIndex = VNI;
+  Desc.StreamName = "/src/files/";
+
+  Desc.StreamName += VName;
+
+  InjectedSources.push_back(std::move(Desc));
+}
+
 Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
 
   if (Ipi && Ipi->getRecordCount() > 0) {
@@ -147,6 +172,47 @@ Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
       return std::move(EC);
   }
 
+  if (!InjectedSources.empty()) {
+    for (const auto &IS : InjectedSources) {
+      JamCRC CRC(0);
+      CRC.update(makeArrayRef(IS.Content->getBufferStart(),
+                              IS.Content->getBufferSize()));
+
+      SrcHeaderBlockEntry Entry;
+      ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
+      Entry.Size = sizeof(SrcHeaderBlockEntry);
+      Entry.FileSize = IS.Content->getBufferSize();
+      Entry.FileNI = IS.NameIndex;
+      Entry.VFileNI = IS.VNameIndex;
+      Entry.ObjNI = 1;
+      Entry.IsVirtual = 0;
+      Entry.Version =
+          static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
+      Entry.CRC = CRC.getCRC();
+      StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
+      InjectedSourceTable.set_as(VName, std::move(Entry));
+    }
+
+    uint32_t SrcHeaderBlockSize =
+        sizeof(SrcHeaderBlockHeader) +
+        InjectedSourceTable.calculateSerializedLength();
+    SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
+    if (!SN)
+      return SN.takeError();
+    for (const auto &IS : InjectedSources) {
+      SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
+      if (!SN)
+        return SN.takeError();
+    }
+  }
+
+  // Do this last, since it relies on the named stream map being complete, and
+  // that can be updated by previous steps in the finalization.
+  if (Info) {
+    if (auto EC = Info->finalizeMsfLayout())
+      return std::move(EC);
+  }
+
   return Msf->build();
 }
 
@@ -182,6 +248,45 @@ void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
   assert(FpmWriter.bytesRemaining() == 0);
 }
 
+void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
+                                          const msf::MSFLayout &Layout) {
+  assert(!InjectedSourceTable.empty());
+
+  uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
+  auto Stream = WritableMappedBlockStream::createIndexedStream(
+      Layout, MsfBuffer, SN, Allocator);
+  BinaryStreamWriter Writer(*Stream);
+
+  SrcHeaderBlockHeader Header;
+  ::memset(&Header, 0, sizeof(Header));
+  Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
+  Header.Size = Writer.bytesRemaining();
+
+  cantFail(Writer.writeObject(Header));
+  cantFail(InjectedSourceTable.commit(Writer));
+
+  assert(Writer.bytesRemaining() == 0);
+}
+
+void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
+                                           const msf::MSFLayout &Layout) {
+  if (InjectedSourceTable.empty())
+    return;
+
+  commitSrcHeaderBlock(MsfBuffer, Layout);
+
+  for (const auto &IS : InjectedSources) {
+    uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
+
+    auto SourceStream = WritableMappedBlockStream::createIndexedStream(
+        Layout, MsfBuffer, SN, Allocator);
+    BinaryStreamWriter SourceWriter(*SourceStream);
+    assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
+    cantFail(SourceWriter.writeBytes(
+        arrayRefFromStringRef(IS.Content->getBuffer())));
+  }
+}
+
 Error PDBFileBuilder::commit(StringRef Filename) {
   assert(!Filename.empty());
   auto ExpectedLayout = finalizeMsfLayout();
@@ -277,6 +382,8 @@ Error PDBFileBuilder::commit(StringRef Filename) {
   InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
       FOB->getBufferStart() + InfoStreamFileOffset);
 
+  commitInjectedSources(Buffer, Layout);
+
   // Set the build id at the very end, after every other byte of the PDB
   // has been written.
   // FIXME: Use a hash of the PDB rather than time(nullptr) for the signature.
index 0975d9e..d9dcabf 100644 (file)
@@ -23,6 +23,21 @@ using namespace llvm::support;
 using namespace llvm::support::endian;
 using namespace llvm::pdb;
 
+StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table)
+    : Table(&Table) {}
+
+uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const {
+  return Table->getIdForString(S);
+}
+
+StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const {
+  return Table->getStringForId(Offset);
+}
+
+uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) {
+  return Table->insert(S);
+}
+
 uint32_t PDBStringTableBuilder::insert(StringRef S) {
   return Strings.insert(S);
 }