Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -16,6 +16,7 @@ #include "Writer.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Timer.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" @@ -821,6 +822,20 @@ return SC; } +static uint32_t +translateStringTableIndex(uint32_t ObjIndex, + const DebugStringTableSubsectionRef &ObjStrTable, + DebugStringTableSubsection &PdbStrTable) { + auto ExpectedString = ObjStrTable.getString(ObjIndex); + if (!ExpectedString) { + warn("Invalid string table reference"); + consumeError(ExpectedString.takeError()); + return 0; + } + + return PdbStrTable.insert(*ExpectedString); +} + void PDBLinker::addObjFile(ObjFile *File) { // Add a module descriptor for every object file. We need to put an absolute // path to the object into the PDB. If this is a plain object, we make its @@ -832,7 +847,8 @@ sys::path::native(Path, sys::path::Style::windows); StringRef Name = InArchive ? File->getName() : StringRef(Path); - File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + File->ModuleDBI = &ExitOnErr(DbiBuilder.addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); auto Chunks = File->getChunks(); @@ -870,6 +886,7 @@ DebugStringTableSubsectionRef CVStrTab; DebugChecksumsSubsectionRef Checksums; std::vector StringTableReferences; + std::vector FpoFrames; for (SectionChunk *DebugChunk : File->getDebugChunks()) { if (!DebugChunk->Live || DebugChunk->getSectionName() != ".debug$S") continue; @@ -901,6 +918,15 @@ // modification because the file checksum offsets will stay the same. File->ModuleDBI->addDebugSubsection(SS); break; + case DebugSubsectionKind::FrameData: { + // We need to re-write string table indices here, so save off all + // frame data subsections until we've processed the entire list of + // subsections so that we can be sure we have the string table. + DebugFrameDataSubsectionRef FDS; + ExitOnErr(FDS.initialize(SS.getRecordData())); + FpoFrames.push_back(std::move(FDS)); + break; + } case DebugSubsectionKind::Symbols: if (Config->DebugGHashes) { mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, @@ -933,19 +959,21 @@ return; } - // Rewrite each string table reference based on the value that the string - // assumes in the final PDB. - for (ulittle32_t *Ref : StringTableReferences) { - auto ExpectedString = CVStrTab.getString(*Ref); - if (!ExpectedString) { - warn("Invalid string table reference"); - consumeError(ExpectedString.takeError()); - continue; + // Rewrite string table indices in the Fpo Data and symbol records to refer to + // the global PDB string table instead of the object file string table. + for (DebugFrameDataSubsectionRef &FDS : FpoFrames) { + const uint32_t *Reloc = FDS.getRelocPtr(); + for (codeview::FrameData FD : FDS) { + FD.RvaStart += *Reloc; + FD.FrameFunc = + translateStringTableIndex(FD.FrameFunc, CVStrTab, PDBStrTab); + DbiBuilder.addFrameData(FD); } - - *Ref = PDBStrTab.insert(*ExpectedString); } + for (ulittle32_t *Ref : StringTableReferences) + *Ref = translateStringTableIndex(*Ref, CVStrTab, PDBStrTab); + // Make a new file checksum table that refers to offsets in the PDB-wide // string table. Generally the string table subsection appears after the // checksum table, so we have to do this after looping over all the Index: lld/test/COFF/pdb-framedata.yaml =================================================================== --- /dev/null +++ lld/test/COFF/pdb-framedata.yaml @@ -0,0 +1,462 @@ +# // Compile with clang-cl -m32 /Z7 /GS- /c t.obj pdb-framedata.cpp +# +# int func(int x, int y) { +# return x + y; +# } +# +# int main(int argc, char **argv) { +# return func(argc, argc+1); +# } + +# RUN: yaml2obj %s -o %t.obj +# RUN: lld-link %t.obj -debug -entry:main -nodefaultlib -debug -out:%t.exe -pdb:%t.pdb +# RUN: llvm-pdbutil dump -fpo %t.pdb | FileCheck %s + +# CHECK: New FPO Data +# CHECK-NEXT: ============================================================ +# CHECK-NEXT: RVA | Code | Locals | Params | Stack | Prolog | Saved Regs | Has SEH | Has C++EH | Start | Program +# CHECK-NEXT: 00001000 | 31 | 0 | 8 | 0 | 6 | 0 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = +# CHECK-NEXT: 00001001 | 30 | 0 | 8 | 0 | 5 | 4 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = +# CHECK-NEXT: 00001003 | 28 | 0 | 8 | 0 | 3 | 4 | false | false | false | $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = +# CHECK-NEXT: 00001020 | 53 | 0 | 8 | 0 | 7 | 0 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = +# CHECK-NEXT: 00001021 | 52 | 0 | 8 | 0 | 6 | 4 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = +# CHECK-NEXT: 00001023 | 50 | 0 | 8 | 0 | 4 | 4 | false | false | false | $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = +# CHECK-NEXT: 00001024 | 49 | 0 | 8 | 0 | 3 | 8 | false | false | false | $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = + + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 5589E583EC088B450C8B4D088B550803550C8945FC89D0894DF883C4085DC3905589E55683EC148B450C8B4D08C745F8000000008B550883C2018B7508893424895424048945F4894DF0E80000000083C4145E5DC3 + Relocations: + - VirtualAddress: 75 + SymbolName: '?func@@YAHHH@Z' + Type: IMAGE_REL_I386_REL32 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + Subsections: + - !Symbols + Records: + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ ] + Machine: Pentium3 + FrontendMajor: 8 + FrontendMinor: 0 + FrontendBuild: 0 + FrontendQFE: 0 + BackendMajor: 8000 + BackendMinor: 0 + BackendBuild: 0 + BackendQFE: 0 + Version: 'clang version 8.0.0 ' + - !FrameData + Frames: + - CodeSize: 31 + FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' + LocalSize: 0 + MaxStackSize: 0 + ParamsSize: 8 + PrologSize: 6 + RvaStart: 0 + SavedRegsSize: 0 + - CodeSize: 30 + FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' + LocalSize: 0 + MaxStackSize: 0 + ParamsSize: 8 + PrologSize: 5 + RvaStart: 1 + SavedRegsSize: 4 + - CodeSize: 28 + FrameFunc: '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' + LocalSize: 0 + MaxStackSize: 0 + ParamsSize: 8 + PrologSize: 3 + RvaStart: 3 + SavedRegsSize: 4 + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 31 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4098 + Flags: [ ] + DisplayName: func + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: x + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 12 + ISectStart: 0 + Range: 19 + Gaps: + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: y + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 12 + Range: + OffsetStart: 12 + ISectStart: 0 + Range: 19 + Gaps: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 31 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.cpp' + Lines: + - Offset: 0 + LineStart: 3 + IsStatement: false + EndDelta: 0 + - Offset: 12 + LineStart: 4 + IsStatement: false + EndDelta: 0 + Columns: + - !FrameData + Frames: + - CodeSize: 53 + FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' + LocalSize: 0 + MaxStackSize: 0 + ParamsSize: 8 + PrologSize: 7 + RvaStart: 0 + SavedRegsSize: 0 + - CodeSize: 52 + FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' + LocalSize: 0 + MaxStackSize: 0 + ParamsSize: 8 + PrologSize: 6 + RvaStart: 1 + SavedRegsSize: 4 + - CodeSize: 50 + FrameFunc: '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' + LocalSize: 0 + MaxStackSize: 0 + ParamsSize: 8 + PrologSize: 4 + RvaStart: 3 + SavedRegsSize: 4 + - CodeSize: 49 + FrameFunc: '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = ' + LocalSize: 0 + MaxStackSize: 0 + ParamsSize: 8 + PrologSize: 3 + RvaStart: 4 + SavedRegsSize: 8 + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 53 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4102 + Flags: [ ] + DisplayName: main + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: argc + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 52 + ISectStart: 0 + Range: 33 + Gaps: + - Kind: S_LOCAL + LocalSym: + Type: 4099 + Flags: [ IsParameter ] + VarName: argv + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 12 + Range: + OffsetStart: 52 + ISectStart: 0 + Range: 33 + Gaps: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 53 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.cpp' + Lines: + - Offset: 0 + LineStart: 7 + IsStatement: false + EndDelta: 0 + - Offset: 20 + LineStart: 8 + IsStatement: false + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.cpp' + Kind: MD5 + Checksum: A611B73E19B77B02646FAAF7CAEB025D + - !StringTable + Strings: + - 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.cpp' + - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' + - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' + - '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' + - '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = ' + - '' + Relocations: + - VirtualAddress: 68 + SymbolName: '?func@@YAHHH@Z' + Type: IMAGE_REL_I386_DIR32NB + - VirtualAddress: 208 + SymbolName: '?func@@YAHHH@Z' + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 212 + SymbolName: '?func@@YAHHH@Z' + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 244 + SymbolName: .text + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 248 + SymbolName: .text + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 276 + SymbolName: .text + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 280 + SymbolName: .text + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 296 + SymbolName: '?func@@YAHHH@Z' + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 300 + SymbolName: '?func@@YAHHH@Z' + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 344 + SymbolName: _main + Type: IMAGE_REL_I386_DIR32NB + - VirtualAddress: 516 + SymbolName: _main + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 520 + SymbolName: _main + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 555 + SymbolName: .text + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 559 + SymbolName: .text + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 590 + SymbolName: .text + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 594 + SymbolName: .text + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 612 + SymbolName: _main + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 616 + SymbolName: _main + Type: IMAGE_REL_I386_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 116 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: func + - Kind: LF_POINTER + Pointer: + ReferentType: 1136 + Attrs: 32778 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 4099 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4100 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4101 + Name: main + - Name: .llvm_addrsig + Characteristics: [ IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 0F +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 85 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 1989857796 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .drectve + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 48 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 149686238 + Number: 4 + - Name: '.debug$S' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 988 + NumberOfRelocations: 18 + NumberOfLinenumbers: 0 + CheckSum: 2571438511 + Number: 5 + - Name: '.debug$T' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 120 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3148269371 + Number: 6 + - Name: .llvm_addrsig + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 2428444049 + Number: 7 + - Name: '@feat.00' + Value: 1 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '?func@@YAHHH@Z' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _main + Value: 32 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: lld/test/COFF/pdb-linker-module.test =================================================================== --- lld/test/COFF/pdb-linker-module.test +++ lld/test/COFF/pdb-linker-module.test @@ -5,7 +5,7 @@ MODS: Mod 0001 | `* Linker *` MODS-NEXT: Obj: ``: -MODS-NEXT: debug stream: 12, # files: 0, has ec info: false +MODS-NEXT: debug stream: 13, # files: 0, has ec info: false MODS-NEXT: pdb file ni: 1 `{{.*}}pdb-linker-module.test.tmp.pdb`, src file ni: 0 `` SYMS: Mod 0001 | `* Linker *` Index: llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h +++ llvm/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h @@ -26,11 +26,12 @@ } Error initialize(BinaryStreamReader Reader); + Error initialize(BinaryStreamRef Stream); FixedStreamArray::Iterator begin() const { return Frames.begin(); } FixedStreamArray::Iterator end() const { return Frames.end(); } - const void *getRelocPtr() const { return RelocPtr; } + const uint32_t *getRelocPtr() const { return RelocPtr; } private: const uint32_t *RelocPtr = nullptr; @@ -39,8 +40,9 @@ class DebugFrameDataSubsection final : public DebugSubsection { public: - DebugFrameDataSubsection() - : DebugSubsection(DebugSubsectionKind::FrameData) {} + DebugFrameDataSubsection(bool IncludeRelocPtr) + : DebugSubsection(DebugSubsectionKind::FrameData), + IncludeRelocPtr(IncludeRelocPtr) {} static bool classof(const DebugSubsection *S) { return S->kind() == DebugSubsectionKind::FrameData; } @@ -52,6 +54,7 @@ void setFrames(ArrayRef Frames); private: + bool IncludeRelocPtr = false; std::vector Frames; }; } Index: llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -15,6 +15,7 @@ #include "llvm/BinaryFormat/COFF.h" #include "llvm/Support/Error.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" @@ -24,6 +25,9 @@ #include "llvm/Support/Endian.h" namespace llvm { +namespace codeview { +struct FrameData; +} namespace msf { class MSFBuilder; } @@ -65,6 +69,7 @@ void setGlobalsStreamIndex(uint32_t Index); void setPublicsStreamIndex(uint32_t Index); void setSymbolRecordStreamIndex(uint32_t Index); + void addFrameData(const codeview::FrameData &FD); Expected addModuleInfo(StringRef ModuleName); Error addModuleSourceFile(DbiModuleDescriptorBuilder &Module, StringRef File); @@ -84,7 +89,8 @@ private: struct DebugStream { - ArrayRef Data; + std::function WriteFn; + uint32_t Size = 0; uint16_t StreamNumber = kInvalidStreamIndex; }; @@ -117,6 +123,8 @@ std::vector> ModiList; + Optional FrameData; + StringMap SourceFileNames; PDBStringTableBuilder ECNamesBuilder; Index: llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp @@ -14,8 +14,11 @@ using namespace llvm::codeview; Error DebugFrameDataSubsectionRef::initialize(BinaryStreamReader Reader) { - if (auto EC = Reader.readObject(RelocPtr)) - return EC; + if (Reader.bytesRemaining() % sizeof(FrameData) != 0) { + if (auto EC = Reader.readObject(RelocPtr)) + return EC; + } + if (Reader.bytesRemaining() % sizeof(FrameData) != 0) return make_error(cv_error_code::corrupt_record, "Invalid frame data record format!"); @@ -26,15 +29,30 @@ return Error::success(); } +Error DebugFrameDataSubsectionRef::initialize(BinaryStreamRef Section) { + BinaryStreamReader Reader(Section); + return initialize(Reader); +} + uint32_t DebugFrameDataSubsection::calculateSerializedSize() const { - return 4 + sizeof(FrameData) * Frames.size(); + uint32_t Size = sizeof(FrameData) * Frames.size(); + if (IncludeRelocPtr) + Size += sizeof(uint32_t); + return Size; } Error DebugFrameDataSubsection::commit(BinaryStreamWriter &Writer) const { - if (auto EC = Writer.writeInteger(0)) - return EC; - - if (auto EC = Writer.writeArray(makeArrayRef(Frames))) + if (IncludeRelocPtr) { + if (auto EC = Writer.writeInteger(0)) + return EC; + } + + std::vector SortedFrames(Frames.begin(), Frames.end()); + std::sort(SortedFrames.begin(), SortedFrames.end(), + [](const FrameData &LHS, const FrameData &RHS) { + return LHS.RvaStart < RHS.RvaStart; + }); + if (auto EC = Writer.writeArray(makeArrayRef(SortedFrames))) return EC; return Error::success(); } Index: llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" @@ -74,10 +75,23 @@ PublicsStreamIndex = Index; } +void DbiStreamBuilder::addFrameData(const codeview::FrameData &FD) { + if (!FrameData.hasValue()) + FrameData.emplace(false); + + FrameData->addFrameData(FD); +} + Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, ArrayRef Data) { + assert(Type != DbgHeaderType::NewFPO && + "NewFPO data should be written via addFrameData()!"); + DbgStreams[(int)Type].emplace(); - DbgStreams[(int)Type]->Data = Data; + DbgStreams[(int)Type]->Size = Data.size(); + DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) { + return Writer.writeArray(Data); + }; return Error::success(); } @@ -272,10 +286,20 @@ } Error DbiStreamBuilder::finalizeMsfLayout() { + if (FrameData.hasValue()) { + DbgStreams[(int)DbgHeaderType::NewFPO].emplace(); + DbgStreams[(int)DbgHeaderType::NewFPO]->Size = + FrameData->calculateSerializedSize(); + DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return FrameData->commit(Writer); + }; + } + for (auto &S : DbgStreams) { if (!S.hasValue()) continue; - auto ExpectedIndex = Msf.addStream(S->Data.size()); + auto ExpectedIndex = Msf.addStream(S->Size); if (!ExpectedIndex) return ExpectedIndex.takeError(); S->StreamNumber = *ExpectedIndex; @@ -406,7 +430,8 @@ auto WritableStream = WritableMappedBlockStream::createIndexedStream( Layout, MsfBuffer, Stream->StreamNumber, Allocator); BinaryStreamWriter DbgStreamWriter(*WritableStream); - if (auto EC = DbgStreamWriter.writeArray(Stream->Data)) + + if (auto EC = Stream->WriteFn(DbgStreamWriter)) return EC; } Index: llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp =================================================================== --- llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp +++ llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp @@ -511,7 +511,7 @@ const codeview::StringsAndChecksums &SC) const { assert(SC.hasStrings()); - auto Result = std::make_shared(); + auto Result = std::make_shared(true); for (const auto &YF : Frames) { codeview::FrameData F; F.CodeSize = YF.CodeSize; Index: llvm/tools/llvm-pdbutil/DumpOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbutil/DumpOutputStyle.h +++ llvm/tools/llvm-pdbutil/DumpOutputStyle.h @@ -85,6 +85,7 @@ Error dumpInlineeLines(); Error dumpXmi(); Error dumpXme(); + Error dumpFpo(); Error dumpTpiStream(uint32_t StreamIdx); Error dumpTypesFromObjectFile(); Error dumpModules(); Index: llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -22,6 +22,7 @@ #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" @@ -142,6 +143,11 @@ return EC; } + if (opts::dump::DumpFpo) { + if (auto EC = dumpFpo()) + return EC; + } + if (File.isObj()) { if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || opts::dump::DumpTypeExtras) @@ -985,6 +991,58 @@ return Error::success(); } +Error DumpOutputStyle::dumpFpo() { + printHeader(P, "New FPO Data"); + + if (!File.isPdb()) { + printStreamNotValidForObj(); + return Error::success(); + } + + PDBFile &File = getPdb(); + if (!File.hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + ExitOnError Err("Error dumping fpo data:"); + + auto &Dbi = Err(File.getPDBDbiStream()); + + uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::NewFPO); + if (Index == kInvalidStreamIndex) { + printStreamNotPresent("New FPO"); + return Error::success(); + } + + std::unique_ptr NewFpo = File.createIndexedStream(Index); + + DebugFrameDataSubsectionRef FDS; + if (auto EC = FDS.initialize(*NewFpo)) + return make_error(raw_error_code::corrupt_file, + "Invalid new fpo stream"); + + P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs " + "| Has SEH | Has C++EH | Start | Program"); + for (const FrameData &FD : FDS) { + bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart; + bool HasEH = FD.Flags & FrameData::HasEH; + bool HasSEH = FD.Flags & FrameData::HasSEH; + + auto &StringTable = Err(File.getStringTable()); + + auto Program = Err(StringTable.getStringForID(FD.FrameFunc)); + P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | " + "{7,7} | {8,9} | {9,5} | {10}", + uint32_t(FD.RvaStart), uint32_t(FD.CodeSize), + uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize), + uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize), + uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart, + Program); + } + return Error::success(); +} + Error DumpOutputStyle::dumpStringTableFromPdb() { AutoIndent Indent(P); auto IS = getPdb().getStringTable(); Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.h =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.h +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.h @@ -171,6 +171,7 @@ extern llvm::cl::opt DumpSectionMap; extern llvm::cl::opt DumpModules; extern llvm::cl::opt DumpModuleFiles; +extern llvm::cl::opt DumpFpo; extern llvm::cl::opt RawAll; } Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -501,6 +501,9 @@ cl::desc("dump CodeView symbol record raw bytes"), cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); +cl::opt DumpFpo("fpo", cl::desc("dump FPO records"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); + // MODULE & FILE OPTIONS cl::opt DumpModules("modules", cl::desc("dump compiland information"), cl::cat(FileOptions), cl::sub(DumpSubcommand)); @@ -1372,6 +1375,7 @@ if (opts::DumpSubcommand) { if (opts::dump::RawAll) { opts::dump::DumpGlobals = true; + opts::dump::DumpFpo = true; opts::dump::DumpInlineeLines = true; opts::dump::DumpIds = true; opts::dump::DumpIdExtras = true;