#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
#pragma pack(pop)
}
}
#endif