ptrace.c (4508B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * OpenRISC ptrace.c 4 * 5 * Linux architectural port borrowing liberally from similar works of 6 * others. All original copyrights apply as per the original source 7 * declaration. 8 * 9 * Modifications for the OpenRISC architecture: 10 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 11 * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com> 12 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 13 */ 14 15#include <linux/kernel.h> 16#include <linux/sched.h> 17#include <linux/sched/task_stack.h> 18#include <linux/string.h> 19 20#include <linux/mm.h> 21#include <linux/errno.h> 22#include <linux/ptrace.h> 23#include <linux/audit.h> 24#include <linux/regset.h> 25#include <linux/elf.h> 26 27#include <asm/thread_info.h> 28#include <asm/page.h> 29 30/* 31 * Copy the thread state to a regset that can be interpreted by userspace. 32 * 33 * It doesn't matter what our internal pt_regs structure looks like. The 34 * important thing is that we export a consistent view of the thread state 35 * to userspace. As such, we need to make sure that the regset remains 36 * ABI compatible as defined by the struct user_regs_struct: 37 * 38 * (Each item is a 32-bit word) 39 * r0 = 0 (exported for clarity) 40 * 31 GPRS r1-r31 41 * PC (Program counter) 42 * SR (Supervision register) 43 */ 44static int genregs_get(struct task_struct *target, 45 const struct user_regset *regset, 46 struct membuf to) 47{ 48 const struct pt_regs *regs = task_pt_regs(target); 49 50 /* r0 */ 51 membuf_zero(&to, 4); 52 membuf_write(&to, regs->gpr + 1, 31 * 4); 53 membuf_store(&to, regs->pc); 54 return membuf_store(&to, regs->sr); 55} 56 57/* 58 * Set the thread state from a regset passed in via ptrace 59 */ 60static int genregs_set(struct task_struct *target, 61 const struct user_regset *regset, 62 unsigned int pos, unsigned int count, 63 const void *kbuf, const void __user * ubuf) 64{ 65 struct pt_regs *regs = task_pt_regs(target); 66 int ret; 67 68 /* ignore r0 */ 69 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4); 70 /* r1 - r31 */ 71 if (!ret) 72 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 73 regs->gpr+1, 4, 4*32); 74 /* PC */ 75 if (!ret) 76 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 77 ®s->pc, 4*32, 4*33); 78 /* 79 * Skip SR and padding... userspace isn't allowed to changes bits in 80 * the Supervision register 81 */ 82 if (!ret) 83 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 84 4*33, -1); 85 86 return ret; 87} 88 89/* 90 * Define the register sets available on OpenRISC under Linux 91 */ 92enum or1k_regset { 93 REGSET_GENERAL, 94}; 95 96static const struct user_regset or1k_regsets[] = { 97 [REGSET_GENERAL] = { 98 .core_note_type = NT_PRSTATUS, 99 .n = ELF_NGREG, 100 .size = sizeof(long), 101 .align = sizeof(long), 102 .regset_get = genregs_get, 103 .set = genregs_set, 104 }, 105}; 106 107static const struct user_regset_view user_or1k_native_view = { 108 .name = "or1k", 109 .e_machine = EM_OPENRISC, 110 .regsets = or1k_regsets, 111 .n = ARRAY_SIZE(or1k_regsets), 112}; 113 114const struct user_regset_view *task_user_regset_view(struct task_struct *task) 115{ 116 return &user_or1k_native_view; 117} 118 119/* 120 * does not yet catch signals sent when the child dies. 121 * in exit.c or in signal.c. 122 */ 123 124 125/* 126 * Called by kernel/ptrace.c when detaching.. 127 * 128 * Make sure the single step bit is not set. 129 */ 130void ptrace_disable(struct task_struct *child) 131{ 132 pr_debug("ptrace_disable(): TODO\n"); 133 134 user_disable_single_step(child); 135 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 136} 137 138long arch_ptrace(struct task_struct *child, long request, unsigned long addr, 139 unsigned long data) 140{ 141 int ret; 142 143 switch (request) { 144 default: 145 ret = ptrace_request(child, request, addr, data); 146 break; 147 } 148 149 return ret; 150} 151 152/* 153 * Notification of system call entry/exit 154 * - triggered by current->work.syscall_trace 155 */ 156asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) 157{ 158 long ret = 0; 159 160 if (test_thread_flag(TIF_SYSCALL_TRACE) && 161 ptrace_report_syscall_entry(regs)) 162 /* 163 * Tracing decided this syscall should not happen. 164 * We'll return a bogus call number to get an ENOSYS 165 * error, but leave the original number in <something>. 166 */ 167 ret = -1L; 168 169 audit_syscall_entry(regs->gpr[11], regs->gpr[3], regs->gpr[4], 170 regs->gpr[5], regs->gpr[6]); 171 172 return ret ? : regs->gpr[11]; 173} 174 175asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) 176{ 177 int step; 178 179 audit_syscall_exit(regs); 180 181 step = test_thread_flag(TIF_SINGLESTEP); 182 if (step || test_thread_flag(TIF_SYSCALL_TRACE)) 183 ptrace_report_syscall_exit(regs, step); 184}