Fix "nosharedlibrary + continue + shared lib event" crash
[binutils-gdb.git] / gdb / aarch64-tdep.c
index 01e98b7195ecf21dd7e190a6152813f68fd8eda0..cb185ee337fe54ff65722a3fc01f2c60200241e0 100644 (file)
@@ -34,6 +34,7 @@
 #include "frame-base.h"
 #include "trad-frame.h"
 #include "objfiles.h"
+#include "dwarf2.h"
 #include "dwarf2-frame.h"
 #include "gdbtypes.h"
 #include "prologue-value.h"
@@ -248,6 +249,26 @@ class instruction_reader : public abstract_instruction_reader
 
 } // namespace
 
+/* If address signing is enabled, mask off the signature bits from ADDR, using
+   the register values in THIS_FRAME.  */
+
+static CORE_ADDR
+aarch64_frame_unmask_address (struct gdbarch_tdep *tdep,
+                             struct frame_info *this_frame,
+                             CORE_ADDR addr)
+{
+  if (tdep->has_pauth ()
+      && frame_unwind_register_unsigned (this_frame,
+                                        tdep->pauth_ra_state_regnum))
+    {
+      int cmask_num = AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base);
+      CORE_ADDR cmask = frame_unwind_register_unsigned (this_frame, cmask_num);
+      addr = addr & ~cmask;
+    }
+
+  return addr;
+}
+
 /* Analyze a prologue, looking for a recognizable stack frame
    and frame pointer.  Scan until we encounter a store that could
    clobber the stack frame unexpectedly, or an unknown instruction.  */
@@ -455,6 +476,37 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch,
          /* Stop analysis on branch.  */
          break;
        }
+      else if (inst.opcode->iclass == ic_system)
+       {
+         struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+         int ra_state_val = 0;
+
+         if (insn == 0xd503233f /* paciasp.  */
+             || insn == 0xd503237f  /* pacibsp.  */)
+           {
+             /* Return addresses are mangled.  */
+             ra_state_val = 1;
+           }
+         else if (insn == 0xd50323bf /* autiasp.  */
+                  || insn == 0xd50323ff /* autibsp.  */)
+           {
+             /* Return addresses are not mangled.  */
+             ra_state_val = 0;
+           }
+         else
+           {
+             if (aarch64_debug)
+               debug_printf ("aarch64: prologue analysis gave up addr=%s"
+                             " opcode=0x%x (iclass)\n",
+                             core_addr_to_string_nz (start), insn);
+             break;
+           }
+
+         if (tdep->has_pauth () && cache != nullptr)
+           trad_frame_set_value (cache->saved_regs,
+                                 tdep->pauth_ra_state_regnum,
+                                 ra_state_val);
+       }
       else
        {
          if (aarch64_debug)
@@ -561,11 +613,13 @@ aarch64_analyze_prologue_test (void)
   struct gdbarch *gdbarch = gdbarch_find_by_info (info);
   SELF_CHECK (gdbarch != NULL);
 
+  struct aarch64_prologue_cache cache;
+  cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
+
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   /* Test the simple prologue in which frame pointer is used.  */
   {
-    struct aarch64_prologue_cache cache;
-    cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
-
     static const uint32_t insns[] = {
       0xa9af7bfd, /* stp     x29, x30, [sp,#-272]! */
       0x910003fd, /* mov     x29, sp */
@@ -601,9 +655,6 @@ aarch64_analyze_prologue_test (void)
   /* Test a prologue in which STR is used and frame pointer is not
      used.  */
   {
-    struct aarch64_prologue_cache cache;
-    cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
-
     static const uint32_t insns[] = {
       0xf81d0ff3, /* str       x19, [sp, #-48]! */
       0xb9002fe0, /* str       w0, [sp, #44] */
@@ -614,6 +665,7 @@ aarch64_analyze_prologue_test (void)
     };
     instruction_reader_test reader (insns);
 
+    trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
     CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
 
     SELF_CHECK (end == 4 * 5);
@@ -643,6 +695,46 @@ aarch64_analyze_prologue_test (void)
                      == -1);
       }
   }
+
+  /* Test a prologue in which there is a return address signing instruction.  */
+  if (tdep->has_pauth ())
+    {
+      static const uint32_t insns[] = {
+       0xd503233f, /* paciasp */
+       0xa9bd7bfd, /* stp      x29, x30, [sp, #-48]! */
+       0x910003fd, /* mov      x29, sp */
+       0xf801c3f3, /* str      x19, [sp, #28] */
+       0xb9401fa0, /* ldr      x19, [x29, #28] */
+      };
+      instruction_reader_test reader (insns);
+
+      trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
+      CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache,
+                                               reader);
+
+      SELF_CHECK (end == 4 * 4);
+      SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM);
+      SELF_CHECK (cache.framesize == 48);
+
+      for (int i = 0; i < AARCH64_X_REGISTER_COUNT; i++)
+       {
+         if (i == 19)
+           SELF_CHECK (cache.saved_regs[i].addr == -20);
+         else if (i == AARCH64_FP_REGNUM)
+           SELF_CHECK (cache.saved_regs[i].addr == -48);
+         else if (i == AARCH64_LR_REGNUM)
+           SELF_CHECK (cache.saved_regs[i].addr == -40);
+         else
+           SELF_CHECK (cache.saved_regs[i].addr == -1);
+       }
+
+      if (tdep->has_pauth ())
+       {
+         SELF_CHECK (trad_frame_value_p (cache.saved_regs,
+                                         tdep->pauth_ra_state_regnum));
+         SELF_CHECK (cache.saved_regs[tdep->pauth_ra_state_regnum].addr == 1);
+       }
+    }
 }
 } // namespace selftests
 #endif /* GDB_SELF_TEST */
