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