Make aarch64_notify_debug_reg_change the same on GDB and GDBserver
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-aarch64-low.c
index d29672e013a89b2097cd47d3b675db4df9bef802..bfff7e4a88756cdc55d51151cef41aa6ad5951fb 100644 (file)
 #include "server.h"
 #include "linux-low.h"
 #include "nat/aarch64-linux-hw-point.h"
+#include "linux-aarch32-low.h"
 #include "elf/common.h"
 
 #include <signal.h>
 #include <sys/user.h>
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
 #include <asm/ptrace.h>
 #include <sys/uio.h>
 
@@ -69,6 +70,16 @@ struct arch_process_info
   struct aarch64_debug_reg_state debug_reg_state;
 };
 
+/* Return true if the size of register 0 is 8 byte.  */
+
+static int
+is_64bit_tdesc (void)
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+
+  return register_size (regcache->tdesc, 0) == 8;
+}
+
 /* Implementation of linux_target_ops method "cannot_store_register".  */
 
 static int
@@ -144,12 +155,24 @@ extern int debug_threads;
 static CORE_ADDR
 aarch64_get_pc (struct regcache *regcache)
 {
-  unsigned long pc;
+  if (register_size (regcache->tdesc, 0) == 8)
+    {
+      unsigned long pc;
 
-  collect_register_by_name (regcache, "pc", &pc);
-  if (debug_threads)
-    debug_printf ("stop pc is %08lx\n", pc);
-  return pc;
+      collect_register_by_name (regcache, "pc", &pc);
+      if (debug_threads)
+       debug_printf ("stop pc is %08lx\n", pc);
+      return pc;
+    }
+  else
+    {
+      unsigned int pc;
+
+      collect_register_by_name (regcache, "pc", &pc);
+      if (debug_threads)
+       debug_printf ("stop pc is %04x\n", pc);
+      return pc;
+    }
 }
 
 /* Implementation of linux_target_ops method "set_pc".  */
@@ -157,8 +180,16 @@ aarch64_get_pc (struct regcache *regcache)
 static void
 aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc)
 {
-  unsigned long newpc = pc;
-  supply_register_by_name (regcache, "pc", &newpc);
+  if (register_size (regcache->tdesc, 0) == 8)
+    {
+      unsigned long newpc = pc;
+      supply_register_by_name (regcache, "pc", &newpc);
+    }
+  else
+    {
+      unsigned int newpc = pc;
+      supply_register_by_name (regcache, "pc", &newpc);
+    }
 }
 
 #define aarch64_breakpoint_len 4
@@ -205,25 +236,23 @@ aarch64_init_debug_reg_state (struct aarch64_debug_reg_state *state)
 
 struct aarch64_dr_update_callback_param
 {
-  int pid;
   int is_watchpoint;
   unsigned int idx;
 };
 
-/* Callback function which records the information about the change of
-   one hardware breakpoint/watchpoint setting for the thread ENTRY.
+/* Callback for iterate_over_lwps.  Records the
+   information about the change of one hardware breakpoint/watchpoint
+   setting for the thread LWP.
    The information is passed in via PTR.
    N.B.  The actual updating of hardware debug registers is not
    carried out until the moment the thread is resumed.  */
 
 static int
