Introduce show_debug_regs
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-aarch64-low.c
index 7f99887c3472f387ed84c7e230dd84f160c30037..ca096b02c93ca49ccaac9bd164a2f345c8278dc0 100644 (file)
@@ -1,7 +1,7 @@
 /* GNU/Linux/AArch64 specific low level interface, for the remote server for
    GDB.
 
-   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+   Copyright (C) 2009-2014 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of GDB.
 #include <signal.h>
 #include <sys/user.h>
 #include <sys/ptrace.h>
+#include <asm/ptrace.h>
 #include <sys/uio.h>
 
 #include "gdb_proc_service.h"
 
 /* Defined in auto-generated files.  */
 void init_registers_aarch64 (void);
-
-/* Defined in auto-generated files.  */
-void init_registers_aarch64_without_fpu (void);
+extern const struct target_desc *tdesc_aarch64;
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
@@ -210,49 +209,6 @@ struct arch_lwp_info
 static int aarch64_num_bp_regs;
 static int aarch64_num_wp_regs;
 
-/* Hardware breakpoint/watchpoint types.
-   The values map to their encodings in the bit 4 and bit 3 of the
-   hardware breakpoint/watchpoint control registers.  */
-
-enum target_point_type
-{
-  hw_execute = 0,              /* Execute HW breakpoint */
-  hw_read = 1,                 /* Read    HW watchpoint */
-  hw_write = 2,                        /* Common  HW watchpoint */
-  hw_access = 3,               /* Access  HW watchpoint */
-  point_type_unsupported
-};
-
-#define Z_PACKET_SW_BP '0'
-#define Z_PACKET_HW_BP '1'
-#define Z_PACKET_WRITE_WP '2'
-#define Z_PACKET_READ_WP '3'
-#define Z_PACKET_ACCESS_WP '4'
-
-/* Map the protocol breakpoint/watchpoint type TYPE to
-   enum target_point_type.  */
-
-static enum target_point_type
-Z_packet_to_point_type (char type)
-{
-  switch (type)
-    {
-    case Z_PACKET_SW_BP:
-      /* Leave the handling of the sw breakpoint with the gdb client.  */
-      return point_type_unsupported;
-    case Z_PACKET_HW_BP:
-      return hw_execute;
-    case Z_PACKET_WRITE_WP:
-      return hw_write;
-    case Z_PACKET_READ_WP:
-      return hw_read;
-    case Z_PACKET_ACCESS_WP:
-      return hw_access;
-    default:
-      return point_type_unsupported;
-    }
-}
-
 static int
 aarch64_cannot_store_register (int regno)
 {
@@ -311,9 +267,6 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
     supply_register (regcache, AARCH64_V0_REGNO + i, &regset->vregs[i]);
 }
 
-/* Debugging of hardware breakpoint/watchpoint support.  */
-extern int debug_hw_points;
-
 /* Enable miscellaneous debugging output.  The name is historical - it
    was originally used to debug LinuxThreads support.  */
 extern int debug_threads;
@@ -325,7 +278,7 @@ aarch64_get_pc (struct regcache *regcache)
 
   collect_register_by_name (regcache, "pc", &pc);
   if (debug_threads)
-    fprintf (stderr, "stop pc is %08lx\n", pc);
+    debug_printf ("stop pc is %08lx\n", pc);
   return pc;
 }
 
