Support fs_base and gs_base on FreeBSD/i386.
[external/binutils.git] / gdb / i386-bsd-nat.c
1 /* Native-dependent code for modern i386 BSD's.
2
3    Copyright (C) 2000-2019 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 3 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, see <http://www.gnu.org/licenses/>.  */
19
20 #include "defs.h"
21 #include "inferior.h"
22 #include "regcache.h"
23
24 #include <signal.h>
25 #include <sys/types.h>
26 #include <sys/ptrace.h>
27 #include <machine/reg.h>
28 #include <machine/frame.h>
29
30 #include "i386-tdep.h"
31 #include "i387-tdep.h"
32 #include "x86-bsd-nat.h"
33 #include "i386-bsd-nat.h"
34 #include "inf-ptrace.h"
35 \f
36
37 /* In older BSD versions we cannot get at some of the segment
38    registers.  FreeBSD for example didn't support the %fs and %gs
39    registers until the 3.0 release.  We have autoconf checks for their
40    presence, and deal gracefully with their absence.  */
41
42 /* Offset in `struct reg' where MEMBER is stored.  */
43 #define REG_OFFSET(member) offsetof (struct reg, member)
44
45 /* At i386bsd_reg_offset[REGNUM] you'll find the offset in `struct
46    reg' where the GDB register REGNUM is stored.  Unsupported
47    registers are marked with `-1'.  */
48 static int i386bsd_r_reg_offset[] =
49 {
50   REG_OFFSET (r_eax),
51   REG_OFFSET (r_ecx),
52   REG_OFFSET (r_edx),
53   REG_OFFSET (r_ebx),
54   REG_OFFSET (r_esp),
55   REG_OFFSET (r_ebp),
56   REG_OFFSET (r_esi),
57   REG_OFFSET (r_edi),
58   REG_OFFSET (r_eip),
59   REG_OFFSET (r_eflags),
60   REG_OFFSET (r_cs),
61   REG_OFFSET (r_ss),
62   REG_OFFSET (r_ds),
63   REG_OFFSET (r_es),
64 #ifdef HAVE_STRUCT_REG_R_FS
65   REG_OFFSET (r_fs),
66 #else
67   -1,
68 #endif
69 #ifdef HAVE_STRUCT_REG_R_GS
70   REG_OFFSET (r_gs)
71 #else
72   -1
73 #endif
74 };
75
76 /* Macro to determine if a register is fetched with PT_GETREGS.  */
77 #define GETREGS_SUPPLIES(regnum) \
78   ((0 <= (regnum) && (regnum) <= 15))
79
80 #ifdef HAVE_PT_GETXMMREGS
81 /* Set to 1 if the kernel supports PT_GETXMMREGS.  Initialized to -1
82    so that we try PT_GETXMMREGS the first time around.  */
83 static int have_ptrace_xmmregs = -1;
84 #endif
85 \f
86
87 /* Supply the general-purpose registers in GREGS, to REGCACHE.  */
88
89 static void
90 i386bsd_supply_gregset (struct regcache *regcache, const void *gregs)
91 {
92   const char *regs = (const char *) gregs;
93   int regnum;
94
95   for (regnum = 0; regnum < ARRAY_SIZE (i386bsd_r_reg_offset); regnum++)
96     {
97       int offset = i386bsd_r_reg_offset[regnum];
98
99       if (offset != -1)
100         regcache->raw_supply (regnum, regs + offset);
101     }
102 }
103
104 /* Collect register REGNUM from REGCACHE and store its contents in
105    GREGS.  If REGNUM is -1, collect and store all appropriate
106    registers.  */
107
108 static void
109 i386bsd_collect_gregset (const struct regcache *regcache,
110                          void *gregs, int regnum)
111 {
112   char *regs = (char *) gregs;
113   int i;
114
115   for (i = 0; i < ARRAY_SIZE (i386bsd_r_reg_offset); i++)
116     {
117       if (regnum == -1 || regnum == i)
118         {
119           int offset = i386bsd_r_reg_offset[i];
120
121           if (offset != -1)
122             regcache->raw_collect (i, regs + offset);
123         }
124     }
125 }
126
127 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
128    for all registers (including the floating point registers).  */
129
130 void
131 i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
132 {
133   pid_t pid = get_ptrace_pid (regcache->ptid ());
134
135   if (regnum == -1 || GETREGS_SUPPLIES (regnum))
136     {
137       struct reg regs;
138
139       if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
140         perror_with_name (_("Couldn't get registers"));
141
142       i386bsd_supply_gregset (regcache, &regs);
143       if (regnum != -1)
144         return;
145     }
146
147 #ifdef PT_GETFSBASE
148   if (regnum == -1 || regnum == I386_FSBASE_REGNUM)
149     {
150       register_t base;
151
152       if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
153         perror_with_name (_("Couldn't get segment register fs_base"));
154
155       regcache->raw_supply (I386_FSBASE_REGNUM, &base);
156       if (regnum != -1)
157         return;
158     }
159 #endif
160 #ifdef PT_GETGSBASE
161   if (regnum == -1 || regnum == I386_GSBASE_REGNUM)
162     {
163       register_t base;
164
165       if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
166         perror_with_name (_("Couldn't get segment register gs_base"));
167
168       regcache->raw_supply (I386_GSBASE_REGNUM, &base);
169       if (regnum != -1)
170         return;
171     }
172 #endif
173
174   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
175     {
176       struct fpreg fpregs;
177 #ifdef HAVE_PT_GETXMMREGS
178       char xmmregs[512];
179 #endif
180
181 #ifdef PT_GETXSTATE_INFO
182       if (x86bsd_xsave_len != 0)
183         {
184           void *xstateregs;
185
186           xstateregs = alloca (x86bsd_xsave_len);
187           if (ptrace (PT_GETXSTATE, pid,
188                       (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
189             perror_with_name (_("Couldn't get extended state status"));
190
191           i387_supply_xsave (regcache, -1, xstateregs);
192           return;
193         }
194 #endif
195       
196 #ifdef HAVE_PT_GETXMMREGS
197       if (have_ptrace_xmmregs != 0
198           && ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
199         {
200           have_ptrace_xmmregs = 1;
201           i387_supply_fxsave (regcache, -1, xmmregs);
202         }
203       else
204         {
205           have_ptrace_xmmregs = 0;
206 #endif
207           if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
208             perror_with_name (_("Couldn't get floating point status"));
209
210           i387_supply_fsave (regcache, -1, &fpregs);
211 #ifdef HAVE_PT_GETXMMREGS
212         }
213 #endif
214     }
215 }
216
217 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
218    this for all registers (including the floating point registers).  */
219
220 void
221 i386bsd_store_inferior_registers (struct regcache *regcache, int regnum)
222 {
223   pid_t pid = get_ptrace_pid (regcache->ptid ());
224
225   if (regnum == -1 || GETREGS_SUPPLIES (regnum))
226     {
227       struct reg regs;
228
229       if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
230         perror_with_name (_("Couldn't get registers"));
231
232       i386bsd_collect_gregset (regcache, &regs, regnum);
233
234       if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
235         perror_with_name (_("Couldn't write registers"));
236
237       if (regnum != -1)
238         return;
239     }
240
241 #ifdef PT_SETFSBASE
242   if (regnum == -1 || regnum == I386_FSBASE_REGNUM)
243     {
244       register_t base;
245
246       regcache->raw_collect (I386_FSBASE_REGNUM, &base);
247
248       if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
249         perror_with_name (_("Couldn't write segment register fs_base"));
250       if (regnum != -1)
251         return;
252     }
253 #endif
254 #ifdef PT_SETGSBASE
255   if (regnum == -1 || regnum == I386_GSBASE_REGNUM)
256     {
257       register_t base;
258
259       regcache->raw_collect (I386_GSBASE_REGNUM, &base);
260
261       if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
262         perror_with_name (_("Couldn't write segment register gs_base"));
263       if (regnum != -1)
264         return;
265     }
266 #endif
267
268   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
269     {
270       struct fpreg fpregs;
271 #ifdef HAVE_PT_GETXMMREGS
272       char xmmregs[512];
273 #endif
274
275 #ifdef PT_GETXSTATE_INFO
276       if (x86bsd_xsave_len != 0)
277         {
278           void *xstateregs;
279
280           xstateregs = alloca (x86bsd_xsave_len);
281           if (ptrace (PT_GETXSTATE, pid,
282                       (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
283             perror_with_name (_("Couldn't get extended state status"));
284
285           i387_collect_xsave (regcache, -1, xstateregs, 0);
286
287           if (ptrace (PT_SETXSTATE, pid,
288                       (PTRACE_TYPE_ARG3) xstateregs, x86bsd_xsave_len) == -1)
289             perror_with_name (_("Couldn't write extended state status"));
290           return;
291         }
292 #endif
293
294 #ifdef HAVE_PT_GETXMMREGS
295       if (have_ptrace_xmmregs != 0
296           && ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
297         {
298           have_ptrace_xmmregs = 1;
299
300           i387_collect_fxsave (regcache, regnum, xmmregs);
301
302           if (ptrace (PT_SETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1)
303             perror_with_name (_("Couldn't write XMM registers"));
304         }
305       else
306         {
307           have_ptrace_xmmregs = 0;
308 #endif
309           if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
310             perror_with_name (_("Couldn't get floating point status"));
311
312           i387_collect_fsave (regcache, regnum, &fpregs);
313
314           if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
315             perror_with_name (_("Couldn't write floating point status"));
316 #ifdef HAVE_PT_GETXMMREGS
317         }
318 #endif
319     }
320 }
321
322 void
323 _initialize_i386bsd_nat (void)
324 {
325   int offset;
326
327   /* To support the recognition of signal handlers, i386-bsd-tdep.c
328      hardcodes some constants.  Inclusion of this file means that we
329      are compiling a native debugger, which means that we can use the
330      system header files and sysctl(3) to get at the relevant
331      information.  */
332
333 #if defined (__FreeBSD_version) && __FreeBSD_version >= 400011
334 #define SC_REG_OFFSET i386fbsd4_sc_reg_offset
335 #elif defined (__FreeBSD_version) && __FreeBSD_version >= 300005
336 #define SC_REG_OFFSET i386fbsd_sc_reg_offset
337 #elif defined (NetBSD) || defined (__NetBSD_Version__)
338 #define SC_REG_OFFSET i386nbsd_sc_reg_offset
339 #elif defined (OpenBSD)
340 #define SC_REG_OFFSET i386obsd_sc_reg_offset
341 #endif
342
343 #ifdef SC_REG_OFFSET
344
345   /* We only check the program counter, stack pointer and frame
346      pointer since these members of `struct sigcontext' are essential
347      for providing backtraces.  More checks could be added, but would
348      involve adding configure checks for the appropriate structure
349      members, since older BSD's don't provide all of them.  */
350
351 #define SC_PC_OFFSET SC_REG_OFFSET[I386_EIP_REGNUM]
352 #define SC_SP_OFFSET SC_REG_OFFSET[I386_ESP_REGNUM]
353 #define SC_FP_OFFSET SC_REG_OFFSET[I386_EBP_REGNUM]
354
355   /* Override the default value for the offset of the program counter
356      in the sigcontext structure.  */
357   offset = offsetof (struct sigcontext, sc_pc);
358
359   if (SC_PC_OFFSET != offset)
360     {
361       warning (_("\
362 offsetof (struct sigcontext, sc_pc) yields %d instead of %d.\n\
363 Please report this to <bug-gdb@gnu.org>."), 
364                offset, SC_PC_OFFSET);
365     }
366
367   SC_PC_OFFSET = offset;
368
369   /* Likewise for the stack pointer.  */
370   offset = offsetof (struct sigcontext, sc_sp);
371
372   if (SC_SP_OFFSET != offset)
373     {
374       warning (_("\
375 offsetof (struct sigcontext, sc_sp) yields %d instead of %d.\n\
376 Please report this to <bug-gdb@gnu.org>."),
377                offset, SC_SP_OFFSET);
378     }
379
380   SC_SP_OFFSET = offset;
381
382   /* And the frame pointer.  */
383   offset = offsetof (struct sigcontext, sc_fp);
384
385   if (SC_FP_OFFSET != offset)
386     {
387       warning (_("\
388 offsetof (struct sigcontext, sc_fp) yields %d instead of %d.\n\
389 Please report this to <bug-gdb@gnu.org>."),
390                offset, SC_FP_OFFSET);
391     }
392
393   SC_FP_OFFSET = offset;
394
395 #endif /* SC_REG_OFFSET */
396 }