]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/arm-linux-tdep.c
gdb: Fix Windows build after #include shuffle
[thirdparty/binutils-gdb.git] / gdb / arm-linux-tdep.c
index 2d563c2b024f0a36431d1724affab3e58ed90509..43869e4fcfe262aea0c9ff04a4e9808e4b922b62 100644 (file)
@@ -1,6 +1,6 @@
 /* GNU/Linux on ARM target support.
 
-   Copyright (C) 1999-2020 Free Software Foundation, Inc.
+   Copyright (C) 1999-2024 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -17,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include "defs.h"
+#include "extract-store-integer.h"
 #include "target.h"
 #include "value.h"
 #include "gdbtypes.h"
@@ -32,6 +32,7 @@
 #include "breakpoint.h"
 #include "auxv.h"
 #include "xml-syscall.h"
+#include "expop.h"
 
 #include "aarch32-tdep.h"
 #include "arch/arm.h"
@@ -59,7 +60,7 @@
 
 /* Under ARM GNU/Linux the traditional way of performing a breakpoint
    is to execute a particular software interrupt, rather than use a
-   particular undefined instruction to provoke a trap.  Upon exection
+   particular undefined instruction to provoke a trap.  Upon execution
    of the software interrupt the kernel stops the inferior with a
    SIGTRAP, and wakes the debugger.  */
 
@@ -276,7 +277,7 @@ static struct arm_get_next_pcs_ops arm_linux_get_next_pcs_ops = {
 };
 
 static void
