mirror of
https://github.com/intel/llvm.git
synced 2026-01-25 01:07:04 +08:00
[codeview] Make obj2yaml/yaml2obj support .debug$S/T sections.
This allows us to use yaml2obj and obj2yaml to round-trip CodeView symbol and type information without having to manually specify the bytes of the section. This makes for much easier to maintain tests. See the tests under lld/COFF in this patch for example. Before they just said SectionData: <blob> whereas now we can use meaningful record descriptions. Note that it still supports the SectionData yaml field, which could be useful for initializing a section to invalid bytes for testing, for example. Differential Revision: https://reviews.llvm.org/D34127 llvm-svn: 305366
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -30,56 +30,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 +40,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 +84,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 +92,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 +101,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);
|
||||
}
|
||||
|
||||
103
llvm/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h
Normal file
103
llvm/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h
Normal file
@@ -0,0 +1,103 @@
|
||||
//===- 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 <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
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
const codeview::StringsAndChecksums &SC);
|
||||
|
||||
std::unique_ptr<codeview::DebugStringTableSubsection>
|
||||
findStringTable(ArrayRef<YAMLDebugSubsection> Sections);
|
||||
std::vector<YAMLDebugSubsection>
|
||||
fromDebugS(ArrayRef<uint8_t> Data, const codeview::StringsAndChecksumsRef &SC);
|
||||
|
||||
void initializeStringsAndChecksums(ArrayRef<YAMLDebugSubsection> Sections,
|
||||
codeview::StringsAndChecksums &SC);
|
||||
|
||||
} // namespace CodeViewYAML
|
||||
} // namespace llvm
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
48
llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
Normal file
48
llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
Normal file
@@ -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();
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -400,23 +391,23 @@ findChecksums(ArrayRef<YAMLDebugSubsection> Subsections) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 +429,16 @@ std::unique_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
|
||||
}
|
||||
}
|
||||
}
|
||||
return llvm::cast<DebugSubsection>(std::move(Result));
|
||||
return std::move(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,55 +450,59 @@ YAMLInlineeLinesSubsection::toCodeViewSubsection(
|
||||
Result->addExtraFile(EF);
|
||||
}
|
||||
}
|
||||
return llvm::cast<DebugSubsection>(std::move(Result));
|
||||
return std::move(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 std::move(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 std::move(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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::unique_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
|
||||
BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
|
||||
DebugChecksumsSubsection *Checksums) const {
|
||||
assert(Strings);
|
||||
std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
|
||||
BumpPtrAllocator &Allocator,
|
||||
const codeview::StringsAndChecksums &SC) const {
|
||||
assert(SC.hasStrings());
|
||||
|
||||
auto Result = llvm::make_unique<DebugFrameDataSubsection>();
|
||||
for (const auto &YF : Frames) {
|
||||
codeview::FrameData F;
|
||||
@@ -519,16 +514,16 @@ 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);
|
||||
}
|
||||
|
||||
std::unique_ptr<DebugSubsection>
|
||||
std::shared_ptr<DebugSubsection>
|
||||
YAMLCoffSymbolRVASubsection::toCodeViewSubsection(
|
||||
BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings,
|
||||
DebugChecksumsSubsection *Checksums) const {
|
||||
BumpPtrAllocator &Allocator,
|
||||
const codeview::StringsAndChecksums &SC) const {
|
||||
auto Result = llvm::make_unique<DebugSymbolRVASubsection>();
|
||||
for (const auto &RVA : RVAs)
|
||||
Result->addRVA(RVA);
|
||||
@@ -741,63 +736,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 +759,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 +786,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 +796,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 +808,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 +819,7 @@ Error SubsectionConversionVisitor::visitInlineeLines(
|
||||
|
||||
Error SubsectionConversionVisitor::visitCrossModuleExports(
|
||||
DebugCrossModuleExportsSubsectionRef &Exports,
|
||||
const DebugSubsectionState &State) {
|
||||
const StringsAndChecksumsRef &State) {
|
||||
auto Result =
|
||||
YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);
|
||||
if (!Result)
|
||||
@@ -880,7 +830,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 +840,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 +850,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 +859,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 +869,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 +878,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;
|
||||
|
||||
// String Table doesn't use the allocator.
|
||||
BumpPtrAllocator Allocator;
|
||||
auto Result =
|
||||
SS.Subsection->toCodeViewSubsection(Allocator, nullptr, nullptr);
|
||||
return llvm::cast<DebugStringTableSubsection>(std::move(Result));
|
||||
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;
|
||||
|
||||
for (const auto &SS : Subsections) {
|
||||
auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));
|
||||
Result.push_back(YamlSS);
|
||||
}
|
||||
return std::move(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;
|
||||
}
|
||||
|
||||
@@ -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 std::move(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;
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
@@ -27,6 +29,33 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
template <typename T> struct WeakishPtr {
|
||||
public:
|
||||
WeakishPtr() : Ref(nullptr) {}
|
||||
|
||||
WeakishPtr(std::unique_ptr<T> Value)
|
||||
: Ref(Value.get()), UniquePtr(std::move(Value)) {}
|
||||
|
||||
WeakishPtr(std::unique_ptr<T> &&Value)
|
||||
: Ref(Value.get()), UniquePtr(std::move(Value)) {}
|
||||
|
||||
WeakishPtr<T> &operator=(std::unique_ptr<T> &&Value) {
|
||||
Owned = std::move(Value);
|
||||
Ref = Owned.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *get() { return Ref; }
|
||||
T &operator*() { return *Ref; }
|
||||
|
||||
operator bool() const { return Ref != nullptr; }
|
||||
|
||||
T *Ref;
|
||||
std::unique_ptr<T> Owned;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/// This parses a yaml stream that represents a COFF object file.
|
||||
/// See docs/yaml2obj for the yaml scheema.
|
||||
struct COFFParser {
|
||||
@@ -142,6 +171,8 @@ struct COFFParser {
|
||||
|
||||
COFFYAML::Object &Obj;
|
||||
|
||||
codeview::StringsAndChecksums StringsAndChecksums;
|
||||
BumpPtrAllocator Allocator;
|
||||
StringMap<unsigned> StringTableMap;
|
||||
std::string StringTable;
|
||||
uint32_t SectionTableStart;
|
||||
@@ -165,6 +196,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 +236,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 +625,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;
|
||||
|
||||
Reference in New Issue
Block a user