linux-old/arch/s390x/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/kernel/ptrace.c
   3 *
   4 *  S390 version
   5 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
   6 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
   7 *
   8 *  Based on PowerPC version 
   9 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  10 *
  11 *  Derived from "arch/m68k/kernel/ptrace.c"
  12 *  Copyright (C) 1994 by Hamish Macdonald
  13 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
  14 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
  15 *
  16 * Modified by Cort Dougan (cort@cs.nmt.edu) 
  17 *
  18 *
  19 * This file is subject to the terms and conditions of the GNU General
  20 * Public License.  See the file README.legal in the main directory of
  21 * this archive for more details.
  22 */
  23
  24#include <stddef.h>
  25#include <linux/config.h>
  26#include <linux/kernel.h>
  27#include <linux/sched.h>
  28#include <linux/mm.h>
  29#include <linux/smp.h>
  30#include <linux/smp_lock.h>
  31#include <linux/errno.h>
  32#include <linux/ptrace.h>
  33#include <linux/user.h>
  34
  35#include <asm/segment.h>
  36#include <asm/page.h>
  37#include <asm/pgtable.h>
  38#include <asm/pgalloc.h>
  39#include <asm/system.h>
  40#include <asm/uaccess.h>
  41#ifdef CONFIG_S390_SUPPORT
  42#include "linux32.h"
  43#else
  44#define parent_31bit 0
  45#endif
  46
  47
  48void FixPerRegisters(struct task_struct *task)
  49{
  50        struct pt_regs *regs = __KSTK_PTREGS(task);
  51        per_struct *per_info=
  52                        (per_struct *)&task->thread.per_info;
  53
  54        per_info->control_regs.bits.em_instruction_fetch =
  55                per_info->single_step | per_info->instruction_fetch;
  56        
  57        if (per_info->single_step) {
  58                per_info->control_regs.bits.starting_addr=0;
  59#ifdef CONFIG_S390_SUPPORT
  60                if (current->thread.flags & S390_FLAG_31BIT) {
  61                        per_info->control_regs.bits.ending_addr=0x7fffffffUL;
  62                }
  63                else 
  64#endif      
  65                {
  66                per_info->control_regs.bits.ending_addr=-1L;
  67                }
  68        } else {
  69                per_info->control_regs.bits.starting_addr=
  70                        per_info->starting_addr;
  71                per_info->control_regs.bits.ending_addr=
  72                        per_info->ending_addr;
  73        }
  74        /* if any of the control reg tracing bits are on 
  75           we switch on per in the psw */
  76        if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
  77                regs->psw.mask |= PSW_PER_MASK;
  78        else
  79                regs->psw.mask &= ~PSW_PER_MASK;
  80        if (per_info->control_regs.bits.storage_alt_space_ctl)
  81                task->thread.user_seg |= USER_STD_MASK;
  82        else
  83                task->thread.user_seg &= ~USER_STD_MASK;
  84}
  85
  86void set_single_step(struct task_struct *task)
  87{
  88        per_struct *per_info= (per_struct *) &task->thread.per_info;    
  89        
  90        per_info->single_step = 1;  /* Single step */
  91        FixPerRegisters (task);
  92}
  93
  94void clear_single_step(struct task_struct *task)
  95{
  96        per_struct *per_info= (per_struct *) &task->thread.per_info;
  97
  98        per_info->single_step = 0;
  99        FixPerRegisters (task);
 100}
 101
 102int ptrace_usercopy(addr_t realuseraddr, addr_t copyaddr, int len,
 103                    int tofromuser, int writeuser, unsigned long mask)
 104{
 105        unsigned long *realuserptr, *copyptr;
 106        unsigned long tempuser;
 107        int retval;
 108
 109        retval = 0;
 110        realuserptr = (unsigned long *) realuseraddr;
 111        copyptr = (unsigned long *) copyaddr;
 112
 113        if (writeuser && realuserptr == NULL)
 114                return 0;
 115
 116        if (mask != -1L) {
 117                tempuser = *realuserptr;
 118                if (!writeuser) {
 119                        tempuser &= mask;
 120                        realuserptr = &tempuser;
 121                }
 122        }
 123        if (tofromuser) {
 124                if (writeuser) {
 125                        retval = copy_from_user(realuserptr, copyptr, len);
 126                } else {
 127                        if (realuserptr == NULL)
 128                                retval = clear_user(copyptr, len);
 129                        else
 130                                retval = copy_to_user(copyptr,realuserptr,len);
 131                }      
 132                retval = retval ? -EFAULT : 0;
 133        } else {
 134                if (writeuser)
 135                        memcpy(realuserptr, copyptr, len);
 136                else
 137                        memcpy(copyptr, realuserptr, len);
 138        }
 139        if (mask != -1L && writeuser)
 140                *realuserptr = (*realuserptr & mask) | (tempuser & ~mask);
 141        return retval;
 142}
 143
 144#ifdef CONFIG_S390_SUPPORT
 145
 146typedef struct
 147{
 148        __u32 cr[3];
 149} per_cr_words32  __attribute__((packed));
 150
 151typedef struct
 152{
 153        __u16          perc_atmid;          /* 0x096 */
 154        __u32          address;             /* 0x098 */
 155        __u8           access_id;           /* 0x0a1 */
 156} per_lowcore_words32  __attribute__((packed));
 157
 158typedef struct
 159{
 160        union {
 161                per_cr_words32   words;
 162        } control_regs  __attribute__((packed));
 163        /*
 164         * Use these flags instead of setting em_instruction_fetch
 165         * directly they are used so that single stepping can be
 166         * switched on & off while not affecting other tracing
 167         */
 168        unsigned  single_step       : 1;
 169        unsigned  instruction_fetch : 1;
 170        unsigned                    : 30;
 171        /*
 172         * These addresses are copied into cr10 & cr11 if single
 173         * stepping is switched off
 174         */
 175        __u32     starting_addr;
 176        __u32     ending_addr;
 177        union {
 178                per_lowcore_words32 words;
 179        } lowcore; 
 180} per_struct32 __attribute__((packed));
 181
 182struct user_regs_struct32
 183{
 184        _psw_t32 psw;
 185        u32 gprs[NUM_GPRS];
 186        u32 acrs[NUM_ACRS];
 187        u32 orig_gpr2;
 188        s390_fp_regs fp_regs;
 189        /*
 190         * These per registers are in here so that gdb can modify them
 191         * itself as there is no "official" ptrace interface for hardware
 192         * watchpoints. This is the way intel does it.
 193         */
 194        per_struct32 per_info;
 195        u32  ieee_instruction_pointer; 
 196        /* Used to give failing instruction back to user for ieee exceptions */
 197};
 198
 199struct user32 {
 200                                  /* We start with the registers, to mimic the way that "memory" is returned
 201                                   from the ptrace(3,...) function.  */
 202  struct user_regs_struct32 regs; /* Where the registers are actually stored */
 203                                  /* The rest of this junk is to help gdb figure out what goes where */
 204  u32 u_tsize;                    /* Text segment size (pages). */
 205  u32 u_dsize;                    /* Data segment size (pages). */
 206  u32 u_ssize;                    /* Stack segment size (pages). */
 207  u32 start_code;                 /* Starting virtual address of text. */
 208  u32 start_stack;                /* Starting virtual address of stack area.
 209                                   This is actually the bottom of the stack,
 210                                   the top of the stack is always found in the
 211                                   esp register.  */
 212  s32 signal;                     /* Signal that caused the core dump. */
 213  u32 u_ar0;                      /* Used by gdb to help find the values for */
 214                                  /* the registers. */
 215  u32 magic;                      /* To uniquely identify a core file */
 216  char u_comm[32];                /* User command that was responsible */
 217};
 218
 219
 220#define PT32_PSWMASK  0x0
 221#define PT32_PSWADDR  0x04
 222#define PT32_GPR0     0x08
 223#define PT32_GPR15    0x44
 224#define PT32_ACR0     0x48
 225#define PT32_ACR15    0x84
 226#define PT32_ORIGGPR2 0x88
 227#define PT32_FPC      0x90
 228#define PT32_FPR0_HI  0x98
 229#define PT32_FPR15_LO 0x114
 230#define PT32_CR_9     0x118
 231#define PT32_CR_11    0x120
 232#define PT32_IEEE_IP  0x13C
 233#define PT32_LASTOFF  PT32_IEEE_IP
 234#define PT32_ENDREGS  0x140-1
 235#define U32OFFSETOF(member) offsetof(struct user32,regs.member)
 236#define U64OFFSETOF(member) offsetof(struct user,regs.member)
 237#define U6432DIFF(member) (U64OFFSETOF(member) - U32OFFSETOF(member))
 238#define PT_SINGLE_STEP   (PT_CR_11+8)
 239#define PT32_SINGLE_STEP (PT32_CR_11+4)
 240
 241#endif /* CONFIG_S390_SUPPORT */
 242
 243int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
 244              int len, int tofromuser, int writingtouser)
 245{
 246        int copylen=0,copymax;
 247        addr_t  realuseraddr;
 248        saddr_t enduseraddr;
 249        unsigned long mask;
 250#ifdef CONFIG_S390_SUPPORT
 251        int     parent_31bit=current->thread.flags & S390_FLAG_31BIT;
 252        int     skip;
 253#endif
 254        enduseraddr=useraddr+len;
 255        if ((useraddr<0||useraddr&3||enduseraddr&3)||
 256#ifdef CONFIG_S390_SUPPORT
 257            (parent_31bit && enduseraddr > sizeof(struct user32)) ||
 258#endif
 259            enduseraddr > sizeof(struct user))
 260                return (-EIO);
 261
 262#ifdef CONFIG_S390_SUPPORT
 263        if(parent_31bit)
 264        {
 265                if(useraddr != PT32_PSWMASK)
 266                {
 267                        if (useraddr == PT32_PSWADDR)
 268                                useraddr = PT_PSWADDR+4;
 269                        else if(useraddr <= PT32_GPR15)
 270                                useraddr = ((useraddr-PT32_GPR0)*2) + PT_GPR0+4;
 271                        else if(useraddr <= PT32_ACR15)
 272                                useraddr += PT_ACR0-PT32_ACR0;
 273                        else if(useraddr == PT32_ORIGGPR2)
 274                                useraddr = PT_ORIGGPR2+4;
 275                        else if(useraddr <= PT32_FPR15_LO)
 276                                useraddr += PT_FPR0-PT32_FPR0_HI;
 277                        else if(useraddr <= PT32_CR_11)
 278                                useraddr = ((useraddr-PT32_CR_9)*2) + PT_CR_9+4;
 279                        else if(useraddr ==  PT32_SINGLE_STEP)
 280                                useraddr = PT_SINGLE_STEP; 
 281                        else if(useraddr <= U32OFFSETOF(per_info.ending_addr))  
 282                                useraddr = (((useraddr-U32OFFSETOF(per_info.starting_addr)))*2) + 
 283                                        U64OFFSETOF(per_info.starting_addr)+4;
 284                        else if( useraddr == U32OFFSETOF(per_info.lowcore.words.perc_atmid))
 285                                useraddr = U64OFFSETOF(per_info.lowcore.words.perc_atmid);
 286                        else if( useraddr == U32OFFSETOF(per_info.lowcore.words.address))
 287                                useraddr = U64OFFSETOF(per_info.lowcore.words.address)+4;
 288                        else if(useraddr == U32OFFSETOF(per_info.lowcore.words.access_id))
 289                                useraddr = U64OFFSETOF(per_info.lowcore.words.access_id);
 290                        else if(useraddr == PT32_IEEE_IP)
 291                                useraddr = PT_IEEE_IP+4;
 292                }
 293        }
 294#endif /* CONFIG_S390_SUPPORT */
 295
 296        while(len>0)
 297        {
 298#ifdef CONFIG_S390_SUPPORT
 299                skip=0;
 300#endif
 301                mask=PSW_ADDR_MASK;
 302                if(useraddr<PT_FPC)
 303                {
 304                        realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
 305                        if(useraddr<(PT_PSWMASK+8))
 306                        {
 307                                if(parent_31bit)
 308                                {
 309                                        copymax=PT_PSWMASK+4;
 310#ifdef CONFIG_S390_SUPPORT
 311                                        skip=8;
 312#endif
 313                                }
 314                                else
 315                                {
 316                                        copymax=PT_PSWMASK+8;
 317                                }
 318                                if(writingtouser)
 319                                        mask=PSW_MASK_DEBUGCHANGE;
 320                        }
 321                        else if(useraddr<(PT_PSWADDR+8))
 322                        {
 323                                copymax=PT_PSWADDR+8;
 324                                mask=PSW_ADDR_DEBUGCHANGE;
 325#ifdef CONFIG_S390_SUPPORT
 326                                if(parent_31bit)
 327                                        skip=4;
 328#endif
 329
 330                        }
 331                        else
 332                        {
 333#ifdef CONFIG_S390_SUPPORT
 334                                if(parent_31bit && useraddr <= PT_GPR15+4)
 335                                {
 336                                        copymax=useraddr+4;
 337                                        if(useraddr<PT_GPR15+4)
 338                                                skip=4;
 339                                }
 340                                else
 341#endif
 342                                        copymax=PT_FPC;
 343                        }
 344                }
 345                else if(useraddr<(PT_FPR15+sizeof(freg_t)))
 346                {
 347                        copymax=(PT_FPR15+sizeof(freg_t));
 348                        realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
 349                }
 350                else if(useraddr<sizeof(struct user_regs_struct))
 351                {
 352#ifdef CONFIG_S390_SUPPORT
 353                        if( parent_31bit && useraddr <= PT_IEEE_IP+4)
 354                        {
 355                                switch(useraddr)
 356                                {
 357                                case PT_CR_11+4:
 358                                case U64OFFSETOF(per_info.ending_addr)+4:
 359                                case U64OFFSETOF(per_info.lowcore.words.address)+4:
 360                                        copymax=useraddr+4;
 361                                        break;
 362                                case  PT_SINGLE_STEP:
 363                                case  U64OFFSETOF(per_info.lowcore.words.perc_atmid):
 364                                        /* We copy 2 bytes in excess for the atmid member this also gets around */
 365                                        /* alignment for this member in 32 bit */
 366                                        skip=8;
 367                                        copymax=useraddr+4;
 368                                        break;
 369                                default: 
 370                                        copymax=useraddr+4;
 371                                        skip=4;
 372                                }
 373                        }
 374                        else
 375#endif
 376                        {
 377                                copymax=sizeof(struct user_regs_struct);
 378                        }
 379                        realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
 380                }
 381                else 
 382                {
 383                        copymax=sizeof(struct user);
 384                        realuseraddr=(addr_t)NULL;
 385                }
 386                copylen=copymax-useraddr;
 387                copylen=(copylen>len ? len:copylen);
 388                if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
 389                        return (-EIO);
 390                copyaddr+=copylen;
 391                len-=copylen;
 392                useraddr+=copylen
 393#if CONFIG_S390_SUPPORT
 394                        +skip
 395#endif
 396                        ;
 397        }
 398        FixPerRegisters(task);
 399        return(0);
 400}
 401
 402/*
 403 * Called by kernel/ptrace.c when detaching..
 404 *
 405 * Make sure single step bits etc are not set.
 406 */
 407void ptrace_disable(struct task_struct *child)
 408{
 409        /* make sure the single step bit is not set. */
 410        clear_single_step(child);
 411}
 412
 413typedef struct
 414{
 415__u32   len;
 416__u32   kernel_addr;
 417__u32   process_addr;
 418} ptrace_area_emu31;
 419
 420
 421asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 422{
 423        struct task_struct *child;
 424        int ret = -EPERM;
 425        int copied;
 426#ifdef CONFIG_S390_SUPPORT
 427        int           parent_31bit;
 428        int           sizeof_parent_long;
 429        u8            *dataptr;
 430#else
 431#define sizeof_parent_long 8
 432#define dataptr (u8 *)&data
 433#endif
 434        lock_kernel();
 435        if (request == PTRACE_TRACEME) 
 436        {
 437                /* are we already being traced? */
 438                if (current->ptrace & PT_PTRACED)
 439                        goto out;
 440                /* set the ptrace bit in the process flags. */
 441                current->ptrace |= PT_PTRACED;
 442                ret = 0;
 443                goto out;
 444        }
 445        ret = -ESRCH;
 446        read_lock(&tasklist_lock);
 447        child = find_task_by_pid(pid);
 448        if (child)
 449                get_task_struct(child);
 450        read_unlock(&tasklist_lock);
 451        if (!child)
 452                goto out;
 453        ret = -EPERM;
 454        if (pid == 1)           /* you may not mess with init */
 455                goto out_tsk;
 456        if (request == PTRACE_ATTACH) 
 457        {
 458                ret = ptrace_attach(child);
 459                goto out_tsk;
 460        }
 461        ret = -ESRCH;
 462        // printk("child=%lX child->flags=%lX",child,child->flags);
 463        /* I added child!=current line so we can get the */
 464        /* ieee_instruction_pointer from the user structure DJB */
 465        if(child!=current)
 466        {
 467                if (!(child->ptrace & PT_PTRACED))
 468                        goto out_tsk;
 469                if (child->state != TASK_STOPPED) 
 470                {
 471                        if (request != PTRACE_KILL)
 472                                goto out_tsk;
 473                }
 474                if (child->p_pptr != current)
 475                        goto out_tsk;
 476        }
 477#ifdef CONFIG_S390_SUPPORT
 478        parent_31bit=(current->thread.flags & S390_FLAG_31BIT);
 479        sizeof_parent_long=(parent_31bit ? 4:8);
 480        dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);
 481#endif
 482        switch (request) 
 483        {
 484                /* If I and D space are separate, these will need to be fixed. */
 485        case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 486        case PTRACE_PEEKDATA: 
 487        {
 488                u8 tmp[8];
 489                copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0);
 490                ret = -EIO;
 491                if (copied != sizeof_parent_long)
 492                        break;
 493                ret = copy_to_user((void *)data,tmp,sizeof_parent_long);
 494                ret = ret ? -EFAULT : 0;
 495                break;
 496        
 497        }
 498                /* read the word at location addr in the USER area. */
 499        case PTRACE_PEEKUSR:
 500                ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
 501                break;
 502
 503                /* If I and D space are separate, this will have to be fixed. */
 504        case PTRACE_POKETEXT: /* write the word at location addr. */
 505        case PTRACE_POKEDATA:
 506                ret = 0;
 507                if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long)
 508                        break;
 509                ret = -EIO;
 510                break;
 511
 512        case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 513                ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
 514                break;
 515
 516        case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
 517        case PTRACE_CONT:        /* restart after signal. */
 518                ret = -EIO;
 519                if ((unsigned long) data >= _NSIG)
 520                        break;
 521                if (request == PTRACE_SYSCALL)
 522                        child->ptrace |= PT_TRACESYS;
 523                else
 524                        child->ptrace &= ~PT_TRACESYS;
 525                child->exit_code = data;
 526                /* make sure the single step bit is not set. */
 527                clear_single_step(child);
 528                wake_up_process(child);
 529                ret = 0;
 530                break;
 531
 532/*
 533 * make the child exit.  Best I can do is send it a sigkill. 
 534 * perhaps it should be put in the status that it wants to 
 535 * exit.
 536 */
 537        case PTRACE_KILL:
 538                ret = 0;
 539                if (child->state == TASK_ZOMBIE) /* already dead */
 540                        break;
 541                child->exit_code = SIGKILL;
 542                clear_single_step(child);
 543                wake_up_process(child);
 544                /* make sure the single step bit is not set. */
 545                break;
 546
 547        case PTRACE_SINGLESTEP:  /* set the trap flag. */
 548                ret = -EIO;
 549                if ((unsigned long) data >= _NSIG)
 550                        break;
 551                child->ptrace &= ~PT_TRACESYS;
 552                child->exit_code = data;
 553                set_single_step(child);
 554                /* give it a chance to run. */
 555                wake_up_process(child);
 556                ret = 0;
 557                break;
 558
 559        case PTRACE_DETACH:  /* detach a process that was attached. */
 560                ret = ptrace_detach(child, data);
 561                break;
 562
 563        case PTRACE_PEEKUSR_AREA:
 564        case PTRACE_POKEUSR_AREA:
 565                if(parent_31bit)
 566                {
 567                        ptrace_area_emu31   parea; 
 568                        if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
 569                                ret=copy_user(child,parea.kernel_addr,parea.process_addr,
 570                                              parea.len,1,(request==PTRACE_POKEUSR_AREA));
 571                        else ret = -EFAULT;
 572                }
 573                else
 574                {
 575                        ptrace_area   parea; 
 576                        if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
 577                                ret=copy_user(child,parea.kernel_addr,parea.process_addr,
 578                                              parea.len,1,(request==PTRACE_POKEUSR_AREA));
 579                        else ret = -EFAULT;
 580                }
 581                break;
 582        default:
 583                ret = -EIO;
 584                break;
 585        }
 586 out_tsk:
 587        free_task_struct(child);
 588 out:
 589        unlock_kernel();
 590        return ret;
 591}
 592
 593
 594
 595asmlinkage void syscall_trace(void)
 596{
 597        lock_kernel();
 598        if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
 599            != (PT_PTRACED|PT_TRACESYS))
 600                goto out;
 601        current->exit_code = SIGTRAP;
 602        set_current_state(TASK_STOPPED);
 603        notify_parent(current, SIGCHLD);
 604        schedule();
 605        /*
 606         * this isn't the same as continuing with a signal, but it will do
 607         * for normal use.  strace only continues with a signal if the
 608         * stopping signal is not SIGTRAP.  -brl
 609         */
 610        if (current->exit_code) {
 611                send_sig(current->exit_code, current, 1);
 612                current->exit_code = 0;
 613        }
 614 out:
 615        unlock_kernel();
 616}
 617
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.