Bug Summary

File:tools/llvm-pdbutil/DumpOutputStyle.cpp
Warning:line 1011, column 15
The left operand of '!=' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name DumpOutputStyle.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/llvm-pdbutil -I /build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn326246/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/llvm-pdbutil -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-02-28-041547-14988-1 -x c++ /build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil/DumpOutputStyle.cpp

/build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil/DumpOutputStyle.cpp

1//===- DumpOutputStyle.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 "DumpOutputStyle.h"
11
12#include "FormatUtil.h"
13#include "InputFile.h"
14#include "MinimalSymbolDumper.h"
15#include "MinimalTypeDumper.h"
16#include "StreamUtil.h"
17#include "llvm-pdbutil.h"
18
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
21#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
22#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
23#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
24#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
25#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
26#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
27#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
28#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
29#include "llvm/DebugInfo/CodeView/Formatters.h"
30#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
31#include "llvm/DebugInfo/CodeView/Line.h"
32#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
33#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
34#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
35#include "llvm/DebugInfo/CodeView/TypeHashing.h"
36#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
37#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
38#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
39#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
40#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
41#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
42#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
43#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
44#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
45#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
46#include "llvm/DebugInfo/PDB/Native/RawError.h"
47#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
48#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
49#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
50#include "llvm/Object/COFF.h"
51#include "llvm/Support/BinaryStreamReader.h"
52#include "llvm/Support/FormatAdapters.h"
53#include "llvm/Support/FormatVariadic.h"
54
55#include <cctype>
56
57using namespace llvm;
58using namespace llvm::codeview;
59using namespace llvm::msf;
60using namespace llvm::pdb;
61
62DumpOutputStyle::DumpOutputStyle(InputFile &File)
63 : File(File), P(2, false, outs()) {}
64
65PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
66object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
67
68Error DumpOutputStyle::dump() {
69 if (opts::dump::DumpSummary) {
70 if (auto EC = dumpFileSummary())
71 return EC;
72 P.NewLine();
73 }
74
75 if (opts::dump::DumpStreams) {
76 if (auto EC = dumpStreamSummary())
77 return EC;
78 P.NewLine();
79 }
80
81 if (opts::dump::DumpSymbolStats) {
82 if (auto EC = dumpSymbolStats())
83 return EC;
84 P.NewLine();
85 }
86
87 if (opts::dump::DumpUdtStats) {
88 if (auto EC = dumpUdtStats())
89 return EC;
90 P.NewLine();
91 }
92
93 if (opts::dump::DumpStringTable) {
94 if (auto EC = dumpStringTable())
95 return EC;
96 P.NewLine();
97 }
98
99 if (opts::dump::DumpModules) {
100 if (auto EC = dumpModules())
101 return EC;
102 }
103
104 if (opts::dump::DumpModuleFiles) {
105 if (auto EC = dumpModuleFiles())
106 return EC;
107 }
108
109 if (opts::dump::DumpLines) {
110 if (auto EC = dumpLines())
111 return EC;
112 }
113
114 if (opts::dump::DumpInlineeLines) {
115 if (auto EC = dumpInlineeLines())
116 return EC;
117 }
118
119 if (opts::dump::DumpXmi) {
120 if (auto EC = dumpXmi())
121 return EC;
122 }
123
124 if (opts::dump::DumpXme) {
125 if (auto EC = dumpXme())
126 return EC;
127 }
128
129 if (File.isObj()) {
130 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
131 opts::dump::DumpTypeExtras)
132 if (auto EC = dumpTypesFromObjectFile())
133 return EC;
134 } else {
135 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
136 opts::dump::DumpTypeExtras) {
137 if (auto EC = dumpTpiStream(StreamTPI))
138 return EC;
139 }
140
141 if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
142 opts::dump::DumpIdExtras) {
143 if (auto EC = dumpTpiStream(StreamIPI))
144 return EC;
145 }
146 }
147
148 if (opts::dump::DumpGlobals) {
149 if (auto EC = dumpGlobals())
150 return EC;
151 }
152
153 if (opts::dump::DumpPublics) {
154 if (auto EC = dumpPublics())
155 return EC;
156 }
157
158 if (opts::dump::DumpSymbols) {
159 auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj();
160 if (EC)
161 return EC;
162 }
163
164 if (opts::dump::DumpSectionHeaders) {
165 if (auto EC = dumpSectionHeaders())
166 return EC;
167 }
168
169 if (opts::dump::DumpSectionContribs) {
170 if (auto EC = dumpSectionContribs())
171 return EC;
172 }
173
174 if (opts::dump::DumpSectionMap) {
175 if (auto EC = dumpSectionMap())
176 return EC;
177 }
178
179 return Error::success();
180}
181
182static void printHeader(LinePrinter &P, const Twine &S) {
183 P.NewLine();
184 P.formatLine("{0,=60}", S);
185 P.formatLine("{0}", fmt_repeat('=', 60));
186}
187
188Error DumpOutputStyle::dumpFileSummary() {
189 printHeader(P, "Summary");
190
191 ExitOnError Err("Invalid PDB Format: ");
192
193 AutoIndent Indent(P);
194 if (File.isObj()) {
195 P.formatLine("Dumping File summary is not valid for object files");
196 return Error::success();
197 }
198
199 P.formatLine("Block Size: {0}", getPdb().getBlockSize());
200 P.formatLine("Number of blocks: {0}", getPdb().getBlockCount());
201 P.formatLine("Number of streams: {0}", getPdb().getNumStreams());
202
203 auto &PS = Err(getPdb().getPDBInfoStream());
204 P.formatLine("Signature: {0}", PS.getSignature());
205 P.formatLine("Age: {0}", PS.getAge());
206 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
207 P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
208 P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream());
209 P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream());
210 P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream());
211 P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream());
212 P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream());
213 if (getPdb().hasPDBDbiStream()) {
214 auto &DBI = Err(getPdb().getPDBDbiStream());
215 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
216 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
217 P.formatLine("Is stripped: {0}", DBI.isStripped());
218 }
219
220 return Error::success();
221}
222
223static StatCollection getSymbolStats(const SymbolGroup &SG,
224 StatCollection &CumulativeStats) {
225 StatCollection Stats;
226 if (SG.getFile().isPdb()) {
227 // For PDB files, all symbols are packed into one stream.
228 for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) {
229 Stats.update(S.kind(), S.length());
230 CumulativeStats.update(S.kind(), S.length());
231 }
232 return Stats;
233 }
234
235 for (const auto &SS : SG.getDebugSubsections()) {
236 // For object files, all symbols are spread across multiple Symbol
237 // subsections of a given .debug$S section.
238 if (SS.kind() != DebugSubsectionKind::Symbols)
239 continue;
240 DebugSymbolsSubsectionRef Symbols;
241 BinaryStreamReader Reader(SS.getRecordData());
242 cantFail(Symbols.initialize(Reader));
243 for (const auto &S : Symbols) {
244 Stats.update(S.kind(), S.length());
245 CumulativeStats.update(S.kind(), S.length());
246 }
247 }
248 return Stats;
249}
250
251static StatCollection getChunkStats(const SymbolGroup &SG,
252 StatCollection &CumulativeStats) {
253 StatCollection Stats;
254 for (const auto &Chunk : SG.getDebugSubsections()) {
255 Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
256 CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
257 }
258 return Stats;
259}
260
261static inline std::string formatModuleDetailKind(DebugSubsectionKind K) {
262 return formatChunkKind(K, false);
263}
264
265static inline std::string formatModuleDetailKind(SymbolKind K) {
266 return formatSymbolKind(K);
267}
268
269template <typename Kind>
270static void printModuleDetailStats(LinePrinter &P, StringRef Label,
271 const StatCollection &Stats) {
272 P.NewLine();
273 P.formatLine(" {0}", Label);
274 AutoIndent Indent(P);
275 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", "Total",
276 Stats.Totals.Count, Stats.Totals.Size);
277 P.formatLine("{0}", fmt_repeat('-', 74));
278 for (const auto &K : Stats.Individual) {
279 std::string KindName = formatModuleDetailKind(Kind(K.first));
280 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", KindName,
281 K.second.Count, K.second.Size);
282 }
283}
284
285static bool isMyCode(const SymbolGroup &Group) {
286 if (Group.getFile().isObj())
287 return true;
288
289 StringRef Name = Group.name();
290 if (Name.startswith("Import:"))
291 return false;
292 if (Name.endswith_lower(".dll"))
293 return false;
294 if (Name.equals_lower("* linker *"))
295 return false;
296 if (Name.startswith_lower("f:\\binaries\\Intermediate\\vctools"))
297 return false;
298 if (Name.startswith_lower("f:\\dd\\vctools\\crt"))
299 return false;
300 return true;
301}
302
303static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) {
304 if (opts::dump::JustMyCode && !isMyCode(Group))
305 return false;
306
307 // If the arg was not specified on the command line, always dump all modules.
308 if (opts::dump::DumpModi.getNumOccurrences() == 0)
309 return true;
310
311 // Otherwise, only dump if this is the same module specified.
312 return (opts::dump::DumpModi == Idx);
313}
314
315Error DumpOutputStyle::dumpStreamSummary() {
316 printHeader(P, "Streams");
317
318 AutoIndent Indent(P);
319 if (File.isObj()) {
320 P.formatLine("Dumping streams is not valid for object files");
321 return Error::success();
322 }
323
324 if (StreamPurposes.empty())
325 discoverStreamPurposes(getPdb(), StreamPurposes);
326
327 uint32_t StreamCount = getPdb().getNumStreams();
328 uint32_t MaxStreamSize = getPdb().getMaxStreamSize();
329
330 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
331 P.formatLine(
332 "Stream {0} ({1} bytes): [{2}]",
333 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
334 fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right,
335 NumDigits(MaxStreamSize)),
336 StreamPurposes[StreamIdx].getLongName());
337
338 if (opts::dump::DumpStreamBlocks) {
339 auto Blocks = getPdb().getStreamBlockList(StreamIdx);
340 std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
341 P.formatLine(" {0} Blocks: [{1}]",
342 fmt_repeat(' ', NumDigits(StreamCount)),
343 make_range(BV.begin(), BV.end()));
344 }
345 }
346
347 return Error::success();
348}
349
350static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
351 uint32_t Index) {
352 ExitOnError Err("Unexpected error: ");
353
354 auto &Dbi = Err(File.getPDBDbiStream());
355 const auto &Modules = Dbi.modules();
356 auto Modi = Modules.getModuleDescriptor(Index);
357
358 uint16_t ModiStream = Modi.getModuleStreamIndex();
359 if (ModiStream == kInvalidStreamIndex)
360 return make_error<RawError>(raw_error_code::no_stream,
361 "Module stream not present");
362
363 auto ModStreamData = File.createIndexedStream(ModiStream);
364
365 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
366 if (auto EC = ModS.reload())
367 return make_error<RawError>(raw_error_code::corrupt_file,
368 "Invalid module stream");
369
370 return std::move(ModS);
371}
372
373template <typename CallbackT>
374static void
375iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope,
376 const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) {
377 if (HeaderScope) {
378 HeaderScope->P.formatLine(
379 "Mod {0:4} | `{1}`: ",
380 fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name());
381 }
382
383 AutoIndent Indent(HeaderScope);
384 Callback(Modi, SG);
385}
386
387template <typename CallbackT>
388static void iterateSymbolGroups(InputFile &Input,
389 const Optional<PrintScope> &HeaderScope,
390 CallbackT Callback) {
391 AutoIndent Indent(HeaderScope);
392
393 ExitOnError Err("Unexpected error processing modules: ");
394
395 if (opts::dump::DumpModi.getNumOccurrences() > 0) {
396 assert(opts::dump::DumpModi.getNumOccurrences() == 1)(static_cast <bool> (opts::dump::DumpModi.getNumOccurrences
() == 1) ? void (0) : __assert_fail ("opts::dump::DumpModi.getNumOccurrences() == 1"
, "/build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil/DumpOutputStyle.cpp"
, 396, __extension__ __PRETTY_FUNCTION__))
;
397 uint32_t Modi = opts::dump::DumpModi;
398 SymbolGroup SG(&Input, Modi);
399 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG,
400 Modi, Callback);
401 return;
402 }
403
404 uint32_t I = 0;
405
406 for (const auto &SG : Input.symbol_groups()) {
407 if (shouldDumpSymbolGroup(I, SG))
408 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I,
409 Callback);
410
411 ++I;
412 }
413}
414
415template <typename SubsectionT>
416static void iterateModuleSubsections(
417 InputFile &File, const Optional<PrintScope> &HeaderScope,
418 llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)>
419 Callback) {
420
421 iterateSymbolGroups(File, HeaderScope,
422 [&](uint32_t Modi, const SymbolGroup &SG) {
423 for (const auto &SS : SG.getDebugSubsections()) {
424 SubsectionT Subsection;
425
426 if (SS.kind() != Subsection.kind())
427 continue;
428
429 BinaryStreamReader Reader(SS.getRecordData());
430 if (auto EC = Subsection.initialize(Reader))
431 continue;
432 Callback(Modi, SG, Subsection);
433 }
434 });
435}
436
437Error DumpOutputStyle::dumpModules() {
438 printHeader(P, "Modules");
439 AutoIndent Indent(P);
440
441 if (File.isObj()) {
442 P.formatLine("Dumping modules is not supported for object files");
443 return Error::success();
444 }
445
446 if (!getPdb().hasPDBDbiStream()) {
447 P.formatLine("DBI Stream not present");
448 return Error::success();
449 }
450
451 ExitOnError Err("Unexpected error processing modules: ");
452
453 auto &Stream = Err(getPdb().getPDBDbiStream());
454
455 const DbiModuleList &Modules = Stream.modules();
456 iterateSymbolGroups(
457 File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) {
458 auto Desc = Modules.getModuleDescriptor(Modi);
459 P.formatLine("Obj: `{0}`: ", Desc.getObjFileName());
460 P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}",
461 Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(),
462 Desc.hasECInfo());
463 StringRef PdbFilePath =
464 Err(Stream.getECName(Desc.getPdbFilePathNameIndex()));
465 StringRef SrcFilePath =
466 Err(Stream.getECName(Desc.getSourceFileNameIndex()));
467 P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
468 Desc.getPdbFilePathNameIndex(), PdbFilePath,
469 Desc.getSourceFileNameIndex(), SrcFilePath);
470 });
471 return Error::success();
472}
473
474Error DumpOutputStyle::dumpModuleFiles() {
475 printHeader(P, "Files");
476
477 if (File.isObj()) {
478 P.formatLine("Dumping files is not valid for object files");
479 return Error::success();
480 }
481
482 ExitOnError Err("Unexpected error processing modules: ");
483
484 iterateSymbolGroups(File, PrintScope{P, 11},
485 [this, &Err](uint32_t Modi, const SymbolGroup &Strings) {
486 auto &Stream = Err(getPdb().getPDBDbiStream());
487
488 const DbiModuleList &Modules = Stream.modules();
489 for (const auto &F : Modules.source_files(Modi)) {
490 Strings.formatFromFileName(P, F);
491 }
492 });
493 return Error::success();
494}
495
496Error DumpOutputStyle::dumpSymbolStats() {
497 printHeader(P, "Module Stats");
498
499 ExitOnError Err("Unexpected error processing modules: ");
500
501 StatCollection SymStats;
502 StatCollection ChunkStats;
503
504 Optional<PrintScope> Scope;
505 if (File.isPdb())
506 Scope.emplace(P, 2);
507
508 iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) {
509 StatCollection SS = getSymbolStats(SG, SymStats);
510 StatCollection CS = getChunkStats(SG, ChunkStats);
511
512 if (SG.getFile().isPdb()) {
513 AutoIndent Indent(P);
514 auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules();
515 uint32_t ModCount = Modules.getModuleCount();
516 DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi);
517 uint32_t StreamIdx = Desc.getModuleStreamIndex();
518
519 if (StreamIdx == kInvalidStreamIndex) {
520 P.formatLine("Mod {0} (debug info not present): [{1}]",
521 fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)),
522 Desc.getModuleName());
523 return;
524 }
525 P.formatLine("Stream {0}, {1} bytes", StreamIdx,
526 getPdb().getStreamByteSize(StreamIdx));
527
528 printModuleDetailStats<SymbolKind>(P, "Symbols", SS);
529 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS);
530 }
531 });
532
533 P.printLine(" Summary |");
534 AutoIndent Indent(P, 4);
535 if (SymStats.Totals.Count > 0) {
536 printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats);
537 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats);
538 }
539
540 return Error::success();
541}
542
543static bool isValidNamespaceIdentifier(StringRef S) {
544 if (S.empty())
545 return false;
546
547 if (std::isdigit(S[0]))
548 return false;
549
550 return llvm::all_of(S, [](char C) { return std::isalnum(C); });
551}
552
553namespace {
554constexpr uint32_t kNoneUdtKind = 0;
555constexpr uint32_t kSimpleUdtKind = 1;
556constexpr uint32_t kUnknownUdtKind = 2;
557const StringRef NoneLabel("<none type>");
558const StringRef SimpleLabel("<simple type>");
559const StringRef UnknownLabel("<unknown type>");
560
561} // namespace
562
563static StringRef getUdtStatLabel(uint32_t Kind) {
564 if (Kind == kNoneUdtKind)
565 return NoneLabel;
566
567 if (Kind == kSimpleUdtKind)
568 return SimpleLabel;
569
570 if (Kind == kUnknownUdtKind)
571 return UnknownLabel;
572
573 return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind));
574}
575
576static uint32_t getLongestTypeLeafName(const StatCollection &Stats) {
577 size_t L = 0;
578 for (const auto &Stat : Stats.Individual) {
579 StringRef Label = getUdtStatLabel(Stat.first);
580 L = std::max(L, Label.size());
581 }
582 return static_cast<uint32_t>(L);
583}
584
585Error DumpOutputStyle::dumpUdtStats() {
586 printHeader(P, "S_UDT Record Stats");
587
588 StatCollection UdtStats;
589 StatCollection UdtTargetStats;
590 AutoIndent Indent(P, 4);
591
592 auto &TpiTypes = File.types();
593
594 StringMap<StatCollection::Stat> NamespacedStats;
595
596 size_t LongestNamespace = 0;
597 auto HandleOneSymbol = [&](const CVSymbol &Sym) {
598 if (Sym.kind() != SymbolKind::S_UDT)
599 return;
600 UdtStats.update(SymbolKind::S_UDT, Sym.length());
601
602 UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym));
603
604 uint32_t Kind = 0;
605 uint32_t RecordSize = 0;
606
607 if (UDT.Type.isNoneType())
608 Kind = kNoneUdtKind;
609 else if (UDT.Type.isSimple())
610 Kind = kSimpleUdtKind;
611 else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
612 Kind = T->kind();
613 RecordSize = T->length();
614 } else
615 Kind = kUnknownUdtKind;
616
617 UdtTargetStats.update(Kind, RecordSize);
618
619 size_t Pos = UDT.Name.find("::");
620 if (Pos == StringRef::npos)
621 return;
622
623 StringRef Scope = UDT.Name.take_front(Pos);
624 if (Scope.empty() || !isValidNamespaceIdentifier(Scope))
625 return;
626
627 LongestNamespace = std::max(LongestNamespace, Scope.size());
628 NamespacedStats[Scope].update(RecordSize);
629 };
630
631 P.NewLine();
632
633 if (File.isPdb()) {
634 if (!getPdb().hasPDBGlobalsStream()) {
635 P.printLine("- Error: globals stream not present");
636 return Error::success();
637 }
638
639 auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream());
640 auto ExpGlobals = getPdb().getPDBGlobalsStream();
641 if (!ExpGlobals)
642 return ExpGlobals.takeError();
643
644 for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) {
645 CVSymbol Sym = SymbolRecords.readRecord(PubSymOff);
646 HandleOneSymbol(Sym);
647 }
648 } else {
649 for (const auto &Sec : File.symbol_groups()) {
650 for (const auto &SS : Sec.getDebugSubsections()) {
651 if (SS.kind() != DebugSubsectionKind::Symbols)
652 continue;
653
654 DebugSymbolsSubsectionRef Symbols;
655 BinaryStreamReader Reader(SS.getRecordData());
656 cantFail(Symbols.initialize(Reader));
657 for (const auto &S : Symbols)
658 HandleOneSymbol(S);
659 }
660 }
661 }
662
663 LongestNamespace += StringRef(" namespace ''").size();
664 size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats);
665 size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind);
666
667 // Compute the max number of digits for count and size fields, including comma
668 // separators.
669 StringRef CountHeader("Count");
670 StringRef SizeHeader("Size");
671 size_t CD = NumDigits(UdtStats.Totals.Count);
672 CD += (CD - 1) / 3;
673 CD = std::max(CD, CountHeader.size());
674
675 size_t SD = NumDigits(UdtStats.Totals.Size);
676 SD += (SD - 1) / 3;
677 SD = std::max(SD, SizeHeader.size());
678
679 uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1;
680
681 P.formatLine("{0} | {1} {2}",
682 fmt_align("Record Kind", AlignStyle::Right, FieldWidth),
683 fmt_align(CountHeader, AlignStyle::Right, CD),
684 fmt_align(SizeHeader, AlignStyle::Right, SD));
685
686 P.formatLine("{0}", fmt_repeat('-', TableWidth));
687 for (const auto &Stat : UdtTargetStats.Individual) {
688 StringRef Label = getUdtStatLabel(Stat.first);
689 P.formatLine("{0} | {1:N} {2:N}",
690 fmt_align(Label, AlignStyle::Right, FieldWidth),
691 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
692 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
693 }
694 P.formatLine("{0}", fmt_repeat('-', TableWidth));
695 P.formatLine("{0} | {1:N} {2:N}",
696 fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth),
697 fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
698 fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
699 P.formatLine("{0}", fmt_repeat('-', TableWidth));
700 for (const auto &Stat : NamespacedStats) {
701 std::string Label = formatv("namespace '{0}'", Stat.getKey());
702 P.formatLine("{0} | {1:N} {2:N}",
703 fmt_align(Label, AlignStyle::Right, FieldWidth),
704 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
705 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
706 }
707 return Error::success();
708}
709
710static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start,
711 const LineColumnEntry &E) {
712 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
713 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
714
715 // Let's try to keep it under 100 characters
716 constexpr uint32_t kMaxRowLength = 100;
717 // At least 3 spaces between columns.
718 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
719 uint32_t ItemsLeft = E.LineNumbers.size();
720 auto LineIter = E.LineNumbers.begin();
721 while (ItemsLeft != 0) {
722 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
723 for (uint32_t I = 0; I < RowColumns; ++I) {
724 LineInfo Line(LineIter->Flags);
725 std::string LineStr;
726 if (Line.isAlwaysStepInto())
727 LineStr = "ASI";
728 else if (Line.isNeverStepInto())
729 LineStr = "NSI";
730 else
731 LineStr = utostr(Line.getStartLine());
732 char Statement = Line.isStatement() ? ' ' : '!';
733 P.format("{0} {1:X-} {2} ",
734 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
735 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
736 Statement);
737 ++LineIter;
738 --ItemsLeft;
739 }
740 P.NewLine();
741 }
742}
743
744Error DumpOutputStyle::dumpLines() {
745 printHeader(P, "Lines");
746
747 uint32_t LastModi = UINT32_MAX(4294967295U);
748 uint32_t LastNameIndex = UINT32_MAX(4294967295U);
749 iterateModuleSubsections<DebugLinesSubsectionRef>(
750 File, PrintScope{P, 4},
751 [this, &LastModi, &LastNameIndex](uint32_t Modi,
752 const SymbolGroup &Strings,
753 DebugLinesSubsectionRef &Lines) {
754 uint16_t Segment = Lines.header()->RelocSegment;
755 uint32_t Begin = Lines.header()->RelocOffset;
756 uint32_t End = Begin + Lines.header()->CodeSize;
757 for (const auto &Block : Lines) {
758 if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
759 LastModi = Modi;
760 LastNameIndex = Block.NameIndex;
761 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
762 }
763
764 AutoIndent Indent(P, 2);
765 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
766 uint32_t Count = Block.LineNumbers.size();
767 if (Lines.hasColumnInfo())
768 P.format("line/column/addr entries = {0}", Count);
769 else
770 P.format("line/addr entries = {0}", Count);
771
772 P.NewLine();
773 typesetLinesAndColumns(P, Begin, Block);
774 }
775 });
776
777 return Error::success();
778}
779
780Error DumpOutputStyle::dumpInlineeLines() {
781 printHeader(P, "Inlinee Lines");
782
783 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
784 File, PrintScope{P, 2},
785 [this](uint32_t Modi, const SymbolGroup &Strings,
786 DebugInlineeLinesSubsectionRef &Lines) {
787 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
788 for (const auto &Entry : Lines) {
789 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
790 fmtle(Entry.Header->SourceLineNum));
791 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
792 }
793 P.NewLine();
794 });
795
796 return Error::success();
797}
798
799Error DumpOutputStyle::dumpXmi() {
800 printHeader(P, "Cross Module Imports");
801 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
802 File, PrintScope{P, 2},
803 [this](uint32_t Modi, const SymbolGroup &Strings,
804 DebugCrossModuleImportsSubsectionRef &Imports) {
805 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
806
807 for (const auto &Xmi : Imports) {
808 auto ExpectedModule =
809 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
810 StringRef Module;
811 SmallString<32> ModuleStorage;
812 if (!ExpectedModule) {
813 Module = "(unknown module)";
814 consumeError(ExpectedModule.takeError());
815 } else
816 Module = *ExpectedModule;
817 if (Module.size() > 32) {
818 ModuleStorage = "...";
819 ModuleStorage += Module.take_back(32 - 3);
820 Module = ModuleStorage;
821 }
822 std::vector<std::string> TIs;
823 for (const auto I : Xmi.Imports)
824 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
825 std::string Result =
826 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
827 P.formatLine("{0,+32} | {1}", Module, Result);
828 }
829 });
830
831 return Error::success();
832}
833
834Error DumpOutputStyle::dumpXme() {
835 printHeader(P, "Cross Module Exports");
836
837 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
838 File, PrintScope{P, 2},
839 [this](uint32_t Modi, const SymbolGroup &Strings,
840 DebugCrossModuleExportsSubsectionRef &Exports) {
841 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
842 for (const auto &Export : Exports) {
843 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
844 TypeIndex(Export.Global));
845 }
846 });
847
848 return Error::success();
849}
850
851Error DumpOutputStyle::dumpStringTableFromPdb() {
852 AutoIndent Indent(P);
853 auto IS = getPdb().getStringTable();
854 if (!IS) {
855 P.formatLine("Not present in file");
856 consumeError(IS.takeError());
857 return Error::success();
858 }
859
860 if (IS->name_ids().empty()) {
861 P.formatLine("Empty");
862 return Error::success();
863 }
864
865 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
866 uint32_t Digits = NumDigits(*MaxID);
867
868 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
869 "String");
870
871 std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
872 std::sort(SortedIDs.begin(), SortedIDs.end());
873 for (uint32_t I : SortedIDs) {
874 auto ES = IS->getStringForID(I);
875 llvm::SmallString<32> Str;
876 if (!ES) {
877 consumeError(ES.takeError());
878 Str = "Error reading string";
879 } else if (!ES->empty()) {
880 Str.append("'");
881 Str.append(*ES);
882 Str.append("'");
883 }
884
885 if (!Str.empty())
886 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
887 }
888 return Error::success();
889}
890
891Error DumpOutputStyle::dumpStringTableFromObj() {
892 iterateModuleSubsections<DebugStringTableSubsectionRef>(
893 File, PrintScope{P, 4},
894 [&](uint32_t Modi, const SymbolGroup &Strings,
895 DebugStringTableSubsectionRef &Strings2) {
896 BinaryStreamRef StringTableBuffer = Strings2.getBuffer();
897 BinaryStreamReader Reader(StringTableBuffer);
898 while (Reader.bytesRemaining() > 0) {
899 StringRef Str;
900 uint32_t Offset = Reader.getOffset();
901 cantFail(Reader.readCString(Str));
902 if (Str.empty())
903 continue;
904
905 P.formatLine("{0} | {1}", fmt_align(Offset, AlignStyle::Right, 4),
906 Str);
907 }
908 });
909 return Error::success();
910}
911
912Error DumpOutputStyle::dumpStringTable() {
913 printHeader(P, "String Table");
914
915 if (File.isPdb())
916 return dumpStringTableFromPdb();
917
918 return dumpStringTableFromObj();
919}
920
921static void buildDepSet(LazyRandomTypeCollection &Types,
922 ArrayRef<TypeIndex> Indices,
923 std::map<TypeIndex, CVType> &DepSet) {
924 SmallVector<TypeIndex, 4> DepList;
925 for (const auto &I : Indices) {
926 TypeIndex TI(I);
927 if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
928 continue;
929
930 CVType Type = Types.getType(TI);
931 DepSet[TI] = Type;
932 codeview::discoverTypeIndices(Type, DepList);
933 buildDepSet(Types, DepList, DepSet);
934 }
935}
936
937static void
938dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
939 uint32_t NumTypeRecords, uint32_t NumHashBuckets,
940 FixedStreamArray<support::ulittle32_t> HashValues,
941 bool Bytes, bool Extras) {
942
943 Printer.formatLine("Showing {0:N} records", NumTypeRecords);
944 uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
945
946 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
947 NumHashBuckets, HashValues);
948
949 if (auto EC = codeview::visitTypeStream(Types, V)) {
950 Printer.formatLine("An error occurred dumping type records: {0}",
951 toString(std::move(EC)));
952 }
953}
954
955static void dumpPartialTypeStream(LinePrinter &Printer,
956 LazyRandomTypeCollection &Types,
957 TpiStream &Stream, ArrayRef<TypeIndex> TiList,
958 bool Bytes, bool Extras, bool Deps) {
959 uint32_t Width =
960 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
961
962 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
963 Stream.getNumHashBuckets(), Stream.getHashValues());
964
965 if (opts::dump::DumpTypeDependents) {
966 // If we need to dump all dependents, then iterate each index and find
967 // all dependents, adding them to a map ordered by TypeIndex.
968 std::map<TypeIndex, CVType> DepSet;
969 buildDepSet(Types, TiList, DepSet);
970
971 Printer.formatLine(
972 "Showing {0:N} records and their dependents ({1:N} records total)",
973 TiList.size(), DepSet.size());
974
975 for (auto &Dep : DepSet) {
976 if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
977 Printer.formatLine("An error occurred dumping type record {0}: {1}",
978 Dep.first, toString(std::move(EC)));
979 }
980 } else {
981 Printer.formatLine("Showing {0:N} records.", TiList.size());
982
983 for (const auto &I : TiList) {
984 TypeIndex TI(I);
985 CVType Type = Types.getType(TI);
986 if (auto EC = codeview::visitTypeRecord(Type, TI, V))
987 Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
988 toString(std::move(EC)));
989 }
990 }
991}
992
993Error DumpOutputStyle::dumpTypesFromObjectFile() {
994 LazyRandomTypeCollection Types(100);
995
996 for (const auto &S : getObj().sections()) {
997 StringRef SectionName;
998 if (auto EC = S.getName(SectionName))
1
Taking false branch
66
Taking false branch
999 return errorCodeToError(EC);
1000
1001 if (SectionName != ".debug$T")
2
Taking false branch
67
Taking false branch
1002 continue;
1003 StringRef Contents;
1004 if (auto EC = S.getContents(Contents))
3
Taking false branch
68
Taking false branch
1005 return errorCodeToError(EC);
1006
1007 uint32_t Magic;
69
'Magic' declared without an initial value
1008 BinaryStreamReader Reader(Contents, llvm::support::little);
1009 if (auto EC = Reader.readInteger(Magic))
4
Calling 'BinaryStreamReader::readInteger'
58
Returning from 'BinaryStreamReader::readInteger'
59
Taking false branch
70
Calling 'BinaryStreamReader::readInteger'
115
Returning from 'BinaryStreamReader::readInteger'
116
Taking false branch
1010 return EC;
1011 if (Magic != COFF::DEBUG_SECTION_MAGIC)
60
Assuming 'Magic' is equal to DEBUG_SECTION_MAGIC
61
Taking false branch
117
The left operand of '!=' is a garbage value
1012 return make_error<StringError>("Invalid CodeView debug section.",
1013 inconvertibleErrorCode());
1014
1015 Types.reset(Reader, 100);
1016
1017 if (opts::dump::DumpTypes) {
62
Assuming the condition is false
63
Taking false branch
1018 dumpFullTypeStream(P, Types, 0, 0, {}, opts::dump::DumpTypeData, false);
1019 } else if (opts::dump::DumpTypeExtras) {
64
Assuming the condition is false
65
Taking false branch
1020 auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
1021 auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
1022 assert(LocalHashes.size() == GlobalHashes.size())(static_cast <bool> (LocalHashes.size() == GlobalHashes
.size()) ? void (0) : __assert_fail ("LocalHashes.size() == GlobalHashes.size()"
, "/build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil/DumpOutputStyle.cpp"
, 1022, __extension__ __PRETTY_FUNCTION__))
;
1023
1024 P.formatLine("Local / Global hashes:");
1025 TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
1026 for (const auto &H : zip(LocalHashes, GlobalHashes)) {
1027 AutoIndent Indent2(P);
1028 LocallyHashedType &L = std::get<0>(H);
1029 GloballyHashedType &G = std::get<1>(H);
1030
1031 P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G);
1032
1033 ++TI;
1034 }
1035 P.NewLine();
1036 }
1037 }
1038
1039 return Error::success();
1040}
1041
1042Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
1043 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI)(static_cast <bool> (StreamIdx == StreamTPI || StreamIdx
== StreamIPI) ? void (0) : __assert_fail ("StreamIdx == StreamTPI || StreamIdx == StreamIPI"
, "/build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil/DumpOutputStyle.cpp"
, 1043, __extension__ __PRETTY_FUNCTION__))
;
1044
1045 if (StreamIdx == StreamTPI) {
1046 printHeader(P, "Types (TPI Stream)");
1047 } else if (StreamIdx == StreamIPI) {
1048 printHeader(P, "Types (IPI Stream)");
1049 }
1050
1051 AutoIndent Indent(P);
1052 assert(!File.isObj())(static_cast <bool> (!File.isObj()) ? void (0) : __assert_fail
("!File.isObj()", "/build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil/DumpOutputStyle.cpp"
, 1052, __extension__ __PRETTY_FUNCTION__))
;
1053
1054 bool Present = false;
1055 bool DumpTypes = false;
1056 bool DumpBytes = false;
1057 bool DumpExtras = false;
1058 std::vector<uint32_t> Indices;
1059 if (StreamIdx == StreamTPI) {
1060 Present = getPdb().hasPDBTpiStream();
1061 DumpTypes = opts::dump::DumpTypes;
1062 DumpBytes = opts::dump::DumpTypeData;
1063 DumpExtras = opts::dump::DumpTypeExtras;
1064 Indices.assign(opts::dump::DumpTypeIndex.begin(),
1065 opts::dump::DumpTypeIndex.end());
1066 } else if (StreamIdx == StreamIPI) {
1067 Present = getPdb().hasPDBIpiStream();
1068 DumpTypes = opts::dump::DumpIds;
1069 DumpBytes = opts::dump::DumpIdData;
1070 DumpExtras = opts::dump::DumpIdExtras;
1071 Indices.assign(opts::dump::DumpIdIndex.begin(),
1072 opts::dump::DumpIdIndex.end());
1073 }
1074
1075 if (!Present) {
1076 P.formatLine("Stream not present");
1077 return Error::success();
1078 }
1079
1080 ExitOnError Err("Unexpected error processing types: ");
1081
1082 auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream()
1083 : getPdb().getPDBIpiStream());
1084
1085 auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
1086
1087 if (DumpTypes || !Indices.empty()) {
1088 if (Indices.empty())
1089 dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
1090 Stream.getNumHashBuckets(), Stream.getHashValues(),
1091 DumpBytes, DumpExtras);
1092 else {
1093 std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
1094 dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
1095 opts::dump::DumpTypeDependents);
1096 }
1097 }
1098
1099 if (DumpExtras) {
1100 P.NewLine();
1101 auto IndexOffsets = Stream.getTypeIndexOffsets();
1102 P.formatLine("Type Index Offsets:");
1103 for (const auto &IO : IndexOffsets) {
1104 AutoIndent Indent2(P);
1105 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
1106 }
1107
1108 P.NewLine();
1109 P.formatLine("Hash Adjusters:");
1110 auto &Adjusters = Stream.getHashAdjusters();
1111 auto &Strings = Err(getPdb().getStringTable());
1112 for (const auto &A : Adjusters) {
1113 AutoIndent Indent2(P);
1114 auto ExpectedStr = Strings.getStringForID(A.first);
1115 TypeIndex TI(A.second);
1116 if (ExpectedStr)
1117 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
1118 else {
1119 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
1120 consumeError(ExpectedStr.takeError());
1121 }
1122 }
1123 }
1124 return Error::success();
1125}
1126
1127Error DumpOutputStyle::dumpModuleSymsForObj() {
1128 printHeader(P, "Symbols");
1129
1130 AutoIndent Indent(P);
1131
1132 ExitOnError Err("Unexpected error processing symbols: ");
1133
1134 auto &Types = File.types();
1135
1136 SymbolVisitorCallbackPipeline Pipeline;
1137 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile);
1138 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types);
1139
1140 Pipeline.addCallbackToPipeline(Deserializer);
1141 Pipeline.addCallbackToPipeline(Dumper);
1142 CVSymbolVisitor Visitor(Pipeline);
1143
1144 std::unique_ptr<llvm::Error> SymbolError;
1145
1146 iterateModuleSubsections<DebugSymbolsSubsectionRef>(
1147 File, PrintScope{P, 2},
1148 [&](uint32_t Modi, const SymbolGroup &Strings,
1149 DebugSymbolsSubsectionRef &Symbols) {
1150 Dumper.setSymbolGroup(&Strings);
1151 for (auto Symbol : Symbols) {
1152 if (auto EC = Visitor.visitSymbolRecord(Symbol)) {
1153 SymbolError = llvm::make_unique<Error>(std::move(EC));
1154 return;
1155 }
1156 }
1157 });
1158
1159 if (SymbolError)
1160 return std::move(*SymbolError);
1161
1162 return Error::success();
1163}
1164
1165Error DumpOutputStyle::dumpModuleSymsForPdb() {
1166 printHeader(P, "Symbols");
1167
1168 AutoIndent Indent(P);
1169 if (!getPdb().hasPDBDbiStream()) {
1170 P.formatLine("DBI Stream not present");
1171 return Error::success();
1172 }
1173
1174 ExitOnError Err("Unexpected error processing symbols: ");
1175
1176 auto &Ids = File.ids();
1177 auto &Types = File.types();
1178
1179 iterateSymbolGroups(
1180 File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) {
1181 auto ExpectedModS = getModuleDebugStream(File.pdb(), I);
1182 if (!ExpectedModS) {
1183 P.formatLine("Error loading module stream {0}. {1}", I,
1184 toString(ExpectedModS.takeError()));
1185 return;
1186 }
1187
1188 ModuleDebugStreamRef &ModS = *ExpectedModS;
1189
1190 SymbolVisitorCallbackPipeline Pipeline;
1191 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
1192 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Strings,
1193 Ids, Types);
1194
1195 Pipeline.addCallbackToPipeline(Deserializer);
1196 Pipeline.addCallbackToPipeline(Dumper);
1197 CVSymbolVisitor Visitor(Pipeline);
1198 auto SS = ModS.getSymbolsSubstream();
1199 if (auto EC =
1200 Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
1201 P.formatLine("Error while processing symbol records. {0}",
1202 toString(std::move(EC)));
1203 return;
1204 }
1205 });
1206 return Error::success();
1207}
1208
1209Error DumpOutputStyle::dumpGlobals() {
1210 printHeader(P, "Global Symbols");
1211 AutoIndent Indent(P);
1212
1213 if (File.isObj()) {
1214 P.formatLine("Dumping Globals is not supported for object files");
1215 return Error::success();
1216 }
1217
1218 if (!getPdb().hasPDBGlobalsStream()) {
1219 P.formatLine("Globals stream not present");
1220 return Error::success();
1221 }
1222 ExitOnError Err("Error dumping globals stream: ");
1223 auto &Globals = Err(getPdb().getPDBGlobalsStream());
1224
1225 const GSIHashTable &Table = Globals.getGlobalsTable();
1226 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
1227 return Error::success();
1228}
1229
1230Error DumpOutputStyle::dumpPublics() {
1231 printHeader(P, "Public Symbols");
1232 AutoIndent Indent(P);
1233
1234 if (File.isObj()) {
1235 P.formatLine("Dumping Globals is not supported for object files");
1236 return Error::success();
1237 }
1238
1239 if (!getPdb().hasPDBPublicsStream()) {
1240 P.formatLine("Publics stream not present");
1241 return Error::success();
1242 }
1243 ExitOnError Err("Error dumping publics stream: ");
1244 auto &Publics = Err(getPdb().getPDBPublicsStream());
1245
1246 const GSIHashTable &PublicsTable = Publics.getPublicsTable();
1247 if (opts::dump::DumpPublicExtras) {
1248 P.printLine("Publics Header");
1249 AutoIndent Indent(P);
1250 P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
1251 formatSegmentOffset(Publics.getThunkTableSection(),
1252 Publics.getThunkTableOffset()));
1253 }
1254 Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
1255
1256 // Skip the rest if we aren't dumping extras.
1257 if (!opts::dump::DumpPublicExtras)
1258 return Error::success();
1259
1260 P.formatLine("Address Map");
1261 {
1262 // These are offsets into the publics stream sorted by secidx:secrel.
1263 AutoIndent Indent2(P);
1264 for (uint32_t Addr : Publics.getAddressMap())
1265 P.formatLine("off = {0}", Addr);
1266 }
1267
1268 // The thunk map is optional debug info used for ILT thunks.
1269 if (!Publics.getThunkMap().empty()) {
1270 P.formatLine("Thunk Map");
1271 AutoIndent Indent2(P);
1272 for (uint32_t Addr : Publics.getThunkMap())
1273 P.formatLine("{0:x8}", Addr);
1274 }
1275
1276 // The section offsets table appears to be empty when incremental linking
1277 // isn't in use.
1278 if (!Publics.getSectionOffsets().empty()) {
1279 P.formatLine("Section Offsets");
1280 AutoIndent Indent2(P);
1281 for (const SectionOffset &SO : Publics.getSectionOffsets())
1282 P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
1283 }
1284
1285 return Error::success();
1286}
1287
1288Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
1289 bool HashExtras) {
1290 auto ExpectedSyms = getPdb().getPDBSymbolStream();
1291 if (!ExpectedSyms)
1292 return ExpectedSyms.takeError();
1293 auto &Types = File.types();
1294 auto &Ids = File.ids();
1295
1296 if (HashExtras) {
1297 P.printLine("GSI Header");
1298 AutoIndent Indent(P);
1299 P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
1300 Table.getVerSignature(), Table.getVerHeader(),
1301 Table.getHashRecordSize(), Table.getNumBuckets());
1302 }
1303
1304 {
1305 P.printLine("Records");
1306 SymbolVisitorCallbackPipeline Pipeline;
1307 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
1308 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
1309
1310 Pipeline.addCallbackToPipeline(Deserializer);
1311 Pipeline.addCallbackToPipeline(Dumper);
1312 CVSymbolVisitor Visitor(Pipeline);
1313
1314 BinaryStreamRef SymStream =
1315 ExpectedSyms->getSymbolArray().getUnderlyingStream();
1316 for (uint32_t PubSymOff : Table) {
1317 Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
1318 if (!Sym)
1319 return Sym.takeError();
1320 if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
1321 return E;
1322 }
1323 }
1324
1325 // Return early if we aren't dumping public hash table and address map info.
1326 if (!HashExtras)
1327 return Error::success();
1328
1329 P.formatLine("Hash Entries");
1330 {
1331 AutoIndent Indent2(P);
1332 for (const PSHashRecord &HR : Table.HashRecords)
1333 P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
1334 uint32_t(HR.CRef));
1335 }
1336
1337 // FIXME: Dump the bitmap.
1338
1339 P.formatLine("Hash Buckets");
1340 {
1341 AutoIndent Indent2(P);
1342 for (uint32_t Hash : Table.HashBuckets)
1343 P.formatLine("{0:x8}", Hash);
1344 }
1345
1346 return Error::success();
1347}
1348
1349static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
1350 OMFSegDescFlags Flags) {
1351 std::vector<std::string> Opts;
1352 if (Flags == OMFSegDescFlags::None)
1353 return "none";
1354
1355 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read")if (OMFSegDescFlags::Read == (Flags & OMFSegDescFlags::Read
)) Opts.push_back("read");
;
1356 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write")if (OMFSegDescFlags::Write == (Flags & OMFSegDescFlags::Write
)) Opts.push_back("write");
;
1357 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute")if (OMFSegDescFlags::Execute == (Flags & OMFSegDescFlags::
Execute)) Opts.push_back("execute");
;
1358 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr")if (OMFSegDescFlags::AddressIs32Bit == (Flags & OMFSegDescFlags
::AddressIs32Bit)) Opts.push_back("32 bit addr");
;
1359 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector")if (OMFSegDescFlags::IsSelector == (Flags & OMFSegDescFlags
::IsSelector)) Opts.push_back("selector");
;
1360 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr")if (OMFSegDescFlags::IsAbsoluteAddress == (Flags & OMFSegDescFlags
::IsAbsoluteAddress)) Opts.push_back("absolute addr");
;
1361 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group")if (OMFSegDescFlags::IsGroup == (Flags & OMFSegDescFlags::
IsGroup)) Opts.push_back("group");
;
1362 return typesetItemList(Opts, IndentLevel, 4, " | ");
1363}
1364
1365Error DumpOutputStyle::dumpSectionHeaders() {
1366 dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
1367 dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
1368 return Error::success();
1369}
1370
1371static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
1372 ArrayRef<llvm::object::coff_section>>>
1373loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
1374 if (!File.hasPDBDbiStream())
1375 return make_error<StringError>(
1376 "Section headers require a DBI Stream, which could not be loaded",
1377 inconvertibleErrorCode());
1378
1379 auto &Dbi = cantFail(File.getPDBDbiStream());
1380 uint32_t SI = Dbi.getDebugStreamIndex(Type);
1381
1382 if (SI == kInvalidStreamIndex)
1383 return make_error<StringError>(
1384 "PDB does not contain the requested image section header type",
1385 inconvertibleErrorCode());
1386
1387 auto Stream = File.createIndexedStream(SI);
1388 if (!Stream)
1389 return make_error<StringError>("Could not load the required stream data",
1390 inconvertibleErrorCode());
1391
1392 ArrayRef<object::coff_section> Headers;
1393 if (Stream->getLength() % sizeof(object::coff_section) != 0)
1394 return make_error<StringError>(
1395 "Section header array size is not a multiple of section header size",
1396 inconvertibleErrorCode());
1397
1398 uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
1399 BinaryStreamReader Reader(*Stream);
1400 cantFail(Reader.readArray(Headers, NumHeaders));
1401 return std::make_pair(std::move(Stream), Headers);
1402}
1403
1404void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
1405 printHeader(P, Label);
1406
1407 AutoIndent Indent(P);
1408 if (File.isObj()) {
1409 P.formatLine("Dumping Section Headers is not supported for object files");
1410 return;
1411 }
1412
1413 ExitOnError Err("Error dumping section headers: ");
1414 std::unique_ptr<MappedBlockStream> Stream;
1415 ArrayRef<object::coff_section> Headers;
1416 auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type);
1417 if (!ExpectedHeaders) {
1418 P.printLine(toString(ExpectedHeaders.takeError()));
1419 return;
1420 }
1421 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
1422
1423 uint32_t I = 1;
1424 for (const auto &Header : Headers) {
1425 P.NewLine();
1426 P.formatLine("SECTION HEADER #{0}", I);
1427 P.formatLine("{0,8} name", Header.Name);
1428 P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
1429 P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
1430 P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
1431 P.formatLine("{0,8:X-} file pointer to raw data",
1432 uint32_t(Header.PointerToRawData));
1433 P.formatLine("{0,8:X-} file pointer to relocation table",
1434 uint32_t(Header.PointerToRelocations));
1435 P.formatLine("{0,8:X-} file pointer to line numbers",
1436 uint32_t(Header.PointerToLinenumbers));
1437 P.formatLine("{0,8:X-} number of relocations",
1438 uint32_t(Header.NumberOfRelocations));
1439 P.formatLine("{0,8:X-} number of line numbers",
1440 uint32_t(Header.NumberOfLinenumbers));
1441 P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
1442 AutoIndent IndentMore(P, 9);
1443 P.formatLine("{0}", formatSectionCharacteristics(
1444 P.getIndentLevel(), Header.Characteristics, 1, ""));
1445 ++I;
1446 }
1447 return;
1448}
1449
1450std::vector<std::string> getSectionNames(PDBFile &File) {
1451 auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
1452 if (!ExpectedHeaders)
1453 return {};
1454
1455 std::unique_ptr<MappedBlockStream> Stream;
1456 ArrayRef<object::coff_section> Headers;
1457 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
1458 std::vector<std::string> Names;
1459 for (const auto &H : Headers)
1460 Names.push_back(H.Name);
1461 return Names;
1462}
1463
1464Error DumpOutputStyle::dumpSectionContribs() {
1465 printHeader(P, "Section Contributions");
1466
1467 AutoIndent Indent(P);
1468 if (File.isObj()) {
1469 P.formatLine(
1470 "Dumping section contributions is not supported for object files");
1471 return Error::success();
1472 }
1473
1474 ExitOnError Err("Error dumping section contributions: ");
1475 if (!getPdb().hasPDBDbiStream()) {
1476 P.formatLine(
1477 "Section contribs require a DBI Stream, which could not be loaded");
1478 return Error::success();
1479 }
1480
1481 auto &Dbi = Err(getPdb().getPDBDbiStream());
1482
1483 class Visitor : public ISectionContribVisitor {
1484 public:
1485 Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) {
1486 auto Max = std::max_element(
1487 Names.begin(), Names.end(),
1488 [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); });
1489 MaxNameLen = (Max == Names.end() ? 0 : Max->size());
1490 }
1491 void visit(const SectionContrib &SC) override {
1492 assert(SC.ISect > 0)(static_cast <bool> (SC.ISect > 0) ? void (0) : __assert_fail
("SC.ISect > 0", "/build/llvm-toolchain-snapshot-7~svn326246/tools/llvm-pdbutil/DumpOutputStyle.cpp"
, 1492, __extension__ __PRETTY_FUNCTION__))
;
1493 std::string NameInsert;
1494 if (SC.ISect < Names.size()) {
1495 StringRef SectionName = Names[SC.ISect - 1];
1496 NameInsert = formatv("[{0}]", SectionName).str();
1497 } else
1498 NameInsert = "[???]";
1499 P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1500 "crc = {4}",
1501 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
1502 fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
1503 fmt_align(NameInsert, AlignStyle::Left, MaxNameLen + 2));
1504 AutoIndent Indent(P, MaxNameLen + 2);
1505 P.formatLine(" {0}",
1506 formatSectionCharacteristics(P.getIndentLevel() + 6,
1507 SC.Characteristics, 3, " | "));
1508 }
1509 void visit(const SectionContrib2 &SC) override {
1510 P.formatLine(
1511 "SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1512 "crc = {4}, coff section = {5}",
1513 formatSegmentOffset(SC.Base.ISect, SC.Base.Off), fmtle(SC.Base.Size),
1514 fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1515 fmtle(SC.ISectCoff));
1516 P.formatLine(" {0}", formatSectionCharacteristics(
1517 P.getIndentLevel() + 6,
1518 SC.Base.Characteristics, 3, " | "));
1519 }
1520
1521 private:
1522 LinePrinter &P;
1523 uint32_t MaxNameLen;
1524 ArrayRef<std::string> Names;
1525 };
1526
1527 std::vector<std::string> Names = getSectionNames(getPdb());
1528 Visitor V(P, makeArrayRef(Names));
1529 Dbi.visitSectionContributions(V);
1530 return Error::success();
1531}
1532
1533Error DumpOutputStyle::dumpSectionMap() {
1534 printHeader(P, "Section Map");
1535 AutoIndent Indent(P);
1536
1537 if (File.isObj()) {
1538 P.formatLine("Dumping section map is not supported for object files");
1539 return Error::success();
1540 }
1541
1542 ExitOnError Err("Error dumping section map: ");
1543
1544 if (!getPdb().hasPDBDbiStream()) {
1545 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1546 "not be loaded");
1547 return Error::success();
1548 }
1549
1550 auto &Dbi = Err(getPdb().getPDBDbiStream());
1551
1552 uint32_t I = 0;
1553 for (auto &M : Dbi.getSectionMap()) {
1554 P.formatLine(
1555 "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
1556 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1557 P.formatLine(" class = {0}, offset = {1}, size = {2}",
1558 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1559 P.formatLine(" flags = {0}",
1560 formatSegMapDescriptorFlag(
1561 P.getIndentLevel() + 13,
1562 static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
1563 ++I;
1564 }
1565 return Error::success();
1566}

/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/BinaryStreamReader.h

1//===- BinaryStreamReader.h - Reads objects from a binary stream *- 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#ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
11#define LLVM_SUPPORT_BINARYSTREAMREADER_H
12
13#include "llvm/ADT/ArrayRef.h"
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/Support/BinaryStreamArray.h"
16#include "llvm/Support/BinaryStreamRef.h"
17#include "llvm/Support/ConvertUTF.h"
18#include "llvm/Support/Endian.h"
19#include "llvm/Support/Error.h"
20#include "llvm/Support/type_traits.h"
21
22#include <string>
23#include <type_traits>
24
25namespace llvm {
26
27/// \brief Provides read only access to a subclass of `BinaryStream`. Provides
28/// bounds checking and helpers for writing certain common data types such as
29/// null-terminated strings, integers in various flavors of endianness, etc.
30/// Can be subclassed to provide reading of custom datatypes, although no
31/// are overridable.
32class BinaryStreamReader {
33public:
34 BinaryStreamReader() = default;
35 explicit BinaryStreamReader(BinaryStreamRef Ref);
36 explicit BinaryStreamReader(BinaryStream &Stream);
37 explicit BinaryStreamReader(ArrayRef<uint8_t> Data,
38 llvm::support::endianness Endian);
39 explicit BinaryStreamReader(StringRef Data, llvm::support::endianness Endian);
40
41 BinaryStreamReader(const BinaryStreamReader &Other)
42 : Stream(Other.Stream), Offset(Other.Offset) {}
43
44 BinaryStreamReader &operator=(const BinaryStreamReader &Other) {
45 Stream = Other.Stream;
46 Offset = Other.Offset;
47 return *this;
48 }
49
50 virtual ~BinaryStreamReader() {}
51
52 /// Read as much as possible from the underlying string at the current offset
53 /// without invoking a copy, and set \p Buffer to the resulting data slice.
54 /// Updates the stream's offset to point after the newly read data.
55 ///
56 /// \returns a success error code if the data was successfully read, otherwise
57 /// returns an appropriate error code.
58 Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
59
60 /// Read \p Size bytes from the underlying stream at the current offset and
61 /// and set \p Buffer to the resulting data slice. Whether a copy occurs
62 /// depends on the implementation of the underlying stream. Updates the
63 /// stream's offset to point after the newly read data.
64 ///
65 /// \returns a success error code if the data was successfully read, otherwise
66 /// returns an appropriate error code.
67 Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
68
69 /// Read an integer of the specified endianness into \p Dest and update the
70 /// stream's offset. The data is always copied from the stream's underlying
71 /// buffer into \p Dest. Updates the stream's offset to point after the newly
72 /// read data.
73 ///
74 /// \returns a success error code if the data was successfully read, otherwise
75 /// returns an appropriate error code.
76 template <typename T> Error readInteger(T &Dest) {
77 static_assert(std::is_integral<T>::value,
78 "Cannot call readInteger with non-integral value!");
79
80 ArrayRef<uint8_t> Bytes;
81 if (auto EC = readBytes(Bytes, sizeof(T)))
5
Calling move constructor for 'Error'
29
Returning from move constructor for 'Error'
30
Calling 'Error::operator bool'
39
Returning from 'Error::operator bool'
40
Taking false branch
71
Calling move constructor for 'Error'
95
Returning from move constructor for 'Error'
96
Calling 'Error::operator bool'
105
Returning from 'Error::operator bool'
106
Taking true branch
82 return EC;
41
Calling '~Error'
48
Returning from '~Error'
107
Calling '~Error'
114
Returning from '~Error'
83
84 Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
51
Calling 'read'
55
Returning from 'read'
85 Bytes.data(), Stream.getEndian());
49
Calling 'BinaryStreamRefBase::getEndian'
50
Returning from 'BinaryStreamRefBase::getEndian'
86 return Error::success();
56
Calling 'Error::success'
57
Returning from 'Error::success'
87 }
88
89 /// Similar to readInteger.
90 template <typename T> Error readEnum(T &Dest) {
91 static_assert(std::is_enum<T>::value,
92 "Cannot call readEnum with non-enum value!");
93 typename std::underlying_type<T>::type N;
94 if (auto EC = readInteger(N))
95 return EC;
96 Dest = static_cast<T>(N);
97 return Error::success();
98 }
99
100 /// Read a null terminated string from \p Dest. Whether a copy occurs depends
101 /// on the implementation of the underlying stream. Updates the stream's
102 /// offset to point after the newly read data.
103 ///
104 /// \returns a success error code if the data was successfully read, otherwise
105 /// returns an appropriate error code.
106 Error readCString(StringRef &Dest);
107
108 /// Similar to readCString, however read a null-terminated UTF16 string
109 /// instead.
110 ///
111 /// \returns a success error code if the data was successfully read, otherwise
112 /// returns an appropriate error code.
113 Error readWideString(ArrayRef<UTF16> &Dest);
114
115 /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
116 /// on the implementation of the underlying stream. Updates the stream's
117 /// offset to point after the newly read data.
118 ///
119 /// \returns a success error code if the data was successfully read, otherwise
120 /// returns an appropriate error code.
121 Error readFixedString(StringRef &Dest, uint32_t Length);
122
123 /// Read the entire remainder of the underlying stream into \p Ref. This is
124 /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the
125 /// stream's offset to point to the end of the stream. Never causes a copy.
126 ///
127 /// \returns a success error code if the data was successfully read, otherwise
128 /// returns an appropriate error code.
129 Error readStreamRef(BinaryStreamRef &Ref);
130
131 /// Read \p Length bytes from the underlying stream into \p Ref. This is
132 /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
133 /// Updates the stream's offset to point after the newly read object. Never
134 /// causes a copy.
135 ///
136 /// \returns a success error code if the data was successfully read, otherwise
137 /// returns an appropriate error code.
138 Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
139
140 /// Read \p Length bytes from the underlying stream into \p Stream. This is
141 /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
142 /// Updates the stream's offset to point after the newly read object. Never
143 /// causes a copy.
144 ///
145 /// \returns a success error code if the data was successfully read, otherwise
146 /// returns an appropriate error code.
147 Error readSubstream(BinarySubstreamRef &Stream, uint32_t Size);
148
149 /// Get a pointer to an object of type T from the underlying stream, as if by
150 /// memcpy, and store the result into \p Dest. It is up to the caller to
151 /// ensure that objects of type T can be safely treated in this manner.
152 /// Updates the stream's offset to point after the newly read object. Whether
153 /// a copy occurs depends upon the implementation of the underlying
154 /// stream.
155 ///
156 /// \returns a success error code if the data was successfully read, otherwise
157 /// returns an appropriate error code.
158 template <typename T> Error readObject(const T *&Dest) {
159 ArrayRef<uint8_t> Buffer;
160 if (auto EC = readBytes(Buffer, sizeof(T)))
161 return EC;
162 Dest = reinterpret_cast<const T *>(Buffer.data());
163 return Error::success();
164 }
165
166 /// Get a reference to a \p NumElements element array of objects of type T
167 /// from the underlying stream as if by memcpy, and store the resulting array
168 /// slice into \p array. It is up to the caller to ensure that objects of
169 /// type T can be safely treated in this manner. Updates the stream's offset
170 /// to point after the newly read object. Whether a copy occurs depends upon
171 /// the implementation of the underlying stream.
172 ///
173 /// \returns a success error code if the data was successfully read, otherwise
174 /// returns an appropriate error code.
175 template <typename T>
176 Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
177 ArrayRef<uint8_t> Bytes;
178 if (NumElements == 0) {
179 Array = ArrayRef<T>();
180 return Error::success();
181 }
182
183 if (NumElements > UINT32_MAX(4294967295U) / sizeof(T))
184 return make_error<BinaryStreamError>(
185 stream_error_code::invalid_array_size);
186
187 if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
188 return EC;
189
190 assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&(static_cast <bool> (alignmentAdjustment(Bytes.data(), alignof
(T)) == 0 && "Reading at invalid alignment!") ? void (
0) : __assert_fail ("alignmentAdjustment(Bytes.data(), alignof(T)) == 0 && \"Reading at invalid alignment!\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/BinaryStreamReader.h"
, 191, __extension__ __PRETTY_FUNCTION__))
191 "Reading at invalid alignment!")(static_cast <bool> (alignmentAdjustment(Bytes.data(), alignof
(T)) == 0 && "Reading at invalid alignment!") ? void (
0) : __assert_fail ("alignmentAdjustment(Bytes.data(), alignof(T)) == 0 && \"Reading at invalid alignment!\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/BinaryStreamReader.h"
, 191, __extension__ __PRETTY_FUNCTION__))
;
192
193 Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
194 return Error::success();
195 }
196
197 /// Read a VarStreamArray of size \p Size bytes and store the result into
198 /// \p Array. Updates the stream's offset to point after the newly read
199 /// array. Never causes a copy (although iterating the elements of the
200 /// VarStreamArray may, depending upon the implementation of the underlying
201 /// stream).
202 ///
203 /// \returns a success error code if the data was successfully read, otherwise
204 /// returns an appropriate error code.
205 template <typename T, typename U>
206 Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
207 BinaryStreamRef S;
208 if (auto EC = readStreamRef(S, Size))
209 return EC;
210 Array.setUnderlyingStream(S);
211 return Error::success();
212 }
213
214 /// Read a FixedStreamArray of \p NumItems elements and store the result into
215 /// \p Array. Updates the stream's offset to point after the newly read
216 /// array. Never causes a copy (although iterating the elements of the
217 /// FixedStreamArray may, depending upon the implementation of the underlying
218 /// stream).
219 ///
220 /// \returns a success error code if the data was successfully read, otherwise
221 /// returns an appropriate error code.
222 template <typename T>
223 Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
224 if (NumItems == 0) {
225 Array = FixedStreamArray<T>();
226 return Error::success();
227 }
228
229 if (NumItems > UINT32_MAX(4294967295U) / sizeof(T))
230 return make_error<BinaryStreamError>(
231 stream_error_code::invalid_array_size);
232
233 BinaryStreamRef View;
234 if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
235 return EC;
236
237 Array = FixedStreamArray<T>(View);
238 return Error::success();
239 }
240
241 bool empty() const { return bytesRemaining() == 0; }
242 void setOffset(uint32_t Off) { Offset = Off; }
243 uint32_t getOffset() const { return Offset; }
244 uint32_t getLength() const { return Stream.getLength(); }
245 uint32_t bytesRemaining() const { return getLength() - getOffset(); }
246
247 /// Advance the stream's offset by \p Amount bytes.
248 ///
249 /// \returns a success error code if at least \p Amount bytes remain in the
250 /// stream, otherwise returns an appropriate error code.
251 Error skip(uint32_t Amount);
252
253 /// Examine the next byte of the underlying stream without advancing the
254 /// stream's offset. If the stream is empty the behavior is undefined.
255 ///
256 /// \returns the next byte in the stream.
257 uint8_t peek() const;
258
259 Error padToAlignment(uint32_t Align);
260
261 std::pair<BinaryStreamReader, BinaryStreamReader>
262 split(uint32_t Offset) const;
263
264private:
265 BinaryStreamRef Stream;
266 uint32_t Offset = 0;
267};
268} // namespace llvm
269
270#endif // LLVM_SUPPORT_BINARYSTREAMREADER_H

