1 //===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "BytesOutputStyle.h"
12 #include "StreamUtil.h"
13 #include "llvm-pdbutil.h"
15 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
16 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17 #include "llvm/DebugInfo/PDB/Native/RawError.h"
18 #include "llvm/Support/BinaryStreamReader.h"
19 #include "llvm/Support/FormatAdapters.h"
20 #include "llvm/Support/FormatVariadic.h"
23 using namespace llvm::msf;
24 using namespace llvm::pdb;
34 static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
36 if (Str.consumeInteger(0, Result.SI))
37 return make_error<RawError>(raw_error_code::invalid_format,
38 "Invalid Stream Specification");
39 if (Str.consume_front(":")) {
40 if (Str.consumeInteger(0, Result.Begin))
41 return make_error<RawError>(raw_error_code::invalid_format,
42 "Invalid Stream Specification");
44 if (Str.consume_front("@")) {
45 if (Str.consumeInteger(0, Result.Size))
46 return make_error<RawError>(raw_error_code::invalid_format,
47 "Invalid Stream Specification");
51 return make_error<RawError>(raw_error_code::invalid_format,
52 "Invalid Stream Specification");
56 static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
57 SmallVector<StreamSpec, 2> Result;
59 for (auto &Str : opts::bytes::DumpStreamData) {
60 auto ESS = parseStreamSpec(Str);
62 P.formatLine("Error parsing stream spec {0}: {1}", Str,
63 toString(ESS.takeError()));
66 Result.push_back(*ESS);
71 static void printHeader(LinePrinter &P, const Twine &S) {
73 P.formatLine("{0,=60}", S);
74 P.formatLine("{0}", fmt_repeat('=', 60));
77 BytesOutputStyle::BytesOutputStyle(PDBFile &File)
78 : File(File), P(2, false, outs()) {}
80 Error BytesOutputStyle::dump() {
82 if (opts::bytes::DumpBlockRange.hasValue()) {
83 auto &R = *opts::bytes::DumpBlockRange;
84 uint32_t Max = R.Max.getValueOr(R.Min);
87 return make_error<StringError>(
88 "Invalid block range specified. Max < Min",
89 inconvertibleErrorCode());
90 if (Max >= File.getBlockCount())
91 return make_error<StringError>(
92 "Invalid block range specified. Requested block out of bounds",
93 inconvertibleErrorCode());
95 dumpBlockRanges(R.Min, Max);
99 if (!opts::bytes::DumpStreamData.empty()) {
103 return Error::success();
106 void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
107 printHeader(P, "MSF Blocks");
109 AutoIndent Indent(P);
110 for (uint32_t I = Min; I <= Max; ++I) {
112 Base *= File.getBlockSize();
114 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
116 P.formatLine("Could not get block {0}. Reason = {1}", I,
117 toString(ExpectedData.takeError()));
120 std::string Label = formatv("Block {0}", I).str();
121 P.formatBinary(Label, *ExpectedData, Base, 0);
125 void BytesOutputStyle::dumpStreamBytes() {
126 if (StreamPurposes.empty())
127 discoverStreamPurposes(File, StreamPurposes);
129 printHeader(P, "Stream Data");
130 ExitOnError Err("Unexpected error reading stream data");
132 auto Specs = parseStreamSpecs(P);
134 for (const auto &Spec : Specs) {
137 AutoIndent Indent(P);
138 if (Spec.SI >= File.getNumStreams()) {
139 P.formatLine("Stream {0}: Not present", Spec.SI);
143 auto S = MappedBlockStream::createIndexedStream(
144 File.getMsfLayout(), File.getMsfBuffer(), Spec.SI, File.getAllocator());
147 P.formatLine("Stream {0}: Not present", Spec.SI);
152 End = S->getLength();
154 End = std::min(Spec.Begin + Spec.Size, S->getLength());
155 uint32_t Size = End - Spec.Begin;
157 P.formatLine("Stream {0} ({1:N} bytes): {2}", Spec.SI, S->getLength(),
158 StreamPurposes[Spec.SI]);
159 AutoIndent Indent2(P);
161 BinaryStreamReader R(*S);
162 ArrayRef<uint8_t> StreamData;
163 Err(R.readBytes(StreamData, S->getLength()));
164 StreamData = StreamData.slice(Spec.Begin, Size);
165 P.formatBinary("Data", StreamData, Spec.Begin);