gdb - Fix indentantion in DragonFly specific files.
[dragonfly.git] / contrib / gdb-7 / gdb / amd64dfly-nat.c
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 #if (__FreeBSD_version < 800075) && (__FreeBSD_kernel_version < 800075)
170         /* struct pcb provides the pcb_ds/pcb_es/pcb_fs/pcb_gs fields only up
171          * until __FreeBSD_version 800074: The removal of these fields
172          * occurred on 2009-04-01 while the __FreeBSD_version number was
173          * bumped to 800075 on 2009-04-06.  So 800075 is the closest version
174          * number where we should not try to access these fields.  */
175         regcache_raw_supply(regcache, AMD64_DS_REGNUM, &pcb->pcb_ds);
176         regcache_raw_supply(regcache, AMD64_ES_REGNUM, &pcb->pcb_es);
177         regcache_raw_supply(regcache, AMD64_FS_REGNUM, &pcb->pcb_fs);
178         regcache_raw_supply(regcache, AMD64_GS_REGNUM, &pcb->pcb_gs);
179 #endif
180
181         return 1;
182 }
183 #endif                          /* DFLY_PCB_SUPPLY */
184
185 static void (*super_mourn_inferior) (struct target_ops *ops);
186
187 static void
188 amd64dfly_mourn_inferior(struct target_ops *ops)
189 {
190 #ifdef HAVE_PT_GETDBREGS
191         i386_cleanup_dregs();
192 #endif
193         super_mourn_inferior(ops);
194 }
195
196 /* Provide a prototype to silence -Wmissing-prototypes.  */
197 void _initialize_amd64dfly_nat(void);
198
199 void
200 _initialize_amd64dfly_nat(void)
201 {
202         struct target_ops *t;
203         int offset;
204
205         amd64_native_gregset32_reg_offset = amd64dfly32_r_reg_offset;
206         amd64_native_gregset64_reg_offset = amd64dfly64_r_reg_offset;
207
208         /* Add some extra features to the common *BSD/i386 target.  */
209         t = amd64bsd_target();
210
211 #ifdef HAVE_PT_GETDBREGS
212
213         i386_use_watchpoints(t);
214
215         i386_dr_low.set_control = amd64bsd_dr_set_control;
216         i386_dr_low.set_addr = amd64bsd_dr_set_addr;
217         i386_dr_low.get_addr = amd64bsd_dr_get_addr;
218         i386_dr_low.get_status = amd64bsd_dr_get_status;
219         i386_dr_low.get_control = amd64bsd_dr_get_control;
220         i386_set_debug_register_length(8);
221
222 #endif                          /* HAVE_PT_GETDBREGS */
223
224         super_mourn_inferior = t->to_mourn_inferior;
225         t->to_mourn_inferior = amd64dfly_mourn_inferior;
226
227         t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
228         t->to_find_memory_regions = fbsd_find_memory_regions;
229         t->to_make_corefile_notes = fbsd_make_corefile_notes;
230         add_target(t);
231
232 #ifdef DFLY_PCB_SUPPLY
233         /* Support debugging kernel virtual memory images.  */
234         bsd_kvm_add_target(amd64dfly_supply_pcb);
235 #endif
236
237         /* To support the recognition of signal handlers, i386bsd-tdep.c
238          * hardcodes some constants.  Inclusion of this file means that we are
239          * compiling a native debugger, which means that we can use the system
240          * header files and sysctl(3) to get at the relevant information.  */
241
242 #define SC_REG_OFFSET amd64dfly_sc_reg_offset
243
244         /* We only check the program counter, stack pointer and frame pointer
245          * since these members of `struct sigcontext' are essential for
246          * providing backtraces.  */
247
248 #define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
249 #define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
250 #define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
251
252         /* Override the default value for the offset of the program counter in
253          * the sigcontext structure.  */
254         offset = offsetof(struct sigcontext, sc_rip);
255
256         if (SC_RIP_OFFSET != offset) {
257                 warning(_("\
258 offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
259 Please report this to <bug-gdb@gnu.org>."),
260                     offset, SC_RIP_OFFSET);
261         }
262         SC_RIP_OFFSET = offset;
263
264         /* Likewise for the stack pointer.  */
265         offset = offsetof(struct sigcontext, sc_rsp);
266
267         if (SC_RSP_OFFSET != offset) {
268                 warning(_("\
269 offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
270 Please report this to <bug-gdb@gnu.org>."),
271                     offset, SC_RSP_OFFSET);
272         }
273         SC_RSP_OFFSET = offset;
274
275         /* And the frame pointer.  */
276         offset = offsetof(struct sigcontext, sc_rbp);
277
278         if (SC_RBP_OFFSET != offset) {
279                 warning(_("\
280 offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
281 Please report this to <bug-gdb@gnu.org>."),
282                     offset, SC_RBP_OFFSET);
283         }
284         SC_RBP_OFFSET = offset;
285
286         /* DragonFly provides a kern.ps_strings sysctl that we can use to
287          * locate the sigtramp.  That way we can still recognize a sigtramp if
288          * its location is changed in a new kernel.  Of course this is still
289          * based on the assumption that the sigtramp is placed directly under
290          * the location where the program arguments and environment can be
291          * found.  */
292         {
293                 int mib[2];
294                 long ps_strings;
295                 size_t len;
296
297                 mib[0] = CTL_KERN;
298                 mib[1] = KERN_PS_STRINGS;
299                 len = sizeof(ps_strings);
300                 if (sysctl(mib, 2, &ps_strings, &len, NULL, 0) == 0) {
301                         amd64dfly_sigtramp_start_addr = ps_strings - 32;
302                         amd64dfly_sigtramp_end_addr = ps_strings;
303                 }
304         }
305 }