Home | History | Annotate | Line # | Download | only in gdb
      1      1.1  christos /* Native-dependent code for FreeBSD/aarch64.
      2      1.1  christos 
      3  1.1.1.4  christos    Copyright (C) 2017-2024 Free Software Foundation, Inc.
      4      1.1  christos 
      5      1.1  christos    This file is part of GDB.
      6      1.1  christos 
      7      1.1  christos    This program is free software; you can redistribute it and/or modify
      8      1.1  christos    it under the terms of the GNU General Public License as published by
      9      1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10      1.1  christos    (at your option) any later version.
     11      1.1  christos 
     12      1.1  christos    This program is distributed in the hope that it will be useful,
     13      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15      1.1  christos    GNU General Public License for more details.
     16      1.1  christos 
     17      1.1  christos    You should have received a copy of the GNU General Public License
     18      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19      1.1  christos 
     20  1.1.1.3  christos #include "arch-utils.h"
     21  1.1.1.3  christos #include "inferior.h"
     22  1.1.1.2  christos #include "regcache.h"
     23      1.1  christos #include "target.h"
     24  1.1.1.3  christos #include "nat/aarch64-hw-point.h"
     25      1.1  christos 
     26  1.1.1.3  christos #include "elf/common.h"
     27  1.1.1.3  christos 
     28  1.1.1.3  christos #include <sys/param.h>
     29      1.1  christos #include <sys/ptrace.h>
     30  1.1.1.3  christos #include <machine/armreg.h>
     31      1.1  christos #include <machine/reg.h>
     32      1.1  christos 
     33      1.1  christos #include "fbsd-nat.h"
     34      1.1  christos #include "aarch64-tdep.h"
     35      1.1  christos #include "aarch64-fbsd-tdep.h"
     36  1.1.1.3  christos #include "aarch64-nat.h"
     37      1.1  christos #include "inf-ptrace.h"
     38      1.1  christos 
     39  1.1.1.3  christos #if __FreeBSD_version >= 1400005
     40  1.1.1.3  christos #define	HAVE_DBREG
     41  1.1.1.3  christos 
     42  1.1.1.3  christos #include <unordered_set>
     43  1.1.1.3  christos #endif
     44  1.1.1.3  christos 
     45  1.1.1.3  christos #ifdef HAVE_DBREG
     46  1.1.1.3  christos struct aarch64_fbsd_nat_target final
     47  1.1.1.3  christos   : public aarch64_nat_target<fbsd_nat_target>
     48  1.1.1.3  christos #else
     49      1.1  christos struct aarch64_fbsd_nat_target final : public fbsd_nat_target
     50  1.1.1.3  christos #endif
     51      1.1  christos {
     52      1.1  christos   void fetch_registers (struct regcache *, int) override;
     53      1.1  christos   void store_registers (struct regcache *, int) override;
     54  1.1.1.3  christos 
     55  1.1.1.3  christos   const struct target_desc *read_description () override;
     56  1.1.1.3  christos 
     57  1.1.1.3  christos #ifdef HAVE_DBREG
     58  1.1.1.3  christos   /* Hardware breakpoints and watchpoints.  */
     59  1.1.1.3  christos   bool stopped_by_watchpoint () override;
     60  1.1.1.3  christos   bool stopped_data_address (CORE_ADDR *) override;
     61  1.1.1.3  christos   bool stopped_by_hw_breakpoint () override;
     62  1.1.1.3  christos   bool supports_stopped_by_hw_breakpoint () override;
     63  1.1.1.3  christos 
     64  1.1.1.3  christos   void post_startup_inferior (ptid_t) override;
     65  1.1.1.3  christos   void post_attach (int pid) override;
     66  1.1.1.3  christos 
     67  1.1.1.3  christos   void low_new_fork (ptid_t parent, pid_t child) override;
     68  1.1.1.3  christos   void low_delete_thread (thread_info *) override;
     69  1.1.1.3  christos   void low_prepare_to_resume (thread_info *) override;
     70  1.1.1.3  christos 
     71  1.1.1.3  christos private:
     72  1.1.1.3  christos   void probe_debug_regs (int pid);
     73  1.1.1.3  christos   static bool debug_regs_probed;
     74  1.1.1.3  christos #endif
     75      1.1  christos };
     76      1.1  christos 
     77      1.1  christos static aarch64_fbsd_nat_target the_aarch64_fbsd_nat_target;
     78      1.1  christos 
     79  1.1.1.3  christos /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
     80  1.1.1.3  christos    for all registers.  */
     81      1.1  christos 
     82  1.1.1.3  christos void
     83  1.1.1.3  christos aarch64_fbsd_nat_target::fetch_registers (struct regcache *regcache,
     84  1.1.1.3  christos 					  int regnum)
     85      1.1  christos {
     86  1.1.1.3  christos   fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS,
     87  1.1.1.3  christos 				  &aarch64_fbsd_gregset);
     88  1.1.1.3  christos   fetch_register_set<struct fpreg> (regcache, regnum, PT_GETFPREGS,
     89  1.1.1.3  christos 				    &aarch64_fbsd_fpregset);
     90  1.1.1.3  christos 
     91  1.1.1.3  christos   gdbarch *gdbarch = regcache->arch ();
     92  1.1.1.3  christos   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
     93  1.1.1.3  christos   if (tdep->has_tls ())
     94  1.1.1.3  christos     fetch_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
     95  1.1.1.3  christos 			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
     96      1.1  christos }
     97      1.1  christos 
     98  1.1.1.3  christos /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
     99  1.1.1.3  christos    this for all registers.  */
    100      1.1  christos 
    101  1.1.1.3  christos void
    102  1.1.1.3  christos aarch64_fbsd_nat_target::store_registers (struct regcache *regcache,
    103  1.1.1.3  christos 					  int regnum)
    104      1.1  christos {
    105  1.1.1.3  christos   store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS,
    106  1.1.1.3  christos 				  &aarch64_fbsd_gregset);
    107  1.1.1.3  christos   store_register_set<struct fpreg> (regcache, regnum, PT_GETFPREGS,
    108  1.1.1.3  christos 				    PT_SETFPREGS, &aarch64_fbsd_fpregset);
    109  1.1.1.3  christos 
    110  1.1.1.3  christos   gdbarch *gdbarch = regcache->arch ();
    111  1.1.1.3  christos   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
    112  1.1.1.3  christos   if (tdep->has_tls ())
    113  1.1.1.3  christos     store_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
    114  1.1.1.3  christos 			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
    115      1.1  christos }
    116      1.1  christos 
    117  1.1.1.3  christos /* Implement the target read_description method.  */
    118      1.1  christos 
    119  1.1.1.3  christos const struct target_desc *
    120  1.1.1.3  christos aarch64_fbsd_nat_target::read_description ()
    121  1.1.1.3  christos {
    122  1.1.1.4  christos   if (inferior_ptid == null_ptid)
    123  1.1.1.4  christos     return this->beneath ()->read_description ();
    124  1.1.1.4  christos 
    125  1.1.1.3  christos   aarch64_features features;
    126  1.1.1.3  christos   features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
    127  1.1.1.3  christos   return aarch64_read_description (features);
    128  1.1.1.3  christos }
    129  1.1.1.3  christos 
    130  1.1.1.3  christos #ifdef HAVE_DBREG
    131  1.1.1.3  christos bool aarch64_fbsd_nat_target::debug_regs_probed;
    132  1.1.1.3  christos 
    133  1.1.1.3  christos /* Set of threads which need to update debug registers on next resume.  */
    134  1.1.1.3  christos 
    135  1.1.1.3  christos static std::unordered_set<lwpid_t> aarch64_debug_pending_threads;
    136  1.1.1.3  christos 
    137  1.1.1.3  christos /* Implement the "stopped_data_address" target_ops method.  */
    138  1.1.1.3  christos 
    139  1.1.1.3  christos bool
    140  1.1.1.3  christos aarch64_fbsd_nat_target::stopped_data_address (CORE_ADDR *addr_p)
    141      1.1  christos {
    142  1.1.1.3  christos   siginfo_t siginfo;
    143  1.1.1.3  christos   struct aarch64_debug_reg_state *state;
    144      1.1  christos 
    145  1.1.1.3  christos   if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo))
    146  1.1.1.3  christos     return false;
    147      1.1  christos 
    148  1.1.1.3  christos   /* This must be a hardware breakpoint.  */
    149  1.1.1.3  christos   if (siginfo.si_signo != SIGTRAP
    150  1.1.1.3  christos       || siginfo.si_code != TRAP_TRACE
    151  1.1.1.3  christos       || siginfo.si_trapno != EXCP_WATCHPT_EL0)
    152  1.1.1.3  christos     return false;
    153  1.1.1.3  christos 
    154  1.1.1.3  christos   const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr;
    155  1.1.1.3  christos 
    156  1.1.1.3  christos   /* Check if the address matches any watched address.  */
    157  1.1.1.3  christos   state = aarch64_get_debug_reg_state (inferior_ptid.pid ());
    158  1.1.1.3  christos   return aarch64_stopped_data_address (state, addr_trap, addr_p);
    159  1.1.1.3  christos }
    160      1.1  christos 
    161  1.1.1.3  christos /* Implement the "stopped_by_watchpoint" target_ops method.  */
    162      1.1  christos 
    163  1.1.1.3  christos bool
    164  1.1.1.3  christos aarch64_fbsd_nat_target::stopped_by_watchpoint ()
    165  1.1.1.3  christos {
    166  1.1.1.4  christos   return stopped_data_address (nullptr);
    167  1.1.1.3  christos }
    168  1.1.1.3  christos 
    169  1.1.1.3  christos /* Implement the "stopped_by_hw_breakpoint" target_ops method.  */
    170  1.1.1.3  christos 
    171  1.1.1.3  christos bool
    172  1.1.1.3  christos aarch64_fbsd_nat_target::stopped_by_hw_breakpoint ()
    173  1.1.1.3  christos {
    174  1.1.1.3  christos   siginfo_t siginfo;
    175  1.1.1.3  christos   struct aarch64_debug_reg_state *state;
    176  1.1.1.3  christos 
    177  1.1.1.3  christos   if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo))
    178  1.1.1.3  christos     return false;
    179      1.1  christos 
    180  1.1.1.3  christos   /* This must be a hardware breakpoint.  */
    181  1.1.1.3  christos   if (siginfo.si_signo != SIGTRAP
    182  1.1.1.3  christos       || siginfo.si_code != TRAP_TRACE
    183  1.1.1.3  christos       || siginfo.si_trapno != EXCP_WATCHPT_EL0)
    184  1.1.1.3  christos     return false;
    185  1.1.1.3  christos 
    186  1.1.1.3  christos   return !stopped_by_watchpoint();
    187  1.1.1.3  christos }
    188  1.1.1.3  christos 
    189  1.1.1.3  christos /* Implement the "supports_stopped_by_hw_breakpoint" target_ops method.  */
    190  1.1.1.3  christos 
    191  1.1.1.3  christos bool
    192  1.1.1.3  christos aarch64_fbsd_nat_target::supports_stopped_by_hw_breakpoint ()
    193  1.1.1.3  christos {
    194  1.1.1.3  christos   return true;
    195  1.1.1.3  christos }
    196  1.1.1.3  christos 
    197  1.1.1.3  christos /* Fetch the hardware debug register capability information.  */
    198  1.1.1.3  christos 
    199  1.1.1.3  christos void
    200  1.1.1.3  christos aarch64_fbsd_nat_target::probe_debug_regs (int pid)
    201  1.1.1.3  christos {
    202  1.1.1.3  christos   if (!debug_regs_probed)
    203  1.1.1.3  christos     {
    204  1.1.1.3  christos       struct dbreg reg;
    205  1.1.1.3  christos 
    206  1.1.1.3  christos       debug_regs_probed = true;
    207  1.1.1.3  christos       aarch64_num_bp_regs = 0;
    208  1.1.1.3  christos       aarch64_num_wp_regs = 0;
    209  1.1.1.3  christos 
    210  1.1.1.3  christos       if (ptrace(PT_GETDBREGS, pid, (PTRACE_TYPE_ARG3) &reg, 0) == 0)
    211  1.1.1.3  christos 	{
    212  1.1.1.3  christos 	  switch (reg.db_debug_ver)
    213  1.1.1.3  christos 	    {
    214  1.1.1.3  christos 	    case AARCH64_DEBUG_ARCH_V8:
    215  1.1.1.3  christos 	    case AARCH64_DEBUG_ARCH_V8_1:
    216  1.1.1.3  christos 	    case AARCH64_DEBUG_ARCH_V8_2:
    217  1.1.1.3  christos 	    case AARCH64_DEBUG_ARCH_V8_4:
    218  1.1.1.4  christos 	    case AARCH64_DEBUG_ARCH_V8_8:
    219  1.1.1.4  christos 	    case AARCH64_DEBUG_ARCH_V8_9:
    220  1.1.1.3  christos 	      break;
    221  1.1.1.3  christos 	    default:
    222  1.1.1.3  christos 	      return;
    223  1.1.1.3  christos 	    }
    224  1.1.1.3  christos 
    225  1.1.1.3  christos 	  aarch64_num_bp_regs = reg.db_nbkpts;
    226  1.1.1.3  christos 	  if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM)
    227  1.1.1.3  christos 	    {
    228  1.1.1.3  christos 	      warning (_("Unexpected number of hardware breakpoint registers"
    229  1.1.1.3  christos 			 " reported by ptrace, got %d, expected %d."),
    230  1.1.1.3  christos 		       aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM);
    231  1.1.1.3  christos 	      aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM;
    232  1.1.1.3  christos 	    }
    233  1.1.1.3  christos 	  aarch64_num_wp_regs = reg.db_nwtpts;
    234  1.1.1.3  christos 	  if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM)
    235  1.1.1.3  christos 	    {
    236  1.1.1.3  christos 	      warning (_("Unexpected number of hardware watchpoint registers"
    237  1.1.1.3  christos 			 " reported by ptrace, got %d, expected %d."),
    238  1.1.1.3  christos 		       aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM);
    239  1.1.1.3  christos 	      aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM;
    240  1.1.1.3  christos 	    }
    241  1.1.1.3  christos 	}
    242      1.1  christos     }
    243      1.1  christos }
    244      1.1  christos 
    245  1.1.1.3  christos /* Implement the virtual inf_ptrace_target::post_startup_inferior method.  */
    246      1.1  christos 
    247      1.1  christos void
    248  1.1.1.3  christos aarch64_fbsd_nat_target::post_startup_inferior (ptid_t ptid)
    249      1.1  christos {
    250  1.1.1.3  christos   aarch64_remove_debug_reg_state (ptid.pid ());
    251  1.1.1.3  christos   probe_debug_regs (ptid.pid ());
    252  1.1.1.3  christos   fbsd_nat_target::post_startup_inferior (ptid);
    253  1.1.1.3  christos }
    254      1.1  christos 
    255  1.1.1.3  christos /* Implement the "post_attach" target_ops method.  */
    256  1.1.1.3  christos 
    257  1.1.1.3  christos void
    258  1.1.1.3  christos aarch64_fbsd_nat_target::post_attach (int pid)
    259  1.1.1.3  christos {
    260  1.1.1.3  christos   aarch64_remove_debug_reg_state (pid);
    261  1.1.1.3  christos   probe_debug_regs (pid);
    262  1.1.1.3  christos   fbsd_nat_target::post_attach (pid);
    263  1.1.1.3  christos }
    264      1.1  christos 
    265  1.1.1.3  christos /* Implement the virtual fbsd_nat_target::low_new_fork method.  */
    266      1.1  christos 
    267  1.1.1.3  christos void
    268  1.1.1.3  christos aarch64_fbsd_nat_target::low_new_fork (ptid_t parent, pid_t child)
    269  1.1.1.3  christos {
    270  1.1.1.3  christos   struct aarch64_debug_reg_state *parent_state, *child_state;
    271      1.1  christos 
    272  1.1.1.3  christos   /* If there is no parent state, no watchpoints nor breakpoints have
    273  1.1.1.3  christos      been set, so there is nothing to do.  */
    274  1.1.1.3  christos   parent_state = aarch64_lookup_debug_reg_state (parent.pid ());
    275  1.1.1.3  christos   if (parent_state == nullptr)
    276  1.1.1.3  christos     return;
    277  1.1.1.3  christos 
    278  1.1.1.3  christos   /* The kernel clears debug registers in the new child process after
    279  1.1.1.3  christos      fork, but GDB core assumes the child inherits the watchpoints/hw
    280  1.1.1.3  christos      breakpoints of the parent, and will remove them all from the
    281  1.1.1.3  christos      forked off process.  Copy the debug registers mirrors into the
    282  1.1.1.3  christos      new process so that all breakpoints and watchpoints can be
    283  1.1.1.3  christos      removed together.  */
    284      1.1  christos 
    285  1.1.1.3  christos   child_state = aarch64_get_debug_reg_state (child);
    286  1.1.1.3  christos   *child_state = *parent_state;
    287  1.1.1.3  christos }
    288  1.1.1.3  christos 
    289  1.1.1.3  christos /* Mark debug register state "dirty" for all threads belonging to the
    290  1.1.1.3  christos    current inferior.  */
    291  1.1.1.3  christos 
    292  1.1.1.3  christos void
    293  1.1.1.3  christos aarch64_notify_debug_reg_change (ptid_t ptid,
    294  1.1.1.3  christos 				 int is_watchpoint, unsigned int idx)
    295  1.1.1.3  christos {
    296  1.1.1.3  christos   for (thread_info *tp : current_inferior ()->non_exited_threads ())
    297      1.1  christos     {
    298  1.1.1.3  christos       if (tp->ptid.lwp_p ())
    299  1.1.1.3  christos 	aarch64_debug_pending_threads.emplace (tp->ptid.lwp ());
    300  1.1.1.3  christos     }
    301  1.1.1.3  christos }
    302  1.1.1.3  christos 
    303  1.1.1.3  christos /* Implement the virtual fbsd_nat_target::low_delete_thread method.  */
    304  1.1.1.3  christos 
    305  1.1.1.3  christos void
    306  1.1.1.3  christos aarch64_fbsd_nat_target::low_delete_thread (thread_info *tp)
    307  1.1.1.3  christos {
    308  1.1.1.3  christos   gdb_assert(tp->ptid.lwp_p ());
    309  1.1.1.3  christos   aarch64_debug_pending_threads.erase (tp->ptid.lwp ());
    310  1.1.1.3  christos }
    311      1.1  christos 
    312  1.1.1.3  christos /* Implement the virtual fbsd_nat_target::low_prepare_to_resume method.  */
    313      1.1  christos 
    314  1.1.1.3  christos void
    315  1.1.1.3  christos aarch64_fbsd_nat_target::low_prepare_to_resume (thread_info *tp)
    316  1.1.1.3  christos {
    317  1.1.1.3  christos   gdb_assert(tp->ptid.lwp_p ());
    318      1.1  christos 
    319  1.1.1.3  christos   if (aarch64_debug_pending_threads.erase (tp->ptid.lwp ()) == 0)
    320  1.1.1.3  christos     return;
    321  1.1.1.3  christos 
    322  1.1.1.3  christos   struct aarch64_debug_reg_state *state =
    323  1.1.1.3  christos     aarch64_lookup_debug_reg_state (tp->ptid.pid ());
    324  1.1.1.3  christos   gdb_assert(state != nullptr);
    325  1.1.1.3  christos 
    326  1.1.1.3  christos   struct dbreg reg;
    327  1.1.1.3  christos   memset (&reg, 0, sizeof(reg));
    328  1.1.1.3  christos   for (int i = 0; i < aarch64_num_bp_regs; i++)
    329  1.1.1.3  christos     {
    330  1.1.1.3  christos       reg.db_breakregs[i].dbr_addr = state->dr_addr_bp[i];
    331  1.1.1.3  christos       reg.db_breakregs[i].dbr_ctrl = state->dr_ctrl_bp[i];
    332      1.1  christos     }
    333  1.1.1.3  christos   for (int i = 0; i < aarch64_num_wp_regs; i++)
    334  1.1.1.3  christos     {
    335  1.1.1.3  christos       reg.db_watchregs[i].dbw_addr = state->dr_addr_wp[i];
    336  1.1.1.3  christos       reg.db_watchregs[i].dbw_ctrl = state->dr_ctrl_wp[i];
    337  1.1.1.3  christos     }
    338  1.1.1.3  christos   if (ptrace(PT_SETDBREGS, tp->ptid.lwp (), (PTRACE_TYPE_ARG3) &reg, 0) != 0)
    339  1.1.1.3  christos     error (_("Failed to set hardware debug registers"));
    340  1.1.1.3  christos }
    341  1.1.1.3  christos #else
    342  1.1.1.3  christos /* A stub that should never be called.  */
    343  1.1.1.3  christos void
    344  1.1.1.3  christos aarch64_notify_debug_reg_change (ptid_t ptid,
    345  1.1.1.3  christos 				 int is_watchpoint, unsigned int idx)
    346  1.1.1.3  christos {
    347  1.1.1.3  christos   gdb_assert (true);
    348      1.1  christos }
    349  1.1.1.3  christos #endif
    350      1.1  christos 
    351  1.1.1.2  christos void _initialize_aarch64_fbsd_nat ();
    352      1.1  christos void
    353  1.1.1.2  christos _initialize_aarch64_fbsd_nat ()
    354      1.1  christos {
    355  1.1.1.3  christos #ifdef HAVE_DBREG
    356  1.1.1.3  christos   aarch64_initialize_hw_point ();
    357  1.1.1.3  christos #endif
    358      1.1  christos   add_inf_child_target (&the_aarch64_fbsd_nat_target);
    359      1.1  christos }
    360