GDB (API)
/home/stan/gdb/src/gdb/ppcobsd-nat.c
Go to the documentation of this file.
00001 /* Native-dependent code for OpenBSD/powerpc.
00002 
00003    Copyright (C) 2004-2013 Free Software Foundation, Inc.
00004 
00005    This file is part of GDB.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 3 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00019 
00020 #include "defs.h"
00021 #include "gdbcore.h"
00022 #include "inferior.h"
00023 #include "regcache.h"
00024 
00025 #include "gdb_assert.h"
00026 #include <stddef.h>
00027 #include <sys/types.h>
00028 #include <sys/ptrace.h>
00029 #include <sys/signal.h>
00030 #include <machine/frame.h>
00031 #include <machine/pcb.h>
00032 #include <machine/reg.h>
00033 
00034 #include "ppc-tdep.h"
00035 #include "ppcobsd-tdep.h"
00036 #include "inf-ptrace.h"
00037 #include "bsd-kvm.h"
00038 
00039 /* OpenBSD/powerpc didn't have PT_GETFPREGS/PT_SETFPREGS until release
00040    4.0.  On older releases the floating-point registers are handled by
00041    PT_GETREGS/PT_SETREGS, but fpscr wasn't available..  */
00042 
00043 #ifdef PT_GETFPREGS
00044 
00045 /* Returns true if PT_GETFPREGS fetches this register.  */
00046 
00047 static int
00048 getfpregs_supplies (struct gdbarch *gdbarch, int regnum)
00049 {
00050   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
00051 
00052   /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
00053      point registers.  Traditionally, GDB's register set has still
00054      listed the floating point registers for such machines, so this
00055      code is harmless.  However, the new E500 port actually omits the
00056      floating point registers entirely from the register set --- they
00057      don't even have register numbers assigned to them.
00058 
00059      It's not clear to me how best to update this code, so this assert
00060      will alert the first person to encounter the NetBSD/E500
00061      combination to the problem.  */
00062   gdb_assert (ppc_floating_point_unit_p (gdbarch));
00063 
00064   return ((regnum >= tdep->ppc_fp0_regnum
00065            && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs)
00066           || regnum == tdep->ppc_fpscr_regnum);
00067 }
00068 
00069 #endif /* PT_GETFPREGS */
00070 
00071 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
00072    for all registers.  */
00073 
00074 static void
00075 ppcobsd_fetch_registers (struct target_ops *ops,
00076                          struct regcache *regcache, int regnum)
00077 {
00078   struct reg regs;
00079 
00080   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
00081               (PTRACE_TYPE_ARG3) &regs, 0) == -1)
00082     perror_with_name (_("Couldn't get registers"));
00083 
00084   ppc_supply_gregset (&ppcobsd_gregset, regcache, -1,
00085                       &regs, sizeof regs);
00086 #ifndef PT_GETFPREGS
00087   ppc_supply_fpregset (&ppcobsd_gregset, regcache, -1,
00088                        &regs, sizeof regs);
00089 #endif
00090 
00091 #ifdef PT_GETFPREGS
00092   if (regnum == -1
00093       || getfpregs_supplies (get_regcache_arch (regcache), regnum))
00094     {
00095       struct fpreg fpregs;
00096 
00097       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
00098                   (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
00099         perror_with_name (_("Couldn't get floating point status"));
00100 
00101       ppc_supply_fpregset (&ppcobsd_fpregset, regcache, -1,
00102                            &fpregs, sizeof fpregs);
00103     }
00104 #endif
00105 }
00106 
00107 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
00108    this for all registers.  */
00109 
00110 static void
00111 ppcobsd_store_registers (struct target_ops *ops,
00112                          struct regcache *regcache, int regnum)
00113 {
00114   struct reg regs;
00115 
00116   if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
00117               (PTRACE_TYPE_ARG3) &regs, 0) == -1)
00118     perror_with_name (_("Couldn't get registers"));
00119 
00120   ppc_collect_gregset (&ppcobsd_gregset, regcache,
00121                        regnum, &regs, sizeof regs);
00122 #ifndef PT_GETFPREGS
00123   ppc_collect_fpregset (&ppcobsd_gregset, regcache,
00124                         regnum, &regs, sizeof regs);
00125 #endif
00126 
00127   if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
00128               (PTRACE_TYPE_ARG3) &regs, 0) == -1)
00129     perror_with_name (_("Couldn't write registers"));
00130 
00131 #ifdef PT_GETFPREGS
00132   if (regnum == -1
00133       || getfpregs_supplies (get_regcache_arch (regcache), regnum))
00134     {
00135       struct fpreg fpregs;
00136 
00137       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
00138                   (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
00139         perror_with_name (_("Couldn't get floating point status"));
00140 
00141       ppc_collect_fpregset (&ppcobsd_fpregset, regcache,
00142                             regnum, &fpregs, sizeof fpregs);
00143 
00144       if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
00145                   (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
00146         perror_with_name (_("Couldn't write floating point status"));
00147     }
00148 #endif
00149 }
00150 
00151 
00152 static int
00153 ppcobsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
00154 {
00155   struct gdbarch *gdbarch = get_regcache_arch (regcache);
00156   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
00157   struct switchframe sf;
00158   struct callframe cf;
00159   int i, regnum;
00160 
00161   /* The following is true for OpenBSD 3.7:
00162 
00163      The pcb contains %r1 (the stack pointer) at the point of the
00164      context switch in cpu_switch().  At that point we have a stack
00165      frame as described by `struct switchframe', and below that a call
00166      frame as described by `struct callframe'.  From this information
00167      we reconstruct the register state as it would look when we are in
00168      cpu_switch().  */
00169 
00170   /* The stack pointer shouldn't be zero.  */
00171   if (pcb->pcb_sp == 0)
00172     return 0;
00173 
00174   read_memory (pcb->pcb_sp, (gdb_byte *)&sf, sizeof sf);
00175   regcache_raw_supply (regcache, gdbarch_sp_regnum (gdbarch), &sf.sp);
00176   regcache_raw_supply (regcache, tdep->ppc_cr_regnum, &sf.cr);
00177   regcache_raw_supply (regcache, tdep->ppc_gp0_regnum + 2, &sf.fixreg2);
00178   for (i = 0, regnum = tdep->ppc_gp0_regnum + 13; i < 19; i++, regnum++)
00179     regcache_raw_supply (regcache, regnum, &sf.fixreg[i]);
00180 
00181   read_memory (sf.sp, (gdb_byte *)&cf, sizeof cf);
00182   regcache_raw_supply (regcache, gdbarch_pc_regnum (gdbarch), &cf.lr);
00183   regcache_raw_supply (regcache, tdep->ppc_gp0_regnum + 30, &cf.r30);
00184   regcache_raw_supply (regcache, tdep->ppc_gp0_regnum + 31, &cf.r31);
00185 
00186   return 1;
00187 }
00188 
00189 
00190 /* Provide a prototype to silence -Wmissing-prototypes.  */
00191 void _initialize_ppcobsd_nat (void);
00192 
00193 void
00194 _initialize_ppcobsd_nat (void)
00195 {
00196   struct target_ops *t;
00197 
00198   /* Add in local overrides.  */
00199   t = inf_ptrace_target ();
00200   t->to_fetch_registers = ppcobsd_fetch_registers;
00201   t->to_store_registers = ppcobsd_store_registers;
00202   add_target (t);
00203 
00204   /* General-purpose registers.  */
00205   ppcobsd_reg_offsets.r0_offset = offsetof (struct reg, gpr);
00206   ppcobsd_reg_offsets.gpr_size = 4;
00207   ppcobsd_reg_offsets.xr_size = 4;
00208   ppcobsd_reg_offsets.pc_offset = offsetof (struct reg, pc);
00209   ppcobsd_reg_offsets.ps_offset = offsetof (struct reg, ps);
00210   ppcobsd_reg_offsets.cr_offset = offsetof (struct reg, cnd);
00211   ppcobsd_reg_offsets.lr_offset = offsetof (struct reg, lr);
00212   ppcobsd_reg_offsets.ctr_offset = offsetof (struct reg, cnt);
00213   ppcobsd_reg_offsets.xer_offset = offsetof (struct reg, xer);
00214   ppcobsd_reg_offsets.mq_offset = offsetof (struct reg, mq);
00215 
00216   /* Floating-point registers.  */
00217   ppcobsd_reg_offsets.f0_offset = offsetof (struct reg, fpr);
00218   ppcobsd_reg_offsets.fpscr_offset = -1;
00219 #ifdef PT_GETFPREGS
00220   ppcobsd_fpreg_offsets.f0_offset = offsetof (struct fpreg, fpr);
00221   ppcobsd_fpreg_offsets.fpscr_offset = offsetof (struct fpreg, fpscr);
00222   ppcobsd_fpreg_offsets.fpscr_size = 4;
00223 #endif
00224 
00225   /* AltiVec registers.  */
00226   ppcobsd_reg_offsets.vr0_offset = offsetof (struct vreg, vreg);
00227   ppcobsd_reg_offsets.vscr_offset = offsetof (struct vreg, vscr);
00228   ppcobsd_reg_offsets.vrsave_offset = offsetof (struct vreg, vrsave);
00229 
00230   /* Support debugging kernel virtual memory images.  */
00231   bsd_kvm_add_target (ppcobsd_supply_pcb);
00232 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines