Home | History | Annotate | Line # | Download | only in gdb
      1 /* Native-dependent code for OpenBSD/powerpc.
      2 
      3    Copyright (C) 2004-2024 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 "gdbcore.h"
     21 #include "inferior.h"
     22 #include "regcache.h"
     23 
     24 #include <sys/types.h>
     25 #include <sys/ptrace.h>
     26 #include <sys/signal.h>
     27 #include <machine/frame.h>
     28 #include <machine/pcb.h>
     29 #include <machine/reg.h>
     30 
     31 #include "ppc-tdep.h"
     32 #include "ppc-obsd-tdep.h"
     33 #include "inf-ptrace.h"
     34 #include "obsd-nat.h"
     35 #include "bsd-kvm.h"
     36 
     37 struct ppc_obsd_nat_target final : public obsd_nat_target
     38 {
     39   void fetch_registers (struct regcache *, int) override;
     40   void store_registers (struct regcache *, int) override;
     41 };
     42 
     43 static ppc_obsd_nat_target the_ppc_obsd_nat_target;
     44 
     45 /* OpenBSD/powerpc didn't have PT_GETFPREGS/PT_SETFPREGS until release
     46    4.0.  On older releases the floating-point registers are handled by
     47    PT_GETREGS/PT_SETREGS, but fpscr wasn't available..  */
     48 
     49 #ifdef PT_GETFPREGS
     50 
     51 /* Returns true if PT_GETFPREGS fetches this register.  */
     52 
     53 static int
     54 getfpregs_supplies (struct gdbarch *gdbarch, int regnum)
     55 {
     56   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
     57 
     58   /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
     59      point registers.  Traditionally, GDB's register set has still
     60      listed the floating point registers for such machines, so this
     61      code is harmless.  However, the new E500 port actually omits the
     62      floating point registers entirely from the register set --- they
     63      don't even have register numbers assigned to them.
     64 
     65      It's not clear to me how best to update this code, so this assert
     66      will alert the first person to encounter the NetBSD/E500
     67      combination to the problem.  */
     68   gdb_assert (ppc_floating_point_unit_p (gdbarch));
     69 
     70   return ((regnum >= tdep->ppc_fp0_regnum
     71 	   && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs)
     72 	  || regnum == tdep->ppc_fpscr_regnum);
     73 }
     74 
     75 #endif /* PT_GETFPREGS */
     76 
     77 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
     78    for all registers.  */
     79 
     80 void
     81 ppc_obsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
     82 {
     83   struct reg regs;
     84   pid_t pid = regcache->ptid ().pid ();
     85 
     86   if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
     87     perror_with_name (_("Couldn't get registers"));
     88 
     89   ppc_supply_gregset (&ppcobsd_gregset, regcache, -1,
     90 		      &regs, sizeof regs);
     91 #ifndef PT_GETFPREGS
     92   ppc_supply_fpregset (&ppcobsd_gregset, regcache, -1,
     93 		       &regs, sizeof regs);
     94 #endif
     95 
     96 #ifdef PT_GETFPREGS
     97   if (regnum == -1
     98       || getfpregs_supplies (regcache->arch (), regnum))
     99     {
    100       struct fpreg fpregs;
    101 
    102       if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
    103 	perror_with_name (_("Couldn't get floating point status"));
    104 
    105       ppc_supply_fpregset (&ppcobsd_fpregset, regcache, -1,
    106 			   &fpregs, sizeof fpregs);
    107     }
    108 #endif
    109 }
    110 
    111 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
    112    this for all registers.  */
    113 
    114 void
    115 ppc_obsd_nat_target::store_registers (struct regcache *regcache, int regnum)
    116 {
    117   struct reg regs;
    118   pid_t pid = regcache->ptid ().pid ();
    119 
    120   if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
    121     perror_with_name (_("Couldn't get registers"));
    122 
    123   ppc_collect_gregset (&ppcobsd_gregset, regcache,
    124 		       regnum, &regs, sizeof regs);
    125 #ifndef PT_GETFPREGS
    126   ppc_collect_fpregset (&ppcobsd_gregset, regcache,
    127 			regnum, &regs, sizeof regs);
    128 #endif
    129 
    130   if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
    131     perror_with_name (_("Couldn't write registers"));
    132 
    133 #ifdef PT_GETFPREGS
    134   if (regnum == -1
    135       || getfpregs_supplies (regcache->arch (), regnum))
    136     {
    137       struct fpreg fpregs;
    138 
    139       if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
    140 	perror_with_name (_("Couldn't get floating point status"));
    141 
    142       ppc_collect_fpregset (&ppcobsd_fpregset, regcache,
    143 			    regnum, &fpregs, sizeof fpregs);
    144 
    145       if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
    146 	perror_with_name (_("Couldn't write floating point status"));
    147     }
    148 #endif
    149 }
    150 
    151 
    153 static int
    154 ppcobsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
    155 {
    156   struct gdbarch *gdbarch = regcache->arch ();
    157   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
    158   struct switchframe sf;
    159   struct callframe cf;
    160   int i, regnum;
    161 
    162   /* The following is true for OpenBSD 3.7:
    163 
    164      The pcb contains %r1 (the stack pointer) at the point of the
    165      context switch in cpu_switch().  At that point we have a stack
    166      frame as described by `struct switchframe', and below that a call
    167      frame as described by `struct callframe'.  From this information
    168      we reconstruct the register state as it would look when we are in
    169      cpu_switch().  */
    170 
    171   /* The stack pointer shouldn't be zero.  */
    172   if (pcb->pcb_sp == 0)
    173     return 0;
    174 
    175   read_memory (pcb->pcb_sp, (gdb_byte *)&sf, sizeof sf);
    176   regcache->raw_supply (gdbarch_sp_regnum (gdbarch), &sf.sp);
    177   regcache->raw_supply (tdep->ppc_cr_regnum, &sf.cr);
    178   regcache->raw_supply (tdep->ppc_gp0_regnum + 2, &sf.fixreg2);
    179   for (i = 0, regnum = tdep->ppc_gp0_regnum + 13; i < 19; i++, regnum++)
    180     regcache->raw_supply (regnum, &sf.fixreg[i]);
    181 
    182   read_memory (sf.sp, (gdb_byte *)&cf, sizeof cf);
    183   regcache->raw_supply (gdbarch_pc_regnum (gdbarch), &cf.lr);
    184   regcache->raw_supply (tdep->ppc_gp0_regnum + 30, &cf.r30);
    185   regcache->raw_supply (tdep->ppc_gp0_regnum + 31, &cf.r31);
    186 
    187   return 1;
    188 }
    189 
    190 void _initialize_ppcobsd_nat ();
    191 void
    192 _initialize_ppcobsd_nat ()
    193 {
    194   add_inf_child_target (&the_ppc_obsd_nat_target);
    195 
    196   /* General-purpose registers.  */
    197   ppcobsd_reg_offsets.r0_offset = offsetof (struct reg, gpr);
    198   ppcobsd_reg_offsets.gpr_size = 4;
    199   ppcobsd_reg_offsets.xr_size = 4;
    200   ppcobsd_reg_offsets.pc_offset = offsetof (struct reg, pc);
    201   ppcobsd_reg_offsets.ps_offset = offsetof (struct reg, ps);
    202   ppcobsd_reg_offsets.cr_offset = offsetof (struct reg, cnd);
    203   ppcobsd_reg_offsets.lr_offset = offsetof (struct reg, lr);
    204   ppcobsd_reg_offsets.ctr_offset = offsetof (struct reg, cnt);
    205   ppcobsd_reg_offsets.xer_offset = offsetof (struct reg, xer);
    206   ppcobsd_reg_offsets.mq_offset = offsetof (struct reg, mq);
    207 
    208   /* Floating-point registers.  */
    209   ppcobsd_reg_offsets.f0_offset = offsetof (struct reg, fpr);
    210   ppcobsd_reg_offsets.fpscr_offset = -1;
    211 #ifdef PT_GETFPREGS
    212   ppcobsd_fpreg_offsets.f0_offset = offsetof (struct fpreg, fpr);
    213   ppcobsd_fpreg_offsets.fpscr_offset = offsetof (struct fpreg, fpscr);
    214   ppcobsd_fpreg_offsets.fpscr_size = 4;
    215 #endif
    216 
    217   /* Support debugging kernel virtual memory images.  */
    218   bsd_kvm_add_target (ppcobsd_supply_pcb);
    219 }
    220