Replace some xmalloc-family functions with XNEW-family ones
[deliverable/binutils-gdb.git] / gdb / arm-linux-tdep.c
index 98b912bcc0ce260c8909ed05e1494c71a84e7be2..b3ad8686e4852099bdcb4f508153b323a0eb5a45 100644 (file)
@@ -1,6 +1,6 @@
 /* GNU/Linux on ARM target support.
 
-   Copyright (C) 1999-2014 Free Software Foundation, Inc.
+   Copyright (C) 1999-2015 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -41,6 +41,7 @@
 #include "glibc-tdep.h"
 #include "arch-utils.h"
 #include "inferior.h"
+#include "infrun.h"
 #include "gdbthread.h"
 #include "symfile.h"
 
@@ -53,8 +54,6 @@
 #include "user-regs.h"
 #include <ctype.h>
 #include "elf/common.h"
-#include <string.h>
-
 extern int arm_apcs_32;
 
 /* Under ARM GNU/Linux the traditional way of performing a breakpoint
@@ -245,6 +244,13 @@ static const gdb_byte arm_linux_thumb2_le_breakpoint[] = { 0xf0, 0xf7, 0x00, 0xa
 #define ARM_SET_R7_RT_SIGRETURN                0xe3a070ad
 #define ARM_EABI_SYSCALL               0xef000000
 
+/* Equivalent patterns for Thumb2.  */
+#define THUMB2_SET_R7_SIGRETURN1       0xf04f
+#define THUMB2_SET_R7_SIGRETURN2       0x0777
+#define THUMB2_SET_R7_RT_SIGRETURN1    0xf04f
+#define THUMB2_SET_R7_RT_SIGRETURN2    0x07ad
+#define THUMB2_EABI_SYSCALL            0xdf00
+
 /* OABI syscall restart trampoline, used for EABI executables too
    whenever OABI support has been enabled in the kernel.  */
 #define ARM_OABI_SYSCALL_RESTART_SYSCALL 0xef900000
@@ -443,6 +449,30 @@ static struct tramp_frame arm_eabi_linux_rt_sigreturn_tramp_frame = {
   arm_linux_rt_sigreturn_init
 };
 
+static struct tramp_frame thumb2_eabi_linux_sigreturn_tramp_frame = {
+  SIGTRAMP_FRAME,
+  2,
+  {
+    { THUMB2_SET_R7_SIGRETURN1, -1 },
+    { THUMB2_SET_R7_SIGRETURN2, -1 },
+    { THUMB2_EABI_SYSCALL, -1 },
+    { TRAMP_SENTINEL_INSN }
+  },
+  arm_linux_sigreturn_init
+};
+
+static struct tramp_frame thumb2_eabi_linux_rt_sigreturn_tramp_frame = {
+  SIGTRAMP_FRAME,
+  2,
+  {
+    { THUMB2_SET_R7_RT_SIGRETURN1, -1 },
+    { THUMB2_SET_R7_RT_SIGRETURN2, -1 },
+    { THUMB2_EABI_SYSCALL, -1 },
+    { TRAMP_SENTINEL_INSN }
+  },
+  arm_linux_rt_sigreturn_init
+};
+
 static struct tramp_frame arm_linux_restart_syscall_tramp_frame = {
   NORMAL_FRAME,
   4,
@@ -686,60 +716,40 @@ arm_linux_collect_vfp (const struct regset *regset,
                            regs + (regno - ARM_D0_REGNUM) * 8);
 }
 
-/* Return the appropriate register set for the core section identified
-   by SECT_NAME and SECT_SIZE.  */
-
-static const struct regset *
-arm_linux_regset_from_core_section (struct gdbarch *gdbarch,
-                                   const char *sect_name, size_t sect_size)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
-  if (strcmp (sect_name, ".reg") == 0
-      && sect_size == ARM_LINUX_SIZEOF_GREGSET)
-    {
-      if (tdep->gregset == NULL)
-        tdep->gregset = regset_alloc (gdbarch, arm_linux_supply_gregset,
-                                      arm_linux_collect_gregset);
-      return tdep->gregset;
-    }
-
-  if (strcmp (sect_name, ".reg2") == 0
-      && sect_size == ARM_LINUX_SIZEOF_NWFPE)
-    {
-      if (tdep->fpregset == NULL)
-        tdep->fpregset = regset_alloc (gdbarch, arm_linux_supply_nwfpe,
-                                       arm_linux_collect_nwfpe);
-      return tdep->fpregset;
-    }
+static const struct regset arm_linux_gregset =
+  {
+    NULL, arm_linux_supply_gregset, arm_linux_collect_gregset
+  };
 