@@ -360,7 +313,7 @@ aarch64_breakpoint_at (CORE_ADDR where)
 static void
 aarch64_show_debug_reg_state (struct aarch64_debug_reg_state *state,
                              const char *func, CORE_ADDR addr,
-                             int len, enum target_point_type type)
+                             int len, enum target_hw_bp_type type)
 {
   int i;
 
@@ -450,12 +403,31 @@ aarch64_watchpoint_length (unsigned int ctrl)
    breakpoint/watchpoint control register.  */
 
 static unsigned int
-aarch64_point_encode_ctrl_reg (enum target_point_type type, int len)
+aarch64_point_encode_ctrl_reg (enum target_hw_bp_type type, int len)
 {
-  unsigned int ctrl;
+  unsigned int ctrl, ttype;
 
   /* type */
-  ctrl = type << 3;
+  switch (type)
+    {
+    case hw_write:
+      ttype = 2;
+      break;
+    case hw_read:
+      ttype = 1;
+      break;
+    case hw_access:
+      ttype = 3;
+      break;
+    case hw_execute:
+      ttype = 0;
+      break;
+    default:
+      perror_with_name (_("Unrecognized breakpoint/watchpoint type"));
+    }
+
+  /* type */
+  ctrl = ttype << 3;
   /* length bitmask */
   ctrl |= ((1 << len) - 1) << 5;
   /* enabled at el0 */
@@ -602,11 +574,15 @@ aarch64_linux_set_debug_regs (const struct aarch64_debug_reg_state *state,
   const CORE_ADDR *addr;
   const unsigned int *ctrl;
 
+  memset (&regs, 0, sizeof (regs));
   iov.iov_base = &regs;
-  iov.iov_len = sizeof (regs);
   count = watchpoint ? aarch64_num_wp_regs : aarch64_num_bp_regs;
   addr = watchpoint ? state->dr_addr_wp : state->dr_addr_bp;
   ctrl = watchpoint ? state->dr_ctrl_wp : state->dr_ctrl_bp;
+  if (count == 0)
+    return;
+  iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs[count - 1])
+                + sizeof (regs.dbg_regs [count - 1]));
 
   for (i = 0; i < count; i++)
     {
@@ -636,7 +612,8 @@ struct aarch64_dr_update_callback_param
 static int
 debug_reg_change_callback (struct inferior_list_entry *entry, void *ptr)
 {
-  struct lwp_info *lwp = (struct lwp_info *) entry;
+  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;
@@ -646,12 +623,12 @@ debug_reg_change_callback (struct inferior_list_entry *entry, void *ptr)
   dr_changed_t *dr_changed_ptr;
   dr_changed_t dr_changed;
 
-  if (debug_hw_points)
+  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 (lwp), info->dr_changed_bp,
+              pid, lwpid_of (thread), info->dr_changed_bp,
               info->dr_changed_wp);
     }
 
@@ -660,7 +637,7 @@ debug_reg_change_callback (struct inferior_list_entry *entry, void *ptr)
   dr_changed = *dr_changed_ptr;
 
   /* Only update the threads of this process.  */
-  if (pid_of (lwp) == pid)
+  if (pid_of (thread) == pid)
     {
       gdb_assert (idx >= 0
                  && (idx <= (is_watchpoint ? aarch64_num_wp_regs
@@ -697,11 +674,12 @@ debug_reg_change_callback (struct inferior_list_entry *entry, void *ptr)
        linux_stop_lwp (lwp);
     }
 
-  if (debug_hw_points)
+  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 (lwp), info->dr_changed_bp, info->dr_changed_wp);
+              pid, lwpid_of (thread), info->dr_changed_bp,
+              info->dr_changed_wp);
     }
 
   return 0;
@@ -719,12 +697,12 @@ aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state,
   struct aarch64_dr_update_callback_param param;
 
   /* Only update the threads of this process.  */
-  param.pid = pid_of (get_thread_lwp (current_inferior));
+  param.pid = pid_of (current_inferior);
 
   param.is_watchpoint = is_watchpoint;
   param.idx = idx;
 
-  find_inferior (&all_lwps, debug_reg_change_callback, (void *) &param);
+  find_inferior (&all_threads, debug_reg_change_callback, (void *) &param);
 }
 
 
