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 23 static 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 54 int 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 111 int 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 130 unsigned 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 171 int 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 static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 192 { 193 int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 194 struct user_i387_struct fpregs; 195 196 err = save_i387_registers(userspace_pid[cpu], 197 (unsigned long *) &fpregs); 198 if (err) 199 return err; 200 201 n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 202 if (n > 0) 203 return -EFAULT; 204 205 return n; 206 } 207 208 static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 209 { 210 int n, cpu = ((struct thread_info *) child->stack)->cpu; 211 struct user_i387_struct fpregs; 212 213 n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 214 if (n > 0) 215 return -EFAULT; 216 217 return restore_i387_registers(userspace_pid[cpu], 218 (unsigned long *) &fpregs); 219 } 220 221 long subarch_ptrace(struct task_struct *child, long request, 222 unsigned long addr, unsigned long data) 223 { 224 int ret = -EIO; 225 void __user *datap = (void __user *) data; 226 227 switch (request) { 228 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 229 ret = get_fpregs(datap, child); 230 break; 231 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 232 ret = set_fpregs(datap, child); 233 break; 234 case PTRACE_ARCH_PRCTL: 235 /* XXX Calls ptrace on the host - needs some SMP thinking */ 236 ret = arch_prctl(child, data, (void __user *) addr); 237 break; 238 } 239 240 return ret; 241 } 242
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.