@@ -784,16 +876,15 @@ aarch64_make_prologue_cache (struct frame_info *this_frame, void **this_cache)
   cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
   *this_cache = cache;
 
-  TRY
+  try
     {
       aarch64_make_prologue_cache_1 (this_frame, cache);
     }
-  CATCH (ex, RETURN_MASK_ERROR)
+  catch (const gdb_exception_error &ex)
     {
       if (ex.error != NOT_AVAILABLE_ERROR)
-       throw_exception (ex);
+       throw;
     }
-  END_CATCH
 
   return cache;
 }
@@ -852,8 +943,16 @@ aarch64_prologue_prev_register (struct frame_info *this_frame,
   if (prev_regnum == AARCH64_PC_REGNUM)
     {
       CORE_ADDR lr;
+      struct gdbarch *gdbarch = get_frame_arch (this_frame);
+      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
       lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
+
+      if (tdep->has_pauth ()
+         && trad_frame_value_p (cache->saved_regs,
+                                tdep->pauth_ra_state_regnum))
+       lr = aarch64_frame_unmask_address (tdep, this_frame, lr);
+
       return frame_unwind_got_constant (this_frame, prev_regnum, lr);
     }
 
@@ -908,19 +1007,18 @@ aarch64_make_stub_cache (struct frame_info *this_frame, void **this_cache)
   cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
   *this_cache = cache;
 
-  TRY
+  try
     {
       cache->prev_sp = get_frame_register_unsigned (this_frame,
                                                    AARCH64_SP_REGNUM);
       cache->prev_pc = get_frame_pc (this_frame);
       cache->available_p = 1;
     }
-  CATCH (ex, RETURN_MASK_ERROR)
+  catch (const gdb_exception_error &ex)
     {
       if (ex.error != NOT_AVAILABLE_ERROR)
-       throw_exception (ex);
+       throw;
     }
-  END_CATCH
 
   return cache;
 }
