xref: /openbsd/gnu/usr.bin/binutils/gdb/i386bsd-nat.c (revision c9d97425)
1 /* Native-dependent code for modern i386 BSD's.
2 
3    Copyright 2000, 2001, 2002, 2003, 2004 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 <machine/reg.h>
32 #include <machine/frame.h>
33 
34 #include "i386-tdep.h"
35 #include "i387-tdep.h"
36 #include "i386bsd-nat.h"
37 #include "inf-ptrace.h"
38 
39 
40 /* In older BSD versions we cannot get at some of the segment
41    registers.  FreeBSD for example didn't support the %fs and %gs
42    registers until the 3.0 release.  We have autoconf checks for their
43    presence, and deal gracefully with their absence.  */
44 
45 /* Offset in `struct reg' where MEMBER is stored.  */
46 #define REG_OFFSET(member) offsetof (struct reg, member)
47 
48 /* At i386bsd_reg_offset[REGNUM] you'll find the offset in `struct
49    reg' where the GDB register REGNUM is stored.  Unsupported
50    registers are marked with `-1'.  */
51 static int i386bsd_r_reg_offset[] =
52 {
53   REG_OFFSET (r_eax),
54   REG_OFFSET (r_ecx),
55   REG_OFFSET (r_edx),
56   REG_OFFSET (r_ebx),
57   REG_OFFSET (r_esp),
58   REG_OFFSET (r_ebp),
59   REG_OFFSET (r_esi),
60   REG_OFFSET (r_edi),
61   REG_OFFSET (r_eip),
62   REG_OFFSET (r_eflags),
63   REG_OFFSET (r_cs),
64   REG_OFFSET (r_ss),
65   REG_OFFSET (r_ds),
66   REG_OFFSET (r_es),
67 #ifdef HAVE_STRUCT_REG_R_FS
68   REG_OFFSET (r_fs),
69 #else
70   -1,
71 #endif
72 #ifdef HAVE_STRUCT_REG_R_GS
73   REG_OFFSET (r_gs)
74 #else
75   -1
76 #endif
77 };
78 
79 /* Macro to determine if a register is fetched with PT_GETREGS.  */
80 #define GETREGS_SUPPLIES(regnum) \
81   ((0 <= (regnum) && (regnum) <= 15))
82 
83 #ifdef HAVE_PT_GETXMMREGS
84 /* Set to 1 if the kernel supports PT_GETXMMREGS.  Initialized to -1
85    so that we try PT_GETXMMREGS the first time around.  */
86 static int have_ptrace_xmmregs = -1;
87 #endif
88 
89 
90 /* Supply the general-purpose registers in GREGS, to REGCACHE.  */
91 
92 static void
i386bsd_supply_gregset(struct regcache * regcache,const void * gregs)93 i386bsd_supply_gregset (struct regcache *regcache, const void *gregs)
94 {
95   const char *regs = gregs;
96   int regnum;
97 
98   for (regnum = 0; regnum < ARRAY_SIZE (i386bsd_r_reg_offset); regnum++)
99     {
100       int offset = i386bsd_r_reg_offset[regnum];
101 
102       if (offset != -1)
103 	regcache_raw_supply (regcache, regnum, regs + offset);
104     }
105 }
106 
107 /* Collect register REGNUM from REGCACHE and store its contents in
108    GREGS.  If REGNUM is -1, collect and store all appropriate
109    registers.  */
110 
111 static void
i386bsd_collect_gregset(const struct regcache * regcache,void * gregs,int regnum)112 i386bsd_collect_gregset (const struct regcache *regcache,
113 			 void *gregs, int regnum)
114 {
115   char *regs = gregs;
116   int i;
117 
118   for (i = 0; i < ARRAY_SIZE (i386bsd_r_reg_offset); i++)
119     {
120       if (regnum == -1 || regnum == i)
121 	{
122 	  int offset = i386bsd_r_reg_offset[i];
123 
124 	  if (offset != -1)
125 	    regcache_raw_collect (regcache, i, regs + offset);
126 	}
127     }
128 }
129 
130 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
131    for all registers (including the floating point registers).  */
132 
133 static void
i386bsd_fetch_inferior_registers(int regnum)134 i386bsd_fetch_inferior_registers (int regnum)
135 {
136   int pid;
137 
138   /* Cater for systems like OpenBSD, that implement threads as
139      separate processes.  */
140   pid = ptid_get_lwp (inferior_ptid);
141   if (pid == 0)
142     pid = ptid_get_pid (inferior_ptid);
143 
144   if (regnum == -1 || GETREGS_SUPPLIES (regnum))
145     {
146       struct reg regs;
147 
148       if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
149 	perror_with_name ("Couldn't get registers");
150 
151       i386bsd_supply_gregset (current_regcache, &regs);
152       if (regnum != -1)
153 	return;
154     }
155 
156   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
157     {
158       struct fpreg fpregs;
159 #ifdef HAVE_PT_GETXMMREGS
160       char xmmregs[512];
161 
162       if (have_ptrace_xmmregs != 0
163 	  && ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
164 	{
165 	  have_ptrace_xmmregs = 1;
166 	  i387_supply_fxsave (current_regcache, -1, xmmregs);
167 	}
168       else
169 	{
170           if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
171 	    perror_with_name ("Couldn't get floating point status");
172 
173 	  i387_supply_fsave (current_regcache, -1, &fpregs);
174 	}
175 #else
176       if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
177 	perror_with_name ("Couldn't get floating point status");
178 
179       i387_supply_fsave (current_regcache, -1, &fpregs);
180 #endif
181     }
182 }
183 
184 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
185    this for all registers (including the floating point registers).  */
186 
187 static void
i386bsd_store_inferior_registers(int regnum)188 i386bsd_store_inferior_registers (int regnum)
189 {
190   int pid;
191 
192   /* Cater for systems like OpenBSD, that implement threads as
193      separate processes.  */
194   pid = ptid_get_lwp (inferior_ptid);
195   if (pid == 0)
196     pid = ptid_get_pid (inferior_ptid);
197 
198   if (regnum == -1 || GETREGS_SUPPLIES (regnum))
199     {
200       struct reg regs;
201 
202       if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
203         perror_with_name ("Couldn't get registers");
204 
205       i386bsd_collect_gregset (current_regcache, &regs, regnum);
206 
207       if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
208         perror_with_name ("Couldn't write registers");
209 
210       if (regnum != -1)
211 	return;
212     }
213 
214   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
215     {
216       struct fpreg fpregs;
217 #ifdef HAVE_PT_GETXMMREGS
218       char xmmregs[512];
219 
220       if (have_ptrace_xmmregs != 0
221 	  && ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
222 	{
223 	  have_ptrace_xmmregs = 1;
224 
225 	  i387_collect_fxsave (current_regcache, regnum, xmmregs);
226 
227 	  if (ptrace (PT_SETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1)
228             perror_with_name ("Couldn't write XMM registers");
229 	}
230       else
231 	{
232 	  have_ptrace_xmmregs = 0;
233 #endif
234           if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
235 	    perror_with_name ("Couldn't get floating point status");
236 
237           i387_collect_fsave (current_regcache, regnum, &fpregs);
238 
239           if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
240 	    perror_with_name ("Couldn't write floating point status");
241 #ifdef HAVE_PT_GETXMMREGS
242         }
243 #endif
244     }
245 }
246 
247 /* Create a prototype *BSD/i386 target.  The client can override it
248    with local methods.  */
249 
250 struct target_ops *
i386bsd_target(void)251 i386bsd_target (void)
252 {
253   struct target_ops *t;
254 
255   t = inf_ptrace_target ();
256   t->to_fetch_registers = i386bsd_fetch_inferior_registers;
257   t->to_store_registers = i386bsd_store_inferior_registers;
258   return t;
259 }
260 
261 
262 /* Support for debug registers.  */
263 
264 #ifdef HAVE_PT_GETDBREGS
265 
266 /* Not all versions of FreeBSD/i386 that support the debug registers
267    have this macro.  */
268 #ifndef DBREG_DRX
269 #define DBREG_DRX(d, x) ((&d->dr0)[x])
270 #endif
271 
272 static void
i386bsd_dr_set(int regnum,unsigned int value)273 i386bsd_dr_set (int regnum, unsigned int value)
274 {
275   struct dbreg dbregs;
276 
277   if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
278               (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
279     perror_with_name ("Couldn't get debug registers");
280 
281   /* For some mysterious reason, some of the reserved bits in the
282      debug control register get set.  Mask these off, otherwise the
283      ptrace call below will fail.  */
284   DBREG_DRX ((&dbregs), 7) &= ~(0x0000fc00);
285 
286   DBREG_DRX ((&dbregs), regnum) = value;
287 
288   if (ptrace (PT_SETDBREGS, PIDGET (inferior_ptid),
289               (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
290     perror_with_name ("Couldn't write debug registers");
291 }
292 
293 void
i386bsd_dr_set_control(unsigned long control)294 i386bsd_dr_set_control (unsigned long control)
295 {
296   i386bsd_dr_set (7, control);
297 }
298 
299 void
i386bsd_dr_set_addr(int regnum,CORE_ADDR addr)300 i386bsd_dr_set_addr (int regnum, CORE_ADDR addr)
301 {
302   gdb_assert (regnum >= 0 && regnum <= 4);
303 
304   i386bsd_dr_set (regnum, addr);
305 }
306 
307 void
i386bsd_dr_reset_addr(int regnum)308 i386bsd_dr_reset_addr (int regnum)
309 {
310   gdb_assert (regnum >= 0 && regnum <= 4);
311 
312   i386bsd_dr_set (regnum, 0);
313 }
314 
315 unsigned long
i386bsd_dr_get_status(void)316 i386bsd_dr_get_status (void)
317 {
318   struct dbreg dbregs;
319 
320   /* FIXME: kettenis/2001-03-31: Calling perror_with_name if the
321      ptrace call fails breaks debugging remote targets.  The correct
322      way to fix this is to add the hardware breakpoint and watchpoint
323      stuff to the target vector.  For now, just return zero if the
324      ptrace call fails.  */
325   if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
326 	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
327 #if 0
328     perror_with_name ("Couldn't read debug registers");
329 #else
330     return 0;
331 #endif
332 
333   return DBREG_DRX ((&dbregs), 6);
334 }
335 
336 #endif /* PT_GETDBREGS */
337 
338 
339 /* Support for the user struct.  */
340 
341 /* Return the address register REGNUM.  BLOCKEND is the value of
342    u.u_ar0, which should point to the registers.  */
343 
344 CORE_ADDR
register_u_addr(CORE_ADDR blockend,int regnum)345 register_u_addr (CORE_ADDR blockend, int regnum)
346 {
347   gdb_assert (regnum >= 0 && regnum < ARRAY_SIZE (i386bsd_r_reg_offset));
348 
349   return blockend + i386bsd_r_reg_offset[regnum];
350 }
351 
352 #include <sys/param.h>
353 #include <sys/user.h>
354 
355 /* Return the size of the user struct.  */
356 
357 int
kernel_u_size(void)358 kernel_u_size (void)
359 {
360   return (sizeof (struct user));
361 }
362 
363 void
_initialize_i386bsd_nat(void)364 _initialize_i386bsd_nat (void)
365 {
366   int offset;
367 
368   /* To support the recognition of signal handlers, i386bsd-tdep.c
369      hardcodes some constants.  Inclusion of this file means that we
370      are compiling a native debugger, which means that we can use the
371      system header files and sysctl(3) to get at the relevant
372      information.  */
373 
374 #if defined (__FreeBSD_version) && __FreeBSD_version >= 400011
375 #define SC_REG_OFFSET i386fbsd4_sc_reg_offset
376 #elif defined (__FreeBSD_version) && __FreeBSD_version >= 300005
377 #define SC_REG_OFFSET i386fbsd_sc_reg_offset
378 #elif defined (NetBSD) || defined (__NetBSD_Version__)
379 #define SC_REG_OFFSET i386nbsd_sc_reg_offset
380 #elif defined (OpenBSD)
381 #define SC_REG_OFFSET i386obsd_sc_reg_offset
382 #endif
383 
384 #ifdef SC_REG_OFFSET
385 
386   /* We only check the program counter, stack pointer and frame
387      pointer since these members of `struct sigcontext' are essential
388      for providing backtraces.  More checks could be added, but would
389      involve adding configure checks for the appropriate structure
390      members, since older BSD's don't provide all of them.  */
391 
392 #define SC_PC_OFFSET SC_REG_OFFSET[I386_EIP_REGNUM]
393 #define SC_SP_OFFSET SC_REG_OFFSET[I386_ESP_REGNUM]
394 #define SC_FP_OFFSET SC_REG_OFFSET[I386_EBP_REGNUM]
395 
396   /* Override the default value for the offset of the program counter
397      in the sigcontext structure.  */
398   offset = offsetof (struct sigcontext, sc_pc);
399 
400   if (SC_PC_OFFSET != offset)
401     {
402       warning ("\
403 offsetof (struct sigcontext, sc_pc) yields %d instead of %d.\n\
404 Please report this to <bug-gdb@gnu.org>.",
405 	       offset, SC_PC_OFFSET);
406     }
407 
408   SC_PC_OFFSET = offset;
409 
410   /* Likewise for the stack pointer.  */
411   offset = offsetof (struct sigcontext, sc_sp);
412 
413   if (SC_SP_OFFSET != offset)
414     {
415       warning ("\
416 offsetof (struct sigcontext, sc_sp) yields %d instead of %d.\n\
417 Please report this to <bug-gdb@gnu.org>.",
418 	       offset, SC_SP_OFFSET);
419     }
420 
421   SC_SP_OFFSET = offset;
422 
423   /* And the frame pointer.  */
424   offset = offsetof (struct sigcontext, sc_fp);
425 
426   if (SC_FP_OFFSET != offset)
427     {
428       warning ("\
429 offsetof (struct sigcontext, sc_fp) yields %d instead of %d.\n\
430 Please report this to <bug-gdb@gnu.org>.",
431 	       offset, SC_FP_OFFSET);
432     }
433 
434   SC_FP_OFFSET = offset;
435 
436 #endif /* SC_REG_OFFSET */
437 }
438