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