1/* 2 * Copyright (C) 2004 PathScale, Inc 3 * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 * Licensed under the GPL 5 */ 6 7#include <errno.h> 8#include <stdlib.h> 9#include <sys/ptrace.h> 10#ifdef __i386__ 11#include <sys/user.h> 12#endif 13#include <longjmp.h> 14#include <sysdep/ptrace_user.h> 15#include <sys/uio.h> 16#include <asm/sigcontext.h> 17#include <linux/elf.h> 18#include <registers.h> 19 20int have_xstate_support; 21 22int save_i387_registers(int pid, unsigned long *fp_regs) 23{ 24 if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) 25 return -errno; 26 return 0; 27} 28 29int save_fp_registers(int pid, unsigned long *fp_regs) 30{ 31#ifdef PTRACE_GETREGSET 32 struct iovec iov; 33 34 if (have_xstate_support) { 35 iov.iov_base = fp_regs; 36 iov.iov_len = FP_SIZE * sizeof(unsigned long); 37 if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 38 return -errno; 39 return 0; 40 } else 41#endif 42 return save_i387_registers(pid, fp_regs); 43} 44 45int restore_i387_registers(int pid, unsigned long *fp_regs) 46{ 47 if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) 48 return -errno; 49 return 0; 50} 51 52int restore_fp_registers(int pid, unsigned long *fp_regs) 53{ 54#ifdef PTRACE_SETREGSET 55 struct iovec iov; 56 if (have_xstate_support) { 57 iov.iov_base = fp_regs; 58 iov.iov_len = FP_SIZE * sizeof(unsigned long); 59 if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 60 return -errno; 61 return 0; 62 } else 63#endif 64 return restore_i387_registers(pid, fp_regs); 65} 66 67#ifdef __i386__ 68int have_fpx_regs = 1; 69int save_fpx_registers(int pid, unsigned long *fp_regs) 70{ 71 if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) 72 return -errno; 73 return 0; 74} 75 76int restore_fpx_registers(int pid, unsigned long *fp_regs) 77{ 78 if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) 79 return -errno; 80 return 0; 81} 82 83int get_fp_registers(int pid, unsigned long *regs) 84{ 85 if (have_fpx_regs) 86 return save_fpx_registers(pid, regs); 87 else 88 return save_fp_registers(pid, regs); 89} 90 91int put_fp_registers(int pid, unsigned long *regs) 92{ 93 if (have_fpx_regs) 94 return restore_fpx_registers(pid, regs); 95 else 96 return restore_fp_registers(pid, regs); 97} 98 99void arch_init_registers(int pid) 100{ 101 struct user_fpxregs_struct fpx_regs; 102 int err; 103 104 err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); 105 if (!err) 106 return; 107 108 if (errno != EIO) 109 panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", 110 errno); 111 112 have_fpx_regs = 0; 113} 114#else 115 116int get_fp_registers(int pid, unsigned long *regs) 117{ 118 return save_fp_registers(pid, regs); 119} 120 121int put_fp_registers(int pid, unsigned long *regs) 122{ 123 return restore_fp_registers(pid, regs); 124} 125 126void arch_init_registers(int pid) 127{ 128#ifdef PTRACE_GETREGSET 129 void * fp_regs; 130 struct iovec iov; 131 132 fp_regs = malloc(FP_SIZE * sizeof(unsigned long)); 133 if(fp_regs == NULL) 134 return; 135 136 iov.iov_base = fp_regs; 137 iov.iov_len = FP_SIZE * sizeof(unsigned long); 138 if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) 139 have_xstate_support = 1; 140 141 free(fp_regs); 142#endif 143} 144#endif 145 146unsigned long get_thread_reg(int reg, jmp_buf *buf) 147{ 148 switch (reg) { 149#ifdef __i386__ 150 case HOST_IP: 151 return buf[0]->__eip; 152 case HOST_SP: 153 return buf[0]->__esp; 154 case HOST_BP: 155 return buf[0]->__ebp; 156#else 157 case HOST_IP: 158 return buf[0]->__rip; 159 case HOST_SP: 160 return buf[0]->__rsp; 161 case HOST_BP: 162 return buf[0]->__rbp; 163#endif 164 default: 165 printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", 166 reg); 167 return 0; 168 } 169} 170