Update copyright year range in all GDB files
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-aarch64-low.c
index a145f80bb4a5702b7956561320756e36061f77ba..eccac4da138bb05449c726b8ad3fcf0bba587e5d 100644 (file)
@@ -1,7 +1,7 @@
 /* GNU/Linux/AArch64 specific low level interface, for the remote server for
    GDB.
 
-   Copyright (C) 2009-2015 Free Software Foundation, Inc.
+   Copyright (C) 2009-2018 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of GDB.
 #include <sys/uio.h>
 
 #include "gdb_proc_service.h"
-
-/* Defined in auto-generated files.  */
-void init_registers_aarch64 (void);
-extern const struct target_desc *tdesc_aarch64;
+#include "arch/aarch64.h"
+#include "linux-aarch64-tdesc.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
 #endif
 
-#define AARCH64_X_REGS_NUM 31
-#define AARCH64_V_REGS_NUM 32
-#define AARCH64_X0_REGNO    0
-#define AARCH64_SP_REGNO   31
-#define AARCH64_PC_REGNO   32
-#define AARCH64_CPSR_REGNO 33
-#define AARCH64_V0_REGNO   34
-#define AARCH64_FPSR_REGNO (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM)
-#define AARCH64_FPCR_REGNO (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM + 1)
-
-#define AARCH64_NUM_REGS (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM + 2)
-
 /* Per-process arch-specific data we want to keep.  */
 
 struct arch_process_info
@@ -109,10 +95,10 @@ aarch64_fill_gregset (struct regcache *regcache, void *buf)
   int i;
 
   for (i = 0; i < AARCH64_X_REGS_NUM; i++)
-    collect_register (regcache, AARCH64_X0_REGNO + i, &regset->regs[i]);
-  collect_register (regcache, AARCH64_SP_REGNO, &regset->sp);
-  collect_register (regcache, AARCH64_PC_REGNO, &regset->pc);
-  collect_register (regcache, AARCH64_CPSR_REGNO, &regset->pstate);
+    collect_register (regcache, AARCH64_X0_REGNUM + i, &regset->regs[i]);
+  collect_register (regcache, AARCH64_SP_REGNUM, &regset->sp);
+  collect_register (regcache, AARCH64_PC_REGNUM, &regset->pc);
+  collect_register (regcache, AARCH64_CPSR_REGNUM, &regset->pstate);
 }
 
 static void
@@ -122,10 +108,10 @@ aarch64_store_gregset (struct regcache *regcache, const void *buf)
   int i;
 
   for (i = 0; i < AARCH64_X_REGS_NUM; i++)
-    supply_register (regcache, AARCH64_X0_REGNO + i, &regset->regs[i]);
-  supply_register (regcache, AARCH64_SP_REGNO, &regset->sp);
-  supply_register (regcache, AARCH64_PC_REGNO, &regset->pc);
-  supply_register (regcache, AARCH64_CPSR_REGNO, &regset->pstate);
+    supply_register (regcache, AARCH64_X0_REGNUM + i, &regset->regs[i]);
+  supply_register (regcache, AARCH64_SP_REGNUM, &regset->sp);
+  supply_register (regcache, AARCH64_PC_REGNUM, &regset->pc);
+  supply_register (regcache, AARCH64_CPSR_REGNUM, &regset->pstate);
 }
 
 static void
@@ -135,9 +121,9 @@ aarch64_fill_fpregset (struct regcache *regcache, void *buf)
   int i;
 
   for (i = 0; i < AARCH64_V_REGS_NUM; i++)
-    collect_register (regcache, AARCH64_V0_REGNO + i, &regset->vregs[i]);
-  collect_register (regcache, AARCH64_FPSR_REGNO, &regset->fpsr);
-  collect_register (regcache, AARCH64_FPCR_REGNO, &regset->fpcr);
+    collect_register (regcache, AARCH64_V0_REGNUM + i, &regset->vregs[i]);
+  collect_register (regcache, AARCH64_FPSR_REGNUM, &regset->fpsr);
+  collect_register (regcache, AARCH64_FPCR_REGNUM, &regset->fpcr);
 }
 
 static void
@@ -148,9 +134,9 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
   int i;
 
   for (i = 0; i < AARCH64_V_REGS_NUM; i++)
