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 <sys/ptrace.h> 9 #ifdef __i386__ 10 #include <sys/user.h> 11 #endif 12 #include <longjmp.h> 13 #include <sysdep/ptrace_user.h> 14 #include <sys/uio.h> 15 #include <asm/sigcontext.h> 16 #include <linux/elf.h> 17 18 int have_xstate_support; 19 20 int save_i387_registers(int pid, unsigned long *fp_regs) 21 { 22 if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) 23 return -errno; 24 return 0; 25 } 26 27 int save_fp_registers(int pid, unsigned long *fp_regs) 28 { 29 #ifdef PTRACE_GETREGSET 30 struct iovec iov; 31 32 if (have_xstate_support) { 33 iov.iov_base = fp_regs; 34 iov.iov_len = sizeof(struct _xstate); 35 if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 36 return -errno; 37 return 0; 38 } else 39 #endif 40 return save_i387_registers(pid, fp_regs); 41 } 42 43 int restore_i387_registers(int pid, unsigned long *fp_regs) 44 { 45 if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) 46 return -errno; 47 return 0; 48 } 49 50 int restore_fp_registers(int pid, unsigned long *fp_regs) 51 { 52 #ifdef PTRACE_SETREGSET 53 struct iovec iov; 54 55 if (have_xstate_support) { 56 iov.iov_base = fp_regs; 57 iov.iov_len = sizeof(struct _xstate); 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 struct _xstate fp_regs; 129 struct iovec iov; 130 131 iov.iov_base = &fp_regs; 132 iov.iov_len = sizeof(struct _xstate); 133 if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) 134 have_xstate_support = 1; 135 #endif 136 } 137 #endif 138 139 unsigned long get_thread_reg(int reg, jmp_buf *buf) 140 { 141 switch (reg) { 142 #ifdef __i386__ 143 case HOST_IP: 144 return buf[0]->__eip; 145 case HOST_SP: 146 return buf[0]->__esp; 147 case HOST_BP: 148 return buf[0]->__ebp; 149 #else 150 case HOST_IP: 151 return buf[0]->__rip; 152 case HOST_SP: 153 return buf[0]->__rsp; 154 case HOST_BP: 155 return buf[0]->__rbp; 156 #endif 157 default: 158 printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", 159 reg); 160 return 0; 161 } 162 } 163