xref: /dflybsd-src/contrib/gdb-7/gdb/amd64dfly-nat.c (revision 7cc1e87b157bd0b53ef6214034ac99cfecc444a2)
1 /* Native-dependent code for DragonFly/amd64.
2 
3    Copyright (C) 2003-2013 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 #include "target.h"
24 #include "gregset.h"
25 
26 #include "gdb_assert.h"
27 #include <signal.h>
28 #include <stddef.h>
29 #include <sys/types.h>
30 #include <sys/procfs.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 #include "amd64bsd-nat.h"
39 #include "i386-nat.h"
40 
41 /* Offset in `struct reg' where MEMBER is stored.  */
42 #define REG_OFFSET(member) offsetof (struct reg, member)
43 
44 /* At amd64dfly64_r_reg_offset[REGNUM] you'll find the offset in
45    `struct reg' location where the GDB register REGNUM is stored.
46    Unsupported registers are marked with `-1'.  */
47 static int amd64dfly64_r_reg_offset[] =
48 {
49 	REG_OFFSET(r_rax),
50 	REG_OFFSET(r_rbx),
51 	REG_OFFSET(r_rcx),
52 	REG_OFFSET(r_rdx),
53 	REG_OFFSET(r_rsi),
54 	REG_OFFSET(r_rdi),
55 	REG_OFFSET(r_rbp),
56 	REG_OFFSET(r_rsp),
57 	REG_OFFSET(r_r8),
58 	REG_OFFSET(r_r9),
59 	REG_OFFSET(r_r10),
60 	REG_OFFSET(r_r11),
61 	REG_OFFSET(r_r12),
62 	REG_OFFSET(r_r13),
63 	REG_OFFSET(r_r14),
64 	REG_OFFSET(r_r15),
65 	REG_OFFSET(r_rip),
66 	REG_OFFSET(r_rflags),
67 	REG_OFFSET(r_cs),
68 	REG_OFFSET(r_ss),
69 	-1,
70 	-1,
71 	-1,
72 	-1
73 };
74 
75 /* Mapping between the general-purpose registers in DragonFly/amd64
76    `struct reg' format and GDB's register cache layout for
77    DragonFly/i386.
78 
79    Note that most DragonFly/amd64 registers are 64-bit, while the
80    DragonFly/i386 registers are all 32-bit, but since we're
81    little-endian we get away with that.  */
82 
83 /* From <machine/reg.h>.  */
84 static int amd64dfly32_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 #ifdef DFLY_PCB_SUPPLY
96 /* Transfering the registers between GDB, inferiors and core files.  */
97 
98 /* Fill GDB's register array with the general-purpose register values
99    in *GREGSETP.  */
100 
101 void
102 supply_gregset(struct regcache *regcache, const gregset_t * gregsetp)
103 {
104 	amd64_supply_native_gregset(regcache, gregsetp, -1);
105 }
106 
107 /* Fill register REGNUM (if it is a general-purpose register) in
108    *GREGSETPS with the value in GDB's register array.  If REGNUM is -1,
109    do this for all registers.  */
110 
111 void
112 fill_gregset(const struct regcache *regcache, gdb_gregset_t * gregsetp, int regnum)
113 {
114 	amd64_collect_native_gregset(regcache, gregsetp, regnum);
115 }
116 
117 /* Fill GDB's register array with the floating-point register values
118    in *FPREGSETP.  */
119 
120 void
121 supply_fpregset(struct regcache *regcache, const fpregset_t * fpregsetp)
122 {
123 	amd64_supply_fxsave(regcache, -1, fpregsetp);
124 }
125 
126 /* Fill register REGNUM (if it is a floating-point register) in
127    *FPREGSETP with the value in GDB's register array.  If REGNUM is -1,
128    do this for all registers.  */
129 
130 void
131 fill_fpregset(const struct regcache *regcache, gdb_fpregset_t * fpregsetp, int regnum)
132 {
133 	amd64_collect_fxsave(regcache, regnum, fpregsetp);
134 }
135 
136 /* Support for debugging kernel virtual memory images.  */
137 
138 #include <sys/types.h>
139 #include <machine/pcb.h>
140 #include <osreldate.h>
141 
142 #include "bsd-kvm.h"
143 
144 static int
145 amd64dfly_supply_pcb(struct regcache *regcache, struct pcb *pcb)
146 {
147 	/* The following is true for FreeBSD 5.2:
148 	 *
149 	 * The pcb contains %rip, %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15, %ds,
150 	 * %es, %fs and %gs.  This accounts for all callee-saved registers
151 	 * specified by the psABI and then some.  Here %esp contains the stack
152 	 * pointer at the point just after the call to cpu_switch().  From
153 	 * this information we reconstruct the register state as it would like
154 	 * when we just returned from cpu_switch().  */
155 
156 	/* The stack pointer shouldn't be zero.  */
157 	if (pcb->pcb_rsp == 0)
158 		return 0;
159 
160 	pcb->pcb_rsp += 8;
161 	regcache_raw_supply(regcache, AMD64_RIP_REGNUM, &pcb->pcb_rip);
162 	regcache_raw_supply(regcache, AMD64_RBX_REGNUM, &pcb->pcb_rbx);
163 	regcache_raw_supply(regcache, AMD64_RSP_REGNUM, &pcb->pcb_rsp);
164 	regcache_raw_supply(regcache, AMD64_RBP_REGNUM, &pcb->pcb_rbp);
165 	regcache_raw_supply(regcache, 12, &pcb->pcb_r12);
166 	regcache_raw_supply(regcache, 13, &pcb->pcb_r13);
167 	regcache_raw_supply(regcache, 14, &pcb->pcb_r14);
168 	regcache_raw_supply(regcache, 15, &pcb->pcb_r15);
169 
170 	return 1;
171 }
172 #endif				/* DFLY_PCB_SUPPLY */
173 
174 static void (*super_mourn_inferior) (struct target_ops *ops);
175 
176 static void
177 amd64dfly_mourn_inferior(struct target_ops *ops)
178 {
179 #ifdef HAVE_PT_GETDBREGS
180 	i386_cleanup_dregs();
181 #endif
182 	super_mourn_inferior(ops);
183 }
184 
185 /* Provide a prototype to silence -Wmissing-prototypes.  */
186 void _initialize_amd64dfly_nat(void);
187 
188 void
189 _initialize_amd64dfly_nat(void)
190 {
191 	struct target_ops *t;
192 	int offset;
193 
194 	amd64_native_gregset32_reg_offset = amd64dfly32_r_reg_offset;
195 	amd64_native_gregset64_reg_offset = amd64dfly64_r_reg_offset;
196 
197 	/* Add some extra features to the common *BSD/i386 target.  */
198 	t = amd64bsd_target();
199 
200 #ifdef HAVE_PT_GETDBREGS
201 
202 	i386_use_watchpoints(t);
203 
204 	i386_dr_low.set_control = amd64bsd_dr_set_control;
205 	i386_dr_low.set_addr = amd64bsd_dr_set_addr;
206 	i386_dr_low.get_addr = amd64bsd_dr_get_addr;
207 	i386_dr_low.get_status = amd64bsd_dr_get_status;
208 	i386_dr_low.get_control = amd64bsd_dr_get_control;
209 	i386_set_debug_register_length(8);
210 
211 #endif				/* HAVE_PT_GETDBREGS */
212 
213 	super_mourn_inferior = t->to_mourn_inferior;
214 	t->to_mourn_inferior = amd64dfly_mourn_inferior;
215 
216 	t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
217 	t->to_find_memory_regions = fbsd_find_memory_regions;
218 	t->to_make_corefile_notes = fbsd_make_corefile_notes;
219 	add_target(t);
220 
221 #ifdef DFLY_PCB_SUPPLY
222 	/* Support debugging kernel virtual memory images.  */
223 	bsd_kvm_add_target(amd64dfly_supply_pcb);
224 #endif
225 
226 	/* To support the recognition of signal handlers, i386bsd-tdep.c
227 	 * hardcodes some constants.  Inclusion of this file means that we are
228 	 * compiling a native debugger, which means that we can use the system
229 	 * header files and sysctl(3) to get at the relevant information.  */
230 
231 #define SC_REG_OFFSET amd64dfly_sc_reg_offset
232 
233 	/* We only check the program counter, stack pointer and frame pointer
234 	 * since these members of `struct sigcontext' are essential for
235 	 * providing backtraces.  */
236 
237 #define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
238 #define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
239 #define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
240 
241 	/* Override the default value for the offset of the program counter in
242 	 * the sigcontext structure.  */
243 	offset = offsetof(struct sigcontext, sc_rip);
244 
245 	if (SC_RIP_OFFSET != offset) {
246 		warning(_("\
247 offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
248 Please report this to <bug-gdb@gnu.org>."),
249 		    offset, SC_RIP_OFFSET);
250 	}
251 	SC_RIP_OFFSET = offset;
252 
253 	/* Likewise for the stack pointer.  */
254 	offset = offsetof(struct sigcontext, sc_rsp);
255 
256 	if (SC_RSP_OFFSET != offset) {
257 		warning(_("\
258 offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
259 Please report this to <bug-gdb@gnu.org>."),
260 		    offset, SC_RSP_OFFSET);
261 	}
262 	SC_RSP_OFFSET = offset;
263 
264 	/* And the frame pointer.  */
265 	offset = offsetof(struct sigcontext, sc_rbp);
266 
267 	if (SC_RBP_OFFSET != offset) {
268 		warning(_("\
269 offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
270 Please report this to <bug-gdb@gnu.org>."),
271 		    offset, SC_RBP_OFFSET);
272 	}
273 	SC_RBP_OFFSET = offset;
274 
275 	/* DragonFly provides a kern.ps_strings sysctl that we can use to
276 	 * locate the sigtramp.  That way we can still recognize a sigtramp if
277 	 * its location is changed in a new kernel.  Of course this is still
278 	 * based on the assumption that the sigtramp is placed directly under
279 	 * the location where the program arguments and environment can be
280 	 * found.  */
281 	{
282 		int mib[2];
283 		long ps_strings;
284 		size_t len;
285 
286 		mib[0] = CTL_KERN;
287 		mib[1] = KERN_PS_STRINGS;
288 		len = sizeof(ps_strings);
289 		if (sysctl(mib, 2, &ps_strings, &len, NULL, 0) == 0) {
290 			amd64dfly_sigtramp_start_addr = ps_strings - 32;
291 			amd64dfly_sigtramp_end_addr = ps_strings;
292 		}
293 	}
294 }
295