Resubmit "[codeview] Make obj2yaml/yaml2obj support .debug$S..."
authorZachary Turner <zturner@google.com>
Wed, 14 Jun 2017 15:59:27 +0000 (15:59 +0000)
committerZachary Turner <zturner@google.com>
Wed, 14 Jun 2017 15:59:27 +0000 (15:59 +0000)
This was originally reverted because of some non-deterministic
failures on certain buildbots.  Luckily ASAN eventually caught
this as a stack-use-after-scope, so the fix is included in
this patch.

llvm-svn: 305393

31 files changed:
lld/test/COFF/Inputs/pdb1.yaml
lld/test/COFF/Inputs/pdb2.yaml
lld/test/COFF/sort-debug.test
llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h
llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h
llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h
llvm/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h [new file with mode: 0644]
llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h
llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h
llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h
llvm/include/llvm/ObjectYAML/COFFYAML.h
llvm/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h
llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h
llvm/lib/DebugInfo/CodeView/CMakeLists.txt
llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp [new file with mode: 0644]
llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp
llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
llvm/lib/ObjectYAML/COFFYAML.cpp
llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp
llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp
llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
llvm/tools/obj2yaml/CMakeLists.txt
llvm/tools/obj2yaml/coff2yaml.cpp
llvm/tools/yaml2obj/CMakeLists.txt
llvm/tools/yaml2obj/yaml2coff.cpp

index 30ddbad..566f2da 100644 (file)
@@ -10,7 +10,77 @@ sections:
   - Name:            '.debug$S'
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
     Alignment:       1
-    SectionData:     04000000F1000000580000001A00011100000000443A5C625C72657434322D6D61696E2E6F626A003A003C1100600000D00013000000F259000013000000F25900004D6963726F736F667420285229204F7074696D697A696E6720436F6D70696C657200F10000004E0000002A0047110000000000000000000000000E000000040000000900000005100000000000000000006D61696E001C001210280000000000000000000000000000000000000000000042110002004F110000F20000002000000000000000000000000E0000000000000001000000140000000000000002000080F400000018000000010000001001C538722F63570DF6705DDE06FE96E5D10000F30000001300000000643A5C625C72657434322D6D61696E2E630000F10000000800000006004C110E100000
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'D:\b\ret42-main.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   23026
+              FrontendQFE:     0
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    23026
+              BackendQFE:      0
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        14
+              DbgStart:        4
+              DbgEnd:          9
+              FunctionType:    4101
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 40
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        14
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'd:\b\ret42-main.c'
+            Lines:
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !FileChecksums
+        Checksums:
+          - FileName:        'd:\b\ret42-main.c'
+            Kind:            MD5
+            Checksum:        C538722F63570DF6705DDE06FE96E5D1
+      - !StringTable
+        Strings:
+          - 'd:\b\ret42-main.c'
+      - !Symbols
+        Records:
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:
+              BuildId:         4110
     Relocations:
       - VirtualAddress:  140
         SymbolName:      main
@@ -27,7 +97,71 @@ sections:
   - Name:            '.debug$T'
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
     Alignment:       1
-    SectionData:     0400000006000112000000000E0008107400000000000000001000000A000210011000000C0001000A00011201000000000000000E0008107400000000000000031000001200011600000000041000006D61696E00F3F2F10E0001160000000001100000666F6F000E00051600000000443A5C6200F3F2F12200051600000000433A5C767331345C56435C42494E5C616D6436345C636C2E6578650002010516000000002D5A37202D63202D4D54202D49433A5C767331345C56435C494E434C554445202D49433A5C767331345C56435C41544C4D46435C494E434C554445202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C31305C696E636C7564655C31302E302E31303135302E305C7563727422202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C4E4554465853444B5C342E365C696E636C7564655C756D22202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C382E315C696E636C7564655C73686172656422000A0004160100000009100000820005160A100000202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C382E315C696E636C7564655C756D22202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C382E315C696E636C7564655C77696E727422202D5443202D5800F3F2F1160005160000000072657434322D6D61696E2E6300F3F2F11600051600000000443A5C625C76633134302E70646200F11A000316050007100000081000000C1000000D1000000B100000F2F1
+    Types:
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_POINTER
+        Pointer:
+          ReferentType:    4097
+          Attrs:           65548
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4099
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4100
+          Name:            main
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            foo
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'C:\vs14\VC\BIN\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:
+          StringIndices:   [ 4105 ]
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              4106
+          String:          ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          ret42-main.c
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:
+          ArgIndices:      [ 4103, 4104, 4108, 4109, 4107 ]
   - Name:            '.text$mn'
     Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
     Alignment:       16
index 7a446b4..6507951 100644 (file)
@@ -10,7 +10,77 @@ sections:
   - Name:            '.debug$S'
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
     Alignment:       1
-    SectionData:     04000000F1000000570000001900011100000000443A5C625C72657434322D7375622E6F626A003A003C1100600000D00013000000F259000013000000F25900004D6963726F736F667420285229204F7074696D697A696E6720436F6D70696C65720000F10000004D000000290047110000000000000000000000000600000000000000050000000210000000000000000000666F6F001C001210000000000000000000000000000000000000000000000042110002004F11000000F2000000200000000000000000000000060000000000000001000000140000000000000001000080F400000018000000010000001001EC2D89EFF5A1FEB6B74EE4D79074072F0000F30000001200000000643A5C625C72657434322D7375622E63000000F10000000800000006004C110A100000
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'D:\b\ret42-sub.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   23026
+              FrontendQFE:     0
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    23026
+              BackendQFE:      0
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        6
+              DbgStart:        0
+              DbgEnd:          5
+              FunctionType:    4098
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     foo
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        6
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'd:\b\ret42-sub.c'
+            Lines:
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !FileChecksums
+        Checksums:
+          - FileName:        'd:\b\ret42-sub.c'
+            Kind:            MD5
+            Checksum:        EC2D89EFF5A1FEB6B74EE4D79074072F
+      - !StringTable
+        Strings:
+          - 'd:\b\ret42-sub.c'
+      - !Symbols
+        Records:
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:
+              BuildId:         4106
     Relocations:
       - VirtualAddress:  140
         SymbolName:      foo
@@ -27,7 +97,52 @@ sections:
   - Name:            '.debug$T'
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
     Alignment:       1
-    SectionData:     0400000006000112000000000E0008107400000000000000001000000E0001160000000001100000666F6F000E00051600000000443A5C6200F3F2F12200051600000000433A5C767331345C56435C42494E5C616D6436345C636C2E6578650002010516000000002D5A37202D63202D4D54202D49433A5C767331345C56435C494E434C554445202D49433A5C767331345C56435C41544C4D46435C494E434C554445202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C31305C696E636C7564655C31302E302E31303135302E305C7563727422202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C4E4554465853444B5C342E365C696E636C7564655C756D22202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C382E315C696E636C7564655C73686172656422000A00041601000000051000008200051606100000202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C382E315C696E636C7564655C756D22202D4922433A5C50726F6772616D2046696C65732028783836295C57696E646F7773204B6974735C382E315C696E636C7564655C77696E727422202D5443202D5800F3F2F1120005160000000072657434322D7375622E63001600051600000000443A5C625C76633134302E70646200F11A00031605000310000004100000081000000910000007100000F2F1
+    Types:
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            foo
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'C:\vs14\VC\BIN\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:
+          StringIndices:   [ 4101 ]
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              4102
+          String:          ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          ret42-sub.c
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:
+          ArgIndices:      [ 4099, 4100, 4104, 4105, 4103 ]
   - Name:            '.text$mn'
     Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
     Alignment:       16
index b04b41a..3bad013 100644 (file)
@@ -35,7 +35,46 @@ sections:
   - Name:            '.debug$S'
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
     Alignment:       1