-  if (strcmp (sect_name, ".reg-arm-vfp") == 0
-      && sect_size == ARM_LINUX_SIZEOF_VFP)
-    {
-      if (tdep->vfpregset == NULL)
-        tdep->vfpregset = regset_alloc (gdbarch, arm_linux_supply_vfp,
-                                       arm_linux_collect_vfp);
-      return tdep->vfpregset;
-    }
+static const struct regset arm_linux_fpregset =
+  {
+    NULL, arm_linux_supply_nwfpe, arm_linux_collect_nwfpe
+  };
 
-  return NULL;
-}
+static const struct regset arm_linux_vfpregset =
+  {
+    NULL, arm_linux_supply_vfp, arm_linux_collect_vfp
+  };
 
-/* Core file register set sections.  */
+/* Iterate over core file register note sections.  */
 
-static struct core_regset_section arm_linux_fpa_regset_sections[] =
+static void
+arm_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                       iterate_over_regset_sections_cb *cb,
+                                       void *cb_data,
+                                       const struct regcache *regcache)
 {
-  { ".reg", ARM_LINUX_SIZEOF_GREGSET, "general-purpose" },
-  { ".reg2", ARM_LINUX_SIZEOF_NWFPE, "FPA floating-point" },
-  { NULL, 0}
-};
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-static struct core_regset_section arm_linux_vfp_regset_sections[] =
-{
-  { ".reg", ARM_LINUX_SIZEOF_GREGSET, "general-purpose" },
-  { ".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, "VFP floating-point" },
-  { NULL, 0}
-};
+  cb (".reg", ARM_LINUX_SIZEOF_GREGSET, &arm_linux_gregset, NULL, cb_data);
+
+  if (tdep->vfp_register_count > 0)
+    cb (".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, &arm_linux_vfpregset,
+       "VFP floating-point", cb_data);
+  else if (tdep->have_fpa_registers)
+    cb (".reg2", ARM_LINUX_SIZEOF_NWFPE, &arm_linux_fpregset,
+       "FPA floating-point", cb_data);
+}
 
 /* Determine target description from core file.  */
 
@@ -929,7 +939,6 @@ arm_linux_cleanup_svc (struct gdbarch *gdbarch,
                       struct regcache *regs,
                       struct displaced_step_closure *dsc)
 {
-  CORE_ADDR from = dsc->insn_addr;
   ULONGEST apparent_pc;
   int within_scratch;
 
@@ -950,7 +959,8 @@ arm_linux_cleanup_svc (struct gdbarch *gdbarch,
     }
 
   if (within_scratch)
-    displaced_write_reg (regs, dsc, ARM_PC_REGNUM, from + 4, BRANCH_WRITE_PC);
+    displaced_write_reg (regs, dsc, ARM_PC_REGNUM,
+                        dsc->insn_addr + dsc->insn_size, BRANCH_WRITE_PC);
 }
 
 static int
