// Copyright 2014 The Crashpad Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_
#define CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_

#include <windows.h>
#include <dbghelp.h>
#include <stdint.h>
#include <winnt.h>

#include "base/compiler_specific.h"
#include "build/build_config.h"
#include "util/misc/pdb_structures.h"
#include "util/misc/uuid.h"

#if defined(COMPILER_MSVC)
// C4200 is "nonstandard extension used : zero-sized array in struct/union".
// We would like to globally disable this warning, but unfortunately, the
// compiler is buggy and only supports disabling it with a pragma, so we can't
// disable it with other silly warnings in the build files. See:
//   https://connect.microsoft.com/VisualStudio/feedback/details/1114440
#pragma warning(push)
#pragma warning(disable: 4200)

#define PACKED
#pragma pack(push, 1)
#else
#define PACKED __attribute__((packed))
#endif  // COMPILER_MSVC

namespace crashpad {

//! \brief Minidump stream type values for MINIDUMP_DIRECTORY::StreamType. Each
//!     stream structure has a corresponding stream type value to identify it.
//!
//! \sa MINIDUMP_STREAM_TYPE
enum MinidumpStreamType : uint32_t {
  //! \brief The stream type for MINIDUMP_THREAD_LIST.
  //!
  //! \sa ThreadListStream
  kMinidumpStreamTypeThreadList = ThreadListStream,

  //! \brief The stream type for MINIDUMP_MODULE_LIST.
  //!
  //! \sa ModuleListStream
  kMinidumpStreamTypeModuleList = ModuleListStream,

  //! \brief The stream type for MINIDUMP_MEMORY_LIST.
  //!
  //! \sa MemoryListStream
  kMinidumpStreamTypeMemoryList = MemoryListStream,

  //! \brief The stream type for MINIDUMP_EXCEPTION_STREAM.
  //!
  //! \sa ExceptionStream
  kMinidumpStreamTypeException = ExceptionStream,

  //! \brief The stream type for MINIDUMP_SYSTEM_INFO.
  //!
  //! \sa SystemInfoStream
  kMinidumpStreamTypeSystemInfo = SystemInfoStream,

  //! \brief The stream type for MINIDUMP_HANDLE_DATA_STREAM.
  //!
  //! \sa HandleDataStream
  kMinidumpStreamTypeHandleData = HandleDataStream,

  //! \brief The stream type for MINIDUMP_UNLOADED_MODULE_LIST.
  //!
  //! \sa UnloadedModuleListStream
  kMinidumpStreamTypeUnloadedModuleList = UnloadedModuleListStream,

  //! \brief The stream type for MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO_2,
  //!     MINIDUMP_MISC_INFO_3, and MINIDUMP_MISC_INFO_4.
  //!
  //! \sa MiscInfoStream
  kMinidumpStreamTypeMiscInfo = MiscInfoStream,

  //! \brief The stream type for MINIDUMP_MEMORY_INFO_LIST.
  //!
  //! \sa MemoryInfoListStream
  kMinidumpStreamTypeMemoryInfoList = MemoryInfoListStream,

  //! \brief The stream type for MINIDUMP_THREAD_NAME_LIST.
  //!
  //! \sa ThreadNamesStream
  kMinidumpStreamTypeThreadNameList = ThreadNamesStream,

  //! \brief The last reserved minidump stream.
  //!
  //! \sa MemoryInfoListStream
  kMinidumpStreamTypeLastReservedStream = LastReservedStream,

  // 0x4350 = "CP"

  //! \brief The stream type for MinidumpCrashpadInfo.
  kMinidumpStreamTypeCrashpadInfo = 0x43500001,

  //! \brief The last reserved crashpad stream.
  kMinidumpStreamTypeCrashpadLastReservedStream = 0x4350ffff,

  // 0x5379 = "Sy"

  //! \brief The stream type for client-side stack traces.
  kMinidumpStreamTypeSentryStackTraces = 0x53790001,