@@ -745,7 +723,7 @@ aarch64_get_debug_reg_state ()
 
 static int
 aarch64_dr_state_insert_one_point (struct aarch64_debug_reg_state *state,
-                                  enum target_point_type type,
+                                  enum target_hw_bp_type type,
                                   CORE_ADDR addr, int len)
 {
   int i, idx, num_regs, is_watchpoint;
@@ -818,7 +796,7 @@ aarch64_dr_state_insert_one_point (struct aarch64_debug_reg_state *state,
 
 static int
 aarch64_dr_state_remove_one_point (struct aarch64_debug_reg_state *state,
-                                  enum target_point_type type,
+                                  enum target_hw_bp_type type,
                                   CORE_ADDR addr, int len)
 {
   int i, num_regs, is_watchpoint;
@@ -872,7 +850,7 @@ aarch64_dr_state_remove_one_point (struct aarch64_debug_reg_state *state,
 }
 
 static int
-aarch64_handle_breakpoint (enum target_point_type type, CORE_ADDR addr,
+aarch64_handle_breakpoint (enum target_hw_bp_type type, CORE_ADDR addr,
                           int len, int is_insert)
 {
   struct aarch64_debug_reg_state *state;
@@ -894,7 +872,7 @@ aarch64_handle_breakpoint (enum target_point_type type, CORE_ADDR addr,
    from that it is an aligned watchpoint to be handled.  */
 
 static int
-aarch64_handle_aligned_watchpoint (enum target_point_type type,
+aarch64_handle_aligned_watchpoint (enum target_hw_bp_type type,
                                   CORE_ADDR addr, int len, int is_insert)
 {
   struct aarch64_debug_reg_state *state;
@@ -915,7 +893,7 @@ aarch64_handle_aligned_watchpoint (enum target_point_type type,
    Return 0 if succeed.  */
 
 static int
-aarch64_handle_unaligned_watchpoint (enum target_point_type type,
+aarch64_handle_unaligned_watchpoint (enum target_hw_bp_type type,
                                     CORE_ADDR addr, int len, int is_insert)
 {
   struct aarch64_debug_reg_state *state
@@ -936,7 +914,7 @@ aarch64_handle_unaligned_watchpoint (enum target_point_type type,
        ret = aarch64_dr_state_remove_one_point (state, type, aligned_addr,
                                                 aligned_len);
 
-      if (debug_hw_points)
+      if (show_debug_regs)
        fprintf (stderr,
  "handle_unaligned_watchpoint: is_insert: %d\n"
  "                             aligned_addr: 0x%s, aligned_len: %d\n"
@@ -952,7 +930,7 @@ aarch64_handle_unaligned_watchpoint (enum target_point_type type,
 }
 
 static int
-aarch64_handle_watchpoint (enum target_point_type type, CORE_ADDR addr,
+aarch64_handle_watchpoint (enum target_hw_bp_type type, CORE_ADDR addr,
                           int len, int is_insert)
 {
   if (aarch64_point_is_aligned (1 /* is_watchpoint */ , addr, len))
@@ -961,6 +939,22 @@ aarch64_handle_watchpoint (enum target_point_type type, CORE_ADDR addr,
     return aarch64_handle_unaligned_watchpoint (type, addr, len, is_insert);
 }
 
+static int
+aarch64_supports_z_point_type (char z_type)
+{
+  switch (z_type)
+    {
+    case Z_PACKET_HW_BP:
+    case Z_PACKET_WRITE_WP:
+    case Z_PACKET_READ_WP:
+    case Z_PACKET_ACCESS_WP:
+      return 1;
+    default:
+      /* Leave the handling of sw breakpoints with the gdb client.  */
+      return 0;
+    }
+}
+
 /* Insert a hardware breakpoint/watchpoint.
    It actually only records the info of the to-be-inserted bp/wp;
    the actual insertion will happen when threads are resumed.
@@ -970,19 +964,18 @@ aarch64_handle_watchpoint (enum target_point_type type, CORE_ADDR addr,
    Return -1 if an error occurs.  */
 
 static int
-aarch64_insert_point (char type, CORE_ADDR addr, int len)
+aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                     int len, struct raw_breakpoint *bp)
 {
   int ret;
-  enum target_point_type targ_type;
+  enum target_hw_bp_type targ_type;
 
-  if (debug_hw_points)
+  if (show_debug_regs)
     fprintf (stderr, "insert_point on entry (addr=0x%08lx, len=%d)\n",
             (unsigned long) addr, len);
 
-  /* Determine the type from the packet.  */
-  targ_type = Z_packet_to_point_type (type);
-  if (targ_type == point_type_unsupported)
-    return 1;
+  /* Determine the type from the raw breakpoint type.  */
+  targ_type = raw_bkpt_type_to_target_hw_bp_type (type);
 
   if (targ_type != hw_execute)
     ret =
@@ -991,7 +984,7 @@ aarch64_insert_point (char type, CORE_ADDR addr, int len)
     ret =
       aarch64_handle_breakpoint (targ_type, addr, len, 1 /* is_insert */);
 
-  if (debug_hw_points > 1)
+  if (show_debug_regs > 1)
     aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (),
                                  "insert_point", addr, len, targ_type);
 
@@ -1007,19 +1000,18 @@ aarch64_insert_point (char type, CORE_ADDR addr, int len)
    Return -1 if an error occurs.  */
 
 static int
-aarch64_remove_point (char type, CORE_ADDR addr, int len)
+aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                     int len, struct raw_breakpoint *bp)
 {
   int ret;
-  enum target_point_type targ_type;
+  enum target_hw_bp_type targ_type;
 
-  if (debug_hw_points)
+  if (show_debug_regs)
     fprintf (stderr, "remove_point on entry (addr=0x%08lx, len=%d)\n",
             (unsigned long) addr, len);
 
-  /* Determine the type from the packet.  */
-  targ_type = Z_packet_to_point_type (type);
-  if (targ_type == point_type_unsupported)
-    return 1;
+  /* Determine the type from the raw breakpoint type.  */
+  targ_type = raw_bkpt_type_to_target_hw_bp_type (type);
 
   /* Set up state pointers.  */
   if (targ_type != hw_execute)
@@ -1029,7 +1021,7 @@ aarch64_remove_point (char type, CORE_ADDR addr, int len)
     ret =
       aarch64_handle_breakpoint (targ_type, addr, len, 0 /* is_insert */);
 
-  if (debug_hw_points > 1)
+  if (show_debug_regs > 1)
     aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (),
                                  "remove_point", addr, len, targ_type);
 
@@ -1046,7 +1038,7 @@ aarch64_stopped_data_address (void)
   int pid, i;
   struct aarch64_debug_reg_state *state;
 
-  pid = lwpid_of (get_thread_lwp (current_inferior));
+  pid = lwpid_of (current_inferior);
 
   /* Get the siginfo.  */
   if (ptrace (PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0)
@@ -1089,16 +1081,22 @@ aarch64_stopped_by_watchpoint (void)
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
-ps_get_thread_area (const struct ps_prochandle * ph,
+ps_get_thread_area (const struct ps_prochandle *ph,
                    lwpid_t lwpid, int idx, void **base)
 {
-  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
+  struct iovec iovec;
+  uint64_t reg;
+
+  iovec.iov_base = &reg;
+  iovec.iov_len = sizeof (reg);
+
+  if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0)
     return PS_ERR;
 
   /* IDX is the bias from the thread pointer to the beginning of the
      thread descriptor.  It has to be subtracted due to implementation
      quirks in libthread_db.  */
-  *base = (void *) ((char *) *base - idx);
+  *base = (void *) (reg - idx);
 
   return PS_OK;
 }
@@ -1137,7 +1135,8 @@ aarch64_linux_new_thread (void)
 static void
 aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
 {
-  ptid_t ptid = ptid_of (lwp);
+  struct thread_info *thread = get_lwp_thread (lwp);
+  ptid_t ptid = ptid_of (thread);
   struct arch_lwp_info *info = lwp->arch_private;
 
   if (DR_HAS_CHANGED (info->dr_changed_bp)
@@ -1148,8 +1147,8 @@ aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
       struct aarch64_debug_reg_state *state
        = &proc->private->arch_private->debug_reg_state;
 
-      if (debug_hw_points)
-       fprintf (stderr, "prepare_to_resume thread %ld\n", lwpid_of (lwp));
+      if (show_debug_regs)
+       fprintf (stderr, "prepare_to_resume thread %ld\n", lwpid_of (thread));
 
       /* Watchpoints.  */
       if (DR_HAS_CHANGED (info->dr_changed_wp))
@@ -1185,9 +1184,9 @@ aarch64_arch_setup (void)
   struct iovec iov;
   struct user_hwdebug_state dreg_state;
 
-  init_registers_aarch64 ();
+  current_process ()->tdesc = tdesc_aarch64;
 
-  pid = lwpid_of (get_thread_lwp (current_inferior));
+  pid = lwpid_of (current_inferior);
   iov.iov_base = &dreg_state;
   iov.iov_len = sizeof (dreg_state);
 
@@ -1196,10 +1195,13 @@ aarch64_arch_setup (void)
       && 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_HBP_MAX_NUM)
-       warning ("Unexpected number of hardware watchpoint registers reported"
-                " by ptrace, got %d, expected %d.",
-                aarch64_num_wp_regs, AARCH64_HBP_MAX_NUM);
+      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;
+       }
     }
   else
     {
@@ -1214,9 +1216,12 @@ aarch64_arch_setup (void)
     {
       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);
+       {
+         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
     {
@@ -1226,7 +1231,7 @@ aarch64_arch_setup (void)
     }
 }
 
-struct regset_info target_regsets[] =
+static struct regset_info aarch64_regsets[] =
 {
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
     sizeof (struct user_pt_regs), GENERAL_REGS,
@@ -1238,12 +1243,36 @@ struct regset_info target_regsets[] =
   { 0, 0, 0, -1, -1, NULL, NULL }
 };
 
+static struct regsets_info aarch64_regsets_info =
+  {
+    aarch64_regsets, /* regsets */
+    0, /* num_regsets */
+    NULL, /* disabled_regsets */
+  };
+
+static struct usrregs_info aarch64_usrregs_info =
+  {
+    AARCH64_NUM_REGS,
+    aarch64_regmap,
+  };
+
+static struct regs_info regs_info =
+  {
+    NULL, /* regset_bitmap */
+    &aarch64_usrregs_info,
+    &aarch64_regsets_info,
+  };
+
+static const struct regs_info *
+aarch64_regs_info (void)
+{
+  return &regs_info;
+}
+
 struct linux_target_ops the_low_target =
 {
   aarch64_arch_setup,
-  AARCH64_NUM_REGS,
-  aarch64_regmap,
-  NULL,
+  aarch64_regs_info,
   aarch64_cannot_fetch_register,
   aarch64_cannot_store_register,
   NULL,
@@ -1254,6 +1283,7 @@ struct linux_target_ops the_low_target =
   NULL,
   0,
   aarch64_breakpoint_at,
+  aarch64_supports_z_point_type,
   aarch64_insert_point,
   aarch64_remove_point,
   aarch64_stopped_by_watchpoint,
@@ -1265,3 +1295,11 @@ struct linux_target_ops the_low_target =
   aarch64_linux_new_thread,
   aarch64_linux_prepare_to_resume,
 };
+
+void
+initialize_low_arch (void)
+{
+  init_registers_aarch64 ();
+
+  initialize_regsets_info (&aarch64_regsets_info);
+}
This page took 0.033161 seconds and 4 git commands to generate.