xref: /llvm-project/llvm/include/llvm/ObjectYAML/MinidumpYAML.h (revision b1edac0496f47374c9780f3f83c6773eed73a66e)
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     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 
58 namespace 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.
62 template <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.
74 struct 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.
85 struct 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.
95 struct 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 
103 struct 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 
113 using ModuleListStream = detail::ListStream<detail::ParsedModule>;
114 using ThreadListStream = detail::ListStream<detail::ParsedThread>;
115 using MemoryListStream = detail::ListStream<detail::ParsedMemoryDescriptor>;
116 
117 struct 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.
127 struct 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.
147 struct 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.
167 struct 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.
181 struct SystemInfoStream : public Stream {
182   minidump::SystemInfo Info;
183   std::string CSDVersion;
184 
185   SystemInfoStream()
186       : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo) {
187     memset(&Info, 0, 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.
201 LLVM_YAML_STRONG_TYPEDEF(StringRef, BlockStringRef)
202 
203 /// A minidump stream containing textual data (typically, the contents of a
204 /// /proc/<pid> file on linux).
205 struct 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.
220 struct 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 
242 namespace yaml {
243 template <> 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 
256 template <> 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 
261 template <> struct MappingContextTraits<minidump::MemoryDescriptor, BinaryRef> {
262   static void mapping(IO &IO, minidump::MemoryDescriptor &Memory,
263                       BinaryRef &Content);
264 };
265 
266 template <>
267 struct 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 
276 LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryProtection)
277 LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryState)
278 LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryType)
279 
280 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::ProcessorArchitecture)
281 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::OSPlatform)
282 LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::StreamType)
283 
284 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::ArmInfo)
285 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo)
286 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
287 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::Exception)
288 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryInfo)
289 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
290 
291 LLVM_YAML_DECLARE_MAPPING_TRAITS(
292     llvm::MinidumpYAML::MemoryListStream::entry_type)
293 LLVM_YAML_DECLARE_MAPPING_TRAITS(
294     llvm::MinidumpYAML::ModuleListStream::entry_type)
295 LLVM_YAML_DECLARE_MAPPING_TRAITS(
296     llvm::MinidumpYAML::ThreadListStream::entry_type)
297 LLVM_YAML_DECLARE_MAPPING_TRAITS(
298     llvm::MinidumpYAML::Memory64ListStream::entry_type)
299 
300 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>)
301 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type)
302 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
303 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
304 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::Memory64ListStream::entry_type)
305 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryInfo)
306 
307 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
308 
309 #endif // LLVM_OBJECTYAML_MINIDUMPYAML_H
310