@@ -215,12 +215,78 @@ void ptrace_disable(struct task_struct *child)
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
+static inline unsigned long ptrace_get_gpr_reg(struct task_struct *child, unsigned long offset)
+{
+ struct pt_regs *regs = task_pt_regs(child);
+
+ return *((unsigned long *)regs + offset / sizeof(regs->a0));
+}
+
+static inline int ptrace_set_gpr_reg(struct task_struct *child, unsigned long offset,
+ unsigned long data)
+{
+ struct pt_regs *regs = task_pt_regs(child);
+
+ *((unsigned long *)regs + offset / sizeof(regs->a0)) = data;
+ return 0;
+}
+
+#ifdef CONFIG_FPU
+static inline unsigned long ptrace_get_fpr_reg(struct task_struct *child, unsigned long offset)
+{
+ struct __riscv_d_ext_state *fstate = &child->thread.fstate;
+
+ if (offset <= offsetof(struct __riscv_d_ext_state, f[31]))
+ return fstate->f[offset / sizeof(fstate->f[0])];
+ else if (offset == offsetof(struct __riscv_d_ext_state, fcsr))
+ return fstate->fcsr;
+ return -EIO;
+}
+
+static inline int ptrace_set_fpr_reg(struct task_struct *child, unsigned long offset,
+ unsigned long data)
+{
+ struct __riscv_d_ext_state *fstate = &child->thread.fstate;
+
+ if (offset <= offsetof(struct __riscv_d_ext_state, f[31]))
+ fstate->f[offset / sizeof(fstate->f[0])] = data;
+ else /* Only f[0] ~ f[31] can write by PTRACE_POKEUSR */
+ return -EIO;
+ return 0;
+}
+#endif
+
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
long ret = -EIO;
+ unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
+ case PTRACE_PEEKUSR:
+ case PTRACE_POKEUSR:
+ /* addr must be aligned to register size */
+ if (addr & (sizeof(addr) - 1))
+ break;
+
+ if (addr < sizeof(struct user_regs_struct)) {
+ if (request == PTRACE_PEEKUSR)
+ ret = put_user(ptrace_get_gpr_reg(child, addr), datap);
+ else // PTRACE_POKEUSR
+ ret = ptrace_set_gpr_reg(child, addr, data);
+#ifdef CONFIG_FPU
+ } else if (addr < (sizeof(struct user_regs_struct) +
+ sizeof(struct __riscv_d_ext_state))) {
+ addr -= sizeof(struct user_regs_struct);
+ if (request == PTRACE_PEEKUSR)
+ ret = put_user(ptrace_get_fpr_reg(child, addr), datap);
+ else // PTRACE_POKEUSR
+ ret = ptrace_set_fpr_reg(child, addr, data);
+#endif
+ } else {
+ // addr invalid
+ }
+ break;
default:
ret = ptrace_request(child, request, addr, data);
break;
Implement PTRACE_{PEEK,POKE}USR for RV64 user app to peek/poke tracee's space register. As the Linux manual page say: the addr is define to a word offset in the tracee's USER area.In riscv it's defined in: struct user { struct user_regs { ulong pc; // addr 0 ulong ra; // addr 8 ... ... ulong t6; // addr 248 } struct d_ext_state { u64 f[0]; // addr 256 ... ... u64 f[31]; // addr 504 u32 fcsr; // addr 512 read-only } } Signed-off-by: Yipeng Zou <zouyipeng@huawei.com> --- arch/riscv/kernel/ptrace.c | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)