]> granicus.if.org Git - llvm/commitdiff
[llvm-pdbdump] Allow printing only a portion of a stream.
authorZachary Turner <zturner@google.com>
Fri, 28 Apr 2017 00:43:38 +0000 (00:43 +0000)
committerZachary Turner <zturner@google.com>
Fri, 28 Apr 2017 00:43:38 +0000 (00:43 +0000)
When dumping raw data from a stream, you might know the offset
of a certain record you're interested in, as well as how long
that record is.  Previously, you had to dump the entire stream
and wade through the bytes to find the interesting record.

This patch allows you to specify an offset and length on the
command line, and it will only dump the requested range.

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

include/llvm/Support/ScopedPrinter.h
lib/Support/ScopedPrinter.cpp
test/tools/llvm-pdbdump/raw-stream-data.test [new file with mode: 0644]
tools/llvm-pdbdump/LLVMOutputStyle.cpp
tools/llvm-pdbdump/llvm-pdbdump.cpp
tools/llvm-pdbdump/llvm-pdbdump.h

index a2f2e0985431427ee3df1193d88d4d27d337bb4c..1b66519322129fe62de95a818966d549b71dccce 100644 (file)
@@ -295,6 +295,11 @@ public:
     printBinaryImpl(Label, StringRef(), V, false);
   }
 
+  void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
+                        uint32_t StartOffset) {
+    printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
+  }
+
   void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
     printBinaryImpl(Label, StringRef(), Value, true);
   }
@@ -333,7 +338,7 @@ private:
   }
 
   void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
-                       bool Block);
+                       bool Block, uint32_t StartOffset = 0);
 
   raw_ostream &OS;
   int IndentLevel;
index d8ee1efd8f3e6934932e1aa1b6f9bafc47abfa49..537ff62c7b09c14e4f5f63fb100982c06180303b 100644 (file)
@@ -21,7 +21,8 @@ const std::string to_hexString(uint64_t Value, bool UpperCase) {
 }
 
 void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str,