-    supply_register (regcache, AARCH64_V0_REGNO + i, &regset->vregs[i]);
-  supply_register (regcache, AARCH64_FPSR_REGNO, &regset->fpsr);
-  supply_register (regcache, AARCH64_FPCR_REGNO, &regset->fpcr);
+    supply_register (regcache, AARCH64_V0_REGNUM + i, &regset->vregs[i]);
+  supply_register (regcache, AARCH64_FPSR_REGNUM, &regset->fpsr);
+  supply_register (regcache, AARCH64_FPCR_REGNUM, &regset->fpcr);
 }
 
 /* Enable miscellaneous debugging output.  The name is historical - it
@@ -163,23 +149,9 @@ static CORE_ADDR
 aarch64_get_pc (struct regcache *regcache)
 {
   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;
-    }
+    return linux_get_pc_64bit (regcache);
   else
-    {
-      unsigned int pc;
-
-      collect_register_by_name (regcache, "pc", &pc);
-      if (debug_threads)
-       debug_printf ("stop pc is %04x\n", pc);
-      return pc;
-    }
+    return linux_get_pc_32bit (regcache);
 }
 
 /* Implementation of linux_target_ops method "set_pc".  */
@@ -188,15 +160,9 @@ static void
 aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc)
 {
   if (register_size (regcache->tdesc, 0) == 8)
-    {
-      unsigned long newpc = pc;
-      supply_register_by_name (regcache, "pc", &newpc);
-    }
+    linux_set_pc_64bit (regcache, pc);
   else
-    {
-      unsigned int newpc = pc;
-      supply_register_by_name (regcache, "pc", &newpc);
-    }
+    linux_set_pc_32bit (regcache, pc);
 }
 
 #define aarch64_breakpoint_len 4
@@ -211,14 +177,19 @@ static const gdb_byte aarch64_breakpoint[] = {0x00, 0x00, 0x20, 0xd4};
 static int
 aarch64_breakpoint_at (CORE_ADDR where)
 {
-  gdb_byte insn[aarch64_breakpoint_len];
+  if (is_64bit_tdesc ())
+    {
+      gdb_byte insn[aarch64_breakpoint_len];
 
-  (*the_target->read_memory) (where, (unsigned char *) &insn,
-                             aarch64_breakpoint_len);
-  if (memcmp (insn, aarch64_breakpoint, aarch64_breakpoint_len) == 0)
-    return 1;
+      (*the_target->read_memory) (where, (unsigned char *) &insn,
+                                 aarch64_breakpoint_len);
+      if (memcmp (insn, aarch64_breakpoint, aarch64_breakpoint_len) == 0)
+       return 1;
 
-  return 0;
+      return 0;
+    }
+  else
+    return arm_breakpoint_at (where);
 }
 
 static void
@@ -260,22 +231,6 @@ 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:
@@ -432,7 +387,7 @@ 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 (struct ps_prochandle *ph,
                    lwpid_t lwpid, int idx, void **base)
 {
   return aarch64_ps_get_thread_area (ph, lwpid, idx, base,
@@ -442,7 +397,7 @@ ps_get_thread_area (const struct ps_prochandle *ph,
 /* Implementation of linux_target_ops method "siginfo_fixup".  */
 
 static int
-aarch64_linux_siginfo_fixup (siginfo_t *native, void *inf, int direction)
+aarch64_linux_siginfo_fixup (siginfo_t *native, gdb_byte *inf, int direction)
 {
   /* Is the inferior 32-bit?  If so, then fixup the siginfo object.  */
   if (!is_64bit_tdesc ())
@@ -460,7 +415,7 @@ aarch64_linux_siginfo_fixup (siginfo_t *native, void *inf, int direction)
   return 0;
 }
 
-/* Implementation of linux_target_ops method "linux_new_process".  */
+/* Implementation of linux_target_ops method "new_process".  */
 
 static struct arch_process_info *
 aarch64_linux_new_process (void)
@@ -472,6 +427,14 @@ aarch64_linux_new_process (void)
   return info;
 }
 
+/* Implementation of linux_target_ops method "delete_process".  */
+
+static void
+aarch64_linux_delete_process (struct arch_process_info *info)
+{
+  xfree (info);
+}
+
 /* Implementation of linux_target_ops method "linux_new_fork".  */
 
 static void
@@ -501,11 +464,10 @@ aarch64_linux_new_fork (struct process_info *parent,
   *child->priv->arch_private = *parent->priv->arch_private;
 }
 
-/* Return the right target description according to the ELF file of
-   current thread.  */
+/* Implementation of linux_target_ops method "arch_setup".  */
 
-static const struct target_desc *
-aarch64_linux_read_description (void)
+static void
+aarch64_arch_setup (void)
 {
   unsigned int machine;
   int is_elf64;
@@ -516,17 +478,9 @@ aarch64_linux_read_description (void)
   is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
 
   if (is_elf64)
-    return tdesc_aarch64;
+    current_process ()->tdesc = aarch64_linux_read_description ();
   else
-    return tdesc_arm_with_neon;
-}
-
-/* Implementation of linux_target_ops method "arch_setup".  */
-
-static void
-aarch64_arch_setup (void)
-{
-  current_process ()->tdesc = aarch64_linux_read_description ();
+    current_process ()->tdesc = tdesc_arm_with_neon;
 
   aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
 }
@@ -601,6 +555,24 @@ aarch64_get_thread_area (int lwpid, CORE_ADDR *addrp)
   return 0;
 }
 
+/* Implementation of linux_target_ops method "get_syscall_trapinfo".  */
+
+static void
+aarch64_get_syscall_trapinfo (struct regcache *regcache, int *sysno)
+{
+  int use_64bit = register_size (regcache->tdesc, 0) == 8;
+
+  if (use_64bit)
+    {
+      long l_sysno;
+
+      collect_register_by_name (regcache, "x8", &l_sysno);
+      *sysno = (int) l_sysno;
+    }
+  else
+    collect_register_by_name (regcache, "r7", sysno);
+}
+
 /* List of condition codes that we need.  */
 
 enum aarch64_condition_codes
@@ -614,17 +586,20 @@ enum aarch64_condition_codes
   LE = 0xd,
 };
 
