1/* Native-dependent code for OpenBSD/powerpc.
2
3   Copyright (C) 2004-2020 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 "gdbcore.h"
22#include "inferior.h"
23#include "regcache.h"
24
25#include <sys/types.h>
26#include <sys/ptrace.h>
27#include <sys/signal.h>
28#include <machine/frame.h>
29#include <machine/pcb.h>
30#include <machine/reg.h>
31
32#include "ppc-tdep.h"
33#include "ppc-obsd-tdep.h"
34#include "inf-ptrace.h"
35#include "obsd-nat.h"
36#include "bsd-kvm.h"
37
38struct ppc_obsd_nat_target final : public obsd_nat_target
39{
40  void fetch_registers (struct regcache *, int) override;
41  void store_registers (struct regcache *, int) override;
42};
43
44static ppc_obsd_nat_target the_ppc_obsd_nat_target;
45
46/* OpenBSD/powerpc didn't have PT_GETFPREGS/PT_SETFPREGS until release
47   4.0.  On older releases the floating-point registers are handled by
48   PT_GETREGS/PT_SETREGS, but fpscr wasn't available..  */
49
50#ifdef PT_GETFPREGS
51
52/* Returns true if PT_GETFPREGS fetches this register.  */
53
54static int
55getfpregs_supplies (struct gdbarch *gdbarch, int regnum)
56{
57  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
58
59  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
60     point registers.  Traditionally, GDB's register set has still
61     listed the floating point registers for such machines, so this
62     code is harmless.  However, the new E500 port actually omits the
63     floating point registers entirely from the register set --- they
64     don't even have register numbers assigned to them.
65
66     It's not clear to me how best to update this code, so this assert
67     will alert the first person to encounter the NetBSD/E500
68     combination to the problem.  */
69  gdb_assert (ppc_floating_point_unit_p (gdbarch));
70
71  return ((regnum >= tdep->ppc_fp0_regnum
72           && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs)
73	  || regnum == tdep->ppc_fpscr_regnum);
74}
75
76#endif /* PT_GETFPREGS */
77
78/* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
79   for all registers.  */
80
81void
82ppc_obsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
83{
84  struct reg regs;
85  pid_t pid = regcache->ptid ().pid ();
86
87  if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
88    perror_with_name (_("Couldn't get registers"));
89
90  ppc_supply_gregset (&ppcobsd_gregset, regcache, -1,
91		      &regs, sizeof regs);
92#ifndef PT_GETFPREGS
93  ppc_supply_fpregset (&ppcobsd_gregset, regcache, -1,
94		       &regs, sizeof regs);
95#endif
96
97#ifdef PT_GETFPREGS
98  if (regnum == -1
99      || getfpregs_supplies (regcache->arch (), regnum))
100    {
101      struct fpreg fpregs;
102
103      if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
104	perror_with_name (_("Couldn't get floating point status"));
105
106      ppc_supply_fpregset (&ppcobsd_fpregset, regcache, -1,
107			   &fpregs, sizeof fpregs);
108    }
109#endif
110}
111
112/* Store register REGNUM back into the inferior.  If REGNUM is -1, do
113   this for all registers.  */
114
115void
116ppc_obsd_nat_target::store_registers (struct regcache *regcache, int regnum)
117{
118  struct reg regs;
119  pid_t pid = regcache->ptid ().pid ();
120
121  if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
122    perror_with_name (_("Couldn't get registers"));
123
124  ppc_collect_gregset (&ppcobsd_gregset, regcache,
125		       regnum, &regs, sizeof regs);
126#ifndef PT_GETFPREGS
127  ppc_collect_fpregset (&ppcobsd_gregset, regcache,
128			regnum, &regs, sizeof regs);
129#endif
130
131  if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
132    perror_with_name (_("Couldn't write registers"));
133
134#ifdef PT_GETFPREGS
135  if (regnum == -1
136      || getfpregs_supplies (regcache->arch (), regnum))
137    {
138      struct fpreg fpregs;
139
140      if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
141	perror_with_name (_("Couldn't get floating point status"));
142
143      ppc_collect_fpregset (&ppcobsd_fpregset, regcache,
144			    regnum, &fpregs, sizeof fpregs);
145
146      if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
147	perror_with_name (_("Couldn't write floating point status"));
148    }
149#endif
150}
151
152
153static int
154ppcobsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
155{
156  struct gdbarch *gdbarch = regcache->arch ();
157  struct gdbarch_tdep *tdep = 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
190void _initialize_ppcobsd_nat ();
191void
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