  //! \brief The last reserved Sentry stream.
  kMinidumpStreamTypeSentryLastReservedStream = 0x5379ffff,
};

//! \brief A variable-length UTF-8-encoded string carried within a minidump
//!     file.
//!
//! \sa MINIDUMP_STRING
struct ALIGNAS(4) PACKED MinidumpUTF8String {
  // The field names do not conform to typical style, they match the names used
  // in MINIDUMP_STRING. This makes it easier to operate on MINIDUMP_STRING (for
  // UTF-16 strings) and MinidumpUTF8String using templates.

  //! \brief The length of the #Buffer field in bytes, not including the `NUL`
  //!     terminator.
  //!
  //! \note This field is interpreted as a byte count, not a count of Unicode
  //!     code points.
  uint32_t Length;

  //! \brief The string, encoded in UTF-8, and terminated with a `NUL` byte.
  uint8_t Buffer[0];
};

//! \brief A variable-length array of bytes carried within a minidump file.
//!     The data have no intrinsic type and should be interpreted according
//!     to their referencing context.
struct ALIGNAS(4) PACKED MinidumpByteArray {
  //! \brief The length of the #data field.
  uint32_t length;

  //! \brief The bytes of data.
  uint8_t data[0];
};

//! \brief CPU type values for MINIDUMP_SYSTEM_INFO::ProcessorArchitecture.
//!
//! \sa \ref PROCESSOR_ARCHITECTURE_x "PROCESSOR_ARCHITECTURE_*"
enum MinidumpCPUArchitecture : uint16_t {
  //! \brief 32-bit x86.
  //!
  //! These systems identify their CPUs generically as “x86” or “ia32”, or with
  //! more specific names such as “i386”, “i486”, “i586”, and “i686”.
  kMinidumpCPUArchitectureX86 = PROCESSOR_ARCHITECTURE_INTEL,

  kMinidumpCPUArchitectureMIPS = PROCESSOR_ARCHITECTURE_MIPS,
  kMinidumpCPUArchitectureAlpha = PROCESSOR_ARCHITECTURE_ALPHA,

  //! \brief 32-bit PowerPC.
  //!
  //! These systems identify their CPUs generically as “ppc”, or with more
  //! specific names such as “ppc6xx”, “ppc7xx”, and “ppc74xx”.
  kMinidumpCPUArchitecturePPC = PROCESSOR_ARCHITECTURE_PPC,

  kMinidumpCPUArchitectureSHx = PROCESSOR_ARCHITECTURE_SHX,

  //! \brief 32-bit ARM.
  //!
  //! These systems identify their CPUs generically as “arm”, or with more
  //! specific names such as “armv6” and “armv7”.
  kMinidumpCPUArchitectureARM = PROCESSOR_ARCHITECTURE_ARM,

  kMinidumpCPUArchitectureIA64 = PROCESSOR_ARCHITECTURE_IA64,
  kMinidumpCPUArchitectureAlpha64 = PROCESSOR_ARCHITECTURE_ALPHA64,
  kMinidumpCPUArchitectureMSIL = PROCESSOR_ARCHITECTURE_MSIL,

  //! \brief 64-bit x86.
  //!
  //! These systems identify their CPUs as “x86_64”, “amd64”, or “x64”.
  kMinidumpCPUArchitectureAMD64 = PROCESSOR_ARCHITECTURE_AMD64,

  //! \brief A 32-bit x86 process running on IA-64 (Itanium).
  //!
  //! \note This value is not used in minidump files for 32-bit x86 processes
  //!     running on a 64-bit-capable x86 CPU and operating system. In that
  //!     configuration, #kMinidumpCPUArchitectureX86 is used instead.
  kMinidumpCPUArchitectureX86Win64 = PROCESSOR_ARCHITECTURE_IA32_ON_WIN64,

  kMinidumpCPUArchitectureNeutral = PROCESSOR_ARCHITECTURE_NEUTRAL,

  //! \brief 64-bit ARM.
  //!
  //! These systems identify their CPUs generically as “arm64” or “aarch64”, or
  //! with more specific names such as “armv8”.
  //!
  //! \sa #kMinidumpCPUArchitectureARM64Breakpad
  kMinidumpCPUArchitectureARM64 = PROCESSOR_ARCHITECTURE_ARM64,

