llvm.org GIT mirror llvm / 08bb54f
[llvm-pdbutil] Create a "bytes" subcommand. This idea originally came about when I was doing some deep investigation of why certain bytes in a PDB that we round-tripped differed from their original bytes in the source PDB. I found myself having to hack up the code in many places to dump the bytes of this substream, or that record. It would be nice if we could just do this for every possible stream, substream, debug chunk type, etc. It doesn't make sense to put this under dump because there's just so many options that would detract from the more common use case of just dumping deserialized records. So making a new subcommand seems like the most logical course of action. In doing so, we already have two command line options that are suitable for this new subcommand, so start out by moving them there. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306056 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 3 years ago
11 changed file(s) with 307 addition(s) and 152 deletion(s). Raw diff Collapse all Expand all
None ; RUN: llvm-pdbutil raw -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
1 ; RUN: llvm-pdbutil raw -summary -modules -files \
0 ; RUN: llvm-pdbutil dump -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
1 ; RUN: llvm-pdbutil dump -summary -modules -files \
22 ; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
3 ; RUN: not llvm-pdbutil raw -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
3 ; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
44
55 ALL: Summary
66 ALL-NEXT: ============================================================
None ; RUN: llvm-pdbutil dump -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
1 ; RUN: llvm-pdbutil dump -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
2 ; RUN: not llvm-pdbutil dump -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
3 ; RUN: not llvm-pdbutil dump -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
4 ; RUN: not llvm-pdbutil dump -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
0 ; RUN: llvm-pdbutil bytes -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
1 ; RUN: llvm-pdbutil bytes -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
2 ; RUN: llvm-pdbutil bytes -block-data=0-0x1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
3 ; RUN: not llvm-pdbutil bytes -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
4 ; RUN: not llvm-pdbutil bytes -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
5 ; RUN: not llvm-pdbutil bytes -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
56
67 BLOCK0: MSF Blocks
78 BLOCK0-NEXT: ============================================================
2021 BLOCK01-NEXT: 0040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
2122 BLOCK01-NEXT: 0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
2223 BLOCK01: Block 1 (
23 BLOCK01-NEXT: 0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
24 BLOCK01-NEXT: 0020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
25 BLOCK01-NEXT: 0040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
24 BLOCK01-NEXT: 1000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
25 BLOCK01-NEXT: 1020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
26 BLOCK01-NEXT: 1040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
2627 BLOCK01-NOT: Block 2 (
2728
2829 BADSYNTAX: Argument '{{.*}}' invalid format.
None ; RUN: llvm-pdbutil dump -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
1 ; RUN: llvm-pdbutil dump -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
2 ; RUN: llvm-pdbutil dump -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
0 ; RUN: llvm-pdbutil bytes -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
1 ; RUN: llvm-pdbutil bytes -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
2 ; RUN: llvm-pdbutil bytes -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
33
44 STREAM: Stream Data
55 STREAM-NEXT: ============================================================
0 //===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "BytesOutputStyle.h"
10
11 #include "StreamUtil.h"
12 #include "llvm-pdbutil.h"
13
14 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
15 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
16 #include "llvm/DebugInfo/PDB/Native/RawError.h"
17 #include "llvm/Support/BinaryStreamReader.h"
18 #include "llvm/Support/FormatAdapters.h"
19 #include "llvm/Support/FormatVariadic.h"
20
21 using namespace llvm;
22 using namespace llvm::msf;
23 using namespace llvm::pdb;
24
25 namespace {
26 struct StreamSpec {
27 uint32_t SI = 0;
28 uint32_t Begin = 0;
29 uint32_t Size = 0;
30 };
31 } // namespace
32
33 static Expected parseStreamSpec(StringRef Str) {
34 StreamSpec Result;
35 if (Str.consumeInteger(0, Result.SI))
36 return make_error(raw_error_code::invalid_format,
37 "Invalid Stream Specification");
38 if (Str.consume_front(":")) {
39 if (Str.consumeInteger(0, Result.Begin))
40 return make_error(raw_error_code::invalid_format,
41 "Invalid Stream Specification");
42 }
43 if (Str.consume_front("@")) {
44 if (Str.consumeInteger(0, Result.Size))
45 return make_error(raw_error_code::invalid_format,
46 "Invalid Stream Specification");
47 }
48
49 if (!Str.empty())
50 return make_error(raw_error_code::invalid_format,
51 "Invalid Stream Specification");
52 return Result;
53 }
54
55 static SmallVector parseStreamSpecs(LinePrinter &P) {
56 SmallVector Result;
57
58 for (auto &Str : opts::bytes::DumpStreamData) {
59 auto ESS = parseStreamSpec(Str);
60 if (!ESS) {
61 P.formatLine("Error parsing stream spec {0}: {1}", Str,
62 toString(ESS.takeError()));
63 continue;
64 }
65 Result.push_back(*ESS);
66 }
67 return Result;
68 }
69
70 static void printHeader(LinePrinter &P, const Twine &S) {
71 P.NewLine();
72 P.formatLine("{0,=60}", S);
73 P.formatLine("{0}", fmt_repeat('=', 60));
74 }
75
76 BytesOutputStyle::BytesOutputStyle(PDBFile &File)
77 : File(File), P(2, false, outs()) {}
78
79 Error BytesOutputStyle::dump() {
80
81 if (opts::bytes::DumpBlockRange.hasValue()) {
82 auto &R = *opts::bytes::DumpBlockRange;
83 uint32_t Max = R.Max.getValueOr(R.Min);
84
85 if (Max < R.Min)
86 return make_error(
87 "Invalid block range specified. Max < Min",
88 inconvertibleErrorCode());
89 if (Max >= File.getBlockCount())
90 return make_error(
91 "Invalid block range specified. Requested block out of bounds",
92 inconvertibleErrorCode());
93
94 dumpBlockRanges(R.Min, Max);
95 P.NewLine();
96 }
97
98 if (!opts::bytes::DumpStreamData.empty()) {
99 dumpStreamBytes();
100 P.NewLine();
101 }
102 return Error::success();
103 }
104
105 void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
106 printHeader(P, "MSF Blocks");
107
108 AutoIndent Indent(P);
109 for (uint32_t I = Min; I <= Max; ++I) {
110 uint64_t Base = I;
111 Base *= File.getBlockSize();
112
113 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
114 if (!ExpectedData) {
115 P.formatLine("Could not get block {0}. Reason = {1}", I,
116 toString(ExpectedData.takeError()));
117 continue;
118 }
119 std::string Label = formatv("Block {0}", I).str();
120 P.formatBinary(Label, *ExpectedData, Base, 0);
121 }
122 }
123
124 void BytesOutputStyle::dumpStreamBytes() {
125 if (StreamPurposes.empty())
126 discoverStreamPurposes(File, StreamPurposes);
127
128 printHeader(P, "Stream Data");
129 ExitOnError Err("Unexpected error reading stream data");
130
131 auto Specs = parseStreamSpecs(P);
132
133 for (const auto &Spec : Specs) {
134 uint32_t End = 0;
135
136 AutoIndent Indent(P);
137 if (Spec.SI >= File.getNumStreams()) {
138 P.formatLine("Stream {0}: Not present", Spec.SI);
139 continue;
140 }
141
142 auto S = MappedBlockStream::createIndexedStream(
143 File.getMsfLayout(), File.getMsfBuffer(), Spec.SI, File.getAllocator());
144 if (!S) {
145 P.NewLine();
146 P.formatLine("Stream {0}: Not present", Spec.SI);
147 continue;
148 }
149
150 if (Spec.Size == 0)
151 End = S->getLength();
152 else
153 End = std::min(Spec.Begin + Spec.Size, S->getLength());
154 uint32_t Size = End - Spec.Begin;
155
156 P.formatLine("Stream {0} ({1:N} bytes): {2}", Spec.SI, S->getLength(),
157 StreamPurposes[Spec.SI]);
158 AutoIndent Indent2(P);
159
160 BinaryStreamReader R(*S);
161 ArrayRef StreamData;
162 Err(R.readBytes(StreamData, S->getLength()));
163 StreamData = StreamData.slice(Spec.Begin, Size);
164 P.formatBinary("Data", StreamData, Spec.Begin);
165 }
166 }
0 //===- BytesOutputStyle.h ------------------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
10 #define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
11
12 #include "LinePrinter.h"
13 #include "OutputStyle.h"
14
15 #include "llvm/Support/Error.h"
16
17 namespace llvm {
18
19 namespace pdb {
20
21 class PDBFile;
22
23 class BytesOutputStyle : public OutputStyle {
24 public:
25 BytesOutputStyle(PDBFile &File);
26
27 Error dump() override;
28
29 private:
30 void dumpBlockRanges(uint32_t Min, uint32_t Max);
31 void dumpStreamBytes();
32
33 PDBFile &File;
34 LinePrinter P;
35 SmallVector StreamPurposes;
36 };
37 } // namespace pdb
38 } // namespace llvm
39
40 #endif
88
99 add_llvm_tool(llvm-pdbutil
1010 Analyze.cpp
11 BytesOutputStyle.cpp
1112 Diff.cpp
1213 DumpOutputStyle.cpp
1314 llvm-pdbutil.cpp
7979 P.NewLine();
8080 }
8181
82 if (opts::dump::DumpBlockRange.hasValue()) {
83 if (auto EC = dumpBlockRanges())
84 return EC;
85 P.NewLine();
86 }
87
88 if (!opts::dump::DumpStreamData.empty()) {
89 if (auto EC = dumpStreamBytes())
90 return EC;
91 P.NewLine();
92 }
93
9482 if (opts::dump::DumpStringTable) {
9583 if (auto EC = dumpStringTable())
9684 return EC;
212200 StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
213201 }
214202
215 return Error::success();
216 }
217
218 Error DumpOutputStyle::dumpBlockRanges() {
219 printHeader(P, "MSF Blocks");
220
221 auto &R = *opts::dump::DumpBlockRange;
222 uint32_t Max = R.Max.getValueOr(R.Min);
223
224 AutoIndent Indent(P);
225 if (Max < R.Min)
226 return make_error(
227 "Invalid block range specified. Max < Min",
228 std::make_error_code(std::errc::bad_address));
229 if (Max >= File.getBlockCount())
230 return make_error(
231 "Invalid block range specified. Requested block out of bounds",
232 std::make_error_code(std::errc::bad_address));
233
234 for (uint32_t I = R.Min; I <= Max; ++I) {
235 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
236 if (!ExpectedData)
237 return ExpectedData.takeError();
238 std::string Label = formatv("Block {0}", I).str();
239 P.formatBinary(Label, *ExpectedData, 0);
240 }
241
242 return Error::success();
243 }
244
245 static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
246 uint32_t &Size) {
247 if (Str.consumeInteger(0, SI))
248 return make_error(raw_error_code::invalid_format,
249 "Invalid Stream Specification");
250 if (Str.consume_front(":")) {
251 if (Str.consumeInteger(0, Offset))
252 return make_error(raw_error_code::invalid_format,
253 "Invalid Stream Specification");
254 }
255 if (Str.consume_front("@")) {
256 if (Str.consumeInteger(0, Size))
257 return make_error(raw_error_code::invalid_format,
258 "Invalid Stream Specification");
259 }
260 if (!Str.empty())
261 return make_error(raw_error_code::invalid_format,
262 "Invalid Stream Specification");
263 return Error::success();
264 }
265
266 Error DumpOutputStyle::dumpStreamBytes() {
267 if (StreamPurposes.empty())
268 discoverStreamPurposes(File, StreamPurposes);
269
270 printHeader(P, "Stream Data");
271 ExitOnError Err("Unexpected error reading stream data");
272
273 for (auto &Str : opts::dump::DumpStreamData) {
274 uint32_t SI = 0;
275 uint32_t Begin = 0;
276 uint32_t Size = 0;
277 uint32_t End = 0;
278
279 if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
280 return EC;
281
282 AutoIndent Indent(P);
283 if (SI >= File.getNumStreams()) {
284 P.formatLine("Stream {0}: Not present", SI);
285 continue;
286 }
287
288 auto S = MappedBlockStream::createIndexedStream(
289 File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
290 if (!S) {
291 P.NewLine();
292 P.formatLine("Stream {0}: Not present", SI);
293 continue;
294 }
295
296 if (Size == 0)
297 End = S->getLength();
298 else
299 End = std::min(Begin + Size, S->getLength());
300
301 P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
302 StreamPurposes[SI]);
303 AutoIndent Indent2(P);
304
305 BinaryStreamReader R(*S);
306 ArrayRef StreamData;
307 Err(R.readBytes(StreamData, S->getLength()));
308 Size = End - Begin;
309 StreamData = StreamData.slice(Begin, Size);
310 P.formatBinary("Data", StreamData, Begin);
311 }
312203 return Error::success();
313204 }
314205
105105 OS << ")";
106106 }
107107
108 void LinePrinter::formatBinary(StringRef Label, ArrayRef Data,
109 uint64_t Base, uint32_t StartOffset) {
110 NewLine();
111 OS << Label << " (";
112 if (!Data.empty()) {
113 OS << "\n";
114 Base += StartOffset;
115 OS << format_bytes_with_ascii(Data, Base, 32, 4,
116 CurrentIndent + IndentSpaces, true);
117 NewLine();
118 }
119 OS << ")";
120 }
121
108122 bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
109123 if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
110124 return true;
4343 }
4444
4545 void formatBinary(StringRef Label, ArrayRef Data,
46 uint32_t StartOffset);
47 void formatBinary(StringRef Label, ArrayRef Data, uint64_t BaseAddr,
4648 uint32_t StartOffset);
4749
4850 bool hasColor() const { return UseColor; }
1313 #include "llvm-pdbutil.h"
1414
1515 #include "Analyze.h"
16 #include "BytesOutputStyle.h"
1617 #include "Diff.h"
1718 #include "DumpOutputStyle.h"
1819 #include "LinePrinter.h"
8687 namespace opts {
8788
8889 cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
90 cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file");
91
8992 cl::SubCommand
9093 PrettySubcommand("pretty",
9194 "Dump semantic information about types and symbols");
262265
263266 cl::OptionCategory FileOptions("Module & File Options");
264267
268 namespace bytes {
269 llvm::Optional DumpBlockRange;
270
271 cl::opt
272 DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
273 cl::desc("Dump binary data from specified range."),
274 cl::sub(BytesSubcommand));
275
276 cl::list
277 DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
278 cl::desc("Dump binary data from specified streams. Format "
279 "is SN[:Start][@Size]"),
280 cl::sub(BytesSubcommand));
281
282 cl::list InputFilenames(cl::Positional,
283 cl::desc(""),
284 cl::OneOrMore, cl::sub(BytesSubcommand));
285
286 } // namespace bytes
287
265288 namespace dump {
266289
267290 cl::OptionCategory MsfOptions("MSF Container Options");
275298 cl::opt DumpStreams("streams",
276299 cl::desc("dump summary of the PDB streams"),
277300 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
278 cl::opt
279 DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
280 cl::desc("Dump binary data from specified range."),
281 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
282 llvm::Optional DumpBlockRange;
283
284 cl::list
285 DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
286 cl::desc("Dump binary data from specified streams. Format "
287 "is SN[:Start][@Size]"),
288 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
289301
290302 // TYPE OPTIONS
291303 cl::opt DumpTypes("types",
625637 ExitOnErr(O->dump());
626638 }
627639
640 static void dumpBytes(StringRef Path) {
641 std::unique_ptr Session;
642 auto &File = loadPDB(Path, Session);
643
644 auto O = llvm::make_unique(File);
645
646 ExitOnErr(O->dump());
647 }
648
628649 static void dumpAnalysis(StringRef Path) {
629650 std::unique_ptr Session;
630651 auto &File = loadPDB(Path, Session);
881902 ExitOnErr(Builder.commit(OutFile));
882903 }
883904
905 static bool validateBlockRangeArgument() {
906 if (opts::bytes::DumpBlockRangeOpt.empty())
907 return true;
908
909 llvm::Regex R("^([^-]+)(-([^-]+))?$");
910 llvm::SmallVector Matches;
911 if (!R.match(opts::bytes::DumpBlockRangeOpt, &Matches))
912 return false;
913
914 opts::bytes::DumpBlockRange.emplace();
915 if (!to_integer(Matches[1], opts::bytes::DumpBlockRange->Min))
916 return false;
917
918 if (!Matches[3].empty()) {
919 opts::bytes::DumpBlockRange->Max.emplace();
920 if (!to_integer(Matches[3], *opts::bytes::DumpBlockRange->Max))
921 return false;
922 }
923 return true;
924 }
925
884926 int main(int argc_, const char *argv_[]) {
885927 // Print a stack trace if we signal out.
886928 sys::PrintStackTraceOnErrorSignal(argv_[0]);
896938 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
897939
898940 cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
899 if (!opts::dump::DumpBlockRangeOpt.empty()) {
900 llvm::Regex R("^([0-9]+)(-([0-9]+))?$");
901 llvm::SmallVector Matches;
902 if (!R.match(opts::dump::DumpBlockRangeOpt, &Matches)) {
903 errs() << "Argument '" << opts::dump::DumpBlockRangeOpt
904 << "' invalid format.\n";
905 errs().flush();
906 exit(1);
907 }
908 opts::dump::DumpBlockRange.emplace();
909 Matches[1].getAsInteger(10, opts::dump::DumpBlockRange->Min);
910 if (!Matches[3].empty()) {
911 opts::dump::DumpBlockRange->Max.emplace();
912 Matches[3].getAsInteger(10, *opts::dump::DumpBlockRange->Max);
913 }
941 if (!validateBlockRangeArgument()) {
942 errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
943 << "' invalid format.\n";
944 errs().flush();
945 exit(1);
914946 }
915947
916948 if (opts::DumpSubcommand) {
10171049 } else if (opts::DumpSubcommand) {
10181050 std::for_each(opts::dump::InputFilenames.begin(),
10191051 opts::dump::InputFilenames.end(), dumpRaw);
1052 } else if (opts::BytesSubcommand) {
1053 std::for_each(opts::bytes::InputFilenames.begin(),
1054 opts::bytes::InputFilenames.end(), dumpBytes);
10201055 } else if (opts::DiffSubcommand) {
10211056 if (opts::diff::InputFilenames.size() != 2) {
10221057 errs() << "diff subcommand expects exactly 2 arguments.\n";
9191 extern llvm::cl::opt ClassRecursionDepth;
9292 }
9393
94 namespace dump {
94 namespace bytes {
9595 struct BlockRange {
9696 uint32_t Min;
9797 llvm::Optional Max;
9898 };
99 extern llvm::Optional DumpBlockRange;
100 extern llvm::cl::list DumpStreamData;
101 } // namespace bytes
102
103 namespace dump {
99104
100105 extern llvm::cl::opt DumpSummary;
101106 extern llvm::cl::opt DumpStreams;
102 extern llvm::Optional DumpBlockRange;
103 extern llvm::cl::list DumpStreamData;
104107
105108 extern llvm::cl::opt DumpLines;
106109 extern llvm::cl::opt DumpInlineeLines;