linux/arch/x86/um/ptrace_32.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/mm.h>
   7#include <linux/sched.h>
   8#include <linux/uaccess.h>
   9#include <asm/ptrace-abi.h>
  10#include <skas.h>
  11
  12extern int arch_switch_tls(struct task_struct *to);
  13
  14void arch_switch_to(struct task_struct *to)
  15{
  16        int err = arch_switch_tls(to);
  17        if (!err)
  18                return;
  19
  20        if (err != -EINVAL)
  21                printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
  22                       "not EINVAL\n", -err);
  23        else
  24                printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
  25}
  26
  27int is_syscall(unsigned long addr)
  28{
  29        unsigned short instr;
  30        int n;
  31
  32        n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
  33        if (n) {
  34                /* access_process_vm() grants access to vsyscall and stub,
  35                 * while copy_from_user doesn't. Maybe access_process_vm is
  36                 * slow, but that doesn't matter, since it will be called only
  37                 * in case of singlestepping, if copy_from_user failed.
  38                 */
  39                n = access_process_vm(current, addr, &instr, sizeof(instr),
  40                                FOLL_FORCE);
  41                if (n != sizeof(instr)) {
  42                        printk(KERN_ERR "is_syscall : failed to read "
  43                               "instruction from 0x%lx\n", addr);
  44                        return 1;
  45                }
  46        }
  47        /* int 0x80 or sysenter */
  48        return (instr == 0x80cd) || (instr == 0x340f);
  49}
  50
  51/* determines which flags the user has access to. */
  52/* 1 = access 0 = no access */
  53#define FLAG_MASK 0x00044dd5
  54
  55static const int reg_offsets[] = {
  56        [EBX] = HOST_BX,
  57        [ECX] = HOST_CX,
  58        [EDX] = HOST_DX,
  59        [ESI] = HOST_SI,
  60        [EDI] = HOST_DI,
  61        [EBP] = HOST_BP,
  62        [EAX] = HOST_AX,
  63        [DS] = HOST_DS,
  64        [ES] = HOST_ES,
  65        [FS] = HOST_FS,
  66        [GS] = HOST_GS,
  67        [EIP] = HOST_IP,
  68        [CS] = HOST_CS,
  69        [EFL] = HOST_EFLAGS,
  70        [UESP] = HOST_SP,
  71        [SS] = HOST_SS,
  72        [ORIG_EAX] = HOST_ORIG_AX,
  73};
  74
  75int putreg(struct task_struct *child, int regno, unsigned long value)
  76{
  77        regno >>= 2;
  78        switch (regno) {
  79        case EBX:
  80        case ECX:
  81        case EDX:
  82        case ESI:
  83        case EDI:
  84        case EBP:
  85        case EAX:
  86        case EIP:
  87        case UESP:
  88                break;
  89        case ORIG_EAX:
  90                /* Update the syscall number. */
  91                UPT_SYSCALL_NR(&child->thread.regs.regs) = value;
  92                break;
  93        case FS:
  94                if (value && (value & 3) != 3)
  95                        return -EIO;
  96                break;
  97        case GS:
  98                if (value && (value & 3) != 3)
  99                        return -EIO;
 100                break;
 101        case DS:
 102        case ES:
 103                if (value && (value & 3) != 3)
 104                        return -EIO;
 105                value &= 0xffff;
 106                break;
 107        case SS:
 108        case CS:
 109                if ((value & 3) != 3)
 110                        return -EIO;
 111                value &= 0xffff;
 112                break;
 113        case EFL:
 114                value &= FLAG_MASK;
 115                child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
 116                return 0;
 117        default :
 118                panic("Bad register in putreg() : %d\n", regno);
 119        }
 120        child->thread.regs.regs.gp[reg_offsets[regno]] = value;
 121        return 0;
 122}
 123
 124int poke_user(struct task_struct *child, long addr, long data)
 125{
 126        if ((addr & 3) || addr < 0)
 127                return -EIO;
 128
 129        if (addr < MAX_REG_OFFSET)
 130                return putreg(child, addr, data);
 131        else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
 132                 (addr <= offsetof(struct user, u_debugreg[7]))) {
 133                addr -= offsetof(struct user, u_debugreg[0]);
 134                addr = addr >> 2;
 135                if ((addr == 4) || (addr == 5))
 136                        return -EIO;
 137                child->thread.arch.debugregs[addr] = data;
 138                return 0;
 139        }
 140        return -EIO;
 141}
 142
 143unsigned long getreg(struct task_struct *child, int regno)
 144{
 145        unsigned long mask = ~0UL;
 146
 147        regno >>= 2;
 148        switch (regno) {
 149        case FS:
 150        case GS:
 151        case DS:
 152        case ES:
 153        case SS:
 154        case CS:
 155                mask = 0xffff;
 156                break;
 157        case EIP:
 158        case UESP:
 159        case EAX:
 160        case EBX:
 161        case ECX:
 162        case EDX:
 163        case ESI:
 164        case EDI:
 165        case EBP:
 166        case EFL:
 167        case ORIG_EAX:
 168                break;
 169        default:
 170                panic("Bad register in getreg() : %d\n", regno);
 171        }
 172        return mask & child->thread.regs.regs.gp[reg_offsets[regno]];
 173}
 174
 175/* read the word at location addr in the USER area. */
 176int peek_user(struct task_struct *child, long addr, long data)
 177{
 178        unsigned long tmp;
 179
 180        if ((addr & 3) || addr < 0)
 181                return -EIO;
 182
 183        tmp = 0;  /* Default return condition */
 184        if (addr < MAX_REG_OFFSET) {
 185                tmp = getreg(child, addr);
 186        }
 187        else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
 188                 (addr <= offsetof(struct user, u_debugreg[7]))) {
 189                addr -= offsetof(struct user, u_debugreg[0]);
 190                addr = addr >> 2;
 191                tmp = child->thread.arch.debugregs[addr];
 192        }
 193        return put_user(tmp, (unsigned long __user *) data);
 194}
 195
 196static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
 197{
 198        int err, n, cpu = task_cpu(child);
 199        struct user_i387_struct fpregs;
 200
 201        err = save_i387_registers(userspace_pid[cpu],
 202                                  (unsigned long *) &fpregs);
 203        if (err)
 204                return err;
 205
 206        n = copy_to_user(buf, &fpregs, sizeof(fpregs));
 207        if(n > 0)
 208                return -EFAULT;
 209
 210        return n;
 211}
 212
 213static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
 214{
 215        int n, cpu = task_cpu(child);
 216        struct user_i387_struct fpregs;
 217
 218        n = copy_from_user(&fpregs, buf, sizeof(fpregs));
 219        if (n > 0)
 220                return -EFAULT;
 221
 222        return restore_i387_registers(userspace_pid[cpu],
 223                                    (unsigned long *) &fpregs);
 224}
 225
 226static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
 227{
 228        int err, n, cpu = task_cpu(child);
 229        struct user_fxsr_struct fpregs;
 230
 231        err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
 232        if (err)
 233                return err;
 234
 235        n = copy_to_user(buf, &fpregs, sizeof(fpregs));
 236        if(n > 0)
 237                return -EFAULT;
 238
 239        return n;
 240}
 241
 242static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
 243{
 244        int n, cpu = task_cpu(child);
 245        struct user_fxsr_struct fpregs;
 246
 247        n = copy_from_user(&fpregs, buf, sizeof(fpregs));
 248        if (n > 0)
 249                return -EFAULT;
 250
 251        return restore_fpx_registers(userspace_pid[cpu],
 252                                     (unsigned long *) &fpregs);
 253}
 254
 255long subarch_ptrace(struct task_struct *child, long request,
 256                    unsigned long addr, unsigned long data)
 257{
 258        int ret = -EIO;
 259        void __user *datap = (void __user *) data;
 260        switch (request) {
 261        case PTRACE_GETFPREGS: /* Get the child FPU state. */
 262                ret = get_fpregs(datap, child);
 263                break;
 264        case PTRACE_SETFPREGS: /* Set the child FPU state. */
 265                ret = set_fpregs(datap, child);
 266                break;
 267        case PTRACE_GETFPXREGS: /* Get the child FPU state. */
 268                ret = get_fpxregs(datap, child);
 269                break;
 270        case PTRACE_SETFPXREGS: /* Set the child FPU state. */
 271                ret = set_fpxregs(datap, child);
 272                break;
 273        default:
 274                ret = -EIO;
 275        }
 276        return ret;
 277}
 278