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