@@ -970,54 +980,54 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
                                                 &return_to, &is_thumb);
   if (is_sigreturn)
     {
-         struct symtab_and_line sal;
-
-         if (debug_displaced)
-           fprintf_unfiltered (gdb_stdlog, "displaced: found "
-             "sigreturn/rt_sigreturn SVC call.  PC in frame = %lx\n",
-             (unsigned long) get_frame_pc (frame));
-
-         if (debug_displaced)
-           fprintf_unfiltered (gdb_stdlog, "displaced: unwind pc = %lx.  "
-             "Setting momentary breakpoint.\n", (unsigned long) return_to);
-
-         gdb_assert (inferior_thread ()->control.step_resume_breakpoint
-                     == NULL);
-
-         sal = find_pc_line (return_to, 0);
-         sal.pc = return_to;
-         sal.section = find_pc_overlay (return_to);
-         sal.explicit_pc = 1;
-
-         frame = get_prev_frame (frame);
-
-         if (frame)
-           {
-             inferior_thread ()->control.step_resume_breakpoint
-               = set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame),
-                                           bp_step_resume);
-
-             /* set_momentary_breakpoint invalidates FRAME.  */
-             frame = NULL;
-
-             /* We need to make sure we actually insert the momentary
-                breakpoint set above.  */
-             insert_breakpoints ();
-           }
-         else if (debug_displaced)
-           fprintf_unfiltered (gdb_stderr, "displaced: couldn't find previous "
-                               "frame to set momentary breakpoint for "
-                               "sigreturn/rt_sigreturn\n");
+      struct symtab_and_line sal;
+
+      if (debug_displaced)
+       fprintf_unfiltered (gdb_stdlog, "displaced: found "
+                           "sigreturn/rt_sigreturn SVC call.  PC in "
+                           "frame = %lx\n",
+                           (unsigned long) get_frame_pc (frame));
+
+      if (debug_displaced)
+       fprintf_unfiltered (gdb_stdlog, "displaced: unwind pc = %lx.  "
+                           "Setting momentary breakpoint.\n",
+                           (unsigned long) return_to);
+
+      gdb_assert (inferior_thread ()->control.step_resume_breakpoint
+                 == NULL);
+
+      sal = find_pc_line (return_to, 0);
+      sal.pc = return_to;
+      sal.section = find_pc_overlay (return_to);
+      sal.explicit_pc = 1;
+
+      frame = get_prev_frame (frame);
+
+      if (frame)
+       {
+         inferior_thread ()->control.step_resume_breakpoint
+           = set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame),
+                                       bp_step_resume);
+
+         /* set_momentary_breakpoint invalidates FRAME.  */
+         frame = NULL;
+
+         /* We need to make sure we actually insert the momentary
+            breakpoint set above.  */
+         insert_breakpoints ();
        }
       else if (debug_displaced)
-       fprintf_unfiltered (gdb_stdlog, "displaced: sigreturn/rt_sigreturn "
-                           "SVC call not in signal trampoline frame\n");
-    
+       fprintf_unfiltered (gdb_stderr, "displaced: couldn't find previous "
+                           "frame to set momentary breakpoint for "
+                           "sigreturn/rt_sigreturn\n");
+    }
+  else if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: found SVC call\n");
 
   /* Preparation: If we detect sigreturn, set momentary breakpoint at resume
                  location, else nothing.
      Insn: unmodified svc.
-     Cleanup: if pc lands in scratch space, pc <- insn_addr + 4
+     Cleanup: if pc lands in scratch space, pc <- insn_addr + insn_size
               else leave pc alone.  */
 
 
@@ -1090,8 +1100,7 @@ arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
                                    CORE_ADDR from, CORE_ADDR to,
                                    struct regcache *regs)
 {
-  struct displaced_step_closure *dsc
-    = xmalloc (sizeof (struct displaced_step_closure));
+  struct displaced_step_closure *dsc = XNEW (struct displaced_step_closure);
 
   /* Detect when we enter an (inaccessible by GDB) Linux kernel helper, and
      stop at the return location.  */
@@ -1257,7 +1266,7 @@ arm_canonicalize_syscall (int syscall)
   else if (syscall >= 248 && syscall <= 253)
     return syscall + 4;
 
-  return -1;
+  return gdb_sys_no_syscall;
 }
 
 /* Record all registers but PC register for process-record.  */
@@ -1289,7 +1298,7 @@ arm_linux_syscall_record (struct regcache *regcache, unsigned long svc_number)
 
   syscall_gdb = arm_canonicalize_syscall (svc_number);
 
