xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/i386-netbsd-tdep.c (revision 32d1c65c71fbdb65a012e8392a62a757dd6853e9)
1 /* Target-dependent code for NetBSD/i386.
2 
3    Copyright (C) 1988-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 "regcache.h"
25 #include "regset.h"
26 #include "osabi.h"
27 #include "symtab.h"
28 #include "trad-frame.h"
29 #include "tramp-frame.h"
30 #include "frame-unwind.h"
31 
32 #include "i386-tdep.h"
33 #include "i387-tdep.h"
34 #include "netbsd-tdep.h"
35 #include "solib-svr4.h"
36 
37 /* From <machine/reg.h>.  */
38 static int i386nbsd_r_reg_offset[] =
39 {
40   0 * 4,			/* %eax */
41   1 * 4,			/* %ecx */
42   2 * 4,			/* %edx */
43   3 * 4,			/* %ebx */
44   4 * 4,			/* %esp */
45   5 * 4,			/* %ebp */
46   6 * 4,			/* %esi */
47   7 * 4,			/* %edi */
48   8 * 4,			/* %eip */
49   9 * 4,			/* %eflags */
50   10 * 4,			/* %cs */
51   11 * 4,			/* %ss */
52   12 * 4,			/* %ds */
53   13 * 4,			/* %es */
54   14 * 4,			/* %fs */
55   15 * 4			/* %gs */
56 };
57 
58 /* From <machine/signal.h>.  */
59 static int i386nbsd_sc_reg_offset[] =
60 {
61   10 * 4,			/* %eax */
62   9 * 4,			/* %ecx */
63   8 * 4,			/* %edx */
64   7 * 4,			/* %ebx */
65   14 * 4,			/* %esp */
66   6 * 4,			/* %ebp */
67   5 * 4,			/* %esi */
68   4 * 4,			/* %edi */
69   11 * 4,			/* %eip */
70   13 * 4,			/* %eflags */
71   12 * 4,			/* %cs */
72   15 * 4,			/* %ss */
73   3 * 4,			/* %ds */
74   2 * 4,			/* %es */
75   1 * 4,			/* %fs */
76   0 * 4				/* %gs */
77 };
78 
79 /* From <machine/mcontext.h>.  */
80 static int i386nbsd_mc_reg_offset[] =
81 {
82   11 * 4,			/* %eax */
83   10 * 4,			/* %ecx */
84   9 * 4,			/* %edx */
85   8 * 4,			/* %ebx */
86   7 * 4,			/* %esp */
87   6 * 4,			/* %ebp */
88   5 * 4,			/* %esi */
89   4 * 4,			/* %edi */
90   14 * 4,			/* %eip */
91   16 * 4,			/* %eflags */
92   15 * 4,			/* %cs */
93   18 * 4,			/* %ss */
94   3 * 4,			/* %ds */
95   2 * 4,			/* %es */
96   1 * 4,			/* %fs */
97   0 * 4				/* %gs */
98 };
99 
100 static void i386nbsd_sigtramp_cache_init (const struct tramp_frame *,
101 					  frame_info_ptr,
102 					  struct trad_frame_cache *,
103 					  CORE_ADDR);
104 
105 static const struct tramp_frame i386nbsd_sigtramp_sc16 =
106 {
107   SIGTRAMP_FRAME,
108   1,
109   {
110    /* leal  0x10(%esp), %eax */
111    { 0x8d, ULONGEST_MAX },
112    { 0x44, ULONGEST_MAX },
113    { 0x24, ULONGEST_MAX },
114    { 0x10, ULONGEST_MAX },
115 
116    /* pushl %eax */
117    { 0x50, ULONGEST_MAX },
118 
119    /* pushl %eax */
120    { 0x50, ULONGEST_MAX },
121 
122    /* movl  $0x127, %eax		# __sigreturn14 */
123    { 0xb8, ULONGEST_MAX },
124    { 0x27, ULONGEST_MAX },
125    {0x01, ULONGEST_MAX },
126    {0x00, ULONGEST_MAX },
127    {0x00, ULONGEST_MAX },
128 
129    /* int   $0x80 */
130    { 0xcd, ULONGEST_MAX },
131    { 0x80, ULONGEST_MAX},
132 
133    /* movl  $0x1, %eax		# exit */
134    { 0xb8, ULONGEST_MAX },
135    { 0x01, ULONGEST_MAX },
136    {0x00, ULONGEST_MAX },
137    {0x00, ULONGEST_MAX },
138    {0x00, ULONGEST_MAX },
139 
140    /* int   $0x80 */
141    { 0xcd, ULONGEST_MAX },
142    { 0x80, ULONGEST_MAX},
143 
144    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
145   },
146   i386nbsd_sigtramp_cache_init
147 };
148 
149 static const struct tramp_frame i386nbsd_sigtramp_sc2 =
150 {
151   SIGTRAMP_FRAME,
152   1,
153   {
154    /* leal  0x0c(%esp), %eax */
155    { 0x8d, ULONGEST_MAX },
156    { 0x44, ULONGEST_MAX },
157    { 0x24, ULONGEST_MAX },
158    { 0x0c, ULONGEST_MAX },
159    /* movl  %eax, 0x4(%esp) */
160    { 0x89, ULONGEST_MAX },
161    { 0x44, ULONGEST_MAX },
162    { 0x24, ULONGEST_MAX },
163    { 0x04, ULONGEST_MAX },
164    /* movl  $0x127, %eax		# __sigreturn14 */
165    { 0xb8, ULONGEST_MAX },
166    { 0x27, ULONGEST_MAX },
167    {0x01, ULONGEST_MAX },
168    {0x00, ULONGEST_MAX },
169    {0x00, ULONGEST_MAX },
170    /* int   $0x80 */
171    { 0xcd, ULONGEST_MAX },
172    { 0x80, ULONGEST_MAX},
173    /* movl  %eax, 0x4(%esp) */
174    { 0x89, ULONGEST_MAX },
175    { 0x44, ULONGEST_MAX },
176    { 0x24, ULONGEST_MAX },
177    { 0x04, ULONGEST_MAX },
178    /* movl  $0x1, %eax */
179    { 0xb8, ULONGEST_MAX },
180    { 0x01, ULONGEST_MAX },
181    {0x00, ULONGEST_MAX },
182    {0x00, ULONGEST_MAX },
183    {0x00, ULONGEST_MAX },
184    /* int   $0x80 */
185    { 0xcd, ULONGEST_MAX },
186    { 0x80, ULONGEST_MAX},
187    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
188   },
189   i386nbsd_sigtramp_cache_init
190 };
191 
192 static const struct tramp_frame i386nbsd_sigtramp_si2 =
193 {
194   SIGTRAMP_FRAME,
195   1,
196   {
197    /* movl  8(%esp),%eax */
198    { 0x8b, ULONGEST_MAX },
199    { 0x44, ULONGEST_MAX },
200    { 0x24, ULONGEST_MAX },
201    { 0x08, ULONGEST_MAX },
202    /* movl  %eax, 0x4(%esp) */
203    { 0x89, ULONGEST_MAX },
204    { 0x44, ULONGEST_MAX },
205    { 0x24, ULONGEST_MAX },
206    { 0x04, ULONGEST_MAX },
207    /* movl  $0x134, %eax            # setcontext */
208    { 0xb8, ULONGEST_MAX },
209    { 0x34, ULONGEST_MAX },
210    { 0x01, ULONGEST_MAX },
211    { 0x00, ULONGEST_MAX },
212    { 0x00, ULONGEST_MAX },
213    /* int   $0x80 */
214    { 0xcd, ULONGEST_MAX },
215    { 0x80, ULONGEST_MAX },
216    /* movl  %eax, 0x4(%esp) */
217    { 0x89, ULONGEST_MAX },
218    { 0x44, ULONGEST_MAX },
219    { 0x24, ULONGEST_MAX },
220    { 0x04, ULONGEST_MAX },
221    /* movl  $0x1, %eax */
222    { 0xb8, ULONGEST_MAX },
223    { 0x01, ULONGEST_MAX },
224    { 0x00, ULONGEST_MAX },
225    { 0x00, ULONGEST_MAX },
226    { 0x00, ULONGEST_MAX },
227    /* int   $0x80 */
228    { 0xcd, ULONGEST_MAX },
229    { 0x80, ULONGEST_MAX },
230    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
231   },
232   i386nbsd_sigtramp_cache_init
233 };
234 
235 static const struct tramp_frame i386nbsd_sigtramp_si31 =
236 {
237   SIGTRAMP_FRAME,
238   1,
239   {
240    /* leal  0x8c(%esp), %eax */
241    { 0x8d, ULONGEST_MAX },
242    { 0x84, ULONGEST_MAX },
243    { 0x24, ULONGEST_MAX },
244    { 0x8c, ULONGEST_MAX },
245    { 0x00, ULONGEST_MAX },
246    { 0x00, ULONGEST_MAX },
247    { 0x00, ULONGEST_MAX },
248    /* movl  %eax, 0x4(%esp) */
249    { 0x89, ULONGEST_MAX },
250    { 0x44, ULONGEST_MAX },
251    { 0x24, ULONGEST_MAX },
252    { 0x04, ULONGEST_MAX },
253    /* movl  $0x134, %eax            # setcontext */
254    { 0xb8, ULONGEST_MAX },
255    { 0x34, ULONGEST_MAX },
256    { 0x01, ULONGEST_MAX },
257    { 0x00, ULONGEST_MAX },
258    { 0x00, ULONGEST_MAX },
259    /* int   $0x80 */
260    { 0xcd, ULONGEST_MAX },
261    { 0x80, ULONGEST_MAX},
262    /* movl  %eax, 0x4(%esp) */
263    { 0x89, ULONGEST_MAX },
264    { 0x44, ULONGEST_MAX },
265    { 0x24, ULONGEST_MAX },
266    { 0x04, ULONGEST_MAX },
267    /* movl  $0x1, %eax */
268    { 0xb8, ULONGEST_MAX },
269    { 0x01, ULONGEST_MAX },
270    {0x00, ULONGEST_MAX },
271    {0x00, ULONGEST_MAX },
272    {0x00, ULONGEST_MAX },
273    /* int   $0x80 */
274    { 0xcd, ULONGEST_MAX },
275    { 0x80, ULONGEST_MAX},
276    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
277   },
278   i386nbsd_sigtramp_cache_init
279 };
280 
281 static const struct tramp_frame i386nbsd_sigtramp_si4 =
282 {
283   SIGTRAMP_FRAME,
284   1,
285   {
286    /* leal  0x8c(%esp), %eax */
287    { 0x8d, ULONGEST_MAX },
288    { 0x84, ULONGEST_MAX },
289    { 0x24, ULONGEST_MAX },
290    { 0x8c, ULONGEST_MAX },
291    { 0x00, ULONGEST_MAX },
292    { 0x00, ULONGEST_MAX },
293    { 0x00, ULONGEST_MAX },
294    /* movl  %eax, 0x4(%esp) */
295    { 0x89, ULONGEST_MAX },
296    { 0x44, ULONGEST_MAX },
297    { 0x24, ULONGEST_MAX },
298    { 0x04, ULONGEST_MAX },
299    /* movl  $0x134, %eax            # setcontext */
300    { 0xb8, ULONGEST_MAX },
301    { 0x34, ULONGEST_MAX },
302    { 0x01, ULONGEST_MAX },
303    { 0x00, ULONGEST_MAX },
304    { 0x00, ULONGEST_MAX },
305    /* int   $0x80 */
306    { 0xcd, ULONGEST_MAX },
307    { 0x80, ULONGEST_MAX},
308    /* movl   $0xffffffff,0x4(%esp) */
309    { 0xc7, ULONGEST_MAX },
310    { 0x44, ULONGEST_MAX },
311    { 0x24, ULONGEST_MAX },
312    { 0x04, ULONGEST_MAX },
313    { 0xff, ULONGEST_MAX },
314    { 0xff, ULONGEST_MAX },
315    { 0xff, ULONGEST_MAX },
316    { 0xff, ULONGEST_MAX },
317    /* movl  $0x1, %eax */
318    { 0xb8, ULONGEST_MAX },
319    { 0x01, ULONGEST_MAX },
320    {0x00, ULONGEST_MAX },
321    {0x00, ULONGEST_MAX },
322    {0x00, ULONGEST_MAX },
323    /* int   $0x80 */
324    { 0xcd, ULONGEST_MAX },
325    { 0x80, ULONGEST_MAX},
326    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
327   },
328   i386nbsd_sigtramp_cache_init
329 };
330 
331 static void
332 i386nbsd_sigtramp_cache_init (const struct tramp_frame *self,
333 			      frame_info_ptr this_frame,
334 			      struct trad_frame_cache *this_cache,
335 			      CORE_ADDR func)
336 {
337   struct gdbarch *gdbarch = get_frame_arch (this_frame);
338   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
339   CORE_ADDR sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
340   CORE_ADDR base;
341   int *reg_offset;
342   int num_regs;
343   int i;
344 
345   if (self == &i386nbsd_sigtramp_sc16 || self == &i386nbsd_sigtramp_sc2)
346     {
347       reg_offset = i386nbsd_sc_reg_offset;
348       num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset);
349 
350       /* Read in the sigcontext address.  */
351       base = read_memory_unsigned_integer (sp + 8, 4, byte_order);
352     }
353   else
354     {
355       reg_offset = i386nbsd_mc_reg_offset;
356       num_regs = ARRAY_SIZE (i386nbsd_mc_reg_offset);
357 
358       /* Read in the ucontext address.  */
359       base = read_memory_unsigned_integer (sp + 8, 4, byte_order);
360       /* offsetof(ucontext_t, uc_mcontext) == 36 */
361       base += 36;
362     }
363 
364   for (i = 0; i < num_regs; i++)
365     if (reg_offset[i] != -1)
366       trad_frame_set_reg_addr (this_cache, i, base + reg_offset[i]);
367 
368   /* Construct the frame ID using the function start.  */
369   trad_frame_set_id (this_cache, frame_id_build (sp, func));
370 }
371 
372 
373 /* From <machine/frame.h>.  Note that %esp and %ess are only saved in
374    a trap frame when entering the kernel from user space.  */
375 static int i386nbsd_tf_reg_offset[] =
376 {
377   10 * 4,			/* %eax */
378    9 * 4,			/* %ecx */
379    8 * 4,			/* %edx */
380    7 * 4,			/* %ebx */
381   -1,				/* %esp */
382    6 * 4,			/* %ebp */
383    5 * 4,			/* %esi */
384    4 * 4,			/* %edi */
385   13 * 4,			/* %eip */
386   15 * 4,			/* %eflags */
387   14 * 4,			/* %cs */
388   -1,				/* %ss */
389    3 * 4,			/* %ds */
390    2 * 4,			/* %es */
391    1 * 4,			/* %fs */
392    0 * 4			/* %gs */
393 };
394 
395 static struct trad_frame_cache *
396 i386nbsd_trapframe_cache(frame_info_ptr this_frame, void **this_cache)
397 {
398   struct trad_frame_cache *cache;
399   CORE_ADDR func, sp, addr, tmp;
400   ULONGEST cs;
401   const char *name;
402   int i;
403   struct gdbarch *gdbarch = get_frame_arch (this_frame);
404   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
405 
406   if (*this_cache)
407     return (struct trad_frame_cache *)*this_cache;
408 
409   cache = trad_frame_cache_zalloc (this_frame);
410   *this_cache = cache;
411 
412   func = get_frame_func (this_frame);
413   sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
414 
415   find_pc_partial_function (func, &name, NULL, NULL);
416   if (name && (strncmp (name, "Xintr", 5) == 0 ||
417                strncmp (name, "Xhandle", 7) == 0))
418     {
419       /* It's an interrupt frame. */
420       tmp = read_memory_unsigned_integer (sp + 4, 4, byte_order);
421       if (tmp < 15)
422         {
423           /* Reasonable value for 'ppl': already on interrupt stack. */
424           addr = sp + 8;
425         }
426       else
427         {
428           /* Switch to previous stack. */
429           addr = tmp + 4;
430         }
431     }
432   else
433     {
434       /* It's a trap frame. */
435       addr = sp + 4;
436     }
437 
438   for (i = 0; i < ARRAY_SIZE (i386nbsd_tf_reg_offset); i++)
439     if (i386nbsd_tf_reg_offset[i] != -1)
440       trad_frame_set_reg_addr (cache, i, addr + i386nbsd_tf_reg_offset[i]);
441 
442   /* Read %cs from trap frame.  */
443   addr += i386nbsd_tf_reg_offset[I386_CS_REGNUM];
444   cs = read_memory_unsigned_integer (addr, 4, byte_order);
445   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
446     {
447       /* Trap from user space; terminate backtrace.  */
448       trad_frame_set_id (cache, outer_frame_id);
449     }
450   else
451     {
452       /* Construct the frame ID using the function start.  */
453       trad_frame_set_id (cache, frame_id_build (sp + 8, func));
454     }
455 
456   return cache;
457 }
458 
459 static void
460 i386nbsd_trapframe_this_id (frame_info_ptr this_frame,
461 			    void **this_cache, struct frame_id *this_id)
462 {
463   struct trad_frame_cache *cache =
464     i386nbsd_trapframe_cache (this_frame, this_cache);
465 
466   trad_frame_get_id (cache, this_id);
467 }
468 
469 static struct value *
470 i386nbsd_trapframe_prev_register (frame_info_ptr this_frame,
471 				  void **this_cache, int regnum)
472 {
473   struct trad_frame_cache *cache =
474     i386nbsd_trapframe_cache (this_frame, this_cache);
475 
476   return trad_frame_get_register (cache, this_frame, regnum);
477 }
478 
479 static int
480 i386nbsd_trapframe_sniffer (const struct frame_unwind *self,
481 			    frame_info_ptr this_frame,
482 			    void **this_prologue_cache)
483 {
484   ULONGEST cs;
485   const char *name;
486 
487   /* Check Current Privilege Level and bail out if we're not executing
488      in kernel space.  */
489   cs = get_frame_register_unsigned (this_frame, I386_CS_REGNUM);
490   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
491     return 0;
492 
493 
494   find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
495   return (name && ((strcmp (name, "alltraps") == 0)
496 	        || (strcmp (name, "calltrap") == 0)
497 		|| (strcmp (name, "syscall1") == 0)
498 		|| (strcmp (name, "Xdoreti") == 0)
499 		|| (strncmp (name, "Xintr", 5) == 0)
500 		|| (strncmp (name, "Xhandle", 7) == 0)
501 		|| (strncmp (name, "Xpreempt", 8) == 0)
502 		|| (strncmp (name, "Xrecurse", 8) == 0)
503 		|| (strncmp (name, "Xresume", 7) == 0)
504 		|| (strncmp (name, "Xsoft", 5) == 0)
505 		|| (strncmp (name, "Xstray", 6) == 0)
506 		|| (strncmp (name, "Xsyscall", 8) == 0)
507 		|| (strncmp (name, "Xtrap", 5) == 0)
508 	    ));
509 }
510 
511 const struct frame_unwind i386nbsd_trapframe_unwind = {
512   /* FIXME: kettenis/20051219: This really is more like an interrupt
513      frame, but SIGTRAMP_FRAME would print <signal handler called>,
514      which really is not what we want here.  */
515   "i386 trapframe",
516   NORMAL_FRAME,
517   default_frame_unwind_stop_reason,
518   i386nbsd_trapframe_this_id,
519   i386nbsd_trapframe_prev_register,
520   NULL,
521   i386nbsd_trapframe_sniffer
522 };
523 
524 static void
525 i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
526 {
527   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
528 
529   /* Obviously NetBSD is BSD-based.  */
530   i386bsd_init_abi (info, gdbarch);
531 
532   nbsd_init_abi (info, gdbarch);
533 
534   /* NetBSD has a different `struct reg'.  */
535   tdep->gregset_reg_offset = i386nbsd_r_reg_offset;
536   tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset);
537   tdep->sizeof_gregset = 16 * 4;
538 
539   /* NetBSD uses -freg-struct-return by default.  */
540   tdep->struct_return = reg_struct_return;
541 
542   /* NetBSD uses tramp_frame sniffers for signal trampolines.  */
543   tdep->sigcontext_addr= 0;
544   tdep->sigtramp_start = 0;
545   tdep->sigtramp_end = 0;
546   tdep->sigtramp_p = 0;
547   tdep->sc_reg_offset = 0;
548   tdep->sc_num_regs = 0;
549 
550   tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc16);
551   tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc2);
552   tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si2);
553   tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si31);
554   tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si4);
555 
556   /* Unwind kernel trap frames correctly.  */
557   frame_unwind_prepend_unwinder (gdbarch, &i386nbsd_trapframe_unwind);
558 }
559 
560 /* NetBSD ELF.  */
561 
562 static void
563 i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
564 {
565   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
566 
567   /* It's still NetBSD.  */
568   i386nbsd_init_abi (info, gdbarch);
569 
570   /* But ELF-based.  */
571   i386_elf_init_abi (info, gdbarch);
572 
573   /* NetBSD ELF uses SVR4-style shared libraries.  */
574   set_solib_svr4_fetch_link_map_offsets
575     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
576 
577   /* NetBSD ELF uses -fpcc-struct-return by default.  */
578   tdep->struct_return = pcc_struct_return;
579 }
580 
581 void _initialize_i386nbsd_tdep ();
582 void
583 _initialize_i386nbsd_tdep ()
584 {
585   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD,
586 			  i386nbsdelf_init_abi);
587 }
588