* defs.h (gdb_byte): New typedef. Tweak comments.
[deliverable/binutils-gdb.git] / gdb / i386obsd-tdep.c
CommitLineData
005328e3 1/* Target-dependent code for OpenBSD/i386.
67457012 2
60a6eeb6 3 Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
a28109e0 4 2003, 2004, 2005
005328e3
MK
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"
911bc6ee 26#include "frame.h"
005328e3
MK
27#include "gdbcore.h"
28#include "regcache.h"
67457012 29#include "regset.h"
911bc6ee
MK
30#include "symtab.h"
31#include "objfiles.h"
4be87837 32#include "osabi.h"
5d93ae8c 33#include "target.h"
005328e3 34
67457012
MK
35#include "gdb_assert.h"
36#include "gdb_string.h"
37
005328e3
MK
38#include "i386-tdep.h"
39#include "i387-tdep.h"
60a6eeb6 40#include "solib-svr4.h"
a28109e0 41#include "bsd-uthread.h"
005328e3 42
5d93ae8c
MK
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. */
53static const int i386obsd_page_size = 4096;
54
377d9ebd 55/* Return whether the frame preceding NEXT_FRAME corresponds to an
911bc6ee 56 OpenBSD sigtramp routine. */
5d93ae8c
MK
57
58static int
911bc6ee 59i386obsd_sigtramp_p (struct frame_info *next_frame)
5d93ae8c 60{
911bc6ee 61 CORE_ADDR pc = frame_pc_unwind (next_frame);
5d93ae8c
MK
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 };
c822af0c 69 size_t buflen = sizeof sigreturn;
911bc6ee 70 char *name, *buf;
5d93ae8c 71
911bc6ee
MK
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)
5d93ae8c
MK
81 return 0;
82
9c8e3411 83 /* Allocate buffer. */
c822af0c 84 buf = alloca (buflen);
9c8e3411
MK
85
86 /* If we can't read the instructions at START_PC, return zero. */
c822af0c 87 if (!safe_frame_unwind_memory (next_frame, start_pc + 0x0a, buf, buflen))
5d93ae8c
MK
88 return 0;
89
90 /* Check for sigreturn(2). */
c822af0c 91 if (memcmp (buf, sigreturn, buflen) == 0)
5d93ae8c
MK
92 return 1;
93
9c8e3411 94 /* If we can't read the instructions at START_PC, return zero. */
c822af0c 95 if (!safe_frame_unwind_memory (next_frame, start_pc + 0x14, buf, buflen))
9c8e3411
MK
96 return 0;
97
98 /* Check for sigreturn(2) (again). */
c822af0c 99 if (memcmp (buf, sigreturn, buflen) == 0)
9c8e3411
MK
100 return 1;
101
911bc6ee 102 return 0;
5d93ae8c
MK
103}
104\f
105/* Mapping between the general-purpose registers in `struct reg'
106 format and GDB's register cache layout. */
107
67457012
MK
108/* From <machine/reg.h>. */
109static 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};
005328e3
MK
128
129static void
67457012
MK
130i386obsd_aout_supply_regset (const struct regset *regset,
131 struct regcache *regcache, int regnum,
132 const void *regs, size_t len)
005328e3 133{
9ea75c57 134 const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
67457012
MK
135
136 gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
005328e3 137
67457012
MK
138 i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
139 i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
005328e3
MK
140}
141
49cfa46f 142static const struct regset *
67457012
MK
143i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
144 const char *sect_name,
145 size_t sect_size)
005328e3 146{
67457012 147 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
005328e3 148
67457012
MK
149 /* OpenBSD a.out core dumps don't use seperate register sets for the
150 general-purpose and floating-point registers. */
005328e3 151
67457012
MK
152 if (strcmp (sect_name, ".reg") == 0
153 && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
005328e3 154 {
67457012 155 if (tdep->gregset == NULL)
9ea75c57
MK
156 tdep->gregset =
157 regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL);
67457012 158 return tdep->gregset;
005328e3
MK
159 }
160
67457012 161 return NULL;
005328e3 162}
005328e3
MK
163\f
164
5d93ae8c
MK
165/* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
166CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
167CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
005328e3
MK
168
169/* From <machine/signal.h>. */
a3386186
MK
170int 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};
005328e3 189
a28109e0
MK
190/* From /usr/src/lib/libpthread/arch/i386/uthread_machdep.c. */
191static 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
215static void
216i386obsd_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
258static void
259i386obsd_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
005328e3
MK
304static void
305i386obsd_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
67457012
MK
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
005328e3
MK
317 /* OpenBSD uses -freg-struct-return by default. */
318 tdep->struct_return = reg_struct_return;
319
320 /* OpenBSD uses a different memory layout. */
5d93ae8c
MK
321 tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
322 tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
911bc6ee 323 tdep->sigtramp_p = i386obsd_sigtramp_p;
005328e3
MK
324
325 /* OpenBSD has a `struct sigcontext' that's different from the
f2e7c15d 326 original 4.3 BSD. */
a3386186 327 tdep->sc_reg_offset = i386obsd_sc_reg_offset;
67457012 328 tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
a28109e0
MK
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);
005328e3 333}
60a6eeb6
MK
334
335/* OpenBSD a.out. */
336
337static void
338i386obsd_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
349static void
350i386obsd_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. */
60a6eeb6
MK
361 set_solib_svr4_fetch_link_map_offsets
362 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
363}
67457012
MK
364\f
365
366/* Provide a prototype to silence -Wmissing-prototypes. */
367void _initialize_i386obsd_tdep (void);
005328e3
MK
368
369void
370_initialize_i386obsd_tdep (void)
371{
005328e3
MK
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
05816f70 378 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
60a6eeb6
MK
379 i386obsd_aout_init_abi);
380 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
381 i386obsd_elf_init_abi);
005328e3 382}
This page took 0.270089 seconds and 4 git commands to generate.