| /* |
| * Copyright (C) 2004 PathScale, Inc |
| * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
| * Licensed under the GPL |
| */ |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <sys/ptrace.h> |
| #ifdef __i386__ |
| #include <sys/user.h> |
| #endif |
| #include <longjmp.h> |
| #include <sysdep/ptrace_user.h> |
| #include <sys/uio.h> |
| #include <asm/sigcontext.h> |
| #include <linux/elf.h> |
| |
| int have_xstate_support; |
| |
| int save_i387_registers(int pid, unsigned long *fp_regs) |
| { |
| if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) |
| return -errno; |
| return 0; |
| } |
| |
| int save_fp_registers(int pid, unsigned long *fp_regs) |
| { |
| #ifdef PTRACE_GETREGSET |
| struct iovec iov; |
| |
| if (have_xstate_support) { |
| iov.iov_base = fp_regs; |
| iov.iov_len = FP_SIZE * sizeof(unsigned long); |
| if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) |
| return -errno; |
| return 0; |
| } else |
| #endif |
| return save_i387_registers(pid, fp_regs); |
| } |
| |
| int restore_i387_registers(int pid, unsigned long *fp_regs) |
| { |
| if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) |
| return -errno; |
| return 0; |
| } |
| |
| int restore_fp_registers(int pid, unsigned long *fp_regs) |
| { |
| #ifdef PTRACE_SETREGSET |
| struct iovec iov; |
| if (have_xstate_support) { |
| iov.iov_base = fp_regs; |
| iov.iov_len = FP_SIZE * sizeof(unsigned long); |
| if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) |
| return -errno; |
| return 0; |
| } else |
| #endif |
| return restore_i387_registers(pid, fp_regs); |
| } |
| |
| #ifdef __i386__ |
| int have_fpx_regs = 1; |
| int save_fpx_registers(int pid, unsigned long *fp_regs) |
| { |
| if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) |
| return -errno; |
| return 0; |
| } |
| |
| int restore_fpx_registers(int pid, unsigned long *fp_regs) |
| { |
| if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) |
| return -errno; |
| return 0; |
| } |
| |
| int get_fp_registers(int pid, unsigned long *regs) |
| { |
| if (have_fpx_regs) |
| return save_fpx_registers(pid, regs); |
| else |
| return save_fp_registers(pid, regs); |
| } |
| |
| int put_fp_registers(int pid, unsigned long *regs) |
| { |
| if (have_fpx_regs) |
| return restore_fpx_registers(pid, regs); |
| else |
| return restore_fp_registers(pid, regs); |
| } |
| |
| void arch_init_registers(int pid) |
| { |
| struct user_fpxregs_struct fpx_regs; |
| int err; |
| |
| err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); |
| if (!err) |
| return; |
| |
| if (errno != EIO) |
| panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", |
| errno); |
| |
| have_fpx_regs = 0; |
| } |
| #else |
| |
| int get_fp_registers(int pid, unsigned long *regs) |
| { |
| return save_fp_registers(pid, regs); |
| } |
| |
| int put_fp_registers(int pid, unsigned long *regs) |
| { |
| return restore_fp_registers(pid, regs); |
| } |
| |
| void arch_init_registers(int pid) |
| { |
| #ifdef PTRACE_GETREGSET |
| void * fp_regs; |
| struct iovec iov; |
| |
| fp_regs = malloc(FP_SIZE * sizeof(unsigned long)); |
| if(fp_regs == NULL) |
| return; |
| |
| iov.iov_base = fp_regs; |
| iov.iov_len = FP_SIZE * sizeof(unsigned long); |
| if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) |
| have_xstate_support = 1; |
| |
| free(fp_regs); |
| #endif |
| } |
| #endif |
| |
| unsigned long get_thread_reg(int reg, jmp_buf *buf) |
| { |
| switch (reg) { |
| #ifdef __i386__ |
| case HOST_IP: |
| return buf[0]->__eip; |
| case HOST_SP: |
| return buf[0]->__esp; |
| case HOST_BP: |
| return buf[0]->__ebp; |
| #else |
| case HOST_IP: |
| return buf[0]->__rip; |
| case HOST_SP: |
| return buf[0]->__rsp; |
| case HOST_BP: |
| return buf[0]->__rbp; |
| #endif |
| default: |
| printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", |
| reg); |
| return 0; |
| } |
| } |