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