An #ifdef CONFIG_PPC_FPU_REGS is missing in arch_ptrace() leading to the following Oops because [REGSET_FPR] entry is not initialised in native_regsets[]. [ 41.917608] BUG: Unable to handle kernel instruction fetch [ 41.922849] Faulting instruction address: 0xff8fd228 [ 41.927760] Oops: Kernel access of bad area, sig: 11 [#1] [ 41.933089] BE PAGE_SIZE=4K PREEMPT CMPC885 [ 41.940753] Modules linked in: [ 41.943768] CPU: 0 PID: 366 Comm: gdb Not tainted 5.12.0-rc5-s3k-dev-01666-g7aac86a0f057-dirty #4835 [ 41.952800] NIP: ff8fd228 LR: c004d9e0 CTR: ff8fd228 [ 41.957790] REGS: caae9df0 TRAP: 0400 Not tainted (5.12.0-rc5-s3k-dev-01666-g7aac86a0f057-dirty) [ 41.966741] MSR: 40009032 <EE,ME,IR,DR,RI> CR: 82004248 XER: 20000000 [ 41.973540] [ 41.973540] GPR00: c004d9b4 caae9eb0 c1b64f60 c1b64520 c0713cd4 caae9eb8 c1bacdfc 00000004 [ 41.973540] GPR08: 00000200 ff8fd228 c1bac700 00001032 28004242 1061aaf4 00000001 106d64a0 [ 41.973540] GPR16: 00000000 00000000 7fa0a774 10610000 7fa0aef9 00000000 10610000 7fa0a538 [ 41.973540] GPR24: 7fa0a580 7fa0a570 c1bacc00 c1b64520 c1bacc00 caae9ee8 00000108 c0713cd4 [ 42.009685] NIP [ff8fd228] 0xff8fd228 [ 42.013300] LR [c004d9e0] __regset_get+0x100/0x124 [ 42.018036] Call Trace: [ 42.020443] [caae9eb0] [c004d9b4] __regset_get+0xd4/0x124 (unreliable) [ 42.026899] [caae9ee0] [c004da94] copy_regset_to_user+0x5c/0xb0 [ 42.032751] [caae9f10] [c002f640] sys_ptrace+0xe4/0x588 [ 42.037915] [caae9f30] [c0011010] ret_from_syscall+0x0/0x28 [ 42.043422] --- interrupt: c00 at 0xfd1f8e4 [ 42.047553] NIP: 0fd1f8e4 LR: 1004a688 CTR: 00000000 [ 42.052544] REGS: caae9f40 TRAP: 0c00 Not tainted (5.12.0-rc5-s3k-dev-01666-g7aac86a0f057-dirty) [ 42.061494] MSR: 0000d032 <EE,PR,ME,IR,DR,RI> CR: 48004442 XER: 00000000 [ 42.068551] [ 42.068551] GPR00: 0000001a 7fa0a040 77dad7e0 0000000e 00000170 00000000 7fa0a078 00000004 [ 42.068551] GPR08: 00000000 108deb88 108dda40 106d6010 44004442 1061aaf4 00000001 106d64a0 [ 42.068551] GPR16: 00000000 00000000 7fa0a774 10610000 7fa0aef9 00000000 10610000 7fa0a538 [ 42.068551] GPR24: 7fa0a580 7fa0a570 1078fe00 1078fd70 1078fd70 00000170 0fdd3244 0000000d [ 42.104696] NIP [0fd1f8e4] 0xfd1f8e4 [ 42.108225] LR [1004a688] 0x1004a688 [ 42.111753] --- interrupt: c00 [ 42.114768] Instruction dump: [ 42.117698] XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX [ 42.125443] XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX [ 42.133195] ---[ end trace d35616f22ab2100c ]--- Adding the missing #ifdef is not good because gdb doesn't like getting an error when getting registers. Instead, make ptrace return 0s when CONFIG_PPC_FPU_REGS is not set. Fixes: b6254ced4da6 ("powerpc/signal: Don't manage floating point regs when no FPU") Cc: stable@vger.kernel.org Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/9121a44a2d50ba1af18d8aa5ada06c9a3bea8afd.1617200085.git.christophe.leroy@csgroup.eu
178 lines
6.3 KiB
C
178 lines
6.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/*
|
|
* Set of msr bits that gdb can change on behalf of a process.
|
|
*/
|
|
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
|
|
#define MSR_DEBUGCHANGE 0
|
|
#else
|
|
#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
|
|
#endif
|
|
|
|
/*
|
|
* Max register writeable via put_reg
|
|
*/
|
|
#ifdef CONFIG_PPC32
|
|
#define PT_MAX_PUT_REG PT_MQ
|
|
#else
|
|
#define PT_MAX_PUT_REG PT_CCR
|
|
#endif
|
|
|
|
#define TVSO(f) (offsetof(struct thread_vr_state, f))
|
|
#define TFSO(f) (offsetof(struct thread_fp_state, f))
|
|
#define TSO(f) (offsetof(struct thread_struct, f))
|
|
|
|
/*
|
|
* These are our native regset flavors.
|
|
*/
|
|
enum powerpc_regset {
|
|
REGSET_GPR,
|
|
REGSET_FPR,
|
|
#ifdef CONFIG_ALTIVEC
|
|
REGSET_VMX,
|
|
#endif
|
|
#ifdef CONFIG_VSX
|
|
REGSET_VSX,
|
|
#endif
|
|
#ifdef CONFIG_SPE
|
|
REGSET_SPE,
|
|
#endif
|
|
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
|
REGSET_TM_CGPR, /* TM checkpointed GPR registers */
|
|
REGSET_TM_CFPR, /* TM checkpointed FPR registers */
|
|
REGSET_TM_CVMX, /* TM checkpointed VMX registers */
|
|
REGSET_TM_CVSX, /* TM checkpointed VSX registers */
|
|
REGSET_TM_SPR, /* TM specific SPR registers */
|
|
REGSET_TM_CTAR, /* TM checkpointed TAR register */
|
|
REGSET_TM_CPPR, /* TM checkpointed PPR register */
|
|
REGSET_TM_CDSCR, /* TM checkpointed DSCR register */
|
|
#endif
|
|
#ifdef CONFIG_PPC64
|
|
REGSET_PPR, /* PPR register */
|
|
REGSET_DSCR, /* DSCR register */
|
|
#endif
|
|
#ifdef CONFIG_PPC_BOOK3S_64
|
|
REGSET_TAR, /* TAR register */
|
|
REGSET_EBB, /* EBB registers */
|
|
REGSET_PMR, /* Performance Monitor Registers */
|
|
#endif
|
|
#ifdef CONFIG_PPC_MEM_KEYS
|
|
REGSET_PKEY, /* AMR register */
|
|
#endif
|
|
};
|
|
|
|
/* ptrace-(no)vsx */
|
|
|
|
user_regset_get2_fn fpr_get;
|
|
int fpr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
|
|
/* ptrace-vsx */
|
|
|
|
int vsr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn vsr_get;
|
|
int vsr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
|
|
/* ptrace-altivec */
|
|
|
|
int vr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn vr_get;
|
|
int vr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
|
|
/* ptrace-spe */
|
|
|
|
int evr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn evr_get;
|
|
int evr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
|
|
/* ptrace */
|
|
|
|
int gpr32_get_common(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
struct membuf to,
|
|
unsigned long *regs);
|
|
int gpr32_set_common(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf,
|
|
unsigned long *regs);
|
|
|
|
/* ptrace-tm */
|
|
|
|
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
|
void flush_tmregs_to_thread(struct task_struct *tsk);
|
|
#else
|
|
static inline void flush_tmregs_to_thread(struct task_struct *tsk) { }
|
|
#endif
|
|
|
|
int tm_cgpr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_cgpr_get;
|
|
int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
int tm_cfpr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_cfpr_get;
|
|
int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
int tm_cvmx_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_cvmx_get;
|
|
int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
int tm_cvsx_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_cvsx_get;
|
|
int tm_cvsx_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
int tm_spr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_spr_get;
|
|
int tm_spr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
int tm_tar_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_tar_get;
|
|
int tm_tar_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
int tm_ppr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_ppr_get;
|
|
int tm_ppr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
int tm_dscr_active(struct task_struct *target, const struct user_regset *regset);
|
|
user_regset_get2_fn tm_dscr_get;
|
|
int tm_dscr_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
user_regset_get2_fn tm_cgpr32_get;
|
|
int tm_cgpr32_set(struct task_struct *target, const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf);
|
|
|
|
/* ptrace-view */
|
|
|
|
int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data);
|
|
int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data);
|
|
|
|
extern const struct user_regset_view user_ppc_native_view;
|
|
|
|
/* ptrace-fpu */
|
|
int ptrace_get_fpr(struct task_struct *child, int index, unsigned long *data);
|
|
int ptrace_put_fpr(struct task_struct *child, int index, unsigned long data);
|
|
|
|
/* ptrace-(no)adv */
|
|
void ppc_gethwdinfo(struct ppc_debug_info *dbginfo);
|
|
int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
|
|
unsigned long __user *datalp);
|
|
int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data);
|
|
long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_info);
|
|
long ppc_del_hwdebug(struct task_struct *child, long data);
|