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