blob: 9761987f0765b70214c71a8139be77dbc9914efb [file] [log] [blame]
Zachary Turner99402032017-06-22 20:58:11 +00001//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "BytesOutputStyle.h"
11
12#include "StreamUtil.h"
13#include "llvm-pdbutil.h"
14
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"
21
22using namespace llvm;
23using namespace llvm::msf;
24using namespace llvm::pdb;
25
26namespace {
27struct StreamSpec {
28 uint32_t SI = 0;
29 uint32_t Begin = 0;
30 uint32_t Size = 0;
31};
32} // namespace
33
34static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
35 StreamSpec Result;
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");
43 }
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");
48 }
49
50 if (!Str.empty())
51 return make_error<RawError>(raw_error_code::invalid_format,
52 "Invalid Stream Specification");
53 return Result;
54}
55
56static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
57 SmallVector<StreamSpec, 2> Result;
58
59 for (auto &Str : opts::bytes::DumpStreamData) {
60 auto ESS = parseStreamSpec(Str);
61 if (!ESS) {
62 P.formatLine("Error parsing stream spec {0}: {1}", Str,
63 toString(ESS.takeError()));
64 continue;
65 }
66 Result.push_back(*ESS);
67 }
68 return Result;
69}
70
71static void printHeader(LinePrinter &P, const Twine &S) {
72 P.NewLine();
73 P.formatLine("{0,=60}", S);
74 P.formatLine("{0}", fmt_repeat('=', 60));
75}
76
77BytesOutputStyle::BytesOutputStyle(PDBFile &File)
78 : File(File), P(2, false, outs()) {}
79
80Error BytesOutputStyle::dump() {
81
82 if (opts::bytes::DumpBlockRange.hasValue()) {
83 auto &R = *opts::bytes::DumpBlockRange;
84 uint32_t Max = R.Max.getValueOr(R.Min);
85
86 if (Max < 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());
94
95 dumpBlockRanges(R.Min, Max);
96 P.NewLine();
97 }
98
Zachary Turner6b124f22017-06-23 19:54:44 +000099 if (opts::bytes::DumpByteRange.hasValue()) {
100 auto &R = *opts::bytes::DumpByteRange;
101 uint32_t Max = R.Max.getValueOr(File.getFileSize());
102
103 if (Max < R.Min)
104 return make_error<StringError>("Invalid byte range specified. Max < Min",
105 inconvertibleErrorCode());
106 if (Max >= File.getFileSize())
107 return make_error<StringError>(
108 "Invalid byte range specified. Requested byte larger than file size",
109 inconvertibleErrorCode());
110
111 dumpByteRanges(R.Min, Max);
112 P.NewLine();
113 }
114
Zachary Turner99402032017-06-22 20:58:11 +0000115 if (!opts::bytes::DumpStreamData.empty()) {
116 dumpStreamBytes();
117 P.NewLine();
118 }
119 return Error::success();
120}
121
122void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
123 printHeader(P, "MSF Blocks");
124
125 AutoIndent Indent(P);
126 for (uint32_t I = Min; I <= Max; ++I) {
127 uint64_t Base = I;
128 Base *= File.getBlockSize();
129
130 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
131 if (!ExpectedData) {
132 P.formatLine("Could not get block {0}. Reason = {1}", I,
133 toString(ExpectedData.takeError()));
134 continue;
135 }
136 std::string Label = formatv("Block {0}", I).str();
137 P.formatBinary(Label, *ExpectedData, Base, 0);
138 }
139}
140
Zachary Turner6b124f22017-06-23 19:54:44 +0000141void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
142 printHeader(P, "MSF Bytes");
143
144 AutoIndent Indent(P);
145
146 BinaryStreamReader Reader(File.getMsfBuffer());
147 ArrayRef<uint8_t> Data;
148 consumeError(Reader.skip(Min));
149 uint32_t Size = Max - Min + 1;
150 auto EC = Reader.readBytes(Data, Size);
151 assert(!EC);
152 consumeError(std::move(EC));
153 P.formatBinary("Bytes", Data, Min);
154}
155
Zachary Turner99402032017-06-22 20:58:11 +0000156void BytesOutputStyle::dumpStreamBytes() {
157 if (StreamPurposes.empty())
158 discoverStreamPurposes(File, StreamPurposes);
159
160 printHeader(P, "Stream Data");
161 ExitOnError Err("Unexpected error reading stream data");
162
163 auto Specs = parseStreamSpecs(P);
164
165 for (const auto &Spec : Specs) {
Zachary Turner99402032017-06-22 20:58:11 +0000166 AutoIndent Indent(P);
Zachary Turner0b36c3e2017-06-23 18:52:13 +0000167 if (Spec.SI >= StreamPurposes.size()) {
Zachary Turner99402032017-06-22 20:58:11 +0000168 P.formatLine("Stream {0}: Not present", Spec.SI);
169 continue;
170 }
Zachary Turner0b36c3e2017-06-23 18:52:13 +0000171 P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
172 Spec.Begin, Spec.Size);
Zachary Turner99402032017-06-22 20:58:11 +0000173 }
174}