/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h

1//===- llvm/Support/Error.h - Recoverable error handling --------*- 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// This file defines an API used to report recoverable errors.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_SUPPORT_ERROR_H
15#define LLVM_SUPPORT_ERROR_H
16
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/Config/abi-breaking.h"
22#include "llvm/Support/AlignOf.h"
23#include "llvm/Support/Compiler.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/ErrorHandling.h"
26#include "llvm/Support/ErrorOr.h"
27#include "llvm/Support/raw_ostream.h"
28#include <algorithm>
29#include <cassert>
30#include <cstdint>
31#include <cstdlib>
32#include <functional>
33#include <memory>
34#include <new>
35#include <string>
36#include <system_error>
37#include <type_traits>
38#include <utility>
39#include <vector>
40
41namespace llvm {
42
43class ErrorSuccess;
44
45/// Base class for error info classes. Do not extend this directly: Extend
46/// the ErrorInfo template subclass instead.
47class ErrorInfoBase {
48public:
49 virtual ~ErrorInfoBase() = default;
50
51 /// Print an error message to an output stream.
52 virtual void log(raw_ostream &OS) const = 0;
53
54 /// Return the error message as a string.
55 virtual std::string message() const {
56 std::string Msg;
57 raw_string_ostream OS(Msg);
58 log(OS);
59 return OS.str();
60 }
61
62 /// Convert this error to a std::error_code.
63 ///
64 /// This is a temporary crutch to enable interaction with code still
65 /// using std::error_code. It will be removed in the future.
66 virtual std::error_code convertToErrorCode() const = 0;
67
68 // Returns the class ID for this type.
69 static const void *classID() { return &ID; }
70
71 // Returns the class ID for the dynamic type of this ErrorInfoBase instance.
72 virtual const void *dynamicClassID() const = 0;
73
74 // Check whether this instance is a subclass of the class identified by
75 // ClassID.
76 virtual bool isA(const void *const ClassID) const {
77 return ClassID == classID();
78 }
79
80 // Check whether this instance is a subclass of ErrorInfoT.
81 template <typename ErrorInfoT> bool isA() const {
82 return isA(ErrorInfoT::classID());
83 }
84
85private:
86 virtual void anchor();
87
88 static char ID;
89};
90
91/// Lightweight error class with error context and mandatory checking.
92///
93/// Instances of this class wrap a ErrorInfoBase pointer. Failure states
94/// are represented by setting the pointer to a ErrorInfoBase subclass
95/// instance containing information describing the failure. Success is
96/// represented by a null pointer value.
97///
98/// Instances of Error also contains a 'Checked' flag, which must be set
99/// before the destructor is called, otherwise the destructor will trigger a
100/// runtime error. This enforces at runtime the requirement that all Error
101/// instances be checked or returned to the caller.
102///
103/// There are two ways to set the checked flag, depending on what state the
104/// Error instance is in. For Error instances indicating success, it
105/// is sufficient to invoke the boolean conversion operator. E.g.:
106///
107/// @code{.cpp}
108/// Error foo(<...>);
109///
110/// if (auto E = foo(<...>))
111/// return E; // <- Return E if it is in the error state.
112/// // We have verified that E was in the success state. It can now be safely
113/// // destroyed.
114/// @endcode
115///
116/// A success value *can not* be dropped. For example, just calling 'foo(<...>)'
117/// without testing the return value will raise a runtime error, even if foo
118/// returns success.
119///
120/// For Error instances representing failure, you must use either the
121/// handleErrors or handleAllErrors function with a typed handler. E.g.:
122///
123/// @code{.cpp}
124/// class MyErrorInfo : public ErrorInfo<MyErrorInfo> {
125/// // Custom error info.
126/// };
127///
128/// Error foo(<...>) { return make_error<MyErrorInfo>(...); }
129///
130/// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo.
131/// auto NewE =
132/// handleErrors(E,
133/// [](const MyErrorInfo &M) {
134/// // Deal with the error.
135/// },
136/// [](std::unique_ptr<OtherError> M) -> Error {
137/// if (canHandle(*M)) {
138/// // handle error.
139/// return Error::success();
140/// }
141/// // Couldn't handle this error instance. Pass it up the stack.
142/// return Error(std::move(M));
143/// );
144/// // Note - we must check or return NewE in case any of the handlers
145/// // returned a new error.
146/// @endcode
147///
148/// The handleAllErrors function is identical to handleErrors, except
149/// that it has a void return type, and requires all errors to be handled and
150/// no new errors be returned. It prevents errors (assuming they can all be
151/// handled) from having to be bubbled all the way to the top-level.
152///
153/// *All* Error instances must be checked before destruction, even if
154/// they're moved-assigned or constructed from Success values that have already
155/// been checked. This enforces checking through all levels of the call stack.
156class LLVM_NODISCARD[[clang::warn_unused_result]] Error {
157 // ErrorList needs to be able to yank ErrorInfoBase pointers out of this
158 // class to add to the error list.
159 friend class ErrorList;
160
161 // handleErrors needs to be able to set the Checked flag.
162 template <typename... HandlerTs>
163 friend Error handleErrors(Error E, HandlerTs &&... Handlers);
164
165 // Expected<T> needs to be able to steal the payload when constructed from an
166 // error.
167 template <typename T> friend class Expected;
168
169protected:
170 /// Create a success value. Prefer using 'Error::success()' for readability
171 Error() {
172 setPtr(nullptr);
173 setChecked(false);
174 }
175
176public:
177 /// Create a success value.
178 static ErrorSuccess success();
179
180 // Errors are not copy-constructable.
181 Error(const Error &Other) = delete;
182
183 /// Move-construct an error value. The newly constructed error is considered
184 /// unchecked, even if the source error had been checked. The original error
185 /// becomes a checked Success value, regardless of its original state.
186 Error(Error &&Other) {
187 setChecked(true);
6
Calling 'Error::setChecked'
8
Returning from 'Error::setChecked'
72
Calling 'Error::setChecked'
74
Returning from 'Error::setChecked'
188 *this = std::move(Other);
9
Calling 'move'
10
Returning from 'move'
11
Calling move assignment operator for 'Error'
28
Returning from move assignment operator for 'Error'
75
Calling 'move'
76
Returning from 'move'
77
Calling move assignment operator for 'Error'
94
Returning from move assignment operator for 'Error'
189 }
190
191 /// Create an error value. Prefer using the 'make_error' function, but
192 /// this constructor can be useful when "re-throwing" errors from handlers.
193 Error(std::unique_ptr<ErrorInfoBase> Payload) {
194 setPtr(Payload.release());
195 setChecked(false);
196 }
197
198 // Errors are not copy-assignable.
199 Error &operator=(const Error &Other) = delete;
200
201 /// Move-assign an error value. The current error must represent success, you
202 /// you cannot overwrite an unhandled error. The current error is then
203 /// considered unchecked. The source error becomes a checked success value,
204 /// regardless of its original state.
205 Error &operator=(Error &&Other) {
206 // Don't allow overwriting of unchecked values.
207 assertIsChecked();
12
Calling 'Error::assertIsChecked'
15
Returning from 'Error::assertIsChecked'
78
Calling 'Error::assertIsChecked'
81
Returning from 'Error::assertIsChecked'
208 setPtr(Other.getPtr());
16
Calling 'Error::getPtr'
17
Returning from 'Error::getPtr'
18
Calling 'Error::setPtr'
19
Returning from 'Error::setPtr'
82
Calling 'Error::getPtr'
83
Returning from 'Error::getPtr'
84
Calling 'Error::setPtr'
85
Returning from 'Error::setPtr'
209
210 // This Error is unchecked, even if the source error was checked.
211 setChecked(false);
20
Calling 'Error::setChecked'
22
Returning from 'Error::setChecked'
86
Calling 'Error::setChecked'
88
Returning from 'Error::setChecked'
212
213 // Null out Other's payload and set its checked bit.
214 Other.setPtr(nullptr);
23
Calling 'Error::setPtr'
24
Returning from 'Error::setPtr'
89
Calling 'Error::setPtr'
90
Returning from 'Error::setPtr'
215 Other.setChecked(true);
25
Calling 'Error::setChecked'
27
Returning from 'Error::setChecked'
91
Calling 'Error::setChecked'
93
Returning from 'Error::setChecked'
216
217 return *this;
218 }
219
220 /// Destroy a Error. Fails with a call to abort() if the error is
221 /// unchecked.
222 ~Error() {
223 assertIsChecked();
42
Calling 'Error::assertIsChecked'
45
Returning from 'Error::assertIsChecked'
108
Calling 'Error::assertIsChecked'
111
Returning from 'Error::assertIsChecked'
224 delete getPtr();
46
Calling 'Error::getPtr'
47
Returning from 'Error::getPtr'
112
Calling 'Error::getPtr'
113
Returning from 'Error::getPtr'
225 }
226
227 /// Bool conversion. Returns true if this Error is in a failure state,
228 /// and false if it is in an accept state. If the error is in a Success state
229 /// it will be considered checked.
230 explicit operator bool() {
231 setChecked(getPtr() == nullptr);
31
Calling 'Error::getPtr'
32
Returning from 'Error::getPtr'
33
Calling 'Error::setChecked'
36
Returning from 'Error::setChecked'
97
Calling 'Error::getPtr'
98
Returning from 'Error::getPtr'
99
Calling 'Error::setChecked'
102
Returning from 'Error::setChecked'
232 return getPtr() != nullptr;
37
Calling 'Error::getPtr'
38
Returning from 'Error::getPtr'
103
Calling 'Error::getPtr'
104
Returning from 'Error::getPtr'
233 }
234
235 /// Check whether one error is a subclass of another.
236 template <typename ErrT> bool isA() const {
237 return getPtr() && getPtr()->isA(ErrT::classID());
238 }
239
240 /// Returns the dynamic class id of this error, or null if this is a success
241 /// value.
242 const void* dynamicClassID() const {
243 if (!getPtr())
244 return nullptr;
245 return getPtr()->dynamicClassID();
246 }
247
248private:
249#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
250 // assertIsChecked() happens very frequently, but under normal circumstances
251 // is supposed to be a no-op. So we want it to be inlined, but having a bunch
252 // of debug prints can cause the function to be too large for inlining. So
253 // it's important that we define this function out of line so that it can't be
254 // inlined.
255 LLVM_ATTRIBUTE_NORETURN__attribute__((noreturn))
256 void fatalUncheckedError() const;
257#endif
258
259 void assertIsChecked() {
260#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
261 if (LLVM_UNLIKELY(!getChecked() || getPtr())__builtin_expect((bool)(!getChecked() || getPtr()), false))
13
Within the expansion of the macro 'LLVM_UNLIKELY':
a
Calling 'Error::getChecked'
b
Returning from 'Error::getChecked'
c
Calling 'Error::getPtr'
d
Returning from 'Error::getPtr'
14
Taking false branch
43
Within the expansion of the macro 'LLVM_UNLIKELY':
a
Calling 'Error::getChecked'
b
Returning from 'Error::getChecked'
c
Calling 'Error::getPtr'
d
Returning from 'Error::getPtr'
44
Taking false branch
79
Within the expansion of the macro 'LLVM_UNLIKELY':
a
Calling 'Error::getChecked'
b
Returning from 'Error::getChecked'
c
Calling 'Error::getPtr'
d
Returning from 'Error::getPtr'
80
Taking false branch
109
Within the expansion of the macro 'LLVM_UNLIKELY':
a
Calling 'Error::getChecked'
b
Returning from 'Error::getChecked'
110
Taking false branch
262 fatalUncheckedError();
263#endif
264 }
265
266 ErrorInfoBase *getPtr() const {
267 return reinterpret_cast<ErrorInfoBase*>(
268 reinterpret_cast<uintptr_t>(Payload) &
269 ~static_cast<uintptr_t>(0x1));
270 }
271
272 void setPtr(ErrorInfoBase *EI) {
273#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
274 Payload = reinterpret_cast<ErrorInfoBase*>(
275 (reinterpret_cast<uintptr_t>(EI) &
276 ~static_cast<uintptr_t>(0x1)) |
277 (reinterpret_cast<uintptr_t>(Payload) & 0x1));
278#else
279 Payload = EI;
280#endif
281 }
282
283 bool getChecked() const {
284#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
285 return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0;
286#else
287 return true;
288#endif
289 }
290
291 void setChecked(bool V) {
292 Payload = reinterpret_cast<ErrorInfoBase*>(
293 (reinterpret_cast<uintptr_t>(Payload) &
294 ~static_cast<uintptr_t>(0x1)) |
295 (V ? 0 : 1));
7
'?' condition is true
21
'?' condition is false
26
'?' condition is true
34
Assuming 'V' is 0
35
'?' condition is false
73
'?' condition is true
87
'?' condition is false
92
'?' condition is true
100
Assuming 'V' is 0
101
'?' condition is false
296 }
297
298 std::unique_ptr<ErrorInfoBase> takePayload() {
299 std::unique_ptr<ErrorInfoBase> Tmp(getPtr());
300 setPtr(nullptr);
301 setChecked(true);
302 return Tmp;
303 }
304
305 ErrorInfoBase *Payload = nullptr;
306};
307
308/// Subclass of Error for the sole purpose of identifying the success path in
309/// the type system. This allows to catch invalid conversion to Expected<T> at
310/// compile time.
311class ErrorSuccess : public Error {};
312
313inline ErrorSuccess Error::success() { return ErrorSuccess(); }
314
315/// Make a Error instance representing failure using the given error info
316/// type.
317template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
318 return Error(llvm::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
319}
320
321/// Base class for user error types. Users should declare their error types
322/// like:
323///
324/// class MyError : public ErrorInfo<MyError> {
325/// ....
326/// };
327///
328/// This class provides an implementation of the ErrorInfoBase::kind
329/// method, which is used by the Error RTTI system.
330template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
331class ErrorInfo : public ParentErrT {
332public:
333 static const void *classID() { return &ThisErrT::ID; }
334
335 const void *dynamicClassID() const override { return &ThisErrT::ID; }
336
337 bool isA(const void *const ClassID) const override {
338 return ClassID == classID() || ParentErrT::isA(ClassID);
339 }
340};
341
342/// Special ErrorInfo subclass representing a list of ErrorInfos.
343/// Instances of this class are constructed by joinError.
344class ErrorList final : public ErrorInfo<ErrorList> {
345 // handleErrors needs to be able to iterate the payload list of an
346 // ErrorList.
347 template <typename... HandlerTs>
348 friend Error handleErrors(Error E, HandlerTs &&... Handlers);
349
350 // joinErrors is implemented in terms of join.
351 friend Error joinErrors(Error, Error);
352
353public:
354 void log(raw_ostream &OS) const override {
355 OS << "Multiple errors:\n";
356 for (auto &ErrPayload : Payloads) {
357 ErrPayload->log(OS);
358 OS << "\n";
359 }
360 }
361
362 std::error_code convertToErrorCode() const override;
363
364 // Used by ErrorInfo::classID.
365 static char ID;
366
367private:
368 ErrorList(std::unique_ptr<ErrorInfoBase> Payload1,
369 std::unique_ptr<ErrorInfoBase> Payload2) {
370 assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() &&(static_cast <bool> (!Payload1->isA<ErrorList>
() && !Payload2->isA<ErrorList>() &&
"ErrorList constructor payloads should be singleton errors")
? void (0) : __assert_fail ("!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && \"ErrorList constructor payloads should be singleton errors\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 371, __extension__ __PRETTY_FUNCTION__))
371 "ErrorList constructor payloads should be singleton errors")(static_cast <bool> (!Payload1->isA<ErrorList>
() && !Payload2->isA<ErrorList>() &&
"ErrorList constructor payloads should be singleton errors")
? void (0) : __assert_fail ("!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && \"ErrorList constructor payloads should be singleton errors\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 371, __extension__ __PRETTY_FUNCTION__))
;
372 Payloads.push_back(std::move(Payload1));
373 Payloads.push_back(std::move(Payload2));
374 }
375
376 static Error join(Error E1, Error E2) {
377 if (!E1)
378 return E2;
379 if (!E2)
380 return E1;
381 if (E1.isA<ErrorList>()) {
382 auto &E1List = static_cast<ErrorList &>(*E1.getPtr());
383 if (E2.isA<ErrorList>()) {
384 auto E2Payload = E2.takePayload();
385 auto &E2List = static_cast<ErrorList &>(*E2Payload);
386 for (auto &Payload : E2List.Payloads)
387 E1List.Payloads.push_back(std::move(Payload));
388 } else
389 E1List.Payloads.push_back(E2.takePayload());
390
391 return E1;
392 }
393 if (E2.isA<ErrorList>()) {
394 auto &E2List = static_cast<ErrorList &>(*E2.getPtr());
395 E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload());
396 return E2;
397 }
398 return Error(std::unique_ptr<ErrorList>(
399 new ErrorList(E1.takePayload(), E2.takePayload())));
400 }
401
402 std::vector<std::unique_ptr<ErrorInfoBase>> Payloads;
403};
404
405/// Concatenate errors. The resulting Error is unchecked, and contains the
406/// ErrorInfo(s), if any, contained in E1, followed by the
407/// ErrorInfo(s), if any, contained in E2.
408inline Error joinErrors(Error E1, Error E2) {
409 return ErrorList::join(std::move(E1), std::move(E2));
410}
411
412/// Tagged union holding either a T or a Error.
413///
414/// This class parallels ErrorOr, but replaces error_code with Error. Since
415/// Error cannot be copied, this class replaces getError() with
416/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
417/// error class type.
418template <class T> class LLVM_NODISCARD[[clang::warn_unused_result]] Expected {
419 template <class T1> friend class ExpectedAsOutParameter;
420 template <class OtherT> friend class Expected;
421
422 static const bool isRef = std::is_reference<T>::value;
423
424 using wrap = ReferenceStorage<typename std::remove_reference<T>::type>;
425
426 using error_type = std::unique_ptr<ErrorInfoBase>;
427
428public:
429 using storage_type = typename std::conditional<isRef, wrap, T>::type;
430 using value_type = T;
431
432private:
433 using reference = typename std::remove_reference<T>::type &;
434 using const_reference = const typename std::remove_reference<T>::type &;
435 using pointer = typename std::remove_reference<T>::type *;
436 using const_pointer = const typename std::remove_reference<T>::type *;
437
438public:
439 /// Create an Expected<T> error value from the given Error.
440 Expected(Error Err)
441 : HasError(true)
442#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
443 // Expected is unchecked upon construction in Debug builds.
444 , Unchecked(true)
445#endif
446 {
447 assert(Err && "Cannot create Expected<T> from Error success value.")(static_cast <bool> (Err && "Cannot create Expected<T> from Error success value."
) ? void (0) : __assert_fail ("Err && \"Cannot create Expected<T> from Error success value.\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 447, __extension__ __PRETTY_FUNCTION__))
;
448 new (getErrorStorage()) error_type(Err.takePayload());
449 }
450
451 /// Forbid to convert from Error::success() implicitly, this avoids having
452 /// Expected<T> foo() { return Error::success(); } which compiles otherwise
453 /// but triggers the assertion above.
454 Expected(ErrorSuccess) = delete;
455
456 /// Create an Expected<T> success value from the given OtherT value, which
457 /// must be convertible to T.
458 template <typename OtherT>
459 Expected(OtherT &&Val,
460 typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
461 * = nullptr)
462 : HasError(false)
463#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
464 // Expected is unchecked upon construction in Debug builds.
465 , Unchecked(true)
466#endif
467 {
468 new (getStorage()) storage_type(std::forward<OtherT>(Val));
469 }
470
471 /// Move construct an Expected<T> value.
472 Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
473
474 /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
475 /// must be convertible to T.
476 template <class OtherT>
477 Expected(Expected<OtherT> &&Other,
478 typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
479 * = nullptr) {
480 moveConstruct(std::move(Other));
481 }
482
483 /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
484 /// isn't convertible to T.
485 template <class OtherT>
486 explicit Expected(
487 Expected<OtherT> &&Other,
488 typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
489 nullptr) {
490 moveConstruct(std::move(Other));
491 }
492
493 /// Move-assign from another Expected<T>.
494 Expected &operator=(Expected &&Other) {
495 moveAssign(std::move(Other));
496 return *this;
497 }
498
499 /// Destroy an Expected<T>.
500 ~Expected() {
501 assertIsChecked();
502 if (!HasError)
503 getStorage()->~storage_type();
504 else
505 getErrorStorage()->~error_type();
506 }
507
508 /// \brief Return false if there is an error.
509 explicit operator bool() {
510#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
511 Unchecked = HasError;
512#endif
513 return !HasError;
514 }
515
516 /// \brief Returns a reference to the stored T value.
517 reference get() {
518 assertIsChecked();
519 return *getStorage();
520 }
521
522 /// \brief Returns a const reference to the stored T value.
523 const_reference get() const {
524 assertIsChecked();
525 return const_cast<Expected<T> *>(this)->get();
526 }
527
528 /// \brief Check that this Expected<T> is an error of type ErrT.
529 template <typename ErrT> bool errorIsA() const {
530 return HasError && (*getErrorStorage())->template isA<ErrT>();
531 }
532
533 /// \brief Take ownership of the stored error.
534 /// After calling this the Expected<T> is in an indeterminate state that can
535 /// only be safely destructed. No further calls (beside the destructor) should
536 /// be made on the Expected<T> vaule.
537 Error takeError() {
538#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
539 Unchecked = false;
540#endif
541 return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
542 }
543
544 /// \brief Returns a pointer to the stored T value.
545 pointer operator->() {
546 assertIsChecked();
547 return toPointer(getStorage());
548 }
549
550 /// \brief Returns a const pointer to the stored T value.
551 const_pointer operator->() const {
552 assertIsChecked();
553 return toPointer(getStorage());
554 }
555
556 /// \brief Returns a reference to the stored T value.
557 reference operator*() {
558 assertIsChecked();
559 return *getStorage();
560 }
561
562 /// \brief Returns a const reference to the stored T value.
563 const_reference operator*() const {
564 assertIsChecked();
565 return *getStorage();
566 }
567
568private:
569 template <class T1>
570 static bool compareThisIfSameType(const T1 &a, const T1 &b) {
571 return &a == &b;
572 }
573
574 template <class T1, class T2>
575 static bool compareThisIfSameType(const T1 &a, const T2 &b) {
576 return false;
577 }
578
579 template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) {
580 HasError = Other.HasError;
581#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
582 Unchecked = true;
583 Other.Unchecked = false;
584#endif
585
586 if (!HasError)
587 new (getStorage()) storage_type(std::move(*Other.getStorage()));
588 else
589 new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage()));
590 }
591
592 template <class OtherT> void moveAssign(Expected<OtherT> &&Other) {
593 assertIsChecked();
594
595 if (compareThisIfSameType(*this, Other))
596 return;
597
598 this->~Expected();
599 new (this) Expected(std::move(Other));
600 }
601
602 pointer toPointer(pointer Val) { return Val; }
603
604 const_pointer toPointer(const_pointer Val) const { return Val; }
605
606 pointer toPointer(wrap *Val) { return &Val->get(); }
607
608 const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
609
610 storage_type *getStorage() {
611 assert(!HasError && "Cannot get value when an error exists!")(static_cast <bool> (!HasError && "Cannot get value when an error exists!"
) ? void (0) : __assert_fail ("!HasError && \"Cannot get value when an error exists!\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 611, __extension__ __PRETTY_FUNCTION__))
;
612 return reinterpret_cast<storage_type *>(TStorage.buffer);
613 }
614
615 const storage_type *getStorage() const {
616 assert(!HasError && "Cannot get value when an error exists!")(static_cast <bool> (!HasError && "Cannot get value when an error exists!"
) ? void (0) : __assert_fail ("!HasError && \"Cannot get value when an error exists!\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 616, __extension__ __PRETTY_FUNCTION__))
;
617 return reinterpret_cast<const storage_type *>(TStorage.buffer);
618 }
619
620 error_type *getErrorStorage() {
621 assert(HasError && "Cannot get error when a value exists!")(static_cast <bool> (HasError && "Cannot get error when a value exists!"
) ? void (0) : __assert_fail ("HasError && \"Cannot get error when a value exists!\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 621, __extension__ __PRETTY_FUNCTION__))
;
622 return reinterpret_cast<error_type *>(ErrorStorage.buffer);
623 }
624
625 const error_type *getErrorStorage() const {
626 assert(HasError && "Cannot get error when a value exists!")(static_cast <bool> (HasError && "Cannot get error when a value exists!"
) ? void (0) : __assert_fail ("HasError && \"Cannot get error when a value exists!\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 626, __extension__ __PRETTY_FUNCTION__))
;
627 return reinterpret_cast<const error_type *>(ErrorStorage.buffer);
628 }
629
630 // Used by ExpectedAsOutParameter to reset the checked flag.
631 void setUnchecked() {
632#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
633 Unchecked = true;
634#endif
635 }
636
637#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
638 LLVM_ATTRIBUTE_NORETURN__attribute__((noreturn))
639 LLVM_ATTRIBUTE_NOINLINE__attribute__((noinline))
640 void fatalUncheckedExpected() const {
641 dbgs() << "Expected<T> must be checked before access or destruction.\n";
642 if (HasError) {
643 dbgs() << "Unchecked Expected<T> contained error:\n";
644 (*getErrorStorage())->log(dbgs());
645 } else
646 dbgs() << "Expected<T> value was in success state. (Note: Expected<T> "
647 "values in success mode must still be checked prior to being "
648 "destroyed).\n";
649 abort();
650 }
651#endif
652
653 void assertIsChecked() {
654#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
655 if (LLVM_UNLIKELY(Unchecked)__builtin_expect((bool)(Unchecked), false))
656 fatalUncheckedExpected();
657#endif
658 }
659
660 union {
661 AlignedCharArrayUnion<storage_type> TStorage;
662 AlignedCharArrayUnion<error_type> ErrorStorage;
663 };
664 bool HasError : 1;
665#if LLVM_ENABLE_ABI_BREAKING_CHECKS1
666 bool Unchecked : 1;
667#endif
668};
669
670/// Report a serious error, calling any installed error handler. See
671/// ErrorHandling.h.
672LLVM_ATTRIBUTE_NORETURN__attribute__((noreturn)) void report_fatal_error(Error Err,
673 bool gen_crash_diag = true);
674
675/// Report a fatal error if Err is a failure value.
676///
677/// This function can be used to wrap calls to fallible functions ONLY when it
678/// is known that the Error will always be a success value. E.g.
679///
680/// @code{.cpp}
681/// // foo only attempts the fallible operation if DoFallibleOperation is
682/// // true. If DoFallibleOperation is false then foo always returns
683/// // Error::success().
684/// Error foo(bool DoFallibleOperation);
685///
686/// cantFail(foo(false));
687/// @endcode
688inline void cantFail(Error Err, const char *Msg = nullptr) {
689 if (Err) {
690 if (!Msg)
691 Msg = "Failure value returned from cantFail wrapped call";
692 llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 692)
;
693 }
694}
695
696/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
697/// returns the contained value.
698///
699/// This function can be used to wrap calls to fallible functions ONLY when it
700/// is known that the Error will always be a success value. E.g.
701///
702/// @code{.cpp}
703/// // foo only attempts the fallible operation if DoFallibleOperation is
704/// // true. If DoFallibleOperation is false then foo always returns an int.
705/// Expected<int> foo(bool DoFallibleOperation);
706///
707/// int X = cantFail(foo(false));
708/// @endcode
709template <typename T>
710T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) {
711 if (ValOrErr)
712 return std::move(*ValOrErr);
713 else {
714 if (!Msg)
715 Msg = "Failure value returned from cantFail wrapped call";
716 llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 716)
;
717 }
718}
719
720/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
721/// returns the contained reference.
722///
723/// This function can be used to wrap calls to fallible functions ONLY when it
724/// is known that the Error will always be a success value. E.g.
725///
726/// @code{.cpp}
727/// // foo only attempts the fallible operation if DoFallibleOperation is
728/// // true. If DoFallibleOperation is false then foo always returns a Bar&.
729/// Expected<Bar&> foo(bool DoFallibleOperation);
730///
731/// Bar &X = cantFail(foo(false));
732/// @endcode
733template <typename T>
734T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) {
735 if (ValOrErr)
736 return *ValOrErr;
737 else {
738 if (!Msg)
739 Msg = "Failure value returned from cantFail wrapped call";
740 llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 740)
;
741 }
742}
743
744/// Helper for testing applicability of, and applying, handlers for
745/// ErrorInfo types.
746template <typename HandlerT>
747class ErrorHandlerTraits
748 : public ErrorHandlerTraits<decltype(
749 &std::remove_reference<HandlerT>::type::operator())> {};
750
751// Specialization functions of the form 'Error (const ErrT&)'.
752template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
753public:
754 static bool appliesTo(const ErrorInfoBase &E) {
755 return E.template isA<ErrT>();
756 }
757
758 template <typename HandlerT>
759 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
760 assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler"
) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 760, __extension__ __PRETTY_FUNCTION__))
;
761 return H(static_cast<ErrT &>(*E));
762 }
763};
764
765// Specialization functions of the form 'void (const ErrT&)'.
766template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
767public:
768 static bool appliesTo(const ErrorInfoBase &E) {
769 return E.template isA<ErrT>();
770 }
771
772 template <typename HandlerT>
773 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
774 assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler"
) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 774, __extension__ __PRETTY_FUNCTION__))
;
775 H(static_cast<ErrT &>(*E));
776 return Error::success();
777 }
778};
779
780/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
781template <typename ErrT>
782class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
783public:
784 static bool appliesTo(const ErrorInfoBase &E) {
785 return E.template isA<ErrT>();
786 }
787
788 template <typename HandlerT>
789 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
790 assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler"
) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 790, __extension__ __PRETTY_FUNCTION__))
;
791 std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
792 return H(std::move(SubE));
793 }
794};
795
796/// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'.
797template <typename ErrT>
798class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
799public:
800 static bool appliesTo(const ErrorInfoBase &E) {
801 return E.template isA<ErrT>();
802 }
803
804 template <typename HandlerT>
805 static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
806 assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler"
) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\""
, "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Error.h"
, 806, __extension__ __PRETTY_FUNCTION__))
;
807 std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
808 H(std::move(SubE));
809 return Error::success();
810 }
811};
812
813// Specialization for member functions of the form 'RetT (const ErrT&)'.
814template <typename C, typename RetT, typename ErrT>
815class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
816 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
817
818// Specialization for member functions of the form 'RetT (const ErrT&) const'.
819template <typename C, typename RetT, typename ErrT>
820class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
821 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
822
823// Specialization for member functions of the form 'RetT (const ErrT&)'.
824template <typename C, typename RetT, typename ErrT>
825class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
826 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
827
828// Specialization for member functions of the form 'RetT (const ErrT&) const'.
829template <typename C, typename RetT, typename ErrT>
830class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const>
831 : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
832
833/// Specialization for member functions of the form
834/// 'RetT (std::unique_ptr<ErrT>)'.
835template <typename C, typename RetT, typename ErrT>
836class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)>
837 : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
838
839/// Specialization for member functions of the form
840/// 'RetT (std::unique_ptr<ErrT>) const'.
841template <typename C, typename RetT, typename ErrT>
842class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
843 : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
844
845inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
846 return Error(std::move(Payload));
847}
848
849template <typename HandlerT, typename... HandlerTs>
850Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
851 HandlerT &&Handler, HandlerTs &&... Handlers) {
852 if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
853 return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
854 std::move(Payload));
855 return handleErrorImpl(std::move(Payload),
856 std::forward<HandlerTs>(Handlers)...);
857}
858
859/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any
860/// unhandled errors (or Errors returned by handlers) are re-concatenated and
861/// returned.
862/// Because this function returns an error, its result must also be checked
863/// or returned. If you intend to handle all errors use handleAllErrors
864/// (which returns void, and will abort() on unhandled errors) instead.
865template <typename... HandlerTs>
866Error handleErrors(Error E, HandlerTs &&... Hs) {
867 if (!E)
868 return Error::success();
869
870 std::unique_ptr<ErrorInfoBase> Payload = E.takePayload();
871
872 if (Payload->isA<ErrorList>()) {
873 ErrorList &List = static_cast<ErrorList &>(*Payload);
874 Error R;
875 for (auto &P : List.Payloads)
876 R = ErrorList::join(
877 std::move(R),
878 handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...));
879 return R;
880 }
881
882 return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
883}
884
885/// Behaves the same as handleErrors, except that it requires that all
886/// errors be handled by the given handlers. If any unhandled error remains
887/// after the handlers have run, report_fatal_error() will be called.
888template <typename... HandlerTs>
889void handleAllErrors(Error E, HandlerTs &&... Handlers) {
890 cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...));
891}
892
893/// Check that E is a non-error, then drop it.
894/// If E is an error report_fatal_error will be called.
895inline void handleAllErrors(Error E) {
896 cantFail(std::move(E));
897}
898
899/// Handle any errors (if present) in an Expected<T>, then try a recovery path.
900///
901/// If the incoming value is a success value it is returned unmodified. If it
902/// is a failure value then it the contained error is passed to handleErrors.
903/// If handleErrors is able to handle the error then the RecoveryPath functor
904/// is called to supply the final result. If handleErrors is not able to
905/// handle all errors then the unhandled errors are returned.
906///
907/// This utility enables the follow pattern:
908///
909/// @code{.cpp}
910/// enum FooStrategy { Aggressive, Conservative };
911/// Expected<Foo> foo(FooStrategy S);
912///
913/// auto ResultOrErr =
914/// handleExpected(
915/// foo(Aggressive),
916/// []() { return foo(Conservative); },
917/// [](AggressiveStrategyError&) {
918/// // Implicitly conusme this - we'll recover by using a conservative
919/// // strategy.
920/// });
921///
922/// @endcode
923template <typename T, typename RecoveryFtor, typename... HandlerTs>
924Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath,
925 HandlerTs &&... Handlers) {
926 if (ValOrErr)
927 return ValOrErr;
928
929 if (auto Err = handleErrors(ValOrErr.takeError(),
930 std::forward<HandlerTs>(Handlers)...))
931 return std::move(Err);
932
933 return RecoveryPath();
934}
935
936/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner
937/// will be printed before the first one is logged. A newline will be printed
938/// after each error.
939///
940/// This is useful in the base level of your program to allow clean termination
941/// (allowing clean deallocation of resources, etc.), while reporting error
942/// information to the user.
943void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner);
944
945/// Write all error messages (if any) in E to a string. The newline character
946/// is used to separate error messages.
947inline std::string toString(Error E) {
948 SmallVector<std::string, 2> Errors;
949 handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
950 Errors.push_back(EI.message());
951 });
952 return join(Errors.begin(), Errors.end(), "\n");
953}
954
955/// Consume a Error without doing anything. This method should be used
956/// only where an error can be considered a reasonable and expected return
957/// value.
958///
959/// Uses of this method are potentially indicative of design problems: If it's
960/// legitimate to do nothing while processing an "error", the error-producer
961/// might be more clearly refactored to return an Optional<T>.
962inline void consumeError(Error Err) {
963 handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
964}
965
966/// Helper for converting an Error to a bool.
967///
968/// This method returns true if Err is in an error state, or false if it is
969/// in a success state. Puts Err in a checked state in both cases (unlike
970/// Error::operator bool(), which only does this for success states).
971inline bool errorToBool(Error Err) {
972 bool IsError = static_cast<bool>(Err);
973 if (IsError)
974 consumeError(std::move(Err));
975 return IsError;
976}
977
978/// Helper for Errors used as out-parameters.
979///
980/// This helper is for use with the Error-as-out-parameter idiom, where an error
981/// is passed to a function or method by reference, rather than being returned.
982/// In such cases it is helpful to set the checked bit on entry to the function
983/// so that the error can be written to (unchecked Errors abort on assignment)
984/// and clear the checked bit on exit so that clients cannot accidentally forget
985/// to check the result. This helper performs these actions automatically using
986/// RAII:
987///
988/// @code{.cpp}
989/// Result foo(Error &Err) {
990/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set
991/// // <body of foo>
992/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
993/// }
994/// @endcode
995///
996/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be
997/// used with optional Errors (Error pointers that are allowed to be null). If
998/// ErrorAsOutParameter took an Error reference, an instance would have to be
999/// created inside every condition that verified that Error was non-null. By
1000/// taking an Error pointer we can just create one instance at the top of the
1001/// function.
1002class ErrorAsOutParameter {
1003public:
1004 ErrorAsOutParameter(Error *Err) : Err(Err) {
1005 // Raise the checked bit if Err is success.
1006 if (Err)
1007 (void)!!*Err;
1008 }
1009
1010 ~ErrorAsOutParameter() {
1011 // Clear the checked bit.
1012 if (Err && !*Err)
1013 *Err = Error::success();
1014 }
1015
1016private:
1017 Error *Err;
1018};
1019
1020/// Helper for Expected<T>s used as out-parameters.
1021///
1022/// See ErrorAsOutParameter.
1023template <typename T>
1024class ExpectedAsOutParameter {
1025public:
1026 ExpectedAsOutParameter(Expected<T> *ValOrErr)
1027 : ValOrErr(ValOrErr) {
1028 if (ValOrErr)
1029 (void)!!*ValOrErr;
1030 }
1031
1032 ~ExpectedAsOutParameter() {
1033 if (ValOrErr)
1034 ValOrErr->setUnchecked();
1035 }
1036
1037private:
1038 Expected<T> *ValOrErr;
1039};
1040
1041/// This class wraps a std::error_code in a Error.
1042///
1043/// This is useful if you're writing an interface that returns a Error
1044/// (or Expected) and you want to call code that still returns
1045/// std::error_codes.
1046class ECError : public ErrorInfo<ECError> {
1047 friend Error errorCodeToError(std::error_code);
1048
1049public:
1050 void setErrorCode(std::error_code EC) { this->EC = EC; }
1051 std::error_code convertToErrorCode() const override { return EC; }
1052 void log(raw_ostream &OS) const override { OS << EC.message(); }
1053
1054 // Used by ErrorInfo::classID.
1055 static char ID;
1056
1057protected:
1058 ECError() = default;
1059 ECError(std::error_code EC) : EC(EC) {}
1060
1061 std::error_code EC;
1062};
1063
1064/// The value returned by this function can be returned from convertToErrorCode
1065/// for Error values where no sensible translation to std::error_code exists.
1066/// It should only be used in this situation, and should never be used where a
1067/// sensible conversion to std::error_code is available, as attempts to convert
1068/// to/from this error will result in a fatal error. (i.e. it is a programmatic
1069///error to try to convert such a value).
1070std::error_code inconvertibleErrorCode();
1071
1072/// Helper for converting an std::error_code to a Error.
1073Error errorCodeToError(std::error_code EC);
1074
1075/// Helper for converting an ECError to a std::error_code.
1076///
1077/// This method requires that Err be Error() or an ECError, otherwise it
1078/// will trigger a call to abort().
1079std::error_code errorToErrorCode(Error Err);
1080
1081/// Convert an ErrorOr<T> to an Expected<T>.
1082template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
1083 if (auto EC = EO.getError())
1084 return errorCodeToError(EC);
1085 return std::move(*EO);
1086}
1087
1088/// Convert an Expected<T> to an ErrorOr<T>.
1089template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) {
1090 if (auto Err = E.takeError())
1091 return errorToErrorCode(std::move(Err));
1092 return std::move(*E);
1093}
1094
1095/// This class wraps a string in an Error.
1096///
1097/// StringError is useful in cases where the client is not expected to be able
1098/// to consume the specific error message programmatically (for example, if the
1099/// error message is to be presented to the user).
1100class StringError : public ErrorInfo<StringError> {
1101public:
1102 static char ID;
1103
1104 StringError(const Twine &S, std::error_code EC);
1105
1106 void log(raw_ostream &OS) const override;
1107 std::error_code convertToErrorCode() const override;
1108
1109 const std::string &getMessage() const { return Msg; }
1110
1111private:
1112 std::string Msg;
1113 std::error_code EC;
1114};
1115
1116/// Helper for check-and-exit error handling.
1117///
1118/// For tool use only. NOT FOR USE IN LIBRARY CODE.
1119///
1120class ExitOnError {
1121public:
1122 /// Create an error on exit helper.
1123 ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1)
1124 : Banner(std::move(Banner)),
1125 GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {}
1126
1127 /// Set the banner string for any errors caught by operator().
1128 void setBanner(std::string Banner) { this->Banner = std::move(Banner); }
1129
1130 /// Set the exit-code mapper function.
1131 void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) {
1132 this->GetExitCode = std::move(GetExitCode);
1133 }
1134
1135 /// Check Err. If it's in a failure state log the error(s) and exit.
1136 void operator()(Error Err) const { checkError(std::move(Err)); }
1137
1138 /// Check E. If it's in a success state then return the contained value. If
1139 /// it's in a failure state log the error(s) and exit.
1140 template <typename T> T operator()(Expected<T> &&E) const {
1141 checkError(E.takeError());
1142 return std::move(*E);
1143 }
1144
1145 /// Check E. If it's in a success state then return the contained reference. If
1146 /// it's in a failure state log the error(s) and exit.
1147 template <typename T> T& operator()(Expected<T&> &&E) const {
1148 checkError(E.takeError());
1149 return *E;
1150 }
1151
1152private:
1153 void checkError(Error Err) const {
1154 if (Err) {
1155 int ExitCode = GetExitCode(Err);
1156 logAllUnhandledErrors(std::move(Err), errs(), Banner);
1157 exit(ExitCode);
1158 }
1159 }
1160
1161 std::string Banner;
1162 std::function<int(const Error &)> GetExitCode;
1163};
1164
1165} // end namespace llvm
1166
1167#endif // LLVM_SUPPORT_ERROR_H

