1 /* Target-dependent code for NetBSD/i386.
3 Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
5 Free Software Foundation, Inc.
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
25 #include "arch-utils.h"
33 #include "gdb_assert.h"
34 #include "gdb_string.h"
36 #include "i386-tdep.h"
37 #include "i387-tdep.h"
38 #include "nbsd-tdep.h"
39 #include "solib-svr4.h"
40 #include "elf-bfd.h" /* for header hack */
41 #include "trad-frame.h" /* signal trampoline/kernel frame support */
42 #include "frame-unwind.h" /* kernel frame support */
43 #include "tramp-frame.h" /* signal trampoline/kernel frame support
45 /* From <machine/reg.h>. */
46 static int i386nbsd_r_reg_offset
[] =
67 i386nbsd_aout_supply_regset (const struct regset
*regset
,
68 struct regcache
*regcache
, int regnum
,
69 const void *regs
, size_t len
)
71 const struct gdbarch_tdep
*tdep
= gdbarch_tdep (regset
->arch
);
73 gdb_assert (len
>= tdep
->sizeof_gregset
+ I387_SIZEOF_FSAVE
);
75 i386_supply_gregset (regset
, regcache
, regnum
, regs
, tdep
->sizeof_gregset
);
76 i387_supply_fsave (regcache
, regnum
, (char *) regs
+ tdep
->sizeof_gregset
);
79 static const struct regset
*
80 i386nbsd_aout_regset_from_core_section (struct gdbarch
*gdbarch
,
81 const char *sect_name
,
84 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
86 /* NetBSD a.out core dumps don't use seperate register sets for the
87 general-purpose and floating-point registers. */
89 if (strcmp (sect_name
, ".reg") == 0
90 && sect_size
>= tdep
->sizeof_gregset
+ I387_SIZEOF_FSAVE
)
92 if (tdep
->gregset
== NULL
)
94 regset_alloc (gdbarch
, i386nbsd_aout_supply_regset
, NULL
);
101 /* From <machine/signal.h>. */
102 int i386nbsd_sc_reg_offset
[] =
113 13 * 4, /* %eflags */
122 /* From <machine/mcontext.h>. */
123 int i386nbsd_mc_reg_offset
[] =
134 16 * 4, /* %eflags */
144 i386nbsd_sigtramp_cache_init (const struct tramp_frame
*,
146 struct trad_frame_cache
*,
149 static const struct tramp_frame i386nbsd_sigtramp_sc16
=
154 { 0x8d, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x10, -1 },
155 /* leal 0x10(%esp), %eax */
156 { 0x50, -1 }, /* pushl %eax */
157 { 0x50, -1 }, /* pushl %eax */
158 { 0xb8, -1 }, { 0x27, -1 }, {0x01, -1 }, {0x00, -1 }, {0x00, -1 },
159 /* movl $0x127, %eax # __sigreturn14 */
160 { 0xcd, -1 }, { 0x80, -1},
162 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
163 /* movl $0x1, %eax # exit */
164 { 0xcd, -1 }, { 0x80, -1},
166 { TRAMP_SENTINEL_INSN
, -1 }
168 i386nbsd_sigtramp_cache_init
171 static const struct tramp_frame i386nbsd_sigtramp_sc2
=
176 { 0x8d, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x0c, -1 },
177 /* leal 0x0c(%esp), %eax */
178 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
179 /* movl %eax, 0x4(%esp) */
180 { 0xb8, -1 }, { 0x27, -1 }, {0x01, -1 }, {0x00, -1 }, {0x00, -1 },
181 /* movl $0x127, %eax # __sigreturn14 */
182 { 0xcd, -1 }, { 0x80, -1},
184 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
185 /* movl %eax, 0x4(%esp) */
186 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
187 /* movl $0x1, %eax */
188 { 0xcd, -1 }, { 0x80, -1},
190 { TRAMP_SENTINEL_INSN
, -1 }
192 i386nbsd_sigtramp_cache_init
195 static const struct tramp_frame i386nbsd_sigtramp_si2
=
200 { 0x8b, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x08, -1 },
201 /* movl 8(%esp),%eax */
202 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
203 /* movl %eax, 0x4(%esp) */
204 { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 },
205 /* movl $0x134, %eax # setcontext */
206 { 0xcd, -1 }, { 0x80, -1 },
208 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
209 /* movl %eax, 0x4(%esp) */
210 { 0xb8, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 },
211 /* movl $0x1, %eax */
212 { 0xcd, -1 }, { 0x80, -1 },
214 { TRAMP_SENTINEL_INSN
, -1 }
216 i386nbsd_sigtramp_cache_init
219 static const struct tramp_frame i386nbsd_sigtramp_si31
=
224 { 0x8d, -1 }, { 0x84, -1 }, { 0x24, -1 },
225 { 0x8c, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 },
226 /* leal 0x8c(%esp), %eax */
227 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
228 /* movl %eax, 0x4(%esp) */
229 { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 },
230 /* movl $0x134, %eax # setcontext */
231 { 0xcd, -1 }, { 0x80, -1},
233 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
234 /* movl %eax, 0x4(%esp) */
235 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
236 /* movl $0x1, %eax */
237 { 0xcd, -1 }, { 0x80, -1},
239 { TRAMP_SENTINEL_INSN
, -1 }
241 i386nbsd_sigtramp_cache_init
244 static const struct tramp_frame i386nbsd_sigtramp_si4
=
249 { 0x8d, -1 }, { 0x84, -1 }, { 0x24, -1 },
250 { 0x8c, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 },
251 /* leal 0x8c(%esp), %eax */
252 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
253 /* movl %eax, 0x4(%esp) */
254 { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 },
255 /* movl $0x134, %eax # setcontext */
256 { 0xcd, -1 }, { 0x80, -1},
258 { 0xc7, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
259 { 0xff, -1 }, { 0xff, -1 }, { 0xff, -1 }, { 0xff, -1 },
260 /* movl $0xffffffff,0x4(%esp) */
261 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
262 /* movl $0x1, %eax */
263 { 0xcd, -1 }, { 0x80, -1},
265 { TRAMP_SENTINEL_INSN
, -1 }
267 i386nbsd_sigtramp_cache_init
272 i386nbsd_sigtramp_cache_init (const struct tramp_frame
*self
,
273 struct frame_info
*next_frame
,
274 struct trad_frame_cache
*this_cache
,
277 struct gdbarch
*gdbarch
= get_frame_arch (next_frame
);
278 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
279 CORE_ADDR sp
= frame_unwind_register_unsigned (next_frame
, I386_ESP_REGNUM
);
285 if (self
== &i386nbsd_sigtramp_sc16
|| self
== &i386nbsd_sigtramp_sc2
)
287 reg_offset
= i386nbsd_sc_reg_offset
;
288 num_regs
= ARRAY_SIZE (i386nbsd_sc_reg_offset
);
290 /* Read in the sigcontext address */
291 base
= read_memory_unsigned_integer (sp
+ 8, 4);
295 reg_offset
= i386nbsd_mc_reg_offset
;
296 num_regs
= ARRAY_SIZE (i386nbsd_mc_reg_offset
);
298 /* Read in the ucontext address */
299 base
= read_memory_unsigned_integer (sp
+ 8, 4);
300 /* offsetof(ucontext_t, uc_mcontext) == 36 */
304 for (i
= 0; i
< num_regs
; i
++)
305 if (reg_offset
[i
] != -1)
306 trad_frame_set_reg_addr (this_cache
, i
, base
+ reg_offset
[i
]);
308 /* Construct the frame ID using the function start. */
309 trad_frame_set_id (this_cache
, frame_id_build (sp
, func
));
312 /* Kernel debugging support */
314 /* From <machine/frame.h>. Note that %esp and %ess are only saved in
315 a trap frame when entering the kernel from user space. */
316 static int i386nbsd_tf_reg_offset
[] =
327 15 * 4, /* %eflags */
336 static struct trad_frame_cache
*
337 i386nbsd_trapframe_cache(struct frame_info
*next_frame
, void **this_cache
)
339 struct trad_frame_cache
*cache
;
340 CORE_ADDR func
, sp
, addr
, tmp
;
348 cache
= trad_frame_cache_zalloc (next_frame
);
351 func
= frame_func_unwind (next_frame
);
352 sp
= frame_unwind_register_unsigned (next_frame
, I386_ESP_REGNUM
);
354 find_pc_partial_function (func
, &name
, NULL
, NULL
);
355 if (name
&& strncmp (name
, "Xintr", 5) == 0)
357 /* It's an interrupt frame. */
358 tmp
= read_memory_unsigned_integer (sp
+ 4, 4);
361 /* Reasonable value for 'ppl': already on interrupt stack. */
366 /* Switch to previous stack. */
372 /* It's a trap frame. */
376 for (i
= 0; i
< ARRAY_SIZE (i386nbsd_tf_reg_offset
); i
++)
377 if (i386nbsd_tf_reg_offset
[i
] != -1)
378 trad_frame_set_reg_addr (cache
, i
, addr
+ i386nbsd_tf_reg_offset
[i
]);
380 /* Read %cs from trap frame. */
381 addr
+= i386nbsd_tf_reg_offset
[I386_CS_REGNUM
];
382 cs
= read_memory_unsigned_integer (addr
, 4);
383 if ((cs
& I386_SEL_RPL
) == I386_SEL_UPL
)
385 /* Trap from user space; terminate backtrace. */
386 trad_frame_set_id (cache
, null_frame_id
);
390 /* Construct the frame ID using the function start. */
391 trad_frame_set_id (cache
, frame_id_build (sp
+ 8, func
));
398 i386nbsd_trapframe_this_id (struct frame_info
*next_frame
,
399 void **this_cache
, struct frame_id
*this_id
)
401 struct trad_frame_cache
*cache
=
402 i386nbsd_trapframe_cache (next_frame
, this_cache
);
404 trad_frame_get_id (cache
, this_id
);
408 i386nbsd_trapframe_prev_register (struct frame_info
*next_frame
,
409 void **this_cache
, int regnum
,
410 int *optimizedp
, enum lval_type
*lvalp
,
411 CORE_ADDR
*addrp
, int *realnump
,
414 struct trad_frame_cache
*cache
=
415 i386nbsd_trapframe_cache (next_frame
, this_cache
);
417 trad_frame_get_register (cache
, next_frame
, regnum
,
418 optimizedp
, lvalp
, addrp
, realnump
, valuep
);
422 i386nbsd_trapframe_sniffer (const struct frame_unwind
*self
,
423 struct frame_info
*next_frame
,
424 void **this_prologue_cache
)
429 /* Check Current Privilege Level and bail out if we're not executing
431 cs
= frame_unwind_register_unsigned (next_frame
, I386_CS_REGNUM
);
432 if ((cs
& I386_SEL_RPL
) == I386_SEL_UPL
)
436 find_pc_partial_function (frame_pc_unwind (next_frame
), &name
, NULL
, NULL
);
437 return (name
&& ((strcmp (name
, "alltraps") == 0)
438 || (strcmp (name
, "calltrap") == 0)
439 || (strncmp (name
, "Xtrap", 5) == 0)
440 || (strcmp (name
, "syscall1") == 0)
441 || (strcmp (name
, "Xsyscall") == 0)
442 || (strncmp (name
, "Xintr", 5) == 0)
443 || (strncmp (name
, "Xresume", 7) == 0)
444 || (strncmp (name
, "Xstray", 6) == 0)
445 || (strncmp (name
, "Xrecurse", 8) == 0)
446 || (strncmp (name
, "Xsoft", 5) == 0)
447 || (strncmp (name
, "Xdoreti", 5) == 0)));
450 const struct frame_unwind i386nbsd_trapframe_unwind
= {
451 /* FIXME: kettenis/20051219: This really is more like an interrupt
452 frame, but SIGTRAMP_FRAME would print <signal handler called>,
453 which really is not what we want here. */
455 i386nbsd_trapframe_this_id
,
456 i386nbsd_trapframe_prev_register
,
458 i386nbsd_trapframe_sniffer
462 i386nbsd_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
464 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
466 /* Obviously NetBSD is BSD-based. */
467 i386bsd_init_abi (info
, gdbarch
);
469 /* NetBSD has a different `struct reg'. */
470 tdep
->gregset_reg_offset
= i386nbsd_r_reg_offset
;
471 tdep
->gregset_num_regs
= ARRAY_SIZE (i386nbsd_r_reg_offset
);
472 tdep
->sizeof_gregset
= 16 * 4;
474 /* NetBSD uses -freg-struct-return by default. */
475 tdep
->struct_return
= reg_struct_return
;
477 /* NetBSD uses tramp_frame sniffers for signal trampolines. */
478 tdep
->sigcontext_addr
= 0;
479 tdep
->sigtramp_start
= 0;
480 tdep
->sigtramp_end
= 0;
481 tdep
->sigtramp_p
= 0;
482 tdep
->sc_reg_offset
= 0;
483 tdep
->sc_num_regs
= 0;
485 tramp_frame_prepend_unwinder (gdbarch
, &i386nbsd_sigtramp_sc16
);
486 tramp_frame_prepend_unwinder (gdbarch
, &i386nbsd_sigtramp_sc2
);
487 tramp_frame_prepend_unwinder (gdbarch
, &i386nbsd_sigtramp_si2
);
488 tramp_frame_prepend_unwinder (gdbarch
, &i386nbsd_sigtramp_si31
);
489 tramp_frame_prepend_unwinder (gdbarch
, &i386nbsd_sigtramp_si4
);
491 /* Unwind kernel trap frames correctly. */
492 frame_unwind_prepend_unwinder (gdbarch
, &i386nbsd_trapframe_unwind
);
498 i386nbsdaout_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
500 i386nbsd_init_abi (info
, gdbarch
);
502 /* NetBSD a.out has a single register set. */
503 set_gdbarch_regset_from_core_section
504 (gdbarch
, i386nbsd_aout_regset_from_core_section
);
510 i386nbsdelf_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
512 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
514 /* It's still NetBSD. */
515 i386nbsd_init_abi (info
, gdbarch
);
518 i386_elf_init_abi (info
, gdbarch
);
520 /* NetBSD ELF uses SVR4-style shared libraries. */
521 set_solib_svr4_fetch_link_map_offsets
522 (gdbarch
, svr4_ilp32_fetch_link_map_offsets
);
524 /* NetBSD ELF uses -fpcc-struct-return by default. */
525 tdep
->struct_return
= pcc_struct_return
;
528 static enum gdb_osabi
529 i386nbsd_elf_osabi_sniffer (bfd
*abfd
)
531 if (strcmp (bfd_get_target (abfd
), "elf32-i386") != 0)
532 return GDB_OSABI_UNKNOWN
;
533 /* disgusting hack since kernels don't have a PT_NOTE section */
534 if ((unsigned long)elf_elfheader (abfd
)->e_entry
!= (unsigned long)0xc0100000)
535 return GDB_OSABI_UNKNOWN
;
537 return GDB_OSABI_NETBSD_ELF
;
542 _initialize_i386nbsd_tdep (void)
544 gdbarch_register_osabi_sniffer (bfd_arch_i386
, bfd_target_elf_flavour
,
545 i386nbsd_elf_osabi_sniffer
);
546 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_NETBSD_AOUT
,
547 i386nbsdaout_init_abi
);
548 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_NETBSD_ELF
,
549 i386nbsdelf_init_abi
);