xref: /netbsd-src/external/gpl3/gdb/dist/gdb/aarch64-netbsd-nat.c (revision 142ea824f95ab686b0e8f15bc602f5512a2e3f8c)
1 /* Native-dependent code for NetBSD/aarch64.
2 
3    Copyright (C) 2017-2018 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 "target.h"
22 
23 #include <sys/types.h>
24 #include <sys/ptrace.h>
25 
26 #include <machine/frame.h>
27 #include <machine/pcb.h>
28 
29 #include "netbsd-nat.h"
30 #include "aarch64-tdep.h"
31 #include "aarch64-netbsd-tdep.h"
32 #include "regcache.h"
33 #include "gdbcore.h"
34 #include "bsd-kvm.h"
35 #include "inf-ptrace.h"
36 
37 struct aarch64_nbsd_nat_target final : public nbsd_nat_target
38 {
39   void fetch_registers (struct regcache *, int) override;
40   void store_registers (struct regcache *, int) override;
41 };
42 
43 static aarch64_nbsd_nat_target the_aarch64_nbsd_nat_target;
44 
45 /* Determine if PT_GETREGS fetches REGNUM.  */
46 
47 static bool
getregs_supplies(struct gdbarch * gdbarch,int regnum)48 getregs_supplies (struct gdbarch *gdbarch, int regnum)
49 {
50   return (regnum >= AARCH64_X0_REGNUM && regnum <= AARCH64_CPSR_REGNUM);
51 }
52 
53 /* Determine if PT_GETFPREGS fetches REGNUM.  */
54 
55 static bool
getfpregs_supplies(struct gdbarch * gdbarch,int regnum)56 getfpregs_supplies (struct gdbarch *gdbarch, int regnum)
57 {
58   return (regnum >= AARCH64_V0_REGNUM && regnum <= AARCH64_FPCR_REGNUM);
59 }
60 
61 void
fetch_registers(struct regcache * regcache,int regnum)62 aarch64_nbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
63 {
64   ptid_t ptid = regcache->ptid ();
65   pid_t pid = ptid.pid ();
66   int lwp = ptid.lwp ();
67 
68   struct gdbarch *gdbarch = regcache->arch ();
69   if (regnum == -1 || getregs_supplies (gdbarch, regnum))
70     {
71       struct reg regs;
72 
73       if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, lwp) == -1)
74 	perror_with_name (_("Couldn't get registers"));
75 
76       regcache_supply_regset (&aarch64_nbsd_gregset, regcache, regnum, &regs,
77 			       sizeof (regs));
78     }
79 
80   if (regnum == -1 || getfpregs_supplies (gdbarch, regnum))
81     {
82       struct fpreg fpregs;
83 
84       if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, lwp) == -1)
85 	perror_with_name (_("Couldn't get floating point status"));
86 
87       regcache_supply_regset (&aarch64_nbsd_fpregset, regcache, regnum, &fpregs,
88 			       sizeof (fpregs));
89     }
90 }
91 
92 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
93    this for all registers.  */
94 
95 void
store_registers(struct regcache * regcache,int regnum)96 aarch64_nbsd_nat_target::store_registers (struct regcache *regcache, int regnum)
97 {
98   ptid_t ptid = regcache->ptid ();
99   pid_t pid = ptid.pid ();
100   int lwp = ptid.lwp ();
101 
102   struct gdbarch *gdbarch = regcache->arch ();
103   if (regnum == -1 || getregs_supplies (gdbarch, regnum))
104     {
105       struct reg regs;
106 
107       if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, lwp) == -1)
108 	perror_with_name (_("Couldn't get registers"));
109 
110       regcache_collect_regset (&aarch64_nbsd_gregset, regcache,regnum, &regs,
111 			       sizeof (regs));
112 
113       if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, lwp) == -1)
114 	perror_with_name (_("Couldn't write registers"));
115     }
116 
117   if (regnum == -1 || getfpregs_supplies (gdbarch, regnum))
118     {
119       struct fpreg fpregs;
120 
121       if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, lwp) == -1)
122 	perror_with_name (_("Couldn't get floating point status"));
123 
124       regcache_collect_regset (&aarch64_nbsd_fpregset, regcache,regnum, &fpregs,
125 				sizeof (fpregs));
126 
127       if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, lwp) == -1)
128 	perror_with_name (_("Couldn't write floating point status"));
129     }
130 }
131 
132 static int
aarch64_nbsd_supply_pcb(struct regcache * regcache,struct pcb * pcb)133 aarch64_nbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
134 {
135   struct trapframe tf;
136   int i;
137 
138   /* The following is true for NetBSD/arm64:
139 
140      The pcb contains the frame pointer at the point of the context
141      switch in cpu_switchto().  At that point we have a stack frame as
142      described by `struct trapframe', which has the following layout:
143 
144      x0..x30
145      sp
146      pc
147      spsr
148      tpidr
149 
150      This accounts for all callee-saved registers specified by the psABI.
151      From this information we reconstruct the register state as it would
152      look when we just returned from cpu_switchto().
153 
154      For kernel core dumps, dumpsys() builds a fake trapframe for us. */
155 
156   /* The trapframe pointer shouldn't be zero.  */
157   if (pcb->pcb_tf == 0)
158     return 0;
159 
160   /* Read the stack frame, and check its validity.  */
161   read_memory ((uintptr_t)pcb->pcb_tf, (gdb_byte *) &tf, sizeof tf);
162 
163   for (i = 0; i <= 30; i++)
164     {
165       regcache->raw_supply (AARCH64_X0_REGNUM + i, &tf.tf_reg[i]);
166     }
167   regcache->raw_supply (AARCH64_SP_REGNUM, &tf.tf_sp);
168   regcache->raw_supply (AARCH64_PC_REGNUM, &tf.tf_pc);
169 
170   regcache->raw_supply (AARCH64_FPCR_REGNUM, &pcb->pcb_fpregs.fpcr);
171   regcache->raw_supply (AARCH64_FPSR_REGNUM, &pcb->pcb_fpregs.fpsr);
172 
173   return 1;
174 }
175 
176 void
_initialize_aarch64_nbsd_nat()177 _initialize_aarch64_nbsd_nat ()
178 {
179   add_inf_child_target (&the_aarch64_nbsd_nat_target);
180 
181   /* Support debugging kernel virtual memory images.  */
182   bsd_kvm_add_target (aarch64_nbsd_supply_pcb);
183 }
184