OSDN Git Service

[llvm-pdbutil] Create a "bytes" subcommand.
authorZachary Turner <zturner@google.com>
Thu, 22 Jun 2017 20:58:11 +0000 (20:58 +0000)
committerZachary Turner <zturner@google.com>
Thu, 22 Jun 2017 20:58:11 +0000 (20:58 +0000)
This idea originally came about when I was doing some deep
investigation of why certain bytes in a PDB that we round-tripped
differed from their original bytes in the source PDB.  I found
myself having to hack up the code in many places to dump the
bytes of this substream, or that record.  It would be nice if
we could just do this for every possible stream, substream,
debug chunk type, etc.

It doesn't make sense to put this under dump because there's just
so many options that would detract from the more common use case
of just dumping deserialized records.  So making a new subcommand
seems like the most logical course of action.  In doing so, we
already have two command line options that are suitable for this
new subcommand, so start out by moving them there.

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

test/DebugInfo/PDB/pdbdump-headers.test
test/DebugInfo/PDB/pdbdump-raw-blocks.test
test/DebugInfo/PDB/pdbdump-raw-stream.test
tools/llvm-pdbutil/BytesOutputStyle.cpp [new file with mode: 0644]
tools/llvm-pdbutil/BytesOutputStyle.h [new file with mode: 0644]
tools/llvm-pdbutil/CMakeLists.txt
tools/llvm-pdbutil/DumpOutputStyle.cpp
tools/llvm-pdbutil/LinePrinter.cpp
tools/llvm-pdbutil/LinePrinter.h
tools/llvm-pdbutil/llvm-pdbutil.cpp
tools/llvm-pdbutil/llvm-pdbutil.h

index afedbb5..e6ee12b 100644 (file)
@@ -1,7 +1,7 @@
-; RUN: llvm-pdbutil raw -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
-; RUN: llvm-pdbutil raw -summary -modules -files \
+; RUN: llvm-pdbutil dump -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
+; RUN: llvm-pdbutil dump -summary -modules -files \
 ; RUN:              %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
-; RUN: not llvm-pdbutil raw -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
+; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
 
 ALL:                                Summary
 ALL-NEXT: ============================================================
index e333a05..16cd8e7 100644 (file)
@@ -1,8 +1,9 @@
-; RUN: llvm-pdbutil dump -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
-; RUN: llvm-pdbutil dump -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
-; RUN: not llvm-pdbutil dump -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
-; RUN: not llvm-pdbutil dump -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
-; RUN: not llvm-pdbutil dump -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
+; 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
 
 BLOCK0:                         MSF Blocks
 BLOCK0-NEXT: ============================================================
