2005-03-07 Manoj Iyer <manjo@austin.ibm.com>
[deliverable/binutils-gdb.git] / gdb / i386obsd-tdep.c
1 /* Target-dependent code for OpenBSD/i386.
2
3 Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
4 2003, 2004, 2005
5 Free Software Foundation, Inc.
6
7 This file is part of GDB.
8
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.
13
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.
18
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., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 #include "defs.h"
25 #include "arch-utils.h"
26 #include "frame.h"
27 #include "gdbcore.h"
28 #include "regcache.h"
29 #include "regset.h"
30 #include "symtab.h"
31 #include "objfiles.h"
32 #include "osabi.h"
33 #include "target.h"
34
35 #include "gdb_assert.h"
36 #include "gdb_string.h"
37
38 #include "i386-tdep.h"
39 #include "i387-tdep.h"
40 #include "solib-svr4.h"
41 #include "bsd-uthread.h"
42
43 /* Support for signal handlers. */
44
45 /* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
46 in virtual memory. The randomness makes it somewhat tricky to
47 detect it, but fortunately we can rely on the fact that the start
48 of the sigtramp routine is page-aligned. By the way, the mapping
49 is read-only, so you cannot place a breakpoint in the signal
50 trampoline. */
51
52 /* Default page size. */
53 static const int i386obsd_page_size = 4096;
54
55 /* Return whether the frame preceding NEXT_FRAME corresponds to an
56 OpenBSD sigtramp routine. */
57
58 static int
59 i386obsd_sigtramp_p (struct frame_info *next_frame)
60 {
61 CORE_ADDR pc = frame_pc_unwind (next_frame);
62 CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
63 const char sigreturn[] =
64 {
65 0xb8,
66 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */
67 0xcd, 0x80 /* int $0x80 */
68 };
69 size_t buflen = sizeof sigreturn;
70 char *name, *buf;
71
72 /* If the function has a valid symbol name, it isn't a
73 trampoline. */
74 find_pc_partial_function (pc, &name, NULL, NULL);
75 if (name != NULL)
76 return 0;
77
78 /* If the function lives in a valid section (even without a starting
79 point) it isn't a trampoline. */
80 if (find_pc_section (pc) != NULL)
81 return 0;
82
83 /* Allocate buffer. */
84 buf = alloca (buflen);
85
86 /* If we can't read the instructions at START_PC, return zero. */
87 if (!safe_frame_unwind_memory (next_frame, start_pc + 0x0a, buf, buflen))
88 return 0;
89
90 /* Check for sigreturn(2). */
91 if (memcmp (buf, sigreturn, buflen) == 0)
92 return 1;
93
94 /* If we can't read the instructions at START_PC, return zero. */
95 if (!safe_frame_unwind_memory (next_frame, start_pc + 0x14, buf, buflen))
96 return 0;
97
98 /* Check for sigreturn(2) (again). */
99 if (memcmp (buf, sigreturn, buflen) == 0)
100 return 1;
101
102 return 0;
103 }
104 \f
105 /* Mapping between the general-purpose registers in `struct reg'
106 format and GDB's register cache layout. */
107
108 /* From <machine/reg.h>. */
109 static int i386obsd_r_reg_offset[] =
110 {
111 0 * 4, /* %eax */
112 1 * 4, /* %ecx */
113 2 * 4, /* %edx */
114 3 * 4, /* %ebx */
115 4 * 4, /* %esp */
116 5 * 4, /* %ebp */
117 6 * 4, /* %esi */
118 7 * 4, /* %edi */
119 8 * 4, /* %eip */
120 9 * 4, /* %eflags */
121 10 * 4, /* %cs */
122 11 * 4, /* %ss */
123 12 * 4, /* %ds */
124 13 * 4, /* %es */
125 14 * 4, /* %fs */
126 15 * 4 /* %gs */
127 };
128
129 static void
130 i386obsd_aout_supply_regset (const struct regset *regset,
131 struct regcache *regcache, int regnum,
132 const void *regs, size_t len)
133 {
134 const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
135
136 gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
137
138 i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
139 i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
140 }
141
142 static const struct regset *
143 i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
144 const char *sect_name,
145 size_t sect_size)
146 {
147 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
148
149 /* OpenBSD a.out core dumps don't use seperate register sets for the
150 general-purpose and floating-point registers. */
151
152 if (strcmp (sect_name, ".reg") == 0
153 && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
154 {
155 if (tdep->gregset == NULL)
156 tdep->gregset =
157 regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL);
158 return tdep->gregset;
159 }
160
161 return NULL;
162 }
163 \f
164
165 /* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
166 CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
167 CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
168
169 /* From <machine/signal.h>. */
170 int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
171 {
172 10 * 4, /* %eax */
173 9 * 4, /* %ecx */
174 8 * 4, /* %edx */
175 7 * 4, /* %ebx */
176 14 * 4, /* %esp */
177 6 * 4, /* %ebp */
178 5 * 4, /* %esi */
179 4 * 4, /* %edi */
180 11 * 4, /* %eip */
181 13 * 4, /* %eflags */
182 12 * 4, /* %cs */
183 15 * 4, /* %ss */
184 3 * 4, /* %ds */
185 2 * 4, /* %es */
186 1 * 4, /* %fs */
187 0 * 4 /* %gs */
188 };
189
190 /* From /usr/src/lib/libpthread/arch/i386/uthread_machdep.c. */
191 static int i386obsd_uthread_reg_offset[] =
192 {
193 11 * 4, /* %eax */
194 10 * 4, /* %ecx */
195 9 * 4, /* %edx */
196 8 * 4, /* %ebx */
197 -1, /* %esp */
198 6 * 4, /* %ebp */
199 5 * 4, /* %esi */
200 4 * 4, /* %edi */
201 12 * 4, /* %eip */
202 -1, /* %eflags */
203 13 * 4, /* %cs */
204 -1, /* %ss */
205 3 * 4, /* %ds */
206 2 * 4, /* %es */
207 1 * 4, /* %fs */
208 0 * 4 /* %gs */
209 };
210
211 /* Offset within the thread structure where we can find the saved
212 stack pointer (%esp). */
213 #define I386OBSD_UTHREAD_ESP_OFFSET 176
214
215 static void
216 i386obsd_supply_uthread (struct regcache *regcache,
217 int regnum, CORE_ADDR addr)
218 {
219 CORE_ADDR sp_addr = addr + I386OBSD_UTHREAD_ESP_OFFSET;
220 CORE_ADDR sp = 0;
221 char buf[4];
222 int i;
223
224 gdb_assert (regnum >= -1);
225
226 if (regnum == -1 || regnum == I386_ESP_REGNUM)
227 {
228 int offset;
229
230 /* Fetch stack pointer from thread structure. */
231 sp = read_memory_unsigned_integer (sp_addr, 4);
232
233 /* Adjust the stack pointer such that it looks as if we just
234 returned from _thread_machdep_switch. */
235 offset = i386obsd_uthread_reg_offset[I386_EIP_REGNUM] + 4;
236 store_unsigned_integer (buf, 4, sp + offset);
237 regcache_raw_supply (regcache, I386_ESP_REGNUM, buf);
238 }
239
240 for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
241 {
242 if (i386obsd_uthread_reg_offset[i] != -1
243 && (regnum == -1 || regnum == i))
244 {
245 /* Fetch stack pointer from thread structure (if we didn't
246 do so already). */
247 if (sp == 0)
248 sp = read_memory_unsigned_integer (sp_addr, 4);
249
250 /* Read the saved register from the stack frame. */
251 read_memory (sp + i386obsd_uthread_reg_offset[i], buf, 4);
252 regcache_raw_supply (regcache, i, buf);
253 }
254 }
255
256 }
257
258 static void
259 i386obsd_collect_uthread (const struct regcache *regcache,
260 int regnum, CORE_ADDR addr)
261 {
262 CORE_ADDR sp_addr = addr + I386OBSD_UTHREAD_ESP_OFFSET;
263 CORE_ADDR sp = 0;
264 char buf[4];
265 int i;
266
267 gdb_assert (regnum >= -1);
268
269 if (regnum == -1 || regnum == I386_ESP_REGNUM)
270 {
271 int offset;
272
273 /* Calculate the stack pointer (frame pointer) that will be
274 stored into the thread structure. */
275 offset = i386obsd_uthread_reg_offset[I386_EIP_REGNUM] + 4;
276 regcache_raw_collect (regcache, I386_ESP_REGNUM, buf);
277 sp = extract_unsigned_integer (buf, 4) - offset;
278
279 /* Store the stack pointer. */
280 write_memory_unsigned_integer (sp_addr, 4, sp);
281
282 /* The stack pointer was (potentially) modified. Make sure we
283 build a proper stack frame. */
284 regnum = -1;
285 }
286
287 for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
288 {
289 if (i386obsd_uthread_reg_offset[i] != -1
290 && (regnum == -1 || regnum == i))
291 {
292 /* Fetch stack pointer from thread structure (if we didn't
293 calculate it already). */
294 if (sp == 0)
295 sp = read_memory_unsigned_integer (sp_addr, 4);
296
297 /* Write the register into the stack frame. */
298 regcache_raw_collect (regcache, i, buf);
299 write_memory (sp + i386obsd_uthread_reg_offset[i], buf, 4);
300 }
301 }
302 }
303
304 static void
305 i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
306 {
307 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
308
309 /* Obviously OpenBSD is BSD-based. */
310 i386bsd_init_abi (info, gdbarch);
311
312 /* OpenBSD has a different `struct reg'. */
313 tdep->gregset_reg_offset = i386obsd_r_reg_offset;
314 tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
315 tdep->sizeof_gregset = 16 * 4;
316
317 /* OpenBSD uses -freg-struct-return by default. */
318 tdep->struct_return = reg_struct_return;
319
320 /* OpenBSD uses a different memory layout. */
321 tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
322 tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
323 tdep->sigtramp_p = i386obsd_sigtramp_p;
324
325 /* OpenBSD has a `struct sigcontext' that's different from the
326 original 4.3 BSD. */
327 tdep->sc_reg_offset = i386obsd_sc_reg_offset;
328 tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
329
330 /* OpenBSD provides a user-level threads implementation. */
331 bsd_uthread_set_supply_uthread (gdbarch, i386obsd_supply_uthread);
332 bsd_uthread_set_collect_uthread (gdbarch, i386obsd_collect_uthread);
333 }
334
335 /* OpenBSD a.out. */
336
337 static void
338 i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
339 {
340 i386obsd_init_abi (info, gdbarch);
341
342 /* OpenBSD a.out has a single register set. */
343 set_gdbarch_regset_from_core_section
344 (gdbarch, i386obsd_aout_regset_from_core_section);
345 }
346
347 /* OpenBSD ELF. */
348
349 static void
350 i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
351 {
352 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
353
354 /* It's still OpenBSD. */
355 i386obsd_init_abi (info, gdbarch);
356
357 /* But ELF-based. */
358 i386_elf_init_abi (info, gdbarch);
359
360 /* OpenBSD ELF uses SVR4-style shared libraries. */
361 set_solib_svr4_fetch_link_map_offsets
362 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
363 }
364 \f
365
366 /* Provide a prototype to silence -Wmissing-prototypes. */
367 void _initialize_i386obsd_tdep (void);
368
369 void
370 _initialize_i386obsd_tdep (void)
371 {
372 /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
373 indistingushable from NetBSD/i386 a.out binaries, building a GDB
374 that should support both these targets will probably not work as
375 expected. */
376 #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
377
378 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
379 i386obsd_aout_init_abi);
380 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
381 i386obsd_elf_init_abi);
382 }
This page took 0.050046 seconds and 4 git commands to generate.