435 lines
9.9 KiB
C++
435 lines
9.9 KiB
C++
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
|
//
|
|
// 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
|
|
|
|
#else
|
|
#error Port.
|
|
#endif // ARCH_CPU_X86_FAMILY
|
|
|
|
#pragma pack(pop)
|
|
|
|
} // namespace internal
|
|
} // namespace crashpad
|
|
|
|
#endif // CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_SIGNAL_CONTEXT_H_
|