1/* ptrace.c */ 2/* By Ross Biro 1/23/92 */ 3/* 4 * Pentium III FXSR, SSE support 5 * Gareth Hughes <gareth@valinux.com>, May 2000 6 */ 7 8#include <linux/kernel.h> 9#include <linux/sched.h> 10#include <linux/mm.h> 11#include <linux/smp.h> 12#include <linux/smp_lock.h> 13#include <linux/errno.h> 14#include <linux/ptrace.h> 15#include <linux/user.h> 16 17#include <asm/uaccess.h> 18#include <asm/pgtable.h> 19#include <asm/system.h> 20#include <asm/processor.h> 21#include <asm/i387.h> 22#include <asm/debugreg.h> 23 24/* 25 * does not yet catch signals sent when the child dies. 26 * in exit.c or in signal.c. 27 */ 28 29/* determines which flags the user has access to. */ 30/* 1 = access 0 = no access */ 31#define FLAG_MASK 0x00044dd5 32 33/* set's the trap flag. */ 34#define TRAP_FLAG 0x100 35 36/* 37 * Offset of eflags on child stack.. 38 */ 39#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs)) 40 41/* 42 * this routine will get a word off of the processes privileged stack. 43 * the offset is how far from the base addr as stored in the TSS. 44 * this routine assumes that all the privileged stacks are in our 45 * data space. 46 */ 47static inline int get_stack_long(struct task_struct *task, int offset) 48{ 49 unsigned char *stack; 50 51 stack = (unsigned char *)task->thread.esp0; 52 stack += offset; 53 return (*((int *)stack)); 54} 55 56/* 57 * this routine will put a word on the processes privileged stack. 58 * the offset is how far from the base addr as stored in the TSS. 59 * this routine assumes that all the privileged stacks are in our 60 * data space. 61 */ 62static inline int put_stack_long(struct task_struct *task, int offset, 63 unsigned long data) 64{ 65 unsigned char * stack; 66 67 stack = (unsigned char *) task->thread.esp0; 68 stack += offset; 69 *(unsigned long *) stack = data; 70 return 0; 71} 72 73static int putreg(struct task_struct *child, 74 unsigned long regno, unsigned long value) 75{ 76 switch (regno >> 2) { 77 case FS: 78 if (value && (value & 3) != 3) 79 return -EIO; 80 child->thread.fs = value; 81 return 0; 82 case GS: 83 if (value && (value & 3) != 3) 84 return -EIO; 85 child->thread.gs = value; 86 return 0; 87 case DS: 88 case ES: 89 if (value && (value & 3) != 3) 90 return -EIO; 91 value &= 0xffff; 92 break; 93 case SS: 94 case CS: 95 if ((value & 3) != 3) 96 return -EIO; 97 value &= 0xffff; 98 break; 99 case EFL: 100 value &= FLAG_MASK; 101 value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK; 102 break; 103 } 104 if (regno > GS*4) 105 regno -= 2*4; 106 put_stack_long(child, regno - sizeof(struct pt_regs), value); 107 return 0; 108} 109 110static unsigned long getreg(struct task_struct *child, 111 unsigned long regno) 112{ 113 unsigned long retval = ~0UL; 114 115 switch (regno >> 2) { 116 case FS: 117 retval = child->thread.fs; 118 break; 119 case GS: 120 retval = child->thread.gs; 121 break; 122 case DS: 123 case ES: 124 case SS: 125 case CS: 126 retval = 0xffff; 127 /* fall through */ 128 default: 129 if (regno > GS*4) 130 regno -= 2*4; 131 regno = regno - sizeof(struct pt_regs); 132 retval &= get_stack_long(child, regno); 133 } 134 return retval; 135} 136 137/* 138 * Called by kernel/ptrace.c when detaching.. 139 * 140 * Make sure the single step bit is not set. 141 */ 142void ptrace_disable(struct task_struct *child) 143{ 144 long tmp; 145 146 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; 147 put_stack_long(child, EFL_OFFSET, tmp); 148} 149 150asmlinkage int sys_ptrace(long request, long pid, long addr, long data) 151{ 152 struct task_struct *child; 153 struct user * dummy = NULL; 154 int i, ret; 155 156 lock_kernel(); 157 ret = -EPERM; 158 if (request == PTRACE_TRACEME) { 159 /* are we already being traced? */ 160 if (current->ptrace & PT_PTRACED) 161 goto out; 162 /* set the ptrace bit in the process flags. */ 163 current->ptrace |= PT_PTRACED; 164 ret = 0; 165 goto out; 166 } 167 ret = -ESRCH; 168 read_lock(&tasklist_lock); 169 child = find_task_by_pid(pid); 170 if (child) 171 get_task_struct(child); 172 read_unlock(&tasklist_lock); 173 if (!child) 174 goto out; 175 176 ret = -EPERM; 177 if (pid == 1) /* you may not mess with init */ 178 goto out_tsk; 179 180 if (request == PTRACE_ATTACH) { 181 ret = ptrace_attach(child); 182 goto out_tsk; 183 } 184 185 ret = ptrace_check_attach(child, request == PTRACE_KILL); 186 if (ret < 0) 187 goto out_tsk; 188 189 switch (request) { 190 /* when I and D space are separate, these will need to be fixed. */ 191 case PTRACE_PEEKTEXT: /* read word at location addr. */ 192 case PTRACE_PEEKDATA: { 193 unsigned long tmp; 194 int copied; 195 196 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); 197 ret = -EIO; 198 if (copied != sizeof(tmp)) 199 break; 200 ret = put_user(tmp,(unsigned long *) data); 201 break; 202 } 203 204 /* read the word at location addr in the USER area. */ 205 case PTRACE_PEEKUSR: { 206 unsigned long tmp; 207 208 ret = -EIO; 209 if ((addr & 3) || addr < 0 || 210 addr > sizeof(struct user) - 3) 211 break; 212 213 tmp = 0; /* Default return condition */ 214 if(addr < FRAME_SIZE*sizeof(long)) 215 tmp = getreg(child, addr); 216 if(addr >= (long) &dummy->u_debugreg[0] && 217 addr <= (long) &dummy->u_debugreg[7]){ 218 addr -= (long) &dummy->u_debugreg[0]; 219 addr = addr >> 2; 220 tmp = child->thread.debugreg[addr]; 221 } 222 ret = put_user(tmp,(unsigned long *) data); 223 break; 224 } 225 226 /* when I and D space are separate, this will have to be fixed. */ 227 case PTRACE_POKETEXT: /* write the word at location addr. */ 228 case PTRACE_POKEDATA: 229 ret = 0; 230 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) 231 break; 232 ret = -EIO; 233 break; 234 235 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 236 ret = -EIO; 237 if ((addr & 3) || addr < 0 || 238 addr > sizeof(struct user) - 3) 239 break; 240 241 if (addr < FRAME_SIZE*sizeof(long)) { 242 ret = putreg(child, addr, data); 243 break; 244 } 245 /* We need to be very careful here. We implicitly 246 want to modify a portion of the task_struct, and we 247 have to be selective about what portions we allow someone 248 to modify. */ 249 250 ret = -EIO; 251 if(addr >= (long) &dummy->u_debugreg[0] && 252 addr <= (long) &dummy->u_debugreg[7]){ 253 254 if(addr == (long) &dummy->u_debugreg[4]) break; 255 if(addr == (long) &dummy->u_debugreg[5]) break; 256 if(addr < (long) &dummy->u_debugreg[4] && 257 ((unsigned long) data) >= TASK_SIZE-3) break; 258 259 if(addr == (long) &dummy->u_debugreg[7]) { 260 data &= ~DR_CONTROL_RESERVED; 261 for(i=0; i<4; i++) 262 if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) 263 goto out_tsk; 264 } 265 266 addr -= (long) &dummy->u_debugreg; 267 addr = addr >> 2; 268 child->thread.debugreg[addr] = data; 269 ret = 0; 270 } 271 break; 272 273 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 274 case PTRACE_CONT: { /* restart after signal. */ 275 long tmp; 276 277 ret = -EIO; 278 if ((unsigned long) data > _NSIG) 279 break; 280 if (request == PTRACE_SYSCALL) 281 child->ptrace |= PT_TRACESYS; 282 else 283 child->ptrace &= ~PT_TRACESYS; 284 child->exit_code = data; 285 /* make sure the single step bit is not set. */ 286 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; 287 put_stack_long(child, EFL_OFFSET,tmp); 288 wake_up_process(child); 289 ret = 0; 290 break; 291 } 292 293/* 294 * make the child exit. Best I can do is send it a sigkill. 295 * perhaps it should be put in the status that it wants to 296 * exit. 297 */ 298 case PTRACE_KILL: { 299 long tmp; 300 301 ret = 0; 302 if (child->state == TASK_ZOMBIE) /* already dead */ 303 break; 304 child->exit_code = SIGKILL; 305 /* make sure the single step bit is not set. */ 306 tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; 307 put_stack_long(child, EFL_OFFSET, tmp); 308 wake_up_process(child); 309 break; 310 } 311 312 case PTRACE_SINGLESTEP: { /* set the trap flag. */ 313 long tmp; 314 315 ret = -EIO; 316 if ((unsigned long) data > _NSIG) 317 break; 318 child->ptrace &= ~PT_TRACESYS; 319 if ((child->ptrace & PT_DTRACE) == 0) { 320 /* Spurious delayed TF traps may occur */ 321 child->ptrace |= PT_DTRACE; 322 } 323 tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; 324 put_stack_long(child, EFL_OFFSET, tmp); 325 child->exit_code = data; 326 /* give it a chance to run. */ 327 wake_up_process(child); 328 ret = 0; 329 break; 330 } 331 332 case PTRACE_DETACH: 333 /* detach a process that was attached. */ 334 ret = ptrace_detach(child, data); 335 break; 336 337 case PTRACE_GETREGS: { /* Get all gp regs from the child. */ 338 if (!access_ok(VERIFY_WRITE, (unsigned *)data, FRAME_SIZE*sizeof(long))) { 339 ret = -EIO; 340 break; 341 } 342 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { 343 __put_user(getreg(child, i),(unsigned long *) data); 344 data += sizeof(long); 345 } 346 ret = 0; 347 break; 348 } 349 350 case PTRACE_SETREGS: { /* Set all gp regs in the child. */ 351 unsigned long tmp; 352 if (!access_ok(VERIFY_READ, (unsigned *)data, FRAME_SIZE*sizeof(long))) { 353 ret = -EIO; 354 break; 355 } 356 for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { 357 __get_user(tmp, (unsigned long *) data); 358 putreg(child, i, tmp); 359 data += sizeof(long); 360 } 361 ret = 0; 362 break; 363 } 364 365 case PTRACE_GETFPREGS: { /* Get the child FPU state. */ 366 if (!access_ok(VERIFY_WRITE, (unsigned *)data, 367 sizeof(struct user_i387_struct))) { 368 ret = -EIO; 369 break; 370 } 371 ret = 0; 372 if ( !child->used_math ) 373 load_empty_fpu(child); 374 get_fpregs((struct user_i387_struct *)data, child); 375 break; 376 } 377 378 case PTRACE_SETFPREGS: { /* Set the child FPU state. */ 379 if (!access_ok(VERIFY_READ, (unsigned *)data, 380 sizeof(struct user_i387_struct))) { 381 ret = -EIO; 382 break; 383 } 384 child->used_math = 1; 385 set_fpregs(child, (struct user_i387_struct *)data); 386 ret = 0; 387 break; 388 } 389 390 case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */ 391 if (!access_ok(VERIFY_WRITE, (unsigned *)data, 392 sizeof(struct user_fxsr_struct))) { 393 ret = -EIO; 394 break; 395 } 396 if ( !child->used_math ) 397 load_empty_fpu(child); 398 ret = get_fpxregs((struct user_fxsr_struct *)data, child); 399 break; 400 } 401 402 case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */ 403 if (!access_ok(VERIFY_READ, (unsigned *)data, 404 sizeof(struct user_fxsr_struct))) { 405 ret = -EIO; 406 break; 407 } 408 child->used_math = 1; 409 ret = set_fpxregs(child, (struct user_fxsr_struct *)data); 410 break; 411 } 412 413 case PTRACE_SETOPTIONS: { 414 if (data & PTRACE_O_TRACESYSGOOD) 415 child->ptrace |= PT_TRACESYSGOOD; 416 else 417 child->ptrace &= ~PT_TRACESYSGOOD; 418 ret = 0; 419 break; 420 } 421 422 default: 423 ret = -EIO; 424 break; 425 } 426out_tsk: 427 free_task_struct(child); 428out: 429 unlock_kernel(); 430 return ret; 431} 432 433asmlinkage void syscall_trace(void) 434{ 435 if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != 436 (PT_PTRACED|PT_TRACESYS)) 437 return; 438 /* the 0x80 provides a way for the tracing parent to distinguish 439 between a syscall stop and SIGTRAP delivery */ 440 current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 441 ? 0x80 : 0); 442 current->state = TASK_STOPPED; 443 notify_parent(current, SIGCHLD); 444 schedule(); 445 /* 446 * this isn't the same as continuing with a signal, but it will do 447 * for normal use. strace only continues with a signal if the 448 * stopping signal is not SIGTRAP. -brl 449 */ 450 if (current->exit_code) { 451 send_sig(current->exit_code, current, 1); 452 current->exit_code = 0; 453 } 454} 455