]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (C) 2004 PathScale, Inc | |
f0c4cad9 | 3 | * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
1da177e4 LT |
4 | * Licensed under the GPL |
5 | */ | |
6 | ||
7 | #include <errno.h> | |
3787fa6d | 8 | #include <sys/ptrace.h> |
38b64aed | 9 | #ifdef __i386__ |
14c8a77e | 10 | #include <sys/user.h> |
38b64aed | 11 | #endif |
37185b33 AV |
12 | #include <longjmp.h> |
13 | #include <sysdep/ptrace_user.h> | |
a78ff111 EC |
14 | #include <sys/uio.h> |
15 | #include <asm/sigcontext.h> | |
16 | #include <linux/elf.h> | |
1da177e4 | 17 | |
a78ff111 EC |
18 | int have_xstate_support; |
19 | ||
20 | int save_i387_registers(int pid, unsigned long *fp_regs) | |
1da177e4 | 21 | { |
f0c4cad9 | 22 | if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) |
6c59e2f5 JD |
23 | return -errno; |
24 | return 0; | |
1da177e4 LT |
25 | } |
26 | ||
a78ff111 EC |
27 | int save_fp_registers(int pid, unsigned long *fp_regs) |
28 | { | |
0a987645 | 29 | #ifdef PTRACE_GETREGSET |
a78ff111 EC |
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; | |
0a987645 FF |
38 | } else |
39 | #endif | |
a78ff111 | 40 | return save_i387_registers(pid, fp_regs); |
a78ff111 EC |
41 | } |
42 | ||
43 | int restore_i387_registers(int pid, unsigned long *fp_regs) | |
1da177e4 | 44 | { |
f0c4cad9 | 45 | if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) |
6c59e2f5 JD |
46 | return -errno; |
47 | return 0; | |
1da177e4 LT |
48 | } |
49 | ||
a78ff111 EC |
50 | int restore_fp_registers(int pid, unsigned long *fp_regs) |
51 | { | |
0a987645 | 52 | #ifdef PTRACE_SETREGSET |
a78ff111 EC |
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; | |
0a987645 FF |
61 | } else |
62 | #endif | |
a78ff111 | 63 | return restore_i387_registers(pid, fp_regs); |
a78ff111 EC |
64 | } |
65 | ||
51d34749 AV |
66 | #ifdef __i386__ |
67 | int have_fpx_regs = 1; | |
a5f6096c JD |
68 | int save_fpx_registers(int pid, unsigned long *fp_regs) |
69 | { | |
f0c4cad9 | 70 | if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) |
a5f6096c JD |
71 | return -errno; |
72 | return 0; | |
73 | } | |
74 | ||
75 | int restore_fpx_registers(int pid, unsigned long *fp_regs) | |
76 | { | |
f0c4cad9 | 77 | if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) |
a5f6096c JD |
78 | return -errno; |
79 | return 0; | |
80 | } | |
81 | ||
2f56debd JD |
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 | ||
a5f6096c JD |
98 | void arch_init_registers(int pid) |
99 | { | |
14c8a77e | 100 | struct user_fpxregs_struct fpx_regs; |
a5f6096c JD |
101 | int err; |
102 | ||
47906dd9 | 103 | err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); |
5134d8fe | 104 | if (!err) |
a5f6096c JD |
105 | return; |
106 | ||
5134d8fe | 107 | if (errno != EIO) |
a5f6096c JD |
108 | panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", |
109 | errno); | |
110 | ||
111 | have_fpx_regs = 0; | |
112 | } | |
51d34749 AV |
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 | ||
a78ff111 EC |
125 | void arch_init_registers(int pid) |
126 | { | |
0a987645 | 127 | #ifdef PTRACE_GETREGSET |
a78ff111 EC |
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; | |
0a987645 | 135 | #endif |
a78ff111 | 136 | } |
51d34749 AV |
137 | #endif |
138 | ||
139 | unsigned long get_thread_reg(int reg, jmp_buf *buf) | |
140 | { | |
141 | switch (reg) { | |
142 | #ifdef __i386__ | |
a10c95d8 | 143 | case HOST_IP: |
51d34749 | 144 | return buf[0]->__eip; |
a10c95d8 | 145 | case HOST_SP: |
51d34749 | 146 | return buf[0]->__esp; |
a10c95d8 | 147 | case HOST_BP: |
51d34749 AV |
148 | return buf[0]->__ebp; |
149 | #else | |
a10c95d8 | 150 | case HOST_IP: |
51d34749 | 151 | return buf[0]->__rip; |
a10c95d8 | 152 | case HOST_SP: |
51d34749 | 153 | return buf[0]->__rsp; |
a10c95d8 | 154 | case HOST_BP: |
51d34749 AV |
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 | } |