1 /* Target-dependent code for NetBSD/amd64.
3 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
5 This file is part of GDB.
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
23 #include "arch-utils.h"
29 #include "gdb_assert.h"
31 #include "amd64-tdep.h"
32 #include "nbsd-tdep.h"
33 #include "solib-svr4.h"
34 #include "trad-frame.h"
35 #include "frame-unwind.h"
37 /* Support for signal handlers. */
39 /* Return whether the frame preceding NEXT_FRAME corresponds to a
40 NetBSD sigtramp routine. */
43 amd64nbsd_sigtramp_p (struct frame_info
*next_frame
)
45 CORE_ADDR pc
= frame_pc_unwind (next_frame
);
48 find_pc_partial_function (pc
, &name
, NULL
, NULL
);
49 return nbsd_pc_in_sigtramp (pc
, name
);
52 /* Assuming NEXT_FRAME is preceded by a frame corresponding to a
53 NetBSD sigtramp routine, return the address of the associated
54 mcontext structure. */
57 amd64nbsd_mcontext_addr (struct frame_info
*next_frame
)
61 /* The register %r15 points at `struct ucontext' upon entry of a
63 addr
= frame_unwind_register_unsigned (next_frame
, AMD64_R15_REGNUM
);
65 /* The mcontext structure lives as offset 56 in `struct ucontext'. */
69 /* NetBSD 2.0 or later. */
71 /* Mapping between the general-purpose registers in `struct reg'
72 format and GDB's register cache layout. */
74 /* From <machine/reg.h>. */
75 int amd64nbsd_r_reg_offset
[] =
92 11 * 8, /* ... %r15 */
103 /* Kernel debuging support */
104 static const int amd64nbsd_tf_reg_offset
[] =
121 15 * 8, /* ... %r15 */
123 27 * 8, /* %eflags */
132 static struct trad_frame_cache
*
133 amd64nbsd_trapframe_cache(struct frame_info
*next_frame
, void **this_cache
)
135 struct trad_frame_cache
*cache
;
136 CORE_ADDR func
, sp
, addr
;
144 cache
= trad_frame_cache_zalloc (next_frame
);
147 func
= frame_func_unwind (next_frame
);
148 sp
= frame_unwind_register_unsigned (next_frame
, AMD64_RSP_REGNUM
);
150 find_pc_partial_function (func
, &name
, NULL
, NULL
);
152 /* There is an extra 'call' in the interrupt sequence - ignore the extra
154 if (name
&& strncmp (name
, "Xintr", 5) == 0)
155 addr
= sp
+ 8; /* It's an interrupt frame. */
159 for (i
= 0; i
< ARRAY_SIZE (amd64nbsd_tf_reg_offset
); i
++)
161 if (amd64nbsd_tf_reg_offset
[i
] != -1)
162 trad_frame_set_reg_addr (cache
, i
, addr
+ amd64nbsd_tf_reg_offset
[i
]);
164 /* Read %cs and %rip when we have the addresses to hand */
165 if (i
== AMD64_CS_REGNUM
)
166 cs
= read_memory_unsigned_integer (addr
+ amd64nbsd_tf_reg_offset
[i
], 8);
167 if (i
== AMD64_RIP_REGNUM
)
168 rip
= read_memory_unsigned_integer (addr
+ amd64nbsd_tf_reg_offset
[i
], 8);
171 /* The trap frame layout was changed lf the %rip value is less than 2^16 it
172 * is almost certainly the %ss of the old format. */
176 for (i
= 0; i
< ARRAY_SIZE (amd64nbsd_tf_reg_offset
); i
++)
179 if (amd64nbsd_tf_reg_offset
[i
] == -1)
182 trad_frame_set_reg_addr (cache
, i
, addr
+ amd64nbsd_r_reg_offset
[i
]);
184 /* Read %cs when we have the address to hand */
185 if (i
== AMD64_CS_REGNUM
)
186 cs
= read_memory_unsigned_integer (addr
+ amd64nbsd_r_reg_offset
[i
], 8);
190 if ((cs
& I386_SEL_RPL
) == I386_SEL_UPL
)
192 /* Trap from user space; terminate backtrace. */
193 trad_frame_set_id (cache
, null_frame_id
);
197 /* Construct the frame ID using the function start. */
198 trad_frame_set_id (cache
, frame_id_build (sp
+ 16, func
));
205 amd64nbsd_trapframe_this_id (struct frame_info
*next_frame
,
206 void **this_cache
, struct frame_id
*this_id
)
208 struct trad_frame_cache
*cache
=
209 amd64nbsd_trapframe_cache (next_frame
, this_cache
);
211 trad_frame_get_id (cache
, this_id
);
215 amd64nbsd_trapframe_prev_register (struct frame_info
*next_frame
,
216 void **this_cache
, int regnum
,
217 int *optimizedp
, enum lval_type
*lvalp
,
218 CORE_ADDR
*addrp
, int *realnump
,
221 struct trad_frame_cache
*cache
=
222 amd64nbsd_trapframe_cache (next_frame
, this_cache
);
224 trad_frame_get_register (cache
, next_frame
, regnum
,
225 optimizedp
, lvalp
, addrp
, realnump
, valuep
);
229 amd64nbsd_trapframe_sniffer (const struct frame_unwind
*self
,
230 struct frame_info
*next_frame
,
231 void **this_prologue_cache
)
236 /* Check Current Privilege Level and bail out if we're not executing
238 cs
= frame_unwind_register_unsigned (next_frame
, AMD64_CS_REGNUM
);
239 if ((cs
& I386_SEL_RPL
) == I386_SEL_UPL
)
242 find_pc_partial_function (frame_pc_unwind (next_frame
), &name
, NULL
, NULL
);
243 return (name
&& ((strcmp (name
, "alltraps") == 0)
244 || (strcmp (name
, "calltrap") == 0)
245 || (strncmp (name
, "Xtrap", 5) == 0)
246 || (strcmp (name
, "osyscall1") == 0)
247 || (strcmp (name
, "Xsyscall") == 0)
248 || (strncmp (name
, "Xintr", 5) == 0)
249 || (strncmp (name
, "Xresume", 7) == 0)
250 || (strncmp (name
, "Xstray", 6) == 0)
251 || (strncmp (name
, "Xrecurse", 8) == 0)
252 || (strncmp (name
, "Xsoft", 5) == 0)
253 || (strcmp (name
, "Xdoreti") == 0)));
256 static const struct frame_unwind amd64nbsd_trapframe_unwind
= {
257 /* FIXME: kettenis/20051219: This really is more like an interrupt
258 frame, but SIGTRAMP_FRAME would print <signal handler called>,
259 which really is not what we want here. */
261 amd64nbsd_trapframe_this_id
,
262 amd64nbsd_trapframe_prev_register
,
264 amd64nbsd_trapframe_sniffer
269 amd64nbsd_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
271 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
273 /* Initialize general-purpose register set details first. */
274 tdep
->gregset_reg_offset
= amd64nbsd_r_reg_offset
;
275 tdep
->gregset_num_regs
= ARRAY_SIZE (amd64nbsd_r_reg_offset
);
276 tdep
->sizeof_gregset
= 26 * 8;
278 amd64_init_abi (info
, gdbarch
);
280 tdep
->jb_pc_offset
= 7 * 8;
282 /* NetBSD has its own convention for signal trampolines. */
283 tdep
->sigtramp_p
= amd64nbsd_sigtramp_p
;
284 tdep
->sigcontext_addr
= amd64nbsd_mcontext_addr
;
285 tdep
->sc_reg_offset
= amd64nbsd_r_reg_offset
;
286 tdep
->sc_num_regs
= ARRAY_SIZE (amd64nbsd_r_reg_offset
);
288 /* NetBSD uses SVR4-style shared libraries. */
289 set_solib_svr4_fetch_link_map_offsets
290 (gdbarch
, svr4_lp64_fetch_link_map_offsets
);
292 /* Unwind kernel trap frames correctly. */
293 frame_unwind_prepend_unwinder (gdbarch
, &amd64nbsd_trapframe_unwind
);
297 /* Provide a prototype to silence -Wmissing-prototypes. */
298 void _initialize_amd64nbsd_tdep (void);
301 _initialize_amd64nbsd_ndep (void)
303 /* The NetBSD/amd64 native dependent code makes this assumption. */
304 gdb_assert (ARRAY_SIZE (amd64nbsd_r_reg_offset
) == AMD64_NUM_GREGS
);
306 gdbarch_register_osabi (bfd_arch_i386
, bfd_mach_x86_64
,
307 GDB_OSABI_NETBSD_ELF
, amd64nbsd_init_abi
);