/* Target-dependent code for NetBSD/sh. Copyright (C) 2002-2019 Free Software Foundation, Inc. Contributed by Wasabi Systems, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "defs.h" #include "gdbcore.h" #include "inferior.h" #include "regcache.h" #include "regset.h" #include "value.h" #include "osabi.h" #include "trad-frame.h" #include "tramp-frame.h" #include "common/gdb_assert.h" #include "solib-svr4.h" #include "sh-tdep.h" #include "sh-nbsd-tdep.h" #include "nbsd-tdep.h" /* Convert a register number into an offset into a ptrace register structure. */ static const struct sh_corefile_regmap gregs_table[] = { {R0_REGNUM, 20 * 4}, {R0_REGNUM + 1, 19 * 4}, {R0_REGNUM + 2, 18 * 4}, {R0_REGNUM + 3, 17 * 4}, {R0_REGNUM + 4, 16 * 4}, {R0_REGNUM + 5, 15 * 4}, {R0_REGNUM + 6, 14 * 4}, {R0_REGNUM + 7, 13 * 4}, {R0_REGNUM + 8, 12 * 4}, {R0_REGNUM + 9, 11 * 4}, {R0_REGNUM + 10, 10 * 4}, {R0_REGNUM + 11, 9 * 4}, {R0_REGNUM + 12, 8 * 4}, {R0_REGNUM + 13, 7 * 4}, {R0_REGNUM + 14, 6 * 4}, {R0_REGNUM + 15, 5 * 4}, {PC_REGNUM, 0 * 4}, {SR_REGNUM, 1 * 4}, {PR_REGNUM, 2 * 4}, {MACH_REGNUM, 3 * 4}, {MACL_REGNUM, 4 * 4}, {GBR_REGNUM, 21 * 4}, {-1 /* Terminator. */, 0} }; #define REGSx16(base) \ {(base), 0}, \ {(base) + 1, 4}, \ {(base) + 2, 8}, \ {(base) + 3, 12}, \ {(base) + 4, 16}, \ {(base) + 5, 20}, \ {(base) + 6, 24}, \ {(base) + 7, 28}, \ {(base) + 8, 32}, \ {(base) + 9, 36}, \ {(base) + 10, 40}, \ {(base) + 11, 44}, \ {(base) + 12, 48}, \ {(base) + 13, 52}, \ {(base) + 14, 56}, \ {(base) + 15, 60} /* Convert an FPU register number into an offset into a ptrace register structure. */ static const struct sh_corefile_regmap fpregs_table[] = { REGSx16 (FR0_REGNUM), /* XXX: REGSx16(XF0_REGNUM) omitted. */ {FPSCR_REGNUM, 128}, {FPUL_REGNUM, 132}, {-1 /* Terminator. */, 0} }; /* From . */ static const int shnbsd_mc_reg_offset[] = { (20 * 4), /* r0 */ (19 * 4), /* r1 */ (18 * 4), /* r2 */ (17 * 4), /* r3 */ (16 * 4), /* r4 */ (15 * 4), /* r5 */ (14 * 4), /* r6 */ (13 * 4), /* r7 */ (12 * 4), /* r8 */ (11 * 4), /* r9 */ (10 * 4), /* r10 */ ( 9 * 4), /* r11 */ ( 8 * 4), /* r12 */ ( 7 * 4), /* r13 */ ( 6 * 4), /* r14 */ (21 * 4), /* r15/sp */ ( 1 * 4), /* pc */ ( 5 * 4), /* pr */ ( 0 * 4), /* gbr */ -1, ( 4 * 4), /* mach */ ( 3 * 4), /* macl */ ( 2 * 4), /* sr */ }; /* SH register sets. */ static void shnbsd_sigtramp_cache_init (const struct tramp_frame *, struct frame_info *, struct trad_frame_cache *, CORE_ADDR); /* The siginfo signal trampoline for NetBSD/sh3 versions 2.0 and later */ static const struct tramp_frame shnbsd_sigtramp_si2 = { SIGTRAMP_FRAME, 2, { { 0x64f3, ULONGEST_MAX }, /* mov r15,r4 */ { 0xd002, ULONGEST_MAX }, /* mov.l .LSYS_setcontext */ { 0xc380, ULONGEST_MAX }, /* trapa #-128 */ { 0xa003, ULONGEST_MAX }, /* bra .Lskip1 */ { 0x0009, ULONGEST_MAX }, /* nop */ { 0x0009, ULONGEST_MAX }, /* nop */ /* .LSYS_setcontext */ { 0x0134, ULONGEST_MAX }, { 0x0000, ULONGEST_MAX }, /* 0x134 */ /* .Lskip1 */ { 0x6403, ULONGEST_MAX }, /* mov r0,r4 */ { 0xd002, ULONGEST_MAX }, /* mov.l .LSYS_exit */ { 0xc380, ULONGEST_MAX }, /* trapa #-128 */ { 0xa003, ULONGEST_MAX }, /* bra .Lskip2 */ { 0x0009, ULONGEST_MAX }, /* nop */ { 0x0009, ULONGEST_MAX }, /* nop */ /* .LSYS_exit */ { 0x0001, ULONGEST_MAX }, { 0x0000, ULONGEST_MAX }, /* 0x1 */ /* .Lskip2 */ { TRAMP_SENTINEL_INSN, ULONGEST_MAX } }, shnbsd_sigtramp_cache_init }; static void shnbsd_sigtramp_cache_init (const struct tramp_frame *self, struct frame_info *next_frame, struct trad_frame_cache *this_cache, CORE_ADDR func) { struct gdbarch *gdbarch = get_frame_arch (next_frame); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); int sp_regnum = gdbarch_sp_regnum (gdbarch); CORE_ADDR sp = get_frame_register_unsigned (next_frame, sp_regnum); CORE_ADDR base; const int *reg_offset; int num_regs; int i; reg_offset = shnbsd_mc_reg_offset; num_regs = ARRAY_SIZE (shnbsd_mc_reg_offset); /* SP already points at the ucontext. */ base = sp; /* offsetof(ucontext_t, uc_mcontext) == 36 */ base += 36; for (i = 0; i < num_regs; i++) if (reg_offset[i] != -1) trad_frame_set_reg_addr (this_cache, i, base + reg_offset[i]); /* Construct the frame ID using the function start. */ trad_frame_set_id (this_cache, frame_id_build (sp, func)); } static void shnbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); tdep->core_gregmap = (struct sh_corefile_regmap *)gregs_table; tdep->sizeof_gregset = 88; tdep->core_fpregmap = (struct sh_corefile_regmap *)fpregs_table; tdep->sizeof_fpregset = 0; /* XXX */ set_solib_svr4_fetch_link_map_offsets (gdbarch, nbsd_ilp32_solib_svr4_fetch_link_map_offsets); tramp_frame_prepend_unwinder (gdbarch, &shnbsd_sigtramp_si2); } void _initialize_shnbsd_tdep (void) { gdbarch_register_osabi (bfd_arch_sh, 0, GDB_OSABI_NETBSD, shnbsd_init_abi); }