-debug_reg_change_callback (struct inferior_list_entry *entry, void *ptr)
+debug_reg_change_callback (struct lwp_info *lwp, void *ptr)
 {
-  struct thread_info *thread = (struct thread_info *) entry;
-  struct lwp_info *lwp = get_thread_lwp (thread);
   struct aarch64_dr_update_callback_param *param_p
     = (struct aarch64_dr_update_callback_param *) ptr;
-  int pid = param_p->pid;
+  int pid = pid_of (lwp->thread);
   int idx = param_p->idx;
   int is_watchpoint = param_p->is_watchpoint;
   struct arch_lwp_info *info = lwp->arch_private;
@@ -232,61 +261,37 @@ debug_reg_change_callback (struct inferior_list_entry *entry, void *ptr)
 
   if (show_debug_regs)
     {
-      fprintf (stderr, "debug_reg_change_callback: \n\tOn entry:\n");
-      fprintf (stderr, "\tpid%d, tid: %ld, dr_changed_bp=0x%llx, "
-              "dr_changed_wp=0x%llx\n",
-              pid, lwpid_of (thread), info->dr_changed_bp,
-              info->dr_changed_wp);
+      debug_printf ("debug_reg_change_callback: \n\tOn entry:\n");
+      debug_printf ("\tpid%d, dr_changed_bp=0x%s, "
+                   "dr_changed_wp=0x%s\n", pid,
+                   phex (info->dr_changed_bp, 8),
+                   phex (info->dr_changed_wp, 8));
     }
 
   dr_changed_ptr = is_watchpoint ? &info->dr_changed_wp
     : &info->dr_changed_bp;
   dr_changed = *dr_changed_ptr;
 
-  /* Only update the threads of this process.  */
-  if (pid_of (thread) == pid)
-    {
-      gdb_assert (idx >= 0
-                 && (idx <= (is_watchpoint ? aarch64_num_wp_regs
-                             : aarch64_num_bp_regs)));
-
-      /* The following assertion is not right, as there can be changes
-        that have not been made to the hardware debug registers
-        before new changes overwrite the old ones.  This can happen,
-        for instance, when the breakpoint/watchpoint hit one of the
-        threads and the user enters continue; then what happens is:
-        1) all breakpoints/watchpoints are removed for all threads;
-        2) a single step is carried out for the thread that was hit;
-        3) all of the points are inserted again for all threads;
-        4) all threads are resumed.
-        The 2nd step will only affect the one thread in which the
-        bp/wp was hit, which means only that one thread is resumed;
-        remember that the actual updating only happen in
-        aarch64_linux_prepare_to_resume, so other threads remain
-        stopped during the removal and insertion of bp/wp.  Therefore
-        for those threads, the change of insertion of the bp/wp
-        overwrites that of the earlier removals.  (The situation may
-        be different when bp/wp is steppable, or in the non-stop
-        mode.)  */
-      /* gdb_assert (DR_N_HAS_CHANGED (dr_changed, idx) == 0);  */
-
-      /* The actual update is done later just before resuming the lwp,
-         we just mark that one register pair needs updating.  */
-      DR_MARK_N_CHANGED (dr_changed, idx);
-      *dr_changed_ptr = dr_changed;
-
-      /* If the lwp isn't stopped, force it to momentarily pause, so
-         we can update its debug registers.  */
-      if (!lwp->stopped)
-       linux_stop_lwp (lwp);
-    }
+  gdb_assert (idx >= 0
+             && (idx <= (is_watchpoint ? aarch64_num_wp_regs
+                         : aarch64_num_bp_regs)));
+
+  /* The actual update is done later just before resuming the lwp,
+     we just mark that one register pair needs updating.  */
+  DR_MARK_N_CHANGED (dr_changed, idx);
+  *dr_changed_ptr = dr_changed;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so
+     we can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
 
   if (show_debug_regs)
     {
-      fprintf (stderr, "\tOn exit:\n\tpid%d, tid: %ld, dr_changed_bp=0x%llx, "
-              "dr_changed_wp=0x%llx\n",
-              pid, lwpid_of (thread), info->dr_changed_bp,
-              info->dr_changed_wp);
+      debug_printf ("\tOn exit:\n\tpid%d, dr_changed_bp=0x%s, "
+                   "dr_changed_wp=0x%s\n", pid,
+                   phex (info->dr_changed_bp, 8),
+                   phex (info->dr_changed_wp, 8));
     }
 
   return 0;
@@ -302,14 +307,12 @@ aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state,
                                 int is_watchpoint, unsigned int idx)
 {
   struct aarch64_dr_update_callback_param param;
-
-  /* Only update the threads of this process.  */
-  param.pid = pid_of (current_thread);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (current_lwp_ptid ()));
 
   param.is_watchpoint = is_watchpoint;
   param.idx = idx;
 
-  find_inferior (&all_threads, debug_reg_change_callback, (void *) &param);
+  iterate_over_lwps (pid_ptid, debug_reg_change_callback, (void *) &param);
 }
 
 
@@ -333,6 +336,22 @@ aarch64_supports_z_point_type (char z_type)
   switch (z_type)
     {
     case Z_PACKET_SW_BP:
+      {
+       if (!extended_protocol && is_64bit_tdesc ())
+         {
+           /* Only enable Z0 packet in non-multi-arch debugging.  If
+              extended protocol is used, don't enable Z0 packet because
+              GDBserver may attach to 32-bit process.  */
+           return 1;
+         }
+       else
+         {
+           /* Disable Z0 packet so that GDBserver doesn't have to handle
+              different breakpoint instructions (aarch64, arm, thumb etc)
+              in multi-arch debugging.  */
+           return 0;
+         }
+      }
     case Z_PACKET_HW_BP:
     case Z_PACKET_WRITE_WP:
     case Z_PACKET_READ_WP:
@@ -582,60 +601,34 @@ aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
     }
 }
 
