1 //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ObjectYAML/MinidumpYAML.h"
10 #include "llvm/Support/Allocator.h"
11 #include "llvm/Support/ConvertUTF.h"
14 using namespace llvm::MinidumpYAML
;
15 using namespace llvm::minidump
;
18 /// A helper class to manage the placement of various structures into the final
19 /// minidump binary. Space for objects can be allocated via various allocate***
20 /// methods, while the final minidump file is written by calling the writeTo
21 /// method. The plain versions of allocation functions take a reference to the
22 /// data which is to be written (and hence the data must be available until
23 /// writeTo is called), while the "New" versions allocate the data in an
24 /// allocator-managed buffer, which is available until the allocator object is
25 /// destroyed. For both kinds of functions, it is possible to modify the
26 /// data for which the space has been "allocated" until the final writeTo call.
27 /// This is useful for "linking" the allocated structures via their offsets.
30 size_t tell() const { return NextOffset
; }
32 size_t allocateCallback(size_t Size
,
33 std::function
<void(raw_ostream
&)> Callback
) {
34 size_t Offset
= NextOffset
;
36 Callbacks
.push_back(std::move(Callback
));
40 size_t allocateBytes(ArrayRef
<uint8_t> Data
) {
41 return allocateCallback(
42 Data
.size(), [Data
](raw_ostream
&OS
) { OS
<< toStringRef(Data
); });
45 size_t allocateBytes(yaml::BinaryRef Data
) {
46 return allocateCallback(Data
.binary_size(), [Data
](raw_ostream
&OS
) {
47 Data
.writeAsBinary(OS
);
51 template <typename T
> size_t allocateArray(ArrayRef
<T
> Data
) {
52 return allocateBytes({reinterpret_cast<const uint8_t *>(Data
.data()),
53 sizeof(T
) * Data
.size()});
56 template <typename T
, typename RangeType
>
57 std::pair
<size_t, MutableArrayRef
<T
>>
58 allocateNewArray(const iterator_range
<RangeType
> &Range
);
60 template <typename T
> size_t allocateObject(const T
&Data
) {
61 return allocateArray(makeArrayRef(Data
));
64 template <typename T
, typename
... Types
>
65 std::pair
<size_t, T
*> allocateNewObject(Types
&&... Args
) {
66 T
*Object
= new (Temporaries
.Allocate
<T
>()) T(std::forward
<Types
>(Args
)...);
67 return {allocateObject(*Object
), Object
};
70 size_t allocateString(StringRef Str
);
72 void writeTo(raw_ostream
&OS
) const;
75 size_t NextOffset
= 0;
77 BumpPtrAllocator Temporaries
;
78 std::vector
<std::function
<void(raw_ostream
&)>> Callbacks
;
82 template <typename T
, typename RangeType
>
83 std::pair
<size_t, MutableArrayRef
<T
>>
84 BlobAllocator::allocateNewArray(const iterator_range
<RangeType
> &Range
) {
85 size_t Num
= std::distance(Range
.begin(), Range
.end());
86 MutableArrayRef
<T
> Array(Temporaries
.Allocate
<T
>(Num
), Num
);
87 std::uninitialized_copy(Range
.begin(), Range
.end(), Array
.begin());
88 return {allocateArray(Array
), Array
};
91 size_t BlobAllocator::allocateString(StringRef Str
) {
92 SmallVector
<UTF16
, 32> WStr
;
93 bool OK
= convertUTF8ToUTF16String(Str
, WStr
);
94 assert(OK
&& "Invalid UTF8 in Str?");
97 // The utf16 string is null-terminated, but the terminator is not counted in
101 allocateNewObject
<support::ulittle32_t
>(2 * (WStr
.size() - 1)).first
;
102 allocateNewArray
<support::ulittle16_t
>(make_range(WStr
.begin(), WStr
.end()));
106 void BlobAllocator::writeTo(raw_ostream
&OS
) const {
107 size_t BeginOffset
= OS
.tell();
108 for (const auto &Callback
: Callbacks
)
110 assert(OS
.tell() == BeginOffset
+ NextOffset
&&
111 "Callbacks wrote an unexpected number of bytes.");
115 /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
116 /// only purpose of this function is to avoid casting the Default value to the
118 template <typename EndianType
>
119 static inline void mapOptional(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
120 typename
EndianType::value_type Default
) {
121 IO
.mapOptional(Key
, Val
, EndianType(Default
));
124 /// Yaml-map an endian-aware type EndianType as some other type MapType.
125 template <typename MapType
, typename EndianType
>
126 static inline void mapRequiredAs(yaml::IO
&IO
, const char *Key
,
128 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
129 IO
.mapRequired(Key
, Mapped
);
130 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
133 /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
134 /// other type MapType.
135 template <typename MapType
, typename EndianType
>
136 static inline void mapOptionalAs(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
138 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
139 IO
.mapOptional(Key
, Mapped
, Default
);
140 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
144 /// Return the appropriate yaml Hex type for a given endian-aware type.
145 template <typename EndianType
> struct HexType
;
146 template <> struct HexType
<support::ulittle16_t
> { using type
= yaml::Hex16
; };
147 template <> struct HexType
<support::ulittle32_t
> { using type
= yaml::Hex32
; };
148 template <> struct HexType
<support::ulittle64_t
> { using type
= yaml::Hex64
; };
151 /// Yaml-map an endian-aware type as an appropriately-sized hex value.
152 template <typename EndianType
>
153 static inline void mapRequiredHex(yaml::IO
&IO
, const char *Key
,
155 mapRequiredAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
);
158 /// Perform an optional yaml-mapping of an endian-aware type as an
159 /// appropriately-sized hex value.
160 template <typename EndianType
>
161 static inline void mapOptionalHex(yaml::IO
&IO
, const char *Key
,
163 typename
EndianType::value_type Default
) {
164 mapOptionalAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
, Default
);
167 Stream::~Stream() = default;
169 Stream::StreamKind
Stream::getKind(StreamType Type
) {
171 case StreamType::MemoryList
:
172 return StreamKind::MemoryList
;
173 case StreamType::ModuleList
:
174 return StreamKind::ModuleList
;
175 case StreamType::SystemInfo
:
176 return StreamKind::SystemInfo
;
177 case StreamType::LinuxCPUInfo
:
178 case StreamType::LinuxProcStatus
:
179 case StreamType::LinuxLSBRelease
:
180 case StreamType::LinuxCMDLine
:
181 case StreamType::LinuxMaps
:
182 case StreamType::LinuxProcStat
:
183 case StreamType::LinuxProcUptime
:
184 return StreamKind::TextContent
;
185 case StreamType::ThreadList
:
186 return StreamKind::ThreadList
;
188 return StreamKind::RawContent
;
192 std::unique_ptr
<Stream
> Stream::create(StreamType Type
) {
193 StreamKind Kind
= getKind(Type
);
195 case StreamKind::MemoryList
:
196 return llvm::make_unique
<MemoryListStream
>();
197 case StreamKind::ModuleList
:
198 return llvm::make_unique
<ModuleListStream
>();
199 case StreamKind::RawContent
:
200 return llvm::make_unique
<RawContentStream
>(Type
);
201 case StreamKind::SystemInfo
:
202 return llvm::make_unique
<SystemInfoStream
>();
203 case StreamKind::TextContent
:
204 return llvm::make_unique
<TextContentStream
>(Type
);
205 case StreamKind::ThreadList
:
206 return llvm::make_unique
<ThreadListStream
>();
208 llvm_unreachable("Unhandled stream kind!");
211 void yaml::ScalarEnumerationTraits
<ProcessorArchitecture
>::enumeration(
212 IO
&IO
, ProcessorArchitecture
&Arch
) {
213 #define HANDLE_MDMP_ARCH(CODE, NAME) \
214 IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
215 #include "llvm/BinaryFormat/MinidumpConstants.def"
216 IO
.enumFallback
<Hex16
>(Arch
);
219 void yaml::ScalarEnumerationTraits
<OSPlatform
>::enumeration(IO
&IO
,
221 #define HANDLE_MDMP_PLATFORM(CODE, NAME) \
222 IO.enumCase(Plat, #NAME, OSPlatform::NAME);
223 #include "llvm/BinaryFormat/MinidumpConstants.def"
224 IO
.enumFallback
<Hex32
>(Plat
);
227 void yaml::ScalarEnumerationTraits
<StreamType
>::enumeration(IO
&IO
,
229 #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) \
230 IO.enumCase(Type, #NAME, StreamType::NAME);
231 #include "llvm/BinaryFormat/MinidumpConstants.def"
232 IO
.enumFallback
<Hex32
>(Type
);
235 void yaml::MappingTraits
<CPUInfo::ArmInfo
>::mapping(IO
&IO
,
236 CPUInfo::ArmInfo
&Info
) {
237 mapRequiredHex(IO
, "CPUID", Info
.CPUID
);
238 mapOptionalHex(IO
, "ELF hwcaps", Info
.ElfHWCaps
, 0);
242 template <std::size_t N
> struct FixedSizeHex
{
243 FixedSizeHex(uint8_t (&Storage
)[N
]) : Storage(Storage
) {}
245 uint8_t (&Storage
)[N
];
251 template <std::size_t N
> struct ScalarTraits
<FixedSizeHex
<N
>> {
252 static void output(const FixedSizeHex
<N
> &Fixed
, void *, raw_ostream
&OS
) {
253 OS
<< toHex(makeArrayRef(Fixed
.Storage
));
256 static StringRef
input(StringRef Scalar
, void *, FixedSizeHex
<N
> &Fixed
) {
257 if (!all_of(Scalar
, isHexDigit
))
258 return "Invalid hex digit in input";
259 if (Scalar
.size() < 2 * N
)
260 return "String too short";
261 if (Scalar
.size() > 2 * N
)
262 return "String too long";
263 copy(fromHex(Scalar
), Fixed
.Storage
);
267 static QuotingType
mustQuote(StringRef S
) { return QuotingType::None
; }
271 void yaml::MappingTraits
<CPUInfo::OtherInfo
>::mapping(
272 IO
&IO
, CPUInfo::OtherInfo
&Info
) {
273 FixedSizeHex
<sizeof(Info
.ProcessorFeatures
)> Features(Info
.ProcessorFeatures
);
274 IO
.mapRequired("Features", Features
);
278 /// A type which only accepts strings of a fixed size for yaml conversion.
279 template <std::size_t N
> struct FixedSizeString
{
280 FixedSizeString(char (&Storage
)[N
]) : Storage(Storage
) {}
288 template <std::size_t N
> struct ScalarTraits
<FixedSizeString
<N
>> {
289 static void output(const FixedSizeString
<N
> &Fixed
, void *, raw_ostream
&OS
) {
290 OS
<< StringRef(Fixed
.Storage
, N
);
293 static StringRef
input(StringRef Scalar
, void *, FixedSizeString
<N
> &Fixed
) {
294 if (Scalar
.size() < N
)
295 return "String too short";
296 if (Scalar
.size() > N
)
297 return "String too long";
298 copy(Scalar
, Fixed
.Storage
);
302 static QuotingType
mustQuote(StringRef S
) { return needsQuotes(S
); }
307 void yaml::MappingTraits
<CPUInfo::X86Info
>::mapping(IO
&IO
,
308 CPUInfo::X86Info
&Info
) {
309 FixedSizeString
<sizeof(Info
.VendorID
)> VendorID(Info
.VendorID
);
310 IO
.mapRequired("Vendor ID", VendorID
);
312 mapRequiredHex(IO
, "Version Info", Info
.VersionInfo
);
313 mapRequiredHex(IO
, "Feature Info", Info
.FeatureInfo
);
314 mapOptionalHex(IO
, "AMD Extended Features", Info
.AMDExtendedFeatures
, 0);
317 void yaml::MappingTraits
<VSFixedFileInfo
>::mapping(IO
&IO
,
318 VSFixedFileInfo
&Info
) {
319 mapOptionalHex(IO
, "Signature", Info
.Signature
, 0);
320 mapOptionalHex(IO
, "Struct Version", Info
.StructVersion
, 0);
321 mapOptionalHex(IO
, "File Version High", Info
.FileVersionHigh
, 0);
322 mapOptionalHex(IO
, "File Version Low", Info
.FileVersionLow
, 0);
323 mapOptionalHex(IO
, "Product Version High", Info
.ProductVersionHigh
, 0);
324 mapOptionalHex(IO
, "Product Version Low", Info
.ProductVersionLow
, 0);
325 mapOptionalHex(IO
, "File Flags Mask", Info
.FileFlagsMask
, 0);
326 mapOptionalHex(IO
, "File Flags", Info
.FileFlags
, 0);
327 mapOptionalHex(IO
, "File OS", Info
.FileOS
, 0);
328 mapOptionalHex(IO
, "File Type", Info
.FileType
, 0);
329 mapOptionalHex(IO
, "File Subtype", Info
.FileSubtype
, 0);
330 mapOptionalHex(IO
, "File Date High", Info
.FileDateHigh
, 0);
331 mapOptionalHex(IO
, "File Date Low", Info
.FileDateLow
, 0);
334 void yaml::MappingTraits
<ModuleListStream::entry_type
>::mapping(
335 IO
&IO
, ModuleListStream::entry_type
&M
) {
336 mapRequiredHex(IO
, "Base of Image", M
.Entry
.BaseOfImage
);
337 mapRequiredHex(IO
, "Size of Image", M
.Entry
.SizeOfImage
);
338 mapOptionalHex(IO
, "Checksum", M
.Entry
.Checksum
, 0);
339 IO
.mapOptional("Time Date Stamp", M
.Entry
.TimeDateStamp
,
340 support::ulittle32_t(0));
341 IO
.mapRequired("Module Name", M
.Name
);
342 IO
.mapOptional("Version Info", M
.Entry
.VersionInfo
, VSFixedFileInfo());
343 IO
.mapRequired("CodeView Record", M
.CvRecord
);
344 IO
.mapOptional("Misc Record", M
.MiscRecord
, yaml::BinaryRef());
345 mapOptionalHex(IO
, "Reserved0", M
.Entry
.Reserved0
, 0);
346 mapOptionalHex(IO
, "Reserved1", M
.Entry
.Reserved1
, 0);
349 static void streamMapping(yaml::IO
&IO
, RawContentStream
&Stream
) {
350 IO
.mapOptional("Content", Stream
.Content
);
351 IO
.mapOptional("Size", Stream
.Size
, Stream
.Content
.binary_size());
354 static StringRef
streamValidate(RawContentStream
&Stream
) {
355 if (Stream
.Size
.value
< Stream
.Content
.binary_size())
356 return "Stream size must be greater or equal to the content size";
360 void yaml::MappingTraits
<MemoryListStream::entry_type
>::mapping(
361 IO
&IO
, MemoryListStream::entry_type
&Range
) {
362 MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
363 IO
, Range
.Entry
, Range
.Content
);
366 static void streamMapping(yaml::IO
&IO
, MemoryListStream
&Stream
) {
367 IO
.mapRequired("Memory Ranges", Stream
.Entries
);
370 static void streamMapping(yaml::IO
&IO
, ModuleListStream
&Stream
) {
371 IO
.mapRequired("Modules", Stream
.Entries
);
374 static void streamMapping(yaml::IO
&IO
, SystemInfoStream
&Stream
) {
375 SystemInfo
&Info
= Stream
.Info
;
376 IO
.mapRequired("Processor Arch", Info
.ProcessorArch
);
377 mapOptional(IO
, "Processor Level", Info
.ProcessorLevel
, 0);
378 mapOptional(IO
, "Processor Revision", Info
.ProcessorRevision
, 0);
379 IO
.mapOptional("Number of Processors", Info
.NumberOfProcessors
, 0);
380 IO
.mapOptional("Product type", Info
.ProductType
, 0);
381 mapOptional(IO
, "Major Version", Info
.MajorVersion
, 0);
382 mapOptional(IO
, "Minor Version", Info
.MinorVersion
, 0);
383 mapOptional(IO
, "Build Number", Info
.BuildNumber
, 0);
384 IO
.mapRequired("Platform ID", Info
.PlatformId
);
385 IO
.mapOptional("CSD Version", Stream
.CSDVersion
, "");
386 mapOptionalHex(IO
, "Suite Mask", Info
.SuiteMask
, 0);
387 mapOptionalHex(IO
, "Reserved", Info
.Reserved
, 0);
388 switch (static_cast<ProcessorArchitecture
>(Info
.ProcessorArch
)) {
389 case ProcessorArchitecture::X86
:
390 case ProcessorArchitecture::AMD64
:
391 IO
.mapOptional("CPU", Info
.CPU
.X86
);
393 case ProcessorArchitecture::ARM
:
394 case ProcessorArchitecture::ARM64
:
395 IO
.mapOptional("CPU", Info
.CPU
.Arm
);
398 IO
.mapOptional("CPU", Info
.CPU
.Other
);
403 static void streamMapping(yaml::IO
&IO
, TextContentStream
&Stream
) {
404 IO
.mapOptional("Text", Stream
.Text
);
407 void yaml::MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
408 IO
&IO
, MemoryDescriptor
&Memory
, BinaryRef
&Content
) {
409 mapRequiredHex(IO
, "Start of Memory Range", Memory
.StartOfMemoryRange
);
410 IO
.mapRequired("Content", Content
);
413 void yaml::MappingTraits
<ThreadListStream::entry_type
>::mapping(
414 IO
&IO
, ThreadListStream::entry_type
&T
) {
415 mapRequiredHex(IO
, "Thread Id", T
.Entry
.ThreadId
);
416 mapOptionalHex(IO
, "Suspend Count", T
.Entry
.SuspendCount
, 0);
417 mapOptionalHex(IO
, "Priority Class", T
.Entry
.PriorityClass
, 0);
418 mapOptionalHex(IO
, "Priority", T
.Entry
.Priority
, 0);
419 mapOptionalHex(IO
, "Environment Block", T
.Entry
.EnvironmentBlock
, 0);
420 IO
.mapRequired("Context", T
.Context
);
421 IO
.mapRequired("Stack", T
.Entry
.Stack
, T
.Stack
);
424 static void streamMapping(yaml::IO
&IO
, ThreadListStream
&Stream
) {
425 IO
.mapRequired("Threads", Stream
.Entries
);
428 void yaml::MappingTraits
<std::unique_ptr
<Stream
>>::mapping(
429 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
433 IO
.mapRequired("Type", Type
);
435 if (!IO
.outputting())
436 S
= MinidumpYAML::Stream::create(Type
);
438 case MinidumpYAML::Stream::StreamKind::MemoryList
:
439 streamMapping(IO
, llvm::cast
<MemoryListStream
>(*S
));
441 case MinidumpYAML::Stream::StreamKind::ModuleList
:
442 streamMapping(IO
, llvm::cast
<ModuleListStream
>(*S
));
444 case MinidumpYAML::Stream::StreamKind::RawContent
:
445 streamMapping(IO
, llvm::cast
<RawContentStream
>(*S
));
447 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
448 streamMapping(IO
, llvm::cast
<SystemInfoStream
>(*S
));
450 case MinidumpYAML::Stream::StreamKind::TextContent
:
451 streamMapping(IO
, llvm::cast
<TextContentStream
>(*S
));
453 case MinidumpYAML::Stream::StreamKind::ThreadList
:
454 streamMapping(IO
, llvm::cast
<ThreadListStream
>(*S
));
459 StringRef
yaml::MappingTraits
<std::unique_ptr
<Stream
>>::validate(
460 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
462 case MinidumpYAML::Stream::StreamKind::RawContent
:
463 return streamValidate(cast
<RawContentStream
>(*S
));
464 case MinidumpYAML::Stream::StreamKind::MemoryList
:
465 case MinidumpYAML::Stream::StreamKind::ModuleList
:
466 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
467 case MinidumpYAML::Stream::StreamKind::TextContent
:
468 case MinidumpYAML::Stream::StreamKind::ThreadList
:
471 llvm_unreachable("Fully covered switch above!");
474 void yaml::MappingTraits
<Object
>::mapping(IO
&IO
, Object
&O
) {
475 IO
.mapTag("!minidump", true);
476 mapOptionalHex(IO
, "Signature", O
.Header
.Signature
, Header::MagicSignature
);
477 mapOptionalHex(IO
, "Version", O
.Header
.Version
, Header::MagicVersion
);
478 mapOptionalHex(IO
, "Flags", O
.Header
.Flags
, 0);
479 IO
.mapRequired("Streams", O
.Streams
);
482 static LocationDescriptor
layout(BlobAllocator
&File
, yaml::BinaryRef Data
) {
483 return {support::ulittle32_t(Data
.binary_size()),
484 support::ulittle32_t(File
.allocateBytes(Data
))};
487 static void layout(BlobAllocator
&File
, MemoryListStream::entry_type
&Range
) {
488 Range
.Entry
.Memory
= layout(File
, Range
.Content
);
491 static void layout(BlobAllocator
&File
, ModuleListStream::entry_type
&M
) {
492 M
.Entry
.ModuleNameRVA
= File
.allocateString(M
.Name
);
494 M
.Entry
.CvRecord
= layout(File
, M
.CvRecord
);
495 M
.Entry
.MiscRecord
= layout(File
, M
.MiscRecord
);
498 static void layout(BlobAllocator
&File
, ThreadListStream::entry_type
&T
) {
499 T
.Entry
.Stack
.Memory
= layout(File
, T
.Stack
);
500 T
.Entry
.Context
= layout(File
, T
.Context
);
503 template <typename EntryT
>
504 static size_t layout(BlobAllocator
&File
,
505 MinidumpYAML::detail::ListStream
<EntryT
> &S
) {
507 File
.allocateNewObject
<support::ulittle32_t
>(S
.Entries
.size());
508 for (auto &E
: S
.Entries
)
509 File
.allocateObject(E
.Entry
);
511 size_t DataEnd
= File
.tell();
513 // Lay out the auxiliary data, (which is not a part of the stream).
514 DataEnd
= File
.tell();
515 for (auto &E
: S
.Entries
)
521 static Directory
layout(BlobAllocator
&File
, Stream
&S
) {
523 Result
.Type
= S
.Type
;
524 Result
.Location
.RVA
= File
.tell();
525 Optional
<size_t> DataEnd
;
527 case Stream::StreamKind::MemoryList
:
528 DataEnd
= layout(File
, cast
<MemoryListStream
>(S
));
530 case Stream::StreamKind::ModuleList
:
531 DataEnd
= layout(File
, cast
<ModuleListStream
>(S
));
533 case Stream::StreamKind::RawContent
: {
534 RawContentStream
&Raw
= cast
<RawContentStream
>(S
);
535 File
.allocateCallback(Raw
.Size
, [&Raw
](raw_ostream
&OS
) {
536 Raw
.Content
.writeAsBinary(OS
);
537 assert(Raw
.Content
.binary_size() <= Raw
.Size
);
538 OS
<< std::string(Raw
.Size
- Raw
.Content
.binary_size(), '\0');
542 case Stream::StreamKind::SystemInfo
: {
543 SystemInfoStream
&SystemInfo
= cast
<SystemInfoStream
>(S
);
544 File
.allocateObject(SystemInfo
.Info
);
545 // The CSD string is not a part of the stream.
546 DataEnd
= File
.tell();
547 SystemInfo
.Info
.CSDVersionRVA
= File
.allocateString(SystemInfo
.CSDVersion
);
550 case Stream::StreamKind::TextContent
:
551 File
.allocateArray(arrayRefFromStringRef(cast
<TextContentStream
>(S
).Text
));
553 case Stream::StreamKind::ThreadList
:
554 DataEnd
= layout(File
, cast
<ThreadListStream
>(S
));
557 // If DataEnd is not set, we assume everything we generated is a part of the
559 Result
.Location
.DataSize
=
560 DataEnd
.getValueOr(File
.tell()) - Result
.Location
.RVA
;
564 void MinidumpYAML::writeAsBinary(Object
&Obj
, raw_ostream
&OS
) {
566 File
.allocateObject(Obj
.Header
);
568 std::vector
<Directory
> StreamDirectory(Obj
.Streams
.size());
569 Obj
.Header
.StreamDirectoryRVA
=
570 File
.allocateArray(makeArrayRef(StreamDirectory
));
571 Obj
.Header
.NumberOfStreams
= StreamDirectory
.size();
573 for (auto &Stream
: enumerate(Obj
.Streams
))
574 StreamDirectory
[Stream
.index()] = layout(File
, *Stream
.value());
579 Error
MinidumpYAML::writeAsBinary(StringRef Yaml
, raw_ostream
&OS
) {
580 yaml::Input
Input(Yaml
);
583 if (std::error_code EC
= Input
.error())
584 return errorCodeToError(EC
);
586 writeAsBinary(Obj
, OS
);
587 return Error::success();
590 Expected
<std::unique_ptr
<Stream
>>
591 Stream::create(const Directory
&StreamDesc
, const object::MinidumpFile
&File
) {
592 StreamKind Kind
= getKind(StreamDesc
.Type
);
594 case StreamKind::MemoryList
: {
595 auto ExpectedList
= File
.getMemoryList();
597 return ExpectedList
.takeError();
598 std::vector
<MemoryListStream::entry_type
> Ranges
;
599 for (const MemoryDescriptor
&MD
: *ExpectedList
) {
600 auto ExpectedContent
= File
.getRawData(MD
.Memory
);
601 if (!ExpectedContent
)
602 return ExpectedContent
.takeError();
603 Ranges
.push_back({MD
, *ExpectedContent
});
605 return llvm::make_unique
<MemoryListStream
>(std::move(Ranges
));
607 case StreamKind::ModuleList
: {
608 auto ExpectedList
= File
.getModuleList();
610 return ExpectedList
.takeError();
611 std::vector
<ModuleListStream::entry_type
> Modules
;
612 for (const Module
&M
: *ExpectedList
) {
613 auto ExpectedName
= File
.getString(M
.ModuleNameRVA
);
615 return ExpectedName
.takeError();
616 auto ExpectedCv
= File
.getRawData(M
.CvRecord
);
618 return ExpectedCv
.takeError();
619 auto ExpectedMisc
= File
.getRawData(M
.MiscRecord
);
621 return ExpectedMisc
.takeError();
623 {M
, std::move(*ExpectedName
), *ExpectedCv
, *ExpectedMisc
});
625 return llvm::make_unique
<ModuleListStream
>(std::move(Modules
));
627 case StreamKind::RawContent
:
628 return llvm::make_unique
<RawContentStream
>(StreamDesc
.Type
,
629 File
.getRawStream(StreamDesc
));
630 case StreamKind::SystemInfo
: {
631 auto ExpectedInfo
= File
.getSystemInfo();
633 return ExpectedInfo
.takeError();
634 auto ExpectedCSDVersion
= File
.getString(ExpectedInfo
->CSDVersionRVA
);
635 if (!ExpectedCSDVersion
)
636 return ExpectedInfo
.takeError();
637 return llvm::make_unique
<SystemInfoStream
>(*ExpectedInfo
,
638 std::move(*ExpectedCSDVersion
));
640 case StreamKind::TextContent
:
641 return llvm::make_unique
<TextContentStream
>(
642 StreamDesc
.Type
, toStringRef(File
.getRawStream(StreamDesc
)));
643 case StreamKind::ThreadList
: {
644 auto ExpectedList
= File
.getThreadList();
646 return ExpectedList
.takeError();
647 std::vector
<ThreadListStream::entry_type
> Threads
;
648 for (const Thread
&T
: *ExpectedList
) {
649 auto ExpectedStack
= File
.getRawData(T
.Stack
.Memory
);
651 return ExpectedStack
.takeError();
652 auto ExpectedContext
= File
.getRawData(T
.Context
);
653 if (!ExpectedContext
)
654 return ExpectedContext
.takeError();
655 Threads
.push_back({T
, *ExpectedStack
, *ExpectedContext
});
657 return llvm::make_unique
<ThreadListStream
>(std::move(Threads
));
660 llvm_unreachable("Unhandled stream kind!");
663 Expected
<Object
> Object::create(const object::MinidumpFile
&File
) {
664 std::vector
<std::unique_ptr
<Stream
>> Streams
;
665 Streams
.reserve(File
.streams().size());
666 for (const Directory
&StreamDesc
: File
.streams()) {
667 auto ExpectedStream
= Stream::create(StreamDesc
, File
);
669 return ExpectedStream
.takeError();
670 Streams
.push_back(std::move(*ExpectedStream
));
672 return Object(File
.header(), std::move(Streams
));