-arm_linux_sigtramp_cache (struct frame_info *this_frame,
+arm_linux_sigtramp_cache (const frame_info_ptr &this_frame,
                          struct trad_frame_cache *this_cache,
                          CORE_ADDR func, int regs_offset)
 {
@@ -299,7 +300,7 @@ arm_linux_sigtramp_cache (struct frame_info *this_frame,
 /* See arm-linux.h for stack layout details.  */
 static void
 arm_linux_sigreturn_init (const struct tramp_frame *self,
-                         struct frame_info *this_frame,
+                         const frame_info_ptr &this_frame,
                          struct trad_frame_cache *this_cache,
                          CORE_ADDR func)
 {
@@ -319,7 +320,7 @@ arm_linux_sigreturn_init (const struct tramp_frame *self,
 
 static void
 arm_linux_rt_sigreturn_init (const struct tramp_frame *self,
-                         struct frame_info *this_frame,
+                         const frame_info_ptr &this_frame,
                          struct trad_frame_cache *this_cache,
                          CORE_ADDR func)
 {
@@ -342,7 +343,7 @@ arm_linux_rt_sigreturn_init (const struct tramp_frame *self,
 
 static void
 arm_linux_restart_syscall_init (const struct tramp_frame *self,
-                               struct frame_info *this_frame,
+                               const frame_info_ptr &this_frame,
                                struct trad_frame_cache *this_cache,
                                CORE_ADDR func)
 {
@@ -711,7 +712,7 @@ arm_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
                                        void *cb_data,
                                        const struct regcache *regcache)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
 
   cb (".reg", ARM_LINUX_SIZEOF_GREGSET, ARM_LINUX_SIZEOF_GREGSET,
       &arm_linux_gregset, NULL, cb_data);
@@ -731,18 +732,19 @@ arm_linux_core_read_description (struct gdbarch *gdbarch,
                                 struct target_ops *target,
                                 bfd *abfd)
 {
-  CORE_ADDR arm_hwcap = linux_get_hwcap (target);
+  std::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target);
+  CORE_ADDR arm_hwcap = linux_get_hwcap (auxv, target, gdbarch);
 
   if (arm_hwcap & HWCAP_VFP)
     {
       /* NEON implies VFPv3-D32 or no-VFP unit.  Say that we only support
         Neon with VFPv3-D32.  */
       if (arm_hwcap & HWCAP_NEON)
-       return aarch32_read_description ();
+       return aarch32_read_description (false);
       else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
-       return arm_read_description (ARM_FP_TYPE_VFPV3);
+       return arm_read_description (ARM_FP_TYPE_VFPV3, false);
 
-      return arm_read_description (ARM_FP_TYPE_VFPV2);
+      return arm_read_description (ARM_FP_TYPE_VFPV2, false);
     }
 
   return nullptr;
@@ -754,7 +756,7 @@ arm_linux_core_read_description (struct gdbarch *gdbarch,
    will return to ARM or Thumb code.  Return 0 if it is not a
    rt_sigreturn/sigreturn syscall.  */
 static int
-arm_linux_sigreturn_return_addr (struct frame_info *frame,
+arm_linux_sigreturn_return_addr (const frame_info_ptr &frame,
                                 unsigned long svc_number,
                                 CORE_ADDR *pc, int *is_thumb)
 {
@@ -811,6 +813,32 @@ arm_linux_sigreturn_next_pc (struct regcache *regcache,
   return next_pc;
 }
 
+/* Return true if we're at execve syscall-exit-stop.  */
+
+static bool
+is_execve_syscall_exit (struct regcache *regs)
+{
+  ULONGEST reg = -1;
+
+  /* Check that lr is 0.  */
+  regcache_cooked_read_unsigned (regs, ARM_LR_REGNUM, &reg);
+  if (reg != 0)
+    return false;
+
+  /* Check that r0-r8 is 0.  */
+  for (int i = 0; i <= 8; ++i)
+    {
+      reg = -1;
+      regcache_cooked_read_unsigned (regs, ARM_A1_REGNUM + i, &reg);
+      if (reg != 0)
+       return false;
+    }
+
+  return true;
+}
+
+#define arm_sys_execve 11
+
 /* At a ptrace syscall-stop, return the syscall number.  This either
    comes from the SWI instruction (OABI) or from r7 (EABI).
 
@@ -828,6 +856,9 @@ arm_linux_get_syscall_number (struct gdbarch *gdbarch,
   int is_thumb;
   ULONGEST svc_number = -1;
 
+  if (is_execve_syscall_exit (regs))
+    return arm_sys_execve;
+
   regcache_cooked_read_unsigned (regs, ARM_PC_REGNUM, &pc);
   regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &cpsr);
   is_thumb = (cpsr & t_bit) != 0;
@@ -843,9 +874,14 @@ arm_linux_get_syscall_number (struct gdbarch *gdbarch,
 
       /* PC gets incremented before the syscall-stop, so read the
         previous instruction.  */
-      unsigned long this_instr = 
-       read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code);
-
+      unsigned long this_instr;
+      {
+       ULONGEST val;
+       if (!safe_read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code,
+                                               &val))
+         return -1;
+       this_instr = val;
+      }
       unsigned long svc_operand = (0x00ffffff & this_instr);
 
       if (svc_operand)
@@ -867,8 +903,10 @@ static CORE_ADDR
 arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
 {
   CORE_ADDR next_pc = 0;
-  CORE_ADDR pc = regcache_read_pc (self->regcache);
-  int is_thumb = arm_is_thumb (self->regcache);
+  regcache *regcache
+    = gdb::checked_static_cast<struct regcache *> (self->regcache);
+  CORE_ADDR pc = regcache_read_pc (regcache);
+  int is_thumb = arm_is_thumb (regcache);
   ULONGEST svc_number = 0;
 
   if (is_thumb)
@@ -878,7 +916,7 @@ arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
     }
   else
     {
-      struct gdbarch *gdbarch = self->regcache->arch ();
+      struct gdbarch *gdbarch = regcache->arch ();
       enum bfd_endian byte_order_for_code = 
        gdbarch_byte_order_for_code (gdbarch);
       unsigned long this_instr = 
@@ -901,8 +939,7 @@ arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
     {
       /* SIGRETURN or RT_SIGRETURN may affect the arm thumb mode, so
         update IS_THUMB.   */
-      next_pc = arm_linux_sigreturn_next_pc (self->regcache, svc_number,
-                                            &is_thumb);
+      next_pc = arm_linux_sigreturn_next_pc (regcache, svc_number, &is_thumb);
     }
 
   /* Addresses for calling Thumb functions have the bit 0 set.  */
@@ -946,7 +983,7 @@ arm_linux_software_single_step (struct regcache *regcache)
 static void
 arm_linux_cleanup_svc (struct gdbarch *gdbarch,
                       struct regcache *regs,
-                      arm_displaced_step_closure *dsc)
+                      arm_displaced_step_copy_insn_closure *dsc)
 {
   ULONGEST apparent_pc;
   int within_scratch;
@@ -970,11 +1007,11 @@ arm_linux_cleanup_svc (struct gdbarch *gdbarch,
 
 static int
 arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
-                   arm_displaced_step_closure *dsc)
+                   arm_displaced_step_copy_insn_closure *dsc)
 {
   CORE_ADDR return_to = 0;
 
-  struct frame_info *frame;
+  frame_info_ptr frame;
   unsigned int svc_number = displaced_read_reg (regs, dsc, 7);
   int is_sigreturn = 0;
   int is_thumb;
@@ -1010,9 +1047,6 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
            = set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame),
                                        bp_step_resume).release ();
 
-         /* set_momentary_breakpoint invalidates FRAME.  */
-         frame = NULL;
-
          /* We need to make sure we actually insert the momentary
             breakpoint set above.  */
          insert_breakpoints ();
@@ -1056,7 +1090,7 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
 static void
 cleanup_kernel_helper_return (struct gdbarch *gdbarch,
                              struct regcache *regs,
-                             arm_displaced_step_closure *dsc)
+                             arm_displaced_step_copy_insn_closure *dsc)
 {
   displaced_write_reg (regs, dsc, ARM_LR_REGNUM, dsc->tmp[0], CANNOT_WRITE_PC);
   displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->tmp[0], BRANCH_WRITE_PC);
@@ -1065,7 +1099,7 @@ cleanup_kernel_helper_return (struct gdbarch *gdbarch,
 static void
 arm_catch_kernel_helper_return (struct gdbarch *gdbarch, CORE_ADDR from,
                                CORE_ADDR to, struct regcache *regs,
-                               arm_displaced_step_closure *dsc)
+                               arm_displaced_step_copy_insn_closure *dsc)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
@@ -1094,13 +1128,13 @@ arm_catch_kernel_helper_return (struct gdbarch *gdbarch, CORE_ADDR from,
    the program has stepped into a Linux kernel helper routine (which must be
    handled as a special case).  */
 
-static displaced_step_closure_up
+static displaced_step_copy_insn_closure_up
 arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
                                    CORE_ADDR from, CORE_ADDR to,
                                    struct regcache *regs)
 {
-  std::unique_ptr<arm_displaced_step_closure> dsc
-    (new arm_displaced_step_closure);
+  std::unique_ptr<arm_displaced_step_copy_insn_closure> dsc
+    (new arm_displaced_step_copy_insn_closure);
 
   /* Detect when we enter an (inaccessible by GDB) Linux kernel helper, and
      stop at the return location.  */
@@ -1122,7 +1156,7 @@ arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
   arm_displaced_init_closure (gdbarch, from, to, dsc.get ());
 
   /* This is a work around for a problem with g++ 4.8.  */
-  return displaced_step_closure_up (dsc.release ());
+  return displaced_step_copy_insn_closure_up (dsc.release ());
 }
 
 /* Implementation of `gdbarch_stap_is_single_operand', as defined in
@@ -1146,7 +1180,7 @@ arm_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
    It returns one if the special token has been parsed successfully,
    or zero if the current token is not considered special.  */
 
-static int
+static expr::operation_up
 arm_stap_parse_special_token (struct gdbarch *gdbarch,
                              struct stap_parse_info *p)
 {
@@ -1161,7 +1195,6 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
       int len, offset;
       int got_minus = 0;
       long displacement;
-      struct stoken str;
 
       ++tmp;
       start = tmp;
@@ -1171,7 +1204,7 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
        ++tmp;
 
       if (*tmp != ',')
-       return 0;
+       return {};
 
       len = tmp - start;
       regname = (char *) alloca (len + 2);
@@ -1212,43 +1245,38 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
 
       /* Skipping last `]'.  */
       if (*tmp++ != ']')
-       return 0;
+       return {};
+      p->arg = tmp;
+
+      using namespace expr;
 
       /* The displacement.  */
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
-      write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
-      write_exp_elt_longcst (&p->pstate, displacement);
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
+      struct type *long_type = builtin_type (gdbarch)->builtin_long;
       if (got_minus)
-       write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+       displacement = -displacement;
+      operation_up disp = make_operation<long_const_operation> (long_type,
+                                                               displacement);
 
       /* The register name.  */
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-      str.ptr = regname;
-      str.length = len;
-      write_exp_string (&p->pstate, str);
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+      operation_up reg
+       = make_operation<register_operation> (regname);
 
-      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+      operation_up sum
+       = make_operation<add_operation> (std::move (reg), std::move (disp));
 
       /* Casting to the expected type.  */
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-      write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-
-      write_exp_elt_opcode (&p->pstate, UNOP_IND);
-
-      p->arg = tmp;
+      struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
+      sum = make_operation<unop_cast_operation> (std::move (sum),
+                                                arg_ptr_type);
+      return make_operation<unop_ind_operation> (std::move (sum));
     }
-  else
-    return 0;
 
-  return 1;
+  return {};
 }
 
 /* ARM process record-replay constructs: syscall, signal etc.  */
 
-struct linux_record_tdep arm_linux_record_tdep;
+static linux_record_tdep arm_linux_record_tdep;
 
 /* arm_canonicalize_syscall maps from the native arm Linux set
    of syscall ids into a canonical set of syscall ids used by
@@ -1269,7 +1297,7 @@ arm_canonicalize_syscall (int syscall)
     case 8: return gdb_sys_creat;
     case 9: return gdb_sys_link;
     case 10: return gdb_sys_unlink;
-    case 11: return gdb_sys_execve;
+    case arm_sys_execve: return gdb_sys_execve;
     case 12: return gdb_sys_chdir;
     case 13: return gdb_sys_time;
     case 14: return gdb_sys_mknod;
@@ -1615,6 +1643,7 @@ arm_canonicalize_syscall (int syscall)
     case 378: return gdb_sys_kcmp;
     case 379: return gdb_sys_finit_module;
       */
+    case 384: return gdb_sys_getrandom;
     case 983041: /* ARM_breakpoint */ return gdb_sys_no_syscall;
     case 983042: /* ARM_cacheflush */ return gdb_sys_no_syscall;
     case 983043: /* ARM_usr26 */ return gdb_sys_no_syscall;
@@ -1655,9 +1684,10 @@ arm_linux_syscall_record (struct regcache *regcache, unsigned long svc_number)
 
   if (syscall_gdb == gdb_sys_no_syscall)
     {
-      printf_unfiltered (_("Process record and replay target doesn't "
-                          "support syscall number %s\n"),
-                          plongest (svc_number));
+      gdb_printf (gdb_stderr,
+                 _("Process record and replay target doesn't "
+                   "support syscall number %s\n"),
+                 plongest (svc_number));
       return -1;
     }
 
@@ -1690,7 +1720,7 @@ arm_linux_syscall_record (struct regcache *regcache, unsigned long svc_number)
 /* Implement the skip_trampoline_code gdbarch method.  */
 
 static CORE_ADDR
-arm_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+arm_linux_skip_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
 {
   CORE_ADDR target_pc = arm_skip_stub (frame, pc);
 
@@ -1719,9 +1749,9 @@ arm_linux_init_abi (struct gdbarch_info info,
                                                                    NULL };
   static const char *const stap_register_indirection_suffixes[] = { "]",
                                                                    NULL };
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
 
-  linux_init_abi (info, gdbarch);
+  linux_init_abi (info, gdbarch, 1);
 
   tdep->lowest_pc = 0x8000;
   if (info.byte_order_for_code == BFD_ENDIAN_BIG)
@@ -1761,14 +1791,13 @@ arm_linux_init_abi (struct gdbarch_info info,
       break;
     default:
       internal_error
-       (__FILE__, __LINE__,
-        _("arm_linux_init_abi: Floating point model not supported"));
+       (_("arm_linux_init_abi: Floating point model not supported"));
       break;
     }
   tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE;
 
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   /* Single stepping.  */
   set_gdbarch_software_single_step (gdbarch, arm_linux_software_single_step);
@@ -1807,7 +1836,6 @@ arm_linux_init_abi (struct gdbarch_info info,
   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_location (gdbarch, linux_displaced_step_location);
 
   /* Reversible debugging, process record.  */
   set_gdbarch_process_record (gdbarch, arm_process_record);