aarch64-fbsd-nat.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /* Native-dependent code for FreeBSD/aarch64.
  2. Copyright (C) 2017-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 "arch-utils.h"
  16. #include "inferior.h"
  17. #include "regcache.h"
  18. #include "target.h"
  19. #include "nat/aarch64-hw-point.h"
  20. #include <sys/param.h>
  21. #include <sys/ptrace.h>
  22. #include <machine/armreg.h>
  23. #include <machine/reg.h>
  24. #include "fbsd-nat.h"
  25. #include "aarch64-fbsd-tdep.h"
  26. #include "aarch64-nat.h"
  27. #include "inf-ptrace.h"
  28. #if __FreeBSD_version >= 1400005
  29. #define HAVE_DBREG
  30. #include <unordered_set>
  31. #endif
  32. #ifdef HAVE_DBREG
  33. struct aarch64_fbsd_nat_target final
  34. : public aarch64_nat_target<fbsd_nat_target>
  35. #else
  36. struct aarch64_fbsd_nat_target final : public fbsd_nat_target
  37. #endif
  38. {
  39. void fetch_registers (struct regcache *, int) override;
  40. void store_registers (struct regcache *, int) override;
  41. #ifdef HAVE_DBREG
  42. /* Hardware breakpoints and watchpoints. */
  43. bool stopped_by_watchpoint () override;
  44. bool stopped_data_address (CORE_ADDR *) override;
  45. bool stopped_by_hw_breakpoint () override;
  46. bool supports_stopped_by_hw_breakpoint () override;
  47. void post_startup_inferior (ptid_t) override;
  48. void post_attach (int pid) override;
  49. void low_new_fork (ptid_t parent, pid_t child) override;
  50. void low_delete_thread (thread_info *) override;
  51. void low_prepare_to_resume (thread_info *) override;
  52. private:
  53. void probe_debug_regs (int pid);
  54. static bool debug_regs_probed;
  55. #endif
  56. };
  57. static aarch64_fbsd_nat_target the_aarch64_fbsd_nat_target;
  58. bool aarch64_fbsd_nat_target::debug_regs_probed;
  59. /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
  60. for all registers. */
  61. void
  62. aarch64_fbsd_nat_target::fetch_registers (struct regcache *regcache,
  63. int regnum)
  64. {
  65. fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS,
  66. &aarch64_fbsd_gregset);
  67. fetch_register_set<struct fpreg> (regcache, regnum, PT_GETFPREGS,
  68. &aarch64_fbsd_fpregset);
  69. }
  70. /* Store register REGNUM back into the inferior. If REGNUM is -1, do
  71. this for all registers. */
  72. void
  73. aarch64_fbsd_nat_target::store_registers (struct regcache *regcache,
  74. int regnum)
  75. {
  76. store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS,
  77. &aarch64_fbsd_gregset);
  78. store_register_set<struct fpreg> (regcache, regnum, PT_GETFPREGS,
  79. PT_SETFPREGS, &aarch64_fbsd_fpregset);
  80. }
  81. #ifdef HAVE_DBREG
  82. /* Set of threads which need to update debug registers on next resume. */
  83. static std::unordered_set<lwpid_t> aarch64_debug_pending_threads;
  84. /* Implement the "stopped_data_address" target_ops method. */
  85. bool
  86. aarch64_fbsd_nat_target::stopped_data_address (CORE_ADDR *addr_p)
  87. {
  88. siginfo_t siginfo;
  89. struct aarch64_debug_reg_state *state;
  90. if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo))
  91. return false;
  92. /* This must be a hardware breakpoint. */
  93. if (siginfo.si_signo != SIGTRAP
  94. || siginfo.si_code != TRAP_TRACE
  95. || siginfo.si_trapno != EXCP_WATCHPT_EL0)
  96. return false;
  97. const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr;
  98. /* Check if the address matches any watched address. */
  99. state = aarch64_get_debug_reg_state (inferior_ptid.pid ());
  100. return aarch64_stopped_data_address (state, addr_trap, addr_p);
  101. }
  102. /* Implement the "stopped_by_watchpoint" target_ops method. */
  103. bool
  104. aarch64_fbsd_nat_target::stopped_by_watchpoint ()
  105. {
  106. CORE_ADDR addr;
  107. return stopped_data_address (&addr);
  108. }
  109. /* Implement the "stopped_by_hw_breakpoint" target_ops method. */
  110. bool
  111. aarch64_fbsd_nat_target::stopped_by_hw_breakpoint ()
  112. {
  113. siginfo_t siginfo;
  114. struct aarch64_debug_reg_state *state;
  115. if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo))
  116. return false;
  117. /* This must be a hardware breakpoint. */
  118. if (siginfo.si_signo != SIGTRAP
  119. || siginfo.si_code != TRAP_TRACE
  120. || siginfo.si_trapno != EXCP_WATCHPT_EL0)
  121. return false;
  122. return !stopped_by_watchpoint();
  123. }
  124. /* Implement the "supports_stopped_by_hw_breakpoint" target_ops method. */
  125. bool
  126. aarch64_fbsd_nat_target::supports_stopped_by_hw_breakpoint ()
  127. {
  128. return true;
  129. }
  130. /* Fetch the hardware debug register capability information. */
  131. void
  132. aarch64_fbsd_nat_target::probe_debug_regs (int pid)
  133. {
  134. if (!debug_regs_probed)
  135. {
  136. struct dbreg reg;
  137. debug_regs_probed = true;
  138. aarch64_num_bp_regs = 0;
  139. aarch64_num_wp_regs = 0;
  140. if (ptrace(PT_GETDBREGS, pid, (PTRACE_TYPE_ARG3) &reg, 0) == 0)
  141. {
  142. switch (reg.db_debug_ver)
  143. {
  144. case AARCH64_DEBUG_ARCH_V8:
  145. case AARCH64_DEBUG_ARCH_V8_1:
  146. case AARCH64_DEBUG_ARCH_V8_2:
  147. case AARCH64_DEBUG_ARCH_V8_4:
  148. break;
  149. default:
  150. return;
  151. }
  152. aarch64_num_bp_regs = reg.db_nbkpts;
  153. if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM)
  154. {
  155. warning (_("Unexpected number of hardware breakpoint registers"
  156. " reported by ptrace, got %d, expected %d."),
  157. aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM);
  158. aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM;
  159. }
  160. aarch64_num_wp_regs = reg.db_nwtpts;
  161. if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM)
  162. {
  163. warning (_("Unexpected number of hardware watchpoint registers"
  164. " reported by ptrace, got %d, expected %d."),
  165. aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM);
  166. aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM;
  167. }
  168. }
  169. }
  170. }
  171. /* Implement the virtual inf_ptrace_target::post_startup_inferior method. */
  172. void
  173. aarch64_fbsd_nat_target::post_startup_inferior (ptid_t ptid)
  174. {
  175. aarch64_remove_debug_reg_state (ptid.pid ());
  176. probe_debug_regs (ptid.pid ());
  177. fbsd_nat_target::post_startup_inferior (ptid);
  178. }
  179. /* Implement the "post_attach" target_ops method. */
  180. void
  181. aarch64_fbsd_nat_target::post_attach (int pid)
  182. {
  183. aarch64_remove_debug_reg_state (pid);
  184. probe_debug_regs (pid);
  185. fbsd_nat_target::post_attach (pid);
  186. }
  187. /* Implement the virtual fbsd_nat_target::low_new_fork method. */
  188. void
  189. aarch64_fbsd_nat_target::low_new_fork (ptid_t parent, pid_t child)
  190. {
  191. struct aarch64_debug_reg_state *parent_state, *child_state;
  192. /* If there is no parent state, no watchpoints nor breakpoints have
  193. been set, so there is nothing to do. */
  194. parent_state = aarch64_lookup_debug_reg_state (parent.pid ());
  195. if (parent_state == nullptr)
  196. return;
  197. /* The kernel clears debug registers in the new child process after
  198. fork, but GDB core assumes the child inherits the watchpoints/hw
  199. breakpoints of the parent, and will remove them all from the
  200. forked off process. Copy the debug registers mirrors into the
  201. new process so that all breakpoints and watchpoints can be
  202. removed together. */
  203. child_state = aarch64_get_debug_reg_state (child);
  204. *child_state = *parent_state;
  205. }
  206. /* Mark debug register state "dirty" for all threads belonging to the
  207. current inferior. */
  208. void
  209. aarch64_notify_debug_reg_change (ptid_t ptid,
  210. int is_watchpoint, unsigned int idx)
  211. {
  212. for (thread_info *tp : current_inferior ()->non_exited_threads ())
  213. {
  214. if (tp->ptid.lwp_p ())
  215. aarch64_debug_pending_threads.emplace (tp->ptid.lwp ());
  216. }
  217. }
  218. /* Implement the virtual fbsd_nat_target::low_delete_thread method. */
  219. void
  220. aarch64_fbsd_nat_target::low_delete_thread (thread_info *tp)
  221. {
  222. gdb_assert(tp->ptid.lwp_p ());
  223. aarch64_debug_pending_threads.erase (tp->ptid.lwp ());
  224. }
  225. /* Implement the virtual fbsd_nat_target::low_prepare_to_resume method. */
  226. void
  227. aarch64_fbsd_nat_target::low_prepare_to_resume (thread_info *tp)
  228. {
  229. gdb_assert(tp->ptid.lwp_p ());
  230. if (aarch64_debug_pending_threads.erase (tp->ptid.lwp ()) == 0)
  231. return;
  232. struct aarch64_debug_reg_state *state =
  233. aarch64_lookup_debug_reg_state (tp->ptid.pid ());
  234. gdb_assert(state != nullptr);
  235. struct dbreg reg;
  236. memset (&reg, 0, sizeof(reg));
  237. for (int i = 0; i < aarch64_num_bp_regs; i++)
  238. {
  239. reg.db_breakregs[i].dbr_addr = state->dr_addr_bp[i];
  240. reg.db_breakregs[i].dbr_ctrl = state->dr_ctrl_bp[i];
  241. }
  242. for (int i = 0; i < aarch64_num_wp_regs; i++)
  243. {
  244. reg.db_watchregs[i].dbw_addr = state->dr_addr_wp[i];
  245. reg.db_watchregs[i].dbw_ctrl = state->dr_ctrl_wp[i];
  246. }
  247. if (ptrace(PT_SETDBREGS, tp->ptid.lwp (), (PTRACE_TYPE_ARG3) &reg, 0) != 0)
  248. error (_("Failed to set hardware debug registers"));
  249. }
  250. #else
  251. /* A stub that should never be called. */
  252. void
  253. aarch64_notify_debug_reg_change (ptid_t ptid,
  254. int is_watchpoint, unsigned int idx)
  255. {
  256. gdb_assert (true);
  257. }
  258. #endif
  259. void _initialize_aarch64_fbsd_nat ();
  260. void
  261. _initialize_aarch64_fbsd_nat ()
  262. {
  263. #ifdef HAVE_DBREG
  264. aarch64_initialize_hw_point ();
  265. #endif
  266. add_inf_child_target (&the_aarch64_fbsd_nat_target);
  267. }