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