diff options
author | Zachary Turner <zturner@google.com> | 2017-06-23 19:54:44 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2017-06-23 19:54:44 +0000 |
commit | 87f3ec22f791e3873d9001a88f5d781352ed8d2a (patch) | |
tree | 3cc6e9481f8a422c1a2ce10c31a3cfabb71ac102 | |
parent | 0804de030c446757e3a57d5674b60568110bbbde (diff) | |
download | llvm-87f3ec22f791e3873d9001a88f5d781352ed8d2a.tar.gz |
[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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306146 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | test/DebugInfo/PDB/pdbdump-raw-blocks.test | 12 | ||||
-rw-r--r-- | test/DebugInfo/PDB/pdbdump-raw-bytes.test | 15 | ||||
-rw-r--r-- | tools/llvm-pdbutil/BytesOutputStyle.cpp | 31 | ||||
-rw-r--r-- | tools/llvm-pdbutil/BytesOutputStyle.h | 1 | ||||
-rw-r--r-- | tools/llvm-pdbutil/llvm-pdbutil.cpp | 50 | ||||
-rw-r--r-- | tools/llvm-pdbutil/llvm-pdbutil.h | 10 |
6 files changed, 93 insertions, 26 deletions
diff --git a/test/DebugInfo/PDB/pdbdump-raw-blocks.test b/test/DebugInfo/PDB/pdbdump-raw-blocks.test index 16cd8e7a469..aa81293805b 100644 --- a/test/DebugInfo/PDB/pdbdump-raw-blocks.test +++ b/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/test/DebugInfo/PDB/pdbdump-raw-bytes.test b/test/DebugInfo/PDB/pdbdump-raw-bytes.test new file mode 100644 index 00000000000..2c5c96c5a38 --- /dev/null +++ b/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/tools/llvm-pdbutil/BytesOutputStyle.cpp b/tools/llvm-pdbutil/BytesOutputStyle.cpp index 123c55d2072..9761987f076 100644 --- a/tools/llvm-pdbutil/BytesOutputStyle.cpp +++ b/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<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); diff --git a/tools/llvm-pdbutil/BytesOutputStyle.h b/tools/llvm-pdbutil/BytesOutputStyle.h index 7fd35e7860b..a2cefbbfb4c 100644 --- a/tools/llvm-pdbutil/BytesOutputStyle.h +++ b/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/tools/llvm-pdbutil/llvm-pdbutil.cpp b/tools/llvm-pdbutil/llvm-pdbutil.cpp index a86dccba50b..bdd8dfa164f 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -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) { diff --git a/tools/llvm-pdbutil/llvm-pdbutil.h b/tools/llvm-pdbutil/llvm-pdbutil.h index 811037ad622..78cea8fba9c 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/tools/llvm-pdbutil/llvm-pdbutil.h @@ -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 |