1/* Target-dependent code for Motorola 68000 BSD's. 2 3 Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20#include "defs.h" 21#include "arch-utils.h" 22#include "frame.h" 23#include "osabi.h" 24#include "regcache.h" 25#include "regset.h" 26#include "trad-frame.h" 27#include "tramp-frame.h" 28 29#include "gdb_assert.h" 30#include "gdb_string.h" 31 32#include "m68k-tdep.h" 33#include "solib-svr4.h" 34 35/* Core file support. */ 36 37/* Sizeof `struct reg' in <machine/reg.h>. */ 38#define M68KBSD_SIZEOF_GREGS (18 * 4) 39 40/* Sizeof `struct fpreg' in <machine/reg.h. */ 41#define M68KBSD_SIZEOF_FPREGS (((8 * 3) + 3) * 4) 42 43int 44m68kbsd_fpreg_offset (int regnum) 45{ 46 int fp_len = TYPE_LENGTH (gdbarch_register_type (current_gdbarch, regnum)); 47 48 if (regnum >= M68K_FPC_REGNUM) 49 return 8 * fp_len + (regnum - M68K_FPC_REGNUM) * 4; 50 51 return (regnum - M68K_FP0_REGNUM) * fp_len; 52} 53 54/* Supply register REGNUM from the buffer specified by FPREGS and LEN 55 in the floating-point register set REGSET to register cache 56 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 57 58static void 59m68kbsd_supply_fpregset (const struct regset *regset, 60 struct regcache *regcache, 61 int regnum, const void *fpregs, size_t len) 62{ 63 const gdb_byte *regs = fpregs; 64 int i; 65 66 gdb_assert (len >= M68KBSD_SIZEOF_FPREGS); 67 68 for (i = M68K_FP0_REGNUM; i <= M68K_PC_REGNUM; i++) 69 { 70 if (regnum == i || regnum == -1) 71 regcache_raw_supply (regcache, i, regs + m68kbsd_fpreg_offset (i)); 72 } 73} 74 75/* Supply register REGNUM from the buffer specified by GREGS and LEN 76 in the general-purpose register set REGSET to register cache 77 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 78 79static void 80m68kbsd_supply_gregset (const struct regset *regset, 81 struct regcache *regcache, 82 int regnum, const void *gregs, size_t len) 83{ 84 const gdb_byte *regs = gregs; 85 int i; 86 87 gdb_assert (len >= M68KBSD_SIZEOF_GREGS); 88 89 for (i = M68K_D0_REGNUM; i <= M68K_PC_REGNUM; i++) 90 { 91 if (regnum == i || regnum == -1) 92 regcache_raw_supply (regcache, i, regs + i * 4); 93 } 94 95 if (len >= M68KBSD_SIZEOF_GREGS + M68KBSD_SIZEOF_FPREGS) 96 { 97 regs += M68KBSD_SIZEOF_GREGS; 98 len -= M68KBSD_SIZEOF_GREGS; 99 m68kbsd_supply_fpregset (regset, regcache, regnum, regs, len); 100 } 101} 102 103/* Motorola 68000 register sets. */ 104 105static struct regset m68kbsd_gregset = 106{ 107 NULL, 108 m68kbsd_supply_gregset 109}; 110 111static struct regset m68kbsd_fpregset = 112{ 113 NULL, 114 m68kbsd_supply_fpregset 115}; 116 117/* Return the appropriate register set for the core section identified 118 by SECT_NAME and SECT_SIZE. */ 119 120static const struct regset * 121m68kbsd_regset_from_core_section (struct gdbarch *gdbarch, 122 const char *sect_name, size_t sect_size) 123{ 124 if (strcmp (sect_name, ".reg") == 0 && sect_size >= M68KBSD_SIZEOF_GREGS) 125 return &m68kbsd_gregset; 126 127 if (strcmp (sect_name, ".reg2") == 0 && sect_size >= M68KBSD_SIZEOF_FPREGS) 128 return &m68kbsd_fpregset; 129 130 return NULL; 131} 132 133 134/* Signal trampolines. */ 135 136static void 137m68kobsd_sigtramp_cache_init (const struct tramp_frame *self, 138 struct frame_info *next_frame, 139 struct trad_frame_cache *this_cache, 140 CORE_ADDR func) 141{ 142 CORE_ADDR addr, base, pc; 143 int regnum; 144 145 base = frame_unwind_register_unsigned (next_frame, M68K_SP_REGNUM); 146 147 /* The 'addql #4,%sp' instruction at offset 8 adjusts the stack 148 pointer. Adjust the frame base accordingly. */ 149 pc = frame_unwind_register_unsigned (next_frame, M68K_PC_REGNUM); 150 if ((pc - func) > 8) 151 base -= 4; 152 153 /* Get frame pointer, stack pointer, program counter and processor 154 state from `struct sigcontext'. */ 155 addr = get_frame_memory_unsigned (next_frame, base + 8, 4); 156 trad_frame_set_reg_addr (this_cache, M68K_FP_REGNUM, addr + 8); 157 trad_frame_set_reg_addr (this_cache, M68K_SP_REGNUM, addr + 12); 158 trad_frame_set_reg_addr (this_cache, M68K_PC_REGNUM, addr + 20); 159 trad_frame_set_reg_addr (this_cache, M68K_PS_REGNUM, addr + 24); 160 161 /* The sc_ap member of `struct sigcontext' points to additional 162 hardware state. Here we find the missing registers. */ 163 addr = get_frame_memory_unsigned (next_frame, addr + 16, 4) + 4; 164 for (regnum = M68K_D0_REGNUM; regnum < M68K_FP_REGNUM; regnum++, addr += 4) 165 trad_frame_set_reg_addr (this_cache, regnum, addr); 166 167 /* Construct the frame ID using the function start. */ 168 trad_frame_set_id (this_cache, frame_id_build (base, func)); 169} 170 171static const struct tramp_frame m68kobsd_sigtramp = { 172 SIGTRAMP_FRAME, 173 2, 174 { 175 { 0x206f, -1 }, { 0x000c, -1}, /* moveal %sp@(12),%a0 */ 176 { 0x4e90, -1 }, /* jsr %a0@ */ 177 { 0x588f, -1 }, /* addql #4,%sp */ 178 { 0x4e41, -1 }, /* trap #1 */ 179 { 0x2f40, -1 }, { 0x0004, -1 }, /* moveal %d0,%sp@(4) */ 180 { 0x7001, -1 }, /* moveq #SYS_exit,%d0 */ 181 { 0x4e40, -1 }, /* trap #0 */ 182 { TRAMP_SENTINEL_INSN, -1 } 183 }, 184 m68kobsd_sigtramp_cache_init 185}; 186 187 188static void 189m68kbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 190{ 191 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 192 193 tdep->jb_pc = 5; 194 tdep->jb_elt_size = 4; 195 196 set_gdbarch_decr_pc_after_break (gdbarch, 2); 197 198 set_gdbarch_regset_from_core_section 199 (gdbarch, m68kbsd_regset_from_core_section); 200} 201 202/* OpenBSD and NetBSD a.out. */ 203 204static void 205m68kbsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 206{ 207 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 208 209 m68kbsd_init_abi (info, gdbarch); 210 211 tdep->struct_return = reg_struct_return; 212 213 tramp_frame_prepend_unwinder (gdbarch, &m68kobsd_sigtramp); 214} 215 216/* NetBSD ELF. */ 217 218static void 219m68kbsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 220{ 221 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 222 223 m68kbsd_init_abi (info, gdbarch); 224 225 /* NetBSD ELF uses the SVR4 ABI. */ 226 m68k_svr4_init_abi (info, gdbarch); 227 tdep->struct_return = pcc_struct_return; 228 229 /* NetBSD ELF uses SVR4-style shared libraries. */ 230 set_solib_svr4_fetch_link_map_offsets 231 (gdbarch, svr4_ilp32_fetch_link_map_offsets); 232} 233 234 235static enum gdb_osabi 236m68kbsd_aout_osabi_sniffer (bfd *abfd) 237{ 238 if (strcmp (bfd_get_target (abfd), "a.out-m68k-netbsd") == 0 239 || strcmp (bfd_get_target (abfd), "a.out-m68k4k-netbsd") == 0) 240 return GDB_OSABI_NETBSD_AOUT; 241 242 return GDB_OSABI_UNKNOWN; 243} 244 245static enum gdb_osabi 246m68kbsd_core_osabi_sniffer (bfd *abfd) 247{ 248 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0) 249 return GDB_OSABI_NETBSD_AOUT; 250 251 return GDB_OSABI_UNKNOWN; 252} 253 254 255/* Provide a prototype to silence -Wmissing-prototypes. */ 256void _initialize_m68kbsd_tdep (void); 257 258void 259_initialize_m68kbsd_tdep (void) 260{ 261 gdbarch_register_osabi_sniffer (bfd_arch_m68k, bfd_target_aout_flavour, 262 m68kbsd_aout_osabi_sniffer); 263 264 /* BFD doesn't set a flavour for NetBSD style a.out core files. */ 265 gdbarch_register_osabi_sniffer (bfd_arch_m68k, bfd_target_unknown_flavour, 266 m68kbsd_core_osabi_sniffer); 267 268 gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_NETBSD_AOUT, 269 m68kbsd_aout_init_abi); 270 gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_NETBSD_ELF, 271 m68kbsd_elf_init_abi); 272} 273