@@ -21,9 +22,9 @@ BLOCK01-NEXT:     0020: 00100000 02000000 19000000 88000000 00000000 18000000 00
 BLOCK01-NEXT:     0040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  |................................|
 BLOCK01-NEXT:     0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  |................................|
 BLOCK01:       Block 1 (
-BLOCK01-NEXT:    0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
-BLOCK01-NEXT:    0020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
-BLOCK01-NEXT:    0040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
+BLOCK01-NEXT:    1000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
+BLOCK01-NEXT:    1020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
+BLOCK01-NEXT:    1040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
 BLOCK01-NOT:  Block 2 (
 
 BADSYNTAX: Argument '{{.*}}' invalid format.
index 4022975..d8510a1 100644 (file)
@@ -1,6 +1,6 @@
-; RUN: llvm-pdbutil dump -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
-; RUN: llvm-pdbutil dump -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
-; RUN: llvm-pdbutil dump -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
+; RUN: llvm-pdbutil bytes -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
+; RUN: llvm-pdbutil bytes -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
+; RUN: llvm-pdbutil bytes -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
 
 STREAM:                             Stream Data
 STREAM-NEXT: ============================================================
diff --git a/tools/llvm-pdbutil/BytesOutputStyle.cpp b/tools/llvm-pdbutil/BytesOutputStyle.cpp
new file mode 100644 (file)
index 0000000..af56092
--- /dev/null
@@ -0,0 +1,167 @@
+//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BytesOutputStyle.h"
+
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+struct StreamSpec {
+  uint32_t SI = 0;
+  uint32_t Begin = 0;
+  uint32_t Size = 0;
+};
+} // namespace
+
+static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
+  StreamSpec Result;
+  if (Str.consumeInteger(0, Result.SI))
+    return make_error<RawError>(raw_error_code::invalid_format,
+                                "Invalid Stream Specification");
+  if (Str.consume_front(":")) {
+    if (Str.consumeInteger(0, Result.Begin))
+      return make_error<RawError>(raw_error_code::invalid_format,
+                                  "Invalid Stream Specification");
+  }
+  if (Str.consume_front("@")) {
+    if (Str.consumeInteger(0, Result.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 Result;
+}
+
+static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
+  SmallVector<StreamSpec, 2> Result;
+
+  for (auto &Str : opts::bytes::DumpStreamData) {
+    auto ESS = parseStreamSpec(Str);
+    if (!ESS) {
+      P.formatLine("Error parsing stream spec {0}: {1}", Str,
+                   toString(ESS.takeError()));
+      continue;
+    }
+    Result.push_back(*ESS);
+  }
+  return Result;
+}
+
+static void printHeader(LinePrinter &P, const Twine &S) {
+  P.NewLine();
+  P.formatLine("{0,=60}", S);
+  P.formatLine("{0}", fmt_repeat('=', 60));
+}
+
+BytesOutputStyle::BytesOutputStyle(PDBFile &File)
+    : File(File), P(2, false, outs()) {}
+
+Error BytesOutputStyle::dump() {
+
+  if (opts::bytes::DumpBlockRange.hasValue()) {
+    auto &R = *opts::bytes::DumpBlockRange;
+    uint32_t Max = R.Max.getValueOr(R.Min);
+
+    if (Max < R.Min)
+      return make_error<StringError>(
+          "Invalid block range specified.  Max < Min",
+          inconvertibleErrorCode());
+    if (Max >= File.getBlockCount())
+      return make_error<StringError>(
+          "Invalid block range specified.  Requested block out of bounds",
+          inconvertibleErrorCode());
+
+    dumpBlockRanges(R.Min, Max);
+    P.NewLine();
+  }
+
+  if (!opts::bytes::DumpStreamData.empty()) {
+    dumpStreamBytes();
+    P.NewLine();
+  }
+  return Error::success();
+}
+
+void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
+  printHeader(P, "MSF Blocks");
+
+  AutoIndent Indent(P);
+  for (uint32_t I = Min; I <= Max; ++I) {
+    uint64_t Base = I;
+    Base *= File.getBlockSize();
+
+    auto ExpectedData = File.getBlockData(I, File.getBlockSize());
+    if (!ExpectedData) {
+      P.formatLine("Could not get block {0}.  Reason = {1}", I,
+                   toString(ExpectedData.takeError()));
+      continue;
+    }
+    std::string Label = formatv("Block {0}", I).str();
+    P.formatBinary(Label, *ExpectedData, Base, 0);
+  }
+}
+
+void BytesOutputStyle::dumpStreamBytes() {
+  if (StreamPurposes.empty())
+    discoverStreamPurposes(File, StreamPurposes);
+
+  printHeader(P, "Stream Data");
+  ExitOnError Err("Unexpected error reading stream data");
+
+  auto Specs = parseStreamSpecs(P);
+
+  for (const auto &Spec : Specs) {
+    uint32_t End = 0;
+
+    AutoIndent Indent(P);
+    if (Spec.SI >= File.getNumStreams()) {
+      P.formatLine("Stream {0}: Not present", Spec.SI);
+      continue;
+    }
+
+    auto S = MappedBlockStream::createIndexedStream(
+        File.getMsfLayout(), File.getMsfBuffer(), Spec.SI, File.getAllocator());
+    if (!S) {
+      P.NewLine();
+      P.formatLine("Stream {0}: Not present", Spec.SI);
+      continue;
+    }
+
+    if (Spec.Size == 0)
+      End = S->getLength();
+    else
+      End = std::min(Spec.Begin + Spec.Size, S->getLength());
+    uint32_t Size = End - Spec.Begin;
+
+    P.formatLine("Stream {0} ({1:N} bytes): {2}", Spec.SI, S->getLength(),
+                 StreamPurposes[Spec.SI]);
+    AutoIndent Indent2(P);
+
+    BinaryStreamReader R(*S);
+    ArrayRef<uint8_t> StreamData;
+    Err(R.readBytes(StreamData, S->getLength()));
+    StreamData = StreamData.slice(Spec.Begin, Size);
+    P.formatBinary("Data", StreamData, Spec.Begin);
+  }
+}
diff --git a/tools/llvm-pdbutil/BytesOutputStyle.h b/tools/llvm-pdbutil/BytesOutputStyle.h
new file mode 100644 (file)
index 0000000..7fd35e7
--- /dev/null
@@ -0,0 +1,41 @@
+//===- BytesOutputStyle.h ------------------------------------- *- C++ --*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
+
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+namespace pdb {
+
+class PDBFile;
+
+class BytesOutputStyle : public OutputStyle {
+public:
+  BytesOutputStyle(PDBFile &File);
+
+  Error dump() override;
+
+private:
+  void dumpBlockRanges(uint32_t Min, uint32_t Max);
+  void dumpStreamBytes();
+
+  PDBFile &File;
+  LinePrinter P;
+  SmallVector<std::string, 8> StreamPurposes;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
index 8ebe013..7a32454 100644 (file)
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_tool(llvm-pdbutil
   Analyze.cpp
+  BytesOutputStyle.cpp
   Diff.cpp
   DumpOutputStyle.cpp
   llvm-pdbutil.cpp
index ea7d9f1..a05e5cf 100644 (file)
@@ -80,18 +80,6 @@ Error DumpOutputStyle::dump() {
     P.NewLine();
   }
 
-  if (opts::dump::DumpBlockRange.hasValue()) {
-    if (auto EC = dumpBlockRanges())
-      return EC;
-    P.NewLine();
-  }
-
-  if (!opts::dump::DumpStreamData.empty()) {
-    if (auto EC = dumpStreamBytes())
-      return EC;
-    P.NewLine();
-  }
-
   if (opts::dump::DumpStringTable) {
     if (auto EC = dumpStringTable())
       return EC;
@@ -216,103 +204,6 @@ Error DumpOutputStyle::dumpStreamSummary() {
   return Error::success();
 }
 
-Error DumpOutputStyle::dumpBlockRanges() {
-  printHeader(P, "MSF Blocks");
-
-  auto &R = *opts::dump::DumpBlockRange;
-  uint32_t Max = R.Max.getValueOr(R.Min);
-
-  AutoIndent Indent(P);
-  if (Max < R.Min)
-    return make_error<StringError>(
-        "Invalid block range specified.  Max < Min",
-        std::make_error_code(std::errc::bad_address));
-  if (Max >= File.getBlockCount())
-    return make_error<StringError>(
-        "Invalid block range specified.  Requested block out of bounds",
-        std::make_error_code(std::errc::bad_address));
-
-  for (uint32_t I = R.Min; I <= Max; ++I) {
-    auto ExpectedData = File.getBlockData(I, File.getBlockSize());
-    if (!ExpectedData)
-      return ExpectedData.takeError();
-    std::string Label = formatv("Block {0}", I).str();
-    P.formatBinary(Label, *ExpectedData, 0);
-  }
-
-  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 DumpOutputStyle::dumpStreamBytes() {
-  if (StreamPurposes.empty())
-    discoverStreamPurposes(File, StreamPurposes);
-
-  printHeader(P, "Stream Data");
-  ExitOnError Err("Unexpected error reading stream data");
-
-  for (auto &Str : opts::dump::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;
-
-    AutoIndent Indent(P);
-    if (SI >= File.getNumStreams()) {
-      P.formatLine("Stream {0}: Not present", SI);
-      continue;
-    }
-
-    auto S = MappedBlockStream::createIndexedStream(
-        File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
-    if (!S) {
-      P.NewLine();
-      P.formatLine("Stream {0}: Not present", SI);
-      continue;
-    }
-
-    if (Size == 0)
-      End = S->getLength();
-    else
-      End = std::min(Begin + Size, S->getLength());
-
-    P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
-                 StreamPurposes[SI]);
-    AutoIndent Indent2(P);
-
-    BinaryStreamReader R(*S);
-    ArrayRef<uint8_t> StreamData;
-    Err(R.readBytes(StreamData, S->getLength()));
-    Size = End - Begin;
-    StreamData = StreamData.slice(Begin, Size);
-    P.formatBinary("Data", StreamData, Begin);
-  }
-  return Error::success();
-}
-
 static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
                                                            uint32_t Index) {
   ExitOnError Err("Unexpected error");
index 718d339..3e736d9 100644 (file)
@@ -106,6 +106,20 @@ void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
   OS << ")";
 }
 
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+                               uint64_t Base, uint32_t StartOffset) {
+  NewLine();
+  OS << Label << " (";
+  if (!Data.empty()) {
+    OS << "\n";
+    Base += StartOffset;
+    OS << format_bytes_with_ascii(Data, Base, 32, 4,
+                                  CurrentIndent + IndentSpaces, true);
+    NewLine();
+  }
+  OS << ")";
+}
+
 bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
   if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
     return true;
index f4fd22b..9293c49 100644 (file)
@@ -45,6 +45,8 @@ public:
 
   void formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
                     uint32_t StartOffset);
+  void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, uint64_t BaseAddr,
+                    uint32_t StartOffset);
 
   bool hasColor() const { return UseColor; }
   raw_ostream &getStream() { return OS; }
index 658833d..a86dccb 100644 (file)
@@ -14,6 +14,7 @@
 #include "llvm-pdbutil.h"
 
 #include "Analyze.h"
+#include "BytesOutputStyle.h"
 #include "Diff.h"
 #include "DumpOutputStyle.h"
 #include "LinePrinter.h"
@@ -87,6 +88,8 @@ using namespace llvm::pdb;
 namespace opts {
 
 cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
+cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file");
+
 cl::SubCommand
     PrettySubcommand("pretty",
                      "Dump semantic information about types and symbols");
@@ -263,6 +266,26 @@ cl::list<std::string> InputFilenames(cl::Positional,
 
 cl::OptionCategory FileOptions("Module & File Options");
 
+namespace bytes {
+llvm::Optional<BlockRange> DumpBlockRange;
+
+cl::opt<std::string>
+    DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
+                      cl::desc("Dump binary data from specified range."),
+                      cl::sub(BytesSubcommand));
+
+cl::list<std::string>
+    DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
+                   cl::desc("Dump binary data from specified streams.  Format "
+                            "is SN[:Start][@Size]"),
+                   cl::sub(BytesSubcommand));
+
+cl::list<std::string> InputFilenames(cl::Positional,
+                                     cl::desc("<input PDB files>"),
+                                     cl::OneOrMore, cl::sub(BytesSubcommand));
+
+} // namespace bytes
+
 namespace dump {
 
 cl::OptionCategory MsfOptions("MSF Container Options");
@@ -276,17 +299,6 @@ cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
 cl::opt<bool> DumpStreams("streams",
                           cl::desc("dump summary of the PDB streams"),
                           cl::cat(MsfOptions), cl::sub(DumpSubcommand));
-cl::opt<std::string>
-    DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
-                      cl::desc("Dump binary data from specified range."),
-                      cl::cat(MsfOptions), cl::sub(DumpSubcommand));
-llvm::Optional<BlockRange> DumpBlockRange;
-
-cl::list<std::string>
-    DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
-                   cl::desc("Dump binary data from specified streams.  Format "
-                            "is SN[:Start][@Size]"),
-                   cl::cat(MsfOptions), cl::sub(DumpSubcommand));
 
 // TYPE OPTIONS
 cl::opt<bool> DumpTypes("types",
@@ -626,6 +638,15 @@ static void dumpRaw(StringRef Path) {
   ExitOnErr(O->dump());
 }
 
+static void dumpBytes(StringRef Path) {
+  std::unique_ptr<IPDBSession> Session;
+  auto &File = loadPDB(Path, Session);
+
+  auto O = llvm::make_unique<BytesOutputStyle>(File);
+
+  ExitOnErr(O->dump());
+}
+
 static void dumpAnalysis(StringRef Path) {
   std::unique_ptr<IPDBSession> Session;
   auto &File = loadPDB(Path, Session);
@@ -882,6 +903,27 @@ static void mergePdbs() {
   ExitOnErr(Builder.commit(OutFile));
 }
 
+static bool validateBlockRangeArgument() {
+  if (opts::bytes::DumpBlockRangeOpt.empty())
+    return true;
+
+  llvm::Regex R("^([^-]+)(-([^-]+))?$");
+  llvm::SmallVector<llvm::StringRef, 2> Matches;
+  if (!R.match(opts::bytes::DumpBlockRangeOpt, &Matches))
+    return false;
+
+  opts::bytes::DumpBlockRange.emplace();
+  if (!to_integer(Matches[1], opts::bytes::DumpBlockRange->Min))
+    return false;
+
+  if (!Matches[3].empty()) {
+    opts::bytes::DumpBlockRange->Max.emplace();
+    if (!to_integer(Matches[3], *opts::bytes::DumpBlockRange->Max))
+      return false;
+  }
+  return true;
+}
+
 int main(int argc_, const char *argv_[]) {
   // Print a stack trace if we signal out.
   sys::PrintStackTraceOnErrorSignal(argv_[0]);
@@ -897,21 +939,11 @@ 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 (!opts::dump::DumpBlockRangeOpt.empty()) {
-    llvm::Regex R("^([0-9]+)(-([0-9]+))?$");
-    llvm::SmallVector<llvm::StringRef, 2> Matches;
-    if (!R.match(opts::dump::DumpBlockRangeOpt, &Matches)) {
-      errs() << "Argument '" << opts::dump::DumpBlockRangeOpt
-             << "' invalid format.\n";
-      errs().flush();
-      exit(1);
-    }
-    opts::dump::DumpBlockRange.emplace();
-    Matches[1].getAsInteger(10, opts::dump::DumpBlockRange->Min);
-    if (!Matches[3].empty()) {
-      opts::dump::DumpBlockRange->Max.emplace();
-      Matches[3].getAsInteger(10, *opts::dump::DumpBlockRange->Max);
-    }
+  if (!validateBlockRangeArgument()) {
+    errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
+           << "' invalid format.\n";
+    errs().flush();
+    exit(1);
   }
 
   if (opts::DumpSubcommand) {
@@ -1018,6 +1050,9 @@ int main(int argc_, const char *argv_[]) {
   } else if (opts::DumpSubcommand) {
     std::for_each(opts::dump::InputFilenames.begin(),
                   opts::dump::InputFilenames.end(), dumpRaw);
+  } else if (opts::BytesSubcommand) {
+    std::for_each(opts::bytes::InputFilenames.begin(),
+                  opts::bytes::InputFilenames.end(), dumpBytes);
   } else if (opts::DiffSubcommand) {
     if (opts::diff::InputFilenames.size() != 2) {
       errs() << "diff subcommand expects exactly 2 arguments.\n";
index c18d1b7..811037a 100644 (file)
@@ -92,16 +92,19 @@ extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
 extern llvm::cl::opt<uint32_t> ClassRecursionDepth;
 }
 
-namespace dump {
+namespace bytes {
 struct BlockRange {
   uint32_t Min;
   llvm::Optional<uint32_t> Max;
 };
+extern llvm::Optional<BlockRange> DumpBlockRange;
+extern llvm::cl::list<std::string> DumpStreamData;
+} // namespace bytes
+
+namespace dump {
 
 extern llvm::cl::opt<bool> DumpSummary;
 extern llvm::cl::opt<bool> DumpStreams;
-extern llvm::Optional<BlockRange> DumpBlockRange;
-extern llvm::cl::list<std::string> DumpStreamData;
 
 extern llvm::cl::opt<bool> DumpLines;
 extern llvm::cl::opt<bool> DumpInlineeLines;