1 // TODO some minor issues 2 /* 3 * This file is subject to the terms and conditions of the GNU General Public 4 * License. See the file "COPYING" in the main directory of this archive 5 * for more details. 6 * 7 * Copyright (C) 2001 - 2007 Tensilica Inc. 8 * 9 * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> 10 * Chris Zankel <chris@zankel.net> 11 * Scott Foehner<sfoehner@yahoo.com>, 12 * Kevin Chea 13 * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> 14 */ 15 16 #include <linux/kernel.h> 17 #include <linux/sched.h> 18 #include <linux/mm.h> 19 #include <linux/errno.h> 20 #include <linux/ptrace.h> 21 #include <linux/smp.h> 22 #include <linux/security.h> 23 #include <linux/signal.h> 24 25 #include <asm/pgtable.h> 26 #include <asm/page.h> 27 #include <asm/uaccess.h> 28 #include <asm/ptrace.h> 29 #include <asm/elf.h> 30 #include <asm/coprocessor.h> 31 32 33 void user_enable_single_step(struct task_struct *child) 34 { 35 child->ptrace |= PT_SINGLESTEP; 36 } 37 38 void user_disable_single_step(struct task_struct *child) 39 { 40 child->ptrace &= ~PT_SINGLESTEP; 41 } 42 43 /* 44 * Called by kernel/ptrace.c when detaching to disable single stepping. 45 */ 46 47 void ptrace_disable(struct task_struct *child) 48 { 49 /* Nothing to do.. */ 50 } 51 52 int ptrace_getregs(struct task_struct *child, void __user *uregs) 53 { 54 struct pt_regs *regs = task_pt_regs(child); 55 xtensa_gregset_t __user *gregset = uregs; 56 unsigned long wm = regs->wmask; 57 unsigned long wb = regs->windowbase; 58 int live, i; 59 60 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 61 return -EIO; 62 63 __put_user(regs->pc, &gregset->pc); 64 __put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps); 65 __put_user(regs->lbeg, &gregset->lbeg); 66 __put_user(regs->lend, &gregset->lend); 67 __put_user(regs->lcount, &gregset->lcount); 68 __put_user(regs->windowstart, &gregset->windowstart); 69 __put_user(regs->windowbase, &gregset->windowbase); 70 71 live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16; 72 73 for (i = 0; i < live; i++) 74 __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); 75 for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++) 76 __put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS)); 77 78 return 0; 79 } 80 81 int ptrace_setregs(struct task_struct *child, void __user *uregs) 82 { 83 struct pt_regs *regs = task_pt_regs(child); 84 xtensa_gregset_t *gregset = uregs; 85 const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK; 86 unsigned long ps; 87 unsigned long wb; 88 89 if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t))) 90 return -EIO; 91 92 __get_user(regs->pc, &gregset->pc); 93 __get_user(ps, &gregset->ps); 94 __get_user(regs->lbeg, &gregset->lbeg); 95 __get_user(regs->lend, &gregset->lend); 96 __get_user(regs->lcount, &gregset->lcount); 97 __get_user(regs->windowstart, &gregset->windowstart); 98 __get_user(wb, &gregset->windowbase); 99 100 regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT); 101 102 if (wb >= XCHAL_NUM_AREGS / 4) 103 return -EFAULT; 104 105 regs->windowbase = wb; 106 107 if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4, 108 gregset->a, wb * 16)) 109 return -EFAULT; 110 111 if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16)) 112 return -EFAULT; 113 114 return 0; 115 } 116 117 118 int ptrace_getxregs(struct task_struct *child, void __user *uregs) 119 { 120 struct pt_regs *regs = task_pt_regs(child); 121 struct thread_info *ti = task_thread_info(child); 122 elf_xtregs_t __user *xtregs = uregs; 123 int ret = 0; 124 125 if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t))) 126 return -EIO; 127 128 #if XTENSA_HAVE_COPROCESSORS 129 /* Flush all coprocessor registers to memory. */ 130 coprocessor_flush_all(ti); 131 ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp, 132 sizeof(xtregs_coprocessor_t)); 133 #endif 134 ret |= __copy_to_user(&xtregs->opt, ®s->xtregs_opt, 135 sizeof(xtregs->opt)); 136 ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user, 137 sizeof(xtregs->user)); 138 139 return ret ? -EFAULT : 0; 140 } 141 142 int ptrace_setxregs(struct task_struct *child, void __user *uregs) 143 { 144 struct thread_info *ti = task_thread_info(child); 145 struct pt_regs *regs = task_pt_regs(child); 146 elf_xtregs_t *xtregs = uregs; 147 int ret = 0; 148 149 if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t))) 150 return -EFAULT; 151 152 #if XTENSA_HAVE_COPROCESSORS 153 /* Flush all coprocessors before we overwrite them. */ 154 coprocessor_flush_all(ti); 155 coprocessor_release_all(ti); 156 157 ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, 158 sizeof(xtregs_coprocessor_t)); 159 #endif 160 ret |= __copy_from_user(®s->xtregs_opt, &xtregs->opt, 161 sizeof(xtregs->opt)); 162 ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user, 163 sizeof(xtregs->user)); 164 165 return ret ? -EFAULT : 0; 166 } 167 168 int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret) 169 { 170 struct pt_regs *regs; 171 unsigned long tmp; 172 173 regs = task_pt_regs(child); 174 tmp = 0; /* Default return value. */ 175 176 switch(regno) { 177 178 case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: 179 tmp = regs->areg[regno - REG_AR_BASE]; 180 break; 181 182 case REG_A_BASE ... REG_A_BASE + 15: 183 tmp = regs->areg[regno - REG_A_BASE]; 184 break; 185 186 case REG_PC: 187 tmp = regs->pc; 188 break; 189 190 case REG_PS: 191 /* Note: PS.EXCM is not set while user task is running; 192 * its being set in regs is for exception handling 193 * convenience. */ 194 tmp = (regs->ps & ~(1 << PS_EXCM_BIT)); 195 break; 196 197 case REG_WB: 198 break; /* tmp = 0 */ 199 200 case REG_WS: 201 { 202 unsigned long wb = regs->windowbase; 203 unsigned long ws = regs->windowstart; 204 tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1); 205 break; 206 } 207 case REG_LBEG: 208 tmp = regs->lbeg; 209 break; 210 211 case REG_LEND: 212 tmp = regs->lend; 213 break; 214 215 case REG_LCOUNT: 216 tmp = regs->lcount; 217 break; 218 219 case REG_SAR: 220 tmp = regs->sar; 221 break; 222 223 case SYSCALL_NR: 224 tmp = regs->syscall; 225 break; 226 227 default: 228 return -EIO; 229 } 230 return put_user(tmp, ret); 231 } 232 233 int ptrace_pokeusr(struct task_struct *child, long regno, long val) 234 { 235 struct pt_regs *regs; 236 regs = task_pt_regs(child); 237 238 switch (regno) { 239 case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: 240 regs->areg[regno - REG_AR_BASE] = val; 241 break; 242 243 case REG_A_BASE ... REG_A_BASE + 15: 244 regs->areg[regno - REG_A_BASE] = val; 245 break; 246 247 case REG_PC: 248 regs->pc = val; 249 break; 250 251 case SYSCALL_NR: 252 regs->syscall = val; 253 break; 254 255 default: 256 return -EIO; 257 } 258 return 0; 259 } 260 261 long arch_ptrace(struct task_struct *child, long request, 262 unsigned long addr, unsigned long data) 263 { 264 int ret = -EPERM; 265 void __user *datap = (void __user *) data; 266 267 switch (request) { 268 case PTRACE_PEEKTEXT: /* read word at location addr. */ 269 case PTRACE_PEEKDATA: 270 ret = generic_ptrace_peekdata(child, addr, data); 271 break; 272 273 case PTRACE_PEEKUSR: /* read register specified by addr. */ 274 ret = ptrace_peekusr(child, addr, datap); 275 break; 276 277 case PTRACE_POKETEXT: /* write the word at location addr. */ 278 case PTRACE_POKEDATA: 279 ret = generic_ptrace_pokedata(child, addr, data); 280 break; 281 282 case PTRACE_POKEUSR: /* write register specified by addr. */ 283 ret = ptrace_pokeusr(child, addr, data); 284 break; 285 286 case PTRACE_GETREGS: 287 ret = ptrace_getregs(child, datap); 288 break; 289 290 case PTRACE_SETREGS: 291 ret = ptrace_setregs(child, datap); 292 break; 293 294 case PTRACE_GETXTREGS: 295 ret = ptrace_getxregs(child, datap); 296 break; 297 298 case PTRACE_SETXTREGS: 299 ret = ptrace_setxregs(child, datap); 300 break; 301 302 default: 303 ret = ptrace_request(child, request, addr, data); 304 break; 305 } 306 307 return ret; 308 } 309 310 void do_syscall_trace(void) 311 { 312 /* 313 * The 0x80 provides a way for the tracing parent to distinguish 314 * between a syscall stop and SIGTRAP delivery 315 */ 316 ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); 317 318 /* 319 * this isn't the same as continuing with a signal, but it will do 320 * for normal use. strace only continues with a signal if the 321 * stopping signal is not SIGTRAP. -brl 322 */ 323 if (current->exit_code) { 324 send_sig(current->exit_code, current, 1); 325 current->exit_code = 0; 326 } 327 } 328 329 void do_syscall_trace_enter(struct pt_regs *regs) 330 { 331 if (test_thread_flag(TIF_SYSCALL_TRACE) 332 && (current->ptrace & PT_PTRACED)) 333 do_syscall_trace(); 334 335 #if 0 336 audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); 337 #endif 338 } 339 340 void do_syscall_trace_leave(struct pt_regs *regs) 341 { 342 if ((test_thread_flag(TIF_SYSCALL_TRACE)) 343 && (current->ptrace & PT_PTRACED)) 344 do_syscall_trace(); 345 } 346