1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2004 PathScale, Inc
3*4882a593Smuzhiyun * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4*4882a593Smuzhiyun * Licensed under the GPL
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <errno.h>
8*4882a593Smuzhiyun #include <stdlib.h>
9*4882a593Smuzhiyun #include <sys/ptrace.h>
10*4882a593Smuzhiyun #ifdef __i386__
11*4882a593Smuzhiyun #include <sys/user.h>
12*4882a593Smuzhiyun #endif
13*4882a593Smuzhiyun #include <longjmp.h>
14*4882a593Smuzhiyun #include <sysdep/ptrace_user.h>
15*4882a593Smuzhiyun #include <sys/uio.h>
16*4882a593Smuzhiyun #include <asm/sigcontext.h>
17*4882a593Smuzhiyun #include <linux/elf.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun int have_xstate_support;
20*4882a593Smuzhiyun
save_i387_registers(int pid,unsigned long * fp_regs)21*4882a593Smuzhiyun int save_i387_registers(int pid, unsigned long *fp_regs)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
24*4882a593Smuzhiyun return -errno;
25*4882a593Smuzhiyun return 0;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
save_fp_registers(int pid,unsigned long * fp_regs)28*4882a593Smuzhiyun int save_fp_registers(int pid, unsigned long *fp_regs)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun #ifdef PTRACE_GETREGSET
31*4882a593Smuzhiyun struct iovec iov;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun if (have_xstate_support) {
34*4882a593Smuzhiyun iov.iov_base = fp_regs;
35*4882a593Smuzhiyun iov.iov_len = FP_SIZE * sizeof(unsigned long);
36*4882a593Smuzhiyun if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
37*4882a593Smuzhiyun return -errno;
38*4882a593Smuzhiyun return 0;
39*4882a593Smuzhiyun } else
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun return save_i387_registers(pid, fp_regs);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
restore_i387_registers(int pid,unsigned long * fp_regs)44*4882a593Smuzhiyun int restore_i387_registers(int pid, unsigned long *fp_regs)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
47*4882a593Smuzhiyun return -errno;
48*4882a593Smuzhiyun return 0;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
restore_fp_registers(int pid,unsigned long * fp_regs)51*4882a593Smuzhiyun int restore_fp_registers(int pid, unsigned long *fp_regs)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun #ifdef PTRACE_SETREGSET
54*4882a593Smuzhiyun struct iovec iov;
55*4882a593Smuzhiyun if (have_xstate_support) {
56*4882a593Smuzhiyun iov.iov_base = fp_regs;
57*4882a593Smuzhiyun iov.iov_len = FP_SIZE * sizeof(unsigned long);
58*4882a593Smuzhiyun if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
59*4882a593Smuzhiyun return -errno;
60*4882a593Smuzhiyun return 0;
61*4882a593Smuzhiyun } else
62*4882a593Smuzhiyun #endif
63*4882a593Smuzhiyun return restore_i387_registers(pid, fp_regs);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #ifdef __i386__
67*4882a593Smuzhiyun int have_fpx_regs = 1;
save_fpx_registers(int pid,unsigned long * fp_regs)68*4882a593Smuzhiyun int save_fpx_registers(int pid, unsigned long *fp_regs)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0)
71*4882a593Smuzhiyun return -errno;
72*4882a593Smuzhiyun return 0;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
restore_fpx_registers(int pid,unsigned long * fp_regs)75*4882a593Smuzhiyun int restore_fpx_registers(int pid, unsigned long *fp_regs)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0)
78*4882a593Smuzhiyun return -errno;
79*4882a593Smuzhiyun return 0;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
get_fp_registers(int pid,unsigned long * regs)82*4882a593Smuzhiyun int get_fp_registers(int pid, unsigned long *regs)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun if (have_fpx_regs)
85*4882a593Smuzhiyun return save_fpx_registers(pid, regs);
86*4882a593Smuzhiyun else
87*4882a593Smuzhiyun return save_fp_registers(pid, regs);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
put_fp_registers(int pid,unsigned long * regs)90*4882a593Smuzhiyun int put_fp_registers(int pid, unsigned long *regs)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun if (have_fpx_regs)
93*4882a593Smuzhiyun return restore_fpx_registers(pid, regs);
94*4882a593Smuzhiyun else
95*4882a593Smuzhiyun return restore_fp_registers(pid, regs);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
arch_init_registers(int pid)98*4882a593Smuzhiyun void arch_init_registers(int pid)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun struct user_fpxregs_struct fpx_regs;
101*4882a593Smuzhiyun int err;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs);
104*4882a593Smuzhiyun if (!err)
105*4882a593Smuzhiyun return;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (errno != EIO)
108*4882a593Smuzhiyun panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
109*4882a593Smuzhiyun errno);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun have_fpx_regs = 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun #else
114*4882a593Smuzhiyun
get_fp_registers(int pid,unsigned long * regs)115*4882a593Smuzhiyun int get_fp_registers(int pid, unsigned long *regs)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun return save_fp_registers(pid, regs);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
put_fp_registers(int pid,unsigned long * regs)120*4882a593Smuzhiyun int put_fp_registers(int pid, unsigned long *regs)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun return restore_fp_registers(pid, regs);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
arch_init_registers(int pid)125*4882a593Smuzhiyun void arch_init_registers(int pid)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun #ifdef PTRACE_GETREGSET
128*4882a593Smuzhiyun void * fp_regs;
129*4882a593Smuzhiyun struct iovec iov;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun fp_regs = malloc(FP_SIZE * sizeof(unsigned long));
132*4882a593Smuzhiyun if(fp_regs == NULL)
133*4882a593Smuzhiyun return;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun iov.iov_base = fp_regs;
136*4882a593Smuzhiyun iov.iov_len = FP_SIZE * sizeof(unsigned long);
137*4882a593Smuzhiyun if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
138*4882a593Smuzhiyun have_xstate_support = 1;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun free(fp_regs);
141*4882a593Smuzhiyun #endif
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun #endif
144*4882a593Smuzhiyun
get_thread_reg(int reg,jmp_buf * buf)145*4882a593Smuzhiyun unsigned long get_thread_reg(int reg, jmp_buf *buf)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun switch (reg) {
148*4882a593Smuzhiyun #ifdef __i386__
149*4882a593Smuzhiyun case HOST_IP:
150*4882a593Smuzhiyun return buf[0]->__eip;
151*4882a593Smuzhiyun case HOST_SP:
152*4882a593Smuzhiyun return buf[0]->__esp;
153*4882a593Smuzhiyun case HOST_BP:
154*4882a593Smuzhiyun return buf[0]->__ebp;
155*4882a593Smuzhiyun #else
156*4882a593Smuzhiyun case HOST_IP:
157*4882a593Smuzhiyun return buf[0]->__rip;
158*4882a593Smuzhiyun case HOST_SP:
159*4882a593Smuzhiyun return buf[0]->__rsp;
160*4882a593Smuzhiyun case HOST_BP:
161*4882a593Smuzhiyun return buf[0]->__rbp;
162*4882a593Smuzhiyun #endif
163*4882a593Smuzhiyun default:
164*4882a593Smuzhiyun printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n",
165*4882a593Smuzhiyun reg);
166*4882a593Smuzhiyun return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun }
169