diff options
31 files changed, 865 insertions, 326 deletions
diff --git a/lld/test/COFF/Inputs/pdb1.yaml b/lld/test/COFF/Inputs/pdb1.yaml index 30ddbadd01e..566f2da003c 100644 --- a/lld/test/COFF/Inputs/pdb1.yaml +++ b/lld/test/COFF/Inputs/pdb1.yaml @@ -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 diff --git a/lld/test/COFF/Inputs/pdb2.yaml b/lld/test/COFF/Inputs/pdb2.yaml index 7a446b40f4f..65079515336 100644 --- a/lld/test/COFF/Inputs/pdb2.yaml +++ b/lld/test/COFF/Inputs/pdb2.yaml @@ -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 diff --git a/lld/test/COFF/sort-debug.test b/lld/test/COFF/sort-debug.test index b04b41ad1c2..3bad013a309 100644 --- a/lld/test/COFF/sort-debug.test +++ b/lld/test/COFF/sort-debug.test @@ -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 diff --git a/llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h b/llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h index 686b5c4f242..1e329c7c3f1 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h +++ b/llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h @@ -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; diff --git a/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h b/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h index 49a269d92e3..69473174206 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h +++ b/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h @@ -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; diff --git a/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h b/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h index d4a3d9195a3..75f749dfa93 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h +++ b/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h @@ -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 index 00000000000..4fe5d450e2e --- /dev/null +++ b/llvm/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h @@ -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 diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h index 8d2049ad225..a89e26ae943 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h @@ -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; } diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h b/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h index 28a14d7356d..86ef1136b41 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h @@ -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); diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h index 0faa02dc452..b57707ee792 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h @@ -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; diff --git a/llvm/include/llvm/ObjectYAML/COFFYAML.h b/llvm/include/llvm/ObjectYAML/COFFYAML.h index 1b5f7b00239..719cb1acf6e 100644 --- a/llvm/include/llvm/ObjectYAML/COFFYAML.h +++ b/llvm/include/llvm/ObjectYAML/COFFYAML.h @@ -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(); diff --git a/llvm/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h b/llvm/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h index faa3ed8a6c5..8180e0fc83f 100644 --- a/llvm/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h +++ b/llvm/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h @@ -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 diff --git a/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h b/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h index 91b75aabe7a..e97d5f92bf7 100644 --- a/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h +++ b/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h @@ -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 diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index 2f9e8981b69..f916695a843 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -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 ) diff --git a/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp b/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp index 6e647c4b976..de02525270c 100644 --- a/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp +++ b/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp @@ -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(); } diff --git a/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp index e9124e68fe8..334c5e002bb 100644 --- a/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp +++ b/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp @@ -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() { diff --git a/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp b/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp index 8550107741c..9b824333369 100644 --- a/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp @@ -26,40 +26,9 @@ 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 index 00000000000..ccd9aba45ea --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp @@ -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(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 396dffaa68b..81a9d3eeec6 100644 --- a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -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)); diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp index 6013c342cf0..f9f8ac219d3 100644 --- a/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -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; } diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp index a472181a489..90acfadd311 100644 --- a/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -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; diff --git a/llvm/lib/ObjectYAML/COFFYAML.cpp b/llvm/lib/ObjectYAML/COFFYAML.cpp index 7f9f4c1f8c2..c8cbea1490f 100644 --- a/llvm/lib/ObjectYAML/COFFYAML.cpp +++ b/llvm/lib/ObjectYAML/COFFYAML.cpp @@ -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); } diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp index 08a4bb715fa..d194420d5ef 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp @@ -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; } diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp index 1302b0713d0..a03b9cd50fa 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp @@ -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; +} diff --git a/llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp b/llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp index 980e3d3d41b..c4af4583a10 100644 --- a/llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp +++ b/llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp @@ -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()) diff --git a/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp b/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp index 4ab7cd39b29..8f7aba6d30c 100644 --- a/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp +++ b/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp @@ -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); diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp index dc46da4a90f..3826ba79a20 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -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)); } diff --git a/llvm/tools/obj2yaml/CMakeLists.txt b/llvm/tools/obj2yaml/CMakeLists.txt index ecd958d75b3..36dcfd92dfe 100644 --- a/llvm/tools/obj2yaml/CMakeLists.txt +++ b/llvm/tools/obj2yaml/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + DebugInfoCodeView DebugInfoDWARF Object ObjectYAML diff --git a/llvm/tools/obj2yaml/coff2yaml.cpp b/llvm/tools/obj2yaml/coff2yaml.cpp index c734601ede7..b1a06bca1a7 100644 --- a/llvm/tools/obj2yaml/coff2yaml.cpp +++ b/llvm/tools/obj2yaml/coff2yaml.cpp @@ -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); diff --git a/llvm/tools/yaml2obj/CMakeLists.txt b/llvm/tools/yaml2obj/CMakeLists.txt index a885547598d..adeac2331a6 100644 --- a/llvm/tools/yaml2obj/CMakeLists.txt +++ b/llvm/tools/yaml2obj/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + DebugInfoCodeView MC Object ObjectYAML diff --git a/llvm/tools/yaml2obj/yaml2coff.cpp b/llvm/tools/yaml2obj/yaml2coff.cpp index 8f3f5217952..1f302fdc45a 100644 --- a/llvm/tools/yaml2obj/yaml2coff.cpp +++ b/llvm/tools/yaml2obj/yaml2coff.cpp @@ -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; |