* i387-tdep.c (i387_supply_fsave, i387_supply_fxsave): Add
[platform/upstream/binutils.git] / gdb / i386nbsd-tdep.c
1 /* Target-dependent code for NetBSD/i386.
2
3    Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 2003
4    Free Software Foundation, Inc.
5
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330,
21    Boston, MA 02111-1307, USA.  */
22
23 #include "defs.h"
24 #include "gdbtypes.h"
25 #include "gdbcore.h"
26 #include "regcache.h"
27 #include "arch-utils.h"
28 #include "osabi.h"
29
30 #include "i386-tdep.h"
31 #include "i387-tdep.h"
32 #include "nbsd-tdep.h"
33
34 #include "solib-svr4.h"
35
36 /* Map a GDB register number to an offset in the reg structure.  */
37 static int regmap[] =
38 {
39   ( 0 * 4),             /* %eax */
40   ( 1 * 4),             /* %ecx */
41   ( 2 * 4),             /* %edx */
42   ( 3 * 4),             /* %ebx */
43   ( 4 * 4),             /* %esp */
44   ( 5 * 4),             /* %epb */
45   ( 6 * 4),             /* %esi */
46   ( 7 * 4),             /* %edi */
47   ( 8 * 4),             /* %eip */
48   ( 9 * 4),             /* %eflags */
49   (10 * 4),             /* %cs */
50   (11 * 4),             /* %ss */
51   (12 * 4),             /* %ds */
52   (13 * 4),             /* %es */
53   (14 * 4),             /* %fs */
54   (15 * 4),             /* %gs */
55 };
56
57 #define SIZEOF_STRUCT_REG       (16 * 4)
58
59 static void
60 i386nbsd_supply_reg (char *regs, int regno)
61 {
62   int i;
63
64   for (i = 0; i <= 15; i++)
65     if (regno == i || regno == -1)
66       supply_register (i, regs + regmap[i]);
67 }
68
69 static void
70 fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
71                       CORE_ADDR ignore)
72 {
73   char *regs, *fsave;
74
75   /* We get everything from one section.  */
76   if (which != 0)
77     return;
78
79   if (core_reg_size < (SIZEOF_STRUCT_REG + 108))
80     {
81       warning ("Wrong size register set in core file.");
82       return;
83     }
84
85   regs = core_reg_sect;
86   fsave = core_reg_sect + SIZEOF_STRUCT_REG;
87
88   /* Integer registers.  */
89   i386nbsd_supply_reg (regs, -1);
90
91   /* Floating point registers.  */
92   i387_supply_fsave (current_regcache, -1, fsave);
93 }
94
95 static void
96 fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size,
97                          int which, CORE_ADDR ignore)
98 {
99   switch (which)
100     {
101     case 0:  /* Integer registers.  */
102       if (core_reg_size != SIZEOF_STRUCT_REG)
103         warning ("Wrong size register set in core file.");
104       else
105         i386nbsd_supply_reg (core_reg_sect, -1);
106       break;
107
108     case 2:  /* Floating point registers.  */
109       if (core_reg_size != 108)
110         warning ("Wrong size FP register set in core file.");
111       else
112         i387_supply_fsave (current_regcache, -1, core_reg_sect);
113       break;
114
115     case 3:  /* "Extended" floating point registers.  This is gdb-speak
116                 for SSE/SSE2. */
117       if (core_reg_size != 512)
118         warning ("Wrong size XMM register set in core file.");
119       else
120         i387_supply_fxsave (current_regcache, -1, core_reg_sect);
121       break;
122
123     default:
124       /* Don't know what kind of register request this is; just ignore it.  */
125       break;
126     }
127 }
128
129 static struct core_fns i386nbsd_core_fns =
130 {
131   bfd_target_unknown_flavour,           /* core_flavour */
132   default_check_format,                 /* check_format */
133   default_core_sniffer,                 /* core_sniffer */
134   fetch_core_registers,                 /* core_read_registers */
135   NULL                                  /* next */
136 };
137
138 static struct core_fns i386nbsd_elfcore_fns =
139 {
140   bfd_target_elf_flavour,               /* core_flavour */
141   default_check_format,                 /* check_format */
142   default_core_sniffer,                 /* core_sniffer */
143   fetch_elfcore_registers,              /* core_read_registers */
144   NULL                                  /* next */
145 };
146
147 /* Under NetBSD/i386, signal handler invocations can be identified by the
148    designated code sequence that is used to return from a signal handler.
149    In particular, the return address of a signal handler points to the
150    following code sequence:
151
152         leal    0x10(%esp), %eax
153         pushl   %eax
154         pushl   %eax
155         movl    $0x127, %eax            # __sigreturn14
156         int     $0x80
157
158    Each instruction has a unique encoding, so we simply attempt to match
159    the instruction the PC is pointing to with any of the above instructions.
160    If there is a hit, we know the offset to the start of the designated
161    sequence and can then check whether we really are executing in the
162    signal trampoline.  If not, -1 is returned, otherwise the offset from the
163    start of the return sequence is returned.  */
164 #define RETCODE_INSN1           0x8d
165 #define RETCODE_INSN2           0x50
166 #define RETCODE_INSN3           0x50
167 #define RETCODE_INSN4           0xb8
168 #define RETCODE_INSN5           0xcd
169
170 #define RETCODE_INSN2_OFF       4
171 #define RETCODE_INSN3_OFF       5
172 #define RETCODE_INSN4_OFF       6
173 #define RETCODE_INSN5_OFF       11
174
175 static const unsigned char sigtramp_retcode[] =
176 {
177   RETCODE_INSN1, 0x44, 0x24, 0x10,
178   RETCODE_INSN2,
179   RETCODE_INSN3,
180   RETCODE_INSN4, 0x27, 0x01, 0x00, 0x00,
181   RETCODE_INSN5, 0x80,
182 };
183
184 static LONGEST
185 i386nbsd_sigtramp_offset (CORE_ADDR pc)
186 {
187   unsigned char ret[sizeof(sigtramp_retcode)], insn;
188   LONGEST off;
189   int i;
190
191   if (read_memory_nobpt (pc, &insn, 1) != 0)
192     return -1;
193
194   switch (insn)
195     {
196     case RETCODE_INSN1:
197       off = 0;
198       break;
199
200     case RETCODE_INSN2:
201       /* INSN2 and INSN3 are the same.  Read at the location of PC+1
202          to determine if we're actually looking at INSN2 or INSN3.  */
203       if (read_memory_nobpt (pc + 1, &insn, 1) != 0)
204         return -1;
205
206       if (insn == RETCODE_INSN3)
207         off = RETCODE_INSN2_OFF;
208       else
209         off = RETCODE_INSN3_OFF;
210       break;
211
212     case RETCODE_INSN4:
213       off = RETCODE_INSN4_OFF;
214       break;
215
216     case RETCODE_INSN5:
217       off = RETCODE_INSN5_OFF;
218       break;
219
220     default:
221       return -1;
222     }
223
224   pc -= off;
225
226   if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
227     return -1;
228
229   if (memcmp (ret, sigtramp_retcode, sizeof (ret)) == 0)
230     return off;
231
232   return -1;
233 }
234
235 static int
236 i386nbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
237 {
238   return (nbsd_pc_in_sigtramp (pc, name)
239           || i386nbsd_sigtramp_offset (pc) >= 0);
240 }
241
242 /* From <machine/signal.h>.  */
243 int i386nbsd_sc_reg_offset[I386_NUM_GREGS] =
244 {
245   10 * 4,                       /* %eax */
246   9 * 4,                        /* %ecx */
247   8 * 4,                        /* %edx */
248   7 * 4,                        /* %ebx */
249   14 * 4,                       /* %esp */
250   6 * 4,                        /* %ebp */
251   5 * 4,                        /* %esi */
252   4 * 4,                        /* %edi */
253   11 * 4,                       /* %eip */
254   13 * 4,                       /* %eflags */
255   12 * 4,                       /* %cs */
256   15 * 4,                       /* %ss */
257   3 * 4,                        /* %ds */
258   2 * 4,                        /* %es */
259   1 * 4,                        /* %fs */
260   0 * 4                         /* %gs */
261 };
262
263 static void 
264 i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
265 {
266   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
267
268   /* Obviously NetBSD is BSD-based.  */
269   i386bsd_init_abi (info, gdbarch);
270
271   /* NetBSD has different signal trampoline conventions.  */
272   set_gdbarch_pc_in_sigtramp (gdbarch, i386nbsd_pc_in_sigtramp);
273   /* FIXME: kettenis/20020906: We should probably provide
274      NetBSD-specific versions of these functions if we want to
275      recognize signal trampolines that live on the stack.  */
276   set_gdbarch_sigtramp_start (gdbarch, NULL);
277   set_gdbarch_sigtramp_end (gdbarch, NULL);
278
279   /* NetBSD uses -freg-struct-return by default.  */
280   tdep->struct_return = reg_struct_return;
281
282   /* NetBSD has a `struct sigcontext' that's different from the
283      origional 4.3 BSD.  */
284   tdep->sc_reg_offset = i386nbsd_sc_reg_offset;
285   tdep->sc_num_regs = I386_NUM_GREGS;
286 }
287
288 /* NetBSD ELF.  */
289 static void
290 i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
291 {
292   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
293
294   /* It's still NetBSD.  */
295   i386nbsd_init_abi (info, gdbarch);
296
297   /* But ELF-based.  */
298   i386_elf_init_abi (info, gdbarch);
299
300   /* NetBSD ELF uses SVR4-style shared libraries.  */
301   set_gdbarch_in_solib_call_trampoline (gdbarch,
302                                         generic_in_solib_call_trampoline);
303   set_solib_svr4_fetch_link_map_offsets (gdbarch,
304                                  nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
305
306   /* NetBSD ELF uses -fpcc-struct-return by default.  */
307   tdep->struct_return = pcc_struct_return;
308
309   /* We support the SSE registers on NetBSD ELF.  */
310   tdep->num_xmm_regs = I386_NUM_XREGS - 1;
311   set_gdbarch_num_regs (gdbarch, I386_NUM_GREGS + I386_NUM_FREGS
312                         + I386_NUM_XREGS);
313 }
314
315 void
316 _initialize_i386nbsd_tdep (void)
317 {
318   add_core_fns (&i386nbsd_core_fns);
319   add_core_fns (&i386nbsd_elfcore_fns);
320
321   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_AOUT,
322                           i386nbsd_init_abi);
323   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_ELF,
324                           i386nbsdelf_init_abi);
325 }