xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/amd64-fbsd-nat.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /* Native-dependent code for FreeBSD/amd64.
2 
3    Copyright (C) 2003-2020 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 
25 #include <signal.h>
26 #include <sys/types.h>
27 #include <sys/ptrace.h>
28 #include <sys/sysctl.h>
29 #include <sys/user.h>
30 #include <machine/reg.h>
31 
32 #include "fbsd-nat.h"
33 #include "amd64-tdep.h"
34 #include "amd64-nat.h"
35 #include "amd64-bsd-nat.h"
36 #include "x86-nat.h"
37 #include "gdbsupport/x86-xstate.h"
38 
39 
40 class amd64_fbsd_nat_target final
41   : public amd64_bsd_nat_target<fbsd_nat_target>
42 {
43 public:
44   /* Add some extra features to the common *BSD/amd64 target.  */
45   const struct target_desc *read_description () override;
46 
47 #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO)
48   bool supports_stopped_by_hw_breakpoint () override;
49 #endif
50 };
51 
52 static amd64_fbsd_nat_target the_amd64_fbsd_nat_target;
53 
54 /* Offset in `struct reg' where MEMBER is stored.  */
55 #define REG_OFFSET(member) offsetof (struct reg, member)
56 
57 /* At amd64fbsd64_r_reg_offset[REGNUM] you'll find the offset in
58    `struct reg' location where the GDB register REGNUM is stored.
59    Unsupported registers are marked with `-1'.  */
60 static int amd64fbsd64_r_reg_offset[] =
61 {
62   REG_OFFSET (r_rax),
63   REG_OFFSET (r_rbx),
64   REG_OFFSET (r_rcx),
65   REG_OFFSET (r_rdx),
66   REG_OFFSET (r_rsi),
67   REG_OFFSET (r_rdi),
68   REG_OFFSET (r_rbp),
69   REG_OFFSET (r_rsp),
70   REG_OFFSET (r_r8),
71   REG_OFFSET (r_r9),
72   REG_OFFSET (r_r10),
73   REG_OFFSET (r_r11),
74   REG_OFFSET (r_r12),
75   REG_OFFSET (r_r13),
76   REG_OFFSET (r_r14),
77   REG_OFFSET (r_r15),
78   REG_OFFSET (r_rip),
79   REG_OFFSET (r_rflags),
80   REG_OFFSET (r_cs),
81   REG_OFFSET (r_ss),
82   -1,
83   -1,
84   -1,
85   -1
86 };
87 
88 
89 /* Mapping between the general-purpose registers in FreeBSD/amd64
90    `struct reg' format and GDB's register cache layout for
91    FreeBSD/i386.
92 
93    Note that most FreeBSD/amd64 registers are 64-bit, while the
94    FreeBSD/i386 registers are all 32-bit, but since we're
95    little-endian we get away with that.  */
96 
97 /* From <machine/reg.h>.  */
98 static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
99 {
100   14 * 8, 13 * 8,		/* %eax, %ecx */
101   12 * 8, 11 * 8,		/* %edx, %ebx */
102   20 * 8, 10 * 8,		/* %esp, %ebp */
103   9 * 8, 8 * 8,			/* %esi, %edi */
104   17 * 8, 19 * 8,		/* %eip, %eflags */
105   18 * 8, 21 * 8,		/* %cs, %ss */
106   -1, -1, -1, -1		/* %ds, %es, %fs, %gs */
107 };
108 
109 
110 /* Support for debugging kernel virtual memory images.  */
111 
112 #include <machine/pcb.h>
113 #include <osreldate.h>
114 
115 #include "bsd-kvm.h"
116 
117 static int
118 amd64fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
119 {
120   /* The following is true for FreeBSD 5.2:
121 
122      The pcb contains %rip, %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15,
123      %ds, %es, %fs and %gs.  This accounts for all callee-saved
124      registers specified by the psABI and then some.  Here %esp
125      contains the stack pointer at the point just after the call to
126      cpu_switch().  From this information we reconstruct the register
127      state as it would like when we just returned from cpu_switch().  */
128 
129   /* The stack pointer shouldn't be zero.  */
130   if (pcb->pcb_rsp == 0)
131     return 0;
132 
133   pcb->pcb_rsp += 8;
134   regcache->raw_supply (AMD64_RIP_REGNUM, &pcb->pcb_rip);
135   regcache->raw_supply (AMD64_RBX_REGNUM, &pcb->pcb_rbx);
136   regcache->raw_supply (AMD64_RSP_REGNUM, &pcb->pcb_rsp);
137   regcache->raw_supply (AMD64_RBP_REGNUM, &pcb->pcb_rbp);
138   regcache->raw_supply (12, &pcb->pcb_r12);
139   regcache->raw_supply (13, &pcb->pcb_r13);
140   regcache->raw_supply (14, &pcb->pcb_r14);
141   regcache->raw_supply (15, &pcb->pcb_r15);
142 #if (__FreeBSD_version < 800075) && (__FreeBSD_kernel_version < 800075)
143   /* struct pcb provides the pcb_ds/pcb_es/pcb_fs/pcb_gs fields only
144      up until __FreeBSD_version 800074: The removal of these fields
145      occurred on 2009-04-01 while the __FreeBSD_version number was
146      bumped to 800075 on 2009-04-06.  So 800075 is the closest version
147      number where we should not try to access these fields.  */
148   regcache->raw_supply (AMD64_DS_REGNUM, &pcb->pcb_ds);
149   regcache->raw_supply (AMD64_ES_REGNUM, &pcb->pcb_es);
150   regcache->raw_supply (AMD64_FS_REGNUM, &pcb->pcb_fs);
151   regcache->raw_supply (AMD64_GS_REGNUM, &pcb->pcb_gs);
152 #endif
153 
154   return 1;
155 }
156 
157 
158 /* Implement the read_description method.  */
159 
160 const struct target_desc *
161 amd64_fbsd_nat_target::read_description ()
162 {
163 #ifdef PT_GETXSTATE_INFO
164   static int xsave_probed;
165   static uint64_t xcr0;
166 #endif
167   struct reg regs;
168   int is64;
169 
170   if (ptrace (PT_GETREGS, inferior_ptid.pid (),
171 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
172     perror_with_name (_("Couldn't get registers"));
173   is64 = (regs.r_cs == GSEL (GUCODE_SEL, SEL_UPL));
174 #ifdef PT_GETXSTATE_INFO
175   if (!xsave_probed)
176     {
177       struct ptrace_xstate_info info;
178 
179       if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (),
180 		  (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
181 	{
182 	  x86bsd_xsave_len = info.xsave_len;
183 	  xcr0 = info.xsave_mask;
184 	}
185       xsave_probed = 1;
186     }
187 
188   if (x86bsd_xsave_len != 0)
189     {
190       if (is64)
191 	return amd64_target_description (xcr0, true);
192       else
193 	return i386_target_description (xcr0, true);
194     }
195 #endif
196   if (is64)
197     return amd64_target_description (X86_XSTATE_SSE_MASK, true);
198   else
199     return i386_target_description (X86_XSTATE_SSE_MASK, true);
200 }
201 
202 #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO)
203 /* Implement the supports_stopped_by_hw_breakpoints method.  */
204 
205 bool
206 amd64_fbsd_nat_target::supports_stopped_by_hw_breakpoint ()
207 {
208   return true;
209 }
210 #endif
211 
212 void _initialize_amd64fbsd_nat ();
213 void
214 _initialize_amd64fbsd_nat ()
215 {
216   int offset;
217 
218   amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
219   amd64_native_gregset64_reg_offset = amd64fbsd64_r_reg_offset;
220 
221   add_inf_child_target (&the_amd64_fbsd_nat_target);
222 
223   /* Support debugging kernel virtual memory images.  */
224   bsd_kvm_add_target (amd64fbsd_supply_pcb);
225 
226   /* To support the recognition of signal handlers, i386-bsd-tdep.c
227      hardcodes some constants.  Inclusion of this file means that we
228      are compiling a native debugger, which means that we can use the
229      system header files and sysctl(3) to get at the relevant
230      information.  */
231 
232 #define SC_REG_OFFSET amd64fbsd_sc_reg_offset
233 
234   /* We only check the program counter, stack pointer and frame
235      pointer since these members of `struct sigcontext' are essential
236      for providing backtraces.  */
237 
238 #define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
239 #define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
240 #define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
241 
242   /* Override the default value for the offset of the program counter
243      in the sigcontext structure.  */
244   offset = offsetof (struct sigcontext, sc_rip);
245 
246   if (SC_RIP_OFFSET != offset)
247     {
248       warning (_("\
249 offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
250 Please report this to <bug-gdb@gnu.org>."),
251 	       offset, SC_RIP_OFFSET);
252     }
253 
254   SC_RIP_OFFSET = offset;
255 
256   /* Likewise for the stack pointer.  */
257   offset = offsetof (struct sigcontext, sc_rsp);
258 
259   if (SC_RSP_OFFSET != offset)
260     {
261       warning (_("\
262 offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
263 Please report this to <bug-gdb@gnu.org>."),
264 	       offset, SC_RSP_OFFSET);
265     }
266 
267   SC_RSP_OFFSET = offset;
268 
269   /* And the frame pointer.  */
270   offset = offsetof (struct sigcontext, sc_rbp);
271 
272   if (SC_RBP_OFFSET != offset)
273     {
274       warning (_("\
275 offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
276 Please report this to <bug-gdb@gnu.org>."),
277 	       offset, SC_RBP_OFFSET);
278     }
279 
280   SC_RBP_OFFSET = offset;
281 
282 #ifdef KERN_PROC_SIGTRAMP
283   /* Normally signal frames are detected via amd64fbsd_sigtramp_p.
284      However, FreeBSD 9.2 through 10.1 do not include the page holding
285      the signal code in core dumps.  These releases do provide a
286      kern.proc.sigtramp.<pid> sysctl that returns the location of the
287      signal trampoline for a running process.  We fetch the location
288      of the current (gdb) process and use this to identify signal
289      frames in core dumps from these releases.  Note that this only
290      works for core dumps of 64-bit (FreeBSD/amd64) processes and does
291      not handle core dumps of 32-bit (FreeBSD/i386) processes.  */
292   {
293     int mib[4];
294     struct kinfo_sigtramp kst;
295     size_t len;
296 
297     mib[0] = CTL_KERN;
298     mib[1] = KERN_PROC;
299     mib[2] = KERN_PROC_SIGTRAMP;
300     mib[3] = getpid ();
301     len = sizeof (kst);
302     if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0)
303       {
304 	amd64fbsd_sigtramp_start_addr = (uintptr_t) kst.ksigtramp_start;
305 	amd64fbsd_sigtramp_end_addr = (uintptr_t) kst.ksigtramp_end;
306       }
307   }
308 #endif
309 }
310