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