1130803Smarcel/* Target-dependent code for NetBSD/i386. 2130803Smarcel 3130803Smarcel Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 4130803Smarcel 2003, 2004 598944Sobrien Free Software Foundation, Inc. 698944Sobrien 798944Sobrien This file is part of GDB. 898944Sobrien 998944Sobrien This program is free software; you can redistribute it and/or modify 1098944Sobrien it under the terms of the GNU General Public License as published by 1198944Sobrien the Free Software Foundation; either version 2 of the License, or 1298944Sobrien (at your option) any later version. 1398944Sobrien 1498944Sobrien This program is distributed in the hope that it will be useful, 1598944Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1698944Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1798944Sobrien GNU General Public License for more details. 1898944Sobrien 1998944Sobrien You should have received a copy of the GNU General Public License 2098944Sobrien along with this program; if not, write to the Free Software 2198944Sobrien Foundation, Inc., 59 Temple Place - Suite 330, 2298944Sobrien Boston, MA 02111-1307, USA. */ 2398944Sobrien 2498944Sobrien#include "defs.h" 25130803Smarcel#include "arch-utils.h" 26130803Smarcel#include "gdbcore.h" 27130803Smarcel#include "regcache.h" 28130803Smarcel#include "regset.h" 29130803Smarcel#include "osabi.h" 3098944Sobrien 31130803Smarcel#include "gdb_assert.h" 32130803Smarcel#include "gdb_string.h" 33130803Smarcel 34130803Smarcel#include "i386-tdep.h" 35130803Smarcel#include "i387-tdep.h" 36130803Smarcel#include "nbsd-tdep.h" 37130803Smarcel#include "solib-svr4.h" 38130803Smarcel 39130803Smarcel/* From <machine/reg.h>. */ 40130803Smarcelstatic int i386nbsd_r_reg_offset[] = 4198944Sobrien{ 42130803Smarcel 0 * 4, /* %eax */ 43130803Smarcel 1 * 4, /* %ecx */ 44130803Smarcel 2 * 4, /* %edx */ 45130803Smarcel 3 * 4, /* %ebx */ 46130803Smarcel 4 * 4, /* %esp */ 47130803Smarcel 5 * 4, /* %ebp */ 48130803Smarcel 6 * 4, /* %esi */ 49130803Smarcel 7 * 4, /* %edi */ 50130803Smarcel 8 * 4, /* %eip */ 51130803Smarcel 9 * 4, /* %eflags */ 52130803Smarcel 10 * 4, /* %cs */ 53130803Smarcel 11 * 4, /* %ss */ 54130803Smarcel 12 * 4, /* %ds */ 55130803Smarcel 13 * 4, /* %es */ 56130803Smarcel 14 * 4, /* %fs */ 57130803Smarcel 15 * 4 /* %gs */ 58130803Smarcel}; 59130803Smarcel 60130803Smarcelstatic void 61130803Smarceli386nbsd_aout_supply_regset (const struct regset *regset, 62130803Smarcel struct regcache *regcache, int regnum, 63130803Smarcel const void *regs, size_t len) 64130803Smarcel{ 65130803Smarcel const struct gdbarch_tdep *tdep = regset->descr; 66130803Smarcel 67130803Smarcel gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE); 68130803Smarcel 69130803Smarcel i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset); 70130803Smarcel i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset); 7198944Sobrien} 72130803Smarcel 73130803Smarcelstatic const struct regset * 74130803Smarceli386nbsd_aout_regset_from_core_section (struct gdbarch *gdbarch, 75130803Smarcel const char *sect_name, 76130803Smarcel size_t sect_size) 77130803Smarcel{ 78130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 79130803Smarcel 80130803Smarcel /* NetBSD a.out core dumps don't use seperate register sets for the 81130803Smarcel general-purpose and floating-point registers. */ 82130803Smarcel 83130803Smarcel if (strcmp (sect_name, ".reg") == 0 84130803Smarcel && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE) 85130803Smarcel { 86130803Smarcel if (tdep->gregset == NULL) 87130803Smarcel { 88130803Smarcel tdep->gregset = XMALLOC (struct regset); 89130803Smarcel tdep->gregset->descr = tdep; 90130803Smarcel tdep->gregset->supply_regset = i386nbsd_aout_supply_regset; 91130803Smarcel } 92130803Smarcel return tdep->gregset; 93130803Smarcel } 94130803Smarcel 95130803Smarcel return NULL; 96130803Smarcel} 97130803Smarcel 98130803Smarcel/* Under NetBSD/i386, signal handler invocations can be identified by the 99130803Smarcel designated code sequence that is used to return from a signal handler. 100130803Smarcel In particular, the return address of a signal handler points to the 101130803Smarcel following code sequence: 102130803Smarcel 103130803Smarcel leal 0x10(%esp), %eax 104130803Smarcel pushl %eax 105130803Smarcel pushl %eax 106130803Smarcel movl $0x127, %eax # __sigreturn14 107130803Smarcel int $0x80 108130803Smarcel 109130803Smarcel Each instruction has a unique encoding, so we simply attempt to match 110130803Smarcel the instruction the PC is pointing to with any of the above instructions. 111130803Smarcel If there is a hit, we know the offset to the start of the designated 112130803Smarcel sequence and can then check whether we really are executing in the 113130803Smarcel signal trampoline. If not, -1 is returned, otherwise the offset from the 114130803Smarcel start of the return sequence is returned. */ 115130803Smarcel#define RETCODE_INSN1 0x8d 116130803Smarcel#define RETCODE_INSN2 0x50 117130803Smarcel#define RETCODE_INSN3 0x50 118130803Smarcel#define RETCODE_INSN4 0xb8 119130803Smarcel#define RETCODE_INSN5 0xcd 120130803Smarcel 121130803Smarcel#define RETCODE_INSN2_OFF 4 122130803Smarcel#define RETCODE_INSN3_OFF 5 123130803Smarcel#define RETCODE_INSN4_OFF 6 124130803Smarcel#define RETCODE_INSN5_OFF 11 125130803Smarcel 126130803Smarcelstatic const unsigned char sigtramp_retcode[] = 127130803Smarcel{ 128130803Smarcel RETCODE_INSN1, 0x44, 0x24, 0x10, 129130803Smarcel RETCODE_INSN2, 130130803Smarcel RETCODE_INSN3, 131130803Smarcel RETCODE_INSN4, 0x27, 0x01, 0x00, 0x00, 132130803Smarcel RETCODE_INSN5, 0x80, 133130803Smarcel}; 134130803Smarcel 135130803Smarcelstatic LONGEST 136130803Smarceli386nbsd_sigtramp_offset (CORE_ADDR pc) 137130803Smarcel{ 138130803Smarcel unsigned char ret[sizeof(sigtramp_retcode)], insn; 139130803Smarcel LONGEST off; 140130803Smarcel int i; 141130803Smarcel 142130803Smarcel if (read_memory_nobpt (pc, &insn, 1) != 0) 143130803Smarcel return -1; 144130803Smarcel 145130803Smarcel switch (insn) 146130803Smarcel { 147130803Smarcel case RETCODE_INSN1: 148130803Smarcel off = 0; 149130803Smarcel break; 150130803Smarcel 151130803Smarcel case RETCODE_INSN2: 152130803Smarcel /* INSN2 and INSN3 are the same. Read at the location of PC+1 153130803Smarcel to determine if we're actually looking at INSN2 or INSN3. */ 154130803Smarcel if (read_memory_nobpt (pc + 1, &insn, 1) != 0) 155130803Smarcel return -1; 156130803Smarcel 157130803Smarcel if (insn == RETCODE_INSN3) 158130803Smarcel off = RETCODE_INSN2_OFF; 159130803Smarcel else 160130803Smarcel off = RETCODE_INSN3_OFF; 161130803Smarcel break; 162130803Smarcel 163130803Smarcel case RETCODE_INSN4: 164130803Smarcel off = RETCODE_INSN4_OFF; 165130803Smarcel break; 166130803Smarcel 167130803Smarcel case RETCODE_INSN5: 168130803Smarcel off = RETCODE_INSN5_OFF; 169130803Smarcel break; 170130803Smarcel 171130803Smarcel default: 172130803Smarcel return -1; 173130803Smarcel } 174130803Smarcel 175130803Smarcel pc -= off; 176130803Smarcel 177130803Smarcel if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0) 178130803Smarcel return -1; 179130803Smarcel 180130803Smarcel if (memcmp (ret, sigtramp_retcode, sizeof (ret)) == 0) 181130803Smarcel return off; 182130803Smarcel 183130803Smarcel return -1; 184130803Smarcel} 185130803Smarcel 186130803Smarcelstatic int 187130803Smarceli386nbsd_pc_in_sigtramp (CORE_ADDR pc, char *name) 188130803Smarcel{ 189130803Smarcel return (nbsd_pc_in_sigtramp (pc, name) 190130803Smarcel || i386nbsd_sigtramp_offset (pc) >= 0); 191130803Smarcel} 192130803Smarcel 193130803Smarcel/* From <machine/signal.h>. */ 194130803Smarcelint i386nbsd_sc_reg_offset[] = 195130803Smarcel{ 196130803Smarcel 10 * 4, /* %eax */ 197130803Smarcel 9 * 4, /* %ecx */ 198130803Smarcel 8 * 4, /* %edx */ 199130803Smarcel 7 * 4, /* %ebx */ 200130803Smarcel 14 * 4, /* %esp */ 201130803Smarcel 6 * 4, /* %ebp */ 202130803Smarcel 5 * 4, /* %esi */ 203130803Smarcel 4 * 4, /* %edi */ 204130803Smarcel 11 * 4, /* %eip */ 205130803Smarcel 13 * 4, /* %eflags */ 206130803Smarcel 12 * 4, /* %cs */ 207130803Smarcel 15 * 4, /* %ss */ 208130803Smarcel 3 * 4, /* %ds */ 209130803Smarcel 2 * 4, /* %es */ 210130803Smarcel 1 * 4, /* %fs */ 211130803Smarcel 0 * 4 /* %gs */ 212130803Smarcel}; 213130803Smarcel 214130803Smarcelstatic void 215130803Smarceli386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 216130803Smarcel{ 217130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 218130803Smarcel 219130803Smarcel /* Obviously NetBSD is BSD-based. */ 220130803Smarcel i386bsd_init_abi (info, gdbarch); 221130803Smarcel 222130803Smarcel /* NetBSD has a different `struct reg'. */ 223130803Smarcel tdep->gregset_reg_offset = i386nbsd_r_reg_offset; 224130803Smarcel tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset); 225130803Smarcel tdep->sizeof_gregset = 16 * 4; 226130803Smarcel 227130803Smarcel /* NetBSD has different signal trampoline conventions. */ 228130803Smarcel set_gdbarch_pc_in_sigtramp (gdbarch, i386nbsd_pc_in_sigtramp); 229130803Smarcel /* FIXME: kettenis/20020906: We should probably provide 230130803Smarcel NetBSD-specific versions of these functions if we want to 231130803Smarcel recognize signal trampolines that live on the stack. */ 232130803Smarcel set_gdbarch_sigtramp_start (gdbarch, NULL); 233130803Smarcel set_gdbarch_sigtramp_end (gdbarch, NULL); 234130803Smarcel 235130803Smarcel /* NetBSD uses -freg-struct-return by default. */ 236130803Smarcel tdep->struct_return = reg_struct_return; 237130803Smarcel 238130803Smarcel /* NetBSD has a `struct sigcontext' that's different from the 239130803Smarcel origional 4.3 BSD. */ 240130803Smarcel tdep->sc_reg_offset = i386nbsd_sc_reg_offset; 241130803Smarcel tdep->sc_num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset); 242130803Smarcel} 243130803Smarcel 244130803Smarcel/* NetBSD a.out. */ 245130803Smarcel 246130803Smarcelstatic void 247130803Smarceli386nbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 248130803Smarcel{ 249130803Smarcel i386nbsd_init_abi (info, gdbarch); 250130803Smarcel 251130803Smarcel /* NetBSD a.out has a single register set. */ 252130803Smarcel set_gdbarch_regset_from_core_section 253130803Smarcel (gdbarch, i386nbsd_aout_regset_from_core_section); 254130803Smarcel} 255130803Smarcel 256130803Smarcel/* NetBSD ELF. */ 257130803Smarcel 258130803Smarcelstatic void 259130803Smarceli386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 260130803Smarcel{ 261130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 262130803Smarcel 263130803Smarcel /* It's still NetBSD. */ 264130803Smarcel i386nbsd_init_abi (info, gdbarch); 265130803Smarcel 266130803Smarcel /* But ELF-based. */ 267130803Smarcel i386_elf_init_abi (info, gdbarch); 268130803Smarcel 269130803Smarcel /* NetBSD ELF uses SVR4-style shared libraries. */ 270130803Smarcel set_gdbarch_in_solib_call_trampoline 271130803Smarcel (gdbarch, generic_in_solib_call_trampoline); 272130803Smarcel set_solib_svr4_fetch_link_map_offsets 273130803Smarcel (gdbarch, svr4_ilp32_fetch_link_map_offsets); 274130803Smarcel 275130803Smarcel /* NetBSD ELF uses -fpcc-struct-return by default. */ 276130803Smarcel tdep->struct_return = pcc_struct_return; 277130803Smarcel} 278130803Smarcel 279130803Smarcelvoid 280130803Smarcel_initialize_i386nbsd_tdep (void) 281130803Smarcel{ 282130803Smarcel gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_AOUT, 283130803Smarcel i386nbsdaout_init_abi); 284130803Smarcel gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_ELF, 285130803Smarcel i386nbsdelf_init_abi); 286130803Smarcel} 287