root/arch/alpha/kernel/ptrace.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. offset_of_register
  2. unset_singlestep
  3. set_singlestep
  4. get_task
  5. get_stack_long
  6. put_stack_long
  7. get_long
  8. put_long
  9. find_extend_vma
  10. read_long
  11. write_long
  12. set_success
  13. set_failure
  14. sys_ptrace
  15. syscall_trace

   1 /* ptrace.c */
   2 /* By Ross Biro 1/23/92 */
   3 /* edited by Linus Torvalds */
   4 /* mangled further by Bob Manson (manson@santafe.edu) */
   5 
   6 #include <linux/head.h>
   7 #include <linux/kernel.h>
   8 #include <linux/sched.h>
   9 #include <linux/mm.h>
  10 #include <linux/errno.h>
  11 #include <linux/ptrace.h>
  12 #include <linux/user.h>
  13 #include <linux/debugreg.h>
  14 
  15 #include <asm/segment.h>
  16 #include <asm/pgtable.h>
  17 #include <asm/system.h>
  18 
  19 /* This was determined via brute force. */
  20 #define MAGICNUM 496
  21 
  22 /*
  23  * does not yet catch signals sent when the child dies.
  24  * in exit.c or in signal.c.
  25  */
  26 
  27 /* determines which flags the user has access to. */
  28 /* 1 = access 0 = no access */
  29 #define FLAG_MASK 0x00044dd5
  30 
  31 /* set's the trap flag. */
  32 #define TRAP_FLAG 0x100
  33 
  34 /*
  35  * this is the number to subtract from the top of the stack. To find
  36  * the local frame.
  37  */
  38 
  39 /* A mapping between register number and its offset on the kernel stack.
  40  * You also need to add MAGICNUM to get past the kernel stack frame
  41  * to the actual saved user info.
  42  * The first portion is the switch_stack, then comes the pt_regs.
  43  * 320 is the size of the switch_stack area.
  44  */
  45 
  46 static int map_reg_to_offset[] = {
  47    320+0,320+8,320+16,320+24,320+32,320+40,320+48,320+56,320+64, /* 0-8 */
  48    0,8,16,24,32,40,48, /* 9-15 */
  49    320+184,320+192,320+200, /* 16-18 */
  50    320+72,320+80,320+88,320+96,320+104,320+112,320+120, /* 19-25 */
  51    320+128,320+136,320+144,320+176,320+160,-1, /* 26-31*/
  52 
  53    /* fp registers below */
  54    64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,
  55    200,208,216,224,232,240,248,256,264,272,280,288,296,304,312,
  56 
  57    /* 64 = pc */
  58    320+168
  59 };
  60 
  61 static int offset_of_register(int reg_num) {
     /* [previous][next][first][last][top][bottom][index][help] */
  62    if(reg_num<0 || reg_num>64) {
  63       return -1;
  64    }
  65    return map_reg_to_offset[reg_num];
  66 }
  67 
  68 static void unset_singlestep(struct task_struct *child) {
     /* [previous][next][first][last][top][bottom][index][help] */
  69 }
  70 
  71 static void set_singlestep(struct task_struct *child) {
     /* [previous][next][first][last][top][bottom][index][help] */
  72 }
  73 
  74 /* change a pid into a task struct. */
  75 static inline struct task_struct * get_task(int pid)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         int i;
  78 
  79         for (i = 1; i < NR_TASKS; i++) {
  80                 if (task[i] != NULL && (task[i]->pid == pid))
  81                         return task[i];
  82         }
  83         return NULL;
  84 }
  85 
  86 /*
  87  * this routine will get a word off of the processes privileged stack. 
  88  * the offset is how far from the base addr as stored in the TSS.  
  89  * this routine assumes that all the privileged stacks are in our
  90  * data space.
  91  * MAGICNUM is the amount to skip to get to the actual user regs. It
  92  * was determined by brute force & asking BufElves.
  93  */   
  94 static inline long get_stack_long(struct task_struct *task, unsigned long offset)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96         unsigned char *stack;
  97 
  98         stack = (unsigned char *)task->tss.ksp;
  99         stack += offset+MAGICNUM;
 100         return (*((long *)stack));
 101 }
 102 
 103 /*
 104  * this routine will put a word on the processes privileged stack. 
 105  * the offset is how far from the base addr as stored in the TSS.  
 106  * this routine assumes that all the privileged stacks are in our
 107  * data space.
 108  */
 109 static inline int put_stack_long(struct task_struct *task, unsigned long offset,
     /* [previous][next][first][last][top][bottom][index][help] */
 110         unsigned long data)
 111 {
 112         unsigned char * stack;
 113 
 114         stack = (unsigned char *) task->tss.ksp;
 115         stack += offset+MAGICNUM;
 116         *(unsigned long *) stack = data;
 117         return 0;
 118 }
 119 
 120 /*
 121  * This routine gets a long from any process space by following the page
 122  * tables. NOTE! You should check that the long isn't on a page boundary,
 123  * and that it is in the task area before calling this: this routine does
 124  * no checking.
 125  */
 126 static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 127 {
 128         pgd_t * pgdir;
 129         pmd_t * pgmiddle;
 130         pte_t * pgtable;
 131         unsigned long page;
 132 
 133 #ifdef DEBUG
 134         printk("Getting long at 0x%lx\n",addr);
 135 #endif
 136 repeat:
 137         pgdir = pgd_offset(vma->vm_task, addr);
 138         if (pgd_none(*pgdir)) {
 139                 do_no_page(vma, addr, 0);
 140                 goto repeat;
 141         }
 142         if (pgd_bad(*pgdir)) {
 143                 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
 144                 pgd_clear(pgdir);
 145                 return 0;
 146         }
 147         pgmiddle = pmd_offset(pgdir, addr);
 148         if (pmd_none(*pgmiddle)) {
 149                 do_no_page(vma, addr, 0);
 150                 goto repeat;
 151         }
 152         if (pmd_bad(*pgmiddle)) {
 153                 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
 154                 pmd_clear(pgmiddle);
 155                 return 0;
 156         }
 157         pgtable = pte_offset(pgmiddle, addr);
 158         if (!pte_present(*pgtable)) {
 159                 do_no_page(vma, addr, 0);
 160                 goto repeat;
 161         }
 162         page = pte_page(*pgtable);
 163 /* this is a hack for non-kernel-mapped video buffers and similar */
 164         if (page >= high_memory)
 165                 return 0;
 166         page += addr & ~PAGE_MASK;
 167         return *(unsigned long *) page;
 168 }
 169 
 170 /*
 171  * This routine puts a long into any process space by following the page
 172  * tables. NOTE! You should check that the long isn't on a page boundary,
 173  * and that it is in the task area before calling this: this routine does
 174  * no checking.
 175  *
 176  * Now keeps R/W state of page so that a text page stays readonly
 177  * even if a debugger scribbles breakpoints into it.  -M.U-
 178  */
 179 static void put_long(struct vm_area_struct * vma, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 180         unsigned long data)
 181 {
 182         pgd_t *pgdir;
 183         pmd_t *pgmiddle;
 184         pte_t *pgtable;
 185         unsigned long page;
 186 
 187 repeat:
 188         pgdir = pgd_offset(vma->vm_task, addr);
 189         if (!pgd_present(*pgdir)) {
 190                 do_no_page(vma, addr, 1);
 191                 goto repeat;
 192         }
 193         if (pgd_bad(*pgdir)) {
 194                 printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
 195                 pgd_clear(pgdir);
 196                 return;
 197         }
 198         pgmiddle = pmd_offset(pgdir, addr);
 199         if (pmd_none(*pgmiddle)) {
 200                 do_no_page(vma, addr, 1);
 201                 goto repeat;
 202         }
 203         if (pmd_bad(*pgmiddle)) {
 204                 printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
 205                 pmd_clear(pgmiddle);
 206                 return;
 207         }
 208         pgtable = pte_offset(pgmiddle, addr);
 209         if (!pte_present(*pgtable)) {
 210                 do_no_page(vma, addr, 1);
 211                 goto repeat;
 212         }
 213         page = pte_page(*pgtable);
 214         if (!pte_write(*pgtable)) {
 215                 do_wp_page(vma, addr, 1);
 216                 goto repeat;
 217         }
 218 /* this is a hack for non-kernel-mapped video buffers and similar */
 219         if (page < high_memory) {
 220                 page += addr & ~PAGE_MASK;
 221                 *(unsigned long *) page = data;
 222         }
 223 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 224 /* this should also re-instate whatever read-only mode there was before */
 225         *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
 226         invalidate();
 227 }
 228 
 229 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231         struct vm_area_struct * vma;
 232 
 233         addr &= PAGE_MASK;
 234         vma = find_vma(tsk,addr);
 235         if (!vma)
 236                 return NULL;
 237         if (vma->vm_start <= addr)
 238                 return vma;
 239         if (!(vma->vm_flags & VM_GROWSDOWN))
 240                 return NULL;
 241         if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
 242                 return NULL;
 243         vma->vm_offset -= vma->vm_start - addr;
 244         vma->vm_start = addr;
 245         return vma;
 246 }
 247 
 248 /*
 249  * This routine checks the page boundaries, and that the offset is
 250  * within the task area. It then calls get_long() to read a long.
 251  */
 252 static int read_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 253         unsigned long * result)
 254 {
 255         struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 256 
 257 #ifdef DEBUG
 258         printk("in read_long\n");
 259 #endif
 260         if (!vma) {
 261                 printk("Unable to find vma for addr 0x%lx\n",addr);
 262                 return -EIO;
 263         }
 264         if ((addr & ~PAGE_MASK) > (PAGE_SIZE-sizeof(long))) {
 265                 unsigned long low,high;
 266                 struct vm_area_struct * vma_high = vma;
 267 
 268                 if (addr + sizeof(long) >= vma->vm_end) {
 269                         vma_high = vma->vm_next;
 270                         if (!vma_high || vma_high->vm_start != vma->vm_end)
 271                                 return -EIO;
 272                 }
 273                 low = get_long(vma, addr & ~(sizeof(long)-1));
 274                 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
 275                 switch (addr & (sizeof(long)-1)) {
 276                         case 1:
 277                                 low >>= 8;
 278                                 low |= high << 56;
 279                                 break;
 280                         case 2:
 281                                 low >>= 16;
 282                                 low |= high << 48;
 283                                 break;
 284                         case 3:
 285                                 low >>= 24;
 286                                 low |= high << 40;
 287                                 break;
 288                         case 4:
 289                                 low >>= 32;
 290                                 low |= high << 32;
 291                                 break;
 292                         case 5:
 293                                 low >>= 40;
 294                                 low |= high << 24;
 295                                 break;
 296                         case 6:
 297                                 low >>= 48;
 298                                 low |= high << 16;
 299                                 break;
 300                         case 7:
 301                                 low >>= 56;
 302                                 low |= high << 8;
 303                                 break;
 304                 }
 305                 *result = low;
 306         } else {
 307                 long l =get_long(vma, addr);
 308 
 309 #ifdef DEBUG
 310                 printk("value is 0x%lx\n",l);
 311 #endif
 312                 *result = l;
 313         }
 314         return 0;
 315 }
 316 
 317 /*
 318  * This routine checks the page boundaries, and that the offset is
 319  * within the task area. It then calls put_long() to write a long.
 320  */
 321 static int write_long(struct task_struct * tsk, unsigned long addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 322         unsigned long data)
 323 {
 324         struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 325 
 326         if (!vma)
 327                 return -EIO;
 328         if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
 329                 unsigned long low,high;
 330                 struct vm_area_struct * vma_high = vma;
 331 
 332                 if (addr + sizeof(long) >= vma->vm_end) {
 333                         vma_high = vma->vm_next;
 334                         if (!vma_high || vma_high->vm_start != vma->vm_end)
 335                                 return -EIO;
 336                 }
 337                 low = get_long(vma, addr & ~(sizeof(long)-1));
 338                 high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
 339                 switch (addr & (sizeof(long)-1)) {
 340                         case 0: /* shouldn't happen, but safety first */
 341                                 low = data;
 342                                 break;
 343                         case 1:
 344                                 low &= 0x00000000000000ffL;
 345                                 low |= data << 8;
 346                                 high &= ~0x000000000000ffL;
 347                                 high |= data >> 56;
 348                                 break;
 349                         case 2:
 350                                 low &= 0x000000000000ffffL;
 351                                 low |= data << 16;
 352                                 high &= ~0x0000000000ffffL;
 353                                 high |= data >> 48;
 354                                 break;
 355                         case 3:
 356                                 low &= 0x0000000000ffffffL;
 357                                 low |= data << 24;
 358                                 high &= ~0x00000000ffffffL;
 359                                 high |= data >> 40;
 360                                 break;
 361                         case 4:
 362                                 low &= 0x00000000ffffffffL;
 363                                 low |= data << 32;
 364                                 high &= ~0x000000ffffffffL;
 365                                 high |= data >> 32;
 366                                 break;
 367 
 368                         case 5:
 369                                 low &= 0x000000ffffffffffL;
 370                                 low |= data << 40;
 371                                 high &= ~0x0000ffffffffffL;
 372                                 high |= data >> 24;
 373                                 break;
 374                         case 6:
 375                                 low &= 0x0000ffffffffffffL;
 376                                 low |= data << 48;
 377                                 high &= ~0x00ffffffffffffL;
 378                                 high |= data >> 16;
 379                                 break;
 380                         case 7:
 381                                 low &= 0x00ffffffffffffffL;
 382                                 low |= data << 56;
 383                                 high &= ~0xffffffffffffffL;
 384                                 high |= data >> 8;
 385                                 break;
 386                 }
 387                 put_long(vma, addr & ~(sizeof(long)-1),low);
 388                 put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
 389         } else
 390                 put_long(vma, addr, data);
 391         return 0;
 392 }
 393 
 394 /* Uh, this does ugly stuff. It stores the specified value in the a3
 395  * register. entry.S will swap a3 and the returned value from
 396  * sys_ptrace() before returning to the user.
 397  */
 398 
 399 static inline void set_success(struct pt_regs *regs,long resval) {
     /* [previous][next][first][last][top][bottom][index][help] */
 400    regs->r19=resval;
 401 }
 402 
 403 /* This doesn't do diddly, actually--if the value returned from 
 404  * sys_ptrace() is != 0, it sets things up properly.
 405  */
 406 
 407 static inline void set_failure(struct pt_regs *regs,long errcode) {
     /* [previous][next][first][last][top][bottom][index][help] */
 408    regs->r19=0;
 409 }
 410 
 411 asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5, struct pt_regs regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 412 {
 413         struct task_struct *child;
 414         struct user * dummy;
 415 
 416         dummy = NULL;
 417 
 418 #ifdef DEBUG
 419         printk("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",request,pid,addr,data);
 420 #endif
 421         set_success(&regs,0);
 422         if (request == PTRACE_TRACEME) {
 423                 /* are we already being traced? */
 424            if (current->flags & PF_PTRACED) {
 425               set_failure(&regs,-EPERM);
 426               return -EPERM;
 427            }
 428            /* set the ptrace bit in the process flags. */
 429            current->flags |= PF_PTRACED;
 430            return 0;
 431         }
 432         if (pid == 1) {
 433            set_failure(&regs,-EPERM);
 434            return -EPERM;
 435         }
 436         if (!(child = get_task(pid))) {
 437            set_failure(&regs,-ESRCH);
 438            return -ESRCH;
 439         }
 440         if (request == PTRACE_ATTACH) {
 441            if (child == current) {
 442               set_failure(&regs,-EPERM);
 443               return -EPERM;
 444            }
 445            if ((!child->dumpable ||
 446                 (current->uid != child->euid) ||
 447                 (current->uid != child->uid) ||
 448                 (current->gid != child->egid) ||
 449                 (current->gid != child->gid)) && !suser()) {
 450               set_failure(&regs,-EPERM);
 451               return -EPERM;
 452            }
 453            /* the same process cannot be attached many times */
 454            if (child->flags & PF_PTRACED) {
 455               set_failure(&regs,-EPERM);
 456               return -EPERM;
 457            }
 458            child->flags |= PF_PTRACED;
 459            if (child->p_pptr != current) {
 460               REMOVE_LINKS(child);
 461               child->p_pptr = current;
 462               SET_LINKS(child);
 463            }
 464            send_sig(SIGSTOP, child, 1);
 465            return 0;
 466         }
 467         if (!(child->flags & PF_PTRACED)) {
 468 #ifdef DEBUG
 469            printk("child not traced\n");
 470 #endif
 471            set_failure(&regs,-ESRCH);
 472            return -ESRCH;
 473         }
 474         if (child->state != TASK_STOPPED) {
 475 #ifdef DEBUG
 476            printk("child process not stopped\n");
 477 #endif
 478            if (request != PTRACE_KILL) {
 479               set_failure(&regs,-ESRCH);
 480               return -ESRCH;
 481            }
 482         }
 483         if (child->p_pptr != current) {
 484 #ifdef DEBUG
 485            printk("child not parent of this process\n");
 486 #endif
 487            set_failure(&regs,-ESRCH);
 488            return -ESRCH;
 489         }
 490 
 491         switch (request) {
 492         /* when I and D space are separate, these will need to be fixed. */
 493                 case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 494                 case PTRACE_PEEKDATA: {
 495                         unsigned long tmp;
 496                         int res;
 497 
 498 #ifdef DEBUG
 499                         printk("doing request at addr 0x%lx\n",addr);
 500 #endif
 501                         res = read_long(child, addr, &tmp);
 502                         if (res < 0) {
 503                            set_failure(&regs,res);
 504                            return res;
 505                         }
 506                         else {
 507                            set_success(&regs,tmp);
 508                            return 0;
 509                         }
 510                 }
 511 
 512         /* read the word at location addr in the USER area. */
 513                 case PTRACE_PEEKUSR: {
 514                         /* We only allow access to registers. */
 515                         unsigned long tmp;
 516 
 517                         tmp = 0;  /* Default return condition */
 518                         if(addr==30) {
 519                            /* stack pointer */
 520                            tmp=child->tss.usp;
 521                         }
 522                         else {
 523                            int reg=addr;
 524                            addr = offset_of_register(addr);
 525                            if(addr < 0) {
 526                               set_failure(&regs,-EIO);
 527                               return -EIO;
 528                            }
 529                            tmp = get_stack_long(child, addr);
 530 #ifdef DEBUG
 531                            printk("%d = reg 0x%lx=tmp\n",reg,tmp);
 532 #endif
 533                         }
 534                         set_success(&regs,tmp);
 535                         return 0;
 536                 }
 537 
 538       /* when I and D space are separate, this will have to be fixed. */
 539                 case PTRACE_POKETEXT: /* write the word at location addr. */
 540                 case PTRACE_POKEDATA: {
 541                         long res=write_long(child,addr,data);
 542                         if(res) {
 543                            set_failure(&regs,res);
 544                         }
 545                         return res;
 546                 }
 547 
 548                 case PTRACE_POKEUSR: /* write the specified register */
 549                 {
 550                    long res;
 551                    addr= offset_of_register(addr);
 552                    if(addr < 0) {
 553                       set_failure(&regs,-EIO);
 554                       return -EIO;
 555                    }
 556                    res=put_stack_long(child,addr,data);
 557                    if(res) {
 558                       set_failure(&regs,res);
 559                    }
 560                    return res;
 561                 }
 562 
 563                 case PTRACE_SYSCALL: /* continue and stop at next 
 564                                         (return from) syscall */
 565                 case PTRACE_CONT: { /* restart after signal. */
 566                         if ((unsigned long) data > NSIG) {
 567                            set_failure(&regs,-EIO);
 568                            return -EIO;
 569                         }
 570                         if (request == PTRACE_SYSCALL)
 571                                 child->flags |= PF_TRACESYS;
 572                         else
 573                                 child->flags &= ~PF_TRACESYS;
 574                         child->exit_code = data;
 575                         child->state = TASK_RUNNING;
 576                         unset_singlestep(child);
 577                         set_success(&regs,data);
 578                         return 0;
 579                 }
 580 
 581 /*
 582  * make the child exit.  Best I can do is send it a sigkill. 
 583  * perhaps it should be put in the status that it wants to 
 584  * exit.
 585  */
 586                 case PTRACE_KILL: {
 587                         child->state = TASK_RUNNING;
 588                         child->exit_code = SIGKILL;
 589                         unset_singlestep(child);
 590                         return 0;
 591                 }
 592 
 593                 case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 594                         if ((unsigned long) data > NSIG) {
 595                            set_failure(&regs,-EIO);
 596                            return -EIO;
 597                         }
 598                         child->flags &= ~PF_TRACESYS;
 599                         set_singlestep(child);
 600                         child->state = TASK_RUNNING;
 601                         child->exit_code = data;
 602                         /* give it a chance to run. */
 603                         return 0;
 604                 }
 605 
 606                 case PTRACE_DETACH: { /* detach a process that was attached. */
 607                         if ((unsigned long) data > NSIG) {
 608                            set_failure(&regs,-EIO);
 609                            return -EIO;
 610                         }
 611                         child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 612                         child->state = TASK_RUNNING;
 613                         child->exit_code = data;
 614                         REMOVE_LINKS(child);
 615                         child->p_pptr = child->p_opptr;
 616                         SET_LINKS(child);
 617                         /* make sure the single step bit is not set. */
 618                         unset_singlestep(child);
 619                         return 0;
 620                 }
 621 
 622                 default:
 623                 {
 624                    set_failure(&regs,-EIO);
 625                    return -EIO;
 626                 }
 627         }
 628 }
 629 
 630 asmlinkage void syscall_trace(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 631 {
 632         if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 633                         != (PF_PTRACED|PF_TRACESYS))
 634                 return;
 635         current->exit_code = SIGTRAP;
 636         current->state = TASK_STOPPED;
 637         notify_parent(current);
 638         schedule();
 639         /*
 640          * this isn't the same as continuing with a signal, but it will do
 641          * for normal use.  strace only continues with a signal if the
 642          * stopping signal is not SIGTRAP.  -brl
 643          */
 644         if (current->exit_code)
 645                 current->signal |= (1 << (current->exit_code - 1));
 646         current->exit_code = 0;
 647 }

/* [previous][next][first][last][top][bottom][index][help] */