Commit | Line | Data |
---|---|---|
68cc0bfb | 1 | /* Native-dependent code for FreeBSD/amd64. |
2a6d284d | 2 | |
68cc0bfb MK |
3 | Copyright 2003 Free Software Foundation, Inc. |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, USA. */ | |
21 | ||
22 | #include "defs.h" | |
23 | #include "inferior.h" | |
24 | #include "regcache.h" | |
25 | ||
26 | #include "gdb_assert.h" | |
27 | #include <signal.h> | |
28 | #include <stddef.h> | |
29 | #include <sys/types.h> | |
30 | #include <sys/ptrace.h> | |
31 | #include <sys/sysctl.h> | |
32 | #include <machine/reg.h> | |
33 | ||
34 | #ifdef HAVE_SYS_PROCFS_H | |
35 | #include <sys/procfs.h> | |
36 | #endif | |
37 | ||
38 | #ifndef HAVE_GREGSET_T | |
39 | typedef struct reg gregset_t; | |
40 | #endif | |
41 | ||
42 | #ifndef HAVE_FPREGSET_T | |
43 | typedef struct fpreg fpregset_t; | |
44 | #endif | |
45 | ||
46 | #include "gregset.h" | |
47 | #include "x86-64-tdep.h" | |
2a6d284d | 48 | #include "amd64-nat.h" |
68cc0bfb MK |
49 | \f |
50 | ||
51 | /* Offset to the gregset_t location where REG is stored. */ | |
52 | #define REG_OFFSET(reg) offsetof (gregset_t, reg) | |
53 | ||
2a6d284d MK |
54 | /* At reg_offset[REGNUM] you'll find the offset to the gregset_t |
55 | location where the GDB register REGNUM is stored. Unsupported | |
68cc0bfb MK |
56 | registers are marked with `-1'. */ |
57 | static int reg_offset[] = | |
58 | { | |
59 | REG_OFFSET (r_rax), | |
60 | REG_OFFSET (r_rbx), | |
61 | REG_OFFSET (r_rcx), | |
62 | REG_OFFSET (r_rdx), | |
63 | REG_OFFSET (r_rsi), | |
64 | REG_OFFSET (r_rdi), | |
65 | REG_OFFSET (r_rbp), | |
66 | REG_OFFSET (r_rsp), | |
67 | REG_OFFSET (r_r8), | |
68 | REG_OFFSET (r_r9), | |
69 | REG_OFFSET (r_r10), | |
70 | REG_OFFSET (r_r11), | |
71 | REG_OFFSET (r_r12), | |
72 | REG_OFFSET (r_r13), | |
73 | REG_OFFSET (r_r14), | |
74 | REG_OFFSET (r_r15), | |
75 | REG_OFFSET (r_rip), | |
76 | REG_OFFSET (r_rflags), | |
77 | -1, | |
78 | -1, | |
79 | -1, | |
80 | -1 | |
81 | }; | |
2a6d284d MK |
82 | \f |
83 | ||
84 | /* Mapping between the general-purpose registers in FreeBSD/amd64 | |
85 | `struct reg' format and GDB's register cache layout for | |
86 | FreeBSD/i386. | |
68cc0bfb | 87 | |
2a6d284d MK |
88 | Note that most FreeBSD/amd64 registers are 64-bit, while the |
89 | FreeBSD/i386 registers are all 32-bit, but since we're | |
90 | little-endian we get away with that. */ | |
68cc0bfb | 91 | |
2a6d284d MK |
92 | /* From <machine/reg.h>. */ |
93 | static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] = | |
94 | { | |
95 | 14 * 8, 13 * 8, /* %eax, %ecx */ | |
96 | 12 * 8, 11 * 8, /* %edx, %ebx */ | |
97 | 20 * 8, 10 * 8, /* %esp, %ebp */ | |
98 | 9 * 8, 8 * 8, /* %esi, %edi */ | |
99 | 17 * 8, 19 * 8, /* %eip, %eflags */ | |
100 | 18 * 8, 21 * 8, /* %cs, %ss */ | |
101 | -1, -1, -1, -1 /* %ds, %es, %fs, %gs */ | |
102 | }; | |
68cc0bfb MK |
103 | \f |
104 | ||
105 | /* Transfering the registers between GDB, inferiors and core files. */ | |
106 | ||
107 | /* Fill GDB's register array with the general-purpose register values | |
108 | in *GREGSETP. */ | |
109 | ||
110 | void | |
111 | supply_gregset (gregset_t *gregsetp) | |
112 | { | |
2a6d284d | 113 | amd64_supply_native_gregset (current_regcache, gregsetp, -1); |
68cc0bfb MK |
114 | } |
115 | ||
2a6d284d MK |
116 | /* Fill register REGNUM (if it is a general-purpose register) in |
117 | *GREGSETPS with the value in GDB's register array. If REGNUM is -1, | |
68cc0bfb MK |
118 | do this for all registers. */ |
119 | ||
120 | void | |
2a6d284d | 121 | fill_gregset (gregset_t *gregsetp, int regnum) |
68cc0bfb | 122 | { |
2a6d284d | 123 | amd64_collect_native_gregset (current_regcache, gregsetp, regnum); |
68cc0bfb MK |
124 | } |
125 | ||
126 | /* Fill GDB's register array with the floating-point register values | |
127 | in *FPREGSETP. */ | |
128 | ||
129 | void | |
130 | supply_fpregset (fpregset_t *fpregsetp) | |
131 | { | |
0485f6ad | 132 | x86_64_supply_fxsave ((const char *) fpregsetp, -1); |
68cc0bfb MK |
133 | } |
134 | ||
2a6d284d MK |
135 | /* Fill register REGNUM (if it is a floating-point register) in |
136 | *FPREGSETP with the value in GDB's register array. If REGNUM is -1, | |
68cc0bfb MK |
137 | do this for all registers. */ |
138 | ||
139 | void | |
2a6d284d | 140 | fill_fpregset (fpregset_t *fpregsetp, int regnum) |
68cc0bfb | 141 | { |
2a6d284d | 142 | x86_64_fill_fxsave ((char *) fpregsetp, regnum); |
68cc0bfb MK |
143 | } |
144 | ||
2a6d284d | 145 | /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this |
68cc0bfb MK |
146 | for all registers (including the floating point registers). */ |
147 | ||
148 | void | |
2a6d284d | 149 | fetch_inferior_registers (int regnum) |
68cc0bfb | 150 | { |
2a6d284d | 151 | if (regnum == -1 || amd64_native_gregset_supplies_p (regnum)) |
68cc0bfb | 152 | { |
2a6d284d | 153 | struct reg regs; |
68cc0bfb MK |
154 | |
155 | if (ptrace (PT_GETREGS, PIDGET (inferior_ptid), | |
2a6d284d | 156 | (PTRACE_ARG3_TYPE) ®s, 0) == -1) |
68cc0bfb MK |
157 | perror_with_name ("Couldn't get registers"); |
158 | ||
2a6d284d MK |
159 | amd64_supply_native_gregset (current_regcache, ®s, -1); |
160 | if (regnum != -1) | |
68cc0bfb MK |
161 | return; |
162 | } | |
163 | ||
2a6d284d | 164 | if (regnum == -1 || regnum >= FP0_REGNUM) |
68cc0bfb | 165 | { |
2a6d284d | 166 | struct fpreg fpregs; |
68cc0bfb MK |
167 | |
168 | if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid), | |
169 | (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) | |
170 | perror_with_name ("Couldn't get floating point status"); | |
171 | ||
2a6d284d | 172 | x86_64_supply_fxsave ((const char *) &fpregs, -1); |
68cc0bfb MK |
173 | } |
174 | } | |
175 | ||
2a6d284d | 176 | /* Store register REGNUM back into the inferior. If REGNUM is -1, do |
68cc0bfb MK |
177 | this for all registers (including the floating point registers). */ |
178 | ||
179 | void | |
2a6d284d | 180 | store_inferior_registers (int regnum) |
68cc0bfb | 181 | { |
2a6d284d | 182 | if (regnum == -1 || amd64_native_gregset_supplies_p (regnum)) |
68cc0bfb | 183 | { |
2a6d284d | 184 | struct reg regs; |
68cc0bfb MK |
185 | |
186 | if (ptrace (PT_GETREGS, PIDGET (inferior_ptid), | |
2a6d284d | 187 | (PTRACE_ARG3_TYPE) ®s, 0) == -1) |
68cc0bfb MK |
188 | perror_with_name ("Couldn't get registers"); |
189 | ||
2a6d284d | 190 | amd64_collect_native_gregset (current_regcache, ®s, regnum); |
68cc0bfb MK |
191 | |
192 | if (ptrace (PT_SETREGS, PIDGET (inferior_ptid), | |
2a6d284d | 193 | (PTRACE_ARG3_TYPE) ®s, 0) == -1) |
68cc0bfb MK |
194 | perror_with_name ("Couldn't write registers"); |
195 | ||
2a6d284d | 196 | if (regnum != -1) |
68cc0bfb MK |
197 | return; |
198 | } | |
199 | ||
2a6d284d | 200 | if (regnum == -1 || regnum >= FP0_REGNUM) |
68cc0bfb | 201 | { |
2a6d284d | 202 | struct fpreg fpregs; |
68cc0bfb MK |
203 | |
204 | if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid), | |
205 | (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) | |
206 | perror_with_name ("Couldn't get floating point status"); | |
207 | ||
2a6d284d | 208 | x86_64_fill_fxsave ((char *) &fpregs, regnum); |
0485f6ad | 209 | |
68cc0bfb MK |
210 | if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid), |
211 | (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) | |
212 | perror_with_name ("Couldn't write floating point status"); | |
213 | } | |
214 | } | |
215 | \f | |
216 | ||
217 | /* Provide a prototype to silence -Wmissing-prototypes. */ | |
218 | void _initialize_amd64fbsd_nat (void); | |
219 | ||
220 | void | |
221 | _initialize_am64fbsd_nat (void) | |
222 | { | |
223 | int offset; | |
224 | ||
2a6d284d MK |
225 | amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset; |
226 | amd64_native_gregset64_reg_offset = reg_offset; | |
227 | ||
68cc0bfb MK |
228 | /* To support the recognition of signal handlers, i386bsd-tdep.c |
229 | hardcodes some constants. Inclusion of this file means that we | |
230 | are compiling a native debugger, which means that we can use the | |
231 | system header files and sysctl(3) to get at the relevant | |
232 | information. */ | |
233 | ||
68cc0bfb MK |
234 | #define SC_REG_OFFSET amd64fbsd_sc_reg_offset |
235 | ||
236 | /* We only check the program counter, stack pointer and frame | |
237 | pointer since these members of `struct sigcontext' are essential | |
238 | for providing backtraces. */ | |
239 | ||
240 | #define SC_RIP_OFFSET SC_REG_OFFSET[X86_64_RIP_REGNUM] | |
241 | #define SC_RSP_OFFSET SC_REG_OFFSET[X86_64_RSP_REGNUM] | |
242 | #define SC_RBP_OFFSET SC_REG_OFFSET[X86_64_RBP_REGNUM] | |
243 | ||
244 | /* Override the default value for the offset of the program counter | |
245 | in the sigcontext structure. */ | |
246 | offset = offsetof (struct sigcontext, sc_rip); | |
247 | ||
248 | if (SC_RIP_OFFSET != offset) | |
249 | { | |
250 | warning ("\ | |
251 | offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\ | |
252 | Please report this to <bug-gdb@gnu.org>.", | |
253 | offset, SC_RIP_OFFSET); | |
254 | } | |
255 | ||
256 | SC_RIP_OFFSET = offset; | |
257 | ||
258 | /* Likewise for the stack pointer. */ | |
259 | offset = offsetof (struct sigcontext, sc_rsp); | |
260 | ||
261 | if (SC_RSP_OFFSET != offset) | |
262 | { | |
263 | warning ("\ | |
264 | offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\ | |
265 | Please report this to <bug-gdb@gnu.org>.", | |
266 | offset, SC_RSP_OFFSET); | |
267 | } | |
268 | ||
269 | SC_RSP_OFFSET = offset; | |
270 | ||
271 | /* And the frame pointer. */ | |
272 | offset = offsetof (struct sigcontext, sc_rbp); | |
273 | ||
274 | if (SC_RBP_OFFSET != offset) | |
275 | { | |
276 | warning ("\ | |
277 | offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\ | |
278 | Please report this to <bug-gdb@gnu.org>.", | |
279 | offset, SC_RBP_OFFSET); | |
280 | } | |
281 | ||
282 | SC_RBP_OFFSET = offset; | |
283 | ||
284 | /* FreeBSD provides a kern.ps_strings sysctl that we can use to | |
285 | locate the sigtramp. That way we can still recognize a sigtramp | |
286 | if its location is changed in a new kernel. Of course this is | |
287 | still based on the assumption that the sigtramp is placed | |
288 | directly under the location where the program arguments and | |
289 | environment can be found. */ | |
290 | { | |
291 | int mib[2]; | |
292 | int ps_strings; | |
293 | size_t len; | |
294 | ||
68cc0bfb MK |
295 | mib[0] = CTL_KERN; |
296 | mib[1] = KERN_PS_STRINGS; | |
297 | len = sizeof (ps_strings); | |
298 | if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0) | |
299 | { | |
300 | amd64fbsd_sigtramp_start = ps_strings - 32; | |
301 | amd64fbsd_sigtramp_end = ps_strings; | |
302 | } | |
303 | } | |
304 | } |