1/* 2 * Copyright 2003 PathScale, Inc. 3 * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 * 5 * Licensed under the GPL 6 */ 7 8#include <linux/mm.h> 9#include <linux/sched.h> 10#include <linux/errno.h> 11#define __FRAME_OFFSETS 12#include <asm/ptrace.h> 13#include <asm/uaccess.h> 14 15/* 16 * determines which flags the user has access to. 17 * 1 = access 0 = no access 18 */ 19#define FLAG_MASK 0x44dd5UL 20 21int putreg(struct task_struct *child, int regno, unsigned long value) 22{ 23 unsigned long tmp; 24 25#ifdef TIF_IA32 26 /* 27 * Some code in the 64bit emulation may not be 64bit clean. 28 * Don't take any chances. 29 */ 30 if (test_tsk_thread_flag(child, TIF_IA32)) 31 value &= 0xffffffff; 32#endif 33 switch (regno) { 34 case FS: 35 case GS: 36 case DS: 37 case ES: 38 case SS: 39 case CS: 40 if (value && (value & 3) != 3) 41 return -EIO; 42 value &= 0xffff; 43 break; 44 45 case FS_BASE: 46 case GS_BASE: 47 if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) 48 return -EIO; 49 break; 50 51 case EFLAGS: 52 value &= FLAG_MASK; 53 tmp = PT_REGS_EFLAGS(&child->thread.regs) & ~FLAG_MASK; 54 value |= tmp; 55 break; 56 } 57 58 PT_REGS_SET(&child->thread.regs, regno, value); 59 return 0; 60} 61 62int poke_user(struct task_struct *child, long addr, long data) 63{ 64 if ((addr & 3) || addr < 0) 65 return -EIO; 66 67 if (addr < MAX_REG_OFFSET) 68 return putreg(child, addr, data); 69 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 70 (addr <= offsetof(struct user, u_debugreg[7]))) { 71 addr -= offsetof(struct user, u_debugreg[0]); 72 addr = addr >> 2; 73 if ((addr == 4) || (addr == 5)) 74 return -EIO; 75 child->thread.arch.debugregs[addr] = data; 76 return 0; 77 } 78 return -EIO; 79} 80 81unsigned long getreg(struct task_struct *child, int regno) 82{ 83 unsigned long retval = ~0UL; 84 switch (regno) { 85 case FS: 86 case GS: 87 case DS: 88 case ES: 89 case SS: 90 case CS: 91 retval = 0xffff; 92 /* fall through */ 93 default: 94 retval &= PT_REG(&child->thread.regs, regno); 95#ifdef TIF_IA32 96 if (test_tsk_thread_flag(child, TIF_IA32)) 97 retval &= 0xffffffff; 98#endif 99 } 100 return retval; 101} 102 103int peek_user(struct task_struct *child, long addr, long data) 104{ 105 /* read the word at location addr in the USER area. */ 106 unsigned long tmp; 107 108 if ((addr & 3) || addr < 0) 109 return -EIO; 110 111 tmp = 0; /* Default return condition */ 112 if (addr < MAX_REG_OFFSET) 113 tmp = getreg(child, addr); 114 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 115 (addr <= offsetof(struct user, u_debugreg[7]))) { 116 addr -= offsetof(struct user, u_debugreg[0]); 117 addr = addr >> 2; 118 tmp = child->thread.arch.debugregs[addr]; 119 } 120 return put_user(tmp, (unsigned long *) data); 121} 122 123int is_syscall(unsigned long addr) 124{ 125 unsigned short instr; 126 int n; 127 128 n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); 129 if (n) { 130 /* 131 * access_process_vm() grants access to vsyscall and stub, 132 * while copy_from_user doesn't. Maybe access_process_vm is 133 * slow, but that doesn't matter, since it will be called only 134 * in case of singlestepping, if copy_from_user failed. 135 */ 136 n = access_process_vm(current, addr, &instr, sizeof(instr), 0); 137 if (n != sizeof(instr)) { 138 printk("is_syscall : failed to read instruction from " 139 "0x%lx\n", addr); 140 return 1; 141 } 142 } 143 /* sysenter */ 144 return instr == 0x050f; 145} 146 147int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 148{ 149 int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 150 long fpregs[HOST_FP_SIZE]; 151 152 BUG_ON(sizeof(*buf) != sizeof(fpregs)); 153 err = save_fp_registers(userspace_pid[cpu], fpregs); 154 if (err) 155 return err; 156 157 n = copy_to_user(buf, fpregs, sizeof(fpregs)); 158 if (n > 0) 159 return -EFAULT; 160 161 return n; 162} 163 164int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 165{ 166 int n, cpu = ((struct thread_info *) child->stack)->cpu; 167 long fpregs[HOST_FP_SIZE]; 168 169 BUG_ON(sizeof(*buf) != sizeof(fpregs)); 170 n = copy_from_user(fpregs, buf, sizeof(fpregs)); 171 if (n > 0) 172 return -EFAULT; 173 174 return restore_fp_registers(userspace_pid[cpu], fpregs); 175} 176 177long subarch_ptrace(struct task_struct *child, long request, long addr, 178 long data) 179{ 180 int ret = -EIO; 181 182 switch (request) { 183 case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 184 ret = get_fpregs((struct user_i387_struct __user *) data, 185 child); 186 break; 187 case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 188 ret = set_fpregs((struct user_i387_struct __user *) data, 189 child); 190 break; 191 } 192 193 return ret; 194} 195