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 
17 namespace llvm {
18 namespace 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.
27 struct 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 
57 namespace 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.
61 template <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.
73 struct 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.
84 struct 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.
94 struct 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 
103 using ModuleListStream = detail::ListStream<detail::ParsedModule>;
104 using ThreadListStream = detail::ListStream<detail::ParsedThread>;
105 using MemoryListStream = detail::ListStream<detail::ParsedMemoryDescriptor>;
106 
107 /// ExceptionStream minidump stream.
108 struct 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.
128 struct 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.
148 struct 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.
162 struct 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.
182 LLVM_YAML_STRONG_TYPEDEF(StringRef, BlockStringRef)
183 
184 /// A minidump stream containing textual data (typically, the contents of a
185 /// /proc/<pid> file on linux).
186 struct 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.
201 struct 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 
223 namespace yaml {
224 template <> 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 
237 template <> struct MappingTraits<std::unique_ptr<MinidumpYAML::Stream>> {
238   static void mapping(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
239   static std::string validate(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
240 };
241 
242 template <> 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 
251 LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryProtection)
252 LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryState)
253 LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryType)
254 
255 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::ProcessorArchitecture)
256 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::OSPlatform)
257 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::StreamType)
258 
259 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::ArmInfo)
260 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo)
261 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
262 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::Exception)
263 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryInfo)
264 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
265 
266 LLVM_YAML_DECLARE_MAPPING_TRAITS(
267     llvm::MinidumpYAML::MemoryListStream::entry_type)
268 LLVM_YAML_DECLARE_MAPPING_TRAITS(
269     llvm::MinidumpYAML::ModuleListStream::entry_type)
270 LLVM_YAML_DECLARE_MAPPING_TRAITS(
271     llvm::MinidumpYAML::ThreadListStream::entry_type)
272 
273 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>)
274 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type)
275 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
276 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
277 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryInfo)
278 
279 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
280 
281 #endif // LLVM_OBJECTYAML_MINIDUMPYAML_H
282