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