-    SectionData:     04000000F1000000300000002A00471100000000000000000000000010000000000000000000000000000000000000000000006D61696E0002004F11F200000024000000000000000000010010000000000000000100000018000000000000000100000000000000F4000000080000000100000000000000F30000003C000000005C7573725C6C6F63616C5C676F6F676C655C686F6D655C6D616A6E656D65725C6C6C766D5C7372635C746F6F6C735C6C6C645C3C737464696E3E00
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        16
+              DbgStart:        0
+              DbgEnd:          0
+              FunctionType:    0
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        16
+        Flags:           [ HasColumnInfo ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        '\usr\local\google\home\majnemer\llvm\src\tools\lld\<stdin>'
+            Lines:
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     false
+                EndDelta:        0
+            Columns:
+              - StartColumn:     0
+                EndColumn:       0
+      - !FileChecksums
+        Checksums:
+          - FileName:        '\usr\local\google\home\majnemer\llvm\src\tools\lld\<stdin>'
+            Kind:            None
+            Checksum:        ''
+      - !StringTable
+        Strings:
+          - '\usr\local\google\home\majnemer\llvm\src\tools\lld\<stdin>'
     Relocations:
       - VirtualAddress:  44
         SymbolName:      _main
index 686b5c4..1e329c7 100644 (file)
@@ -49,6 +49,7 @@ public:
   Error commit(BinaryStreamWriter &Writer) const override;
 
   void addFrameData(const FrameData &Frame);
+  void setFrames(ArrayRef<FrameData> Frames);
 
 private:
   std::vector<FrameData> Frames;
index 49a269d..6947317 100644 (file)
@@ -49,13 +49,13 @@ private:
 
 class DebugSubsectionRecordBuilder {
 public:
-  DebugSubsectionRecordBuilder(std::unique_ptr<DebugSubsection> Subsection,
+  DebugSubsectionRecordBuilder(std::shared_ptr<DebugSubsection> Subsection,
                                CodeViewContainer Container);
   uint32_t calculateSerializedLength();
   Error commit(BinaryStreamWriter &Writer) const;
 
 private:
-  std::unique_ptr<DebugSubsection> Subsection;
+  std::shared_ptr<DebugSubsection> Subsection;
   CodeViewContainer Container;
 };
 
@@ -64,6 +64,9 @@ private:
 template <> struct VarStreamArrayExtractor<codeview::DebugSubsectionRecord> {
   Error operator()(BinaryStreamRef Stream, uint32_t &Length,
                    codeview::DebugSubsectionRecord &Info) {
+    // FIXME: We need to pass the container type through to this function.  In
+    // practice this isn't super important since the subsection header describes
+    // its length and we can just skip it.  It's more important when writing.
     if (auto EC = codeview::DebugSubsectionRecord::initialize(
             Stream, Info, codeview::CodeViewContainer::Pdb))
       return EC;
index d4a3d91..75f749d 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/Support/Error.h"
 #include <cstdint>
 
@@ -30,56 +31,7 @@ class DebugStringTableSubsectionRef;
 class DebugSymbolRVASubsectionRef;
 class DebugSymbolsSubsectionRef;
 class DebugUnknownSubsectionRef;
-
-struct DebugSubsectionState {
-public:
-  // If no subsections are known about initially, we find as much as we can.
-  DebugSubsectionState();
-
-  // If only a string table subsection is given, we find a checksums subsection.
-  explicit DebugSubsectionState(const DebugStringTableSubsectionRef &Strings);
-
-  // If both subsections are given, we don't need to find anything.
-  DebugSubsectionState(const DebugStringTableSubsectionRef &Strings,
-                       const DebugChecksumsSubsectionRef &Checksums);
-
-  template <typename T> void initialize(T &&FragmentRange) {
-    for (const DebugSubsectionRecord &R : FragmentRange) {
-      if (Strings && Checksums)
-        return;
-      if (R.kind() == DebugSubsectionKind::FileChecksums) {
-        initializeChecksums(R);
-        continue;
-      }
-      if (R.kind() == DebugSubsectionKind::StringTable && !Strings) {
-        // While in practice we should never encounter a string table even
-        // though the string table is already initialized, in theory it's
-        // possible.  PDBs are supposed to have one global string table and
-        // then this subsection should not appear.  Whereas object files are
-        // supposed to have this subsection appear exactly once.  However,
-        // for testing purposes it's nice to be able to test this subsection
-        // independently of one format or the other, so for some tests we
-        // manually construct a PDB that contains this subsection in addition
-        // to a global string table.
-        initializeStrings(R);
-        continue;
-      }
-    }
-  }
-
-  const DebugStringTableSubsectionRef &strings() const { return *Strings; }
-  const DebugChecksumsSubsectionRef &checksums() const { return *Checksums; }
-
-private:
-  void initializeStrings(const DebugSubsectionRecord &SR);
-  void initializeChecksums(const DebugSubsectionRecord &FCR);
-
-  std::unique_ptr<DebugStringTableSubsectionRef> OwnedStrings;
-  std::unique_ptr<DebugChecksumsSubsectionRef> OwnedChecksums;
-
-  const DebugStringTableSubsectionRef *Strings = nullptr;
-  const DebugChecksumsSubsectionRef *Checksums = nullptr;
-};
+class StringsAndChecksumsRef;
 
 class DebugSubsectionVisitor {
 public:
@@ -89,38 +41,38 @@ public:
     return Error::success();
   }
   virtual Error visitLines(DebugLinesSubsectionRef &Lines,
-                           const DebugSubsectionState &State) = 0;
+                           const StringsAndChecksumsRef &State) = 0;
   virtual Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,
-                                   const DebugSubsectionState &State) = 0;
+                                   const StringsAndChecksumsRef &State) = 0;
   virtual Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,
-                                  const DebugSubsectionState &State) = 0;
+                                  const StringsAndChecksumsRef &State) = 0;
   virtual Error
   visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE,
-                          const DebugSubsectionState &State) = 0;
+                          const StringsAndChecksumsRef &State) = 0;
   virtual Error
   visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSE,
-                          const DebugSubsectionState &State) = 0;
+                          const StringsAndChecksumsRef &State) = 0;
 
   virtual Error visitStringTable(DebugStringTableSubsectionRef &ST,
-                                 const DebugSubsectionState &State) = 0;
+                                 const StringsAndChecksumsRef &State) = 0;
 
   virtual Error visitSymbols(DebugSymbolsSubsectionRef &CSE,
-                             const DebugSubsectionState &State) = 0;
+                             const StringsAndChecksumsRef &State) = 0;
 
   virtual Error visitFrameData(DebugFrameDataSubsectionRef &FD,
-                               const DebugSubsectionState &State) = 0;
+                               const StringsAndChecksumsRef &State) = 0;
   virtual Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &RVAs,
-                                    const DebugSubsectionState &State) = 0;
+                                    const StringsAndChecksumsRef &State) = 0;
 };
 
 Error visitDebugSubsection(const DebugSubsectionRecord &R,
                            DebugSubsectionVisitor &V,
-                           const DebugSubsectionState &State);
+                           const StringsAndChecksumsRef &State);
 
 namespace detail {
 template <typename T>
 Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V,
-                            DebugSubsectionState &State) {
+                            StringsAndChecksumsRef &State) {
   State.initialize(std::forward<T>(FragmentRange));
 
   for (const DebugSubsectionRecord &L : FragmentRange) {
@@ -133,7 +85,7 @@ Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V,
 
 template <typename T>
 Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V) {
-  DebugSubsectionState State;
+  StringsAndChecksumsRef State;
   return detail::visitDebugSubsections(std::forward<T>(FragmentRange), V,
                                        State);
 }
@@ -141,7 +93,7 @@ Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V) {
 template <typename T>
 Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V,
                             const DebugStringTableSubsectionRef &Strings) {
-  DebugSubsectionState State(Strings);
+  StringsAndChecksumsRef State(Strings);
   return detail::visitDebugSubsections(std::forward<T>(FragmentRange), V,
                                        State);
 }
@@ -150,7 +102,7 @@ template <typename T>
 Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V,
                             const DebugStringTableSubsectionRef &Strings,
                             const DebugChecksumsSubsectionRef &Checksums) {
-  DebugSubsectionState State(Strings, Checksums);
+  StringsAndChecksumsRef State(Strings, Checksums);
   return detail::visitDebugSubsections(std::forward<T>(FragmentRange), V,
                                        State);
 }
