chromium/third_party/crashpad/crashpad/snapshot/linux/signal_context.h

// Copyright 2017 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_SNAPSHOT_LINUX_SNAPSHOT_SIGNAL_CONTEXT_H_
#define CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_SIGNAL_CONTEXT_H_

#include <signal.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/ucontext.h>

#include <cstddef>
#include <type_traits>

#include "build/build_config.h"
#include "util/linux/thread_info.h"
#include "util/linux/traits.h"

namespace crashpad {
namespace internal {

#pragma pack(push, 1)

template <class Traits>
union Sigval {};

template <class Traits>
struct Siginfo {};

template <typename Traits>
struct SignalStack {};

template <typename Traits, typename Enable = void>
struct Sigset {};

Sigset<Traits, typename std::enable_if<std::is_base_of<Traits32, Traits>::value>::type>;

Sigset<Traits, typename std::enable_if<std::is_base_of<Traits64, Traits>::value>::type>;

#if defined(ARCH_CPU_X86_FAMILY)

struct SignalThreadContext32 {};

struct SignalThreadContext64 {};

struct SignalFloatContext32 {};

SignalFloatContext64;

struct ContextTraits32 : public Traits32 {};

struct ContextTraits64 : public Traits64 {};

template <typename Traits>
struct MContext {};

template <typename Traits>
struct UContext {};

#elif defined(ARCH_CPU_ARM_FAMILY)

struct CoprocessorContextHead {
  uint32_t magic;
  uint32_t size;
};

struct SignalFPSIMDContext {
  uint32_t fpsr;
  uint32_t fpcr;
  uint128_struct vregs[32];
};

struct SignalVFPContext {
  FloatContext::f32_t::vfp_t vfp;
  struct vfp_exc {
    uint32_t fpexc;
    uint32_t fpinst;
    uint32_t fpinst2;
  } vfp_exc;
  uint32_t padding;
};

struct SignalThreadContext32 {
  uint32_t regs[11];
  uint32_t fp;
  uint32_t ip;
  uint32_t sp;
  uint32_t lr;
  uint32_t pc;
  uint32_t cpsr;
};

using SignalThreadContext64 = ThreadContext::t64_t;

struct MContext32Data {
  uint32_t trap_no;
  uint32_t error_code;
  uint32_t oldmask;
  SignalThreadContext32 gprs;
  uint32_t fault_address;
};

struct MContext64Data {
  uint64_t fault_address;
  SignalThreadContext64 gprs;
};

struct ContextTraits32 : public Traits32 {
  using MContext32 = MContext32Data;
  using MContext64 = Nothing;
};

struct ContextTraits64 : public Traits64 {
  using MContext32 = Nothing;
  using MContext64 = MContext64Data;
};

template <typename Traits>
struct UContext {
  typename Traits::ULong flags;
  typename Traits::Address link;
  SignalStack<Traits> stack;
  typename Traits::MContext32 mcontext32;
  Sigset<Traits> sigmask;
  char padding[128 - sizeof(sigmask)];
  typename Traits::Char_64Only padding2[8];
  typename Traits::MContext64 mcontext64;
  typename Traits::Char_64Only padding3[8];
  char reserved[0];
};

#if defined(ARCH_CPU_ARMEL)
static_assert(offsetof(UContext<ContextTraits32>, mcontext32) ==
                  offsetof(ucontext_t, uc_mcontext),
              "context offset mismatch");
static_assert(offsetof(UContext<ContextTraits32>, reserved) ==
                  offsetof(ucontext_t, uc_regspace),
              "regspace offset mismatch");

#elif defined(ARCH_CPU_ARM64)
static_assert(offsetof(UContext<ContextTraits64>, mcontext64) ==
                  offsetof(ucontext_t, uc_mcontext),
              "context offset mismtach");
static_assert(offsetof(UContext<ContextTraits64>, reserved) ==
                  offsetof(ucontext_t, uc_mcontext) +
                      offsetof(mcontext_t, __reserved),
              "reserved space offset mismtach");
#endif

#elif defined(ARCH_CPU_MIPS_FAMILY)

struct MContext32 {
  uint32_t regmask;
  uint32_t status;
  uint64_t pc;
  uint64_t gregs[32];
  struct {
    float _fp_fregs;
    unsigned int _fp_pad;
  } fpregs[32];
  uint32_t fp_owned;
  uint32_t fpc_csr;
  uint32_t fpc_eir;
  uint32_t used_math;
  uint32_t dsp;
  uint64_t mdhi;
  uint64_t mdlo;
  uint32_t hi1;
  uint32_t lo1;
  uint32_t hi2;
  uint32_t lo2;
  uint32_t hi3;
  uint32_t lo3;
};

struct MContext64 {
  uint64_t gregs[32];
  double fpregs[32];
  uint64_t mdhi;
  uint64_t hi1;
  uint64_t hi2;
  uint64_t hi3;
  uint64_t mdlo;
  uint64_t lo1;
  uint64_t lo2;
  uint64_t lo3;
  uint64_t pc;
  uint32_t fpc_csr;
  uint32_t used_math;
  uint32_t dsp;
  uint32_t __glibc_reserved1;
};

struct SignalThreadContext32 {
  uint64_t regs[32];
  uint32_t lo;
  uint32_t hi;
  uint32_t cp0_epc;
  uint32_t cp0_badvaddr;
  uint32_t cp0_status;
  uint32_t cp0_cause;