-                                    ArrayRef<uint8_t> Data, bool Block) {
+                                    ArrayRef<uint8_t> Data, bool Block,
+                                    uint32_t StartOffset) {
   if (Data.size() > 16)
     Block = true;
 
@@ -31,7 +32,8 @@ void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str,
       OS << ": " << Str;
     OS << " (\n";
     if (!Data.empty())
-      OS << format_bytes_with_ascii(Data, 0, 16, 4, (IndentLevel + 1) * 2, true)
+      OS << format_bytes_with_ascii(Data, StartOffset, 16, 4,
+                                    (IndentLevel + 1) * 2, true)
          << "\n";
     startLine() << ")\n";
   } else {
diff --git a/test/tools/llvm-pdbdump/raw-stream-data.test b/test/tools/llvm-pdbdump/raw-stream-data.test
new file mode 100644 (file)
index 0000000..d559806
--- /dev/null
@@ -0,0 +1,47 @@
+; RUN: llvm-pdbdump raw -stream-data=8 %p/Inputs/LoadAddressTest.pdb \\r
+; RUN:   | FileCheck %s -check-prefix=FULL_STREAM\r
+; RUN: llvm-pdbdump raw -stream-data=8:4 %p/Inputs/LoadAddressTest.pdb \\r
+; RUN:   | FileCheck %s -check-prefix=OFFSET_STREAM\r
+; RUN: llvm-pdbdump raw -stream-data=8:4@24 %p/Inputs/LoadAddressTest.pdb \\r
+; RUN:   | FileCheck %s -check-prefix=OFFSET_AND_LENGTH\r
+\r
+FULL_STREAM:      Stream Data {\r
+FULL_STREAM-NEXT:   Stream {\r
+FULL_STREAM-NEXT:     Index: 8\r
+FULL_STREAM-NEXT:     Type: Public Symbol Records\r
+FULL_STREAM-NEXT:     Size: 40\r
+FULL_STREAM-NEXT:     Blocks:\r
+FULL_STREAM-NEXT:     Data (\r
+FULL_STREAM-NEXT:       0000: 12000E11 02000000 10000000 01005F6D  |.............._m|\r
+FULL_STREAM-NEXT:       0010: 61696E00 12002511 00000000 88000000  |ain...%.........|\r
+FULL_STREAM-NEXT:       0020: 01006D61 696E0000                    |..main..|\r
+FULL_STREAM-NEXT:     )\r
+FULL_STREAM-NEXT:   }\r
+FULL_STREAM-NEXT: }\r
+\r
+OFFSET_STREAM:      Stream Data {\r
+OFFSET_STREAM-NEXT:   Stream {\r
+OFFSET_STREAM-NEXT:    Index: 8\r
+OFFSET_STREAM-NEXT:    Type: Public Symbol Records\r
+OFFSET_STREAM-NEXT:    Size: 40\r
+OFFSET_STREAM-NEXT:    Blocks: \r
+OFFSET_STREAM-NEXT:    Data (\r
+OFFSET_STREAM-NEXT:      0004: 02000000 10000000 01005F6D 61696E00  |.........._main.|\r
+OFFSET_STREAM-NEXT:      0014: 12002511 00000000 88000000 01006D61  |..%...........ma|\r
+OFFSET_STREAM-NEXT:      0024: 696E0000                             |in..|\r
+OFFSET_STREAM-NEXT:    )\r
+OFFSET_STREAM-NEXT:  }\r
+OFFSET_STREAM-NEXT:}\r
+\r
+OFFSET_AND_LENGTH:      Stream Data {\r
+OFFSET_AND_LENGTH-NEXT:   Stream {\r
+OFFSET_AND_LENGTH-NEXT:    Index: 8\r
+OFFSET_AND_LENGTH-NEXT:    Type: Public Symbol Records\r
+OFFSET_AND_LENGTH-NEXT:    Size: 40\r
+OFFSET_AND_LENGTH-NEXT:    Blocks: \r
+OFFSET_AND_LENGTH-NEXT:    Data (\r
+OFFSET_AND_LENGTH-NEXT:      0004: 02000000 10000000 01005F6D 61696E00  |.........._main.|\r
+OFFSET_AND_LENGTH-NEXT:      0014: 12002511 00000000                    |..%.....|\r
+OFFSET_AND_LENGTH-NEXT:    )\r
+OFFSET_AND_LENGTH-NEXT:  }\r
+OFFSET_AND_LENGTH-NEXT:}
\ No newline at end of file
index 20223ac60f430bbe2ca803eee991625bf833ae44..705728e27d015ffd438e41a42e95afcdd12dcc6c 100644 (file)
@@ -319,6 +319,27 @@ Error LLVMOutputStyle::dumpBlockRanges() {
   return Error::success();
 }
 
+static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
+                             uint32_t &Size) {
+  if (Str.consumeInteger(0, SI))
+    return make_error<RawError>(raw_error_code::invalid_format,
+                                "Invalid Stream Specification");
+  if (Str.consume_front(":")) {
+    if (Str.consumeInteger(0, Offset))
+      return make_error<RawError>(raw_error_code::invalid_format,
+                                  "Invalid Stream Specification");
+  }
+  if (Str.consume_front("@")) {
+    if (Str.consumeInteger(0, Size))
+      return make_error<RawError>(raw_error_code::invalid_format,
+                                  "Invalid Stream Specification");
+  }
+  if (!Str.empty())
+    return make_error<RawError>(raw_error_code::invalid_format,
+                                "Invalid Stream Specification");
+  return Error::success();
+}
+
 Error LLVMOutputStyle::dumpStreamBytes() {
   if (opts::raw::DumpStreamData.empty())
     return Error::success();
@@ -327,7 +348,15 @@ Error LLVMOutputStyle::dumpStreamBytes() {
     discoverStreamPurposes(File, StreamPurposes);
 
   DictScope D(P, "Stream Data");
-  for (uint32_t SI : opts::raw::DumpStreamData) {
+  for (auto &Str : opts::raw::DumpStreamData) {
+    uint32_t SI = 0;
+    uint32_t Begin = 0;
+    uint32_t Size = 0;
+    uint32_t End = 0;
+
+    if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
+      return EC;
+
     if (SI >= File.getNumStreams())
       return make_error<RawError>(raw_error_code::no_stream);
 
@@ -336,6 +365,14 @@ Error LLVMOutputStyle::dumpStreamBytes() {
     if (!S)
       continue;
     DictScope DD(P, "Stream");
+    if (Size == 0)
+      End = S->getLength();
+    else {
+      End = Begin + Size;
+      if (End >= S->getLength())
+        return make_error<RawError>(raw_error_code::index_out_of_bounds,
+                                    "Stream is not long enough!");
+    }
 
     P.printNumber("Index", SI);
     P.printString("Type", StreamPurposes[SI]);
@@ -347,7 +384,9 @@ Error LLVMOutputStyle::dumpStreamBytes() {
     ArrayRef<uint8_t> StreamData;
     if (auto EC = R.readBytes(StreamData, S->getLength()))
       return EC;
-    P.printBinaryBlock("Data", StreamData);
+    Size = End - Begin;
+    StreamData = StreamData.slice(Begin, Size);
+    P.printBinaryBlock("Data", StreamData, Begin);
   }
   return Error::success();
 }
index 3d7dbffb0d5b6a1ef61f0efd90fbd21d0cb96ce6..e6d363e1626445594e1462e0f2f17e9c85ee2cb6 100644 (file)
@@ -261,9 +261,10 @@ cl::opt<std::string>
                       cl::cat(MsfOptions), cl::sub(RawSubcommand));
 llvm::Optional<BlockRange> DumpBlockRange;
 
-cl::list<uint32_t>
+cl::list<std::string>
     DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
-                   cl::desc("Dump binary data from specified streams."),
+                   cl::desc("Dump binary data from specified streams.  Format "
+                            "is SN[:Start][@Size]"),
                    cl::cat(MsfOptions), cl::sub(RawSubcommand));
 
 // TYPE OPTIONS
index f080d6d552501cb22cc29dedccad4e5813359373..8b1dde9399bfa78d4241ffba9bb773f82ad3fd52 100644 (file)
@@ -60,7 +60,7 @@ struct BlockRange {
 };
 
 extern llvm::Optional<BlockRange> DumpBlockRange;
-extern llvm::cl::list<uint32_t> DumpStreamData;
+extern llvm::cl::list<std::string> DumpStreamData;
 
 extern llvm::cl::opt<bool> CompactRecords;
 extern llvm::cl::opt<bool> DumpGlobals;