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 20 int have_xstate_support; 21 22 int 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 29 int 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 45 int 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 52 int 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__ 68 int have_fpx_regs = 1; 69 int 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 76 int 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 83 int 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 91 int 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 99 void 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 116 int get_fp_registers(int pid, unsigned long *regs) 117 { 118 return save_fp_registers(pid, regs); 119 } 120 121 int put_fp_registers(int pid, unsigned long *regs) 122 { 123 return restore_fp_registers(pid, regs); 124 } 125 126 void 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 146 unsigned 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