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 #include <linux/regset.h> 12 #define __FRAME_OFFSETS 13 #include <asm/ptrace.h> 14 #include <linux/uaccess.h> 15 #include <registers.h> 16 #include <asm/ptrace-abi.h> 17 18 /* 19 * determines which flags the user has access to. 20 * 1 = access 0 = no access 21 */ 22 #define FLAG_MASK 0x44dd5UL 23 24 static const int reg_offsets[] = 25 { 26 [R8 >> 3] = HOST_R8, 27 [R9 >> 3] = HOST_R9, 28 [R10 >> 3] = HOST_R10, 29 [R11 >> 3] = HOST_R11, 30 [R12 >> 3] = HOST_R12, 31 [R13 >> 3] = HOST_R13, 32 [R14 >> 3] = HOST_R14, 33 [R15 >> 3] = HOST_R15, 34 [RIP >> 3] = HOST_IP, 35 [RSP >> 3] = HOST_SP, 36 [RAX >> 3] = HOST_AX, 37 [RBX >> 3] = HOST_BX, 38 [RCX >> 3] = HOST_CX, 39 [RDX >> 3] = HOST_DX, 40 [RSI >> 3] = HOST_SI, 41 [RDI >> 3] = HOST_DI, 42 [RBP >> 3] = HOST_BP, 43 [CS >> 3] = HOST_CS, 44 [SS >> 3] = HOST_SS, 45 [FS_BASE >> 3] = HOST_FS_BASE, 46 [GS_BASE >> 3] = HOST_GS_BASE, 47 [DS >> 3] = HOST_DS, 48 [ES >> 3] = HOST_ES, 49 [FS >> 3] = HOST_FS, 50 [GS >> 3] = HOST_GS, 51 [EFLAGS >> 3] = HOST_EFLAGS, 52 [ORIG_RAX >> 3] = HOST_ORIG_AX, 53 }; 54 55 int putreg(struct task_struct *child, int regno, unsigned long value) 56 { 57 switch (regno) { 58 case R8: 59 case R9: 60 case R10: 61 case R11: 62 case R12: 63 case R13: 64 case R14: 65 case R15: 66 case RIP: 67 case RSP: 68 case RAX: 69 case RBX: 70 case RCX: 71 case RDX: 72 case RSI: 73 case RDI: 74 case RBP: 75 break; 76 77 case ORIG_RAX: 78 /* Update the syscall number. */ 79 UPT_SYSCALL_NR(&child->thread.regs.regs) = value; 80 break; 81 82 case FS: 83 case GS: 84 case DS: 85 case ES: 86 case SS: 87 case CS: 88 if (value && (value & 3) != 3) 89 return -EIO; 90 value &= 0xffff; 91 break; 92 93 case FS_BASE: 94 case GS_BASE: 95 if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) 96 return -EIO; 97 break; 98 99 case EFLAGS: 100 value &= FLAG_MASK; 101 child->thread.regs.regs.gp[HOST_EFLAGS] |= value; 102 return 0; 103 104 default: 105 panic("Bad register in putreg(): %d\n", regno); 106 } 107 108 child->thread.regs.regs.gp[reg_offsets[regno >> 3]] = value; 109 return 0; 110 } 111 112 int poke_user(struct task_struct *child, long addr, long data) 113 { 114 if ((addr & 3) || addr < 0) 115 return -EIO; 116 117 if (addr < MAX_REG_OFFSET) 118 return putreg(child, addr, data); 119 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 120 (addr <= offsetof(struct user, u_debugreg[7]))) { 121 addr -= offsetof(struct user, u_debugreg[0]); 122 addr = addr >> 3; 123 if ((addr == 4) || (addr == 5)) 124 return -EIO; 125 child->thread.arch.debugregs[addr] = data; 126 return 0; 127 } 128 return -EIO; 129 } 130 131 unsigned long getreg(struct task_struct *child, int regno) 132 { 133 unsigned long mask = ~0UL; 134 135 switch (regno) { 136 case R8: 137 case R9: 138 case R10: 139 case R11: 140 case R12: 141 case R13: 142 case R14: 143 case R15: 144 case RIP: 145 case RSP: 146 case RAX: 147 case RBX: 148 case RCX: 149 case RDX: 150 case RSI: 151 case RDI: 152 case RBP: 153 case ORIG_RAX: 154 case EFLAGS: 155 case FS_BASE: 156 case GS_BASE: 157 break; 158 case FS: 159 case GS: 160 case DS: 161 case ES: 162 case SS: 163 case CS: 164 mask = 0xffff; 165 break; 166 default: 167 panic("Bad register in getreg: %d\n", regno); 168 } 169 return mask & child->thread.regs.regs.gp[reg_offsets[regno >> 3]]; 170 } 171 172 int peek_user(struct task_struct *child, long addr, long data) 173 { 174 /* read the word at location addr in the USER area. */ 175 unsigned long tmp; 176 177 if ((addr & 3) || addr < 0) 178 return -EIO; 179 180 tmp = 0; /* Default return condition */ 181 if (addr < MAX_REG_OFFSET) 182 tmp = getreg(child, addr); 183 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 184 (addr <= offsetof(struct user, u_debugreg[7]))) { 185 addr -= offsetof(struct user, u_debugreg[0]); 186 addr = addr >> 2; 187 tmp = child->thread.arch.debugregs[addr]; 188 } 189 return put_user(tmp, (unsigned long *) data); 190 } 191 192 long subarch_ptrace(struct task_struct *child, long request, 193 unsigned long addr, unsigned long data) 194 { 195 int ret = -EIO; 196 void __user *datap = (void __user *) data; 197 198 switch (request) { 199 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 200 return copy_regset_to_user(child, task_user_regset_view(child), 201 REGSET_FP, 202 0, sizeof(struct user_i387_struct), 203 datap); 204 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 205 return copy_regset_from_user(child, task_user_regset_view(child), 206 REGSET_FP, 207 0, sizeof(struct user_i387_struct), 208 datap); 209 case PTRACE_ARCH_PRCTL: 210 /* XXX Calls ptrace on the host - needs some SMP thinking */ 211 ret = arch_prctl(child, data, (void __user *) addr); 212 break; 213 } 214 215 return ret; 216 } 217