1 /* 2 * Copyright 2010 Tilera Corporation. All Rights Reserved. 3 * Copyright 2015 Regents of the University of California 4 * Copyright 2017 SiFive 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation, version 2. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * Copied from arch/tile/kernel/ptrace.c 16 */ 17 18 #include <asm/ptrace.h> 19 #include <asm/syscall.h> 20 #include <asm/thread_info.h> 21 #include <linux/ptrace.h> 22 #include <linux/elf.h> 23 #include <linux/regset.h> 24 #include <linux/sched.h> 25 #include <linux/sched/task_stack.h> 26 #include <linux/tracehook.h> 27 #include <trace/events/syscalls.h> 28 29 enum riscv_regset { 30 REGSET_X, 31 }; 32 33 static int riscv_gpr_get(struct task_struct *target, 34 const struct user_regset *regset, 35 unsigned int pos, unsigned int count, 36 void *kbuf, void __user *ubuf) 37 { 38 struct pt_regs *regs; 39 40 regs = task_pt_regs(target); 41 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1); 42 } 43 44 static int riscv_gpr_set(struct task_struct *target, 45 const struct user_regset *regset, 46 unsigned int pos, unsigned int count, 47 const void *kbuf, const void __user *ubuf) 48 { 49 int ret; 50 struct pt_regs *regs; 51 52 regs = task_pt_regs(target); 53 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1); 54 return ret; 55 } 56 57 58 static const struct user_regset riscv_user_regset[] = { 59 [REGSET_X] = { 60 .core_note_type = NT_PRSTATUS, 61 .n = ELF_NGREG, 62 .size = sizeof(elf_greg_t), 63 .align = sizeof(elf_greg_t), 64 .get = &riscv_gpr_get, 65 .set = &riscv_gpr_set, 66 }, 67 }; 68 69 static const struct user_regset_view riscv_user_native_view = { 70 .name = "riscv", 71 .e_machine = EM_RISCV, 72 .regsets = riscv_user_regset, 73 .n = ARRAY_SIZE(riscv_user_regset), 74 }; 75 76 const struct user_regset_view *task_user_regset_view(struct task_struct *task) 77 { 78 return &riscv_user_native_view; 79 } 80 81 void ptrace_disable(struct task_struct *child) 82 { 83 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 84 } 85 86 long arch_ptrace(struct task_struct *child, long request, 87 unsigned long addr, unsigned long data) 88 { 89 long ret = -EIO; 90 91 switch (request) { 92 default: 93 ret = ptrace_request(child, request, addr, data); 94 break; 95 } 96 97 return ret; 98 } 99 100 /* 101 * Allows PTRACE_SYSCALL to work. These are called from entry.S in 102 * {handle,ret_from}_syscall. 103 */ 104 void do_syscall_trace_enter(struct pt_regs *regs) 105 { 106 if (test_thread_flag(TIF_SYSCALL_TRACE)) 107 if (tracehook_report_syscall_entry(regs)) 108 syscall_set_nr(current, regs, -1); 109 110 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS 111 if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) 112 trace_sys_enter(regs, syscall_get_nr(current, regs)); 113 #endif 114 } 115 116 void do_syscall_trace_exit(struct pt_regs *regs) 117 { 118 if (test_thread_flag(TIF_SYSCALL_TRACE)) 119 tracehook_report_syscall_exit(regs, 0); 120 121 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS 122 if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) 123 trace_sys_exit(regs, regs->regs[0]); 124 #endif 125 } 126