//===- MinidumpYAML.h - Minidump YAMLIO implementation ----------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_OBJECTYAML_MINIDUMPYAML_H
 
#define LLVM_OBJECTYAML_MINIDUMPYAML_H
 
 
 
#include "llvm/BinaryFormat/Minidump.h"
 
#include "llvm/Object/Minidump.h"
 
#include "llvm/ObjectYAML/YAML.h"
 
#include "llvm/Support/YAMLTraits.h"
 
 
 
namespace llvm {
 
namespace MinidumpYAML {
 
 
 
/// The base class for all minidump streams. The "Type" of the stream
 
/// corresponds to the Stream Type field in the minidump file. The "Kind" field
 
/// specifies how are we going to treat it. For highly specialized streams (e.g.
 
/// SystemInfo), there is a 1:1 mapping between Types and Kinds, but in general
 
/// one stream Kind can be used to represent multiple stream Types (e.g. any
 
/// unrecognised stream Type will be handled via RawContentStream). The mapping
 
/// from Types to Kinds is fixed and given by the static getKind function.
 
struct Stream {
 
  enum class StreamKind {
 
    Exception,
 
    MemoryInfoList,
 
    MemoryList,
 
    ModuleList,
 
    RawContent,
 
    SystemInfo,
 
    TextContent,
 
    ThreadList,
 
  };
 
 
 
  Stream(StreamKind Kind, minidump::StreamType Type) : Kind(Kind), Type(Type) {}
 
  virtual ~Stream(); // anchor
 
 
 
  const StreamKind Kind;
 
  const minidump::StreamType Type;
 
 
 
  /// Get the stream Kind used for representing streams of a given Type.
 
  static StreamKind getKind(minidump::StreamType Type);
 
 
 
  /// Create an empty stream of the given Type.
 
  static std::unique_ptr<Stream> create(minidump::StreamType Type);
 
 
 
  /// Create a stream from the given stream directory entry.
 
  static Expected<std::unique_ptr<Stream>>
 
  create(const minidump::Directory &StreamDesc,
 
         const object::MinidumpFile &File);
 
};
 
 
 
namespace detail {
 
/// A stream representing a list of abstract entries in a minidump stream. Its
 
/// instantiations can be used to represent the ModuleList stream and other
 
/// streams with a similar structure.
 
template <typename EntryT> struct ListStream : public Stream {
 
  using entry_type = EntryT;
 
 
 
  std::vector<entry_type> Entries;
 
 
 
  explicit ListStream(std::vector<entry_type> Entries = {})
 
      : Stream(EntryT::Kind, EntryT::Type), Entries(std::move(Entries)) {}
 
 
 
  static bool classof(const Stream *S) { return S->Kind == EntryT::Kind; }
 
};
 
 
 
/// A structure containing all data belonging to a single minidump module.
 
struct ParsedModule {
 
  static constexpr Stream::StreamKind Kind = Stream::StreamKind::ModuleList;
 
  static constexpr minidump::StreamType Type = minidump::StreamType::ModuleList;
 
 
 
  minidump::Module Entry;
 
  std::string Name;
 
  yaml::BinaryRef CvRecord;
 
  yaml::BinaryRef MiscRecord;
 
};
 
 
 
/// A structure containing all data belonging to a single minidump thread.
 
struct ParsedThread {
 
  static constexpr Stream::StreamKind Kind = Stream::StreamKind::ThreadList;
 
  static constexpr minidump::StreamType Type = minidump::StreamType::ThreadList;
 
 
 
  minidump::Thread Entry;
 
  yaml::BinaryRef Stack;
 
  yaml::BinaryRef Context;
 
};
 
 
 
/// A structure containing all data describing a single memory region.
 
struct ParsedMemoryDescriptor {
 
  static constexpr Stream::StreamKind Kind = Stream::StreamKind::MemoryList;
 
  static constexpr minidump::StreamType Type = minidump::StreamType::MemoryList;
 
 
 
  minidump::MemoryDescriptor Entry;
 
  yaml::BinaryRef Content;
 
};
 
} // namespace detail
 
 
 
using ModuleListStream = detail::ListStream<detail::ParsedModule>;
 
using ThreadListStream = detail::ListStream<detail::ParsedThread>;
 
using MemoryListStream = detail::ListStream<detail::ParsedMemoryDescriptor>;
 
 
 
/// ExceptionStream minidump stream.
 
struct ExceptionStream : public Stream {
 
  minidump::ExceptionStream MDExceptionStream;
 
  yaml::BinaryRef ThreadContext;
 
 
 
  ExceptionStream()
 
      : Stream(StreamKind::Exception, minidump::StreamType::Exception),
 
        MDExceptionStream({}) {}
 
 
 
  explicit ExceptionStream(const minidump::ExceptionStream &MDExceptionStream,
 
                           ArrayRef<uint8_t> ThreadContext)
 
      : Stream(StreamKind::Exception, minidump::StreamType::Exception),
 
        MDExceptionStream(MDExceptionStream), ThreadContext(ThreadContext) {}
 
 
 
  static bool classof(const Stream *S) {
 
    return S->Kind == StreamKind::Exception;
 
  }
 
};
 
 
 
/// A structure containing the list of MemoryInfo entries comprising a
 
/// MemoryInfoList stream.
 
struct MemoryInfoListStream : public Stream {
 