diff --git a/llvm/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h b/llvm/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h
new file mode 100644 (file)
index 0000000..4fe5d45
--- /dev/null
@@ -0,0 +1,104 @@
+//===- StringsAndChecksums.h ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_STRINGS_AND_CHECKSUMS_H
+#define LLVM_DEBUGINFO_CODEVIEW_STRINGS_AND_CHECKSUMS_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+
+#include <memory>
+
+namespace llvm {
+namespace codeview {
+
+class DebugSubsectionRecord;
+class DebugChecksumsSubsectionRef;
+class DebugStringTableSubsectionRef;
+class DebugChecksumsSubsection;
+class DebugStringTableSubsection;
+
+class StringsAndChecksumsRef {
+public:
+  // If no subsections are known about initially, we find as much as we can.
+  StringsAndChecksumsRef();
+
+  // If only a string table subsection is given, we find a checksums subsection.
+  explicit StringsAndChecksumsRef(const DebugStringTableSubsectionRef &Strings);
+
+  // If both subsections are given, we don't need to find anything.
+  StringsAndChecksumsRef(const DebugStringTableSubsectionRef &Strings,
+                         const DebugChecksumsSubsectionRef &Checksums);
+
+  template <typename T> void initialize(T &&FragmentRange) {
+    for (const DebugSubsectionRecord &R : FragmentRange) {
+      if (Strings && Checksums)
+        return;
+      if (R.kind() == DebugSubsectionKind::FileChecksums) {
+        initializeChecksums(R);
+        continue;
+      }
+      if (R.kind() == DebugSubsectionKind::StringTable && !Strings) {
+        // While in practice we should never encounter a string table even
+        // though the string table is already initialized, in theory it's
+        // possible.  PDBs are supposed to have one global string table and
+        // then this subsection should not appear.  Whereas object files are
+        // supposed to have this subsection appear exactly once.  However,
+        // for testing purposes it's nice to be able to test this subsection
+        // independently of one format or the other, so for some tests we
+        // manually construct a PDB that contains this subsection in addition
+        // to a global string table.
+        initializeStrings(R);
+        continue;
+      }
+    }
+  }
+
+  const DebugStringTableSubsectionRef &strings() const { return *Strings; }
+  const DebugChecksumsSubsectionRef &checksums() const { return *Checksums; }
+
+  bool hasStrings() const { return Strings != nullptr; }
+  bool hasChecksums() const { return Checksums != nullptr; }
+
+private:
+  void initializeStrings(const DebugSubsectionRecord &SR);
+  void initializeChecksums(const DebugSubsectionRecord &FCR);
+
+  std::unique_ptr<DebugStringTableSubsectionRef> OwnedStrings;
+  std::unique_ptr<DebugChecksumsSubsectionRef> OwnedChecksums;
+
+  const DebugStringTableSubsectionRef *Strings = nullptr;
+  const DebugChecksumsSubsectionRef *Checksums = nullptr;
+};
+
+class StringsAndChecksums {
+public:
+  using StringsPtr = std::shared_ptr<DebugStringTableSubsection>;
+  using ChecksumsPtr = std::shared_ptr<DebugChecksumsSubsection>;
+  // If no subsections are known about initially, we find as much as we can.
+  StringsAndChecksums() {}
+
+  void setStrings(const StringsPtr &SP) { Strings = SP; }
+  void setChecksums(const ChecksumsPtr &CP) { Checksums = CP; }
+
+  const StringsPtr &strings() const { return Strings; }
+  const ChecksumsPtr &checksums() const { return Checksums; }
+
+  bool hasStrings() const { return Strings != nullptr; }
+  bool hasChecksums() const { return Checksums != nullptr; }
+
+private:
+  StringsPtr Strings;
+  ChecksumsPtr Checksums;
+};
+
+} // namespace codeview
+} // namespace llvm
+
+#endif
index 8d2049a..a89e26a 100644 (file)
@@ -50,7 +50,7 @@ public:
   void addSymbol(codeview::CVSymbol Symbol);
 
   void
-  addDebugSubsection(std::unique_ptr<codeview::DebugSubsection> Subsection);
+  addDebugSubsection(std::shared_ptr<codeview::DebugSubsection> Subsection);
 
   uint16_t getStreamIndex() const;
   StringRef getModuleName() const { return ModuleName; }
index 28a14d7..86ef113 100644 (file)
@@ -45,7 +45,7 @@ public:
 
   FixedStreamArray<support::ulittle32_t> name_ids() const;
 
-  codeview::DebugStringTableSubsectionRef getStringTable() const;
+  const codeview::DebugStringTableSubsectionRef &getStringTable() const;
 
 private:
   Error readHeader(BinaryStreamReader &Reader);
index 0faa02d..b57707e 100644 (file)
@@ -41,10 +41,7 @@ public:
   uint32_t calculateSerializedSize() const;
   Error commit(BinaryStreamWriter &Writer) const;
 
-  codeview::DebugStringTableSubsection &getStrings() { return Strings; }
-  const codeview::DebugStringTableSubsection &getStrings() const {
-    return Strings;
-  }
+  void setStrings(const codeview::DebugStringTableSubsection &Strings);
 
 private:
   uint32_t calculateHashTableSize() const;
index 1b5f7b0..719cb1a 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "llvm/ADT/Optional.h"
 #include "llvm/BinaryFormat/COFF.h"
+#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
+#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
 #include "llvm/ObjectYAML/YAML.h"
 
 namespace llvm {
@@ -56,6 +58,8 @@ namespace COFFYAML {
     COFF::section Header;
     unsigned Alignment = 0;
     yaml::BinaryRef SectionData;
+    std::vector<CodeViewYAML::YAMLDebugSubsection> DebugS;
+    std::vector<CodeViewYAML::LeafRecord> DebugT;
     std::vector<Relocation> Relocations;
     StringRef Name;
     Section();
index faa3ed8..8180e0f 100644 (file)
@@ -28,6 +28,8 @@ class DebugStringTableSubsectionRef;
 class DebugChecksumsSubsectionRef;
 class DebugStringTableSubsection;
 class DebugChecksumsSubsection;
+class StringsAndChecksums;
+class StringsAndChecksumsRef;
 }
 namespace CodeViewYAML {
 
@@ -103,25 +105,24 @@ struct InlineeInfo {
 
 struct YAMLDebugSubsection {
   static Expected<YAMLDebugSubsection>
-  fromCodeViewSubection(const codeview::DebugStringTableSubsectionRef &Strings,
-                        const codeview::DebugChecksumsSubsectionRef &Checksums,
+  fromCodeViewSubection(const codeview::StringsAndChecksumsRef &SC,
                         const codeview::DebugSubsectionRecord &SS);
 
   std::shared_ptr<detail::YAMLSubsectionBase> Subsection;
 };
 
-Expected<std::vector<std::unique_ptr<codeview::DebugSubsection>>>
+struct DebugSubsectionState {};
+
+Expected<std::vector<std::shared_ptr<codeview::DebugSubsection>>>
 toCodeViewSubsectionList(BumpPtrAllocator &Allocator,
                          ArrayRef<YAMLDebugSubsection> Subsections,
-                         codeview::DebugStringTableSubsection &Strings);
-Expected<std::vector<std::unique_ptr<codeview::DebugSubsection>>>
-toCodeViewSubsectionList(
-    BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,
-    std::unique_ptr<codeview::DebugStringTableSubsection> &TakeStrings,
-    codeview::DebugStringTableSubsection *StringsRef);
-
-std::unique_ptr<codeview::DebugStringTableSubsection>
-findStringTable(ArrayRef<YAMLDebugSubsection> Sections);
+                         const codeview::StringsAndChecksums &SC);
+
+std::vector<YAMLDebugSubsection>
+fromDebugS(ArrayRef<uint8_t> Data, const codeview::StringsAndChecksumsRef &SC);
+
+void initializeStringsAndChecksums(ArrayRef<YAMLDebugSubsection> Sections,
+                                   codeview::StringsAndChecksums &SC);
 
 } // namespace CodeViewYAML
 } // namespace llvm
index 91b75aa..e97d5f9 100644 (file)
@@ -41,6 +41,9 @@ struct LeafRecord {
   codeview::CVType toCodeViewRecord(codeview::TypeTableBuilder &TS) const;
   static Expected<LeafRecord> fromCodeViewRecord(codeview::CVType Type);
 };
+
+std::vector<LeafRecord> fromDebugT(ArrayRef<uint8_t> DebugT);
+ArrayRef<uint8_t> toDebugT(ArrayRef<LeafRecord>, BumpPtrAllocator &Alloc);
 } // namespace CodeViewYAML
 } // namespace llvm
 
