linux/arch/um/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include "linux/audit.h"
   7#include "linux/ptrace.h"
   8#include "linux/sched.h"
   9#include "asm/uaccess.h"
  10#ifdef CONFIG_PROC_MM
  11#include "proc_mm.h"
  12#endif
  13#include "skas_ptrace.h"
  14
  15static inline void set_singlestepping(struct task_struct *child, int on)
  16{
  17        if (on)
  18                child->ptrace |= PT_DTRACE;
  19        else
  20                child->ptrace &= ~PT_DTRACE;
  21        child->thread.singlestep_syscall = 0;
  22
  23#ifdef SUBARCH_SET_SINGLESTEPPING
  24        SUBARCH_SET_SINGLESTEPPING(child, on);
  25#endif
  26}
  27
  28/*
  29 * Called by kernel/ptrace.c when detaching..
  30 */
  31void ptrace_disable(struct task_struct *child)
  32{
  33        set_singlestepping(child,0);
  34}
  35
  36extern int peek_user(struct task_struct * child, long addr, long data);
  37extern int poke_user(struct task_struct * child, long addr, long data);
  38
  39long arch_ptrace(struct task_struct *child, long request, long addr, long data)
  40{
  41        int i, ret;
  42        unsigned long __user *p = (void __user *)(unsigned long)data;
  43
  44        switch (request) {
  45        /* read word at location addr. */
  46        case PTRACE_PEEKTEXT:
  47        case PTRACE_PEEKDATA:
  48                ret = generic_ptrace_peekdata(child, addr, data);
  49                break;
  50
  51        /* read the word at location addr in the USER area. */
  52        case PTRACE_PEEKUSR:
  53                ret = peek_user(child, addr, data);
  54                break;
  55
  56        /* write the word at location addr. */
  57        case PTRACE_POKETEXT:
  58        case PTRACE_POKEDATA:
  59                ret = generic_ptrace_pokedata(child, addr, data);
  60                break;
  61
  62        /* write the word at location addr in the USER area */
  63        case PTRACE_POKEUSR:
  64                ret = poke_user(child, addr, data);
  65                break;
  66
  67        case PTRACE_SYSEMU:
  68        case PTRACE_SYSEMU_SINGLESTEP:
  69                ret = -EIO;
  70                break;
  71
  72        /* continue and stop at next (return from) syscall */
  73        case PTRACE_SYSCALL:
  74        /* restart after signal. */
  75        case PTRACE_CONT: {
  76                ret = -EIO;
  77                if (!valid_signal(data))
  78                        break;
  79
  80                set_singlestepping(child, 0);
  81                if (request == PTRACE_SYSCALL)
  82                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  83                else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  84                child->exit_code = data;
  85                wake_up_process(child);
  86                ret = 0;
  87                break;
  88        }
  89
  90/*
  91 * make the child exit.  Best I can do is send it a sigkill.
  92 * perhaps it should be put in the status that it wants to
  93 * exit.
  94 */
  95        case PTRACE_KILL: {
  96                ret = 0;
  97                if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
  98                        break;
  99
 100                set_singlestepping(child, 0);
 101                child->exit_code = SIGKILL;
 102                wake_up_process(child);
 103                break;
 104        }
 105
 106        case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 107                ret = -EIO;
 108                if (!valid_signal(data))
 109                        break;
 110                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 111                set_singlestepping(child, 1);
 112                child->exit_code = data;
 113                /* give it a chance to run. */
 114                wake_up_process(child);
 115                ret = 0;
 116                break;
 117        }
 118
 119#ifdef PTRACE_GETREGS
 120        case PTRACE_GETREGS: { /* Get all gp regs from the child. */
 121                if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
 122                        ret = -EIO;
 123                        break;
 124                }
 125                for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
 126                        __put_user(getreg(child, i), p);
 127                        p++;
 128                }
 129                ret = 0;
 130                break;
 131        }
 132#endif
 133#ifdef PTRACE_SETREGS
 134        case PTRACE_SETREGS: { /* Set all gp regs in the child. */
 135                unsigned long tmp = 0;
 136                if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
 137                        ret = -EIO;
 138                        break;
 139                }
 140                for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
 141                        __get_user(tmp, p);
 142                        putreg(child, i, tmp);
 143                        p++;
 144                }
 145                ret = 0;
 146                break;
 147        }
 148#endif
 149#ifdef PTRACE_GETFPREGS
 150        case PTRACE_GETFPREGS: /* Get the child FPU state. */
 151                ret = get_fpregs((struct user_i387_struct __user *) data,
 152                                 child);
 153                break;
 154#endif
 155#ifdef PTRACE_SETFPREGS
 156        case PTRACE_SETFPREGS: /* Set the child FPU state. */
 157                ret = set_fpregs((struct user_i387_struct __user *) data,
 158                                 child);
 159                break;
 160#endif
 161        case PTRACE_GET_THREAD_AREA:
 162                ret = ptrace_get_thread_area(child, addr,
 163                                             (struct user_desc __user *) data);
 164                break;
 165
 166        case PTRACE_SET_THREAD_AREA:
 167                ret = ptrace_set_thread_area(child, addr,
 168                                             (struct user_desc __user *) data);
 169                break;
 170
 171        case PTRACE_FAULTINFO: {
 172                /*
 173                 * Take the info from thread->arch->faultinfo,
 174                 * but transfer max. sizeof(struct ptrace_faultinfo).
 175                 * On i386, ptrace_faultinfo is smaller!
 176                 */
 177                ret = copy_to_user(p, &child->thread.arch.faultinfo,
 178                                   sizeof(struct ptrace_faultinfo));
 179                break;
 180        }
 181
 182#ifdef PTRACE_LDT
 183        case PTRACE_LDT: {
 184                struct ptrace_ldt ldt;
 185
 186                if (copy_from_user(&ldt, p, sizeof(ldt))) {
 187                        ret = -EIO;
 188                        break;
 189                }
 190
 191                /*
 192                 * This one is confusing, so just punt and return -EIO for
 193                 * now
 194                 */
 195                ret = -EIO;
 196                break;
 197        }
 198#endif
 199#ifdef CONFIG_PROC_MM
 200        case PTRACE_SWITCH_MM: {
 201                struct mm_struct *old = child->mm;
 202                struct mm_struct *new = proc_mm_get_mm(data);
 203
 204                if (IS_ERR(new)) {
 205                        ret = PTR_ERR(new);
 206                        break;
 207                }
 208
 209                atomic_inc(&new->mm_users);
 210                child->mm = new;
 211                child->active_mm = new;
 212                mmput(old);
 213                ret = 0;
 214                break;
 215        }
 216#endif
 217#ifdef PTRACE_ARCH_PRCTL
 218        case PTRACE_ARCH_PRCTL:
 219                /* XXX Calls ptrace on the host - needs some SMP thinking */
 220                ret = arch_prctl(child, data, (void *) addr);
 221                break;
 222#endif
 223        default:
 224                ret = ptrace_request(child, request, addr, data);
 225                if (ret == -EIO)
 226                        ret = subarch_ptrace(child, request, addr, data);
 227                break;
 228        }
 229
 230        return ret;
 231}
 232
 233static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,
 234                  int error_code)
 235{
 236        struct siginfo info;
 237
 238        memset(&info, 0, sizeof(info));
 239        info.si_signo = SIGTRAP;
 240        info.si_code = TRAP_BRKPT;
 241
 242        /* User-mode eip? */
 243        info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
 244
 245        /* Send us the fake SIGTRAP */
 246        force_sig_info(SIGTRAP, &info, tsk);
 247}
 248
 249/*
 250 * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
 251 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
 252 */
 253void syscall_trace(struct uml_pt_regs *regs, int entryexit)
 254{
 255        int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
 256        int tracesysgood;
 257
 258        if (unlikely(current->audit_context)) {
 259                if (!entryexit)
 260                        audit_syscall_entry(HOST_AUDIT_ARCH,
 261                                            UPT_SYSCALL_NR(regs),
 262                                            UPT_SYSCALL_ARG1(regs),
 263                                            UPT_SYSCALL_ARG2(regs),
 264                                            UPT_SYSCALL_ARG3(regs),
 265                                            UPT_SYSCALL_ARG4(regs));
 266                else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
 267                                        UPT_SYSCALL_RET(regs));
 268        }
 269
 270        /* Fake a debug trap */
 271        if (is_singlestep)
 272                send_sigtrap(current, regs, 0);
 273
 274        if (!test_thread_flag(TIF_SYSCALL_TRACE))
 275                return;
 276
 277        if (!(current->ptrace & PT_PTRACED))
 278                return;
 279
 280        /*
 281         * the 0x80 provides a way for the tracing parent to distinguish
 282         * between a syscall stop and SIGTRAP delivery
 283         */
 284        tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
 285        ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
 286
 287        if (entryexit) /* force do_signal() --> is_syscall() */
 288                set_thread_flag(TIF_SIGPENDING);
 289
 290        /*
 291         * this isn't the same as continuing with a signal, but it will do
 292         * for normal use.  strace only continues with a signal if the
 293         * stopping signal is not SIGTRAP.  -brl
 294         */
 295        if (current->exit_code) {
 296                send_sig(current->exit_code, current, 1);
 297                current->exit_code = 0;
 298        }
 299}
 300