  SignalThreadContext32() {}
  explicit SignalThreadContext32(
      const struct ThreadContext::t32_t& thread_context) {
    for (size_t reg = 0; reg < 32; ++reg) {
      regs[reg] = thread_context.regs[reg];
    }
    lo = thread_context.lo;
    hi = thread_context.hi;
    cp0_epc = thread_context.cp0_epc;
    cp0_badvaddr = thread_context.cp0_badvaddr;
    cp0_status = thread_context.cp0_status;
    cp0_cause = thread_context.cp0_cause;
  }
};

struct ContextTraits32 : public Traits32 {
  using MContext = MContext32;
  using SignalThreadContext = SignalThreadContext32;
  using SignalFloatContext = FloatContext::f32_t;
  using CPUContext = CPUContextMIPS;
};

struct ContextTraits64 : public Traits64 {
  using MContext = MContext64;
  using SignalThreadContext = ThreadContext::t64_t;
  using SignalFloatContext = FloatContext::f64_t;
  using CPUContext = CPUContextMIPS64;
};

template <typename Traits>
struct UContext {
  typename Traits::ULong flags;
  typename Traits::Address link;
  SignalStack<Traits> stack;
  typename Traits::ULong_32Only alignment_padding_;
  typename Traits::MContext mcontext;
  Sigset<Traits> sigmask;
};

#if defined(ARCH_CPU_MIPSEL)
static_assert(offsetof(UContext<ContextTraits32>, mcontext) ==
                  offsetof(ucontext_t, uc_mcontext),
              "context offset mismatch");
static_assert(offsetof(UContext<ContextTraits32>, mcontext.gregs) ==
                  offsetof(ucontext_t, uc_mcontext.gregs),
              "context offset mismatch");
static_assert(offsetof(UContext<ContextTraits32>, mcontext.fpregs) ==
                  offsetof(ucontext_t, uc_mcontext.fpregs),
              "context offset mismatch");

#elif defined(ARCH_CPU_MIPS64EL)
static_assert(offsetof(UContext<ContextTraits64>, mcontext) ==
                  offsetof(ucontext_t, uc_mcontext),
              "context offset mismtach");
static_assert(offsetof(UContext<ContextTraits64>, mcontext.gregs) ==
                  offsetof(ucontext_t, uc_mcontext.gregs),
              "context offset mismatch");
static_assert(offsetof(UContext<ContextTraits64>, mcontext.fpregs) ==
                  offsetof(ucontext_t, uc_mcontext.fpregs),
              "context offset mismatch");
#endif

#elif defined(ARCH_CPU_RISCV64)

struct ContextTraits64 : public Traits64 {
  using SignalThreadContext = ThreadContext::t64_t;
  using SignalFloatContext = FloatContext::f64_t;
  using CPUContext = CPUContextRISCV64;
};

struct MContext64 {
  ThreadContext::t64_t regs;
  FloatContext::f64_t fpregs;
};

template <typename Traits>
struct UContext {
  typename Traits::ULong flags;
  typename Traits::Address link;
  SignalStack<Traits> stack;
  Sigset<Traits> sigmask;
  char alignment_padding_[8];
  char padding[128 - sizeof(Sigset<Traits>)];
  MContext64 mcontext;
};

static_assert(offsetof(UContext<ContextTraits64>, mcontext) ==
                  offsetof(ucontext_t, uc_mcontext),
              "context offset mismatch");
static_assert(offsetof(UContext<ContextTraits64>, mcontext.regs) ==
                  offsetof(ucontext_t, uc_mcontext.__gregs),
              "context offset mismatch");
static_assert(offsetof(UContext<ContextTraits64>, mcontext.fpregs) ==
                  offsetof(ucontext_t, uc_mcontext.__fpregs),
              "context offset mismatch");

#else
#error Port.
#endif  // ARCH_CPU_X86_FAMILY

#pragma pack(pop)

}  // namespace internal
}  // namespace crashpad

#endif  // CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_SIGNAL_CONTEXT_H_