index 2f9e898..f916695 100644 (file)
@@ -20,6 +20,7 @@ add_llvm_library(LLVMDebugInfoCodeView
   LazyRandomTypeCollection.cpp
   Line.cpp
   RecordSerialization.cpp
+  StringsAndChecksums.cpp
   SymbolRecordMapping.cpp
   SymbolDumper.cpp
   SymbolSerializer.cpp
@@ -32,7 +33,7 @@ add_llvm_library(LLVMDebugInfoCodeView
   TypeSerializer.cpp
   TypeStreamMerger.cpp
   TypeTableCollection.cpp
-  
+
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
   )
index 6e647c4..de02525 100644 (file)
@@ -58,6 +58,10 @@ Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const {
   uint32_t Begin = Writer.getOffset();
   uint32_t End = Begin + StringSize;
 
+  // Write a null string at the beginning.
+  if (auto EC = Writer.writeCString(StringRef()))
+    return EC;
+
   for (auto &Pair : Strings) {
     StringRef S = Pair.getKey();
     uint32_t Offset = Begin + Pair.getValue();
@@ -68,6 +72,7 @@ Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const {
   }
 
   Writer.setOffset(End);
+  assert((End - Begin) == StringSize);
   return Error::success();
 }
 
index e9124e6..334c5e0 100644 (file)
@@ -50,7 +50,7 @@ DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
 BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
 
 DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
-    std::unique_ptr<DebugSubsection> Subsection, CodeViewContainer Container)
+    std::shared_ptr<DebugSubsection> Subsection, CodeViewContainer Container)
     : Subsection(std::move(Subsection)), Container(Container) {}
 
 uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() {
index 8550107..9b82433 100644 (file)
 using namespace llvm;
 using namespace llvm::codeview;
 
-DebugSubsectionState::DebugSubsectionState() {}
-
-DebugSubsectionState::DebugSubsectionState(
-    const DebugStringTableSubsectionRef &Strings)
-    : Strings(&Strings) {}
-
-DebugSubsectionState::DebugSubsectionState(
-    const DebugStringTableSubsectionRef &Strings,
-    const DebugChecksumsSubsectionRef &Checksums)
-    : Strings(&Strings), Checksums(&Checksums) {}
-
-void DebugSubsectionState::initializeStrings(const DebugSubsectionRecord &SR) {
-  assert(SR.kind() == DebugSubsectionKind::StringTable);
-  assert(!Strings && "Found a string table even though we already have one!");
-
-  OwnedStrings = llvm::make_unique<DebugStringTableSubsectionRef>();
-  consumeError(OwnedStrings->initialize(SR.getRecordData()));
-  Strings = OwnedStrings.get();
-}
-
-void DebugSubsectionState::initializeChecksums(
-    const DebugSubsectionRecord &FCR) {
-  assert(FCR.kind() == DebugSubsectionKind::FileChecksums);
-  if (Checksums)
-    return;
-
-  OwnedChecksums = llvm::make_unique<DebugChecksumsSubsectionRef>();
-  consumeError(OwnedChecksums->initialize(FCR.getRecordData()));
-  Checksums = OwnedChecksums.get();
-}
-
-Error llvm::codeview::visitDebugSubsection(const DebugSubsectionRecord &R,
-                                           DebugSubsectionVisitor &V,
-                                           const DebugSubsectionState &State) {
+Error llvm::codeview::visitDebugSubsection(
+    const DebugSubsectionRecord &R, DebugSubsectionVisitor &V,
+    const StringsAndChecksumsRef &State) {
   BinaryStreamReader Reader(R.getRecordData());
   switch (R.kind()) {
   case DebugSubsectionKind::Lines: {
diff --git a/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp b/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
new file mode 100644 (file)
index 0000000..ccd9aba
--- /dev/null
@@ -0,0 +1,48 @@
+//===- StringsAndChecksums.cpp ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+StringsAndChecksumsRef::StringsAndChecksumsRef() {}
+
+StringsAndChecksumsRef::StringsAndChecksumsRef(
+    const DebugStringTableSubsectionRef &Strings)
+    : Strings(&Strings) {}
+
+StringsAndChecksumsRef::StringsAndChecksumsRef(
+    const DebugStringTableSubsectionRef &Strings,
+    const DebugChecksumsSubsectionRef &Checksums)
+    : Strings(&Strings), Checksums(&Checksums) {}
+
+void StringsAndChecksumsRef::initializeStrings(
+    const DebugSubsectionRecord &SR) {
+  assert(SR.kind() == DebugSubsectionKind::StringTable);
+  assert(!Strings && "Found a string table even though we already have one!");
+
+  OwnedStrings = llvm::make_unique<DebugStringTableSubsectionRef>();
+  consumeError(OwnedStrings->initialize(SR.getRecordData()));
+  Strings = OwnedStrings.get();
+}
+
+void StringsAndChecksumsRef::initializeChecksums(
+    const DebugSubsectionRecord &FCR) {
+  assert(FCR.kind() == DebugSubsectionKind::FileChecksums);
+  if (Checksums)
+    return;
+
+  OwnedChecksums = llvm::make_unique<DebugChecksumsSubsectionRef>();
+  consumeError(OwnedChecksums->initialize(FCR.getRecordData()));
+  Checksums = OwnedChecksums.get();
+}
index 396dffa..81a9d3e 100644 (file)
@@ -177,7 +177,7 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter,
 }
 
 void DbiModuleDescriptorBuilder::addDebugSubsection(
-    std::unique_ptr<DebugSubsection> Subsection) {
+    std::shared_ptr<DebugSubsection> Subsection) {
   assert(Subsection);
   C13Builders.push_back(llvm::make_unique<DebugSubsectionRecordBuilder>(
       std::move(Subsection), CodeViewContainer::Pdb));
index 6013c34..f9f8ac2 100644 (file)
@@ -56,7 +56,8 @@ Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
   return Error::success();
 }
 
-codeview::DebugStringTableSubsectionRef PDBStringTable::getStringTable() const {
+const codeview::DebugStringTableSubsectionRef &
+PDBStringTable::getStringTable() const {
   return Strings;
 }
 
index a472181..90acfad 100644 (file)
@@ -52,6 +52,11 @@ uint32_t PDBStringTableBuilder::calculateSerializedSize() const {
   return Size;
 }
 
+void PDBStringTableBuilder::setStrings(
+    const codeview::DebugStringTableSubsection &Strings) {
+  this->Strings = Strings;
+}
+
 Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const {
   // Write a header
   PDBStringTableHeader H;
index 7f9f4c1..c8cbea1 100644 (file)
@@ -488,7 +488,16 @@ void MappingTraits<COFFYAML::Section>::mapping(IO &IO, COFFYAML::Section &Sec) {
   IO.mapOptional("VirtualAddress", Sec.Header.VirtualAddress, 0U);
   IO.mapOptional("VirtualSize", Sec.Header.VirtualSize, 0U);
   IO.mapOptional("Alignment", Sec.Alignment, 0U);
-  IO.mapRequired("SectionData", Sec.SectionData);
+
+  // If this is a .debug$S or .debug$T section parse the semantic representation
+  // of the symbols/types.  If it is any other kind of section, just deal in raw
+  // bytes.
+  IO.mapOptional("SectionData", Sec.SectionData);
+  if (Sec.Name == ".debug$S")
+    IO.mapOptional("Subsections", Sec.DebugS);
+  else if (Sec.Name == ".debug$T")
+    IO.mapOptional("Types", Sec.DebugT);
+
   IO.mapOptional("Relocations", Sec.Relocations);
 }
 
index 08a4bb7..d194420 100644 (file)
@@ -28,6 +28,7 @@
 #include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
 #include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
 #include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
 #include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"
@@ -75,10 +76,9 @@ struct YAMLSubsectionBase {
   virtual ~YAMLSubsectionBase() {}
 
   virtual void map(IO &IO) = 0;
-  virtual std::unique_ptr<DebugSubsection>
+  virtual std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *UseStrings,
-                       DebugChecksumsSubsection *UseChecksums) const = 0;
+                       const codeview::StringsAndChecksums &SC) const = 0;
 };
 }
 }
@@ -90,10 +90,9 @@ struct YAMLChecksumsSubsection : public YAMLSubsectionBase {
       : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLChecksumsSubsection>>
   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
                          const DebugChecksumsSubsectionRef &FC);
@@ -105,10 +104,9 @@ struct YAMLLinesSubsection : public YAMLSubsectionBase {
   YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLLinesSubsection>>
   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
                          const DebugChecksumsSubsectionRef &Checksums,
@@ -122,10 +120,9 @@ struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {
       : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>
   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
                          const DebugChecksumsSubsectionRef &Checksums,
@@ -139,10 +136,9 @@ struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {
       : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>
   fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef &Exports);
 
@@ -154,10 +150,9 @@ struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {
       : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>
   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
                          const DebugCrossModuleImportsSubsectionRef &Imports);
@@ -169,10 +164,9 @@ struct YAMLSymbolsSubsection : public YAMLSubsectionBase {
   YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLSymbolsSubsection>>
   fromCodeViewSubsection(const DebugSymbolsSubsectionRef &Symbols);
 
@@ -184,10 +178,9 @@ struct YAMLStringTableSubsection : public YAMLSubsectionBase {
       : YAMLSubsectionBase(DebugSubsectionKind::StringTable) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLStringTableSubsection>>
   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings);
 
@@ -199,10 +192,9 @@ struct YAMLFrameDataSubsection : public YAMLSubsectionBase {
       : YAMLSubsectionBase(DebugSubsectionKind::FrameData) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLFrameDataSubsection>>
   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
                          const DebugFrameDataSubsectionRef &Frames);
@@ -215,10 +207,9 @@ struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {
       : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA) {}
 
   void map(IO &IO) override;
-  std::unique_ptr<DebugSubsection>
+  std::shared_ptr<DebugSubsection>
   toCodeViewSubsection(BumpPtrAllocator &Allocator,
-                       DebugStringTableSubsection *Strings,
-                       DebugChecksumsSubsection *Checksums) const override;
+                       const codeview::StringsAndChecksums &SC) const override;
   static Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>
   fromCodeViewSubsection(const DebugSymbolRVASubsectionRef &RVAs);
 
@@ -389,34 +380,23 @@ void MappingTraits<YAMLDebugSubsection>::mapping(
   Subsection.Subsection->map(IO);
 }
 
-static std::shared_ptr<YAMLChecksumsSubsection>
-findChecksums(ArrayRef<YAMLDebugSubsection> Subsections) {
-  for (const auto &SS : Subsections) {
-    if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums) {
-      return std::static_pointer_cast<YAMLChecksumsSubsection>(SS.Subsection);
-    }
-  }
-
-  return nullptr;
-}
-
-std::unique_ptr<DebugSubsection> YAMLChecksumsSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *UseStrings,
-    DebugChecksumsSubsection *UseChecksums) const {
-  assert(UseStrings && !UseChecksums);
-  auto Result = llvm::make_unique<DebugChecksumsSubsection>(*UseStrings);
+std::shared_ptr<DebugSubsection> YAMLChecksumsSubsection::toCodeViewSubsection(
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  assert(SC.hasStrings());
+  auto Result = std::make_shared<DebugChecksumsSubsection>(*SC.strings());
   for (const auto &CS : Checksums) {
     Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes);
   }
-  return std::move(Result);
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *UseStrings,
-    DebugChecksumsSubsection *UseChecksums) const {
-  assert(UseStrings && UseChecksums);
+std::shared_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  assert(SC.hasStrings() && SC.hasChecksums());
   auto Result =
-      llvm::make_unique<DebugLinesSubsection>(*UseChecksums, *UseStrings);
+      std::make_shared<DebugLinesSubsection>(*SC.checksums(), *SC.strings());
   Result->setCodeSize(Lines.CodeSize);
   Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset);
   Result->setFlags(Lines.Flags);
@@ -438,16 +418,16 @@ std::unique_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
       }
     }
   }