  kMinidumpCPUArchitectureARM32Win64 = PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64,
  kMinidumpCPUArchitectureSPARC = 0x8001,

  //! \brief 64-bit PowerPC.
  //!
  //! These systems identify their CPUs generically as “ppc64”, or with more
  //! specific names such as “ppc970”.
  kMinidumpCPUArchitecturePPC64 = 0x8002,

  //! \brief Used by Breakpad for 64-bit ARM.
  //!
  //! \deprecated Use #kMinidumpCPUArchitectureARM64 instead.
  kMinidumpCPUArchitectureARM64Breakpad = 0x8003,

  //! \brief Unknown CPU architecture.
  kMinidumpCPUArchitectureUnknown = PROCESSOR_ARCHITECTURE_UNKNOWN,
};

//! \brief Operating system type values for MINIDUMP_SYSTEM_INFO::ProductType.
//!
//! \sa \ref VER_NT_x "VER_NT_*"
enum MinidumpOSType : uint8_t {
  //! \brief A “desktop” or “workstation” system.
  kMinidumpOSTypeWorkstation = VER_NT_WORKSTATION,

  //! \brief A “domain controller” system. Windows-specific.
  kMinidumpOSTypeDomainController = VER_NT_DOMAIN_CONTROLLER,

  //! \brief A “server” system.
  kMinidumpOSTypeServer = VER_NT_SERVER,
};

//! \brief Operating system family values for MINIDUMP_SYSTEM_INFO::PlatformId.
//!
//! \sa \ref VER_PLATFORM_x "VER_PLATFORM_*"
enum MinidumpOS : uint32_t {
  //! \brief Windows 3.1.
  kMinidumpOSWin32s = VER_PLATFORM_WIN32s,

  //! \brief Windows 95, Windows 98, and Windows Me.
  kMinidumpOSWin32Windows = VER_PLATFORM_WIN32_WINDOWS,

  //! \brief Windows NT, Windows 2000, and later.
  kMinidumpOSWin32NT = VER_PLATFORM_WIN32_NT,

  kMinidumpOSUnix = 0x8000,

  //! \brief macOS, Darwin for traditional systems.
  kMinidumpOSMacOSX = 0x8101,

  //! \brief iOS, Darwin for mobile devices.
  kMinidumpOSIOS = 0x8102,

  //! \brief Linux, not including Android.
  kMinidumpOSLinux = 0x8201,

  kMinidumpOSSolaris = 0x8202,

  //! \brief Android.
  kMinidumpOSAndroid = 0x8203,

  kMinidumpOSPS3 = 0x8204,

  //! \brief Native Client (NaCl).
  kMinidumpOSNaCl = 0x8205,

  //! \brief Fuchsia.
  kMinidumpOSFuchsia = 0x8206,

  //! \brief Unknown operating system.
  kMinidumpOSUnknown = 0xffffffff,
};

//! \brief A list of ::RVA pointers.
struct ALIGNAS(4) PACKED MinidumpRVAList {
  //! \brief The number of children present in the #children array.
  uint32_t count;

  //! \brief Pointers to other structures in the minidump file.
  RVA children[0];
};

//! \brief A key-value pair.
struct ALIGNAS(4) PACKED MinidumpSimpleStringDictionaryEntry {
  //! \brief ::RVA of a MinidumpUTF8String containing the key of a key-value
  //!     pair.
  RVA key;

  //! \brief ::RVA of a MinidumpUTF8String containing the value of a key-value
  //!     pair.
  RVA value;
};

//! \brief A list of key-value pairs.
struct ALIGNAS(4) PACKED MinidumpSimpleStringDictionary {
  //! \brief The number of key-value pairs present.
  uint32_t count;

  //! \brief A list of MinidumpSimpleStringDictionaryEntry entries.
  MinidumpSimpleStringDictionaryEntry entries[0];
};

//! \brief A typed annotation object.
struct ALIGNAS(4) PACKED MinidumpAnnotation {
  //! \brief ::RVA of a MinidumpUTF8String containing the name of the
  //!     annotation.
  RVA name;

