amd64fbsd-nat.c revision 258887
1/* Native-dependent code for FreeBSD/amd64.
2
3   Copyright 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 <sys/sysctl.h>
32#include <sys/user.h>
33#include <machine/reg.h>
34
35#ifdef HAVE_SYS_PROCFS_H
36#include <sys/procfs.h>
37#endif
38
39#ifndef HAVE_GREGSET_T
40typedef struct reg gregset_t;
41#endif
42
43#ifndef HAVE_FPREGSET_T
44typedef struct fpreg fpregset_t;
45#endif
46
47#include "gregset.h"
48#include "amd64-tdep.h"
49#include "amd64-nat.h"
50
51
52/* Offset to the gregset_t location where REG is stored.  */
53#define REG_OFFSET(reg) offsetof (gregset_t, reg)
54
55/* At reg_offset[REGNUM] you'll find the offset to the gregset_t
56   location where the GDB register REGNUM is stored.  Unsupported
57   registers are marked with `-1'.  */
58static int reg_offset[] =
59{
60  REG_OFFSET (r_rax),
61  REG_OFFSET (r_rbx),
62  REG_OFFSET (r_rcx),
63  REG_OFFSET (r_rdx),
64  REG_OFFSET (r_rsi),
65  REG_OFFSET (r_rdi),
66  REG_OFFSET (r_rbp),
67  REG_OFFSET (r_rsp),
68  REG_OFFSET (r_r8),
69  REG_OFFSET (r_r9),
70  REG_OFFSET (r_r10),
71  REG_OFFSET (r_r11),
72  REG_OFFSET (r_r12),
73  REG_OFFSET (r_r13),
74  REG_OFFSET (r_r14),
75  REG_OFFSET (r_r15),
76  REG_OFFSET (r_rip),
77  REG_OFFSET (r_rflags),
78  REG_OFFSET (r_cs),
79  REG_OFFSET (r_ss),
80  -1,
81  -1,
82  -1,
83  -1
84};
85
86
87/* Mapping between the general-purpose registers in FreeBSD/amd64
88   `struct reg' format and GDB's register cache layout for
89   FreeBSD/i386.
90
91   Note that most FreeBSD/amd64 registers are 64-bit, while the
92   FreeBSD/i386 registers are all 32-bit, but since we're
93   little-endian we get away with that.  */
94
95/* From <machine/reg.h>.  */
96static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
97{
98  14 * 8, 13 * 8,		/* %eax, %ecx */
99  12 * 8, 11 * 8,		/* %edx, %ebx */
100  20 * 8, 10 * 8,		/* %esp, %ebp */
101  9 * 8, 8 * 8,			/* %esi, %edi */
102  17 * 8, 19 * 8,		/* %eip, %eflags */
103  18 * 8, 21 * 8,		/* %cs, %ss */
104  -1, -1, -1, -1		/* %ds, %es, %fs, %gs */
105};
106
107
108/* Transfering the registers between GDB, inferiors and core files.  */
109
110/* Fill GDB's register array with the general-purpose register values
111   in *GREGSETP.  */
112
113void
114supply_gregset (gregset_t *gregsetp)
115{
116  amd64_supply_native_gregset (current_regcache, gregsetp, -1);
117}
118
119/* Fill register REGNUM (if it is a general-purpose register) in
120   *GREGSETPS with the value in GDB's register array.  If REGNUM is -1,
121   do this for all registers.  */
122
123void
124fill_gregset (gregset_t *gregsetp, int regnum)
125{
126  amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
127}
128
129/* Fill GDB's register array with the floating-point register values
130   in *FPREGSETP.  */
131
132void
133supply_fpregset (fpregset_t *fpregsetp)
134{
135  amd64_supply_fxsave (current_regcache, -1, fpregsetp);
136}
137
138/* Fill register REGNUM (if it is a floating-point register) in
139   *FPREGSETP with the value in GDB's register array.  If REGNUM is -1,
140   do this for all registers.  */
141
142void
143fill_fpregset (fpregset_t *fpregsetp, int regnum)
144{
145  amd64_fill_fxsave ((char *) fpregsetp, regnum);
146}
147
148
149/* Provide a prototype to silence -Wmissing-prototypes.  */
150void _initialize_amd64fbsd_nat (void);
151
152void
153_initialize_amd64fbsd_nat (void)
154{
155  int offset;
156
157  amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
158  amd64_native_gregset64_reg_offset = reg_offset;
159
160  /* To support the recognition of signal handlers, i386bsd-tdep.c
161     hardcodes some constants.  Inclusion of this file means that we
162     are compiling a native debugger, which means that we can use the
163     system header files and sysctl(3) to get at the relevant
164     information.  */
165
166#define SC_REG_OFFSET amd64fbsd_sc_reg_offset
167
168  /* We only check the program counter, stack pointer and frame
169     pointer since these members of `struct sigcontext' are essential
170     for providing backtraces.  */
171
172#define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
173#define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
174#define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
175
176  /* Override the default value for the offset of the program counter
177     in the sigcontext structure.  */
178  offset = offsetof (struct sigcontext, sc_rip);
179
180  if (SC_RIP_OFFSET != offset)
181    {
182      warning ("\
183offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
184Please report this to <bug-gdb@gnu.org>.",
185	       offset, SC_RIP_OFFSET);
186    }
187
188  SC_RIP_OFFSET = offset;
189
190  /* Likewise for the stack pointer.  */
191  offset = offsetof (struct sigcontext, sc_rsp);
192
193  if (SC_RSP_OFFSET != offset)
194    {
195      warning ("\
196offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
197Please report this to <bug-gdb@gnu.org>.",
198	       offset, SC_RSP_OFFSET);
199    }
200
201  SC_RSP_OFFSET = offset;
202
203  /* And the frame pointer.  */
204  offset = offsetof (struct sigcontext, sc_rbp);
205
206  if (SC_RBP_OFFSET != offset)
207    {
208      warning ("\
209offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
210Please report this to <bug-gdb@gnu.org>.",
211	       offset, SC_RBP_OFFSET);
212    }
213
214  SC_RBP_OFFSET = offset;
215
216  /* FreeBSD provides a kern.proc.sigtramp sysctl that we can use to
217     locate the sigtramp.  That way we can still recognize a sigtramp
218     if its location is changed in a new kernel. */
219  {
220    int mib[4];
221    struct kinfo_sigtramp kst;
222    size_t len;
223
224    mib[0] = CTL_KERN;
225    mib[1] = KERN_PROC;
226    mib[2] = KERN_PROC_SIGTRAMP;
227    mib[3] = getpid();
228    len = sizeof (kst);
229    if (sysctl (mib, sizeof(mib) / sizeof(mib[0]), &kst, &len, NULL, 0) == 0)
230      {
231	amd64fbsd_sigtramp_start_addr = kst.ksigtramp_start;
232	amd64fbsd_sigtramp_end_addr = kst.ksigtramp_end;
233      }
234  }
235}
236