From 6b124f29e727da3f3d27112b7ded82b404a68b2f Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Fri, 23 Jun 2017 19:54:44 +0000 Subject: [PATCH] [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 --- .../DebugInfo/PDB/pdbdump-raw-blocks.test | 12 ++--- .../test/DebugInfo/PDB/pdbdump-raw-bytes.test | 15 ++++++ llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp | 31 ++++++++++++ llvm/tools/llvm-pdbutil/BytesOutputStyle.h | 1 + llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp | 50 +++++++++++++------ llvm/tools/llvm-pdbutil/llvm-pdbutil.h | 10 ++-- 6 files changed, 93 insertions(+), 26 deletions(-) create mode 100644 llvm/test/DebugInfo/PDB/pdbdump-raw-bytes.test diff --git a/llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test b/llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test index 16cd8e7a4694..aa81293805b4 100644 --- a/llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test +++ b/llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test @@ -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/llvm/test/DebugInfo/PDB/pdbdump-raw-bytes.test b/llvm/test/DebugInfo/PDB/pdbdump-raw-bytes.test new file mode 100644 index 000000000000..2c5c96c5a380 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/pdbdump-raw-bytes.test @@ -0,0 +1,15 @@ +; RUN: llvm-pdbutil bytes -byte-range=20-60 %p/Inputs/empty.pdb | FileCheck --check-prefix=VALID %s +; RUN: not llvm-pdbutil bytes -byte-range=100-20 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALID %s +; RUN: not llvm-pdbutil bytes -byte-range=100000-200000 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALID-RANGE %s + + +VALID: MSF Bytes +VALID-NEXT: ============================================================ +VALID-NEXT: Bytes ( +VALID-NEXT: 0014: 372E3030 0D0A1A44 53000000 00100000 02000000 19000000 88000000 00000000 |7.00...DS.......................| +VALID-NEXT: 0034: 18000000 00000000 00 |.........| +VALID-NEXT: ) + +INVALID: llvm-pdbutil: Invalid byte range specified. Max < Min + +INVALID-RANGE: llvm-pdbutil: Invalid byte range specified. Requested byte larger than file size diff --git a/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp index 123c55d20725..9761987f0765 100644 --- a/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp +++ b/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp @@ -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("Invalid byte range specified. Max < Min", + inconvertibleErrorCode()); + if (Max >= File.getFileSize()) + return make_error( + "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 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 7fd35e7860b3..a2cefbbfb4cd 100644 --- a/llvm/tools/llvm-pdbutil/BytesOutputStyle.h +++ b/llvm/tools/llvm-pdbutil/BytesOutputStyle.h @@ -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; diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp index a86dccba50bc..bdd8dfa164f4 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -267,12 +267,18 @@ cl::list InputFilenames(cl::Positional, cl::OptionCategory FileOptions("Module & File Options"); namespace bytes { -llvm::Optional DumpBlockRange; +llvm::Optional DumpBlockRange; +llvm::Optional DumpByteRange; + +cl::opt DumpBlockRangeOpt( + "block-range", cl::value_desc("start[-end]"), + cl::desc("Dump binary data from specified range of blocks."), + cl::sub(BytesSubcommand)); cl::opt - 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 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 &Parsed) { + if (Str.empty()) return true; llvm::Regex R("^([^-]+)(-([^-]+))?$"); llvm::SmallVector 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) { diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h index 811037ad6220..78cea8fba9ce 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h @@ -93,11 +93,13 @@ extern llvm::cl::opt ClassRecursionDepth; } namespace bytes { -struct BlockRange { - uint32_t Min; - llvm::Optional Max; +struct NumberRange { + uint64_t Min; + llvm::Optional Max; }; -extern llvm::Optional DumpBlockRange; + +extern llvm::Optional DumpBlockRange; +extern llvm::Optional DumpByteRange; extern llvm::cl::list DumpStreamData; } // namespace bytes -- GitLab