From: Zachary Turner Date: Fri, 28 Apr 2017 00:43:38 +0000 (+0000) Subject: [llvm-pdbdump] Allow printing only a portion of a stream. X-Git-Tag: android-x86-7.1-r4~17019 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a102628313675d0671f30fbbbcb02dbbab2cdb9d;p=android-x86%2Fexternal-llvm.git [llvm-pdbdump] Allow printing only a portion of a stream. When dumping raw data from a stream, you might know the offset of a certain record you're interested in, as well as how long that record is. Previously, you had to dump the entire stream and wade through the bytes to find the interesting record. This patch allows you to specify an offset and length on the command line, and it will only dump the requested range. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301607 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Support/ScopedPrinter.h b/include/llvm/Support/ScopedPrinter.h index a2f2e098543..1b665193221 100644 --- a/include/llvm/Support/ScopedPrinter.h +++ b/include/llvm/Support/ScopedPrinter.h @@ -295,6 +295,11 @@ public: printBinaryImpl(Label, StringRef(), V, false); } + void printBinaryBlock(StringRef Label, ArrayRef Value, + uint32_t StartOffset) { + printBinaryImpl(Label, StringRef(), Value, true, StartOffset); + } + void printBinaryBlock(StringRef Label, ArrayRef Value) { printBinaryImpl(Label, StringRef(), Value, true); } @@ -333,7 +338,7 @@ private: } void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef Value, - bool Block); + bool Block, uint32_t StartOffset = 0); raw_ostream &OS; int IndentLevel; diff --git a/lib/Support/ScopedPrinter.cpp b/lib/Support/ScopedPrinter.cpp index d8ee1efd8f3..537ff62c7b0 100644 --- a/lib/Support/ScopedPrinter.cpp +++ b/lib/Support/ScopedPrinter.cpp @@ -21,7 +21,8 @@ const std::string to_hexString(uint64_t Value, bool UpperCase) { } void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str, - ArrayRef Data, bool Block) { + ArrayRef Data, bool Block, + uint32_t StartOffset) { if (Data.size() > 16) Block = true; @@ -31,7 +32,8 @@ void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str, OS << ": " << Str; OS << " (\n"; if (!Data.empty()) - OS << format_bytes_with_ascii(Data, 0, 16, 4, (IndentLevel + 1) * 2, true) + OS << format_bytes_with_ascii(Data, StartOffset, 16, 4, + (IndentLevel + 1) * 2, true) << "\n"; startLine() << ")\n"; } else { diff --git a/test/tools/llvm-pdbdump/raw-stream-data.test b/test/tools/llvm-pdbdump/raw-stream-data.test new file mode 100644 index 00000000000..d55980632d4 --- /dev/null +++ b/test/tools/llvm-pdbdump/raw-stream-data.test @@ -0,0 +1,47 @@ +; RUN: llvm-pdbdump raw -stream-data=8 %p/Inputs/LoadAddressTest.pdb \ +; RUN: | FileCheck %s -check-prefix=FULL_STREAM +; RUN: llvm-pdbdump raw -stream-data=8:4 %p/Inputs/LoadAddressTest.pdb \ +; RUN: | FileCheck %s -check-prefix=OFFSET_STREAM +; RUN: llvm-pdbdump raw -stream-data=8:4@24 %p/Inputs/LoadAddressTest.pdb \ +; RUN: | FileCheck %s -check-prefix=OFFSET_AND_LENGTH + +FULL_STREAM: Stream Data { +FULL_STREAM-NEXT: Stream { +FULL_STREAM-NEXT: Index: 8 +FULL_STREAM-NEXT: Type: Public Symbol Records +FULL_STREAM-NEXT: Size: 40 +FULL_STREAM-NEXT: Blocks: +FULL_STREAM-NEXT: Data ( +FULL_STREAM-NEXT: 0000: 12000E11 02000000 10000000 01005F6D |.............._m| +FULL_STREAM-NEXT: 0010: 61696E00 12002511 00000000 88000000 |ain...%.........| +FULL_STREAM-NEXT: 0020: 01006D61 696E0000 |..main..| +FULL_STREAM-NEXT: ) +FULL_STREAM-NEXT: } +FULL_STREAM-NEXT: } + +OFFSET_STREAM: Stream Data { +OFFSET_STREAM-NEXT: Stream { +OFFSET_STREAM-NEXT: Index: 8 +OFFSET_STREAM-NEXT: Type: Public Symbol Records +OFFSET_STREAM-NEXT: Size: 40 +OFFSET_STREAM-NEXT: Blocks: +OFFSET_STREAM-NEXT: Data ( +OFFSET_STREAM-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.| +OFFSET_STREAM-NEXT: 0014: 12002511 00000000 88000000 01006D61 |..%...........ma| +OFFSET_STREAM-NEXT: 0024: 696E0000 |in..| +OFFSET_STREAM-NEXT: ) +OFFSET_STREAM-NEXT: } +OFFSET_STREAM-NEXT:} + +OFFSET_AND_LENGTH: Stream Data { +OFFSET_AND_LENGTH-NEXT: Stream { +OFFSET_AND_LENGTH-NEXT: Index: 8 +OFFSET_AND_LENGTH-NEXT: Type: Public Symbol Records +OFFSET_AND_LENGTH-NEXT: Size: 40 +OFFSET_AND_LENGTH-NEXT: Blocks: +OFFSET_AND_LENGTH-NEXT: Data ( +OFFSET_AND_LENGTH-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.| +OFFSET_AND_LENGTH-NEXT: 0014: 12002511 00000000 |..%.....| +OFFSET_AND_LENGTH-NEXT: ) +OFFSET_AND_LENGTH-NEXT: } +OFFSET_AND_LENGTH-NEXT:} \ No newline at end of file diff --git a/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 20223ac60f4..705728e27d0 100644 --- a/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -319,6 +319,27 @@ Error LLVMOutputStyle::dumpBlockRanges() { 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 LLVMOutputStyle::dumpStreamBytes() { if (opts::raw::DumpStreamData.empty()) return Error::success(); @@ -327,7 +348,15 @@ Error LLVMOutputStyle::dumpStreamBytes() { discoverStreamPurposes(File, StreamPurposes); DictScope D(P, "Stream Data"); - for (uint32_t SI : opts::raw::DumpStreamData) { + for (auto &Str : opts::raw::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; + if (SI >= File.getNumStreams()) return make_error(raw_error_code::no_stream); @@ -336,6 +365,14 @@ Error LLVMOutputStyle::dumpStreamBytes() { if (!S) continue; DictScope DD(P, "Stream"); + if (Size == 0) + End = S->getLength(); + else { + End = Begin + Size; + if (End >= S->getLength()) + return make_error(raw_error_code::index_out_of_bounds, + "Stream is not long enough!"); + } P.printNumber("Index", SI); P.printString("Type", StreamPurposes[SI]); @@ -347,7 +384,9 @@ Error LLVMOutputStyle::dumpStreamBytes() { ArrayRef StreamData; if (auto EC = R.readBytes(StreamData, S->getLength())) return EC; - P.printBinaryBlock("Data", StreamData); + Size = End - Begin; + StreamData = StreamData.slice(Begin, Size); + P.printBinaryBlock("Data", StreamData, Begin); } return Error::success(); } diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index 3d7dbffb0d5..e6d363e1626 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -261,9 +261,10 @@ cl::opt cl::cat(MsfOptions), cl::sub(RawSubcommand)); llvm::Optional DumpBlockRange; -cl::list +cl::list DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, - cl::desc("Dump binary data from specified streams."), + cl::desc("Dump binary data from specified streams. Format " + "is SN[:Start][@Size]"), cl::cat(MsfOptions), cl::sub(RawSubcommand)); // TYPE OPTIONS diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h index f080d6d5525..8b1dde9399b 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/tools/llvm-pdbdump/llvm-pdbdump.h @@ -60,7 +60,7 @@ struct BlockRange { }; extern llvm::Optional DumpBlockRange; -extern llvm::cl::list DumpStreamData; +extern llvm::cl::list DumpStreamData; extern llvm::cl::opt CompactRecords; extern llvm::cl::opt DumpGlobals;