-  return llvm::cast<DebugSubsection>(std::move(Result));
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection>
+std::shared_ptr<DebugSubsection>
 YAMLInlineeLinesSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *UseStrings,
-    DebugChecksumsSubsection *UseChecksums) const {
-  assert(UseChecksums);
-  auto Result = llvm::make_unique<DebugInlineeLinesSubsection>(
-      *UseChecksums, InlineeLines.HasExtraFiles);
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  assert(SC.hasChecksums());
+  auto Result = std::make_shared<DebugInlineeLinesSubsection>(
+      *SC.checksums(), InlineeLines.HasExtraFiles);
 
   for (const auto &Site : InlineeLines.Sites) {
     Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,
@@ -459,56 +439,60 @@ YAMLInlineeLinesSubsection::toCodeViewSubsection(
       Result->addExtraFile(EF);
     }
   }
-  return llvm::cast<DebugSubsection>(std::move(Result));
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection>
+std::shared_ptr<DebugSubsection>
 YAMLCrossModuleExportsSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
-    DebugChecksumsSubsection *Checksums) const {
-  auto Result = llvm::make_unique<DebugCrossModuleExportsSubsection>();
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  auto Result = std::make_shared<DebugCrossModuleExportsSubsection>();
   for (const auto &M : Exports)
     Result->addMapping(M.Local, M.Global);
-  return llvm::cast<DebugSubsection>(std::move(Result));
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection>
+std::shared_ptr<DebugSubsection>
 YAMLCrossModuleImportsSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
-    DebugChecksumsSubsection *Checksums) const {
-  auto Result = llvm::make_unique<DebugCrossModuleImportsSubsection>(*Strings);
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  assert(SC.hasStrings());
+
+  auto Result =
+      std::make_shared<DebugCrossModuleImportsSubsection>(*SC.strings());
   for (const auto &M : Imports) {
     for (const auto Id : M.ImportIds)
       Result->addImport(M.ModuleName, Id);
   }
-  return llvm::cast<DebugSubsection>(std::move(Result));
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection> YAMLSymbolsSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
-    DebugChecksumsSubsection *Checksums) const {
-  auto Result = llvm::make_unique<DebugSymbolsSubsection>();
+std::shared_ptr<DebugSubsection> YAMLSymbolsSubsection::toCodeViewSubsection(
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  auto Result = std::make_shared<DebugSymbolsSubsection>();
   for (const auto &Sym : Symbols)
     Result->addSymbol(
         Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile));
-  return std::move(Result);
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection>
+std::shared_ptr<DebugSubsection>
 YAMLStringTableSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
-    DebugChecksumsSubsection *Checksums) const {
-  auto Result = llvm::make_unique<DebugStringTableSubsection>();
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  auto Result = std::make_shared<DebugStringTableSubsection>();
   for (const auto &Str : this->Strings)
     Result->insert(Str);
-  return std::move(Result);
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
-    DebugChecksumsSubsection *Checksums) const {
-  assert(Strings);
-  auto Result = llvm::make_unique<DebugFrameDataSubsection>();
+std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  assert(SC.hasStrings());
+
+  auto Result = std::make_shared<DebugFrameDataSubsection>();
   for (const auto &YF : Frames) {
     codeview::FrameData F;
     F.CodeSize = YF.CodeSize;
@@ -519,20 +503,20 @@ std::unique_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
     F.PrologSize = YF.PrologSize;
     F.RvaStart = YF.RvaStart;
     F.SavedRegsSize = YF.SavedRegsSize;
-    F.FrameFunc = Strings->insert(YF.FrameFunc);
+    F.FrameFunc = SC.strings()->insert(YF.FrameFunc);
     Result->addFrameData(F);
   }
-  return std::move(Result);
+  return Result;
 }
 
-std::unique_ptr<DebugSubsection>
+std::shared_ptr<DebugSubsection>
 YAMLCoffSymbolRVASubsection::toCodeViewSubsection(
-    BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
-    DebugChecksumsSubsection *Checksums) const {
-  auto Result = llvm::make_unique<DebugSymbolRVASubsection>();
+    BumpPtrAllocator &Allocator,
+    const codeview::StringsAndChecksums &SC) const {
+  auto Result = std::make_shared<DebugSymbolRVASubsection>();
   for (const auto &RVA : RVAs)
     Result->addRVA(RVA);
-  return std::move(Result);
+  return Result;
 }
 
 static Expected<SourceFileChecksumEntry>
@@ -741,63 +725,17 @@ YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
   return Result;
 }
 
