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