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#include "target.h"
26
27#include "gdb_assert.h"
28#include <signal.h>
29#include <stddef.h>
30#include <sys/types.h>
31#include <sys/ptrace.h>
32#include <sys/sysctl.h>
33#include <machine/reg.h>
34
35#include "fbsd-nat.h"
36#include "amd64-tdep.h"
37#include "amd64-nat.h"
38
39
40/* Offset in `struct reg' where MEMBER is stored.  */
41#define REG_OFFSET(member) offsetof (struct reg, member)
42
43/* At amd64fbsd64_r_reg_offset[REGNUM] you'll find the offset in
44   `struct reg' location where the GDB register REGNUM is stored.
45   Unsupported registers are marked with `-1'.  */
46static int amd64fbsd64_r_reg_offset[] =
47{
48  REG_OFFSET (r_rax),
49  REG_OFFSET (r_rbx),
50  REG_OFFSET (r_rcx),
51  REG_OFFSET (r_rdx),
52  REG_OFFSET (r_rsi),
53  REG_OFFSET (r_rdi),
54  REG_OFFSET (r_rbp),
55  REG_OFFSET (r_rsp),
56  REG_OFFSET (r_r8),
57  REG_OFFSET (r_r9),
58  REG_OFFSET (r_r10),
59  REG_OFFSET (r_r11),
60  REG_OFFSET (r_r12),
61  REG_OFFSET (r_r13),
62  REG_OFFSET (r_r14),
63  REG_OFFSET (r_r15),
64  REG_OFFSET (r_rip),
65  REG_OFFSET (r_rflags),
66  REG_OFFSET (r_cs),
67  REG_OFFSET (r_ss),
68  -1,
69  -1,
70  -1,
71  -1
72};
73
74
75/* Mapping between the general-purpose registers in FreeBSD/amd64
76   `struct reg' format and GDB's register cache layout for
77   FreeBSD/i386.
78
79   Note that most FreeBSD/amd64 registers are 64-bit, while the
80   FreeBSD/i386 registers are all 32-bit, but since we're
81   little-endian we get away with that.  */
82
83/* From <machine/reg.h>.  */
84static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
85{
86  14 * 8, 13 * 8,		/* %eax, %ecx */
87  12 * 8, 11 * 8,		/* %edx, %ebx */
88  20 * 8, 10 * 8,		/* %esp, %ebp */
89  9 * 8, 8 * 8,			/* %esi, %edi */
90  17 * 8, 19 * 8,		/* %eip, %eflags */
91  18 * 8, 21 * 8,		/* %cs, %ss */
92  -1, -1, -1, -1		/* %ds, %es, %fs, %gs */
93};
94
95
96/* Support for debugging kernel virtual memory images.  */
97
98#include <sys/types.h>
99#include <machine/pcb.h>
100
101#include "bsd-kvm.h"
102
103static int
104amd64fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
105{
106  /* The following is true for FreeBSD 5.2:
107
108     The pcb contains %rip, %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15,
109     %ds, %es, %fs and %gs.  This accounts for all callee-saved
110     registers specified by the psABI and then some.  Here %esp
111     contains the stack pointer at the point just after the call to
112     cpu_switch().  From this information we reconstruct the register
113     state as it would like when we just returned from cpu_switch().  */
114
115  /* The stack pointer shouldn't be zero.  */
116  if (pcb->pcb_rsp == 0)
117    return 0;
118
119  pcb->pcb_rsp += 8;
120  regcache_raw_supply (regcache, AMD64_RIP_REGNUM, &pcb->pcb_rip);
121  regcache_raw_supply (regcache, AMD64_RBX_REGNUM, &pcb->pcb_rbx);
122  regcache_raw_supply (regcache, AMD64_RSP_REGNUM, &pcb->pcb_rsp);
123  regcache_raw_supply (regcache, AMD64_RBP_REGNUM, &pcb->pcb_rbp);
124  regcache_raw_supply (regcache, 12, &pcb->pcb_r12);
125  regcache_raw_supply (regcache, 13, &pcb->pcb_r13);
126  regcache_raw_supply (regcache, 14, &pcb->pcb_r14);
127  regcache_raw_supply (regcache, 15, &pcb->pcb_r15);
128  regcache_raw_supply (regcache, AMD64_DS_REGNUM, &pcb->pcb_ds);
129  regcache_raw_supply (regcache, AMD64_ES_REGNUM, &pcb->pcb_es);
130  regcache_raw_supply (regcache, AMD64_FS_REGNUM, &pcb->pcb_fs);
131  regcache_raw_supply (regcache, AMD64_GS_REGNUM, &pcb->pcb_gs);
132
133  return 1;
134}
135
136
137/* Provide a prototype to silence -Wmissing-prototypes.  */
138void _initialize_amd64fbsd_nat (void);
139
140void
141_initialize_amd64fbsd_nat (void)
142{
143  struct target_ops *t;
144  int offset;
145
146  amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
147  amd64_native_gregset64_reg_offset = amd64fbsd64_r_reg_offset;
148
149  /* Add some extra features to the common *BSD/i386 target.  */
150  t = amd64bsd_target ();
151  t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
152  t->to_find_memory_regions = fbsd_find_memory_regions;
153  t->to_make_corefile_notes = fbsd_make_corefile_notes;
154  add_target (t);
155
156  /* Support debugging kernel virtual memory images.  */
157  bsd_kvm_add_target (amd64fbsd_supply_pcb);
158
159  /* To support the recognition of signal handlers, i386bsd-tdep.c
160     hardcodes some constants.  Inclusion of this file means that we
161     are compiling a native debugger, which means that we can use the
162     system header files and sysctl(3) to get at the relevant
163     information.  */
164
165#define SC_REG_OFFSET amd64fbsd_sc_reg_offset
166
167  /* We only check the program counter, stack pointer and frame
168     pointer since these members of `struct sigcontext' are essential
169     for providing backtraces.  */
170
171#define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
172#define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
173#define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
174
175  /* Override the default value for the offset of the program counter
176     in the sigcontext structure.  */
177  offset = offsetof (struct sigcontext, sc_rip);
178
179  if (SC_RIP_OFFSET != offset)
180    {
181      warning ("\
182offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
183Please report this to <bug-gdb@gnu.org>.",
184	       offset, SC_RIP_OFFSET);
185    }
186
187  SC_RIP_OFFSET = offset;
188
189  /* Likewise for the stack pointer.  */
190  offset = offsetof (struct sigcontext, sc_rsp);
191
192  if (SC_RSP_OFFSET != offset)
193    {
194      warning ("\
195offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
196Please report this to <bug-gdb@gnu.org>.",
197	       offset, SC_RSP_OFFSET);
198    }
199
200  SC_RSP_OFFSET = offset;
201
202  /* And the frame pointer.  */
203  offset = offsetof (struct sigcontext, sc_rbp);
204
205  if (SC_RBP_OFFSET != offset)
206    {
207      warning ("\
208offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
209Please report this to <bug-gdb@gnu.org>.",
210	       offset, SC_RBP_OFFSET);
211    }
212
213  SC_RBP_OFFSET = offset;
214
215  /* FreeBSD provides a kern.ps_strings sysctl that we can use to
216     locate the sigtramp.  That way we can still recognize a sigtramp
217     if its location is changed in a new kernel.  Of course this is
218     still based on the assumption that the sigtramp is placed
219     directly under the location where the program arguments and
220     environment can be found.  */
221  {
222    int mib[2];
223    long ps_strings;
224    size_t len;
225
226    mib[0] = CTL_KERN;
227    mib[1] = KERN_PS_STRINGS;
228    len = sizeof (ps_strings);
229    if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0)
230      {
231	amd64fbsd_sigtramp_start_addr = ps_strings - 32;
232	amd64fbsd_sigtramp_end_addr = ps_strings;
233      }
234  }
235}
236