  //! \brief The type of data stored in the \a value of the annotation. This
  //!     may correspond to an \a Annotation::Type or it may be user-defined.
  uint16_t type;

  //! \brief This field is always `0`.
  uint16_t reserved;

  //! \brief ::RVA of a MinidumpByteArray to the data for the annotation.
  RVA value;
};

//! \brief A list of annotation objects.
struct ALIGNAS(4) PACKED MinidumpAnnotationList {
  //! \brief The number of annotation objects present.
  uint32_t count;

  //! \brief A list of MinidumpAnnotation objects.
  MinidumpAnnotation objects[0];
};

//! \brief Additional Crashpad-specific information about a module carried
//!     within a minidump file.
//!
//! This structure augments the information provided by MINIDUMP_MODULE. The
//! minidump file must contain a module list stream
//! (::kMinidumpStreamTypeModuleList) in order for this structure to appear.
//!
//! This structure is versioned. When changing this structure, leave the
//! existing structure intact so that earlier parsers will be able to understand
//! the fields they are aware of, and make additions at the end of the
//! structure. Revise #kVersion and document each field’s validity based on
//! #version, so that newer parsers will be able to determine whether the added
//! fields are valid or not.
//!
//! \sa MinidumpModuleCrashpadInfoList
struct ALIGNAS(4) PACKED MinidumpModuleCrashpadInfo {
  //! \brief The structure’s currently-defined version number.
  //!
  //! \sa version
  static constexpr uint32_t kVersion = 1;

  //! \brief The structure’s version number.
  //!
  //! Readers can use this field to determine which other fields in the
  //! structure are valid. Upon encountering a value greater than #kVersion, a
  //! reader should assume that the structure’s layout is compatible with the
  //! structure defined as having value #kVersion.
  //!
  //! Writers may produce values less than #kVersion in this field if there is
  //! no need for any fields present in later versions.
  uint32_t version;

  //! \brief A MinidumpRVAList pointing to MinidumpUTF8String objects. The
  //!     module controls the data that appears here.
  //!
  //! These strings correspond to ModuleSnapshot::AnnotationsVector() and do not
  //! duplicate anything in #simple_annotations or #annotation_objects.
  //!
  //! This field is present when #version is at least `1`.
  MINIDUMP_LOCATION_DESCRIPTOR list_annotations;

  //! \brief A MinidumpSimpleStringDictionary pointing to strings interpreted as
  //!     key-value pairs. The module controls the data that appears here.
  //!
  //! These key-value pairs correspond to
  //! ModuleSnapshot::AnnotationsSimpleMap() and do not duplicate anything in
  //! #list_annotations or #annotation_objects.
  //!
  //! This field is present when #version is at least `1`.
  MINIDUMP_LOCATION_DESCRIPTOR simple_annotations;

  //! \brief A MinidumpAnnotationList object containing the annotation objects
  //!     stored within the module. The module controls the data that appears
  //!     here.
  //!
  //! These key-value pairs correspond to ModuleSnapshot::AnnotationObjects()
  //! and do not duplicate anything in #list_annotations or #simple_annotations.
  //!
  //! This field may be present when #version is at least `1`.
  MINIDUMP_LOCATION_DESCRIPTOR annotation_objects;
};

//! \brief A link between a MINIDUMP_MODULE structure and additional
//!     Crashpad-specific information about a module carried within a minidump
//!     file.
struct ALIGNAS(4) PACKED MinidumpModuleCrashpadInfoLink {
  //! \brief A link to a MINIDUMP_MODULE structure in the module list stream.
  //!
  //! This field is an index into MINIDUMP_MODULE_LIST::Modules. This field’s
  //! value must be in the range of MINIDUMP_MODULE_LIST::NumberOfEntries.
  uint32_t minidump_module_list_index;

