// 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_UTIL_LINUX_THREAD_INFO_H_ #define CRASHPAD_UTIL_LINUX_THREAD_INFO_H_ #include #include #include #include "build/build_config.h" #include "util/linux/address_types.h" #include "util/numeric/int128.h" #if BUILDFLAG(IS_ANDROID) #include #endif namespace crashpad { //! \brief The set of general purpose registers for an architecture family. union ThreadContext { ThreadContext(); ~ThreadContext(); //! \brief The general purpose registers used by the 32-bit variant of the //! architecture. struct t32_t { #if defined(ARCH_CPU_X86_FAMILY) // Reflects user_regs_struct in sys/user.h. uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t esi; uint32_t edi; uint32_t ebp; uint32_t eax; uint32_t xds; uint32_t xes; uint32_t xfs; uint32_t xgs; uint32_t orig_eax; uint32_t eip; uint32_t xcs; uint32_t eflags; uint32_t esp; uint32_t xss; #elif defined(ARCH_CPU_ARM_FAMILY) // Reflects user_regs in sys/user.h. uint32_t regs[11]; uint32_t fp; uint32_t ip; uint32_t sp; uint32_t lr; uint32_t pc; uint32_t cpsr; uint32_t orig_r0; #elif defined(ARCH_CPU_MIPS_FAMILY) // Reflects output format of static int gpr32_get(), defined in // arch/mips/kernel/ptrace.c in kernel source uint32_t padding0_[6]; uint32_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; uint32_t padding1_; #elif defined(ARCH_CPU_RISCV_FAMILY) // Reflects user_regs_struct in asm/ptrace.h. uint32_t pc; uint32_t ra; uint32_t sp; uint32_t gp; uint32_t tp; uint32_t t0; uint32_t t1; uint32_t t2; uint32_t s0; uint32_t s1; uint32_t a0; uint32_t a1; uint32_t a2; uint32_t a3; uint32_t a4; uint32_t a5; uint32_t a6; uint32_t a7; uint32_t s2; uint32_t s3; uint32_t s4; uint32_t s5; uint32_t s6; uint32_t s7; uint32_t s8; uint32_t s9; uint32_t s10; uint32_t s11; uint32_t t3; uint32_t t4; uint32_t t5; uint32_t t6; #else #error Port. #endif // ARCH_CPU_X86_FAMILY } t32; //! \brief The general purpose registers used by the 64-bit variant of the //! architecture. struct t64_t { #if defined(ARCH_CPU_X86_FAMILY) // Reflects user_regs_struct in sys/user.h. uint64_t r15; uint64_t r14; uint64_t r13; uint64_t r12; uint64_t rbp; uint64_t rbx; uint64_t r11; uint64_t r10; uint64_t r9; uint64_t r8; uint64_t rax; uint64_t rcx; uint64_t rdx; uint64_t rsi; uint64_t rdi; uint64_t orig_rax; uint64_t rip; uint64_t cs; uint64_t eflags; uint64_t rsp; uint64_t ss; uint64_t fs_base; uint64_t gs_base; uint64_t ds; uint64_t es; uint64_t fs; uint64_t gs; #elif defined(ARCH_CPU_ARM_FAMILY) // Reflects user_regs_struct in sys/user.h. uint64_t regs[31]; uint64_t sp; uint64_t pc; uint64_t pstate; #elif defined(ARCH_CPU_MIPS_FAMILY) // Reflects output format of static int gpr64_get(), defined in // arch/mips/kernel/ptrace.c in kernel source uint64_t regs[32]; uint64_t lo; uint64_t hi; uint64_t cp0_epc; uint64_t cp0_badvaddr; uint64_t cp0_status; uint64_t cp0_cause; #elif defined(ARCH_CPU_RISCV_FAMILY) // Reflects user_regs_struct in asm/ptrace.h. uint64_t pc; uint64_t ra; uint64_t sp; uint64_t gp; uint64_t tp; uint64_t t0; uint64_t t1; uint64_t t2; uint64_t s0; uint64_t s1; uint64_t a0; uint64_t a1; uint64_t a2; uint64_t a3; uint64_t a4; uint64_t a5; uint64_t a6; uint64_t a7; uint64_t s2; uint64_t s3; uint64_t s4; uint64_t s5; uint64_t s6; uint64_t s7; uint64_t s8; uint64_t s9; uint64_t s10; uint64_t s11; uint64_t t3; uint64_t t4; uint64_t t5; uint64_t t6; #else #error Port. #endif // ARCH_CPU_X86_FAMILY } t64; #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64) using NativeThreadContext = user_regs_struct; #elif defined(ARCH_CPU_ARMEL) using NativeThreadContext = user_regs; #elif defined(ARCH_CPU_MIPS_FAMILY) // No appropriate NativeThreadsContext type available for MIPS #elif defined(ARCH_CPU_RISCV_FAMILY) #else #error Port. #endif // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64 #if !defined(ARCH_CPU_MIPS_FAMILY) && !defined(ARCH_CPU_RISCV_FAMILY) #if defined(ARCH_CPU_32_BITS) static_assert(sizeof(t32_t) == sizeof(NativeThreadContext), "Size mismatch"); #else // ARCH_CPU_64_BITS static_assert(sizeof(t64_t) == sizeof(NativeThreadContext), "Size mismatch"); #endif // ARCH_CPU_32_BITS #endif // !ARCH_CPU_MIPS_FAMILY }; static_assert(std::is_standard_layout::value, "Not standard layout"); //! \brief The floating point registers used for an architecture family. union FloatContext { FloatContext(); ~FloatContext(); //! \brief The floating point registers used by the 32-bit variant of the //! architecture. struct f32_t { #if defined(ARCH_CPU_X86_FAMILY) // Reflects user_fpxregs_struct in sys/user.h struct fxsave { uint16_t cwd; uint16_t swd; uint16_t twd; uint16_t fop; uint32_t fip; uint32_t fcs; uint32_t foo; uint32_t fos; uint32_t mxcsr; uint32_t reserved; uint32_t st_space[32]; uint32_t xmm_space[32]; uint32_t padding[56]; } fxsave; #elif defined(ARCH_CPU_ARM_FAMILY) // Reflects user_fpregs in sys/user.h. struct fpregs { struct fp_reg { uint32_t sign1 : 1; uint32_t unused : 15; uint32_t sign2 : 1; uint32_t exponent : 14; uint32_t j : 1; uint32_t mantissa1 : 31; uint32_t mantisss0 : 32; } fpregs[8]; uint32_t fpsr : 32; uint32_t fpcr : 32; uint8_t type[8]; uint32_t init_flag; } fpregs; // Reflects user_vfp in sys/user.h. struct vfp_t { uint64_t fpregs[32]; uint32_t fpscr; } vfp; bool have_fpregs; bool have_vfp; #elif defined(ARCH_CPU_MIPS_FAMILY) // Reflects data format filled by ptrace_getfpregs() in // arch/mips/kernel/ptrace.c struct { float _fp_fregs; unsigned int _fp_pad; } fpregs[32]; uint32_t fpcsr; uint32_t fpu_id; #elif defined(ARCH_CPU_RISCV_FAMILY) uint64_t f[32]; uint32_t fcsr; #else #error Port. #endif // ARCH_CPU_X86_FAMILY } f32; //! \brief The floating point registers used by the 64-bit variant of the //! architecture. struct f64_t { #if defined(ARCH_CPU_X86_FAMILY) // Refelects user_fpregs_struct in sys/user.h struct fxsave { uint16_t cwd; uint16_t swd; uint16_t ftw; uint16_t fop; uint64_t rip; uint64_t rdp; uint32_t mxcsr; uint32_t mxcr_mask; uint32_t st_space[32]; uint32_t xmm_space[64]; uint32_t padding[24]; } fxsave; #elif defined(ARCH_CPU_ARM_FAMILY) uint128_struct vregs[32]; uint32_t fpsr; uint32_t fpcr; uint8_t padding[8]; #elif defined(ARCH_CPU_MIPS_FAMILY) // Reflects data format filled by ptrace_getfpregs() in // arch/mips/kernel/ptrace.c double fpregs[32]; uint32_t fpcsr; uint32_t fpu_id; #elif defined(ARCH_CPU_RISCV_FAMILY) uint64_t f[32]; uint32_t fcsr; #else #error Port. #endif // ARCH_CPU_X86_FAMILY } f64; #if defined(ARCH_CPU_X86) // __ANDROID_API_N__ is a proxy for determining whether unified headers are in // use. It’s only defined by unified headers. Unified headers call this // structure user_fpxregs_struct regardless of API level. #if BUILDFLAG(IS_ANDROID) && __ANDROID_API__ <= 19 && \ !defined(__ANDROID_API_N__) using NativeFpxregs = user_fxsr_struct; #else using NativeFpxregs = user_fpxregs_struct; #endif // BUILDFLAG(IS_ANDROID) static_assert(sizeof(f32_t::fxsave) == sizeof(NativeFpxregs), "Size mismatch"); #elif defined(ARCH_CPU_X86_64) static_assert(sizeof(f64_t::fxsave) == sizeof(user_fpregs_struct), "Size mismatch"); #elif defined(ARCH_CPU_ARMEL) static_assert(sizeof(f32_t::fpregs) == sizeof(user_fpregs), "Size mismatch"); #if !defined(__GLIBC__) static_assert(sizeof(f32_t::vfp) == sizeof(user_vfp), "Size mismatch"); #endif #elif defined(ARCH_CPU_ARM64) static_assert(sizeof(f64) == sizeof(user_fpsimd_struct), "Size mismatch"); #elif defined(ARCH_CPU_MIPS_FAMILY) // No appropriate floating point context native type for available MIPS. #elif defined(ARCH_CPU_RISCV_FAMILY) #else #error Port. #endif // ARCH_CPU_X86 }; static_assert(std::is_standard_layout::value, "Not standard layout"); //! \brief A collection of `ptrace`-able information about a thread. struct ThreadInfo { ThreadInfo(); ~ThreadInfo(); //! \brief The general purpose registers for the thread. ThreadContext thread_context; //! \brief The floating point registers for the thread. FloatContext float_context; //! \brief The thread-local storage address for the thread. LinuxVMAddress thread_specific_data_address; }; } // namespace crashpad #endif // CRASHPAD_UTIL_LINUX_THREAD_INFO_H_