OSDN Git Service

[pdbdump] Print out New FPO stream contents.
authorRui Ueyama <ruiu@google.com>
Mon, 6 Jun 2016 18:39:21 +0000 (18:39 +0000)
committerRui Ueyama <ruiu@google.com>
Mon, 6 Jun 2016 18:39:21 +0000 (18:39 +0000)
The data strucutre in the new FPO stream is described in the
PE/COFF spec. There is one record per function if frame pointer
is omitted.

Differential Revision: http://reviews.llvm.org/D20999

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@271926 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/PDB/Raw/DbiStream.h
include/llvm/Object/COFF.h
lib/DebugInfo/PDB/Raw/DbiStream.cpp
test/DebugInfo/PDB/pdbdump-headers.test
tools/llvm-pdbdump/LLVMOutputStyle.cpp
tools/llvm-pdbdump/LLVMOutputStyle.h
tools/llvm-pdbdump/OutputStyle.h
tools/llvm-pdbdump/llvm-pdbdump.cpp
tools/llvm-pdbdump/llvm-pdbdump.h

index 132dfda..525aa7e 100644 (file)
@@ -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;
 };
 }
index 4578ce1..5f13137 100644 (file)
@@ -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
 
index e79d657..b1c571b 100644 (file)
@@ -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;
index b4ecf95..c3a97f0 100644 (file)
@@ -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
 ; 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 2c3dabf..1707454 100644 (file)
@@ -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();
+}
index 1643b42..0c601c9 100644 (file)
@@ -33,6 +33,7 @@ public:
   Error dumpSectionMap() override;
   Error dumpPublicsStream() override;
   Error dumpSectionHeaders() override;
+  Error dumpFpoStream() override;
 
 private:
   PDBFile &File;
index d8ab0d4..c42f7d2 100644 (file)
@@ -31,6 +31,7 @@ public:
   virtual Error dumpSectionMap() = 0;
   virtual Error dumpPublicsStream() = 0;
   virtual Error dumpSectionHeaders() = 0;
+  virtual Error dumpFpoStream() = 0;
 };
 }
 }
index 4396c0d..b798929 100644 (file)
@@ -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
index 4c12bea..4a6afae 100644 (file)
@@ -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;