-Expected<std::vector<std::unique_ptr<DebugSubsection>>>
+Expected<std::vector<std::shared_ptr<DebugSubsection>>>
 llvm::CodeViewYAML::toCodeViewSubsectionList(
     BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,
-    DebugStringTableSubsection &Strings) {
-  std::vector<std::unique_ptr<DebugSubsection>> Result;
+    const codeview::StringsAndChecksums &SC) {
+  std::vector<std::shared_ptr<DebugSubsection>> Result;
   if (Subsections.empty())
     return std::move(Result);
 
-  auto Checksums = findChecksums(Subsections);
-  std::unique_ptr<DebugSubsection> ChecksumsBase;
-  if (Checksums)
-    ChecksumsBase =
-        Checksums->toCodeViewSubsection(Allocator, &Strings, nullptr);
-  DebugChecksumsSubsection *CS =
-      static_cast<DebugChecksumsSubsection *>(ChecksumsBase.get());
   for (const auto &SS : Subsections) {
-    // We've already converted the checksums subsection, don't do it
-    // twice.
-    std::unique_ptr<DebugSubsection> CVS;
-    if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums)
-      CVS = std::move(ChecksumsBase);
-    else
-      CVS = SS.Subsection->toCodeViewSubsection(Allocator, &Strings, CS);
-    assert(CVS != nullptr);
-    Result.push_back(std::move(CVS));
-  }
-  return std::move(Result);
-}
-
-Expected<std::vector<std::unique_ptr<codeview::DebugSubsection>>>
-llvm::CodeViewYAML::toCodeViewSubsectionList(
-    BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,
-    std::unique_ptr<DebugStringTableSubsection> &TakeStrings,
-    DebugStringTableSubsection *StringsRef) {
-  std::vector<std::unique_ptr<DebugSubsection>> Result;
-  if (Subsections.empty())
-    return std::move(Result);
-
-  auto Checksums = findChecksums(Subsections);
-
-  std::unique_ptr<DebugSubsection> ChecksumsBase;
-  if (Checksums)
-    ChecksumsBase =
-        Checksums->toCodeViewSubsection(Allocator, StringsRef, nullptr);
-  DebugChecksumsSubsection *CS =
-      static_cast<DebugChecksumsSubsection *>(ChecksumsBase.get());
-  for (const auto &SS : Subsections) {
-    // We've already converted the checksums and string table subsection, don't
-    // do it twice.
-    std::unique_ptr<DebugSubsection> CVS;
-    if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums)
-      CVS = std::move(ChecksumsBase);
-    else if (SS.Subsection->Kind == DebugSubsectionKind::StringTable) {
-      assert(TakeStrings && "No string table!");
-      CVS = std::move(TakeStrings);
-    } else
-      CVS = SS.Subsection->toCodeViewSubsection(Allocator, StringsRef, CS);
+    std::shared_ptr<DebugSubsection> CVS;
+    CVS = SS.Subsection->toCodeViewSubsection(Allocator, SC);
     assert(CVS != nullptr);
     Result.push_back(std::move(CVS));
   }
@@ -810,23 +748,23 @@ struct SubsectionConversionVisitor : public DebugSubsectionVisitor {
 
   Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override;
   Error visitLines(DebugLinesSubsectionRef &Lines,
-                   const DebugSubsectionState &State) override;
+                   const StringsAndChecksumsRef &State) override;
   Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,
-                           const DebugSubsectionState &State) override;
+                           const StringsAndChecksumsRef &State) override;
   Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,
-                          const DebugSubsectionState &State) override;
+                          const StringsAndChecksumsRef &State) override;
   Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &Checksums,
-                                const DebugSubsectionState &State) override;
+                                const StringsAndChecksumsRef &State) override;
   Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &Inlinees,
-                                const DebugSubsectionState &State) override;
+                                const StringsAndChecksumsRef &State) override;
   Error visitStringTable(DebugStringTableSubsectionRef &ST,
-                         const DebugSubsectionState &State) override;
+                         const StringsAndChecksumsRef &State) override;
   Error visitSymbols(DebugSymbolsSubsectionRef &Symbols,
-                     const DebugSubsectionState &State) override;
+                     const StringsAndChecksumsRef &State) override;
   Error visitFrameData(DebugFrameDataSubsectionRef &Symbols,
-                       const DebugSubsectionState &State) override;
+                       const StringsAndChecksumsRef &State) override;
   Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &Symbols,
-                            const DebugSubsectionState &State) override;
+                            const StringsAndChecksumsRef &State) override;
 
   YAMLDebugSubsection Subsection;
 };
@@ -837,7 +775,7 @@ Error SubsectionConversionVisitor::visitUnknown(
 }
 
 Error SubsectionConversionVisitor::visitLines(
-    DebugLinesSubsectionRef &Lines, const DebugSubsectionState &State) {
+    DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {
   auto Result = YAMLLinesSubsection::fromCodeViewSubsection(
       State.strings(), State.checksums(), Lines);
   if (!Result)
@@ -847,7 +785,8 @@ Error SubsectionConversionVisitor::visitLines(
 }
 
 Error SubsectionConversionVisitor::visitFileChecksums(
-    DebugChecksumsSubsectionRef &Checksums, const DebugSubsectionState &State) {
+    DebugChecksumsSubsectionRef &Checksums,
+    const StringsAndChecksumsRef &State) {
   auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),
                                                                 Checksums);
   if (!Result)
@@ -858,7 +797,7 @@ Error SubsectionConversionVisitor::visitFileChecksums(
 
 Error SubsectionConversionVisitor::visitInlineeLines(
     DebugInlineeLinesSubsectionRef &Inlinees,
-    const DebugSubsectionState &State) {
+    const StringsAndChecksumsRef &State) {
   auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(
       State.strings(), State.checksums(), Inlinees);
   if (!Result)
@@ -869,7 +808,7 @@ Error SubsectionConversionVisitor::visitInlineeLines(
 
 Error SubsectionConversionVisitor::visitCrossModuleExports(
     DebugCrossModuleExportsSubsectionRef &Exports,
-    const DebugSubsectionState &State) {
+    const StringsAndChecksumsRef &State) {
   auto Result =
       YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);
   if (!Result)
@@ -880,7 +819,7 @@ Error SubsectionConversionVisitor::visitCrossModuleExports(
 
 Error SubsectionConversionVisitor::visitCrossModuleImports(
     DebugCrossModuleImportsSubsectionRef &Imports,
-    const DebugSubsectionState &State) {
+    const StringsAndChecksumsRef &State) {
   auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
       State.strings(), Imports);
   if (!Result)
@@ -890,7 +829,8 @@ Error SubsectionConversionVisitor::visitCrossModuleImports(
 }
 
 Error SubsectionConversionVisitor::visitStringTable(
-    DebugStringTableSubsectionRef &Strings, const DebugSubsectionState &State) {
+    DebugStringTableSubsectionRef &Strings,
+    const StringsAndChecksumsRef &State) {
   auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);
   if (!Result)
     return Result.takeError();
@@ -899,7 +839,7 @@ Error SubsectionConversionVisitor::visitStringTable(
 }
 
 Error SubsectionConversionVisitor::visitSymbols(
-    DebugSymbolsSubsectionRef &Symbols, const DebugSubsectionState &State) {
+    DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {
   auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);
   if (!Result)
     return Result.takeError();
@@ -908,7 +848,7 @@ Error SubsectionConversionVisitor::visitSymbols(
 }
 
 Error SubsectionConversionVisitor::visitFrameData(
-    DebugFrameDataSubsectionRef &Frames, const DebugSubsectionState &State) {
+    DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {
   auto Result =
       YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);
   if (!Result)
@@ -918,7 +858,7 @@ Error SubsectionConversionVisitor::visitFrameData(
 }
 
 Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(
-    DebugSymbolRVASubsectionRef &RVAs, const DebugSubsectionState &State) {
+    DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) {
   auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);
   if (!Result)
     return Result.takeError();
@@ -927,29 +867,71 @@ Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(
 }
 }
 
-Expected<YAMLDebugSubsection> YAMLDebugSubsection::fromCodeViewSubection(
-    const DebugStringTableSubsectionRef &Strings,
-    const DebugChecksumsSubsectionRef &Checksums,
-    const DebugSubsectionRecord &SS) {
-  DebugSubsectionState State(Strings, Checksums);
+Expected<YAMLDebugSubsection>
+YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef &SC,
+                                           const DebugSubsectionRecord &SS) {
   SubsectionConversionVisitor V;
-  if (auto EC = visitDebugSubsection(SS, V, State))
+  if (auto EC = visitDebugSubsection(SS, V, SC))
     return std::move(EC);
 
   return V.Subsection;
 }
 
-std::unique_ptr<DebugStringTableSubsection>
-llvm::CodeViewYAML::findStringTable(ArrayRef<YAMLDebugSubsection> Sections) {
-  for (const auto &SS : Sections) {
-    if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)
-      continue;
+std::vector<YAMLDebugSubsection>
+llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,
+                               const StringsAndChecksumsRef &SC) {
+  BinaryStreamReader Reader(Data, support::little);
+  uint32_t Magic;
+
+  ExitOnError Err("Invalid .debug$S section!");
+  Err(Reader.readInteger(Magic));
+  assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
+
+  DebugSubsectionArray Subsections;
+  Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
+
+  std::vector<YAMLDebugSubsection> Result;
 
-    // String Table doesn't use the allocator.
-    BumpPtrAllocator Allocator;
-    auto Result =
-        SS.Subsection->toCodeViewSubsection(Allocator, nullptr, nullptr);
-    return llvm::cast<DebugStringTableSubsection>(std::move(Result));
+  for (const auto &SS : Subsections) {
+    auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));
+    Result.push_back(YamlSS);
+  }
+  return Result;
+}
+
+void llvm::CodeViewYAML::initializeStringsAndChecksums(
+    ArrayRef<YAMLDebugSubsection> Sections, codeview::StringsAndChecksums &SC) {
+  // String Table and Checksums subsections don't use the allocator.
+  BumpPtrAllocator Allocator;
+
+  // It's possible for checksums and strings to even appear in different debug$S
+  // sections, so we have to make this a stateful function that can build up
+  // the strings and checksums field over multiple iterations.
+
+  // File Checksums require the string table, but may become before it, so we
+  // have to scan for strings first, then scan for checksums again from the
+  // beginning.
+  if (!SC.hasStrings()) {
+    for (const auto &SS : Sections) {
+      if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)
+        continue;
+
+      auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
+      SC.setStrings(
+          std::static_pointer_cast<DebugStringTableSubsection>(Result));
+      break;
+    }
+  }
+
+  if (SC.hasStrings() && !SC.hasChecksums()) {
+    for (const auto &SS : Sections) {
+      if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)
+        continue;
+
+      auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
+      SC.setChecksums(
+          std::static_pointer_cast<DebugChecksumsSubsection>(Result));
+      break;
+    }
   }
-  return nullptr;
 }
index 1302b07..a03b9cd 100644 (file)
@@ -714,3 +714,43 @@ void MappingTraits<MemberRecord>::mapping(IO &IO, MemberRecord &Obj) {
   default: { llvm_unreachable("Unknown member kind!"); }
   }
 }
+
+std::vector<LeafRecord>
+llvm::CodeViewYAML::fromDebugT(ArrayRef<uint8_t> DebugT) {
+  ExitOnError Err("Invalid .debug$T section!");
+  BinaryStreamReader Reader(DebugT, support::little);
+  CVTypeArray Types;
+  uint32_t Magic;
+
+  Err(Reader.readInteger(Magic));
+  assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$T section!");
+
+  std::vector<LeafRecord> Result;
+  Err(Reader.readArray(Types, Reader.bytesRemaining()));
+  for (const auto &T : Types) {
+    auto CVT = Err(LeafRecord::fromCodeViewRecord(T));
+    Result.push_back(CVT);
+  }
+  return Result;
+}
+
+ArrayRef<uint8_t> llvm::CodeViewYAML::toDebugT(ArrayRef<LeafRecord> Leafs,
+                                               BumpPtrAllocator &Alloc) {
+  TypeTableBuilder TTB(Alloc, false);
+  uint32_t Size = sizeof(uint32_t);
+  for (const auto &Leaf : Leafs) {
+    CVType T = Leaf.toCodeViewRecord(TTB);
+    Size += T.length();
+    assert(T.length() % 4 == 0 && "Improper type record alignment!");
+  }
+  uint8_t *ResultBuffer = Alloc.Allocate<uint8_t>(Size);
+  MutableArrayRef<uint8_t> Output(ResultBuffer, Size);
+  BinaryStreamWriter Writer(Output, support::little);
+  ExitOnError Err("Error writing type record to .debug$T section");
+  Err(Writer.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC));
+  for (const auto &R : TTB.records()) {
+    Err(Writer.writeBytes(R));
+  }
+  assert(Writer.bytesRemaining() == 0 && "Didn't write all type record bytes!");
+  return Output;
+}
index 980e3d3..c4af458 100644 (file)
@@ -28,6 +28,7 @@
 #include "llvm/DebugInfo/CodeView/EnumTables.h"
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
 #include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
