| // 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 { |
| int32_t sigval; |
| typename Traits::Address pointer; |
| }; |
| |
| template <class Traits> |
| struct Siginfo { |
| int32_t signo; |
| #ifdef ARCH_CPU_MIPS_FAMILY |
| // Attribute order for signo_t defined in kernel is different for MIPS. |
| int32_t code; |
| int32_t err; |
| #else |
| int32_t err; |
| int32_t code; |
| #endif |
| typename Traits::UInteger32_64Only padding; |
| |
| union { |
| // SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGTRAP |
| struct { |
| typename Traits::Address address; |
| }; |
| |
| // SIGPOLL |
| struct { |
| typename Traits::Long band; |
| int32_t fd; |
| }; |
| |
| // SIGSYS |
| struct { |
| typename Traits::Address call_address; |
| int32_t syscall; |
| uint32_t arch; |
| }; |
| |
| // Everything else |
| struct { |
| union { |
| struct { |
| pid_t pid; |
| uid_t uid; |
| }; |
| struct { |
| int32_t timerid; |
| int32_t overrun; |
| }; |
| }; |
| |
| union { |
| Sigval<Traits> sigval; |
| |
| // SIGCHLD |
| struct { |
| int32_t status; |
| typename Traits::Clock utime; |
| typename Traits::Clock stime; |
| }; |
| }; |
| }; |
| }; |
| }; |
| |
| template <typename Traits> |
| struct SignalStack { |
| typename Traits::Address stack_pointer; |
| uint32_t flags; |
| typename Traits::UInteger32_64Only padding; |
| typename Traits::Size size; |
| }; |
| |
| template <typename Traits, typename Enable = void> |
| struct Sigset {}; |
| |
| template <typename Traits> |
| struct Sigset< |
| Traits, |
| typename std::enable_if<std::is_base_of<Traits32, Traits>::value>::type> { |
| uint64_t val; |
| }; |
| |
| template <typename Traits> |
| struct Sigset< |
| Traits, |
| typename std::enable_if<std::is_base_of<Traits64, Traits>::value>::type> { |
| #if BUILDFLAG(IS_ANDROID) |
| uint64_t val; |
| #else |
| typename Traits::ULong val[16]; |
| #endif // BUILDFLAG(IS_ANDROID) |
| }; |
| |
| #if defined(ARCH_CPU_X86_FAMILY) |
| |
| struct SignalThreadContext32 { |
| uint32_t xgs; |
| uint32_t xfs; |
| uint32_t xes; |
| uint32_t xds; |
| uint32_t edi; |
| uint32_t esi; |
| uint32_t ebp; |
| uint32_t esp; |
| uint32_t ebx; |
| uint32_t edx; |
| uint32_t ecx; |
| uint32_t eax; |
| uint32_t trapno; |
| uint32_t err; |
| uint32_t eip; |
| uint32_t xcs; |
| uint32_t eflags; |
| uint32_t uesp; |
| uint32_t xss; |
| }; |
| |
| struct SignalThreadContext64 { |
| uint64_t r8; |
| uint64_t r9; |
| uint64_t r10; |
| uint64_t r11; |
| uint64_t r12; |
| uint64_t r13; |
| uint64_t r14; |
| uint64_t r15; |
| uint64_t rdi; |
| uint64_t rsi; |
| uint64_t rbp; |
| uint64_t rbx; |
| uint64_t rdx; |
| uint64_t rax; |
| uint64_t rcx; |
| uint64_t rsp; |
| uint64_t rip; |
| uint64_t eflags; |
| uint16_t cs; |
| uint16_t gs; |
| uint16_t fs; |
| uint16_t padding; |
| uint64_t err; |
| uint64_t trapno; |
| uint64_t oldmask; |
| uint64_t cr2; |
| }; |
| |
| struct SignalFloatContext32 { |
| CPUContextX86::Fsave fsave; |
| uint16_t status; |
| uint16_t magic; |
| CPUContextX86::Fxsave fxsave[0]; |
| }; |
| |
| using SignalFloatContext64 = CPUContextX86_64::Fxsave; |
| |
| struct ContextTraits32 : public Traits32 { |
| using ThreadContext = SignalThreadContext32; |
| using FloatContext = SignalFloatContext32; |
| }; |
| |
| struct ContextTraits64 : public Traits64 { |
| using ThreadContext = SignalThreadContext64; |
| using FloatContext = SignalFloatContext64; |
| }; |
| |
| template <typename Traits> |
| struct MContext { |
| typename Traits::ThreadContext gprs; |
| typename Traits::Address fpptr; |
| typename Traits::ULong_32Only oldmask; |
| typename Traits::ULong_32Only cr2; |
| typename Traits::ULong_64Only reserved[8]; |
| }; |
| |
| template <typename Traits> |
| struct UContext { |
| typename Traits::ULong flags; |
| typename Traits::Address link; |
| SignalStack<Traits> stack; |
| MContext<Traits> mcontext; |
| Sigset<Traits> sigmask; |
| char fpregs_mem[0]; |
| }; |
| |
| #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_ |