xtensa-linux-nat.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /* Xtensa GNU/Linux native support.
  2. Copyright (C) 2007-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 "frame.h"
  16. #include "inferior.h"
  17. #include "gdbcore.h"
  18. #include "regcache.h"
  19. #include "target.h"
  20. #include "linux-nat.h"
  21. #include <sys/types.h>
  22. #include <signal.h>
  23. #include <sys/user.h>
  24. #include <sys/ioctl.h>
  25. #include "gdbsupport/gdb_wait.h"
  26. #include <fcntl.h>
  27. #include <sys/procfs.h>
  28. #include "nat/gdb_ptrace.h"
  29. #include <asm/ptrace.h>
  30. #include "gregset.h"
  31. #include "xtensa-tdep.h"
  32. /* Defines ps_err_e, struct ps_prochandle. */
  33. #include "gdb_proc_service.h"
  34. /* Extended register set depends on hardware configs.
  35. Keeping these definitions separately allows to introduce
  36. hardware-specific overlays. */
  37. #include "xtensa-xtregs.c"
  38. class xtensa_linux_nat_target final : public linux_nat_target
  39. {
  40. public:
  41. /* Add our register access methods. */
  42. void fetch_registers (struct regcache *, int) override;
  43. void store_registers (struct regcache *, int) override;
  44. };
  45. static xtensa_linux_nat_target the_xtensa_linux_nat_target;
  46. void
  47. fill_gregset (const struct regcache *regcache,
  48. gdb_gregset_t *gregsetp, int regnum)
  49. {
  50. int i;
  51. xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp;
  52. struct gdbarch *gdbarch = regcache->arch ();
  53. xtensa_gdbarch_tdep *tdep = (xtensa_gdbarch_tdep *) gdbarch_tdep (gdbarch);
  54. if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
  55. regcache->raw_collect (gdbarch_pc_regnum (gdbarch), &regs->pc);
  56. if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1)
  57. regcache->raw_collect (gdbarch_ps_regnum (gdbarch), &regs->ps);
  58. if (regnum == tdep->wb_regnum || regnum == -1)
  59. regcache->raw_collect (tdep->wb_regnum,
  60. &regs->windowbase);
  61. if (regnum == tdep->ws_regnum || regnum == -1)
  62. regcache->raw_collect (tdep->ws_regnum,
  63. &regs->windowstart);
  64. if (regnum == tdep->lbeg_regnum || regnum == -1)
  65. regcache->raw_collect (tdep->lbeg_regnum,
  66. &regs->lbeg);
  67. if (regnum == tdep->lend_regnum || regnum == -1)
  68. regcache->raw_collect (tdep->lend_regnum,
  69. &regs->lend);
  70. if (regnum == tdep->lcount_regnum || regnum == -1)
  71. regcache->raw_collect (tdep->lcount_regnum,
  72. &regs->lcount);
  73. if (regnum == tdep->sar_regnum || regnum == -1)
  74. regcache->raw_collect (tdep->sar_regnum,
  75. &regs->sar);
  76. if (regnum == tdep->threadptr_regnum || regnum == -1)
  77. regcache->raw_collect (tdep->threadptr_regnum,
  78. &regs->threadptr);
  79. if (regnum >=tdep->ar_base
  80. && regnum < tdep->ar_base
  81. + tdep->num_aregs)
  82. regcache->raw_collect (regnum,
  83. &regs->ar[regnum - tdep->ar_base]);
  84. else if (regnum == -1)
  85. {
  86. for (i = 0; i < tdep->num_aregs; ++i)
  87. regcache->raw_collect (tdep->ar_base + i,
  88. &regs->ar[i]);
  89. }
  90. if (regnum >= tdep->a0_base
  91. && regnum < tdep->a0_base + C0_NREGS)
  92. regcache->raw_collect (regnum,
  93. &regs->ar[(4 * regs->windowbase + regnum
  94. - tdep->a0_base)
  95. % tdep->num_aregs]);
  96. else if (regnum == -1)
  97. {
  98. for (i = 0; i < C0_NREGS; ++i)
  99. regcache->raw_collect (tdep->a0_base + i,
  100. (&regs->ar[(4 * regs->windowbase + i)
  101. % tdep->num_aregs]));
  102. }
  103. }
  104. static void
  105. supply_gregset_reg (struct regcache *regcache,
  106. const gdb_gregset_t *gregsetp, int regnum)
  107. {
  108. int i;
  109. xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp;
  110. struct gdbarch *gdbarch = regcache->arch ();
  111. xtensa_gdbarch_tdep *tdep = (xtensa_gdbarch_tdep *) gdbarch_tdep (gdbarch);
  112. if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
  113. regcache->raw_supply (gdbarch_pc_regnum (gdbarch), &regs->pc);
  114. if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1)
  115. regcache->raw_supply (gdbarch_ps_regnum (gdbarch), &regs->ps);
  116. if (regnum == tdep->wb_regnum || regnum == -1)
  117. regcache->raw_supply (tdep->wb_regnum,
  118. &regs->windowbase);
  119. if (regnum == tdep->ws_regnum || regnum == -1)
  120. regcache->raw_supply (tdep->ws_regnum,
  121. &regs->windowstart);
  122. if (regnum == tdep->lbeg_regnum || regnum == -1)
  123. regcache->raw_supply (tdep->lbeg_regnum,
  124. &regs->lbeg);
  125. if (regnum == tdep->lend_regnum || regnum == -1)
  126. regcache->raw_supply (tdep->lend_regnum,
  127. &regs->lend);
  128. if (regnum == tdep->lcount_regnum || regnum == -1)
  129. regcache->raw_supply (tdep->lcount_regnum,
  130. &regs->lcount);
  131. if (regnum == tdep->sar_regnum || regnum == -1)
  132. regcache->raw_supply (tdep->sar_regnum,
  133. &regs->sar);
  134. if (regnum == tdep->threadptr_regnum || regnum == -1)
  135. regcache->raw_supply (tdep->threadptr_regnum,
  136. &regs->threadptr);
  137. if (regnum >=tdep->ar_base
  138. && regnum < tdep->ar_base
  139. + tdep->num_aregs)
  140. regcache->raw_supply (regnum,
  141. &regs->ar[regnum - tdep->ar_base]);
  142. else if (regnum == -1)
  143. {
  144. for (i = 0; i < tdep->num_aregs; ++i)
  145. regcache->raw_supply (tdep->ar_base + i,
  146. &regs->ar[i]);
  147. }
  148. if (regnum >= tdep->a0_base
  149. && regnum < tdep->a0_base + C0_NREGS)
  150. regcache->raw_supply (regnum,
  151. &regs->ar[(4 * regs->windowbase + regnum
  152. - tdep->a0_base)
  153. % tdep->num_aregs]);
  154. else if (regnum == -1)
  155. {
  156. for (i = 0; i < C0_NREGS; ++i)
  157. regcache->raw_supply (tdep->a0_base + i,
  158. &regs->ar[(4 * regs->windowbase + i)
  159. % tdep->num_aregs]);
  160. }
  161. }
  162. void
  163. supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
  164. {
  165. supply_gregset_reg (regcache, gregsetp, -1);
  166. }
  167. void
  168. fill_fpregset (const struct regcache *regcache,
  169. gdb_fpregset_t *fpregsetp, int regnum)
  170. {
  171. return;
  172. }
  173. void
  174. supply_fpregset (struct regcache *regcache,
  175. const gdb_fpregset_t *fpregsetp)
  176. {
  177. return;
  178. }
  179. /* Fetch greg-register(s) from process/thread TID
  180. and store value(s) in GDB's register array. */
  181. static void
  182. fetch_gregs (struct regcache *regcache, int regnum)
  183. {
  184. int tid = regcache->ptid ().lwp ();
  185. gdb_gregset_t regs;
  186. if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
  187. {
  188. perror_with_name (_("Couldn't get registers"));
  189. return;
  190. }
  191. supply_gregset_reg (regcache, &regs, regnum);
  192. }
  193. /* Store greg-register(s) in GDB's register
  194. array into the process/thread specified by TID. */
  195. static void
  196. store_gregs (struct regcache *regcache, int regnum)
  197. {
  198. int tid = regcache->ptid ().lwp ();
  199. gdb_gregset_t regs;
  200. if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
  201. {
  202. perror_with_name (_("Couldn't get registers"));
  203. return;
  204. }
  205. fill_gregset (regcache, &regs, regnum);
  206. if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
  207. {
  208. perror_with_name (_("Couldn't write registers"));
  209. return;
  210. }
  211. }
  212. static int xtreg_lo;
  213. static int xtreg_high;
  214. /* Fetch/Store Xtensa TIE registers. Xtensa GNU/Linux PTRACE
  215. interface provides special requests for this. */
  216. static void
  217. fetch_xtregs (struct regcache *regcache, int regnum)
  218. {
  219. int tid = regcache->ptid ().lwp ();
  220. const xtensa_regtable_t *ptr;
  221. char xtregs [XTENSA_ELF_XTREG_SIZE];
  222. if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0)
  223. perror_with_name (_("Couldn't get extended registers"));
  224. for (ptr = xtensa_regmap_table; ptr->name; ptr++)
  225. if (regnum == ptr->gdb_regnum || regnum == -1)
  226. regcache->raw_supply (ptr->gdb_regnum, xtregs + ptr->ptrace_offset);
  227. }
  228. static void
  229. store_xtregs (struct regcache *regcache, int regnum)
  230. {
  231. int tid = regcache->ptid ().lwp ();
  232. const xtensa_regtable_t *ptr;
  233. char xtregs [XTENSA_ELF_XTREG_SIZE];
  234. if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0)
  235. perror_with_name (_("Couldn't get extended registers"));
  236. for (ptr = xtensa_regmap_table; ptr->name; ptr++)
  237. if (regnum == ptr->gdb_regnum || regnum == -1)
  238. regcache->raw_collect (ptr->gdb_regnum, xtregs + ptr->ptrace_offset);
  239. if (ptrace (PTRACE_SETXTREGS, tid, 0, (long)&xtregs) < 0)
  240. perror_with_name (_("Couldn't write extended registers"));
  241. }
  242. void
  243. xtensa_linux_nat_target::fetch_registers (struct regcache *regcache,
  244. int regnum)
  245. {
  246. if (regnum == -1)
  247. {
  248. fetch_gregs (regcache, regnum);
  249. fetch_xtregs (regcache, regnum);
  250. }
  251. else if ((regnum < xtreg_lo) || (regnum > xtreg_high))
  252. fetch_gregs (regcache, regnum);
  253. else
  254. fetch_xtregs (regcache, regnum);
  255. }
  256. void
  257. xtensa_linux_nat_target::store_registers (struct regcache *regcache,
  258. int regnum)
  259. {
  260. if (regnum == -1)
  261. {
  262. store_gregs (regcache, regnum);
  263. store_xtregs (regcache, regnum);
  264. }
  265. else if ((regnum < xtreg_lo) || (regnum > xtreg_high))
  266. store_gregs (regcache, regnum);
  267. else
  268. store_xtregs (regcache, regnum);
  269. }
  270. /* Called by libthread_db. */
  271. ps_err_e
  272. ps_get_thread_area (struct ps_prochandle *ph,
  273. lwpid_t lwpid, int idx, void **base)
  274. {
  275. xtensa_elf_gregset_t regs;
  276. if (ptrace (PTRACE_GETREGS, lwpid, NULL, &regs) != 0)
  277. return PS_ERR;
  278. /* IDX is the bias from the thread pointer to the beginning of the
  279. thread descriptor. It has to be subtracted due to implementation
  280. quirks in libthread_db. */
  281. *base = (void *) ((char *) regs.threadptr - idx);
  282. return PS_OK;
  283. }
  284. void _initialize_xtensa_linux_nat ();
  285. void
  286. _initialize_xtensa_linux_nat ()
  287. {
  288. const xtensa_regtable_t *ptr;
  289. /* Calculate the number range for extended registers. */
  290. xtreg_lo = 1000000000;
  291. xtreg_high = -1;
  292. for (ptr = xtensa_regmap_table; ptr->name; ptr++)
  293. {
  294. if (ptr->gdb_regnum < xtreg_lo)
  295. xtreg_lo = ptr->gdb_regnum;
  296. if (ptr->gdb_regnum > xtreg_high)
  297. xtreg_high = ptr->gdb_regnum;
  298. }
  299. linux_target = &the_xtensa_linux_nat_target;
  300. add_inf_child_target (&the_xtensa_linux_nat_target);
  301. }