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