// 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 #include #include #include #include #include #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 union Sigval { int32_t sigval; typename Traits::Address pointer; }; template 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 sigval; // SIGCHLD struct { int32_t status; typename Traits::Clock utime; typename Traits::Clock stime; }; }; }; }; }; template struct SignalStack { typename Traits::Address stack_pointer; uint32_t flags; typename Traits::UInteger32_64Only padding; typename Traits::Size size; }; template struct Sigset {}; template struct Sigset< Traits, typename std::enable_if::value>::type> { uint64_t val; }; template struct Sigset< Traits, typename std::enable_if::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 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 struct UContext { typename Traits::ULong flags; typename Traits::Address link; SignalStack stack; MContext mcontext; Sigset 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 struct UContext { typename Traits::ULong flags; typename Traits::Address link; SignalStack stack; typename Traits::MContext32 mcontext32; Sigset 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, mcontext32) == offsetof(ucontext_t, uc_mcontext), "context offset mismatch"); static_assert(offsetof(UContext, reserved) == offsetof(ucontext_t, uc_regspace), "regspace offset mismatch"); #elif defined(ARCH_CPU_ARM64) static_assert(offsetof(UContext, mcontext64) == offsetof(ucontext_t, uc_mcontext), "context offset mismtach"); static_assert(offsetof(UContext, 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 struct UContext { typename Traits::ULong flags; typename Traits::Address link; SignalStack stack; typename Traits::ULong_32Only alignment_padding_; typename Traits::MContext mcontext; Sigset sigmask; }; #if defined(ARCH_CPU_MIPSEL) static_assert(offsetof(UContext, mcontext) == offsetof(ucontext_t, uc_mcontext), "context offset mismatch"); static_assert(offsetof(UContext, mcontext.gregs) == offsetof(ucontext_t, uc_mcontext.gregs), "context offset mismatch"); static_assert(offsetof(UContext, mcontext.fpregs) == offsetof(ucontext_t, uc_mcontext.fpregs), "context offset mismatch"); #elif defined(ARCH_CPU_MIPS64EL) static_assert(offsetof(UContext, mcontext) == offsetof(ucontext_t, uc_mcontext), "context offset mismtach"); static_assert(offsetof(UContext, mcontext.gregs) == offsetof(ucontext_t, uc_mcontext.gregs), "context offset mismatch"); static_assert(offsetof(UContext, 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 struct UContext { typename Traits::ULong flags; typename Traits::Address link; SignalStack stack; Sigset sigmask; char alignment_padding_[8]; char padding[128 - sizeof(Sigset)]; MContext64 mcontext; }; static_assert(offsetof(UContext, mcontext) == offsetof(ucontext_t, uc_mcontext), "context offset mismatch"); static_assert(offsetof(UContext, mcontext.regs) == offsetof(ucontext_t, uc_mcontext.__gregs), "context offset mismatch"); static_assert(offsetof(UContext, 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_