Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /* ptrace.c: Sparc process tracing support.
  2  *
  3  * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
  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 orignal 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/smp_lock.h>
 20 #include <linux/security.h>
 21 
 22 #include <asm/pgtable.h>
 23 #include <asm/system.h>
 24 #include <asm/uaccess.h>
 25 
 26 #define MAGIC_CONSTANT 0x80000000
 27 
 28 
 29 /* Returning from ptrace is a bit tricky because the syscall return
 30  * low level code assumes any value returned which is negative and
 31  * is a valid errno will mean setting the condition codes to indicate
 32  * an error return.  This doesn't work, so we have this hook.
 33  */
 34 static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
 35 {
 36         regs->u_regs[UREG_I0] = error;
 37         regs->psr |= PSR_C;
 38         regs->pc = regs->npc;
 39         regs->npc += 4;
 40 }
 41 
 42 static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
 43 {
 44         regs->u_regs[UREG_I0] = value;
 45         regs->psr &= ~PSR_C;
 46         regs->pc = regs->npc;
 47         regs->npc += 4;
 48 }
 49 
 50 static void
 51 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr)
 52 {
 53         if (put_user(value, addr)) {
 54                 pt_error_return(regs, EFAULT);
 55                 return;
 56         }
 57         regs->u_regs[UREG_I0] = 0;
 58         regs->psr &= ~PSR_C;
 59         regs->pc = regs->npc;
 60         regs->npc += 4;
 61 }
 62 
 63 static void
 64 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr)
 65 {
 66         if (current->personality == PER_SUNOS)
 67                 pt_succ_return (regs, val);
 68         else
 69                 pt_succ_return_linux (regs, val, addr);
 70 }
 71 
 72 /* Fuck me gently with a chainsaw... */
 73 static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
 74                                    struct task_struct *tsk, long __user *addr)
 75 {
 76         struct pt_regs *cregs = tsk->thread.kregs;
 77         struct thread_info *t = tsk->thread_info;
 78         int v;
 79         
 80         if(offset >= 1024)
 81                 offset -= 1024; /* whee... */
 82         if(offset & ((sizeof(unsigned long) - 1))) {
 83                 pt_error_return(regs, EIO);
 84                 return;
 85         }
 86         if(offset >= 16 && offset < 784) {
 87                 offset -= 16; offset >>= 2;
 88                 pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
 89                 return;
 90         }
 91         if(offset >= 784 && offset < 832) {
 92                 offset -= 784; offset >>= 2;
 93                 pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
 94                 return;
 95         }
 96         switch(offset) {
 97         case 0:
 98                 v = t->ksp;
 99                 break;
100         case 4:
101                 v = t->kpc;
102                 break;
103         case 8:
104                 v = t->kpsr;
105                 break;
106         case 12:
107                 v = t->uwinmask;
108                 break;
109         case 832:
110                 v = t->w_saved;
111                 break;
112         case 896:
113                 v = cregs->u_regs[UREG_I0];
114                 break;
115         case 900:
116                 v = cregs->u_regs[UREG_I1];
117                 break;
118         case 904:
119                 v = cregs->u_regs[UREG_I2];
120                 break;
121         case 908:
122                 v = cregs->u_regs[UREG_I3];
123                 break;
124         case 912:
125                 v = cregs->u_regs[UREG_I4];
126                 break;
127         case 916:
128                 v = cregs->u_regs[UREG_I5];
129                 break;
130         case 920:
131                 v = cregs->u_regs[UREG_I6];
132                 break;
133         case 924:
134                 if(tsk->thread.flags & MAGIC_CONSTANT)
135                         v = cregs->u_regs[UREG_G1];
136                 else
137                         v = 0;
138                 break;
139         case 940:
140                 v = cregs->u_regs[UREG_I0];
141                 break;
142         case 944:
143                 v = cregs->u_regs[UREG_I1];
144                 break;
145 
146         case 948:
147                 /* Isn't binary compatibility _fun_??? */
148                 if(cregs->psr & PSR_C)
149                         v = cregs->u_regs[UREG_I0] << 24;
150                 else
151                         v = 0;
152                 break;
153 
154                 /* Rest of them are completely unsupported. */
155         default:
156                 printk("%s [%d]: Wants to read user offset %ld\n",
157                        current->comm, current->pid, offset);
158                 pt_error_return(regs, EIO);
159                 return;
160         }
161         if (current->personality == PER_SUNOS)
162                 pt_succ_return (regs, v);
163         else
164                 pt_succ_return_linux (regs, v, addr);
165         return;
166 }
167 
168 static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
169                                     struct task_struct *tsk)
170 {
171         struct pt_regs *cregs = tsk->thread.kregs;
172         struct thread_info *t = tsk->thread_info;
173         unsigned long value = regs->u_regs[UREG_I3];
174 
175         if(offset >= 1024)
176                 offset -= 1024; /* whee... */
177         if(offset & ((sizeof(unsigned long) - 1)))
178                 goto failure;
179         if(offset >= 16 && offset < 784) {
180                 offset -= 16; offset >>= 2;
181                 *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
182                 goto success;
183         }
184         if(offset >= 784 && offset < 832) {
185                 offset -= 784; offset >>= 2;
186                 *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
187                 goto success;
188         }
189         switch(offset) {
190         case 896:
191                 cregs->u_regs[UREG_I0] = value;
192                 break;
193         case 900:
194                 cregs->u_regs[UREG_I1] = value;
195                 break;
196         case 904:
197                 cregs->u_regs[UREG_I2] = value;
198                 break;
199         case 908:
200                 cregs->u_regs[UREG_I3] = value;
201                 break;
202         case 912:
203                 cregs->u_regs[UREG_I4] = value;
204                 break;
205         case 916:
206                 cregs->u_regs[UREG_I5] = value;
207                 break;
208         case 920:
209                 cregs->u_regs[UREG_I6] = value;
210                 break;
211         case 924:
212                 cregs->u_regs[UREG_I7] = value;
213                 break;
214         case 940:
215                 cregs->u_regs[UREG_I0] = value;
216                 break;
217         case 944:
218                 cregs->u_regs[UREG_I1] = value;
219                 break;
220 
221                 /* Rest of them are completely unsupported or "no-touch". */
222         default:
223                 printk("%s [%d]: Wants to write user offset %ld\n",
224                        current->comm, current->pid, offset);
225                 goto failure;
226         }
227 success:
228         pt_succ_return(regs, 0);
229         return;
230 failure:
231         pt_error_return(regs, EIO);
232         return;
233 }
234 
235 /* #define ALLOW_INIT_TRACING */
236 /* #define DEBUG_PTRACE */
237 
238 #ifdef DEBUG_PTRACE
239 char *pt_rq [] = {
240         /* 0  */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
241         /* 4  */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
242         /* 8  */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
243         /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
244         /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
245         /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
246         /* 24 */ "SYSCALL", ""
247 };
248 #endif
249 
250 /*
251  * Called by kernel/ptrace.c when detaching..
252  *
253  * Make sure single step bits etc are not set.
254  */
255 void ptrace_disable(struct task_struct *child)
256 {
257         /* nothing to do */
258 }
259 
260 asmlinkage void do_ptrace(struct pt_regs *regs)
261 {
262         unsigned long request = regs->u_regs[UREG_I0];
263         unsigned long pid = regs->u_regs[UREG_I1];
264         unsigned long addr = regs->u_regs[UREG_I2];
265         unsigned long data = regs->u_regs[UREG_I3];
266         unsigned long addr2 = regs->u_regs[UREG_I4];
267         struct task_struct *child;
268         int ret;
269 
270         lock_kernel();
271 #ifdef DEBUG_PTRACE
272         {
273                 char *s;
274 
275                 if ((request >= 0) && (request <= 24))
276                         s = pt_rq [request];
277                 else
278                         s = "unknown";
279 
280                 if (request == PTRACE_POKEDATA && data == 0x91d02001){
281                         printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n",
282                                 pid, addr, addr2);
283                 } else 
284                         printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
285                                s, (int) request, (int) pid, addr, data, addr2);
286         }
287 #endif
288         if(request == PTRACE_TRACEME) {
289                 int ret;
290 
291                 /* are we already being traced? */
292                 if (current->ptrace & PT_PTRACED) {
293                         pt_error_return(regs, EPERM);
294                         goto out;
295                 }
296                 ret = security_ptrace(current->parent, current);
297                 if (ret) {
298                         pt_error_return(regs, -ret);
299                         goto out;
300                 }
301 
302                 /* set the ptrace bit in the process flags. */
303                 current->ptrace |= PT_PTRACED;
304                 pt_succ_return(regs, 0);
305                 goto out;
306         }
307 #ifndef ALLOW_INIT_TRACING
308         if(pid == 1) {
309                 /* Can't dork with init. */
310                 pt_error_return(regs, EPERM);
311                 goto out;
312         }
313 #endif
314         read_lock(&tasklist_lock);
315         child = find_task_by_pid(pid);
316         if (child)
317                 get_task_struct(child);
318         read_unlock(&tasklist_lock);
319 
320         if (!child) {
321                 pt_error_return(regs, ESRCH);
322                 goto out;
323         }
324 
325         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
326             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
327                 if (ptrace_attach(child)) {
328                         pt_error_return(regs, EPERM);
329                         goto out_tsk;
330                 }
331                 pt_succ_return(regs, 0);
332                 goto out_tsk;
333         }
334 
335         ret = ptrace_check_attach(child, request == PTRACE_KILL);
336         if (ret < 0) {
337                 pt_error_return(regs, -ret);
338                 goto out_tsk;
339         }
340 
341         switch(request) {
342         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
343         case PTRACE_PEEKDATA: {
344                 unsigned long tmp;
345 
346                 if (access_process_vm(child, addr,
347                                       &tmp, sizeof(tmp), 0) == sizeof(tmp))
348                         pt_os_succ_return(regs, tmp, (long __user *)data);
349                 else
350                         pt_error_return(regs, EIO);
351                 goto out_tsk;
352         }
353 
354         case PTRACE_PEEKUSR:
355                 read_sunos_user(regs, addr, child, (long __user *) data);
356                 goto out_tsk;
357 
358         case PTRACE_POKEUSR:
359                 write_sunos_user(regs, addr, child);
360                 goto out_tsk;
361 
362         case PTRACE_POKETEXT: /* write the word at location addr. */
363         case PTRACE_POKEDATA: {
364                 if (access_process_vm(child, addr,
365                                       &data, sizeof(data), 1) == sizeof(data))
366                         pt_succ_return(regs, 0);
367                 else
368                         pt_error_return(regs, EIO);
369                 goto out_tsk;
370         }
371 
372         case PTRACE_GETREGS: {
373                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
374                 struct pt_regs *cregs = child->thread.kregs;
375                 int rval;
376 
377                 rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs));
378                 if(rval) {
379                         pt_error_return(regs, -rval);
380                         goto out_tsk;
381                 }
382                 __put_user(cregs->psr, (&pregs->psr));
383                 __put_user(cregs->pc, (&pregs->pc));
384                 __put_user(cregs->npc, (&pregs->npc));
385                 __put_user(cregs->y, (&pregs->y));
386                 for(rval = 1; rval < 16; rval++)
387                         __put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
388                 pt_succ_return(regs, 0);
389 #ifdef DEBUG_PTRACE
390                 printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
391 #endif
392                 goto out_tsk;
393         }
394 
395         case PTRACE_SETREGS: {
396                 struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
397                 struct pt_regs *cregs = child->thread.kregs;
398                 unsigned long psr, pc, npc, y;
399                 int i;
400 
401                 /* Must be careful, tracing process can only set certain
402                  * bits in the psr.
403                  */
404                 i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs));
405                 if(i) {
406                         pt_error_return(regs, -i);
407                         goto out_tsk;
408                 }
409                 __get_user(psr, (&pregs->psr));
410                 __get_user(pc, (&pregs->pc));
411                 __get_user(npc, (&pregs->npc));
412                 __get_user(y, (&pregs->y));
413                 psr &= PSR_ICC;
414                 cregs->psr &= ~PSR_ICC;
415                 cregs->psr |= psr;
416                 if(!((pc | npc) & 3)) {
417                         cregs->pc = pc;
418                         cregs->npc =npc;
419                 }
420                 cregs->y = y;
421                 for(i = 1; i < 16; i++)
422                         __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
423                 pt_succ_return(regs, 0);
424                 goto out_tsk;
425         }
426 
427         case PTRACE_GETFPREGS: {
428                 struct fps {
429                         unsigned long regs[32];
430                         unsigned long fsr;
431                         unsigned long flags;
432                         unsigned long extra;
433                         unsigned long fpqd;
434                         struct fq {
435                                 unsigned long *insnaddr;
436                                 unsigned long insn;
437                         } fpq[16];
438                 };
439                 struct fps __user *fps = (struct fps __user *) addr;
440                 int i;
441 
442                 i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
443                 if(i) {
444                         pt_error_return(regs, -i);
445                         goto out_tsk;
446                 }
447                 for(i = 0; i < 32; i++)
448                         __put_user(child->thread.float_regs[i], (&fps->regs[i]));
449                 __put_user(child->thread.fsr, (&fps->fsr));
450                 __put_user(child->thread.fpqdepth, (&fps->fpqd));
451                 __put_user(0, (&fps->flags));
452                 __put_user(0, (&fps->extra));
453                 for(i = 0; i < 16; i++) {
454                         __put_user(child->thread.fpqueue[i].insn_addr,
455                                    (&fps->fpq[i].insnaddr));
456                         __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
457                 }
458                 pt_succ_return(regs, 0);
459                 goto out_tsk;
460         }
461 
462         case PTRACE_SETFPREGS: {
463                 struct fps {
464                         unsigned long regs[32];
465                         unsigned long fsr;
466                         unsigned long flags;
467                         unsigned long extra;
468                         unsigned long fpqd;
469                         struct fq {
470                                 unsigned long *insnaddr;
471                                 unsigned long insn;
472                         } fpq[16];
473                 };
474                 struct fps __user *fps = (struct fps __user *) addr;
475                 int i;
476 
477                 i = verify_area(VERIFY_READ, fps, sizeof(struct fps));
478                 if(i) {
479                         pt_error_return(regs, -i);
480                         goto out_tsk;
481                 }
482                 copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long)));
483                 __get_user(child->thread.fsr, (&fps->fsr));
484                 __get_user(child->thread.fpqdepth, (&fps->fpqd));
485                 for(i = 0; i < 16; i++) {
486                         __get_user(child->thread.fpqueue[i].insn_addr,
487                                    (&fps->fpq[i].insnaddr));
488                         __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
489                 }
490                 pt_succ_return(regs, 0);
491                 goto out_tsk;
492         }
493 
494         case PTRACE_READTEXT:
495         case PTRACE_READDATA: {
496                 int res = ptrace_readdata(child, addr,
497                                           (void __user *) addr2, data);
498 
499                 if (res == data) {
500                         pt_succ_return(regs, 0);
501                         goto out_tsk;
502                 }
503                 /* Partial read is an IO failure */
504                 if (res >= 0)
505                         res = -EIO;
506                 pt_error_return(regs, -res);
507                 goto out_tsk;
508         }
509 
510         case PTRACE_WRITETEXT:
511         case PTRACE_WRITEDATA: {
512                 int res = ptrace_writedata(child, (void __user *) addr2,
513                                            addr, data);
514 
515                 if (res == data) {
516                         pt_succ_return(regs, 0);
517                         goto out_tsk;
518                 }
519                 /* Partial write is an IO failure */
520                 if (res >= 0)
521                         res = -EIO;
522                 pt_error_return(regs, -res);
523                 goto out_tsk;
524         }
525 
526         case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
527                 addr = 1;
528 
529         case PTRACE_CONT: { /* restart after signal. */
530                 if (data > _NSIG) {
531                         pt_error_return(regs, EIO);
532                         goto out_tsk;
533                 }
534 
535                 if (request == PTRACE_SYSCALL)
536                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
537                 else
538                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
539 
540                 child->exit_code = data;
541 #ifdef DEBUG_PTRACE
542                 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
543                         child->comm, child->pid, child->exit_code,
544                         child->thread.kregs->pc,
545                         child->thread.kregs->npc);
546 #endif
547                 wake_up_process(child);
548                 pt_succ_return(regs, 0);
549                 goto out_tsk;
550         }
551 
552 /*
553  * make the child exit.  Best I can do is send it a sigkill. 
554  * perhaps it should be put in the status that it wants to 
555  * exit.
556  */
557         case PTRACE_KILL: {
558                 if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
559                         pt_succ_return(regs, 0);
560                         goto out_tsk;
561                 }
562                 wake_up_process(child);
563                 child->exit_code = SIGKILL;
564                 pt_succ_return(regs, 0);
565                 goto out_tsk;
566         }
567 
568         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
569                 int err = ptrace_detach(child, data);
570                 if (err) {
571                         pt_error_return(regs, EIO);
572                         goto out_tsk;
573                 }
574                 pt_succ_return(regs, 0);
575                 goto out_tsk;
576         }
577 
578         /* PTRACE_DUMPCORE unsupported... */
579 
580         default: {
581                 int err = ptrace_request(child, request, addr, data);
582                 if (err)
583                         pt_error_return(regs, -err);
584                 else
585                         pt_succ_return(regs, 0);
586                 goto out_tsk;
587         }
588         }
589 out_tsk:
590         if (child)
591                 put_task_struct(child);
592 out:
593         unlock_kernel();
594 }
595 
596 asmlinkage void syscall_trace(void)
597 {
598 #ifdef DEBUG_PTRACE
599         printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
600 #endif
601         if (!test_thread_flag(TIF_SYSCALL_TRACE))
602                 return;
603         if (!(current->ptrace & PT_PTRACED))
604                 return;
605         current->thread.flags ^= MAGIC_CONSTANT;
606         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
607                                  ? 0x80 : 0));
608         /*
609          * this isn't the same as continuing with a signal, but it will do
610          * for normal use.  strace only continues with a signal if the
611          * stopping signal is not SIGTRAP.  -brl
612          */
613 #ifdef DEBUG_PTRACE
614         printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
615                 current->pid, current->exit_code);
616 #endif
617         if (current->exit_code) {
618                 send_sig (current->exit_code, current, 1);
619                 current->exit_code = 0;
620         }
621 }
622 
  This page was automatically generated by the LXR engine.