Index: include/llvm/DebugInfo/PDB/Raw/DbiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -24,6 +24,7 @@ namespace llvm { namespace object { +struct FpoData; struct coff_section; } @@ -65,6 +66,8 @@ codeview::FixedStreamArray getSectionHeaders(); + codeview::FixedStreamArray getFpoRecords(); + codeview::FixedStreamArray getSectionMap() const; void visitSectionContributions(ISectionContribVisitor &Visitor) const; @@ -73,6 +76,7 @@ Error initializeSectionHeadersData(); Error initializeSectionMapData(); Error initializeFileInfo(); + Error initializeFpoRecords(); PDBFile &Pdb; MappedBlockStream Stream; @@ -100,6 +104,9 @@ std::unique_ptr SectionHeaderStream; codeview::FixedStreamArray SectionHeaders; + std::unique_ptr FpoStream; + codeview::FixedStreamArray FpoRecords; + const HeaderInfo *Header; }; } Index: include/llvm/Object/COFF.h =================================================================== --- include/llvm/Object/COFF.h +++ include/llvm/Object/COFF.h @@ -1012,6 +1012,30 @@ const COFFObjectFile *OwningObject; }; +// Corresponds to `_FPO_DATA` structure in the PE/COFF spec. +struct FpoData { + support::ulittle32_t Offset; // ulOffStart: Offset 1st byte of function code + support::ulittle32_t Size; // cbProcSize: # bytes in function + support::ulittle32_t NumLocals; // cdwLocals: # bytes in locals/4 + support::ulittle16_t NumParams; // cdwParams: # bytes in params/4 + support::ulittle16_t Attributes; + + // cbProlog: # bytes in prolog + int getPrologSize() const { return Attributes & 0xF; } + + // cbRegs: # regs saved + int getNumSavedRegs() const { return (Attributes >> 8) & 0x7; } + + // fHasSEH: true if seh is func + bool hasSEH() const { return (Attributes >> 9) & 1; } + + // fUseBP: true if EBP has been allocated + bool useBP() const { return (Attributes >> 10) & 1; } + + // cbFrame: frame pointer + int getFP() const { return Attributes >> 14; } +}; + } // end namespace object } // end namespace llvm Index: lib/DebugInfo/PDB/Raw/DbiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -186,9 +186,10 @@ return EC; if (auto EC = initializeSectionMapData()) return EC; - if (auto EC = initializeFileInfo()) return EC; + if (auto EC = initializeFpoRecords()) + return EC; if (Reader.bytesRemaining() > 0) return make_error(raw_error_code::corrupt_file, @@ -252,6 +253,10 @@ return SectionHeaders; } +codeview::FixedStreamArray DbiStream::getFpoRecords() { + return FpoRecords; +} + ArrayRef DbiStream::modules() const { return ModuleInfos; } codeview::FixedStreamArray DbiStream::getSectionMap() const { return SectionMap; @@ -300,6 +305,20 @@ return Error::success(); } +// Initializes this->Fpos. +Error DbiStream::initializeFpoRecords() { + uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO); + FpoStream.reset(new MappedBlockStream(StreamNum, Pdb)); + + size_t StreamLen = FpoStream->getLength(); + size_t NumRecords = StreamLen / sizeof(object::FpoData); + codeview::StreamReader Reader(*FpoStream); + if (auto EC = Reader.readArray(FpoRecords, NumRecords)) + return make_error(raw_error_code::corrupt_file, + "Corrupted New FPO stream."); + return Error::success(); +} + Error DbiStream::initializeSectionMapData() { StreamReader SMReader(SecMapSubstream); const SecMapHeader *Header; Index: test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- test/DebugInfo/PDB/pdbdump-headers.test +++ test/DebugInfo/PDB/pdbdump-headers.test @@ -2,7 +2,7 @@ ; RUN: -raw-sym-record-bytes -raw-publics -raw-module-files -raw-stream-name=/names \ ; RUN: -raw-stream-summary -raw-stream-blocks -raw-ipi-records -raw-ipi-record-bytes \ ; RUN: -raw-section-contribs -raw-section-map -raw-section-headers -raw-line-info \ -; RUN: -raw-tpi-hash %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s +; RUN: -raw-tpi-hash -raw-fpo %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s ; RUN: llvm-pdbdump -raw-all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s ; RUN: llvm-pdbdump -raw-headers -raw-stream-name=/names -raw-modules -raw-module-files \ ; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s @@ -898,6 +898,30 @@ ; EMPTY-NEXT: Characteristics: 1107296320 ; EMPTY-NEXT: } ; EMPTY-NEXT: ] +; EMPTY: New FPO [ +; EMPTY-NEXT: { +; EMPTY-NEXT: Offset: 4112 +; EMPTY-NEXT: Size: 10 +; EMPTY-NEXT: Number of locals: 0 +; EMPTY-NEXT: Number of params: 0 +; EMPTY-NEXT: Size of Prolog: 0 +; EMPTY-NEXT: Number of Saved Registers: 0 +; EMPTY-NEXT: Has SEH: No +; EMPTY-NEXT: Use BP: No +; EMPTY-NEXT: Frame Pointer: 0 +; EMPTY-NEXT: } +; EMPTY-NEXT: { +; EMPTY-NEXT: Offset: 0 +; EMPTY-NEXT: Size: 134 +; EMPTY-NEXT: Number of locals: 3 +; EMPTY-NEXT: Number of params: 4 +; EMPTY-NEXT: Size of Prolog: 0 +; EMPTY-NEXT: Number of Saved Registers: 0 +; EMPTY-NEXT: Has SEH: No +; EMPTY-NEXT: Use BP: No +; EMPTY-NEXT: Frame Pointer: 0 +; EMPTY-NEXT: } +; EMPTY-NEXT: ] ; ALL: FileHeaders { ; ALL: BlockSize: 4096 Index: tools/llvm-pdbdump/LLVMOutputStyle.h =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.h +++ tools/llvm-pdbdump/LLVMOutputStyle.h @@ -33,6 +33,7 @@ Error dumpSectionMap() override; Error dumpPublicsStream() override; Error dumpSectionHeaders() override; + Error dumpFpoStream() override; private: PDBFile &File; Index: tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -669,3 +669,28 @@ } return Error::success(); } + +Error LLVMOutputStyle::dumpFpoStream() { + if (!opts::DumpFpo) + return Error::success(); + + auto DbiS = File.getPDBDbiStream(); + if (auto EC = DbiS.takeError()) + return EC; + DbiStream &DS = DbiS.get(); + + ListScope D(P, "New FPO"); + for (const object::FpoData &Fpo : DS.getFpoRecords()) { + DictScope DD(P, ""); + P.printNumber("Offset", Fpo.Offset); + P.printNumber("Size", Fpo.Size); + P.printNumber("Number of locals", Fpo.NumLocals); + P.printNumber("Number of params", Fpo.NumParams); + P.printNumber("Size of Prolog", Fpo.getPrologSize()); + P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs()); + P.printBoolean("Has SEH", Fpo.hasSEH()); + P.printBoolean("Use BP", Fpo.useBP()); + P.printNumber("Frame Pointer", Fpo.getFP()); + } + return Error::success(); +} Index: tools/llvm-pdbdump/OutputStyle.h =================================================================== --- tools/llvm-pdbdump/OutputStyle.h +++ tools/llvm-pdbdump/OutputStyle.h @@ -31,6 +31,7 @@ virtual Error dumpSectionMap() = 0; virtual Error dumpPublicsStream() = 0; virtual Error dumpSectionHeaders() = 0; + virtual Error dumpFpoStream() = 0; }; } } Index: tools/llvm-pdbdump/llvm-pdbdump.h =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.h +++ tools/llvm-pdbdump/llvm-pdbdump.h @@ -43,6 +43,7 @@ extern llvm::cl::opt DumpSectionMap; extern llvm::cl::opt DumpSymRecordBytes; extern llvm::cl::opt DumpSectionHeaders; +extern llvm::cl::opt DumpFpo; extern llvm::cl::opt ExcludeCompilerGenerated; Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -154,6 +154,8 @@ cl::opt DumpSectionHeaders("raw-section-headers", cl::desc("dump section headers"), cl::cat(NativeOptions)); +cl::opt DumpFpo("raw-fpo", cl::desc("dump FPO records"), + cl::cat(NativeOptions)); cl::opt RawAll("raw-all", @@ -251,6 +253,9 @@ if (auto EC = O->dumpSectionHeaders()) return EC; + + if (auto EC = O->dumpFpoStream()) + return EC; return Error::success(); } @@ -291,6 +296,8 @@ return true; if (opts::DumpLineInfo) return true; + if (opts::DumpFpo) + return true; return false; } @@ -460,6 +467,7 @@ opts::DumpSectionMap = true; opts::DumpSectionContribs = true; opts::DumpLineInfo = true; + opts::DumpFpo = true; } // When adding filters for excluded compilands and types, we need to remember