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;