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