-/* Implementation of linux_target_ops method "arch_setup".  */
+/* Return the right target description according to the ELF file of
+   current thread.  */
 
-static void
-aarch64_arch_setup (void)
+static const struct target_desc *
+aarch64_linux_read_description (void)
 {
-  int pid;
-  struct iovec iov;
-  struct user_hwdebug_state dreg_state;
+  unsigned int machine;
+  int is_elf64;
+  int tid;
 
-  current_process ()->tdesc = tdesc_aarch64;
+  tid = lwpid_of (current_thread);
 
-  pid = lwpid_of (current_thread);
-  iov.iov_base = &dreg_state;
-  iov.iov_len = sizeof (dreg_state);
+  is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
 
-  /* Get hardware watchpoint register info.  */
-  if (ptrace (PTRACE_GETREGSET, pid, NT_ARM_HW_WATCH, &iov) == 0
-      && AARCH64_DEBUG_ARCH (dreg_state.dbg_info) == AARCH64_DEBUG_ARCH_V8)
-    {
-      aarch64_num_wp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
-      if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM)
-       {
-         warning ("Unexpected number of hardware watchpoint registers reported"
-                  " by ptrace, got %d, expected %d.",
-                  aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM);
-         aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM;
-       }
-    }
+  if (is_elf64)
+    return tdesc_aarch64;
   else
-    {
-      warning ("Unable to determine the number of hardware watchpoints"
-              " available.");
-      aarch64_num_wp_regs = 0;
-    }
+    return tdesc_arm_with_neon;
+}
 
-  /* Get hardware breakpoint register info.  */
-  if (ptrace (PTRACE_GETREGSET, pid, NT_ARM_HW_BREAK, &iov) == 0
-      && AARCH64_DEBUG_ARCH (dreg_state.dbg_info) == AARCH64_DEBUG_ARCH_V8)
-    {
-      aarch64_num_bp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
-      if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM)
-       {
-         warning ("Unexpected number of hardware breakpoint registers reported"
-                  " by ptrace, got %d, expected %d.",
-                  aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM);
-         aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM;
-       }
-    }
-  else
-    {
-      warning ("Unable to determine the number of hardware breakpoints"
-              " available.");
-      aarch64_num_bp_regs = 0;
-    }
+/* Implementation of linux_target_ops method "arch_setup".  */
+
+static void
+aarch64_arch_setup (void)
+{
+  current_process ()->tdesc = aarch64_linux_read_description ();
+
+  aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
 }
 
 static struct regset_info aarch64_regsets[] =
@@ -657,7 +650,7 @@ static struct regsets_info aarch64_regsets_info =
     NULL, /* disabled_regsets */
   };
 
-static struct regs_info regs_info =
+static struct regs_info regs_info_aarch64 =
   {
     NULL, /* regset_bitmap */
     NULL, /* usrregs */
@@ -669,7 +662,10 @@ static struct regs_info regs_info =
 static const struct regs_info *
 aarch64_regs_info (void)
 {
-  return &regs_info;
+  if (is_64bit_tdesc ())
+    return &regs_info_aarch64;
+  else
+    return &regs_info_aarch32;
 }
 
 /* Implementation of linux_target_ops method "supports_tracepoints".  */
@@ -677,7 +673,13 @@ aarch64_regs_info (void)
 static int
 aarch64_supports_tracepoints (void)
 {
-  return 1;
+  if (current_thread == NULL)
+    return 1;
+  else
+    {
+      /* We don't support tracepoints on aarch32 now.  */
+      return is_64bit_tdesc ();
+    }
 }
 
 /* Implementation of linux_target_ops method "supports_range_stepping".  */
@@ -728,5 +730,7 @@ initialize_low_arch (void)
 {
   init_registers_aarch64 ();
 
+  initialize_low_arch_aarch32 ();
+
   initialize_regsets_info (&aarch64_regsets_info);
 }
This page took 0.031815 seconds and 4 git commands to generate.