xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/amd64-netbsd-tdep.c (revision 32d1c65c71fbdb65a012e8392a62a757dd6853e9)
1 /* Target-dependent code for NetBSD/amd64.
2 
3    Copyright (C) 2003-2023 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 "arch-utils.h"
22 #include "frame.h"
23 #include "gdbcore.h"
24 #include "osabi.h"
25 #include "symtab.h"
26 
27 #include "amd64-tdep.h"
28 #include "gdbsupport/x86-xstate.h"
29 #include "netbsd-tdep.h"
30 #include "solib-svr4.h"
31 #include "trad-frame.h"
32 #include "frame-unwind.h"
33 
34 /* Support for signal handlers.  */
35 
36 /* Return whether THIS_FRAME corresponds to a NetBSD sigtramp
37    routine.  */
38 
39 static int
40 amd64nbsd_sigtramp_p (frame_info_ptr this_frame)
41 {
42   CORE_ADDR pc = get_frame_pc (this_frame);
43   const char *name;
44 
45   find_pc_partial_function (pc, &name, NULL, NULL);
46   return nbsd_pc_in_sigtramp (pc, name);
47 }
48 
49 /* Assuming THIS_FRAME corresponds to a NetBSD sigtramp routine,
50    return the address of the associated mcontext structure.  */
51 
52 static CORE_ADDR
53 amd64nbsd_mcontext_addr (frame_info_ptr this_frame)
54 {
55   CORE_ADDR addr;
56 
57   /* The register %r15 points at `struct ucontext' upon entry of a
58      signal trampoline.  */
59   addr = get_frame_register_unsigned (this_frame, AMD64_R15_REGNUM);
60 
61   /* The mcontext structure lives as offset 56 in `struct ucontext'.  */
62   return addr + 56;
63 }
64 
65 /* NetBSD 2.0 or later.  */
66 
67 /* Mapping between the general-purpose registers in `struct reg'
68    format and GDB's register cache layout.  */
69 
70 /* From <machine/reg.h>.  */
71 int amd64nbsd_r_reg_offset[] =
72 {
73   14 * 8,			/* %rax */
74   13 * 8,			/* %rbx */
75   3 * 8,			/* %rcx */
76   2 * 8,			/* %rdx */
77   1 * 8,			/* %rsi */
78   0 * 8,			/* %rdi */
79   12 * 8,			/* %rbp */
80   24 * 8,			/* %rsp */
81   4 * 8,			/* %r8 ..  */
82   5 * 8,
83   6 * 8,
84   7 * 8,
85   8 * 8,
86   9 * 8,
87   10 * 8,
88   11 * 8,			/* ... %r15 */
89   21 * 8,			/* %rip */
90   23 * 8,			/* %eflags */
91   22 * 8,			/* %cs */
92   25 * 8,			/* %ss */
93   18 * 8,			/* %ds */
94   17 * 8,			/* %es */
95   16 * 8,			/* %fs */
96   15 * 8			/* %gs */
97 };
98 
99 /* Kernel debugging support */
100 static const int amd64nbsd_tf_reg_offset[] =
101 {
102   18 * 8,			/* %rax */
103   17 * 8,			/* %rbx */
104   10 * 8,			/* %rcx */
105   2 * 8,			/* %rdx */
106   1 * 8,			/* %rsi */
107   0 * 8,			/* %rdi */
108   16 * 8,			/* %rbp */
109   28 * 8,			/* %rsp */
110   4 * 8,			/* %r8 .. */
111   5 * 8,
112   3 * 8,
113   11 * 8,
114   12 * 8,
115   13 * 8,
116   14 * 8,
117   15 * 8,			/* ... %r15 */
118   25 * 8,			/* %rip */
119   27 * 8,			/* %eflags */
120   26 * 8,			/* %cs */
121   29 * 8,			/* %ss */
122   22 * 8,			/* %ds */
123   21 * 8,			/* %es */
124   20 * 8,			/* %fs */
125   19 * 8,			/* %gs */
126 };
127 
128 static struct trad_frame_cache *
129 amd64nbsd_trapframe_cache(frame_info_ptr this_frame, void **this_cache)
130 {
131   struct trad_frame_cache *cache;
132   CORE_ADDR func, sp, addr;
133   ULONGEST cs = 0, rip = 0;
134   const char *name;
135   int i;
136   struct gdbarch *gdbarch = get_frame_arch (this_frame);
137   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
138 
139   if (*this_cache)
140     return (struct trad_frame_cache *)*this_cache;
141 
142   cache = trad_frame_cache_zalloc (this_frame);
143   *this_cache = cache;
144 
145   func = get_frame_func (this_frame);
146   sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
147 
148   find_pc_partial_function (func, &name, NULL, NULL);
149 
150   /* There is an extra 'call' in the interrupt sequence - ignore the extra
151    * return address */
152 
153   addr = sp;
154   if (name) {
155 	if (strncmp (name, "Xintr", 5) == 0
156 	 || strncmp (name, "Xhandle", 7) == 0) {
157 		addr += 8;		/* It's an interrupt frame.  */
158 	}
159   }
160 
161 #ifdef DEBUG_TRAPFRAME
162   for (i = 0; i < 50; i++) {
163     cs = read_memory_unsigned_integer (addr + i * 8, 8, byte_order);
164     printf("%s i=%d r=%#jx\n", name, i, (intmax_t)cs);
165   }
166 #endif
167 
168   for (i = 0; i < ARRAY_SIZE (amd64nbsd_tf_reg_offset); i++)
169     if (amd64nbsd_tf_reg_offset[i] != -1)
170       trad_frame_set_reg_addr (cache, i, addr + amd64nbsd_tf_reg_offset[i]);
171 
172   /* Read %cs and %rip when we have the addresses to hand */
173   cs = read_memory_unsigned_integer (addr
174     + amd64nbsd_tf_reg_offset[AMD64_CS_REGNUM], 8, byte_order);
175   rip = read_memory_unsigned_integer (addr
176     + amd64nbsd_tf_reg_offset[AMD64_RIP_REGNUM], 8, byte_order);
177 
178 #ifdef DEBUG_TRAPFRAME
179   printf("%s cs=%#jx rip=%#jx\n", name, (intmax_t)cs, (intmax_t)rip);
180 #endif
181 
182   /* The trap frame layout was changed lf the %rip value is less than 2^16 it
183    * is almost certainly the %ss of the old format. */
184   if (rip < (1 << 16))
185     {
186 
187       for (i = 0; i < ARRAY_SIZE (amd64nbsd_tf_reg_offset); i++)
188         {
189 
190           if (amd64nbsd_tf_reg_offset[i] == -1)
191             continue;
192 
193           trad_frame_set_reg_addr (cache, i, addr + amd64nbsd_r_reg_offset[i]);
194 
195           /* Read %cs when we have the address to hand */
196           if (i == AMD64_CS_REGNUM)
197 	    cs = read_memory_unsigned_integer (addr + amd64nbsd_r_reg_offset[i],
198 	    8, byte_order);
199         }
200     }
201 
202   if ((cs & I386_SEL_RPL) == I386_SEL_UPL ||
203 	(name && strncmp(name, "Xsoft", 5) == 0))
204     {
205       /* Trap from user space or soft interrupt; terminate backtrace.  */
206       trad_frame_set_id (cache, outer_frame_id);
207     }
208   else
209     {
210       /* Construct the frame ID using the function start.  */
211       trad_frame_set_id (cache, frame_id_build (sp + 16, func));
212     }
213 
214   return cache;
215 }
216 
217 static void
218 amd64nbsd_trapframe_this_id (frame_info_ptr this_frame,
219 			     void **this_cache,
220 			     struct frame_id *this_id)
221 {
222   struct trad_frame_cache *cache =
223     amd64nbsd_trapframe_cache (this_frame, this_cache);
224 
225   trad_frame_get_id (cache, this_id);
226 }
227 
228 static struct value *
229 amd64nbsd_trapframe_prev_register (frame_info_ptr this_frame,
230 				   void **this_cache, int regnum)
231 {
232   struct trad_frame_cache *cache =
233     amd64nbsd_trapframe_cache (this_frame, this_cache);
234 
235   return trad_frame_get_register (cache, this_frame, regnum);
236 }
237 
238 static int
239 amd64nbsd_trapframe_sniffer (const struct frame_unwind *self,
240 			     frame_info_ptr this_frame,
241 			     void **this_prologue_cache)
242 {
243   ULONGEST cs = 0;
244   const char *name;
245 
246   try
247     {
248       cs = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
249     }
250   catch (const gdb_exception &except)
251     {
252       if (except.reason < 0 && except.error != NOT_AVAILABLE_ERROR)
253 	throw;
254     }
255   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
256     return 0;
257 
258   find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
259   return (name && ((strcmp (name, "alltraps") == 0)
260 	        || (strcmp (name, "calltrap") == 0)
261 	        || (strcmp (name, "handle_syscall") == 0)
262 		|| (strcmp (name, "Xdoreti") == 0)
263 		|| (strcmp (name, "Xspllower") == 0)
264 		|| (strncmp (name, "Xhandle", 7) == 0)
265 		|| (strncmp (name, "Xintr", 5) == 0)
266 		|| (strncmp (name, "Xpreempt", 8) == 0)
267 		|| (strncmp (name, "Xrecurse", 8) == 0)
268 		|| (strncmp (name, "Xresume", 7) == 0)
269 		|| (strncmp (name, "Xsoft", 5) == 0)
270 		|| (strncmp (name, "Xstray", 6) == 0)
271 		|| (strncmp (name, "Xsyscall", 8) == 0)
272 		|| (strncmp (name, "Xtrap", 5) == 0)
273 	    ));
274 }
275 
276 static const struct frame_unwind amd64nbsd_trapframe_unwind = {
277   /* FIXME: kettenis/20051219: This really is more like an interrupt
278      frame, but SIGTRAMP_FRAME would print <signal handler called>,
279      which really is not what we want here.  */
280   "amd64 trapframe",
281   NORMAL_FRAME,
282   default_frame_unwind_stop_reason,
283   amd64nbsd_trapframe_this_id,
284   amd64nbsd_trapframe_prev_register,
285   NULL,
286   amd64nbsd_trapframe_sniffer
287 };
288 
289 static void
290 amd64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
291 {
292   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
293 
294   /* Initialize general-purpose register set details first.  */
295   tdep->gregset_reg_offset = amd64nbsd_r_reg_offset;
296   tdep->gregset_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
297   tdep->sizeof_gregset = 26 * 8;
298 
299   amd64_init_abi (info, gdbarch,
300 		  amd64_target_description (X86_XSTATE_SSE_MASK, true));
301   nbsd_init_abi (info, gdbarch);
302 
303   tdep->jb_pc_offset = 7 * 8;
304 
305   /* NetBSD has its own convention for signal trampolines.  */
306   tdep->sigtramp_p = amd64nbsd_sigtramp_p;
307   tdep->sigcontext_addr = amd64nbsd_mcontext_addr;
308   tdep->sc_reg_offset = amd64nbsd_r_reg_offset;
309   tdep->sc_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
310 
311   /* NetBSD uses SVR4-style shared libraries.  */
312   set_solib_svr4_fetch_link_map_offsets
313     (gdbarch, svr4_lp64_fetch_link_map_offsets);
314   /* Unwind kernel trap frames correctly.  */
315   frame_unwind_prepend_unwinder (gdbarch, &amd64nbsd_trapframe_unwind);
316 }
317 
318 void _initialize_amd64nbsd_tdep ();
319 void
320 _initialize_amd64nbsd_tdep ()
321 {
322   /* The NetBSD/amd64 native dependent code makes this assumption.  */
323   gdb_assert (ARRAY_SIZE (amd64nbsd_r_reg_offset) == AMD64_NUM_GREGS);
324 
325   gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
326 			  GDB_OSABI_NETBSD, amd64nbsd_init_abi);
327 }
328