GDB: S12Z: new function s12z_extract_return_value
[external/binutils.git] / gdb / riscv-linux-nat.c
1 /* Native-dependent code for GNU/Linux RISC-V.
2    Copyright (C) 2018 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 #include "defs.h"
20 #include "regcache.h"
21 #include "gregset.h"
22 #include "linux-nat.h"
23 #include "riscv-tdep.h"
24
25 #include "elf/common.h"
26
27 #include <sys/ptrace.h>
28
29 /* RISC-V Linux native additions to the default linux support.  */
30
31 class riscv_linux_nat_target final : public linux_nat_target
32 {
33 public:
34   /* Add our register access methods.  */
35   void fetch_registers (struct regcache *regcache, int regnum) override;
36   void store_registers (struct regcache *regcache, int regnum) override;
37 };
38
39 static riscv_linux_nat_target the_riscv_linux_nat_target;
40
41 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
42    from regset GREGS into REGCACHE.  */
43
44 static void
45 supply_gregset_regnum (struct regcache *regcache, const prgregset_t *gregs,
46                        int regnum)
47 {
48   int i;
49   const elf_greg_t *regp = *gregs;
50
51   if (regnum == -1)
52     {
53       /* We only support the integer registers and PC here.  */
54       for (i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++)
55         regcache->raw_supply (i, regp + i);
56
57       /* GDB stores PC in reg 32.  Linux kernel stores it in reg 0.  */
58       regcache->raw_supply (32, regp + 0);
59
60       /* Fill the inaccessible zero register with zero.  */
61       regcache->raw_supply_zeroed (0);
62     }
63   else if (regnum == RISCV_ZERO_REGNUM)
64     regcache->raw_supply_zeroed (0);
65   else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM)
66     regcache->raw_supply (regnum, regp + regnum);
67   else if (regnum == RISCV_PC_REGNUM)
68     regcache->raw_supply (32, regp + 0);
69 }
70
71 /* Copy all general purpose registers from regset GREGS into REGCACHE.  */
72
73 void
74 supply_gregset (struct regcache *regcache, const prgregset_t *gregs)
75 {
76   supply_gregset_regnum (regcache, gregs, -1);
77 }
78
79 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
80    from regset FPREGS into REGCACHE.  */
81
82 static void
83 supply_fpregset_regnum (struct regcache *regcache, const prfpregset_t *fpregs,
84                         int regnum)
85 {
86   int i;
87
88   if (regnum == -1)
89     {
90       /* We only support the FP registers and FCSR here.  */
91       for (i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++)
92         regcache->raw_supply (i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]);
93
94       regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
95     }
96   else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
97     regcache->raw_supply (regnum,
98                           &fpregs->__d.__f[regnum - RISCV_FIRST_FP_REGNUM]);
99   else if (regnum == RISCV_CSR_FCSR_REGNUM)
100     regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
101 }
102
103 /* Copy all floating point registers from regset FPREGS into REGCACHE.  */
104
105 void
106 supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs)
107 {
108   supply_fpregset_regnum (regcache, fpregs, -1);
109 }
110
111 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
112    from REGCACHE into regset GREGS.  */
113
114 void
115 fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum)
116 {
117   elf_greg_t *regp = *gregs;
118
119   if (regnum == -1)
120     {
121       /* We only support the integer registers and PC here.  */
122       for (int i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++)
123         regcache->raw_collect (i, regp + i);
124
125       regcache->raw_collect (32, regp + 0);
126     }
127   else if (regnum == RISCV_ZERO_REGNUM)
128     /* Nothing to do here.  */
129     ;
130   else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM)
131     regcache->raw_collect (regnum, regp + regnum);
132   else if (regnum == RISCV_PC_REGNUM)
133     regcache->raw_collect (32, regp + 0);
134 }
135
136 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
137    from REGCACHE into regset FPREGS.  */
138
139 void
140 fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs,
141                int regnum)
142 {
143   if (regnum == -1)
144     {
145       /* We only support the FP registers and FCSR here.  */
146       for (int i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++)
147         regcache->raw_collect (i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]);
148
149       regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
150     }
151   else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
152     regcache->raw_collect (regnum,
153                            &fpregs->__d.__f[regnum - RISCV_FIRST_FP_REGNUM]);
154   else if (regnum == RISCV_CSR_FCSR_REGNUM)
155     regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
156 }
157
158 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target
159    into REGCACHE using PTRACE_GETREGSET.  */
160
161 void
162 riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
163 {
164   int tid;
165
166   tid = get_ptrace_pid (regcache->ptid());
167
168   if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM)
169       || (regnum == -1))
170     {
171       struct iovec iov;
172       elf_gregset_t regs;
173
174       iov.iov_base = &regs;
175       iov.iov_len = sizeof (regs);
176
177       if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS,
178                   (PTRACE_TYPE_ARG3) &iov) == -1)
179         perror_with_name (_("Couldn't get registers"));
180       else
181         supply_gregset_regnum (regcache, &regs, regnum);
182     }
183
184   if ((regnum >= RISCV_FIRST_FP_REGNUM
185        && regnum <= RISCV_LAST_FP_REGNUM)
186       || (regnum == RISCV_CSR_FCSR_REGNUM)
187       || (regnum == -1))
188     {
189       struct iovec iov;
190       elf_fpregset_t regs;
191
192       iov.iov_base = &regs;
193       iov.iov_len = sizeof (regs);
194
195       if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET,
196                   (PTRACE_TYPE_ARG3) &iov) == -1)
197         perror_with_name (_("Couldn't get registers"));
198       else
199         supply_fpregset_regnum (regcache, &regs, regnum);
200     }
201
202   if ((regnum == RISCV_CSR_MISA_REGNUM)
203       || (regnum == -1))
204     {
205       /* TODO: Need to add a ptrace call for this.  */
206       regcache->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM);
207     }
208
209   /* Access to other CSRs has potential security issues, don't support them for
210      now.  */
211 }
212
213 /* Store REGNUM (or all registers if REGNUM == -1) to the target
214    from REGCACHE using PTRACE_SETREGSET.  */
215
216 void
217 riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
218 {
219   int tid;
220
221   tid = get_ptrace_pid (regcache->ptid ());
222
223   if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM)
224       || (regnum == -1))
225     {
226       struct iovec iov;
227       elf_gregset_t regs;
228
229       iov.iov_base = &regs;
230       iov.iov_len = sizeof (regs);
231
232       if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS,
233                   (PTRACE_TYPE_ARG3) &iov) == -1)
234         perror_with_name (_("Couldn't get registers"));
235       else
236         {
237           fill_gregset (regcache, &regs, regnum);
238
239           if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS,
240                       (PTRACE_TYPE_ARG3) &iov) == -1)
241             perror_with_name (_("Couldn't set registers"));
242         }
243     }
244
245   if ((regnum >= RISCV_FIRST_FP_REGNUM
246        && regnum <= RISCV_LAST_FP_REGNUM)
247       || (regnum == RISCV_CSR_FCSR_REGNUM)
248       || (regnum == -1))
249     {
250       struct iovec iov;
251       elf_fpregset_t regs;
252
253       iov.iov_base = &regs;
254       iov.iov_len = sizeof (regs);
255
256       if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET,
257                   (PTRACE_TYPE_ARG3) &iov) == -1)
258         perror_with_name (_("Couldn't get registers"));
259       else
260         {
261           fill_fpregset (regcache, &regs, regnum);
262
263           if (ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET,
264                       (PTRACE_TYPE_ARG3) &iov) == -1)
265             perror_with_name (_("Couldn't set registers"));
266         }
267     }
268
269   /* Access to CSRs has potential security issues, don't support them for
270      now.  */
271 }
272
273 /* Initialize RISC-V Linux native support.  */
274
275 void
276 _initialize_riscv_linux_nat (void)
277 {
278   /* Register the target.  */
279   linux_target = &the_riscv_linux_nat_target;
280   add_inf_child_target (&the_riscv_linux_nat_target);
281 }