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 19int have_xstate_support; 20 21int 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 28int 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 44int 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 51int 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__ 67int have_fpx_regs = 1; 68int 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 75int 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 82int 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 90int 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 98void 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 115int get_fp_registers(int pid, unsigned long *regs) 116{ 117 return save_fp_registers(pid, regs); 118} 119 120int put_fp_registers(int pid, unsigned long *regs) 121{ 122 return restore_fp_registers(pid, regs); 123} 124 125void 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 145unsigned 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