xref: /openbsd-src/gnu/usr.bin/binutils/gdb/i386obsd-tdep.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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 "frame-unwind.h"
28 #include "gdbcore.h"
29 #include "regcache.h"
30 #include "regset.h"
31 #include "symtab.h"
32 #include "objfiles.h"
33 #include "osabi.h"
34 #include "target.h"
35 #include "trad-frame.h"
36 
37 #include "gdb_assert.h"
38 #include "gdb_string.h"
39 
40 #include "i386-tdep.h"
41 #include "i387-tdep.h"
42 #include "solib-svr4.h"
43 #include "bsd-uthread.h"
44 
45 /* Support for signal handlers.  */
46 
47 /* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
48    in virtual memory.  The randomness makes it somewhat tricky to
49    detect it, but fortunately we can rely on the fact that the start
50    of the sigtramp routine is page-aligned.  By the way, the mapping
51    is read-only, so you cannot place a breakpoint in the signal
52    trampoline.  */
53 
54 /* Default page size.  */
55 static const int i386obsd_page_size = 4096;
56 
57 /* Offset for sigreturn(2).  */
58 static const int i386obsd_sigreturn_offset[] = {
59   0x0a,				/* OpenBSD 3.2 */
60   0x14,				/* OpenBSD 3.6 */
61   0x3a,				/* OpenBSD 3.8 */
62   -1
63 };
64 
65 /* Return whether the frame preceding NEXT_FRAME corresponds to an
66    OpenBSD sigtramp routine.  */
67 
68 static int
69 i386obsd_sigtramp_p (struct frame_info *next_frame)
70 {
71   CORE_ADDR pc = frame_pc_unwind (next_frame);
72   CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
73   const char sigreturn[] =
74   {
75     0xb8,
76     0x67, 0x00, 0x00, 0x00,	/* movl $SYS_sigreturn, %eax */
77     0xcd, 0x80			/* int $0x80 */
78   };
79   size_t buflen = sizeof sigreturn;
80   const int *offset;
81   char *name, *buf;
82 
83   /* If the function has a valid symbol name, it isn't a
84      trampoline.  */
85   find_pc_partial_function (pc, &name, NULL, NULL);
86   if (name != NULL)
87     return 0;
88 
89   /* If the function lives in a valid section (even without a starting
90      point) it isn't a trampoline.  */
91   if (find_pc_section (pc) != NULL)
92     return 0;
93 
94   /* Allocate buffer.  */
95   buf = alloca (buflen);
96 
97   /* Loop over all offsets.  */
98   for (offset = i386obsd_sigreturn_offset; *offset != -1; offset++)
99     {
100       /* If we can't read the instructions, return zero.  */
101       if (!safe_frame_unwind_memory (next_frame, start_pc + *offset,
102 				     buf, buflen))
103 	return 0;
104 
105       /* Check for sigreturn(2).  */
106       if (memcmp (buf, sigreturn, buflen) == 0)
107 	return 1;
108     }
109 
110   return 0;
111 }
112 
113 /* Mapping between the general-purpose registers in `struct reg'
114    format and GDB's register cache layout.  */
115 
116 /* From <machine/reg.h>.  */
117 static int i386obsd_r_reg_offset[] =
118 {
119   0 * 4,			/* %eax */
120   1 * 4,			/* %ecx */
121   2 * 4,			/* %edx */
122   3 * 4,			/* %ebx */
123   4 * 4,			/* %esp */
124   5 * 4,			/* %ebp */
125   6 * 4,			/* %esi */
126   7 * 4,			/* %edi */
127   8 * 4,			/* %eip */
128   9 * 4,			/* %eflags */
129   10 * 4,			/* %cs */
130   11 * 4,			/* %ss */
131   12 * 4,			/* %ds */
132   13 * 4,			/* %es */
133   14 * 4,			/* %fs */
134   15 * 4			/* %gs */
135 };
136 
137 static void
138 i386obsd_aout_supply_regset (const struct regset *regset,
139 			     struct regcache *regcache, int regnum,
140 			     const void *regs, size_t len)
141 {
142   const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
143 
144   gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
145 
146   i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
147   i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
148 }
149 
150 static const struct regset *
151 i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
152 					const char *sect_name,
153 					size_t sect_size)
154 {
155   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
156 
157   /* OpenBSD a.out core dumps don't use seperate register sets for the
158      general-purpose and floating-point registers.  */
159 
160   if (strcmp (sect_name, ".reg") == 0
161       && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
162     {
163       if (tdep->gregset == NULL)
164         tdep->gregset =
165 	  regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL);
166       return tdep->gregset;
167     }
168 
169   return NULL;
170 }
171 
172 
173 /* Sigtramp routine location for OpenBSD 3.1 and earlier releases.  */
174 CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
175 CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
176 
177 /* From <machine/signal.h>.  */
178 int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
179 {
180   10 * 4,			/* %eax */
181   9 * 4,			/* %ecx */
182   8 * 4,			/* %edx */
183   7 * 4,			/* %ebx */
184   14 * 4,			/* %esp */
185   6 * 4,			/* %ebp */
186   5 * 4,			/* %esi */
187   4 * 4,			/* %edi */
188   11 * 4,			/* %eip */
189   13 * 4,			/* %eflags */
190   12 * 4,			/* %cs */
191   15 * 4,			/* %ss */
192   3 * 4,			/* %ds */
193   2 * 4,			/* %es */
194   1 * 4,			/* %fs */
195   0 * 4				/* %gs */
196 };
197 
198 /* From /usr/src/lib/libpthread/arch/i386/uthread_machdep.c.  */
199 static int i386obsd_uthread_reg_offset[] =
200 {
201   11 * 4,			/* %eax */
202   10 * 4,			/* %ecx */
203   9 * 4,			/* %edx */
204   8 * 4,			/* %ebx */
205   -1,				/* %esp */
206   6 * 4,			/* %ebp */
207   5 * 4,			/* %esi */
208   4 * 4,			/* %edi */
209   12 * 4,			/* %eip */
210   -1,				/* %eflags */
211   13 * 4,			/* %cs */
212   -1,				/* %ss */
213   3 * 4,			/* %ds */
214   2 * 4,			/* %es */
215   1 * 4,			/* %fs */
216   0 * 4				/* %gs */
217 };
218 
219 /* Offset within the thread structure where we can find the saved
220    stack pointer (%esp).  */
221 #define I386OBSD_UTHREAD_ESP_OFFSET	176
222 
223 static void
224 i386obsd_supply_uthread (struct regcache *regcache,
225 			 int regnum, CORE_ADDR addr,
226 			 int ctx_offset)
227 {
228   CORE_ADDR sp_addr = addr + ctx_offset;
229   CORE_ADDR sp = 0;
230   char buf[4];
231   int i;
232 
233   gdb_assert (regnum >= -1);
234 
235   /* if ctx_offset is 0 use old fixed offset */
236   if (ctx_offset == 0)
237     sp_addr += I386OBSD_UTHREAD_ESP_OFFSET;
238 
239   if (regnum == -1 || regnum == I386_ESP_REGNUM)
240     {
241       int offset;
242 
243       /* Fetch stack pointer from thread structure.  */
244       sp = read_memory_unsigned_integer (sp_addr, 4);
245 
246       /* Adjust the stack pointer such that it looks as if we just
247          returned from _thread_machdep_switch.  */
248       offset = i386obsd_uthread_reg_offset[I386_EIP_REGNUM] + 4;
249       store_unsigned_integer (buf, 4, sp + offset);
250       regcache_raw_supply (regcache, I386_ESP_REGNUM, buf);
251     }
252 
253   for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
254     {
255       if (i386obsd_uthread_reg_offset[i] != -1
256 	  && (regnum == -1 || regnum == i))
257 	{
258 	  /* Fetch stack pointer from thread structure (if we didn't
259              do so already).  */
260 	  if (sp == 0)
261 	    sp = read_memory_unsigned_integer (sp_addr, 4);
262 
263 	  /* Read the saved register from the stack frame.  */
264 	  read_memory (sp + i386obsd_uthread_reg_offset[i], buf, 4);
265 	  regcache_raw_supply (regcache, i, buf);
266 	}
267     }
268 }
269 
270 static void
271 i386obsd_collect_uthread (const struct regcache *regcache,
272 			  int regnum, CORE_ADDR addr,
273 			  int ctx_offset)
274 {
275   CORE_ADDR sp_addr = addr + ctx_offset;
276   CORE_ADDR sp = 0;
277   char buf[4];
278   int i;
279 
280   gdb_assert (regnum >= -1);
281 
282   /* if ctx_offset is 0 use old fixed offset */
283   if (ctx_offset == 0)
284     sp_addr += I386OBSD_UTHREAD_ESP_OFFSET;
285 
286   if (regnum == -1 || regnum == I386_ESP_REGNUM)
287     {
288       int offset;
289 
290       /* Calculate the stack pointer (frame pointer) that will be
291          stored into the thread structure.  */
292       offset = i386obsd_uthread_reg_offset[I386_EIP_REGNUM] + 4;
293       regcache_raw_collect (regcache, I386_ESP_REGNUM, buf);
294       sp = extract_unsigned_integer (buf, 4) - offset;
295 
296       /* Store the stack pointer.  */
297       write_memory_unsigned_integer (sp_addr, 4, sp);
298 
299       /* The stack pointer was (potentially) modified.  Make sure we
300          build a proper stack frame.  */
301       regnum = -1;
302     }
303 
304   for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
305     {
306       if (i386obsd_uthread_reg_offset[i] != -1
307 	  && (regnum == -1 || regnum == i))
308 	{
309 	  /* Fetch stack pointer from thread structure (if we didn't
310              calculate it already).  */
311 	  if (sp == 0)
312 	    sp = read_memory_unsigned_integer (sp_addr, 4);
313 
314 	  /* Write the register into the stack frame.  */
315 	  regcache_raw_collect (regcache, i, buf);
316 	  write_memory (sp + i386obsd_uthread_reg_offset[i], buf, 4);
317 	}
318     }
319 }
320 
321 /* Kernel debugging support.  */
322 
323 /* From <machine/frame.h>.  Note that %esp and %ess are only saved in
324    a trap frame when entering the kernel from user space.  */
325 static int i386obsd_tf_reg_offset[] =
326 {
327   10 * 4,			/* %eax */
328   9 * 4,			/* %ecx */
329   8 * 4,			/* %edx */
330   7 * 4,			/* %ebx */
331   -1,				/* %esp */
332   6 * 4,			/* %ebp */
333   5 * 4,			/* %esi */
334   4 * 4,			/* %edi */
335   13 * 4,			/* %eip */
336   15 * 4,			/* %eflags */
337   14 * 4,			/* %cs */
338   -1,				/* %ss */
339   3 * 4,			/* %ds */
340   2 * 4,			/* %es */
341   0 * 4,			/* %fs */
342   1 * 4				/* %gs */
343 };
344 
345 static struct trad_frame_cache *
346 i386obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache)
347 {
348   struct trad_frame_cache *cache;
349   CORE_ADDR func, sp, addr;
350   ULONGEST cs;
351   char *name;
352   int i;
353 
354   if (*this_cache)
355     return *this_cache;
356 
357   cache = trad_frame_cache_zalloc (next_frame);
358   *this_cache = cache;
359 
360   func = frame_func_unwind (next_frame);
361   sp = frame_unwind_register_unsigned (next_frame, I386_ESP_REGNUM);
362 
363   find_pc_partial_function (func, &name, NULL, NULL);
364   if (name && strncmp (name, "Xintr", 5) == 0)
365     addr = sp + 8;		/* It's an interrupt frame.  */
366   else if (name && strcmp (name, "alltraps") == 0)
367     addr = sp + 4;		/* It's a trap frame.  */
368   else if (name && strcmp (name, "calltrap") == 0)
369     addr = sp + 4;		/* It's a trap frame with debug symbols.  */
370   else
371     addr = sp;
372 
373   for (i = 0; i < ARRAY_SIZE (i386obsd_tf_reg_offset); i++)
374     if (i386obsd_tf_reg_offset[i] != -1)
375       trad_frame_set_reg_addr (cache, i, addr + i386obsd_tf_reg_offset[i]);
376 
377   /* Read %cs from trap frame.  */
378   addr += i386obsd_tf_reg_offset[I386_CS_REGNUM];
379   cs = read_memory_unsigned_integer (addr, 4);
380   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
381     {
382       /* Trap from user space; terminate backtrace.  */
383       trad_frame_set_id (cache, null_frame_id);
384     }
385   else
386     {
387       /* Construct the frame ID using the function start.  */
388       trad_frame_set_id (cache, frame_id_build (sp + 8, func));
389     }
390 
391   return cache;
392 }
393 
394 static void
395 i386obsd_trapframe_this_id (struct frame_info *next_frame,
396 			    void **this_cache, struct frame_id *this_id)
397 {
398   struct trad_frame_cache *cache =
399     i386obsd_trapframe_cache (next_frame, this_cache);
400 
401   trad_frame_get_id (cache, this_id);
402 }
403 
404 static void
405 i386obsd_trapframe_prev_register (struct frame_info *next_frame,
406 				  void **this_cache, int regnum,
407 				  int *optimizedp, enum lval_type *lvalp,
408 				  CORE_ADDR *addrp, int *realnump,
409 				  void *valuep)
410 {
411   struct trad_frame_cache *cache =
412     i386obsd_trapframe_cache (next_frame, this_cache);
413 
414   trad_frame_get_register (cache, next_frame, regnum,
415 			   optimizedp, lvalp, addrp, realnump, valuep);
416 }
417 
418 static int
419 i386obsd_trapframe_sniffer (const struct frame_unwind *self,
420 			    struct frame_info *next_frame,
421 			    void **this_prologue_cache)
422 {
423   ULONGEST cs;
424   char *name;
425 
426   /* Check Current Privilege Level and bail out if we're not executing
427      in kernel space.  */
428   cs = frame_unwind_register_unsigned (next_frame, I386_CS_REGNUM);
429   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
430     return 0;
431 
432   find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL);
433   return (name && (strcmp (name, "calltrap") == 0
434 		   || strcmp (name, "alltraps") == 0
435 		   || strcmp (name, "syscall1") == 0
436 		   || strncmp (name, "Xintr", 5) == 0
437 		   || strncmp (name, "Xsoft", 5) == 0));
438 }
439 
440 static const struct frame_unwind i386obsd_trapframe_unwind = {
441   /* FIXME: kettenis/20051219: This really is more like an interrupt
442      frame, but SIGTRAMP_FRAME would print <signal handler called>,
443      which really is not what we want here.  */
444   NORMAL_FRAME,
445   i386obsd_trapframe_this_id,
446   i386obsd_trapframe_prev_register,
447   NULL,
448   i386obsd_trapframe_sniffer
449 };
450 
451 
452 static void
453 i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
454 {
455   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
456 
457   /* Obviously OpenBSD is BSD-based.  */
458   i386bsd_init_abi (info, gdbarch);
459 
460   /* OpenBSD has a different `struct reg'.  */
461   tdep->gregset_reg_offset = i386obsd_r_reg_offset;
462   tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
463   tdep->sizeof_gregset = 16 * 4;
464 
465   /* OpenBSD uses -freg-struct-return by default.  */
466   tdep->struct_return = reg_struct_return;
467 
468   /* OpenBSD uses a different memory layout.  */
469   tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
470   tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
471   tdep->sigtramp_p = i386obsd_sigtramp_p;
472 
473   /* OpenBSD has a `struct sigcontext' that's different from the
474      original 4.3 BSD.  */
475   tdep->sc_reg_offset = i386obsd_sc_reg_offset;
476   tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
477 
478   /* OpenBSD provides a user-level threads implementation.  */
479   bsd_uthread_set_supply_uthread (gdbarch, i386obsd_supply_uthread);
480   bsd_uthread_set_collect_uthread (gdbarch, i386obsd_collect_uthread);
481 
482   /* Unwind kernel trap frames correctly.  */
483   frame_unwind_prepend_unwinder (gdbarch, &i386obsd_trapframe_unwind);
484 }
485 
486 /* OpenBSD a.out.  */
487 
488 static void
489 i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
490 {
491   i386obsd_init_abi (info, gdbarch);
492 
493   /* OpenBSD a.out has a single register set.  */
494   set_gdbarch_regset_from_core_section
495     (gdbarch, i386obsd_aout_regset_from_core_section);
496 }
497 
498 /* OpenBSD ELF.  */
499 
500 static void
501 i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
502 {
503   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
504 
505   /* It's still OpenBSD.  */
506   i386obsd_init_abi (info, gdbarch);
507 
508   /* But ELF-based.  */
509   i386_elf_init_abi (info, gdbarch);
510 
511   /* OpenBSD ELF uses SVR4-style shared libraries.  */
512   set_gdbarch_in_solib_call_trampoline
513     (gdbarch, generic_in_solib_call_trampoline);
514   set_solib_svr4_fetch_link_map_offsets
515     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
516 }
517 
518 
519 /* Provide a prototype to silence -Wmissing-prototypes.  */
520 void _initialize_i386obsd_tdep (void);
521 
522 void
523 _initialize_i386obsd_tdep (void)
524 {
525   /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
526      indistingushable from NetBSD/i386 a.out binaries, building a GDB
527      that should support both these targets will probably not work as
528      expected.  */
529 #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
530 
531   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
532 			  i386obsd_aout_init_abi);
533   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
534 			  i386obsd_elf_init_abi);
535 }
536