@@ -105,7 +106,7 @@ public:
   }
 
   Error visitLines(DebugLinesSubsectionRef &Lines,
-                   const DebugSubsectionState &State) override {
+                   const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::Lines))
       return Error::success();
 
@@ -146,7 +147,7 @@ public:
   }
 
   Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,
-                           const DebugSubsectionState &State) override {
+                           const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::FileChecksums))
       return Error::success();
 
@@ -164,7 +165,7 @@ public:
   }
 
   Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,
-                          const DebugSubsectionState &State) override {
+                          const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::InlineeLines))
       return Error::success();
 
@@ -191,7 +192,7 @@ public:
   }
 
   Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE,
-                                const DebugSubsectionState &State) override {
+                                const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeExports))
       return Error::success();
 
@@ -205,7 +206,7 @@ public:
   }
 
   Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSI,
-                                const DebugSubsectionState &State) override {
+                                const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeImports))
       return Error::success();
 
@@ -222,7 +223,7 @@ public:
   }
 
   Error visitFrameData(DebugFrameDataSubsectionRef &FD,
-                       const DebugSubsectionState &State) override {
+                       const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::FrameData))
       return Error::success();
 
@@ -248,7 +249,7 @@ public:
   }
 
   Error visitSymbols(DebugSymbolsSubsectionRef &Symbols,
-                     const DebugSubsectionState &State) override {
+                     const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::Symbols))
       return Error::success();
     ListScope L(P, "Symbols");
@@ -270,7 +271,7 @@ public:
   }
 
   Error visitStringTable(DebugStringTableSubsectionRef &Strings,
-                         const DebugSubsectionState &State) override {
+                         const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::StringTable))
       return Error::success();
 
@@ -288,7 +289,7 @@ public:
   }
 
   Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &RVAs,
-                            const DebugSubsectionState &State) override {
+                            const StringsAndChecksumsRef &State) override {
     if (!opts::checkModuleSubsection(opts::ModuleSubsection::CoffSymbolRVAs))
       return Error::success();
 
@@ -309,7 +310,7 @@ private:
           return EC;
       }
     }