  std::vector<minidump::MemoryInfo> Infos;
 
 
 
  MemoryInfoListStream()
 
      : Stream(StreamKind::MemoryInfoList,
 
               minidump::StreamType::MemoryInfoList) {}
 
 
 
  explicit MemoryInfoListStream(
 
      iterator_range<object::MinidumpFile::MemoryInfoIterator> Range)
 
      : Stream(StreamKind::MemoryInfoList,
 
               minidump::StreamType::MemoryInfoList),
 
        Infos(Range.begin(), Range.end()) {}
 
 
 
  static bool classof(const Stream *S) {
 
    return S->Kind == StreamKind::MemoryInfoList;
 
  }
 
};
 
 
 
/// A minidump stream represented as a sequence of hex bytes. This is used as a
 
/// fallback when no other stream kind is suitable.
 
struct RawContentStream : public Stream {
 
  yaml::BinaryRef Content;
 
  yaml::Hex32 Size;
 
 
 
  RawContentStream(minidump::StreamType Type, ArrayRef<uint8_t> Content = {})
 
      : Stream(StreamKind::RawContent, Type), Content(Content),
 
        Size(Content.size()) {}
 
 
 
  static bool classof(const Stream *S) {
 
    return S->Kind == StreamKind::RawContent;
 
  }
 
};
 
 
 
/// SystemInfo minidump stream.
 
struct SystemInfoStream : public Stream {
 
  minidump::SystemInfo Info;
 
  std::string CSDVersion;
 
 
 
  SystemInfoStream()
 
      : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo) {
 
    memset(&Info, 0, sizeof(Info));
 
  }
 
 
 
  explicit SystemInfoStream(const minidump::SystemInfo &Info,
 
                            std::string CSDVersion)
 
      : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo),
 
        Info(Info), CSDVersion(std::move(CSDVersion)) {}
 
 
 
  static bool classof(const Stream *S) {
 
    return S->Kind == StreamKind::SystemInfo;
 
  }
 
};
 
 
 
/// A StringRef, which is printed using YAML block notation.
 
LLVM_YAML_STRONG_TYPEDEF(StringRef, BlockStringRef)
 
 
 
/// A minidump stream containing textual data (typically, the contents of a
 
/// /proc/<pid> file on linux).
 
struct TextContentStream : public Stream {
 
  BlockStringRef Text;
 
 
 
  TextContentStream(minidump::StreamType Type, StringRef Text = {})
 
      : Stream(StreamKind::TextContent, Type), Text(Text) {}
 
 
 
  static bool classof(const Stream *S) {
 
    return S->Kind == StreamKind::TextContent;
 
  }
 
};
 
 
 
/// The top level structure representing a minidump object, consisting of a
 
/// minidump header, and zero or more streams. To construct an Object from a
 
/// minidump file, use the static create function. To serialize to/from yaml,
 
/// use the appropriate streaming operator on a yaml stream.
 
struct Object {
 
  Object() = default;
 
  Object(const Object &) = delete;
 
  Object &operator=(const Object &) = delete;
 
  Object(Object &&) = default;
 
  Object &operator=(Object &&) = default;
 
 
 
  Object(const minidump::Header &Header,
 
         std::vector<std::unique_ptr<Stream>> Streams)
 
      : Header(Header), Streams(std::move(Streams)) {}
 
 
 
  /// The minidump header.
 
  minidump::Header Header;
 
 
 
  /// The list of streams in this minidump object.
 
  std::vector<std::unique_ptr<Stream>> Streams;
 
 
 
  static Expected<Object> create(const object::MinidumpFile &File);
 
};
 
 
 
} // namespace MinidumpYAML
 
 
 
namespace yaml {
 
template <> struct BlockScalarTraits<MinidumpYAML::BlockStringRef> {
 
  static void output(const MinidumpYAML::BlockStringRef &Text, void *,
 
                     raw_ostream &OS) {
 
    OS << Text;
 
  }
 
 
 
  static StringRef input(StringRef Scalar, void *,
 
                         MinidumpYAML::BlockStringRef &Text) {
 
    Text = Scalar;
 
    return "";
 
  }
 
};
 
 
 
template <> struct MappingTraits<std::unique_ptr<MinidumpYAML::Stream>> {
 
  static void mapping(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
 
  static std::string validate(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
 
};
 
 
 
template <> struct MappingContextTraits<minidump::MemoryDescriptor, BinaryRef> {
 
  static void mapping(IO &IO, minidump::MemoryDescriptor &Memory,
 
                      BinaryRef &Content);
 
};
 
 
 
} // namespace yaml
 
 
 
} // namespace llvm
 
 
 
LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryProtection)
 
LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryState)
 
LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryType)
 
 
 
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::ProcessorArchitecture)
 
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::OSPlatform)
 
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::StreamType)
 
 
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::ArmInfo)
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo)
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::Exception)
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryInfo)
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
 
 
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(
 
    llvm::MinidumpYAML::MemoryListStream::entry_type)
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(
 
    llvm::MinidumpYAML::ModuleListStream::entry_type)
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(
 
    llvm::MinidumpYAML::ThreadListStream::entry_type)
 
 
 
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>)
 
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type)
 
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
 
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
 
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryInfo)
 
 
 
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
 
 
 
#endif // LLVM_OBJECTYAML_MINIDUMPYAML_H