@@ -1013,12 +1111,14 @@ static struct value *
 aarch64_dwarf2_prev_register (struct frame_info *this_frame,
                              void **this_cache, int regnum)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
   CORE_ADDR lr;
 
   switch (regnum)
     {
     case AARCH64_PC_REGNUM:
       lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
+      lr = aarch64_frame_unmask_address (tdep, this_frame, lr);
       return frame_unwind_got_constant (this_frame, regnum, lr);
 
     default:
@@ -1027,6 +1127,9 @@ aarch64_dwarf2_prev_register (struct frame_info *this_frame,
     }
 }
 
+static const unsigned char op_lit0 = DW_OP_lit0;
+static const unsigned char op_lit1 = DW_OP_lit1;
+
 /* Implement the "init_reg" dwarf2_frame_ops method.  */
 
 static void
@@ -1034,16 +1137,70 @@ aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
                               struct dwarf2_frame_state_reg *reg,
                               struct frame_info *this_frame)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   switch (regnum)
     {
     case AARCH64_PC_REGNUM:
       reg->how = DWARF2_FRAME_REG_FN;
       reg->loc.fn = aarch64_dwarf2_prev_register;
-      break;
+      return;
+
     case AARCH64_SP_REGNUM:
       reg->how = DWARF2_FRAME_REG_CFA;
-      break;
+      return;
     }
+
+  /* Init pauth registers.  */
+  if (tdep->has_pauth ())
+    {
+      if (regnum == tdep->pauth_ra_state_regnum)
+       {
+         /* Initialize RA_STATE to zero.  */
+         reg->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
+         reg->loc.exp.start = &op_lit0;
+         reg->loc.exp.len = 1;
+         return;
+       }
+      else if (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
+              || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
+       {
+         reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+         return;
+       }
+    }
+}
+
+/* Implement the execute_dwarf_cfa_vendor_op method.  */
+
+static bool
+aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
+                                    struct dwarf2_frame_state *fs)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct dwarf2_frame_state_reg *ra_state;
+
+  if (tdep->has_pauth () && op == DW_CFA_AARCH64_negate_ra_state)
+    {
+      /* Allocate RA_STATE column if it's not allocated yet.  */
+      fs->regs.alloc_regs (AARCH64_DWARF_PAUTH_RA_STATE + 1);
+
+      /* Toggle the status of RA_STATE between 0 and 1.  */
+      ra_state = &(fs->regs.reg[AARCH64_DWARF_PAUTH_RA_STATE]);
+      ra_state->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
+
+      if (ra_state->loc.exp.start == nullptr
+         || ra_state->loc.exp.start == &op_lit0)
+       ra_state->loc.exp.start = &op_lit1;
+      else
+       ra_state->loc.exp.start = &op_lit0;
+
+      ra_state->loc.exp.len = 1;
+
+      return true;
+    }
+
+  return false;
 }
 
 /* When arguments must be pushed onto the stack, they go on in reverse
@@ -1819,14 +1976,57 @@ aarch64_vnv_type (struct gdbarch *gdbarch)
 
   if (tdep->vnv_type == NULL)
     {
+      /* The other AArch64 psuedo registers (Q,D,H,S,B) refer to a single value
+        slice from the non-pseudo vector registers.  However NEON V registers
+        are always vector registers, and need constructing as such.  */
+      const struct builtin_type *bt = builtin_type (gdbarch);
+
       struct type *t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnv",
                                            TYPE_CODE_UNION);
 
