From: Zachary Turner Date: Thu, 22 Jun 2017 20:58:11 +0000 (+0000) Subject: [llvm-pdbutil] Create a "bytes" subcommand. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=08bb54f87baf45c7c4724ae1c5ef24d3a196e6d2;p=llvm [llvm-pdbutil] Create a "bytes" subcommand. 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 --- diff --git a/test/DebugInfo/PDB/pdbdump-headers.test b/test/DebugInfo/PDB/pdbdump-headers.test index afedbb5c257..e6ee12b6d10 100644 --- a/test/DebugInfo/PDB/pdbdump-headers.test +++ b/test/DebugInfo/PDB/pdbdump-headers.test @@ -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: ============================================================ diff --git a/test/DebugInfo/PDB/pdbdump-raw-blocks.test b/test/DebugInfo/PDB/pdbdump-raw-blocks.test index e333a05fce3..16cd8e7a469 100644 --- a/test/DebugInfo/PDB/pdbdump-raw-blocks.test +++ b/test/DebugInfo/PDB/pdbdump-raw-blocks.test @@ -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. diff --git a/test/DebugInfo/PDB/pdbdump-raw-stream.test b/test/DebugInfo/PDB/pdbdump-raw-stream.test index 4022975e108..d8510a1af73 100644 --- a/test/DebugInfo/PDB/pdbdump-raw-stream.test +++ b/test/DebugInfo/PDB/pdbdump-raw-stream.test @@ -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 index 00000000000..af56092ce63 --- /dev/null +++ b/tools/llvm-pdbutil/BytesOutputStyle.cpp @@ -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 parseStreamSpec(StringRef Str) { + StreamSpec Result; + if (Str.consumeInteger(0, Result.SI)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + if (Str.consume_front(":")) { + if (Str.consumeInteger(0, Result.Begin)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + if (Str.consume_front("@")) { + if (Str.consumeInteger(0, Result.Size)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + + if (!Str.empty()) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + return Result; +} + +static SmallVector parseStreamSpecs(LinePrinter &P) { + SmallVector 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( + "Invalid block range specified. Max < Min", + inconvertibleErrorCode()); + if (Max >= File.getBlockCount()) + return make_error( + "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 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 index 00000000000..7fd35e7860b --- /dev/null +++ b/tools/llvm-pdbutil/BytesOutputStyle.h @@ -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 StreamPurposes; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/tools/llvm-pdbutil/CMakeLists.txt b/tools/llvm-pdbutil/CMakeLists.txt index 8ebe0133f5e..7a3245424ef 100644 --- a/tools/llvm-pdbutil/CMakeLists.txt +++ b/tools/llvm-pdbutil/CMakeLists.txt @@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-pdbutil Analyze.cpp + BytesOutputStyle.cpp Diff.cpp DumpOutputStyle.cpp llvm-pdbutil.cpp diff --git a/tools/llvm-pdbutil/DumpOutputStyle.cpp b/tools/llvm-pdbutil/DumpOutputStyle.cpp index ea7d9f1f708..a05e5cf03e9 100644 --- a/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ b/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -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( - "Invalid block range specified. Max < Min", - std::make_error_code(std::errc::bad_address)); - if (Max >= File.getBlockCount()) - return make_error( - "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(raw_error_code::invalid_format, - "Invalid Stream Specification"); - if (Str.consume_front(":")) { - if (Str.consumeInteger(0, Offset)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - } - if (Str.consume_front("@")) { - if (Str.consumeInteger(0, Size)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - } - if (!Str.empty()) - return make_error(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 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 getModuleDebugStream(PDBFile &File, uint32_t Index) { ExitOnError Err("Unexpected error"); diff --git a/tools/llvm-pdbutil/LinePrinter.cpp b/tools/llvm-pdbutil/LinePrinter.cpp index 718d3394e21..3e736d90426 100644 --- a/tools/llvm-pdbutil/LinePrinter.cpp +++ b/tools/llvm-pdbutil/LinePrinter.cpp @@ -106,6 +106,20 @@ void LinePrinter::formatBinary(StringRef Label, ArrayRef Data, OS << ")"; } +void LinePrinter::formatBinary(StringRef Label, ArrayRef 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; diff --git a/tools/llvm-pdbutil/LinePrinter.h b/tools/llvm-pdbutil/LinePrinter.h index f4fd22bcb6f..9293c49132d 100644 --- a/tools/llvm-pdbutil/LinePrinter.h +++ b/tools/llvm-pdbutil/LinePrinter.h @@ -45,6 +45,8 @@ public: void formatBinary(StringRef Label, ArrayRef Data, uint32_t StartOffset); + void formatBinary(StringRef Label, ArrayRef Data, uint64_t BaseAddr, + uint32_t StartOffset); bool hasColor() const { return UseColor; } raw_ostream &getStream() { return OS; } diff --git a/tools/llvm-pdbutil/llvm-pdbutil.cpp b/tools/llvm-pdbutil/llvm-pdbutil.cpp index 658833de625..a86dccba50b 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -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 InputFilenames(cl::Positional, cl::OptionCategory FileOptions("Module & File Options"); +namespace bytes { +llvm::Optional DumpBlockRange; + +cl::opt + DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"), + cl::desc("Dump binary data from specified range."), + cl::sub(BytesSubcommand)); + +cl::list + 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 InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore, cl::sub(BytesSubcommand)); + +} // namespace bytes + namespace dump { cl::OptionCategory MsfOptions("MSF Container Options"); @@ -276,17 +299,6 @@ cl::opt DumpSummary("summary", cl::desc("dump file summary"), cl::opt DumpStreams("streams", cl::desc("dump summary of the PDB streams"), cl::cat(MsfOptions), cl::sub(DumpSubcommand)); -cl::opt - DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"), - cl::desc("Dump binary data from specified range."), - cl::cat(MsfOptions), cl::sub(DumpSubcommand)); -llvm::Optional DumpBlockRange; - -cl::list - 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 DumpTypes("types", @@ -626,6 +638,15 @@ static void dumpRaw(StringRef Path) { ExitOnErr(O->dump()); } +static void dumpBytes(StringRef Path) { + std::unique_ptr Session; + auto &File = loadPDB(Path, Session); + + auto O = llvm::make_unique(File); + + ExitOnErr(O->dump()); +} + static void dumpAnalysis(StringRef Path) { std::unique_ptr 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 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 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"; diff --git a/tools/llvm-pdbutil/llvm-pdbutil.h b/tools/llvm-pdbutil/llvm-pdbutil.h index c18d1b79549..811037ad622 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/tools/llvm-pdbutil/llvm-pdbutil.h @@ -92,16 +92,19 @@ extern llvm::cl::opt ClassFormat; extern llvm::cl::opt ClassRecursionDepth; } -namespace dump { +namespace bytes { struct BlockRange { uint32_t Min; llvm::Optional Max; }; +extern llvm::Optional DumpBlockRange; +extern llvm::cl::list DumpStreamData; +} // namespace bytes + +namespace dump { extern llvm::cl::opt DumpSummary; extern llvm::cl::opt DumpStreams; -extern llvm::Optional DumpBlockRange; -extern llvm::cl::list DumpStreamData; extern llvm::cl::opt DumpLines; extern llvm::cl::opt DumpInlineeLines;