1 | //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ObjectYAML/MinidumpYAML.h" |
10 | #include "llvm/Support/Allocator.h" |
11 | |
12 | using namespace llvm; |
13 | using namespace llvm::MinidumpYAML; |
14 | using namespace llvm::minidump; |
15 | |
16 | /// Perform an optional yaml-mapping of an endian-aware type EndianType. The |
17 | /// only purpose of this function is to avoid casting the Default value to the |
18 | /// endian type; |
19 | template <typename EndianType> |
20 | static inline void mapOptional(yaml::IO &IO, const char *Key, EndianType &Val, |
21 | typename EndianType::value_type Default) { |
22 | IO.mapOptional(Key, Val, EndianType(Default)); |
23 | } |
24 | |
25 | /// Yaml-map an endian-aware type EndianType as some other type MapType. |
26 | template <typename MapType, typename EndianType> |
27 | static inline void mapRequiredAs(yaml::IO &IO, const char *Key, |
28 | EndianType &Val) { |
29 | MapType Mapped = static_cast<typename EndianType::value_type>(Val); |
30 | IO.mapRequired(Key, Mapped); |
31 | Val = static_cast<typename EndianType::value_type>(Mapped); |
32 | } |
33 | |
34 | /// Perform an optional yaml-mapping of an endian-aware type EndianType as some |
35 | /// other type MapType. |
36 | template <typename MapType, typename EndianType> |
37 | static inline void mapOptionalAs(yaml::IO &IO, const char *Key, EndianType &Val, |
38 | MapType Default) { |
39 | MapType Mapped = static_cast<typename EndianType::value_type>(Val); |
40 | IO.mapOptional(Key, Mapped, Default); |
41 | Val = static_cast<typename EndianType::value_type>(Mapped); |
42 | } |
43 | |
44 | namespace { |
45 | /// Return the appropriate yaml Hex type for a given endian-aware type. |
46 | template <typename EndianType> struct HexType; |
47 | template <> struct HexType<support::ulittle16_t> { using type = yaml::Hex16; }; |
48 | template <> struct HexType<support::ulittle32_t> { using type = yaml::Hex32; }; |
49 | template <> struct HexType<support::ulittle64_t> { using type = yaml::Hex64; }; |
50 | } // namespace |
51 | |
52 | /// Yaml-map an endian-aware type as an appropriately-sized hex value. |
53 | template <typename EndianType> |
54 | static inline void mapRequiredHex(yaml::IO &IO, const char *Key, |
55 | EndianType &Val) { |
56 | mapRequiredAs<typename HexType<EndianType>::type>(IO, Key, Val); |
57 | } |
58 | |
59 | /// Perform an optional yaml-mapping of an endian-aware type as an |
60 | /// appropriately-sized hex value. |
61 | template <typename EndianType> |
62 | static inline void mapOptionalHex(yaml::IO &IO, const char *Key, |
63 | EndianType &Val, |
64 | typename EndianType::value_type Default) { |
65 | mapOptionalAs<typename HexType<EndianType>::type>(IO, Key, Val, Default); |
66 | } |
67 | |
68 | Stream::~Stream() = default; |
69 | |
70 | Stream::StreamKind Stream::getKind(StreamType Type) { |
71 | switch (Type) { |
72 | case StreamType::Exception: |
73 | return StreamKind::Exception; |
74 | case StreamType::MemoryInfoList: |
75 | return StreamKind::MemoryInfoList; |
76 | case StreamType::MemoryList: |
77 | return StreamKind::MemoryList; |
78 | case StreamType::ModuleList: |
79 | return StreamKind::ModuleList; |
80 | case StreamType::SystemInfo: |
81 | return StreamKind::SystemInfo; |
82 | case StreamType::LinuxCPUInfo: |
83 | case StreamType::LinuxProcStatus: |
84 | case StreamType::LinuxLSBRelease: |
85 | case StreamType::LinuxCMDLine: |
86 | case StreamType::LinuxMaps: |
87 | case StreamType::LinuxProcStat: |
88 | case StreamType::LinuxProcUptime: |
89 | return StreamKind::TextContent; |
90 | case StreamType::ThreadList: |
91 | return StreamKind::ThreadList; |
92 | default: |
93 | return StreamKind::RawContent; |
94 | } |
95 | } |
96 | |
97 | std::unique_ptr<Stream> Stream::create(StreamType Type) { |
98 | StreamKind Kind = getKind(Type); |
99 | switch (Kind) { |
100 | case StreamKind::Exception: |
101 | return std::make_unique<ExceptionStream>(); |
102 | case StreamKind::MemoryInfoList: |
103 | return std::make_unique<MemoryInfoListStream>(); |
104 | case StreamKind::MemoryList: |
105 | return std::make_unique<MemoryListStream>(); |
106 | case StreamKind::ModuleList: |
107 | return std::make_unique<ModuleListStream>(); |
108 | case StreamKind::RawContent: |
109 | return std::make_unique<RawContentStream>(args&: Type); |
110 | case StreamKind::SystemInfo: |
111 | return std::make_unique<SystemInfoStream>(); |
112 | case StreamKind::TextContent: |
113 | return std::make_unique<TextContentStream>(args&: Type); |
114 | case StreamKind::ThreadList: |
115 | return std::make_unique<ThreadListStream>(); |
116 | } |
117 | llvm_unreachable("Unhandled stream kind!" ); |
118 | } |
119 | |
120 | void yaml::ScalarBitSetTraits<MemoryProtection>::bitset( |
121 | IO &IO, MemoryProtection &Protect) { |
122 | #define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) \ |
123 | IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME); |
124 | #include "llvm/BinaryFormat/MinidumpConstants.def" |
125 | } |
126 | |
127 | void yaml::ScalarBitSetTraits<MemoryState>::bitset(IO &IO, MemoryState &State) { |
128 | #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) \ |
129 | IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME); |
130 | #include "llvm/BinaryFormat/MinidumpConstants.def" |
131 | } |
132 | |
133 | void yaml::ScalarBitSetTraits<MemoryType>::bitset(IO &IO, MemoryType &Type) { |
134 | #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) \ |
135 | IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME); |
136 | #include "llvm/BinaryFormat/MinidumpConstants.def" |
137 | } |
138 | |
139 | void yaml::ScalarEnumerationTraits<ProcessorArchitecture>::enumeration( |
140 | IO &IO, ProcessorArchitecture &Arch) { |
141 | #define HANDLE_MDMP_ARCH(CODE, NAME) \ |
142 | IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME); |
143 | #include "llvm/BinaryFormat/MinidumpConstants.def" |
144 | IO.enumFallback<Hex16>(Val&: Arch); |
145 | } |
146 | |
147 | void yaml::ScalarEnumerationTraits<OSPlatform>::enumeration(IO &IO, |
148 | OSPlatform &Plat) { |
149 | #define HANDLE_MDMP_PLATFORM(CODE, NAME) \ |
150 | IO.enumCase(Plat, #NAME, OSPlatform::NAME); |
151 | #include "llvm/BinaryFormat/MinidumpConstants.def" |
152 | IO.enumFallback<Hex32>(Val&: Plat); |
153 | } |
154 | |
155 | void yaml::ScalarEnumerationTraits<StreamType>::enumeration(IO &IO, |
156 | StreamType &Type) { |
157 | #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) \ |
158 | IO.enumCase(Type, #NAME, StreamType::NAME); |
159 | #include "llvm/BinaryFormat/MinidumpConstants.def" |
160 | IO.enumFallback<Hex32>(Val&: Type); |
161 | } |
162 | |
163 | void yaml::MappingTraits<CPUInfo::ArmInfo>::mapping(IO &IO, |
164 | CPUInfo::ArmInfo &Info) { |
165 | mapRequiredHex(IO, Key: "CPUID" , Val&: Info.CPUID); |
166 | mapOptionalHex(IO, Key: "ELF hwcaps" , Val&: Info.ElfHWCaps, Default: 0); |
167 | } |
168 | |
169 | namespace { |
170 | template <std::size_t N> struct FixedSizeHex { |
171 | FixedSizeHex(uint8_t (&Storage)[N]) : Storage(Storage) {} |
172 | |
173 | uint8_t (&Storage)[N]; |
174 | }; |
175 | } // namespace |
176 | |
177 | namespace llvm { |
178 | namespace yaml { |
179 | template <std::size_t N> struct ScalarTraits<FixedSizeHex<N>> { |
180 | static void output(const FixedSizeHex<N> &Fixed, void *, raw_ostream &OS) { |
181 | OS << toHex(ArrayRef(Fixed.Storage)); |
182 | } |
183 | |
184 | static StringRef input(StringRef Scalar, void *, FixedSizeHex<N> &Fixed) { |
185 | if (!all_of(Range&: Scalar, P: isHexDigit)) |
186 | return "Invalid hex digit in input" ; |
187 | if (Scalar.size() < 2 * N) |
188 | return "String too short" ; |
189 | if (Scalar.size() > 2 * N) |
190 | return "String too long" ; |
191 | copy(fromHex(Input: Scalar), Fixed.Storage); |
192 | return "" ; |
193 | } |
194 | |
195 | static QuotingType mustQuote(StringRef S) { return QuotingType::None; } |
196 | }; |
197 | } // namespace yaml |
198 | } // namespace llvm |
199 | void yaml::MappingTraits<CPUInfo::OtherInfo>::mapping( |
200 | IO &IO, CPUInfo::OtherInfo &Info) { |
201 | FixedSizeHex<sizeof(Info.ProcessorFeatures)> Features(Info.ProcessorFeatures); |
202 | IO.mapRequired(Key: "Features" , Val&: Features); |
203 | } |
204 | |
205 | namespace { |
206 | /// A type which only accepts strings of a fixed size for yaml conversion. |
207 | template <std::size_t N> struct FixedSizeString { |
208 | FixedSizeString(char (&Storage)[N]) : Storage(Storage) {} |
209 | |
210 | char (&Storage)[N]; |
211 | }; |
212 | } // namespace |
213 | |
214 | namespace llvm { |
215 | namespace yaml { |
216 | template <std::size_t N> struct ScalarTraits<FixedSizeString<N>> { |
217 | static void output(const FixedSizeString<N> &Fixed, void *, raw_ostream &OS) { |
218 | OS << StringRef(Fixed.Storage, N); |
219 | } |
220 | |
221 | static StringRef input(StringRef Scalar, void *, FixedSizeString<N> &Fixed) { |
222 | if (Scalar.size() < N) |
223 | return "String too short" ; |
224 | if (Scalar.size() > N) |
225 | return "String too long" ; |
226 | copy(Scalar, Fixed.Storage); |
227 | return "" ; |
228 | } |
229 | |
230 | static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } |
231 | }; |
232 | } // namespace yaml |
233 | } // namespace llvm |
234 | |
235 | void yaml::MappingTraits<CPUInfo::X86Info>::mapping(IO &IO, |
236 | CPUInfo::X86Info &Info) { |
237 | FixedSizeString<sizeof(Info.VendorID)> VendorID(Info.VendorID); |
238 | IO.mapRequired(Key: "Vendor ID" , Val&: VendorID); |
239 | |
240 | mapRequiredHex(IO, Key: "Version Info" , Val&: Info.VersionInfo); |
241 | mapRequiredHex(IO, Key: "Feature Info" , Val&: Info.FeatureInfo); |
242 | mapOptionalHex(IO, Key: "AMD Extended Features" , Val&: Info.AMDExtendedFeatures, Default: 0); |
243 | } |
244 | |
245 | void yaml::MappingTraits<MemoryInfo>::mapping(IO &IO, MemoryInfo &Info) { |
246 | mapRequiredHex(IO, Key: "Base Address" , Val&: Info.BaseAddress); |
247 | mapOptionalHex(IO, Key: "Allocation Base" , Val&: Info.AllocationBase, Default: Info.BaseAddress); |
248 | mapRequiredAs<MemoryProtection>(IO, Key: "Allocation Protect" , |
249 | Val&: Info.AllocationProtect); |
250 | mapOptionalHex(IO, Key: "Reserved0" , Val&: Info.Reserved0, Default: 0); |
251 | mapRequiredHex(IO, Key: "Region Size" , Val&: Info.RegionSize); |
252 | mapRequiredAs<MemoryState>(IO, Key: "State" , Val&: Info.State); |
253 | mapOptionalAs<MemoryProtection>(IO, Key: "Protect" , Val&: Info.Protect, |
254 | Default: Info.AllocationProtect); |
255 | mapRequiredAs<MemoryType>(IO, Key: "Type" , Val&: Info.Type); |
256 | mapOptionalHex(IO, Key: "Reserved1" , Val&: Info.Reserved1, Default: 0); |
257 | } |
258 | |
259 | void yaml::MappingTraits<VSFixedFileInfo>::mapping(IO &IO, |
260 | VSFixedFileInfo &Info) { |
261 | mapOptionalHex(IO, Key: "Signature" , Val&: Info.Signature, Default: 0); |
262 | mapOptionalHex(IO, Key: "Struct Version" , Val&: Info.StructVersion, Default: 0); |
263 | mapOptionalHex(IO, Key: "File Version High" , Val&: Info.FileVersionHigh, Default: 0); |
264 | mapOptionalHex(IO, Key: "File Version Low" , Val&: Info.FileVersionLow, Default: 0); |
265 | mapOptionalHex(IO, Key: "Product Version High" , Val&: Info.ProductVersionHigh, Default: 0); |
266 | mapOptionalHex(IO, Key: "Product Version Low" , Val&: Info.ProductVersionLow, Default: 0); |
267 | mapOptionalHex(IO, Key: "File Flags Mask" , Val&: Info.FileFlagsMask, Default: 0); |
268 | mapOptionalHex(IO, Key: "File Flags" , Val&: Info.FileFlags, Default: 0); |
269 | mapOptionalHex(IO, Key: "File OS" , Val&: Info.FileOS, Default: 0); |
270 | mapOptionalHex(IO, Key: "File Type" , Val&: Info.FileType, Default: 0); |
271 | mapOptionalHex(IO, Key: "File Subtype" , Val&: Info.FileSubtype, Default: 0); |
272 | mapOptionalHex(IO, Key: "File Date High" , Val&: Info.FileDateHigh, Default: 0); |
273 | mapOptionalHex(IO, Key: "File Date Low" , Val&: Info.FileDateLow, Default: 0); |
274 | } |
275 | |
276 | void yaml::MappingTraits<ModuleListStream::entry_type>::mapping( |
277 | IO &IO, ModuleListStream::entry_type &M) { |
278 | mapRequiredHex(IO, Key: "Base of Image" , Val&: M.Entry.BaseOfImage); |
279 | mapRequiredHex(IO, Key: "Size of Image" , Val&: M.Entry.SizeOfImage); |
280 | mapOptionalHex(IO, Key: "Checksum" , Val&: M.Entry.Checksum, Default: 0); |
281 | mapOptional(IO, Key: "Time Date Stamp" , Val&: M.Entry.TimeDateStamp, Default: 0); |
282 | IO.mapRequired(Key: "Module Name" , Val&: M.Name); |
283 | IO.mapOptional(Key: "Version Info" , Val&: M.Entry.VersionInfo, Default: VSFixedFileInfo()); |
284 | IO.mapRequired(Key: "CodeView Record" , Val&: M.CvRecord); |
285 | IO.mapOptional(Key: "Misc Record" , Val&: M.MiscRecord, Default: yaml::BinaryRef()); |
286 | mapOptionalHex(IO, Key: "Reserved0" , Val&: M.Entry.Reserved0, Default: 0); |
287 | mapOptionalHex(IO, Key: "Reserved1" , Val&: M.Entry.Reserved1, Default: 0); |
288 | } |
289 | |
290 | static void streamMapping(yaml::IO &IO, RawContentStream &Stream) { |
291 | IO.mapOptional(Key: "Content" , Val&: Stream.Content); |
292 | IO.mapOptional(Key: "Size" , Val&: Stream.Size, Default: Stream.Content.binary_size()); |
293 | } |
294 | |
295 | static std::string streamValidate(RawContentStream &Stream) { |
296 | if (Stream.Size.value < Stream.Content.binary_size()) |
297 | return "Stream size must be greater or equal to the content size" ; |
298 | return "" ; |
299 | } |
300 | |
301 | void yaml::MappingTraits<MemoryListStream::entry_type>::mapping( |
302 | IO &IO, MemoryListStream::entry_type &Range) { |
303 | MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping( |
304 | IO, Memory&: Range.Entry, Content&: Range.Content); |
305 | } |
306 | |
307 | static void streamMapping(yaml::IO &IO, MemoryInfoListStream &Stream) { |
308 | IO.mapRequired(Key: "Memory Ranges" , Val&: Stream.Infos); |
309 | } |
310 | |
311 | static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) { |
312 | IO.mapRequired(Key: "Memory Ranges" , Val&: Stream.Entries); |
313 | } |
314 | |
315 | static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) { |
316 | IO.mapRequired(Key: "Modules" , Val&: Stream.Entries); |
317 | } |
318 | |
319 | static void streamMapping(yaml::IO &IO, SystemInfoStream &Stream) { |
320 | SystemInfo &Info = Stream.Info; |
321 | IO.mapRequired(Key: "Processor Arch" , Val&: Info.ProcessorArch); |
322 | mapOptional(IO, Key: "Processor Level" , Val&: Info.ProcessorLevel, Default: 0); |
323 | mapOptional(IO, Key: "Processor Revision" , Val&: Info.ProcessorRevision, Default: 0); |
324 | IO.mapOptional(Key: "Number of Processors" , Val&: Info.NumberOfProcessors, Default: 0); |
325 | IO.mapOptional(Key: "Product type" , Val&: Info.ProductType, Default: 0); |
326 | mapOptional(IO, Key: "Major Version" , Val&: Info.MajorVersion, Default: 0); |
327 | mapOptional(IO, Key: "Minor Version" , Val&: Info.MinorVersion, Default: 0); |
328 | mapOptional(IO, Key: "Build Number" , Val&: Info.BuildNumber, Default: 0); |
329 | IO.mapRequired(Key: "Platform ID" , Val&: Info.PlatformId); |
330 | IO.mapOptional(Key: "CSD Version" , Val&: Stream.CSDVersion, Default: "" ); |
331 | mapOptionalHex(IO, Key: "Suite Mask" , Val&: Info.SuiteMask, Default: 0); |
332 | mapOptionalHex(IO, Key: "Reserved" , Val&: Info.Reserved, Default: 0); |
333 | switch (static_cast<ProcessorArchitecture>(Info.ProcessorArch)) { |
334 | case ProcessorArchitecture::X86: |
335 | case ProcessorArchitecture::AMD64: |
336 | IO.mapOptional(Key: "CPU" , Val&: Info.CPU.X86); |
337 | break; |
338 | case ProcessorArchitecture::ARM: |
339 | case ProcessorArchitecture::ARM64: |
340 | case ProcessorArchitecture::BP_ARM64: |
341 | IO.mapOptional(Key: "CPU" , Val&: Info.CPU.Arm); |
342 | break; |
343 | default: |
344 | IO.mapOptional(Key: "CPU" , Val&: Info.CPU.Other); |
345 | break; |
346 | } |
347 | } |
348 | |
349 | static void streamMapping(yaml::IO &IO, TextContentStream &Stream) { |
350 | IO.mapOptional(Key: "Text" , Val&: Stream.Text); |
351 | } |
352 | |
353 | void yaml::MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping( |
354 | IO &IO, MemoryDescriptor &Memory, BinaryRef &Content) { |
355 | mapRequiredHex(IO, Key: "Start of Memory Range" , Val&: Memory.StartOfMemoryRange); |
356 | IO.mapRequired(Key: "Content" , Val&: Content); |
357 | } |
358 | |
359 | void yaml::MappingTraits<ThreadListStream::entry_type>::mapping( |
360 | IO &IO, ThreadListStream::entry_type &T) { |
361 | mapRequiredHex(IO, Key: "Thread Id" , Val&: T.Entry.ThreadId); |
362 | mapOptionalHex(IO, Key: "Suspend Count" , Val&: T.Entry.SuspendCount, Default: 0); |
363 | mapOptionalHex(IO, Key: "Priority Class" , Val&: T.Entry.PriorityClass, Default: 0); |
364 | mapOptionalHex(IO, Key: "Priority" , Val&: T.Entry.Priority, Default: 0); |
365 | mapOptionalHex(IO, Key: "Environment Block" , Val&: T.Entry.EnvironmentBlock, Default: 0); |
366 | IO.mapRequired(Key: "Context" , Val&: T.Context); |
367 | IO.mapRequired(Key: "Stack" , Val&: T.Entry.Stack, Ctx&: T.Stack); |
368 | } |
369 | |
370 | static void streamMapping(yaml::IO &IO, ThreadListStream &Stream) { |
371 | IO.mapRequired(Key: "Threads" , Val&: Stream.Entries); |
372 | } |
373 | |
374 | static void streamMapping(yaml::IO &IO, MinidumpYAML::ExceptionStream &Stream) { |
375 | mapRequiredHex(IO, Key: "Thread ID" , Val&: Stream.MDExceptionStream.ThreadId); |
376 | IO.mapRequired(Key: "Exception Record" , Val&: Stream.MDExceptionStream.ExceptionRecord); |
377 | IO.mapRequired(Key: "Thread Context" , Val&: Stream.ThreadContext); |
378 | } |
379 | |
380 | void yaml::MappingTraits<minidump::Exception>::mapping( |
381 | yaml::IO &IO, minidump::Exception &Exception) { |
382 | mapRequiredHex(IO, Key: "Exception Code" , Val&: Exception.ExceptionCode); |
383 | mapOptionalHex(IO, Key: "Exception Flags" , Val&: Exception.ExceptionFlags, Default: 0); |
384 | mapOptionalHex(IO, Key: "Exception Record" , Val&: Exception.ExceptionRecord, Default: 0); |
385 | mapOptionalHex(IO, Key: "Exception Address" , Val&: Exception.ExceptionAddress, Default: 0); |
386 | mapOptional(IO, Key: "Number of Parameters" , Val&: Exception.NumberParameters, Default: 0); |
387 | |
388 | for (size_t Index = 0; Index < Exception.MaxParameters; ++Index) { |
389 | SmallString<16> Name("Parameter " ); |
390 | Twine(Index).toVector(Out&: Name); |
391 | support::ulittle64_t &Field = Exception.ExceptionInformation[Index]; |
392 | |
393 | if (Index < Exception.NumberParameters) |
394 | mapRequiredHex(IO, Key: Name.c_str(), Val&: Field); |
395 | else |
396 | mapOptionalHex(IO, Key: Name.c_str(), Val&: Field, Default: 0); |
397 | } |
398 | } |
399 | |
400 | void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping( |
401 | yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) { |
402 | StreamType Type; |
403 | if (IO.outputting()) |
404 | Type = S->Type; |
405 | IO.mapRequired(Key: "Type" , Val&: Type); |
406 | |
407 | if (!IO.outputting()) |
408 | S = MinidumpYAML::Stream::create(Type); |
409 | switch (S->Kind) { |
410 | case MinidumpYAML::Stream::StreamKind::Exception: |
411 | streamMapping(IO, Stream&: llvm::cast<MinidumpYAML::ExceptionStream>(Val&: *S)); |
412 | break; |
413 | case MinidumpYAML::Stream::StreamKind::MemoryInfoList: |
414 | streamMapping(IO, Stream&: llvm::cast<MemoryInfoListStream>(Val&: *S)); |
415 | break; |
416 | case MinidumpYAML::Stream::StreamKind::MemoryList: |
417 | streamMapping(IO, Stream&: llvm::cast<MemoryListStream>(Val&: *S)); |
418 | break; |
419 | case MinidumpYAML::Stream::StreamKind::ModuleList: |
420 | streamMapping(IO, Stream&: llvm::cast<ModuleListStream>(Val&: *S)); |
421 | break; |
422 | case MinidumpYAML::Stream::StreamKind::RawContent: |
423 | streamMapping(IO, Stream&: llvm::cast<RawContentStream>(Val&: *S)); |
424 | break; |
425 | case MinidumpYAML::Stream::StreamKind::SystemInfo: |
426 | streamMapping(IO, Stream&: llvm::cast<SystemInfoStream>(Val&: *S)); |
427 | break; |
428 | case MinidumpYAML::Stream::StreamKind::TextContent: |
429 | streamMapping(IO, Stream&: llvm::cast<TextContentStream>(Val&: *S)); |
430 | break; |
431 | case MinidumpYAML::Stream::StreamKind::ThreadList: |
432 | streamMapping(IO, Stream&: llvm::cast<ThreadListStream>(Val&: *S)); |
433 | break; |
434 | } |
435 | } |
436 | |
437 | std::string yaml::MappingTraits<std::unique_ptr<Stream>>::validate( |
438 | yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) { |
439 | switch (S->Kind) { |
440 | case MinidumpYAML::Stream::StreamKind::RawContent: |
441 | return streamValidate(Stream&: cast<RawContentStream>(Val&: *S)); |
442 | case MinidumpYAML::Stream::StreamKind::Exception: |
443 | case MinidumpYAML::Stream::StreamKind::MemoryInfoList: |
444 | case MinidumpYAML::Stream::StreamKind::MemoryList: |
445 | case MinidumpYAML::Stream::StreamKind::ModuleList: |
446 | case MinidumpYAML::Stream::StreamKind::SystemInfo: |
447 | case MinidumpYAML::Stream::StreamKind::TextContent: |
448 | case MinidumpYAML::Stream::StreamKind::ThreadList: |
449 | return "" ; |
450 | } |
451 | llvm_unreachable("Fully covered switch above!" ); |
452 | } |
453 | |
454 | void yaml::MappingTraits<Object>::mapping(IO &IO, Object &O) { |
455 | IO.mapTag(Tag: "!minidump" , Default: true); |
456 | mapOptionalHex(IO, Key: "Signature" , Val&: O.Header.Signature, Default: Header::MagicSignature); |
457 | mapOptionalHex(IO, Key: "Version" , Val&: O.Header.Version, Default: Header::MagicVersion); |
458 | mapOptionalHex(IO, Key: "Flags" , Val&: O.Header.Flags, Default: 0); |
459 | IO.mapRequired(Key: "Streams" , Val&: O.Streams); |
460 | } |
461 | |
462 | Expected<std::unique_ptr<Stream>> |
463 | Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) { |
464 | StreamKind Kind = getKind(Type: StreamDesc.Type); |
465 | switch (Kind) { |
466 | case StreamKind::Exception: { |
467 | Expected<const minidump::ExceptionStream &> ExpectedExceptionStream = |
468 | File.getExceptionStream(); |
469 | if (!ExpectedExceptionStream) |
470 | return ExpectedExceptionStream.takeError(); |
471 | Expected<ArrayRef<uint8_t>> ExpectedThreadContext = |
472 | File.getRawData(Desc: ExpectedExceptionStream->ThreadContext); |
473 | if (!ExpectedThreadContext) |
474 | return ExpectedThreadContext.takeError(); |
475 | return std::make_unique<ExceptionStream>(args: *ExpectedExceptionStream, |
476 | args&: *ExpectedThreadContext); |
477 | } |
478 | case StreamKind::MemoryInfoList: { |
479 | if (auto ExpectedList = File.getMemoryInfoList()) |
480 | return std::make_unique<MemoryInfoListStream>(args&: *ExpectedList); |
481 | else |
482 | return ExpectedList.takeError(); |
483 | } |
484 | case StreamKind::MemoryList: { |
485 | auto ExpectedList = File.getMemoryList(); |
486 | if (!ExpectedList) |
487 | return ExpectedList.takeError(); |
488 | std::vector<MemoryListStream::entry_type> Ranges; |
489 | for (const MemoryDescriptor &MD : *ExpectedList) { |
490 | auto ExpectedContent = File.getRawData(Desc: MD.Memory); |
491 | if (!ExpectedContent) |
492 | return ExpectedContent.takeError(); |
493 | Ranges.push_back(x: {.Entry: MD, .Content: *ExpectedContent}); |
494 | } |
495 | return std::make_unique<MemoryListStream>(args: std::move(Ranges)); |
496 | } |
497 | case StreamKind::ModuleList: { |
498 | auto ExpectedList = File.getModuleList(); |
499 | if (!ExpectedList) |
500 | return ExpectedList.takeError(); |
501 | std::vector<ModuleListStream::entry_type> Modules; |
502 | for (const Module &M : *ExpectedList) { |
503 | auto ExpectedName = File.getString(Offset: M.ModuleNameRVA); |
504 | if (!ExpectedName) |
505 | return ExpectedName.takeError(); |
506 | auto ExpectedCv = File.getRawData(Desc: M.CvRecord); |
507 | if (!ExpectedCv) |
508 | return ExpectedCv.takeError(); |
509 | auto ExpectedMisc = File.getRawData(Desc: M.MiscRecord); |
510 | if (!ExpectedMisc) |
511 | return ExpectedMisc.takeError(); |
512 | Modules.push_back( |
513 | x: {.Entry: M, .Name: std::move(*ExpectedName), .CvRecord: *ExpectedCv, .MiscRecord: *ExpectedMisc}); |
514 | } |
515 | return std::make_unique<ModuleListStream>(args: std::move(Modules)); |
516 | } |
517 | case StreamKind::RawContent: |
518 | return std::make_unique<RawContentStream>(args: StreamDesc.Type, |
519 | args: File.getRawStream(Stream: StreamDesc)); |
520 | case StreamKind::SystemInfo: { |
521 | auto ExpectedInfo = File.getSystemInfo(); |
522 | if (!ExpectedInfo) |
523 | return ExpectedInfo.takeError(); |
524 | auto ExpectedCSDVersion = File.getString(Offset: ExpectedInfo->CSDVersionRVA); |
525 | if (!ExpectedCSDVersion) |
526 | return ExpectedInfo.takeError(); |
527 | return std::make_unique<SystemInfoStream>(args: *ExpectedInfo, |
528 | args: std::move(*ExpectedCSDVersion)); |
529 | } |
530 | case StreamKind::TextContent: |
531 | return std::make_unique<TextContentStream>( |
532 | args: StreamDesc.Type, args: toStringRef(Input: File.getRawStream(Stream: StreamDesc))); |
533 | case StreamKind::ThreadList: { |
534 | auto ExpectedList = File.getThreadList(); |
535 | if (!ExpectedList) |
536 | return ExpectedList.takeError(); |
537 | std::vector<ThreadListStream::entry_type> Threads; |
538 | for (const Thread &T : *ExpectedList) { |
539 | auto ExpectedStack = File.getRawData(Desc: T.Stack.Memory); |
540 | if (!ExpectedStack) |
541 | return ExpectedStack.takeError(); |
542 | auto ExpectedContext = File.getRawData(Desc: T.Context); |
543 | if (!ExpectedContext) |
544 | return ExpectedContext.takeError(); |
545 | Threads.push_back(x: {.Entry: T, .Stack: *ExpectedStack, .Context: *ExpectedContext}); |
546 | } |
547 | return std::make_unique<ThreadListStream>(args: std::move(Threads)); |
548 | } |
549 | } |
550 | llvm_unreachable("Unhandled stream kind!" ); |
551 | } |
552 | |
553 | Expected<Object> Object::create(const object::MinidumpFile &File) { |
554 | std::vector<std::unique_ptr<Stream>> Streams; |
555 | Streams.reserve(n: File.streams().size()); |
556 | for (const Directory &StreamDesc : File.streams()) { |
557 | auto ExpectedStream = Stream::create(StreamDesc, File); |
558 | if (!ExpectedStream) |
559 | return ExpectedStream.takeError(); |
560 | Streams.push_back(x: std::move(*ExpectedStream)); |
561 | } |
562 | return Object(File.header(), std::move(Streams)); |
563 | } |
564 | |