-      append_composite_type_field (t, "d", aarch64_vnd_type (gdbarch));
-      append_composite_type_field (t, "s", aarch64_vns_type (gdbarch));
-      append_composite_type_field (t, "h", aarch64_vnh_type (gdbarch));
-      append_composite_type_field (t, "b", aarch64_vnb_type (gdbarch));
-      append_composite_type_field (t, "q", aarch64_vnq_type (gdbarch));
+      struct type *sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnd",
+                                TYPE_CODE_UNION);
+      append_composite_type_field (sub, "f",
+                                  init_vector_type (bt->builtin_double, 2));
+      append_composite_type_field (sub, "u",
+                                  init_vector_type (bt->builtin_uint64, 2));
+      append_composite_type_field (sub, "s",
+                                  init_vector_type (bt->builtin_int64, 2));
+      append_composite_type_field (t, "d", sub);
+
+      sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vns",
+                                TYPE_CODE_UNION);
+      append_composite_type_field (sub, "f",
+                                  init_vector_type (bt->builtin_float, 4));
+      append_composite_type_field (sub, "u",
+                                  init_vector_type (bt->builtin_uint32, 4));
+      append_composite_type_field (sub, "s",
+                                  init_vector_type (bt->builtin_int32, 4));
+      append_composite_type_field (t, "s", sub);
+
+      sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnh",
+                                TYPE_CODE_UNION);
+      append_composite_type_field (sub, "u",
+                                  init_vector_type (bt->builtin_uint16, 8));
+      append_composite_type_field (sub, "s",
+                                  init_vector_type (bt->builtin_int16, 8));
+      append_composite_type_field (t, "h", sub);
+
+      sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnb",
+                                TYPE_CODE_UNION);
+      append_composite_type_field (sub, "u",
+                                  init_vector_type (bt->builtin_uint8, 16));
+      append_composite_type_field (sub, "s",
+                                  init_vector_type (bt->builtin_int8, 16));
+      append_composite_type_field (t, "b", sub);
+
+      sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnq",
+                                TYPE_CODE_UNION);
+      append_composite_type_field (sub, "u",
+                                  init_vector_type (bt->builtin_uint128, 1));
+      append_composite_type_field (sub, "s",
+                                  init_vector_type (bt->builtin_int128, 1));
+      append_composite_type_field (t, "q", sub);
 
       tdep->vnv_type = t;
     }
@@ -2992,36 +3192,53 @@ aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
 static struct gdbarch *
 aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
-  struct gdbarch_tdep *tdep;
-  struct gdbarch *gdbarch;
-  struct gdbarch_list *best_arch;
-  struct tdesc_arch_data *tdesc_data = NULL;
-  const struct target_desc *tdesc = info.target_desc;
-  int i;
-  int valid_p = 1;
-  const struct tdesc_feature *feature_core;
-  const struct tdesc_feature *feature_fpu;
-  const struct tdesc_feature *feature_sve;
+  const struct tdesc_feature *feature_core, *feature_fpu, *feature_sve;
   const struct tdesc_feature *feature_pauth;
-  int num_regs = 0;
-  int num_pseudo_regs = 0;
-  int first_pauth_regnum = -1;
-  int pauth_ra_state_offset = -1;
+  bool valid_p = true;
+  int i, num_regs = 0, num_pseudo_regs = 0;
+  int first_pauth_regnum = -1, pauth_ra_state_offset = -1;
+
+  /* Use the vector length passed via the target info.  Here -1 is used for no
+     SVE, and 0 is unset.  If unset then use the vector length from the existing
+     tdesc.  */
+  uint64_t vq = 0;
+  if (info.id == (int *) -1)
+    vq = 0;
+  else if (info.id != 0)
+    vq = (uint64_t) info.id;
+  else
+    vq = aarch64_get_tdesc_vq (info.target_desc);
 
-  /* Ensure we always have a target description.  */
-  if (!tdesc_has_registers (tdesc))
-    tdesc = aarch64_read_description (0, false);
+  if (vq > AARCH64_MAX_SVE_VQ)
+    internal_error (__FILE__, __LINE__, _("VQ out of bounds: %ld (max %d)"),
+                   vq, AARCH64_MAX_SVE_VQ);
+
+  /* If there is already a candidate, use it.  */
+  for (gdbarch_list *best_arch = gdbarch_list_lookup_by_info (arches, &info);
+       best_arch != nullptr;
+       best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+    {
+      struct gdbarch_tdep *tdep = gdbarch_tdep (best_arch->gdbarch);
+      if (tdep && tdep->vq == vq)
+       return best_arch->gdbarch;
+    }
+
+  /* Ensure we always have a target descriptor, and that it is for the given VQ
+     value.  */
+  const struct target_desc *tdesc = info.target_desc;
+  if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc))
+    tdesc = aarch64_read_description (vq, false);
   gdb_assert (tdesc);
 
