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