Fix up mix of man(7)/mdoc(7).
[netbsd-mini2440.git] / gnu / dist / gdb6 / gdb / amd64nbsd-tdep.c
blob05694880b3e8518c7b6043bc156319d3d43cecb7
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. */
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "frame.h"
25 #include "gdbcore.h"
26 #include "osabi.h"
27 #include "symtab.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. */
42 static int
43 amd64nbsd_sigtramp_p (struct frame_info *next_frame)
45 CORE_ADDR pc = frame_pc_unwind (next_frame);
46 char *name;
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. */
56 static CORE_ADDR
57 amd64nbsd_mcontext_addr (struct frame_info *next_frame)
59 CORE_ADDR addr;
61 /* The register %r15 points at `struct ucontext' upon entry of a
62 signal trampoline. */
63 addr = frame_unwind_register_unsigned (next_frame, AMD64_R15_REGNUM);
65 /* The mcontext structure lives as offset 56 in `struct ucontext'. */
66 return addr + 56;
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[] =
77 14 * 8, /* %rax */
78 13 * 8, /* %rbx */
79 3 * 8, /* %rcx */
80 2 * 8, /* %rdx */
81 1 * 8, /* %rsi */
82 0 * 8, /* %rdi */
83 12 * 8, /* %rbp */
84 24 * 8, /* %rsp */
85 4 * 8, /* %r8 .. */
86 5 * 8,
87 6 * 8,
88 7 * 8,
89 8 * 8,
90 9 * 8,
91 10 * 8,
92 11 * 8, /* ... %r15 */
93 21 * 8, /* %rip */
94 23 * 8, /* %eflags */
95 22 * 8, /* %cs */
96 25 * 8, /* %ss */
97 18 * 8, /* %ds */
98 17 * 8, /* %es */
99 16 * 8, /* %fs */
100 15 * 8 /* %gs */
103 /* Kernel debuging support */
104 static const int amd64nbsd_tf_reg_offset[] =
106 18 * 8, /* %rax */
107 17 * 8, /* %rbx */
108 10 * 8, /* %rcx */
109 2 * 8, /* %rdx */
110 1 * 8, /* %rsi */
111 0 * 8, /* %rdi */
112 16 * 8, /* %rbp */
113 28 * 8, /* %rsp */
114 4 * 8, /* %r8 .. */
115 5 * 8,
116 3 * 8,
117 11 * 8,
118 12 * 8,
119 13 * 8,
120 14 * 8,
121 15 * 8, /* ... %r15 */
122 25 * 8, /* %rip */
123 27 * 8, /* %eflags */
124 26 * 8, /* %cs */
125 29 * 8, /* %ss */
126 22 * 8, /* %ds */
127 21 * 8, /* %es */
128 20 * 8, /* %fs */
129 19 * 8, /* %gs */
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;
137 ULONGEST cs, rip;
138 char *name;
139 int i;
141 if (*this_cache)
142 return *this_cache;
144 cache = trad_frame_cache_zalloc (next_frame);
145 *this_cache = cache;
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
153 * return address */
154 if (name && strncmp (name, "Xintr", 5) == 0)
155 addr = sp + 8; /* It's an interrupt frame. */
156 else
157 addr = sp;
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. */
173 if (rip < 2^16)
176 for (i = 0; i < ARRAY_SIZE (amd64nbsd_tf_reg_offset); i++)
179 if (amd64nbsd_tf_reg_offset[i] == -1)
180 continue;
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);
195 else
197 /* Construct the frame ID using the function start. */
198 trad_frame_set_id (cache, frame_id_build (sp + 16, func));
201 return cache;
204 static void
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);
214 static void
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,
219 gdb_byte *valuep)
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);
228 static int
229 amd64nbsd_trapframe_sniffer (const struct frame_unwind *self,
230 struct frame_info *next_frame,
231 void **this_prologue_cache)
233 ULONGEST cs;
234 char *name;
236 /* Check Current Privilege Level and bail out if we're not executing
237 in kernel space. */
238 cs = frame_unwind_register_unsigned (next_frame, AMD64_CS_REGNUM);
239 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
240 return 0;
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. */
260 NORMAL_FRAME,
261 amd64nbsd_trapframe_this_id,
262 amd64nbsd_trapframe_prev_register,
263 NULL,
264 amd64nbsd_trapframe_sniffer
268 static void
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);
300 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);