riscv-linux-nat.c 9.4 KB

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