diff options
-rw-r--r-- | llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h | 7 | ||||
-rw-r--r-- | llvm/include/llvm/Object/COFF.h | 24 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp | 25 | ||||
-rw-r--r-- | llvm/test/DebugInfo/PDB/pdbdump-headers.test | 26 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp | 25 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/LLVMOutputStyle.h | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/OutputStyle.h | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp | 8 | ||||
-rw-r--r-- | llvm/tools/llvm-pdbdump/llvm-pdbdump.h | 1 |
9 files changed, 116 insertions, 2 deletions
diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h b/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h index 132dfda5506..525aa7e3fa8 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -24,6 +24,7 @@ namespace llvm { namespace object { +struct FpoData; struct coff_section; } @@ -65,6 +66,8 @@ public: codeview::FixedStreamArray<object::coff_section> getSectionHeaders(); + codeview::FixedStreamArray<object::FpoData> getFpoRecords(); + codeview::FixedStreamArray<SecMapEntry> getSectionMap() const; void visitSectionContributions(ISectionContribVisitor &Visitor) const; @@ -73,6 +76,7 @@ private: Error initializeSectionHeadersData(); Error initializeSectionMapData(); Error initializeFileInfo(); + Error initializeFpoRecords(); PDBFile &Pdb; MappedBlockStream Stream; @@ -100,6 +104,9 @@ private: std::unique_ptr<MappedBlockStream> SectionHeaderStream; codeview::FixedStreamArray<object::coff_section> SectionHeaders; + std::unique_ptr<MappedBlockStream> FpoStream; + codeview::FixedStreamArray<object::FpoData> FpoRecords; + const HeaderInfo *Header; }; } diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h index 4578ce10f1c..5f13137e26e 100644 --- a/llvm/include/llvm/Object/COFF.h +++ b/llvm/include/llvm/Object/COFF.h @@ -1012,6 +1012,30 @@ private: 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 diff --git a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp index e79d6572be1..b1c571bf78c 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -186,9 +186,10 @@ Error DbiStream::reload() { 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<RawError>(raw_error_code::corrupt_file, @@ -252,6 +253,10 @@ DbiStream::getSectionHeaders() { return SectionHeaders; } +codeview::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { + return FpoRecords; +} + ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; } codeview::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { return SectionMap; @@ -300,6 +305,24 @@ Error DbiStream::initializeSectionHeadersData() { 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(); + if (StreamLen % sizeof(object::FpoData)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted New FPO stream."); + + size_t NumRecords = StreamLen / sizeof(object::FpoData); + codeview::StreamReader Reader(*FpoStream); + if (auto EC = Reader.readArray(FpoRecords, NumRecords)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted New FPO stream."); + return Error::success(); +} + Error DbiStream::initializeSectionMapData() { StreamReader SMReader(SecMapSubstream); const SecMapHeader *Header; diff --git a/llvm/test/DebugInfo/PDB/pdbdump-headers.test b/llvm/test/DebugInfo/PDB/pdbdump-headers.test index b4ecf9500b0..c3a97f0dd64 100644 --- a/llvm/test/DebugInfo/PDB/pdbdump-headers.test +++ b/llvm/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 diff --git a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 2c3dabf613b..1707454df66 100644 --- a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -669,3 +669,28 @@ Error LLVMOutputStyle::dumpSectionHeaders() { } 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(); +} diff --git a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h index 1643b42bbdf..0c601c9b9b1 100644 --- a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h +++ b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h @@ -33,6 +33,7 @@ public: Error dumpSectionMap() override; Error dumpPublicsStream() override; Error dumpSectionHeaders() override; + Error dumpFpoStream() override; private: PDBFile &File; diff --git a/llvm/tools/llvm-pdbdump/OutputStyle.h b/llvm/tools/llvm-pdbdump/OutputStyle.h index d8ab0d46464..c42f7d21002 100644 --- a/llvm/tools/llvm-pdbdump/OutputStyle.h +++ b/llvm/tools/llvm-pdbdump/OutputStyle.h @@ -31,6 +31,7 @@ public: virtual Error dumpSectionMap() = 0; virtual Error dumpPublicsStream() = 0; virtual Error dumpSectionHeaders() = 0; + virtual Error dumpFpoStream() = 0; }; } } diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 4396c0d681b..b798929ace8 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -154,6 +154,8 @@ cl::opt<bool> cl::opt<bool> DumpSectionHeaders("raw-section-headers", cl::desc("dump section headers"), cl::cat(NativeOptions)); +cl::opt<bool> DumpFpo("raw-fpo", cl::desc("dump FPO records"), + cl::cat(NativeOptions)); cl::opt<bool> RawAll("raw-all", @@ -251,6 +253,9 @@ static Error dumpStructure(RawSession &RS) { if (auto EC = O->dumpSectionHeaders()) return EC; + + if (auto EC = O->dumpFpoStream()) + return EC; return Error::success(); } @@ -291,6 +296,8 @@ bool isRawDumpEnabled() { return true; if (opts::DumpLineInfo) return true; + if (opts::DumpFpo) + return true; return false; } @@ -460,6 +467,7 @@ int main(int argc_, const char *argv_[]) { opts::DumpSectionMap = true; opts::DumpSectionContribs = true; opts::DumpLineInfo = true; + opts::DumpFpo = true; } // When adding filters for excluded compilands and types, we need to remember diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h index 4c12beadce3..4a6afaeb14e 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -43,6 +43,7 @@ extern llvm::cl::opt<bool> DumpLineInfo; extern llvm::cl::opt<bool> DumpSectionMap; extern llvm::cl::opt<bool> DumpSymRecordBytes; extern llvm::cl::opt<bool> DumpSectionHeaders; +extern llvm::cl::opt<bool> DumpFpo; extern llvm::cl::opt<bool> ExcludeCompilerGenerated; |