1//===- MinidumpYAML.h - Minidump YAMLIO implementation ----------*- C++ -*-===//
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#ifndef LLVM_OBJECTYAML_MINIDUMPYAML_H
10#define LLVM_OBJECTYAML_MINIDUMPYAML_H
11
12#include "llvm/BinaryFormat/Minidump.h"
13#include "llvm/Object/Minidump.h"
14#include "llvm/ObjectYAML/YAML.h"
15#include "llvm/Support/YAMLTraits.h"
16
17namespace llvm {
18namespace MinidumpYAML {
19
20/// The base class for all minidump streams. The "Type" of the stream
21/// corresponds to the Stream Type field in the minidump file. The "Kind" field
22/// specifies how are we going to treat it. For highly specialized streams (e.g.
23/// SystemInfo), there is a 1:1 mapping between Types and Kinds, but in general
24/// one stream Kind can be used to represent multiple stream Types (e.g. any
25/// unrecognised stream Type will be handled via RawContentStream). The mapping
26/// from Types to Kinds is fixed and given by the static getKind function.
27struct Stream {
28 enum class StreamKind {
29 Exception,
30 MemoryInfoList,
31 MemoryList,
32 Memory64List,
33 ModuleList,
34 RawContent,
35 SystemInfo,
36 TextContent,
37 ThreadList,
38 };
39
40 Stream(StreamKind Kind, minidump::StreamType Type) : Kind(Kind), Type(Type) {}
41 virtual ~Stream(); // anchor
42
43 const StreamKind Kind;
44 const minidump::StreamType Type;
45
46 /// Get the stream Kind used for representing streams of a given Type.
47 static StreamKind getKind(minidump::StreamType Type);
48
49 /// Create an empty stream of the given Type.
50 static std::unique_ptr<Stream> create(minidump::StreamType Type);
51
52 /// Create a stream from the given stream directory entry.
53 static Expected<std::unique_ptr<Stream>>
54 create(const minidump::Directory &StreamDesc,
55 const object::MinidumpFile &File);
56};
57
58namespace detail {
59/// A stream representing a list of abstract entries in a minidump stream. Its
60/// instantiations can be used to represent the ModuleList stream and other
61/// streams with a similar structure.
62template <typename EntryT> struct ListStream : public Stream {
63 using entry_type = EntryT;
64
65 std::vector<entry_type> Entries;
66
67 explicit ListStream(std::vector<entry_type> Entries = {})
68 : Stream(EntryT::Kind, EntryT::Type), Entries(std::move(Entries)) {}
69
70 static bool classof(const Stream *S) { return S->Kind == EntryT::Kind; }
71};
72
73/// A structure containing all data belonging to a single minidump module.
74struct ParsedModule {
75 static constexpr Stream::StreamKind Kind = Stream::StreamKind::ModuleList;
76 static constexpr minidump::StreamType Type = minidump::StreamType::ModuleList;
77
78 minidump::Module Entry;
79 std::string Name;
80 yaml::BinaryRef CvRecord;
81 yaml::BinaryRef MiscRecord;
82};
83
84/// A structure containing all data belonging to a single minidump thread.
85struct ParsedThread {
86 static constexpr Stream::StreamKind Kind = Stream::StreamKind::ThreadList;
87 static constexpr minidump::StreamType Type = minidump::StreamType::ThreadList;
88
89 minidump::Thread Entry;
90 yaml::BinaryRef Stack;
91 yaml::BinaryRef Context;
92};
93
94/// A structure containing all data describing a single memory region.
95struct ParsedMemoryDescriptor {
96 static constexpr Stream::StreamKind Kind = Stream::StreamKind::MemoryList;
97 static constexpr minidump::StreamType Type = minidump::StreamType::MemoryList;
98
99 minidump::MemoryDescriptor Entry;
100 yaml::BinaryRef Content;
101};
102
103struct ParsedMemory64Descriptor {
104 static constexpr Stream::StreamKind Kind = Stream::StreamKind::Memory64List;
105 static constexpr minidump::StreamType Type =
106 minidump::StreamType::Memory64List;
107
108 minidump::MemoryDescriptor_64 Entry;
109 yaml::BinaryRef Content;
110};
111} // namespace detail
112
113using ModuleListStream = detail::ListStream<detail::ParsedModule>;
114using ThreadListStream = detail::ListStream<detail::ParsedThread>;
115using MemoryListStream = detail::ListStream<detail::ParsedMemoryDescriptor>;
116
117struct Memory64ListStream
118 : public detail::ListStream<detail::ParsedMemory64Descriptor> {
119 minidump::Memory64ListHeader Header;
120
121 explicit Memory64ListStream(
122 std::vector<detail::ParsedMemory64Descriptor> Entries = {})
123 : ListStream(Entries) {}
124};
125
126/// ExceptionStream minidump stream.
127struct ExceptionStream : public Stream {
128 minidump::ExceptionStream MDExceptionStream;
129 yaml::BinaryRef ThreadContext;
130
131 ExceptionStream()
132 : Stream(StreamKind::Exception, minidump::StreamType::Exception),
133 MDExceptionStream({}) {}
134
135 explicit ExceptionStream(const minidump::ExceptionStream &MDExceptionStream,
136 ArrayRef<uint8_t> ThreadContext)
137 : Stream(StreamKind::Exception, minidump::StreamType::Exception),
138 MDExceptionStream(MDExceptionStream), ThreadContext(ThreadContext) {}
139
140 static bool classof(const Stream *S) {
141 return S->Kind == StreamKind::Exception;
142 }
143};
144
145/// A structure containing the list of MemoryInfo entries comprising a
146/// MemoryInfoList stream.
147struct MemoryInfoListStream : public Stream {
148 std::vector<minidump::MemoryInfo> Infos;
149
150 MemoryInfoListStream()
151 : Stream(StreamKind::MemoryInfoList,
152 minidump::StreamType::MemoryInfoList) {}
153
154 explicit MemoryInfoListStream(
155 iterator_range<object::MinidumpFile::MemoryInfoIterator> Range)
156 : Stream(StreamKind::MemoryInfoList,
157 minidump::StreamType::MemoryInfoList),
158 Infos(Range.begin(), Range.end()) {}
159
160 static bool classof(const Stream *S) {
161 return S->Kind == StreamKind::MemoryInfoList;
162 }
163};
164
165/// A minidump stream represented as a sequence of hex bytes. This is used as a
166/// fallback when no other stream kind is suitable.
167struct RawContentStream : public Stream {
168 yaml::BinaryRef Content;
169 yaml::Hex32 Size;
170
171 RawContentStream(minidump::StreamType Type, ArrayRef<uint8_t> Content = {})
172 : Stream(StreamKind::RawContent, Type), Content(Content),
173 Size(Content.size()) {}
174
175 static bool classof(const Stream *S) {
176 return S->Kind == StreamKind::RawContent;
177 }
178};
179
180/// SystemInfo minidump stream.
181struct SystemInfoStream : public Stream {
182 minidump::SystemInfo Info;
183 std::string CSDVersion;
184
185 SystemInfoStream()
186 : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo) {
187 memset(s: &Info, c: 0, n: sizeof(Info));
188 }
189
190 explicit SystemInfoStream(const minidump::SystemInfo &Info,
191 std::string CSDVersion)
192 : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo),
193 Info(Info), CSDVersion(std::move(CSDVersion)) {}
194
195 static bool classof(const Stream *S) {
196 return S->Kind == StreamKind::SystemInfo;
197 }
198};
199
200/// A StringRef, which is printed using YAML block notation.
201LLVM_YAML_STRONG_TYPEDEF(StringRef, BlockStringRef)
202
203/// A minidump stream containing textual data (typically, the contents of a
204/// /proc/<pid> file on linux).
205struct TextContentStream : public Stream {
206 BlockStringRef Text;
207
208 TextContentStream(minidump::StreamType Type, StringRef Text = {})
209 : Stream(StreamKind::TextContent, Type), Text(Text) {}
210
211 static bool classof(const Stream *S) {
212 return S->Kind == StreamKind::TextContent;
213 }
214};
215
216/// The top level structure representing a minidump object, consisting of a
217/// minidump header, and zero or more streams. To construct an Object from a
218/// minidump file, use the static create function. To serialize to/from yaml,
219/// use the appropriate streaming operator on a yaml stream.
220struct Object {
221 Object() = default;
222 Object(const Object &) = delete;
223 Object &operator=(const Object &) = delete;
224 Object(Object &&) = default;
225 Object &operator=(Object &&) = default;
226
227 Object(const minidump::Header &Header,
228 std::vector<std::unique_ptr<Stream>> Streams)
229 : Header(Header), Streams(std::move(Streams)) {}
230
231 /// The minidump header.
232 minidump::Header Header;
233
234 /// The list of streams in this minidump object.
235 std::vector<std::unique_ptr<Stream>> Streams;
236
237 static Expected<Object> create(const object::MinidumpFile &File);
238};
239
240} // namespace MinidumpYAML
241
242namespace yaml {
243template <> struct BlockScalarTraits<MinidumpYAML::BlockStringRef> {
244 static void output(const MinidumpYAML::BlockStringRef &Text, void *,
245 raw_ostream &OS) {
246 OS << Text;
247 }
248
249 static StringRef input(StringRef Scalar, void *,
250 MinidumpYAML::BlockStringRef &Text) {
251 Text = Scalar;
252 return "";
253 }
254};
255
256template <> struct MappingTraits<std::unique_ptr<MinidumpYAML::Stream>> {
257 static void mapping(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
258 static std::string validate(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
259};
260
261template <> struct MappingContextTraits<minidump::MemoryDescriptor, BinaryRef> {
262 static void mapping(IO &IO, minidump::MemoryDescriptor &Memory,
263 BinaryRef &Content);
264};
265
266template <>
267struct MappingContextTraits<minidump::MemoryDescriptor_64, BinaryRef> {
268 static void mapping(IO &IO, minidump::MemoryDescriptor_64 &Memory,
269 BinaryRef &Content);
270};
271
272} // namespace yaml
273
274} // namespace llvm
275
276LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryProtection)
277LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryState)
278LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryType)
279
280LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::ProcessorArchitecture)
281LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::OSPlatform)
282LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::StreamType)
283
284LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::ArmInfo)
285LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo)
286LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
287LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::Exception)
288LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryInfo)
289LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
290
291LLVM_YAML_DECLARE_MAPPING_TRAITS(
292 llvm::MinidumpYAML::MemoryListStream::entry_type)
293LLVM_YAML_DECLARE_MAPPING_TRAITS(
294 llvm::MinidumpYAML::ModuleListStream::entry_type)
295LLVM_YAML_DECLARE_MAPPING_TRAITS(
296 llvm::MinidumpYAML::ThreadListStream::entry_type)
297LLVM_YAML_DECLARE_MAPPING_TRAITS(
298 llvm::MinidumpYAML::Memory64ListStream::entry_type)
299
300LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>)
301LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type)
302LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
303LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
304LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::Memory64ListStream::entry_type)
305LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryInfo)
306
307LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
308
309#endif // LLVM_OBJECTYAML_MINIDUMPYAML_H
310