OSDN Git Service

* lib/gdbserver-support.exp (gdbserver_spawn): Only match full_buffer.
[pf3gnuchains/pf3gnuchains4x.git] / gdb / i386nbsd-tdep.c
1 /* Target-dependent code for NetBSD/i386.
2
3    Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 2003,
4    2004, 2007 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., 51 Franklin Street, Fifth Floor,
21    Boston, MA 02110-1301, USA.  */
22
23 #include "defs.h"
24 #include "arch-utils.h"
25 #include "frame.h"
26 #include "gdbcore.h"
27 #include "regcache.h"
28 #include "regset.h"
29 #include "osabi.h"
30 #include "symtab.h"
31
32 #include "gdb_assert.h"
33 #include "gdb_string.h"
34
35 #include "i386-tdep.h"
36 #include "i387-tdep.h"
37 #include "nbsd-tdep.h"
38 #include "solib-svr4.h"
39
40 /* From <machine/reg.h>.  */
41 static int i386nbsd_r_reg_offset[] =
42 {
43   0 * 4,                        /* %eax */
44   1 * 4,                        /* %ecx */
45   2 * 4,                        /* %edx */
46   3 * 4,                        /* %ebx */
47   4 * 4,                        /* %esp */
48   5 * 4,                        /* %ebp */
49   6 * 4,                        /* %esi */
50   7 * 4,                        /* %edi */
51   8 * 4,                        /* %eip */
52   9 * 4,                        /* %eflags */
53   10 * 4,                       /* %cs */
54   11 * 4,                       /* %ss */
55   12 * 4,                       /* %ds */
56   13 * 4,                       /* %es */
57   14 * 4,                       /* %fs */
58   15 * 4                        /* %gs */
59 };
60
61 static void
62 i386nbsd_aout_supply_regset (const struct regset *regset,
63                              struct regcache *regcache, int regnum,
64                              const void *regs, size_t len)
65 {
66   const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
67
68   gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
69
70   i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
71   i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
72 }
73
74 static const struct regset *
75 i386nbsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
76                                         const char *sect_name,
77                                         size_t sect_size)
78 {
79   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
80
81   /* NetBSD a.out core dumps don't use seperate register sets for the
82      general-purpose and floating-point registers.  */
83
84   if (strcmp (sect_name, ".reg") == 0
85       && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
86     {
87       if (tdep->gregset == NULL)
88         tdep->gregset =
89           regset_alloc (gdbarch, i386nbsd_aout_supply_regset, NULL);
90       return tdep->gregset;
91     }
92
93   return NULL;
94 }
95
96 /* Under NetBSD/i386, signal handler invocations can be identified by the
97    designated code sequence that is used to return from a signal handler.
98    In particular, the return address of a signal handler points to the
99    following code sequence:
100
101         leal    0x10(%esp), %eax
102         pushl   %eax
103         pushl   %eax
104         movl    $0x127, %eax            # __sigreturn14
105         int     $0x80
106
107    Each instruction has a unique encoding, so we simply attempt to match
108    the instruction the PC is pointing to with any of the above instructions.
109    If there is a hit, we know the offset to the start of the designated
110    sequence and can then check whether we really are executing in the
111    signal trampoline.  If not, -1 is returned, otherwise the offset from the
112    start of the return sequence is returned.  */
113 #define RETCODE_INSN1           0x8d
114 #define RETCODE_INSN2           0x50
115 #define RETCODE_INSN3           0x50
116 #define RETCODE_INSN4           0xb8
117 #define RETCODE_INSN5           0xcd
118
119 #define RETCODE_INSN2_OFF       4
120 #define RETCODE_INSN3_OFF       5
121 #define RETCODE_INSN4_OFF       6
122 #define RETCODE_INSN5_OFF       11
123
124 static const unsigned char sigtramp_retcode[] =
125 {
126   RETCODE_INSN1, 0x44, 0x24, 0x10,
127   RETCODE_INSN2,
128   RETCODE_INSN3,
129   RETCODE_INSN4, 0x27, 0x01, 0x00, 0x00,
130   RETCODE_INSN5, 0x80,
131 };
132
133 static LONGEST
134 i386nbsd_sigtramp_offset (struct frame_info *next_frame)
135 {
136   CORE_ADDR pc = frame_pc_unwind (next_frame);
137   unsigned char ret[sizeof(sigtramp_retcode)], insn;
138   LONGEST off;
139   int i;
140
141   if (!safe_frame_unwind_memory (next_frame, pc, &insn, 1))
142     return -1;
143
144   switch (insn)
145     {
146     case RETCODE_INSN1:
147       off = 0;
148       break;
149
150     case RETCODE_INSN2:
151       /* INSN2 and INSN3 are the same.  Read at the location of PC+1
152          to determine if we're actually looking at INSN2 or INSN3.  */
153       if (!safe_frame_unwind_memory (next_frame, pc + 1, &insn, 1))
154         return -1;
155
156       if (insn == RETCODE_INSN3)
157         off = RETCODE_INSN2_OFF;
158       else
159         off = RETCODE_INSN3_OFF;
160       break;
161
162     case RETCODE_INSN4:
163       off = RETCODE_INSN4_OFF;
164       break;
165
166     case RETCODE_INSN5:
167       off = RETCODE_INSN5_OFF;
168       break;
169
170     default:
171       return -1;
172     }
173
174   pc -= off;
175
176   if (!safe_frame_unwind_memory (next_frame, pc, ret, sizeof (ret)))
177     return -1;
178
179   if (memcmp (ret, sigtramp_retcode, sizeof (ret)) == 0)
180     return off;
181
182   return -1;
183 }
184
185 /* Return whether the frame preceding NEXT_FRAME corresponds to a
186    NetBSD sigtramp routine.  */
187
188 static int
189 i386nbsd_sigtramp_p (struct frame_info *next_frame)
190 {
191   CORE_ADDR pc = frame_pc_unwind (next_frame);
192   char *name;
193
194   find_pc_partial_function (pc, &name, NULL, NULL);
195   return (nbsd_pc_in_sigtramp (pc, name)
196           || i386nbsd_sigtramp_offset (next_frame) >= 0);
197 }
198
199 /* From <machine/signal.h>.  */
200 int i386nbsd_sc_reg_offset[] =
201 {
202   10 * 4,                       /* %eax */
203   9 * 4,                        /* %ecx */
204   8 * 4,                        /* %edx */
205   7 * 4,                        /* %ebx */
206   14 * 4,                       /* %esp */
207   6 * 4,                        /* %ebp */
208   5 * 4,                        /* %esi */
209   4 * 4,                        /* %edi */
210   11 * 4,                       /* %eip */
211   13 * 4,                       /* %eflags */
212   12 * 4,                       /* %cs */
213   15 * 4,                       /* %ss */
214   3 * 4,                        /* %ds */
215   2 * 4,                        /* %es */
216   1 * 4,                        /* %fs */
217   0 * 4                         /* %gs */
218 };
219
220 static void 
221 i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
222 {
223   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
224
225   /* Obviously NetBSD is BSD-based.  */
226   i386bsd_init_abi (info, gdbarch);
227
228   /* NetBSD has a different `struct reg'.  */
229   tdep->gregset_reg_offset = i386nbsd_r_reg_offset;
230   tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset);
231   tdep->sizeof_gregset = 16 * 4;
232
233   /* NetBSD has different signal trampoline conventions.  */
234   tdep->sigtramp_start = 0;
235   tdep->sigtramp_end = 0;
236   tdep->sigtramp_p = i386nbsd_sigtramp_p;
237
238   /* NetBSD uses -freg-struct-return by default.  */
239   tdep->struct_return = reg_struct_return;
240
241   /* NetBSD has a `struct sigcontext' that's different from the
242      original 4.3 BSD.  */
243   tdep->sc_reg_offset = i386nbsd_sc_reg_offset;
244   tdep->sc_num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset);
245 }
246
247 /* NetBSD a.out.  */
248
249 static void
250 i386nbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
251 {
252   i386nbsd_init_abi (info, gdbarch);
253
254   /* NetBSD a.out has a single register set.  */
255   set_gdbarch_regset_from_core_section
256     (gdbarch, i386nbsd_aout_regset_from_core_section);
257 }
258
259 /* NetBSD ELF.  */
260
261 static void
262 i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
263 {
264   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
265
266   /* It's still NetBSD.  */
267   i386nbsd_init_abi (info, gdbarch);
268
269   /* But ELF-based.  */
270   i386_elf_init_abi (info, gdbarch);
271
272   /* NetBSD ELF uses SVR4-style shared libraries.  */
273   set_solib_svr4_fetch_link_map_offsets
274     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
275
276   /* NetBSD ELF uses -fpcc-struct-return by default.  */
277   tdep->struct_return = pcc_struct_return;
278 }
279
280 void
281 _initialize_i386nbsd_tdep (void)
282 {
283   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_AOUT,
284                           i386nbsdaout_init_abi);
285   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_ELF,
286                           i386nbsdelf_init_abi);
287 }