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 StreamStream39 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 = {}) StreamListStream67 : Stream(EntryT::Kind, EntryT::Type), Entries(std::move(Entries)) {} 68 classofListStream69 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 ExceptionStreamExceptionStream112 ExceptionStream() 113 : Stream(StreamKind::Exception, minidump::StreamType::Exception), 114 MDExceptionStream({}) {} 115 ExceptionStreamExceptionStream116 explicit ExceptionStream(const minidump::ExceptionStream &MDExceptionStream, 117 ArrayRef<uint8_t> ThreadContext) 118 : Stream(StreamKind::Exception, minidump::StreamType::Exception), 119 MDExceptionStream(MDExceptionStream), ThreadContext(ThreadContext) {} 120 classofExceptionStream121 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 MemoryInfoListStreamMemoryInfoListStream131 MemoryInfoListStream() 132 : Stream(StreamKind::MemoryInfoList, 133 minidump::StreamType::MemoryInfoList) {} 134 MemoryInfoListStreamMemoryInfoListStream135 explicit MemoryInfoListStream( 136 iterator_range<object::MinidumpFile::MemoryInfoIterator> Range) 137 : Stream(StreamKind::MemoryInfoList, 138 minidump::StreamType::MemoryInfoList), 139 Infos(Range.begin(), Range.end()) {} 140 classofMemoryInfoListStream141 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 = {}) StreamRawContentStream153 : Stream(StreamKind::RawContent, Type), Content(Content), 154 Size(Content.size()) {} 155 classofRawContentStream156 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 SystemInfoStreamSystemInfoStream166 SystemInfoStream() 167 : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo) { 168 memset(&Info, 0, sizeof(Info)); 169 } 170 SystemInfoStreamSystemInfoStream171 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 classofSystemInfoStream176 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 = {}) StreamTextContentStream190 : Stream(StreamKind::TextContent, Type), Text(Text) {} 191 classofTextContentStream192 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 ObjectObject208 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