  //! \brief A link to a MinidumpModuleCrashpadInfo structure.
  //!
  //! MinidumpModuleCrashpadInfo structures are accessed indirectly through
  //! MINIDUMP_LOCATION_DESCRIPTOR pointers to allow for future growth of the
  //! MinidumpModuleCrashpadInfo structure.
  MINIDUMP_LOCATION_DESCRIPTOR location;
};

//! \brief Additional Crashpad-specific information about modules carried within
//!     a minidump file.
//!
//! This structure augments the information provided by
//! MINIDUMP_MODULE_LIST. The minidump file must contain a module list stream
//! (::kMinidumpStreamTypeModuleList) in order for this structure to appear.
//!
//! MinidumpModuleCrashpadInfoList::count may be less than the value of
//! MINIDUMP_MODULE_LIST::NumberOfModules because not every MINIDUMP_MODULE
//! structure carried within the minidump file will necessarily have
//! Crashpad-specific information provided by a MinidumpModuleCrashpadInfo
//! structure.
struct ALIGNAS(4) PACKED MinidumpModuleCrashpadInfoList {
  //! \brief The number of children present in the #modules array.
  uint32_t count;

  //! \brief Crashpad-specific information about modules, along with links to
  //!     MINIDUMP_MODULE structures that contain module information
  //!     traditionally carried within minidump files.
  MinidumpModuleCrashpadInfoLink modules[0];
};

//! \brief Additional Crashpad-specific information carried within a minidump
//!     file.
//!
//! This structure is versioned. When changing this structure, leave the
//! existing structure intact so that earlier parsers will be able to understand
//! the fields they are aware of, and make additions at the end of the
//! structure. Revise #kVersion and document each field’s validity based on
//! #version, so that newer parsers will be able to determine whether the added
//! fields are valid or not.
struct ALIGNAS(4) PACKED MinidumpCrashpadInfo {
  // UUID has a constructor, which makes it non-POD, which makes this structure
  // non-POD. In order for the default constructor to zero-initialize other
  // members, an explicit constructor must be provided.
  MinidumpCrashpadInfo()
      : version(),
        report_id(),
        client_id(),
        simple_annotations(),
        module_list() {
    }

  //! \brief The structure’s currently-defined version number.
  //!
  //! \sa version
  static constexpr uint32_t kVersion = 1;

  //! \brief The structure’s version number.
  //!
  //! Readers can use this field to determine which other fields in the
  //! structure are valid. Upon encountering a value greater than #kVersion, a
  //! reader should assume that the structure’s layout is compatible with the
  //! structure defined as having value #kVersion.
  //!
  //! Writers may produce values less than #kVersion in this field if there is
  //! no need for any fields present in later versions.
  uint32_t version;

  //! \brief A %UUID identifying an individual crash report.
  //!
  //! This provides a stable identifier for a crash even as the report is
  //! converted to different formats, provided that all formats support storing
  //! a crash report ID.
  //!
  //! If no identifier is available, this field will contain zeroes.
  //!
  //! This field is present when #version is at least `1`.
  UUID report_id;

  //! \brief A %UUID identifying the client that crashed.
  //!
  //! Client identification is within the scope of the application, but it is
  //! expected that the identifier will be unique for an instance of Crashpad
  //! monitoring an application or set of applications for a user. The
  //! identifier shall remain stable over time.
  //!
  //! If no identifier is available, this field will contain zeroes.
  //!
  //! This field is present when #version is at least `1`.
  UUID client_id;

  //! \brief A MinidumpSimpleStringDictionary pointing to strings interpreted as
  //!     key-value pairs.
  //!
  //! These key-value pairs correspond to
  //! ProcessSnapshot::AnnotationsSimpleMap().
  //!
  //! This field is present when #version is at least `1`.
  MINIDUMP_LOCATION_DESCRIPTOR simple_annotations;

  //! \brief A pointer to a MinidumpModuleCrashpadInfoList structure.
  //!
  //! This field is present when #version is at least `1`.
  MINIDUMP_LOCATION_DESCRIPTOR module_list;
};

#if defined(COMPILER_MSVC)
#pragma pack(pop)
#pragma warning(pop)  // C4200
#endif  // COMPILER_MSVC
#undef PACKED

}  // namespace crashpad

#endif  // CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_
