162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2004 PathScale, Inc 362306a36Sopenharmony_ci * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 462306a36Sopenharmony_ci * Licensed under the GPL 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <errno.h> 862306a36Sopenharmony_ci#include <stdlib.h> 962306a36Sopenharmony_ci#include <sys/ptrace.h> 1062306a36Sopenharmony_ci#ifdef __i386__ 1162306a36Sopenharmony_ci#include <sys/user.h> 1262306a36Sopenharmony_ci#endif 1362306a36Sopenharmony_ci#include <longjmp.h> 1462306a36Sopenharmony_ci#include <sysdep/ptrace_user.h> 1562306a36Sopenharmony_ci#include <sys/uio.h> 1662306a36Sopenharmony_ci#include <asm/sigcontext.h> 1762306a36Sopenharmony_ci#include <linux/elf.h> 1862306a36Sopenharmony_ci#include <registers.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciint have_xstate_support; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciint save_i387_registers(int pid, unsigned long *fp_regs) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) 2562306a36Sopenharmony_ci return -errno; 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciint save_fp_registers(int pid, unsigned long *fp_regs) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci#ifdef PTRACE_GETREGSET 3262306a36Sopenharmony_ci struct iovec iov; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (have_xstate_support) { 3562306a36Sopenharmony_ci iov.iov_base = fp_regs; 3662306a36Sopenharmony_ci iov.iov_len = FP_SIZE * sizeof(unsigned long); 3762306a36Sopenharmony_ci if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 3862306a36Sopenharmony_ci return -errno; 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci } else 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci return save_i387_registers(pid, fp_regs); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciint restore_i387_registers(int pid, unsigned long *fp_regs) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) 4862306a36Sopenharmony_ci return -errno; 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciint restore_fp_registers(int pid, unsigned long *fp_regs) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci#ifdef PTRACE_SETREGSET 5562306a36Sopenharmony_ci struct iovec iov; 5662306a36Sopenharmony_ci if (have_xstate_support) { 5762306a36Sopenharmony_ci iov.iov_base = fp_regs; 5862306a36Sopenharmony_ci iov.iov_len = FP_SIZE * sizeof(unsigned long); 5962306a36Sopenharmony_ci if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 6062306a36Sopenharmony_ci return -errno; 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci } else 6362306a36Sopenharmony_ci#endif 6462306a36Sopenharmony_ci return restore_i387_registers(pid, fp_regs); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifdef __i386__ 6862306a36Sopenharmony_ciint have_fpx_regs = 1; 6962306a36Sopenharmony_ciint save_fpx_registers(int pid, unsigned long *fp_regs) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) 7262306a36Sopenharmony_ci return -errno; 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciint restore_fpx_registers(int pid, unsigned long *fp_regs) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) 7962306a36Sopenharmony_ci return -errno; 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciint get_fp_registers(int pid, unsigned long *regs) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci if (have_fpx_regs) 8662306a36Sopenharmony_ci return save_fpx_registers(pid, regs); 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci return save_fp_registers(pid, regs); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint put_fp_registers(int pid, unsigned long *regs) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci if (have_fpx_regs) 9462306a36Sopenharmony_ci return restore_fpx_registers(pid, regs); 9562306a36Sopenharmony_ci else 9662306a36Sopenharmony_ci return restore_fp_registers(pid, regs); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_civoid arch_init_registers(int pid) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct user_fpxregs_struct fpx_regs; 10262306a36Sopenharmony_ci int err; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); 10562306a36Sopenharmony_ci if (!err) 10662306a36Sopenharmony_ci return; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (errno != EIO) 10962306a36Sopenharmony_ci panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", 11062306a36Sopenharmony_ci errno); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci have_fpx_regs = 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci#else 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciint get_fp_registers(int pid, unsigned long *regs) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci return save_fp_registers(pid, regs); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciint put_fp_registers(int pid, unsigned long *regs) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci return restore_fp_registers(pid, regs); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_civoid arch_init_registers(int pid) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci#ifdef PTRACE_GETREGSET 12962306a36Sopenharmony_ci void * fp_regs; 13062306a36Sopenharmony_ci struct iovec iov; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci fp_regs = malloc(FP_SIZE * sizeof(unsigned long)); 13362306a36Sopenharmony_ci if(fp_regs == NULL) 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci iov.iov_base = fp_regs; 13762306a36Sopenharmony_ci iov.iov_len = FP_SIZE * sizeof(unsigned long); 13862306a36Sopenharmony_ci if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) 13962306a36Sopenharmony_ci have_xstate_support = 1; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci free(fp_regs); 14262306a36Sopenharmony_ci#endif 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci#endif 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciunsigned long get_thread_reg(int reg, jmp_buf *buf) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci switch (reg) { 14962306a36Sopenharmony_ci#ifdef __i386__ 15062306a36Sopenharmony_ci case HOST_IP: 15162306a36Sopenharmony_ci return buf[0]->__eip; 15262306a36Sopenharmony_ci case HOST_SP: 15362306a36Sopenharmony_ci return buf[0]->__esp; 15462306a36Sopenharmony_ci case HOST_BP: 15562306a36Sopenharmony_ci return buf[0]->__ebp; 15662306a36Sopenharmony_ci#else 15762306a36Sopenharmony_ci case HOST_IP: 15862306a36Sopenharmony_ci return buf[0]->__rip; 15962306a36Sopenharmony_ci case HOST_SP: 16062306a36Sopenharmony_ci return buf[0]->__rsp; 16162306a36Sopenharmony_ci case HOST_BP: 16262306a36Sopenharmony_ci return buf[0]->__rbp; 16362306a36Sopenharmony_ci#endif 16462306a36Sopenharmony_ci default: 16562306a36Sopenharmony_ci printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", 16662306a36Sopenharmony_ci reg); 16762306a36Sopenharmony_ci return 0; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci} 170