[llvm-pdbutil] Add the ability to dump raw bytes from the file.

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.

llvm-svn: 306146
diff --git a/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
index 123c55d..9761987 100644
--- a/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
+++ b/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
@@ -96,6 +96,22 @@
     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::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);
diff --git a/llvm/tools/llvm-pdbutil/BytesOutputStyle.h b/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
index 7fd35e7..a2cefbb 100644
--- a/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
+++ b/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
@@ -29,6 +29,7 @@
 
 private:
   void dumpBlockRanges(uint32_t Min, uint32_t Max);
+  void dumpByteRanges(uint32_t Min, uint32_t Max);
   void dumpStreamBytes();
 
   PDBFile &File;
diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
index a86dccb..bdd8dfa 100644
--- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -267,12 +267,18 @@
 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 @@
   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 @@
   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) {
diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
index 811037a..78cea8f 100644
--- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
+++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -93,11 +93,13 @@
 }
 
 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