1 /* ptrace.c: Sparc process tracing support. 2 * 3 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) 4 * 5 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, 6 * and David Mosberger. 7 * 8 * Added Linux support -miguel (weird, eh?, the original code was meant 9 * to emulate SunOS). 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/sched.h> 14 #include <linux/mm.h> 15 #include <linux/errno.h> 16 #include <linux/ptrace.h> 17 #include <linux/user.h> 18 #include <linux/smp.h> 19 #include <linux/security.h> 20 #include <linux/signal.h> 21 #include <linux/regset.h> 22 #include <linux/elf.h> 23 #include <linux/tracehook.h> 24 25 #include <asm/pgtable.h> 26 #include <asm/system.h> 27 #include <asm/uaccess.h> 28 29 /* #define ALLOW_INIT_TRACING */ 30 31 /* 32 * Called by kernel/ptrace.c when detaching.. 33 * 34 * Make sure single step bits etc are not set. 35 */ 36 void ptrace_disable(struct task_struct *child) 37 { 38 /* nothing to do */ 39 } 40 41 enum sparc_regset { 42 REGSET_GENERAL, 43 REGSET_FP, 44 }; 45 46 static int genregs32_get(struct task_struct *target, 47 const struct user_regset *regset, 48 unsigned int pos, unsigned int count, 49 void *kbuf, void __user *ubuf) 50 { 51 const struct pt_regs *regs = target->thread.kregs; 52 unsigned long __user *reg_window; 53 unsigned long *k = kbuf; 54 unsigned long __user *u = ubuf; 55 unsigned long reg; 56 57 if (target == current) 58 flush_user_windows(); 59 60 pos /= sizeof(reg); 61 count /= sizeof(reg); 62 63 if (kbuf) { 64 for (; count > 0 && pos < 16; count--) 65 *k++ = regs->u_regs[pos++]; 66 67 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; 68 for (; count > 0 && pos < 32; count--) { 69 if (get_user(*k++, ®_window[pos++])) 70 return -EFAULT; 71 } 72 } else { 73 for (; count > 0 && pos < 16; count--) { 74 if (put_user(regs->u_regs[pos++], u++)) 75 return -EFAULT; 76 } 77 78 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; 79 for (; count > 0 && pos < 32; count--) { 80 if (get_user(reg, ®_window[pos++]) || 81 put_user(reg, u++)) 82 return -EFAULT; 83 } 84 } 85 while (count > 0) { 86 switch (pos) { 87 case 32: /* PSR */ 88 reg = regs->psr; 89 break; 90 case 33: /* PC */ 91 reg = regs->pc; 92 break; 93 case 34: /* NPC */ 94 reg = regs->npc; 95 break; 96 case 35: /* Y */ 97 reg = regs->y; 98 break; 99 case 36: /* WIM */ 100 case 37: /* TBR */ 101 reg = 0; 102 break; 103 default: 104 goto finish; 105 } 106 107 if (kbuf) 108 *k++ = reg; 109 else if (put_user(reg, u++)) 110 return -EFAULT; 111 pos++; 112 count--; 113 } 114 finish: 115 pos *= sizeof(reg); 116 count *= sizeof(reg); 117 118 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 119 38 * sizeof(reg), -1); 120 } 121 122 static int genregs32_set(struct task_struct *target, 123 const struct user_regset *regset, 124 unsigned int pos, unsigned int count, 125 const void *kbuf, const void __user *ubuf) 126 { 127 struct pt_regs *regs = target->thread.kregs; 128 unsigned long __user *reg_window; 129 const unsigned long *k = kbuf; 130 const unsigned long __user *u = ubuf; 131 unsigned long reg; 132 133 if (target == current) 134 flush_user_windows(); 135 136 pos /= sizeof(reg); 137 count /= sizeof(reg); 138 139 if (kbuf) { 140 for (; count > 0 && pos < 16; count--) 141 regs->u_regs[pos++] = *k++; 142 143 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; 144 for (; count > 0 && pos < 32; count--) { 145 if (put_user(*k++, ®_window[pos++])) 146 return -EFAULT; 147 } 148 } else { 149 for (; count > 0 && pos < 16; count--) { 150 if (get_user(reg, u++)) 151 return -EFAULT; 152 regs->u_regs[pos++] = reg; 153 } 154 155 reg_window = (unsigned long __user *) regs->u_regs[UREG_I6]; 156 for (; count > 0 && pos < 32; count--) { 157 if (get_user(reg, u++) || 158 put_user(reg, ®_window[pos++])) 159 return -EFAULT; 160 } 161 } 162 while (count > 0) { 163 unsigned long psr; 164 165 if (kbuf) 166 reg = *k++; 167 else if (get_user(reg, u++)) 168 return -EFAULT; 169 170 switch (pos) { 171 case 32: /* PSR */ 172 psr = regs->psr; 173 psr &= ~(PSR_ICC | PSR_SYSCALL); 174 psr |= (reg & (PSR_ICC | PSR_SYSCALL)); 175 regs->psr = psr; 176 break; 177 case 33: /* PC */ 178 regs->pc = reg; 179 break; 180 case 34: /* NPC */ 181 regs->npc = reg; 182 break; 183 case 35: /* Y */ 184 regs->y = reg; 185 break; 186 case 36: /* WIM */ 187 case 37: /* TBR */ 188 break; 189 default: 190 goto finish; 191 } 192 193 pos++; 194 count--; 195 } 196 finish: 197 pos *= sizeof(reg); 198 count *= sizeof(reg); 199 200 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 201 38 * sizeof(reg), -1); 202 } 203 204 static int fpregs32_get(struct task_struct *target, 205 const struct user_regset *regset, 206 unsigned int pos, unsigned int count, 207 void *kbuf, void __user *ubuf) 208 { 209 const unsigned long *fpregs = target->thread.float_regs; 210 int ret = 0; 211 212 #if 0 213 if (target == current) 214 save_and_clear_fpu(); 215 #endif 216 217 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 218 fpregs, 219 0, 32 * sizeof(u32)); 220 221 if (!ret) 222 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 223 32 * sizeof(u32), 224 33 * sizeof(u32)); 225 if (!ret) 226 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 227 &target->thread.fsr, 228 33 * sizeof(u32), 229 34 * sizeof(u32)); 230 231 if (!ret) { 232 unsigned long val; 233 234 val = (1 << 8) | (8 << 16); 235 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 236 &val, 237 34 * sizeof(u32), 238 35 * sizeof(u32)); 239 } 240 241 if (!ret) 242 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 243 35 * sizeof(u32), -1); 244 245 return ret; 246 } 247 248 static int fpregs32_set(struct task_struct *target, 249 const struct user_regset *regset, 250 unsigned int pos, unsigned int count, 251 const void *kbuf, const void __user *ubuf) 252 { 253 unsigned long *fpregs = target->thread.float_regs; 254 int ret; 255 256 #if 0 257 if (target == current) 258 save_and_clear_fpu(); 259 #endif 260 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 261 fpregs, 262 0, 32 * sizeof(u32)); 263 if (!ret) 264 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 265 32 * sizeof(u32), 266 33 * sizeof(u32)); 267 if (!ret && count > 0) { 268 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 269 &target->thread.fsr, 270 33 * sizeof(u32), 271 34 * sizeof(u32)); 272 } 273 274 if (!ret) 275 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 276 34 * sizeof(u32), -1); 277 return ret; 278 } 279 280 static const struct user_regset sparc32_regsets[] = { 281 /* Format is: 282 * G0 --> G7 283 * O0 --> O7 284 * L0 --> L7 285 * I0 --> I7 286 * PSR, PC, nPC, Y, WIM, TBR 287 */ 288 [REGSET_GENERAL] = { 289 .core_note_type = NT_PRSTATUS, 290 .n = 38, 291 .size = sizeof(u32), .align = sizeof(u32), 292 .get = genregs32_get, .set = genregs32_set 293 }, 294 /* Format is: 295 * F0 --> F31 296 * empty 32-bit word 297 * FSR (32--bit word) 298 * FPU QUEUE COUNT (8-bit char) 299 * FPU QUEUE ENTRYSIZE (8-bit char) 300 * FPU ENABLED (8-bit char) 301 * empty 8-bit char 302 * FPU QUEUE (64 32-bit ints) 303 */ 304 [REGSET_FP] = { 305 .core_note_type = NT_PRFPREG, 306 .n = 99, 307 .size = sizeof(u32), .align = sizeof(u32), 308 .get = fpregs32_get, .set = fpregs32_set 309 }, 310 }; 311 312 static const struct user_regset_view user_sparc32_view = { 313 .name = "sparc", .e_machine = EM_SPARC, 314 .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) 315 }; 316 317 const struct user_regset_view *task_user_regset_view(struct task_struct *task) 318 { 319 return &user_sparc32_view; 320 } 321 322 long arch_ptrace(struct task_struct *child, long request, long addr, long data) 323 { 324 unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; 325 const struct user_regset_view *view; 326 int ret; 327 328 view = task_user_regset_view(current); 329 330 switch(request) { 331 case PTRACE_GETREGS: { 332 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 333 334 ret = copy_regset_to_user(child, view, REGSET_GENERAL, 335 32 * sizeof(u32), 336 4 * sizeof(u32), 337 &pregs->psr); 338 if (!ret) 339 copy_regset_to_user(child, view, REGSET_GENERAL, 340 1 * sizeof(u32), 341 15 * sizeof(u32), 342 &pregs->u_regs[0]); 343 break; 344 } 345 346 case PTRACE_SETREGS: { 347 struct pt_regs __user *pregs = (struct pt_regs __user *) addr; 348 349 ret = copy_regset_from_user(child, view, REGSET_GENERAL, 350 32 * sizeof(u32), 351 4 * sizeof(u32), 352 &pregs->psr); 353 if (!ret) 354 copy_regset_from_user(child, view, REGSET_GENERAL, 355 1 * sizeof(u32), 356 15 * sizeof(u32), 357 &pregs->u_regs[0]); 358 break; 359 } 360 361 case PTRACE_GETFPREGS: { 362 struct fps { 363 unsigned long regs[32]; 364 unsigned long fsr; 365 unsigned long flags; 366 unsigned long extra; 367 unsigned long fpqd; 368 struct fq { 369 unsigned long *insnaddr; 370 unsigned long insn; 371 } fpq[16]; 372 }; 373 struct fps __user *fps = (struct fps __user *) addr; 374 375 ret = copy_regset_to_user(child, view, REGSET_FP, 376 0 * sizeof(u32), 377 32 * sizeof(u32), 378 &fps->regs[0]); 379 if (!ret) 380 ret = copy_regset_to_user(child, view, REGSET_FP, 381 33 * sizeof(u32), 382 1 * sizeof(u32), 383 &fps->fsr); 384 385 if (!ret) { 386 if (__put_user(0, &fps->fpqd) || 387 __put_user(0, &fps->flags) || 388 __put_user(0, &fps->extra) || 389 clear_user(fps->fpq, sizeof(fps->fpq))) 390 ret = -EFAULT; 391 } 392 break; 393 } 394 395 case PTRACE_SETFPREGS: { 396 struct fps { 397 unsigned long regs[32]; 398 unsigned long fsr; 399 unsigned long flags; 400 unsigned long extra; 401 unsigned long fpqd; 402 struct fq { 403 unsigned long *insnaddr; 404 unsigned long insn; 405 } fpq[16]; 406 }; 407 struct fps __user *fps = (struct fps __user *) addr; 408 409 ret = copy_regset_from_user(child, view, REGSET_FP, 410 0 * sizeof(u32), 411 32 * sizeof(u32), 412 &fps->regs[0]); 413 if (!ret) 414 ret = copy_regset_from_user(child, view, REGSET_FP, 415 33 * sizeof(u32), 416 1 * sizeof(u32), 417 &fps->fsr); 418 break; 419 } 420 421 case PTRACE_READTEXT: 422 case PTRACE_READDATA: 423 ret = ptrace_readdata(child, addr, 424 (void __user *) addr2, data); 425 426 if (ret == data) 427 ret = 0; 428 else if (ret >= 0) 429 ret = -EIO; 430 break; 431 432 case PTRACE_WRITETEXT: 433 case PTRACE_WRITEDATA: 434 ret = ptrace_writedata(child, (void __user *) addr2, 435 addr, data); 436 437 if (ret == data) 438 ret = 0; 439 else if (ret >= 0) 440 ret = -EIO; 441 break; 442 443 default: 444 if (request == PTRACE_SPARC_DETACH) 445 request = PTRACE_DETACH; 446 ret = ptrace_request(child, request, addr, data); 447 break; 448 } 449 450 return ret; 451 } 452 453 asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p) 454 { 455 int ret = 0; 456 457 if (test_thread_flag(TIF_SYSCALL_TRACE)) { 458 if (syscall_exit_p) 459 tracehook_report_syscall_exit(regs, 0); 460 else 461 ret = tracehook_report_syscall_entry(regs); 462 } 463 464 return ret; 465 } 466