-    
+
     if (!Success) {
       P.printString(
           llvm::formatv("Index: {0:x} (unknown function)", Index.getIndex())
@@ -318,7 +319,7 @@ private:
     return Error::success();
   }
   Error printFileName(StringRef Label, uint32_t Offset,
-                      const DebugSubsectionState &State) {
+                      const StringsAndChecksumsRef &State) {
     if (auto Result = getNameFromChecksumsBuffer(Offset, State)) {
       P.printString(Label, *Result);
       return Error::success();
@@ -327,13 +328,13 @@ private:
   }
 
   Expected<StringRef>
-  getNameFromStringTable(uint32_t Offset, const DebugSubsectionState &State) {
+  getNameFromStringTable(uint32_t Offset, const StringsAndChecksumsRef &State) {
     return State.strings().getString(Offset);
   }
 
   Expected<StringRef>
   getNameFromChecksumsBuffer(uint32_t Offset,
-                             const DebugSubsectionState &State) {
+                             const StringsAndChecksumsRef &State) {
     auto Array = State.checksums().getArray();
     auto ChecksumIter = Array.at(Offset);
     if (ChecksumIter == Array.end())
index 4ab7cd3..8f7aba6 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
 #include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
@@ -236,14 +237,16 @@ Error YAMLOutputStyle::dumpDbiStream() {
         if (!ExpectedChecksums)
           return ExpectedChecksums.takeError();
 
+        StringsAndChecksumsRef SC(ExpectedST->getStringTable(),
+                                  *ExpectedChecksums);
+
         for (const auto &SS : ModS.subsections()) {
           opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind());
           if (!opts::checkModuleSubsection(OptionKind))
             continue;
 
           auto Converted =
-              CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(
-                  ExpectedST->getStringTable(), *ExpectedChecksums, SS);
+              CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(SC, SS);
           if (!Converted)
             return Converted.takeError();
           DMI.Subsections.push_back(*Converted);
index dc46da4..3826ba7 100644 (file)
@@ -35,6 +35,7 @@
 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
@@ -511,10 +512,12 @@ static void yamlToPdb(StringRef Path) {
   for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
     ExitOnErr(Builder.getMsfBuilder().addStream(0));
 
+  StringsAndChecksums Strings;
+  Strings.setStrings(std::make_shared<DebugStringTableSubsection>());
+
   if (YamlObj.StringTable.hasValue()) {
-    auto &Strings = Builder.getStringTableBuilder();
     for (auto S : *YamlObj.StringTable)
-      Strings.insert(S);
+      Strings.strings()->insert(S);
   }
 
   pdb::yaml::PdbInfoStream DefaultInfoStream;
@@ -532,8 +535,6 @@ static void yamlToPdb(StringRef Path) {
   for (auto F : Info.Features)
     InfoBuilder.addFeature(F);
 
-  auto &Strings = Builder.getStringTableBuilder().getStrings();
-
   const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
   auto &DbiBuilder = Builder.getDbiBuilder();
   DbiBuilder.setAge(Dbi.Age);
@@ -557,10 +558,14 @@ static void yamlToPdb(StringRef Path) {
       }
     }
 
+    // Each module has its own checksum subsection, so scan for it every time.
+    Strings.setChecksums(nullptr);
+    CodeViewYAML::initializeStringsAndChecksums(MI.Subsections, Strings);
+
     auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList(
         Allocator, MI.Subsections, Strings));
     for (auto &SS : CodeViewSubsections) {
-      ModiBuilder.addDebugSubsection(std::move(SS));
+      ModiBuilder.addDebugSubsection(SS);
     }
   }
 
@@ -580,6 +585,8 @@ static void yamlToPdb(StringRef Path) {
     IpiBuilder.addTypeRecord(Type.RecordData, None);
   }
 
+  Builder.getStringTableBuilder().setStrings(*Strings.strings());
+
   ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
 }
 
index ecd958d..36dcfd9 100644 (file)
@@ -1,4 +1,5 @@
 set(LLVM_LINK_COMPONENTS
+  DebugInfoCodeView
   DebugInfoDWARF
   Object
   ObjectYAML
index c734601..b1a06bc 100644 (file)
@@ -8,8 +8,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "obj2yaml.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/ObjectYAML/COFFYAML.h"
+#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"
+#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/YAMLTraits.h"
 
@@ -99,8 +104,45 @@ void COFFDumper::dumpHeader() {
   YAMLObj.Header.Characteristics = Obj.getCharacteristics();
 }
 
+static void
+initializeFileAndStringTable(const llvm::object::COFFObjectFile &Obj,
+                             codeview::StringsAndChecksumsRef &SC) {
+
+  ExitOnError Err("Invalid .debug$S section!");
+  // Iterate all .debug$S sections looking for the checksums and string table.
+  // Exit as soon as both sections are found.
+  for (const auto &S : Obj.sections()) {
+    if (SC.hasStrings() && SC.hasChecksums())
+      break;
+
+    StringRef SectionName;
+    S.getName(SectionName);
+    ArrayRef<uint8_t> sectionData;
+    if (SectionName != ".debug$S")
+      continue;
+
+    const object::coff_section *COFFSection = Obj.getCOFFSection(S);
+
+    Obj.getSectionContents(COFFSection, sectionData);
+
+    BinaryStreamReader Reader(sectionData, support::little);
+    uint32_t Magic;
+
+    Err(Reader.readInteger(Magic));
+    assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
+
+    codeview::DebugSubsectionArray Subsections;
+    Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
+
+    SC.initialize(Subsections);
+  }
+}
+
 void COFFDumper::dumpSections(unsigned NumSections) {
   std::vector<COFFYAML::Section> &YAMLSections = YAMLObj.Sections;
+  codeview::StringsAndChecksumsRef SC;
+  initializeFileAndStringTable(Obj, SC);
+
   for (const auto &ObjSection : Obj.sections()) {
     const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection);
     COFFYAML::Section NewYAMLSection;
@@ -108,6 +150,16 @@ void COFFDumper::dumpSections(unsigned NumSections) {
     NewYAMLSection.Header.Characteristics = COFFSection->Characteristics;
     NewYAMLSection.Header.VirtualAddress = ObjSection.getAddress();
     NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize;
+    NewYAMLSection.Header.NumberOfLineNumbers =
+        COFFSection->NumberOfLinenumbers;
+    NewYAMLSection.Header.NumberOfRelocations =
+        COFFSection->NumberOfRelocations;
+    NewYAMLSection.Header.PointerToLineNumbers =
+        COFFSection->PointerToLinenumbers;
+    NewYAMLSection.Header.PointerToRawData = COFFSection->PointerToRawData;
+    NewYAMLSection.Header.PointerToRelocations =
+        COFFSection->PointerToRelocations;
+    NewYAMLSection.Header.SizeOfRawData = COFFSection->SizeOfRawData;
     NewYAMLSection.Alignment = ObjSection.getAlignment();
     assert(NewYAMLSection.Alignment <= 8192);
 
@@ -116,6 +168,11 @@ void COFFDumper::dumpSections(unsigned NumSections) {
       Obj.getSectionContents(COFFSection, sectionData);
     NewYAMLSection.SectionData = yaml::BinaryRef(sectionData);
 
+    if (NewYAMLSection.Name == ".debug$S")
+      NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC);
+    else if (NewYAMLSection.Name == ".debug$T")
+      NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData);
+
     std::vector<COFFYAML::Relocation> Relocations;
     for (const auto &Reloc : ObjSection.relocations()) {
       const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc);
index a885547..adeac23 100644 (file)
@@ -1,4 +1,5 @@
 set(LLVM_LINK_COMPONENTS
+  DebugInfoCodeView
   MC
   Object
   ObjectYAML
index 8f3f521..1f302fd 100644 (file)
@@ -17,6 +17,8 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/ObjectYAML/ObjectYAML.h"
 #include "llvm/Support/Endian.h"
@@ -142,6 +144,8 @@ struct COFFParser {
 
   COFFYAML::Object &Obj;
 
+  codeview::StringsAndChecksums StringsAndChecksums;
+  BumpPtrAllocator Allocator;
   StringMap<unsigned> StringTableMap;
   std::string StringTable;
   uint32_t SectionTableStart;
@@ -165,6 +169,32 @@ namespace {
 enum { DOSStubSize = 128 };
 }
 
+static yaml::BinaryRef
+toDebugS(ArrayRef<CodeViewYAML::YAMLDebugSubsection> Subsections,
+         const codeview::StringsAndChecksums &SC, BumpPtrAllocator &Allocator) {
+  using namespace codeview;
+  ExitOnError Err("Error occurred writing .debug$S section");
+  auto CVSS =
+      Err(CodeViewYAML::toCodeViewSubsectionList(Allocator, Subsections, SC));
+
+  std::vector<DebugSubsectionRecordBuilder> Builders;
+  uint32_t Size = sizeof(uint32_t);
+  for (auto &SS : CVSS) {
+    DebugSubsectionRecordBuilder B(SS, CodeViewContainer::ObjectFile);
+    Size += B.calculateSerializedLength();
+    Builders.push_back(std::move(B));
+  }
+  uint8_t *Buffer = Allocator.Allocate<uint8_t>(Size);
+  MutableArrayRef<uint8_t> Output(Buffer, Size);
+  BinaryStreamWriter Writer(Output, support::little);
+
+  Err(Writer.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC));
+  for (const auto &B : Builders) {
+    Err(B.commit(Writer));
+  }
+  return {Output};
+}
+
 // Take a CP and assign addresses and sizes to everything. Returns false if the
 // layout is not valid to do.
 static bool layoutCOFF(COFFParser &CP) {
@@ -179,8 +209,33 @@ static bool layoutCOFF(COFFParser &CP) {
   uint32_t CurrentSectionDataOffset =
       CP.SectionTableStart + CP.SectionTableSize;
 
+  for (COFFYAML::Section &S : CP.Obj.Sections) {
+    // We support specifying exactly one of SectionData or Subsections.  So if
+    // there is already some SectionData, then we don't need to do any of this.
+    if (S.Name == ".debug$S" && S.SectionData.binary_size() == 0) {
+      CodeViewYAML::initializeStringsAndChecksums(S.DebugS,
+                                                  CP.StringsAndChecksums);
+      if (CP.StringsAndChecksums.hasChecksums() &&
+          CP.StringsAndChecksums.hasStrings())
+        break;
+    }
+  }
+
   // Assign each section data address consecutively.
   for (COFFYAML::Section &S : CP.Obj.Sections) {
+    if (S.Name == ".debug$S") {
+      if (S.SectionData.binary_size() == 0) {
+        assert(CP.StringsAndChecksums.hasStrings() &&
+               "Object file does not have debug string table!");
+
+        S.SectionData =
+            toDebugS(S.DebugS, CP.StringsAndChecksums, CP.Allocator);
+      }
+    } else if (S.Name == ".debug$T") {
+      if (S.SectionData.binary_size() == 0)
+        S.SectionData = CodeViewYAML::toDebugT(S.DebugT, CP.Allocator);
+    }
+
     if (S.SectionData.binary_size() > 0) {
       CurrentSectionDataOffset = alignTo(CurrentSectionDataOffset,
                                          CP.isPE() ? CP.getFileAlignment() : 4);
@@ -543,6 +598,7 @@ int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) {
     errs() << "yaml2obj: Failed to layout optional header for COFF file!\n";
     return 1;
   }
+
   if (!layoutCOFF(CP)) {
     errs() << "yaml2obj: Failed to layout COFF file!\n";
     return 1;