]> granicus.if.org Git - llvm/commitdiff
[llvm-pdbutil] Add the ability to dump raw bytes from the file.
authorZachary Turner <zturner@google.com>
Fri, 23 Jun 2017 19:54:44 +0000 (19:54 +0000)
committerZachary Turner <zturner@google.com>
Fri, 23 Jun 2017 19:54:44 +0000 (19:54 +0000)
Normally we can only make sense of the content of a PDB in terms
of streams and blocks, but in some cases it may be useful to dump
bytes at a specific absolute file offset.  For example, if you
know that some interesting data is at a particular location and
you want to see some surrounding data.

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

test/DebugInfo/PDB/pdbdump-raw-blocks.test
test/DebugInfo/PDB/pdbdump-raw-bytes.test [new file with mode: 0644]
tools/llvm-pdbutil/BytesOutputStyle.cpp
tools/llvm-pdbutil/BytesOutputStyle.h
tools/llvm-pdbutil/llvm-pdbutil.cpp
tools/llvm-pdbutil/llvm-pdbutil.h

index 16cd8e7a469409e5dc0b153e044e55b5e2266d11..aa81293805b47167a3a04789cdfc1a7abab54c0e 100644 (file)
@@ -1,9 +1,9 @@
-; RUN: llvm-pdbutil bytes -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
-; RUN: llvm-pdbutil bytes -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
-; RUN: llvm-pdbutil bytes -block-data=0-0x1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
-; RUN: not llvm-pdbutil bytes -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
-; RUN: not llvm-pdbutil bytes -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
-; RUN: not llvm-pdbutil bytes -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
+; RUN: llvm-pdbutil bytes -block-range=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
+; RUN: llvm-pdbutil bytes -block-range=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
+; RUN: llvm-pdbutil bytes -block-range=0-0x1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
+; RUN: not llvm-pdbutil bytes -block-range=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
+; RUN: not llvm-pdbutil bytes -block-range=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
+; RUN: not llvm-pdbutil bytes -block-range=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
 
 BLOCK0:                         MSF Blocks
 BLOCK0-NEXT: ============================================================
diff --git a/test/DebugInfo/PDB/pdbdump-raw-bytes.test b/test/DebugInfo/PDB/pdbdump-raw-bytes.test
new file mode 100644 (file)
index 0000000..2c5c96c
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: llvm-pdbutil bytes -byte-range=20-60 %p/Inputs/empty.pdb | FileCheck --check-prefix=VALID %s\r
+; RUN: not llvm-pdbutil bytes -byte-range=100-20 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALID %s\r
+; RUN: not llvm-pdbutil bytes -byte-range=100000-200000 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALID-RANGE %s\r
+\r
+\r
+VALID:                               MSF Bytes\r
+VALID-NEXT: ============================================================\r
+VALID-NEXT:  Bytes (\r
+VALID-NEXT:    0014: 372E3030 0D0A1A44 53000000 00100000 02000000 19000000 88000000 00000000  |7.00...DS.......................|\r
+VALID-NEXT:    0034: 18000000 00000000 00                                                     |.........|\r
+VALID-NEXT:  )\r
+\r
+INVALID: llvm-pdbutil: Invalid byte range specified.  Max < Min\r
+\r
+INVALID-RANGE: llvm-pdbutil: Invalid byte range specified.  Requested byte larger than file size\r
index 123c55d207257db104dcc3d625cf83b5e3223ee1..9761987f0765b70214c71a8139be77dbc9914efb 100644 (file)
@@ -96,6 +96,22 @@ Error BytesOutputStyle::dump() {
     P.NewLine();
   }
 
+  if (opts::bytes::DumpByteRange.hasValue()) {
+    auto &R = *opts::bytes::DumpByteRange;
+    uint32_t Max = R.Max.getValueOr(File.getFileSize());
+
+    if (Max < R.Min)
+      return make_error<StringError>("Invalid byte range specified.  Max < Min",
+                                     inconvertibleErrorCode());
+    if (Max >= File.getFileSize())
+      return make_error<StringError>(
+          "Invalid byte range specified.  Requested byte larger than file size",
+          inconvertibleErrorCode());
+
+    dumpByteRanges(R.Min, Max);
+    P.NewLine();
+  }
+
   if (!opts::bytes::DumpStreamData.empty()) {
     dumpStreamBytes();
     P.NewLine();
@@ -122,6 +138,21 @@ void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
   }
 }
 
