1 /* 2 * Copyright (C) 2014 Altera Corporation 3 * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 4 * 5 * This file is subject to the terms and conditions of the GNU General 6 * Public License. See the file COPYING in the main directory of this 7 * archive for more details. 8 */ 9 10 #include <linux/elf.h> 11 #include <linux/errno.h> 12 #include <linux/kernel.h> 13 #include <linux/mm.h> 14 #include <linux/ptrace.h> 15 #include <linux/regset.h> 16 #include <linux/sched.h> 17 #include <linux/sched/task_stack.h> 18 #include <linux/tracehook.h> 19 #include <linux/uaccess.h> 20 #include <linux/user.h> 21 22 static int genregs_get(struct task_struct *target, 23 const struct user_regset *regset, 24 unsigned int pos, unsigned int count, 25 void *kbuf, void __user *ubuf) 26 { 27 const struct pt_regs *regs = task_pt_regs(target); 28 const struct switch_stack *sw = (struct switch_stack *)regs - 1; 29 int ret = 0; 30 31 #define REG_O_ZERO_RANGE(START, END) \ 32 if (!ret) \ 33 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \ 34 START * 4, (END * 4) + 4); 35 36 #define REG_O_ONE(PTR, LOC) \ 37 if (!ret) \ 38 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ 39 LOC * 4, (LOC * 4) + 4); 40 41 #define REG_O_RANGE(PTR, START, END) \ 42 if (!ret) \ 43 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ 44 START * 4, (END * 4) + 4); 45 46 REG_O_ZERO_RANGE(PTR_R0, PTR_R0); 47 REG_O_RANGE(®s->r1, PTR_R1, PTR_R7); 48 REG_O_RANGE(®s->r8, PTR_R8, PTR_R15); 49 REG_O_RANGE(sw, PTR_R16, PTR_R23); 50 REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */ 51 REG_O_ONE(®s->gp, PTR_GP); 52 REG_O_ONE(®s->sp, PTR_SP); 53 REG_O_ONE(®s->fp, PTR_FP); 54 REG_O_ONE(®s->ea, PTR_EA); 55 REG_O_ZERO_RANGE(PTR_BA, PTR_BA); 56 REG_O_ONE(®s->ra, PTR_RA); 57 REG_O_ONE(®s->ea, PTR_PC); /* use ea for PC */ 58 if (!ret) 59 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 60 PTR_STATUS * 4, -1); 61 62 return ret; 63 } 64 65 /* 66 * Set the thread state from a regset passed in via ptrace 67 */ 68 static int genregs_set(struct task_struct *target, 69 const struct user_regset *regset, 70 unsigned int pos, unsigned int count, 71 const void *kbuf, const void __user *ubuf) 72 { 73 struct pt_regs *regs = task_pt_regs(target); 74 const struct switch_stack *sw = (struct switch_stack *)regs - 1; 75 int ret = 0; 76 77 #define REG_IGNORE_RANGE(START, END) \ 78 if (!ret) \ 79 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \ 80 START * 4, (END * 4) + 4); 81 82 #define REG_IN_ONE(PTR, LOC) \ 83 if (!ret) \ 84 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \ 85 (void *)(PTR), LOC * 4, (LOC * 4) + 4); 86 87 #define REG_IN_RANGE(PTR, START, END) \ 88 if (!ret) \ 89 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \ 90 (void *)(PTR), START * 4, (END * 4) + 4); 91 92 REG_IGNORE_RANGE(PTR_R0, PTR_R0); 93 REG_IN_RANGE(®s->r1, PTR_R1, PTR_R7); 94 REG_IN_RANGE(®s->r8, PTR_R8, PTR_R15); 95 REG_IN_RANGE(sw, PTR_R16, PTR_R23); 96 REG_IGNORE_RANGE(PTR_R24, PTR_R25); /* et and bt */ 97 REG_IN_ONE(®s->gp, PTR_GP); 98 REG_IN_ONE(®s->sp, PTR_SP); 99 REG_IN_ONE(®s->fp, PTR_FP); 100 REG_IN_ONE(®s->ea, PTR_EA); 101 REG_IGNORE_RANGE(PTR_BA, PTR_BA); 102 REG_IN_ONE(®s->ra, PTR_RA); 103 REG_IN_ONE(®s->ea, PTR_PC); /* use ea for PC */ 104 if (!ret) 105 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 106 PTR_STATUS * 4, -1); 107 108 return ret; 109 } 110 111 /* 112 * Define the register sets available on Nios2 under Linux 113 */ 114 enum nios2_regset { 115 REGSET_GENERAL, 116 }; 117 118 static const struct user_regset nios2_regsets[] = { 119 [REGSET_GENERAL] = { 120 .core_note_type = NT_PRSTATUS, 121 .n = NUM_PTRACE_REG, 122 .size = sizeof(unsigned long), 123 .align = sizeof(unsigned long), 124 .get = genregs_get, 125 .set = genregs_set, 126 } 127 }; 128 129 static const struct user_regset_view nios2_user_view = { 130 .name = "nios2", 131 .e_machine = ELF_ARCH, 132 .ei_osabi = ELF_OSABI, 133 .regsets = nios2_regsets, 134 .n = ARRAY_SIZE(nios2_regsets) 135 }; 136 137 const struct user_regset_view *task_user_regset_view(struct task_struct *task) 138 { 139 return &nios2_user_view; 140 } 141 142 void ptrace_disable(struct task_struct *child) 143 { 144 145 } 146 147 long arch_ptrace(struct task_struct *child, long request, unsigned long addr, 148 unsigned long data) 149 { 150 return ptrace_request(child, request, addr, data); 151 } 152 153 asmlinkage int do_syscall_trace_enter(void) 154 { 155 int ret = 0; 156 157 if (test_thread_flag(TIF_SYSCALL_TRACE)) 158 ret = tracehook_report_syscall_entry(task_pt_regs(current)); 159 160 return ret; 161 } 162 163 asmlinkage void do_syscall_trace_exit(void) 164 { 165 if (test_thread_flag(TIF_SYSCALL_TRACE)) 166 tracehook_report_syscall_exit(task_pt_regs(current), 0); 167 } 168