-  feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.core");
+  feature_core = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.core");
   feature_fpu = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu");
   feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
   feature_pauth = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth");
 
-  if (feature_core == NULL)
-    return NULL;
+  if (feature_core == nullptr)
+    return nullptr;
 
-  tdesc_data = tdesc_data_alloc ();
+  struct tdesc_arch_data *tdesc_data = tdesc_data_alloc ();
 
   /* Validate the description provides the mandatory core R registers
      and allocate their numbers.  */
@@ -3033,9 +3250,9 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   num_regs = AARCH64_X0_REGNUM + i;
 
   /* Add the V registers.  */
-  if (feature_fpu != NULL)
+  if (feature_fpu != nullptr)
     {
-      if (feature_sve != NULL)
+      if (feature_sve != nullptr)
        error (_("Program contains both fpu and SVE features."));
 
       /* Validate the description provides the mandatory V registers
@@ -3049,7 +3266,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
 
   /* Add the SVE registers.  */
-  if (feature_sve != NULL)
+  if (feature_sve != nullptr)
     {
       /* Validate the description provides the mandatory SVE registers
         and allocate their numbers.  */
@@ -3062,7 +3279,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       num_pseudo_regs += 32;   /* add the Vn register pseudos.  */
     }
 
-  if (feature_fpu != NULL || feature_sve != NULL)
+  if (feature_fpu != nullptr || feature_sve != nullptr)
     {
       num_pseudo_regs += 32;   /* add the Qn scalar register pseudos */
       num_pseudo_regs += 32;   /* add the Dn scalar register pseudos */
@@ -3090,41 +3307,24 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (!valid_p)
     {
       tdesc_data_cleanup (tdesc_data);
-      return NULL;
+      return nullptr;
     }
 
   /* AArch64 code is always little-endian.  */
   info.byte_order_for_code = BFD_ENDIAN_LITTLE;
 
-  /* If there is already a candidate, use it.  */
-  for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
-       best_arch != NULL;
-       best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
-    {
-      /* Found a match.  */
-      break;
-    }
-
-  if (best_arch != NULL)
-    {
-      if (tdesc_data != NULL)
-       tdesc_data_cleanup (tdesc_data);
-      return best_arch->gdbarch;
-    }
-
-  tdep = XCNEW (struct gdbarch_tdep);
-  gdbarch = gdbarch_alloc (&info, tdep);
+  struct gdbarch_tdep *tdep = XCNEW (struct gdbarch_tdep);
+  struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
 
   /* This should be low enough for everything.  */
   tdep->lowest_pc = 0x20;
   tdep->jb_pc = -1;            /* Longjump support not enabled by default.  */
   tdep->jb_elt_size = 8;
-  tdep->vq = aarch64_get_tdesc_vq (tdesc);
+  tdep->vq = vq;
   tdep->pauth_reg_base = first_pauth_regnum;
   tdep->pauth_ra_state_regnum = (feature_pauth == NULL) ? -1
                                : pauth_ra_state_offset + num_regs;
 
-
   set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
   set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
 
@@ -3192,6 +3392,9 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   gdbarch_init_osabi (info, gdbarch);
 
   dwarf2_frame_set_init_reg (gdbarch, aarch64_dwarf2_frame_init_reg);
+  /* Register DWARF CFA vendor handler.  */
+  set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch,
+                                          aarch64_execute_dwarf_cfa_vendor_op);
 
   /* Add some default predicates.  */
   frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);