+void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
+  printHeader(P, "MSF Bytes");
+
+  AutoIndent Indent(P);
+
+  BinaryStreamReader Reader(File.getMsfBuffer());
+  ArrayRef<uint8_t> Data;
+  consumeError(Reader.skip(Min));
+  uint32_t Size = Max - Min + 1;
+  auto EC = Reader.readBytes(Data, Size);
+  assert(!EC);
+  consumeError(std::move(EC));
+  P.formatBinary("Bytes", Data, Min);
+}
+
 void BytesOutputStyle::dumpStreamBytes() {
   if (StreamPurposes.empty())
     discoverStreamPurposes(File, StreamPurposes);
index 7fd35e7860b3957c6fb3b3672d09c269d301e879..a2cefbbfb4cd5d59cb45d7084563b461f3376ce6 100644 (file)
@@ -29,6 +29,7 @@ public:
 
 private:
   void dumpBlockRanges(uint32_t Min, uint32_t Max);
+  void dumpByteRanges(uint32_t Min, uint32_t Max);
   void dumpStreamBytes();
 
   PDBFile &File;
index a86dccba50bcac0b202757e453c541b129b492ac..bdd8dfa164f4af6e6a746c5b257a58f7e6c01a9f 100644 (file)
@@ -267,12 +267,18 @@ cl::list<std::string> InputFilenames(cl::Positional,
 cl::OptionCategory FileOptions("Module & File Options");
 
 namespace bytes {
-llvm::Optional<BlockRange> DumpBlockRange;
+llvm::Optional<NumberRange> DumpBlockRange;
+llvm::Optional<NumberRange> DumpByteRange;
+
+cl::opt<std::string> DumpBlockRangeOpt(
+    "block-range", cl::value_desc("start[-end]"),
+    cl::desc("Dump binary data from specified range of blocks."),
+    cl::sub(BytesSubcommand));
 
 cl::opt<std::string>
-    DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
-                      cl::desc("Dump binary data from specified range."),
-                      cl::sub(BytesSubcommand));
+    DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"),
+                     cl::desc("Dump binary data from specified range of bytes"),
+                     cl::sub(BytesSubcommand));
 
 cl::list<std::string>
     DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
@@ -903,22 +909,23 @@ static void mergePdbs() {
   ExitOnErr(Builder.commit(OutFile));
 }
 
-static bool validateBlockRangeArgument() {
-  if (opts::bytes::DumpBlockRangeOpt.empty())
+static bool parseRange(StringRef Str,
+                       Optional<opts::bytes::NumberRange> &Parsed) {
+  if (Str.empty())
     return true;
 
   llvm::Regex R("^([^-]+)(-([^-]+))?$");
   llvm::SmallVector<llvm::StringRef, 2> Matches;
-  if (!R.match(opts::bytes::DumpBlockRangeOpt, &Matches))
+  if (!R.match(Str, &Matches))
     return false;
 
-  opts::bytes::DumpBlockRange.emplace();
-  if (!to_integer(Matches[1], opts::bytes::DumpBlockRange->Min))
+  Parsed.emplace();
+  if (!to_integer(Matches[1], Parsed->Min))
     return false;
 
   if (!Matches[3].empty()) {
-    opts::bytes::DumpBlockRange->Max.emplace();
-    if (!to_integer(Matches[3], *opts::bytes::DumpBlockRange->Max))
+    Parsed->Max.emplace();
+    if (!to_integer(Matches[3], *Parsed->Max))
       return false;
   }
   return true;
@@ -939,11 +946,22 @@ int main(int argc_, const char *argv_[]) {
   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
 
   cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
-  if (!validateBlockRangeArgument()) {
-    errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
-           << "' invalid format.\n";
-    errs().flush();
-    exit(1);
+
+  if (opts::BytesSubcommand) {
+    if (!parseRange(opts::bytes::DumpBlockRangeOpt,
+                    opts::bytes::DumpBlockRange)) {
+      errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
+             << "' invalid format.\n";
+      errs().flush();
+      exit(1);
+    }
+    if (!parseRange(opts::bytes::DumpByteRangeOpt,
+                    opts::bytes::DumpByteRange)) {
+      errs() << "Argument '" << opts::bytes::DumpByteRangeOpt
+             << "' invalid format.\n";
+      errs().flush();
+      exit(1);
+    }
   }
 
   if (opts::DumpSubcommand) {
index 811037ad62203f0988b1be0de64d3152e6614126..78cea8fba9ce14e0f28736109825f2f0be3eb3f9 100644 (file)
@@ -93,11 +93,13 @@ extern llvm::cl::opt<uint32_t> ClassRecursionDepth;
 }
 
 namespace bytes {
-struct BlockRange {
-  uint32_t Min;
-  llvm::Optional<uint32_t> Max;
+struct NumberRange {
+  uint64_t Min;
+  llvm::Optional<uint64_t> Max;
 };
-extern llvm::Optional<BlockRange> DumpBlockRange;
+
+extern llvm::Optional<NumberRange> DumpBlockRange;
+extern llvm::Optional<NumberRange> DumpByteRange;
 extern llvm::cl::list<std::string> DumpStreamData;
 } // namespace bytes