+enum aarch64_operand_type
+{
+  OPERAND_IMMEDIATE,
+  OPERAND_REGISTER,
+};
+
 /* Representation of an operand.  At this time, it only supports register
    and immediate types.  */
 
 struct aarch64_operand
 {
   /* Type of the operand.  */
-  enum
-    {
-      OPERAND_IMMEDIATE,
-      OPERAND_REGISTER,
-    } type;
+  enum aarch64_operand_type type;
+
   /* Value of the operand according to the type.  */
   union
     {
@@ -1026,7 +1001,7 @@ emit_stlr (uint32_t *buf, struct aarch64_register rt,
 /* Helper function for data processing instructions with register sources.  */
 
 static int
-emit_data_processing_reg (uint32_t *buf, enum aarch64_opcodes opcode,
+emit_data_processing_reg (uint32_t *buf, uint32_t opcode,
                          struct aarch64_register rd,
                          struct aarch64_register rn,
                          struct aarch64_register rm)
@@ -1546,7 +1521,7 @@ append_insns (CORE_ADDR *to, size_t len, const uint32_t *buf)
 {
   size_t byte_len = len * sizeof (uint32_t);
 #if (__BYTE_ORDER == __BIG_ENDIAN)
-  uint32_t *le_buf = xmalloc (byte_len);
+  uint32_t *le_buf = (uint32_t *) xmalloc (byte_len);
   size_t i;
 
   for (i = 0; i < len; i++)
@@ -1585,7 +1560,7 @@ aarch64_ftrace_insn_reloc_b (const int is_bl, const int32_t offset,
 {
   struct aarch64_insn_relocation_data *insn_reloc
     = (struct aarch64_insn_relocation_data *) data;
-  int32_t new_offset
+  int64_t new_offset
     = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset;
 
   if (can_encode_int32 (new_offset, 28))
@@ -1600,7 +1575,7 @@ aarch64_ftrace_insn_reloc_b_cond (const unsigned cond, const int32_t offset,
 {
   struct aarch64_insn_relocation_data *insn_reloc
     = (struct aarch64_insn_relocation_data *) data;
-  int32_t new_offset
+  int64_t new_offset
     = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset;
 
   if (can_encode_int32 (new_offset, 21))
@@ -1637,7 +1612,7 @@ aarch64_ftrace_insn_reloc_cb (const int32_t offset, const int is_cbnz,
 {
   struct aarch64_insn_relocation_data *insn_reloc
     = (struct aarch64_insn_relocation_data *) data;
-  int32_t new_offset
+  int64_t new_offset
     = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset;
 
   if (can_encode_int32 (new_offset, 21))
@@ -1674,7 +1649,7 @@ aarch64_ftrace_insn_reloc_tb (const int32_t offset, int is_tbnz,
 {
   struct aarch64_insn_relocation_data *insn_reloc
     = (struct aarch64_insn_relocation_data *) data;
-  int32_t new_offset
+  int64_t new_offset
     = insn_reloc->base.insn_addr - insn_reloc->new_addr + offset;
 
   if (can_encode_int32 (new_offset, 16))
@@ -1810,7 +1785,7 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
 {
   uint32_t buf[256];
   uint32_t *p = buf;
-  int32_t offset;
+  int64_t offset;
   int i;
   uint32_t insn;
   CORE_ADDR buildaddr = *jump_entry;
@@ -2147,7 +2122,7 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
     {
       sprintf (err,
               "E.Jump back from jump pad too far from tracepoint "
-              "(offset 0x%" PRIx32 " cannot be encoded in 28 bits).",
+              "(offset 0x%" PRIx64 " cannot be encoded in 28 bits).",
               offset);
       return 1;
     }
@@ -2161,7 +2136,7 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
     {
       sprintf (err,
               "E.Jump pad too far from tracepoint "
-              "(offset 0x%" PRIx32 " cannot be encoded in 28 bits).",
+              "(offset 0x%" PRIx64 " cannot be encoded in 28 bits).",
               offset);
       return 1;
     }
@@ -2286,7 +2261,7 @@ aarch64_emit_add (void)
   uint32_t *p = buf;
 
   p += emit_pop (p, x1);
-  p += emit_add (p, x0, x0, register_operand (x1));
+  p += emit_add (p, x0, x1, register_operand (x0));
 
   emit_ops_insns (buf, p - buf);
 }
@@ -2300,7 +2275,7 @@ aarch64_emit_sub (void)
   uint32_t *p = buf;
 
   p += emit_pop (p, x1);
-  p += emit_sub (p, x0, x0, register_operand (x1));
+  p += emit_sub (p, x0, x1, register_operand (x0));
 
   emit_ops_insns (buf, p - buf);
 }
@@ -2937,8 +2912,44 @@ aarch64_supports_range_stepping (void)
 static const gdb_byte *
 aarch64_sw_breakpoint_from_kind (int kind, int *size)
 {
-  *size = aarch64_breakpoint_len;
-  return aarch64_breakpoint;
+  if (is_64bit_tdesc ())
+    {
+      *size = aarch64_breakpoint_len;
+      return aarch64_breakpoint;
+    }
+  else
+    return arm_sw_breakpoint_from_kind (kind, size);
+}
+
+/* Implementation of linux_target_ops method "breakpoint_kind_from_pc".  */
+
+static int
+aarch64_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
+{
+  if (is_64bit_tdesc ())
+    return aarch64_breakpoint_len;
+  else
+    return arm_breakpoint_kind_from_pc (pcptr);
+}
+
+/* Implementation of the linux_target_ops method
+   "breakpoint_kind_from_current_state".  */
+
+static int
+aarch64_breakpoint_kind_from_current_state (CORE_ADDR *pcptr)
+{
+  if (is_64bit_tdesc ())
+    return aarch64_breakpoint_len;
+  else
+    return arm_breakpoint_kind_from_current_state (pcptr);
+}
+
+/* Support for hardware single step.  */
+
+static int
+aarch64_supports_hardware_single_step (void)
+{
+  return 1;
 }
 
 struct linux_target_ops the_low_target =
@@ -2950,9 +2961,9 @@ struct linux_target_ops the_low_target =
   NULL, /* fetch_register */
   aarch64_get_pc,
   aarch64_set_pc,
-  NULL, /* breakpoint_kind_from_pc */
+  aarch64_breakpoint_kind_from_pc,
   aarch64_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,    /* decr_pc_after_break */
   aarch64_breakpoint_at,
   aarch64_supports_z_point_type,
@@ -2964,7 +2975,9 @@ struct linux_target_ops the_low_target =
   NULL, /* supply_ptrace_register */
   aarch64_linux_siginfo_fixup,
   aarch64_linux_new_process,
+  aarch64_linux_delete_process,
   aarch64_linux_new_thread,
+  aarch64_linux_delete_thread,
   aarch64_linux_new_fork,
   aarch64_linux_prepare_to_resume,
   NULL, /* process_qsupported */
@@ -2974,14 +2987,19 @@ struct linux_target_ops the_low_target =
   aarch64_emit_ops,
   aarch64_get_min_fast_tracepoint_insn_len,
   aarch64_supports_range_stepping,
+  aarch64_breakpoint_kind_from_current_state,
+  aarch64_supports_hardware_single_step,
+  aarch64_get_syscall_trapinfo,
 };
 
 void
 initialize_low_arch (void)
 {
-  init_registers_aarch64 ();
-
   initialize_low_arch_aarch32 ();
 
   initialize_regsets_info (&aarch64_regsets_info);
+
+#if GDB_SELF_TEST
+  initialize_low_tdesc ();
+#endif
 }
This page took 0.031064 seconds and 4 git commands to generate.