OSDN Git Service

[llvm-pdbutil] Create a "bytes" subcommand.
[android-x86/external-llvm.git] / tools / llvm-pdbutil / BytesOutputStyle.cpp
1 //===- 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
22 using namespace llvm;
23 using namespace llvm::msf;
24 using namespace llvm::pdb;
25
26 namespace {
27 struct StreamSpec {
28   uint32_t SI = 0;
29   uint32_t Begin = 0;
30   uint32_t Size = 0;
31 };
32 } // namespace
33
34 static 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
56 static 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
71 static 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
77 BytesOutputStyle::BytesOutputStyle(PDBFile &File)
78     : File(File), P(2, false, outs()) {}
79
80 Error 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
99   if (!opts::bytes::DumpStreamData.empty()) {
100     dumpStreamBytes();
101     P.NewLine();
102   }
103   return Error::success();
104 }
105
106 void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
107   printHeader(P, "MSF Blocks");
108
109   AutoIndent Indent(P);
110   for (uint32_t I = Min; I <= Max; ++I) {
111     uint64_t Base = I;
112     Base *= File.getBlockSize();
113
114     auto ExpectedData = File.getBlockData(I, File.getBlockSize());
115     if (!ExpectedData) {
116       P.formatLine("Could not get block {0}.  Reason = {1}", I,
117                    toString(ExpectedData.takeError()));
118       continue;
119     }
120     std::string Label = formatv("Block {0}", I).str();
121     P.formatBinary(Label, *ExpectedData, Base, 0);
122   }
123 }
124
125 void BytesOutputStyle::dumpStreamBytes() {
126   if (StreamPurposes.empty())
127     discoverStreamPurposes(File, StreamPurposes);
128
129   printHeader(P, "Stream Data");
130   ExitOnError Err("Unexpected error reading stream data");
131
132   auto Specs = parseStreamSpecs(P);
133
134   for (const auto &Spec : Specs) {
135     uint32_t End = 0;
136
137     AutoIndent Indent(P);
138     if (Spec.SI >= File.getNumStreams()) {
139       P.formatLine("Stream {0}: Not present", Spec.SI);
140       continue;
141     }
142
143     auto S = MappedBlockStream::createIndexedStream(
144         File.getMsfLayout(), File.getMsfBuffer(), Spec.SI, File.getAllocator());
145     if (!S) {
146       P.NewLine();
147       P.formatLine("Stream {0}: Not present", Spec.SI);
148       continue;
149     }
150
151     if (Spec.Size == 0)
152       End = S->getLength();
153     else
154       End = std::min(Spec.Begin + Spec.Size, S->getLength());
155     uint32_t Size = End - Spec.Begin;
156
157     P.formatLine("Stream {0} ({1:N} bytes): {2}", Spec.SI, S->getLength(),
158                  StreamPurposes[Spec.SI]);
159     AutoIndent Indent2(P);
160
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);
166   }
167 }