summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h7
-rw-r--r--llvm/include/llvm/Object/COFF.h24
-rw-r--r--llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp25
-rw-r--r--llvm/test/DebugInfo/PDB/pdbdump-headers.test26
-rw-r--r--llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp25
-rw-r--r--llvm/tools/llvm-pdbdump/LLVMOutputStyle.h1
-rw-r--r--llvm/tools/llvm-pdbdump/OutputStyle.h1
-rw-r--r--llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp8
-rw-r--r--llvm/tools/llvm-pdbdump/llvm-pdbdump.h1
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;
OpenPOWER on IntegriCloud