1/* Target-dependent code for FreeBSD/sparc64. 2 3 Copyright 2003, 2004 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 2 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, write to the Free Software 19 Foundation, Inc., 59 Temple Place - Suite 330, 20 Boston, MA 02111-1307, USA. */ 21 22#include "defs.h" 23#include "frame.h" 24#include "frame-unwind.h" 25#include "gdbcore.h" 26#include "osabi.h" 27#include "regcache.h" 28#include "regset.h" 29#include "target.h" 30#include "trad-frame.h" 31 32#include "gdb_assert.h" 33#include "gdb_string.h" 34 35#include "sparc64-tdep.h" 36 37/* From <machine/reg.h>. */ 38const struct sparc_gregset sparc64fbsd_gregset = 39{ 40 26 * 8, /* "tstate" */ 41 25 * 8, /* %pc */ 42 24 * 8, /* %npc */ 43 28 * 8, /* %y */ 44 16 * 8, /* %fprs */ 45 -1, 46 1 * 8, /* %g1 */ 47 -1, /* %l0 */ 48 8 /* sizeof (%y) */ 49}; 50 51 52static void 53sparc64fbsd_supply_gregset (const struct regset *regset, 54 struct regcache *regcache, 55 int regnum, const void *gregs, size_t len) 56{ 57 sparc64_supply_gregset (regset->descr, regcache, regnum, gregs); 58} 59 60static void 61sparc64fbsd_supply_fpregset (const struct regset *regset, 62 struct regcache *regcache, 63 int regnum, const void *fpregs, size_t len) 64{ 65 sparc64_supply_fpregset (regcache, regnum, fpregs); 66} 67 68void 69supply_gregset (const void *gregs) 70{ 71 sparc64_supply_gregset (&sparc64fbsd_gregset, current_regcache, -1, gregs); 72} 73 74void 75supply_fpregset (const void *fpregs) 76{ 77 sparc64_supply_fpregset (current_regcache, -1, fpregs); 78} 79 80void 81fill_gregset (void *gregs, int regnum) 82{ 83 sparc64_collect_gregset (&sparc64fbsd_gregset, current_regcache, regnum, 84 gregs); 85} 86 87void 88fill_fpregset (void *fpregs, int regnum) 89{ 90 sparc64_collect_fpregset (current_regcache, regnum, fpregs); 91} 92 93 94/* Signal trampolines. */ 95 96static int 97sparc64fbsd_pc_in_sigtramp (CORE_ADDR pc, char *name) 98{ 99 return (name && strcmp (name, "__sigtramp") == 0); 100} 101 102static struct sparc_frame_cache * 103sparc64fbsd_sigtramp_frame_cache (struct frame_info *next_frame, 104 void **this_cache) 105{ 106 struct sparc_frame_cache *cache; 107 CORE_ADDR addr, mcontext_addr, sp; 108 LONGEST fprs; 109 int regnum; 110 111 if (*this_cache) 112 return *this_cache; 113 114 cache = sparc_frame_cache (next_frame, this_cache); 115 gdb_assert (cache == *this_cache); 116 117 cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); 118 119 /* The third argument is a pointer to an instance of `ucontext_t', 120 which has a member `uc_mcontext' that contains the saved 121 registers. */ 122 addr = frame_unwind_register_unsigned (next_frame, SPARC_O2_REGNUM); 123 mcontext_addr = addr + 64; 124 125 /* The following registers travel in the `mc_local' slots of 126 `mcontext_t'. */ 127 addr = mcontext_addr + 16 * 8; 128 cache->saved_regs[SPARC64_FPRS_REGNUM].addr = addr + 0 * 8; 129 cache->saved_regs[SPARC64_FSR_REGNUM].addr = addr + 1 * 8; 130 131 /* The following registers travel in the `mc_in' slots of 132 `mcontext_t'. */ 133 addr = mcontext_addr + 24 * 8; 134 cache->saved_regs[SPARC64_NPC_REGNUM].addr = addr + 0 * 8; 135 cache->saved_regs[SPARC64_PC_REGNUM].addr = addr + 1 * 8; 136 cache->saved_regs[SPARC64_STATE_REGNUM].addr = addr + 2 * 8; 137 cache->saved_regs[SPARC64_Y_REGNUM].addr = addr + 4 * 8; 138 139 /* The `global' and `out' registers travel in the `mc_global' and 140 `mc_out' slots of `mcontext_t', except for %g0. Since %g0 is 141 always zero, keep the identity encoding. */ 142 for (regnum = SPARC_G1_REGNUM, addr = mcontext_addr + 8; 143 regnum <= SPARC_O7_REGNUM; regnum++, addr += 8) 144 cache->saved_regs[regnum].addr = addr; 145 146 /* The `local' and `in' registers have been saved in the register 147 save area. */ 148 addr = cache->saved_regs[SPARC_SP_REGNUM].addr; 149 sp = get_frame_memory_unsigned (next_frame, addr, 8); 150 for (regnum = SPARC_L0_REGNUM, addr = sp + BIAS; 151 regnum <= SPARC_I7_REGNUM; regnum++, addr += 8) 152 cache->saved_regs[regnum].addr = addr; 153 154 /* The floating-point registers are only saved if the FEF bit in 155 %fprs has been set. */ 156 157#define FPRS_FEF (1 << 2) 158 159 addr = cache->saved_regs[SPARC64_FPRS_REGNUM].addr; 160 fprs = get_frame_memory_unsigned (next_frame, addr, 8); 161 if (fprs & FPRS_FEF) 162 { 163 for (regnum = SPARC_F0_REGNUM, addr = mcontext_addr + 32 * 8; 164 regnum <= SPARC_F31_REGNUM; regnum++, addr += 4) 165 cache->saved_regs[regnum].addr = addr; 166 167 for (regnum = SPARC64_F32_REGNUM; 168 regnum <= SPARC64_F62_REGNUM; regnum++, addr += 8) 169 cache->saved_regs[regnum].addr = addr; 170 } 171 172 return cache; 173} 174 175static void 176sparc64fbsd_sigtramp_frame_this_id (struct frame_info *next_frame, 177 void **this_cache, 178 struct frame_id *this_id) 179{ 180 struct sparc_frame_cache *cache = 181 sparc64fbsd_sigtramp_frame_cache (next_frame, this_cache); 182 183 (*this_id) = frame_id_build (cache->base, cache->pc); 184} 185 186static void 187sparc64fbsd_sigtramp_frame_prev_register (struct frame_info *next_frame, 188 void **this_cache, 189 int regnum, int *optimizedp, 190 enum lval_type *lvalp, 191 CORE_ADDR *addrp, 192 int *realnump, void *valuep) 193{ 194 struct sparc_frame_cache *cache = 195 sparc64fbsd_sigtramp_frame_cache (next_frame, this_cache); 196 197 trad_frame_prev_register (next_frame, cache->saved_regs, regnum, 198 optimizedp, lvalp, addrp, realnump, valuep); 199} 200 201static const struct frame_unwind sparc64fbsd_sigtramp_frame_unwind = 202{ 203 SIGTRAMP_FRAME, 204 sparc64fbsd_sigtramp_frame_this_id, 205 sparc64fbsd_sigtramp_frame_prev_register 206}; 207 208static const struct frame_unwind * 209sparc64fbsd_sigtramp_frame_sniffer (struct frame_info *next_frame) 210{ 211 CORE_ADDR pc = frame_pc_unwind (next_frame); 212 char *name; 213 214 find_pc_partial_function (pc, &name, NULL, NULL); 215 if (sparc64fbsd_pc_in_sigtramp (pc, name)) 216 return &sparc64fbsd_sigtramp_frame_unwind; 217 218 return NULL; 219} 220 221 222static void 223sparc64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 224{ 225 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 226 227 tdep->gregset = XMALLOC (struct regset); 228 tdep->gregset->descr = &sparc64fbsd_gregset; 229 tdep->gregset->supply_regset = sparc64fbsd_supply_gregset; 230 tdep->sizeof_gregset = 256; 231 232 tdep->fpregset = XMALLOC (struct regset); 233 tdep->fpregset->supply_regset = sparc64fbsd_supply_fpregset; 234 tdep->sizeof_fpregset = 272; 235 236 set_gdbarch_pc_in_sigtramp (gdbarch, sparc64fbsd_pc_in_sigtramp); 237 frame_unwind_append_sniffer (gdbarch, sparc64fbsd_sigtramp_frame_sniffer); 238 239 sparc64_init_abi (info, gdbarch); 240} 241 242/* Provide a prototype to silence -Wmissing-prototypes. */ 243void _initialize_sparc64fbsd_tdep (void); 244 245void 246_initialize_sparc64fbsd_tdep (void) 247{ 248 gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9, 249 GDB_OSABI_FREEBSD_ELF, sparc64fbsd_init_abi); 250} 251