-  if (syscall_gdb < 0)
+  if (syscall_gdb == gdb_sys_no_syscall)
     {
       printf_unfiltered (_("Process record and replay target doesn't "
                            "support syscall number %s\n"),
@@ -1323,6 +1332,19 @@ arm_linux_syscall_record (struct regcache *regcache, unsigned long svc_number)
   return 0;
 }
 
+/* Implement the skip_trampoline_code gdbarch method.  */
+
+static CORE_ADDR
+arm_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+  CORE_ADDR target_pc = arm_skip_stub (frame, pc);
+
+  if (target_pc != 0)
+    return target_pc;
+
+  return find_solib_trampoline_target (frame, pc);
+}
+
 static void
 arm_linux_init_abi (struct gdbarch_info info,
                    struct gdbarch *gdbarch)
@@ -1338,7 +1360,7 @@ arm_linux_init_abi (struct gdbarch_info info,
   linux_init_abi (info, gdbarch);
 
   tdep->lowest_pc = 0x8000;
-  if (info.byte_order == BFD_ENDIAN_BIG)
+  if (info.byte_order_for_code == BFD_ENDIAN_BIG)
     {
       if (tdep->arm_abi == ARM_ABI_AAPCS)
        tdep->arm_breakpoint = eabi_linux_arm_be_breakpoint;
@@ -1388,7 +1410,7 @@ arm_linux_init_abi (struct gdbarch_info info,
   set_gdbarch_software_single_step (gdbarch, arm_linux_software_single_step);
 
   /* Shared library handling.  */
-  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+  set_gdbarch_skip_trampoline_code (gdbarch, arm_linux_skip_trampoline_code);
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
 
   /* Enable TLS support.  */
@@ -1403,30 +1425,27 @@ arm_linux_init_abi (struct gdbarch_info info,
                                &arm_eabi_linux_sigreturn_tramp_frame);
   tramp_frame_prepend_unwinder (gdbarch,
                                &arm_eabi_linux_rt_sigreturn_tramp_frame);
+  tramp_frame_prepend_unwinder (gdbarch,
+                               &thumb2_eabi_linux_sigreturn_tramp_frame);
+  tramp_frame_prepend_unwinder (gdbarch,
+                               &thumb2_eabi_linux_rt_sigreturn_tramp_frame);
   tramp_frame_prepend_unwinder (gdbarch,
                                &arm_linux_restart_syscall_tramp_frame);
   tramp_frame_prepend_unwinder (gdbarch,
                                &arm_kernel_linux_restart_syscall_tramp_frame);
 
   /* Core file support.  */
-  set_gdbarch_regset_from_core_section (gdbarch,
-                                       arm_linux_regset_from_core_section);
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, arm_linux_iterate_over_regset_sections);
   set_gdbarch_core_read_description (gdbarch, arm_linux_core_read_description);
 
-  if (tdep->have_vfp_registers)
-    set_gdbarch_core_regset_sections (gdbarch, arm_linux_vfp_regset_sections);
-  else if (tdep->have_fpa_registers)
-    set_gdbarch_core_regset_sections (gdbarch, arm_linux_fpa_regset_sections);
-
-  set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
-
   /* Displaced stepping.  */
   set_gdbarch_displaced_step_copy_insn (gdbarch,
                                        arm_linux_displaced_step_copy_insn);
   set_gdbarch_displaced_step_fixup (gdbarch, arm_displaced_step_fixup);
   set_gdbarch_displaced_step_free_closure (gdbarch,
                                           simple_displaced_step_free_closure);
-  set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point);
+  set_gdbarch_displaced_step_location (gdbarch, linux_displaced_step_location);
 
   /* Reversible debugging, process record.  */
   set_gdbarch_process_record (gdbarch, arm_process_record);
@@ -1446,7 +1465,7 @@ arm_linux_init_abi (struct gdbarch_info info,
   tdep->syscall_next_pc = arm_linux_syscall_next_pc;
 
   /* `catch syscall' */
-  set_xml_syscall_file_name ("syscalls/arm-linux.xml");
+  set_xml_syscall_file_name (gdbarch, "syscalls/arm-linux.xml");
   set_gdbarch_get_syscall_number (gdbarch, arm_linux_get_syscall_number);
 
   /* Syscall record.  */
This page took 0.038666 seconds and 4 git commands to generate.