1 /* Native-dependent code for PowerPC's running FreeBSD, for GDB.
2 
3    Copyright (C) 2013 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 "gdb_assert.h"
26 #include <stddef.h>
27 #include <sys/types.h>
28 #include <sys/procfs.h>
29 #include <sys/ptrace.h>
30 #include <sys/signal.h>
31 #include <machine/frame.h>
32 #include <machine/pcb.h>
33 #include <machine/reg.h>
34 
35 #include "fbsd-nat.h"
36 #include "gregset.h"
37 #include "ppc-tdep.h"
38 #include "ppcfbsd-tdep.h"
39 #include "inf-ptrace.h"
40 #include "bsd-kvm.h"
41 
42 /* Fill GDB's register array with the general-purpose register values
43    in *GREGSETP.  */
44 
45 void
supply_gregset(struct regcache * regcache,const gdb_gregset_t * gregsetp)46 supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
47 {
48   const struct regset *regset = ppc_fbsd_gregset (sizeof (long));
49 
50   ppc_supply_gregset (regset, regcache, -1, gregsetp, sizeof (*gregsetp));
51 }
52 
53 /* Fill register REGNO (if a gpr) in *GREGSETP with the value in GDB's
54    register array. If REGNO is -1 do it for all registers.  */
55 
56 void
fill_gregset(const struct regcache * regcache,gdb_gregset_t * gregsetp,int regno)57 fill_gregset (const struct regcache *regcache,
58 	      gdb_gregset_t *gregsetp, int regno)
59 {
60   const struct regset *regset = ppc_fbsd_gregset (sizeof (long));
61 
62   if (regno == -1)
63     memset (gregsetp, 0, sizeof (*gregsetp));
64   ppc_collect_gregset (regset, regcache, regno, gregsetp, sizeof (*gregsetp));
65 }
66 
67 /* Fill GDB's register array with the floating-point register values
68    in *FPREGSETP.  */
69 
70 void
supply_fpregset(struct regcache * regcache,const gdb_fpregset_t * fpregsetp)71 supply_fpregset (struct regcache *regcache, const gdb_fpregset_t * fpregsetp)
72 {
73   const struct regset *regset = ppc_fbsd_fpregset ();
74 
75   ppc_supply_fpregset (regset, regcache, -1,
76 		       fpregsetp, sizeof (*fpregsetp));
77 }
78 
79 /* Fill register REGNO in *FGREGSETP with the value in GDB's
80    register array. If REGNO is -1 do it for all registers.  */
81 
82 void
fill_fpregset(const struct regcache * regcache,gdb_fpregset_t * fpregsetp,int regno)83 fill_fpregset (const struct regcache *regcache,
84 	       gdb_fpregset_t *fpregsetp, int regno)
85 {
86   const struct regset *regset = ppc_fbsd_fpregset ();
87 
88   ppc_collect_fpregset (regset, regcache, regno,
89 			fpregsetp, sizeof (*fpregsetp));
90 }
91 
92 /* Returns true if PT_GETFPREGS fetches this register.  */
93 
94 static int
getfpregs_supplies(struct gdbarch * gdbarch,int regno)95 getfpregs_supplies (struct gdbarch *gdbarch, int regno)
96 {
97   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
98 
99   /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
100 	 point registers.  Traditionally, GDB's register set has still
101 	 listed the floating point registers for such machines, so this
102 	 code is harmless.  However, the new E500 port actually omits the
103 	 floating point registers entirely from the register set --- they
104 	 don't even have register numbers assigned to them.
105 
106 	 It's not clear to me how best to update this code, so this assert
107 	 will alert the first person to encounter the NetBSD/E500
108 	 combination to the problem.  */
109 
110   gdb_assert (ppc_floating_point_unit_p (gdbarch));
111 
112   return ((regno >= tdep->ppc_fp0_regnum
113 	   && regno < tdep->ppc_fp0_regnum + ppc_num_fprs)
114 	  || regno == tdep->ppc_fpscr_regnum);
115 }
116 
117 /* Fetch register REGNO from the child process. If REGNO is -1, do it
118    for all registers.  */
119 
120 static void
ppcfbsd_fetch_inferior_registers(struct target_ops * ops,struct regcache * regcache,int regno)121 ppcfbsd_fetch_inferior_registers (struct target_ops *ops,
122 				  struct regcache *regcache, int regno)
123 {
124   gdb_gregset_t regs;
125 
126   if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
127 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
128     perror_with_name (_("Couldn't get registers"));
129 
130   supply_gregset (regcache, &regs);
131 
132   if (regno == -1 || getfpregs_supplies (get_regcache_arch (regcache), regno))
133     {
134       const struct regset *fpregset = ppc_fbsd_fpregset ();
135       gdb_fpregset_t fpregs;
136 
137       if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
138 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
139 	perror_with_name (_("Couldn't get FP registers"));
140 
141       ppc_supply_fpregset (fpregset, regcache, regno, &fpregs, sizeof fpregs);
142     }
143 }
144 
145 /* Store register REGNO back into the child process. If REGNO is -1,
146    do this for all registers.  */
147 
148 static void
ppcfbsd_store_inferior_registers(struct target_ops * ops,struct regcache * regcache,int regno)149 ppcfbsd_store_inferior_registers (struct target_ops *ops,
150 				  struct regcache *regcache, int regno)
151 {
152   gdb_gregset_t regs;
153 
154   if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
155 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
156     perror_with_name (_("Couldn't get registers"));
157 
158   fill_gregset (regcache, &regs, regno);
159 
160   if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
161 	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
162     perror_with_name (_("Couldn't write registers"));
163 
164   if (regno == -1 || getfpregs_supplies (get_regcache_arch (regcache), regno))
165     {
166       gdb_fpregset_t fpregs;
167 
168       if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
169 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
170 	perror_with_name (_("Couldn't get FP registers"));
171 
172       fill_fpregset (regcache, &fpregs, regno);
173 
174       if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
175 		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
176 	perror_with_name (_("Couldn't set FP registers"));
177     }
178 }
179 
180 /* Architecture specific function that reconstructs the
181    register state from PCB (Process Control Block) and supplies it
182    to REGCACHE.  */
183 
184 static int
ppcfbsd_supply_pcb(struct regcache * regcache,struct pcb * pcb)185 ppcfbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
186 {
187   struct gdbarch *gdbarch = get_regcache_arch (regcache);
188   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
189   int i, regnum;
190 
191   /* The stack pointer shouldn't be zero.  */
192   if (pcb->pcb_sp == 0)
193     return 0;
194 
195   regcache_raw_supply (regcache, gdbarch_sp_regnum (gdbarch), &pcb->pcb_sp);
196   regcache_raw_supply (regcache, tdep->ppc_cr_regnum, &pcb->pcb_cr);
197   regcache_raw_supply (regcache, tdep->ppc_lr_regnum, &pcb->pcb_lr);
198   for (i = 0, regnum = tdep->ppc_gp0_regnum + 14; i < 20; i++, regnum++)
199     regcache_raw_supply (regcache, regnum, &pcb->pcb_context[i]);
200 
201   return 1;
202 }
203 
204 /* Provide a prototype to silence -Wmissing-prototypes.  */
205 
206 void _initialize_ppcfbsd_nat (void);
207 
208 void
_initialize_ppcfbsd_nat(void)209 _initialize_ppcfbsd_nat (void)
210 {
211   struct target_ops *t;
212 
213   /* Add in local overrides.  */
214   t = inf_ptrace_target ();
215   t->to_fetch_registers = ppcfbsd_fetch_inferior_registers;
216   t->to_store_registers = ppcfbsd_store_inferior_registers;
217   t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
218   t->to_find_memory_regions = fbsd_find_memory_regions;
219   t->to_make_corefile_notes = fbsd_make_corefile_notes;
220   add_target (t);
221 
222   /* Support debugging kernel virtual memory images.  */
223   bsd_kvm_add_target (ppcfbsd_supply_pcb);
224 }
225