FreeBSD x86: Remove fallback for detecting signal trampolines by address.
[binutils-gdb.git] / gdb / amd64-fbsd-nat.c
1 /* Native-dependent code for FreeBSD/amd64.
2
3 Copyright (C) 2003-2022 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 \f
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 \f
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 \f
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 \f
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 }