/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Endian.h

1//===- Endian.h - Utilities for IO with endian specific data ----*- 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// This file declares generic functions to read and write endian specific data.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_SUPPORT_ENDIAN_H
15#define LLVM_SUPPORT_ENDIAN_H
16
17#include "llvm/Support/AlignOf.h"
18#include "llvm/Support/Compiler.h"
19#include "llvm/Support/Host.h"
20#include "llvm/Support/SwapByteOrder.h"
21#include <cassert>
22#include <cstddef>
23#include <cstdint>
24#include <cstring>
25#include <type_traits>
26
27namespace llvm {
28namespace support {
29
30enum endianness {big, little, native};
31
32// These are named values for common alignments.
33enum {aligned = 0, unaligned = 1};
34
35namespace detail {
36
37/// \brief ::value is either alignment, or alignof(T) if alignment is 0.
38template<class T, int alignment>
39struct PickAlignment {
40 enum { value = alignment == 0 ? alignof(T) : alignment };
41};
42
43} // end namespace detail
44
45namespace endian {
46
47constexpr endianness system_endianness() {
48 return sys::IsBigEndianHost ? big : little;
49}
50
51template <typename value_type>
52inline value_type byte_swap(value_type value, endianness endian) {
53 if ((endian != native) && (endian != system_endianness()))
53
Assuming 'endian' is equal to native
54 sys::swapByteOrder(value);
55 return value;
56}
57
58/// Swap the bytes of value to match the given endianness.
59template<typename value_type, endianness endian>
60inline value_type byte_swap(value_type value) {
61 return byte_swap(value, endian);
62}
63
64/// Read a value of a particular endianness from memory.
65template <typename value_type, std::size_t alignment>
66inline value_type read(const void *memory, endianness endian) {
67 value_type ret;
68
69 memcpy(&ret,
70 LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
71 memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
,
72 sizeof(value_type));
73 return byte_swap<value_type>(ret, endian);
52
Calling 'byte_swap'
54
Returning from 'byte_swap'
74}
75
76template<typename value_type,
77 endianness endian,
78 std::size_t alignment>
79inline value_type read(const void *memory) {
80 return read<value_type, alignment>(memory, endian);
81}
82
83/// Read a value of a particular endianness from a buffer, and increment the
84/// buffer past that value.
85template <typename value_type, std::size_t alignment, typename CharT>
86inline value_type readNext(const CharT *&memory, endianness endian) {
87 value_type ret = read<value_type, alignment>(memory, endian);
88 memory += sizeof(value_type);
89 return ret;
90}
91
92template<typename value_type, endianness endian, std::size_t alignment,
93 typename CharT>
94inline value_type readNext(const CharT *&memory) {
95 return readNext<value_type, alignment, CharT>(memory, endian);
96}
97
98/// Write a value to memory with a particular endianness.
99template <typename value_type, std::size_t alignment>
100inline void write(void *memory, value_type value, endianness endian) {
101 value = byte_swap<value_type>(value, endian);
102 memcpy(LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
103 memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
,
104 &value, sizeof(value_type));
105}
106
107template<typename value_type,
108 endianness endian,
109 std::size_t alignment>
110inline void write(void *memory, value_type value) {
111 write<value_type, alignment>(memory, value, endian);
112}
113
114template <typename value_type>
115using make_unsigned_t = typename std::make_unsigned<value_type>::type;
116
117/// Read a value of a particular endianness from memory, for a location
118/// that starts at the given bit offset within the first byte.
119template <typename value_type, endianness endian, std::size_t alignment>
120inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
121 assert(startBit < 8)(static_cast <bool> (startBit < 8) ? void (0) : __assert_fail
("startBit < 8", "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Endian.h"
, 121, __extension__ __PRETTY_FUNCTION__))
;
122 if (startBit == 0)
123 return read<value_type, endian, alignment>(memory);
124 else {
125 // Read two values and compose the result from them.
126 value_type val[2];
127 memcpy(&val[0],
128 LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
129 memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
,
130 sizeof(value_type) * 2);
131 val[0] = byte_swap<value_type, endian>(val[0]);
132 val[1] = byte_swap<value_type, endian>(val[1]);
133
134 // Shift bits from the lower value into place.
135 make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
136 // Mask off upper bits after right shift in case of signed type.
137 make_unsigned_t<value_type> numBitsFirstVal =
138 (sizeof(value_type) * 8) - startBit;
139 lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
140
141 // Get the bits from the upper value.
142 make_unsigned_t<value_type> upperVal =
143 val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
144 // Shift them in to place.
145 upperVal <<= numBitsFirstVal;
146
147 return lowerVal | upperVal;
148 }
149}
150
151/// Write a value to memory with a particular endianness, for a location
152/// that starts at the given bit offset within the first byte.
153template <typename value_type, endianness endian, std::size_t alignment>
154inline void writeAtBitAlignment(void *memory, value_type value,
155 uint64_t startBit) {
156 assert(startBit < 8)(static_cast <bool> (startBit < 8) ? void (0) : __assert_fail
("startBit < 8", "/build/llvm-toolchain-snapshot-7~svn326246/include/llvm/Support/Endian.h"
, 156, __extension__ __PRETTY_FUNCTION__))
;
157 if (startBit == 0)
158 write<value_type, endian, alignment>(memory, value);
159 else {
160 // Read two values and shift the result into them.
161 value_type val[2];
162 memcpy(&val[0],
163 LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
164 memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
,
165 sizeof(value_type) * 2);
166 val[0] = byte_swap<value_type, endian>(val[0]);
167 val[1] = byte_swap<value_type, endian>(val[1]);
168
169 // Mask off any existing bits in the upper part of the lower value that
170 // we want to replace.
171 val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
172 make_unsigned_t<value_type> numBitsFirstVal =
173 (sizeof(value_type) * 8) - startBit;
174 make_unsigned_t<value_type> lowerVal = value;
175 if (startBit > 0) {
176 // Mask off the upper bits in the new value that are not going to go into
177 // the lower value. This avoids a left shift of a negative value, which
178 // is undefined behavior.
179 lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
180 // Now shift the new bits into place
181 lowerVal <<= startBit;
182 }
183 val[0] |= lowerVal;
184
185 // Mask off any existing bits in the lower part of the upper value that
186 // we want to replace.
187 val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
188 // Next shift the bits that go into the upper value into position.
189 make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
190 // Mask off upper bits after right shift in case of signed type.
191 upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
192 val[1] |= upperVal;
193
194 // Finally, rewrite values.
195 val[0] = byte_swap<value_type, endian>(val[0]);
196 val[1] = byte_swap<value_type, endian>(val[1]);
197 memcpy(LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
198 memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type
, alignment>::value))
,
199 &val[0], sizeof(value_type) * 2);
200 }
201}
202
203} // end namespace endian
204
205namespace detail {
206
207template<typename value_type,
208 endianness endian,
209 std::size_t alignment>
210struct packed_endian_specific_integral {
211 packed_endian_specific_integral() = default;
212
213 explicit packed_endian_specific_integral(value_type val) { *this = val; }
214
215 operator value_type() const {
216 return endian::read<value_type, endian, alignment>(
217 (const void*)Value.buffer);
218 }
219
220 void operator=(value_type newValue) {
221 endian::write<value_type, endian, alignment>(
222 (void*)Value.buffer, newValue);
223 }
224
225 packed_endian_specific_integral &operator+=(value_type newValue) {
226 *this = *this + newValue;
227 return *this;
228 }
229
230 packed_endian_specific_integral &operator-=(value_type newValue) {
231 *this = *this - newValue;
232 return *this;
233 }
234
235 packed_endian_specific_integral &operator|=(value_type newValue) {
236 *this = *this | newValue;
237 return *this;
238 }
239
240 packed_endian_specific_integral &operator&=(value_type newValue) {
241 *this = *this & newValue;
242 return *this;
243 }
244
245private:
246 AlignedCharArray<PickAlignment<value_type, alignment>::value,
247 sizeof(value_type)> Value;
248
249public:
250 struct ref {
251 explicit ref(void *Ptr) : Ptr(Ptr) {}
252
253 operator value_type() const {
254 return endian::read<value_type, endian, alignment>(Ptr);
255 }
256
257 void operator=(value_type NewValue) {
258 endian::write<value_type, endian, alignment>(Ptr, NewValue);
259 }
260
261 private:
262 void *Ptr;
263 };
264};
265
266} // end namespace detail
267
268using ulittle16_t =
269 detail::packed_endian_specific_integral<uint16_t, little, unaligned>;
270using ulittle32_t =
271 detail::packed_endian_specific_integral<uint32_t, little, unaligned>;
272using ulittle64_t =
273 detail::packed_endian_specific_integral<uint64_t, little, unaligned>;
274
275using little16_t =
276 detail::packed_endian_specific_integral<int16_t, little, unaligned>;
277using little32_t =
278 detail::packed_endian_specific_integral<int32_t, little, unaligned>;
279using little64_t =
280 detail::packed_endian_specific_integral<int64_t, little, unaligned>;
281
282using aligned_ulittle16_t =
283 detail::packed_endian_specific_integral<uint16_t, little, aligned>;
284using aligned_ulittle32_t =
285 detail::packed_endian_specific_integral<uint32_t, little, aligned>;
286using aligned_ulittle64_t =
287 detail::packed_endian_specific_integral<uint64_t, little, aligned>;
288
289using aligned_little16_t =
290 detail::packed_endian_specific_integral<int16_t, little, aligned>;
291using aligned_little32_t =
292 detail::packed_endian_specific_integral<int32_t, little, aligned>;
293using aligned_little64_t =
294 detail::packed_endian_specific_integral<int64_t, little, aligned>;
295
296using ubig16_t =
297 detail::packed_endian_specific_integral<uint16_t, big, unaligned>;
298using ubig32_t =
299 detail::packed_endian_specific_integral<uint32_t, big, unaligned>;
300using ubig64_t =
301 detail::packed_endian_specific_integral<uint64_t, big, unaligned>;
302
303using big16_t =
304 detail::packed_endian_specific_integral<int16_t, big, unaligned>;
305using big32_t =
306 detail::packed_endian_specific_integral<int32_t, big, unaligned>;
307using big64_t =
308 detail::packed_endian_specific_integral<int64_t, big, unaligned>;
309
310using aligned_ubig16_t =
311 detail::packed_endian_specific_integral<uint16_t, big, aligned>;
312using aligned_ubig32_t =
313 detail::packed_endian_specific_integral<uint32_t, big, aligned>;
314using aligned_ubig64_t =
315 detail::packed_endian_specific_integral<uint64_t, big, aligned>;
316
317using aligned_big16_t =
318 detail::packed_endian_specific_integral<int16_t, big, aligned>;
319using aligned_big32_t =
320 detail::packed_endian_specific_integral<int32_t, big, aligned>;
321using aligned_big64_t =
322 detail::packed_endian_specific_integral<int64_t, big, aligned>;
323
324using unaligned_uint16_t =
325 detail::packed_endian_specific_integral<uint16_t, native, unaligned>;
326using unaligned_uint32_t =
327 detail::packed_endian_specific_integral<uint32_t, native, unaligned>;
328using unaligned_uint64_t =
329 detail::packed_endian_specific_integral<uint64_t, native, unaligned>;
330
331using unaligned_int16_t =
332 detail::packed_endian_specific_integral<int16_t, native, unaligned>;
333using unaligned_int32_t =
334 detail::packed_endian_specific_integral<int32_t, native, unaligned>;
335using unaligned_int64_t =
336 detail::packed_endian_specific_integral<int64_t, native, unaligned>;
337
338namespace endian {
339
340template <typename T> inline T read(const void *P, endianness E) {
341 return read<T, unaligned>(P, E);
342}
343
344template <typename T, endianness E> inline T read(const void *P) {
345 return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
346}
347
348inline uint16_t read16(const void *P, endianness E) {
349 return read<uint16_t>(P, E);
350}
351inline uint32_t read32(const void *P, endianness E) {
352 return read<uint32_t>(P, E);
353}
354inline uint64_t read64(const void *P, endianness E) {
355 return read<uint64_t>(P, E);
356}
357
358template <endianness E> inline uint16_t read16(const void *P) {
359 return read<uint16_t, E>(P);
360}
361template <endianness E> inline uint32_t read32(const void *P) {
362 return read<uint32_t, E>(P);
363}
364template <endianness E> inline uint64_t read64(const void *P) {
365 return read<uint64_t, E>(P);
366}
367
368inline uint16_t read16le(const void *P) { return read16<little>(P); }
369inline uint32_t read32le(const void *P) { return read32<little>(P); }
370inline uint64_t read64le(const void *P) { return read64<little>(P); }
371inline uint16_t read16be(const void *P) { return read16<big>(P); }
372inline uint32_t read32be(const void *P) { return read32<big>(P); }
373inline uint64_t read64be(const void *P) { return read64<big>(P); }
374
375template <typename T> inline void write(void *P, T V, endianness E) {
376 write<T, unaligned>(P, V, E);
377}
378
379template <typename T, endianness E> inline void write(void *P, T V) {
380 *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
381}
382
383inline void write16(void *P, uint16_t V, endianness E) {
384 write<uint16_t>(P, V, E);
385}
386inline void write32(void *P, uint32_t V, endianness E) {
387 write<uint32_t>(P, V, E);
388}
389inline void write64(void *P, uint64_t V, endianness E) {
390 write<uint64_t>(P, V, E);
391}
392
393template <endianness E> inline void write16(void *P, uint16_t V) {
394 write<uint16_t, E>(P, V);
395}
396template <endianness E> inline void write32(void *P, uint32_t V) {
397 write<uint32_t, E>(P, V);
398}
399template <endianness E> inline void write64(void *P, uint64_t V) {
400 write<uint64_t, E>(P, V);
401}
402
403inline void write16le(void *P, uint16_t V) { write16<little>(P, V); }
404inline void write32le(void *P, uint32_t V) { write32<little>(P, V); }
405inline void write64le(void *P, uint64_t V) { write64<little>(P, V); }
406inline void write16be(void *P, uint16_t V) { write16<big>(P, V); }
407inline void write32be(void *P, uint32_t V) { write32<big>(P, V); }
408inline void write64be(void *P, uint64_t V) { write64<big>(P, V); }
409
410} // end namespace endian
411
412} // end namespace support
413} // end namespace llvm
414
415#endif // LLVM_SUPPORT_ENDIAN_H