aboutsummaryrefslogtreecommitdiff
path: root/gdb/aarch64-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/aarch64-tdep.c')
-rw-r--r--gdb/aarch64-tdep.c164
1 files changed, 154 insertions, 10 deletions
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index bf5b5d3..500ac77d 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -159,6 +159,18 @@ static const char *const aarch64_mte_register_names[] =
"tag_ctl"
};
+static const char *const aarch64_gcs_register_names[] = {
+ /* Guarded Control Stack Pointer Register. */
+ "gcspr"
+};
+
+static const char *const aarch64_gcs_linux_register_names[] = {
+ /* Field in struct user_gcs. */
+ "gcs_features_enabled",
+ /* Field in struct user_gcs. */
+ "gcs_features_locked",
+};
+
static int aarch64_stack_frame_destroyed_p (struct gdbarch *, CORE_ADDR);
/* AArch64 prologue cache structure. */
@@ -1396,6 +1408,12 @@ aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
return;
}
}
+ if (tdep->has_gcs () && tdep->fn_prev_gcspr != nullptr
+ && regnum == tdep->gcs_reg_base)
+ {
+ reg->how = DWARF2_FRAME_REG_FN;
+ reg->loc.fn = tdep->fn_prev_gcspr;
+ }
}
/* Implement the execute_dwarf_cfa_vendor_op method. */
@@ -1875,6 +1893,55 @@ pass_in_v_vfp_candidate (struct gdbarch *gdbarch, struct regcache *regcache,
}
}
+/* Push LR_VALUE to the Guarded Control Stack. */
+
+static void
+aarch64_push_gcs_entry (regcache *regs, CORE_ADDR lr_value)
+{
+ gdbarch *arch = regs->arch ();
+ aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (arch);
+ CORE_ADDR gcs_addr;
+
+ register_status status = regs->cooked_read (tdep->gcs_reg_base, &gcs_addr);
+ if (status != REG_VALID)
+ error (_("Can't read $gcspr."));
+
+ gcs_addr -= 8;
+ gdb_byte buf[8];
+ store_integer (buf, gdbarch_byte_order (arch), lr_value);
+ if (target_write_memory (gcs_addr, buf, sizeof (buf)) != 0)
+ error (_("Can't write to Guarded Control Stack."));
+
+ /* Update GCSPR. */
+ regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr);
+}
+
+/* Remove the newest entry from the Guarded Control Stack. */
+
+static void
+aarch64_pop_gcs_entry (regcache *regs)
+{
+ gdbarch *arch = regs->arch ();
+ aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (arch);
+ CORE_ADDR gcs_addr;
+
+ register_status status = regs->cooked_read (tdep->gcs_reg_base, &gcs_addr);
+ if (status != REG_VALID)
+ error (_("Can't read $gcspr."));
+
+ /* Update GCSPR. */
+ regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr + 8);
+}
+
+/* Implement the "shadow_stack_push" gdbarch method. */
+
+static void
+aarch64_shadow_stack_push (gdbarch *gdbarch, CORE_ADDR new_addr,
+ regcache *regcache)
+{
+ aarch64_push_gcs_entry (regcache, new_addr);
+}
+
/* Implement the "push_dummy_call" gdbarch method. */
static CORE_ADDR
@@ -3557,6 +3624,9 @@ struct aarch64_displaced_step_copy_insn_closure
/* PC adjustment offset after displaced stepping. If 0, then we don't
write the PC back, assuming the PC is already the right address. */
int32_t pc_adjust = 0;
+
+ /* True if it's a branch instruction that saves the link register. */
+ bool linked_branch = false;
};
/* Data when visiting instructions for displaced stepping. */
@@ -3608,6 +3678,12 @@ aarch64_displaced_step_b (const int is_bl, const int32_t offset,
/* Update LR. */
regcache_cooked_write_unsigned (dsd->regs, AARCH64_LR_REGNUM,
data->insn_addr + 4);
+ dsd->dsc->linked_branch = true;
+ bool gcs_is_enabled;
+ gdbarch_get_shadow_stack_pointer (dsd->regs->arch (), dsd->regs,
+ gcs_is_enabled);
+ if (gcs_is_enabled)
+ aarch64_push_gcs_entry (dsd->regs, data->insn_addr + 4);
}
}
@@ -3766,6 +3842,12 @@ aarch64_displaced_step_others (const uint32_t insn,
aarch64_emit_insn (dsd->insn_buf, insn & 0xffdfffff);
regcache_cooked_write_unsigned (dsd->regs, AARCH64_LR_REGNUM,
data->insn_addr + 4);
+ dsd->dsc->linked_branch = true;
+ bool gcs_is_enabled;
+ gdbarch_get_shadow_stack_pointer (dsd->regs->arch (), dsd->regs,
+ gcs_is_enabled);
+ if (gcs_is_enabled)
+ aarch64_push_gcs_entry (dsd->regs, data->insn_addr + 4);
}
else
aarch64_emit_insn (dsd->insn_buf, insn);
@@ -3862,20 +3944,24 @@ aarch64_displaced_step_fixup (struct gdbarch *gdbarch,
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs, bool completed_p)
{
+ aarch64_displaced_step_copy_insn_closure *dsc
+ = (aarch64_displaced_step_copy_insn_closure *) dsc_;
CORE_ADDR pc = regcache_read_pc (regs);
- /* If the displaced instruction didn't complete successfully then all we
- need to do is restore the program counter. */
+ /* If the displaced instruction didn't complete successfully then we need
+ to restore the program counter, and perhaps the Guarded Control Stack. */
if (!completed_p)
{
+ bool gcs_is_enabled;
+ gdbarch_get_shadow_stack_pointer (gdbarch, regs, gcs_is_enabled);
+ if (dsc->linked_branch && gcs_is_enabled)
+ aarch64_pop_gcs_entry (regs);
+
pc = from + (pc - to);
regcache_write_pc (regs, pc);
return;
}
- aarch64_displaced_step_copy_insn_closure *dsc
- = (aarch64_displaced_step_copy_insn_closure *) dsc_;
-
displaced_debug_printf ("PC after stepping: %s (was %s).",
paddress (gdbarch, pc), paddress (gdbarch, to));
@@ -4046,6 +4132,14 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
features.sme2 = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sme2")
!= nullptr);
+ /* Check for the GCS feature. */
+ features.gcs = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs")
+ != nullptr);
+
+ /* Check for the GCS Linux feature. */
+ features.gcs_linux = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs.linux")
+ != nullptr);
+
return features;
}
@@ -4236,7 +4330,7 @@ aarch64_memtag_to_string (struct gdbarch *gdbarch, struct value *tag_value)
CORE_ADDR tag = value_as_address (tag_value);
- return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
+ return string_printf ("0x%s", phex_nz (tag));
}
/* See aarch64-tdep.h. */
@@ -4590,6 +4684,48 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
int first_w_regnum = num_pseudo_regs;
num_pseudo_regs += 31;
+ const tdesc_feature *feature_gcs
+ = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs");
+ int first_gcs_regnum = -1;
+ /* Add the GCS registers. */
+ if (feature_gcs != nullptr)
+ {
+ first_gcs_regnum = num_regs;
+ /* Validate the descriptor provides the mandatory GCS registers and
+ allocate their numbers. */
+ for (i = 0; i < ARRAY_SIZE (aarch64_gcs_register_names); i++)
+ valid_p &= tdesc_numbered_register (feature_gcs, tdesc_data.get (),
+ first_gcs_regnum + i,
+ aarch64_gcs_register_names[i]);
+
+ num_regs += i;
+ }
+
+ if (!valid_p)
+ return nullptr;
+
+ const tdesc_feature *feature_gcs_linux
+ = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs.linux");
+ int first_gcs_linux_regnum = -1;
+ /* Add the GCS Linux registers. */
+ if (feature_gcs_linux != nullptr && feature_gcs == nullptr)
+ {
+ /* This feature depends on the GCS feature. */
+ return nullptr;
+ }
+ else if (feature_gcs_linux != nullptr)
+ {
+ first_gcs_linux_regnum = num_regs;
+ /* Validate the descriptor provides the mandatory GCS Linux registers
+ and allocate their numbers. */
+ for (i = 0; i < ARRAY_SIZE (aarch64_gcs_linux_register_names); i++)
+ valid_p &= tdesc_numbered_register (feature_gcs_linux, tdesc_data.get (),
+ first_gcs_linux_regnum + i,
+ aarch64_gcs_linux_register_names[i]);
+
+ num_regs += i;
+ }
+
if (!valid_p)
return nullptr;
@@ -4611,6 +4747,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep->mte_reg_base = first_mte_regnum;
tdep->tls_regnum_base = first_tls_regnum;
tdep->tls_register_count = tls_register_count;
+ tdep->gcs_reg_base = first_gcs_regnum;
+ tdep->gcs_linux_reg_base = first_gcs_linux_regnum;
/* Set the SME register set details. The pseudo-registers will be adjusted
later. */
@@ -4638,7 +4776,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_sw_breakpoint_from_kind (gdbarch,
aarch64_breakpoint::bp_from_kind);
set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
- set_gdbarch_software_single_step (gdbarch, aarch64_software_single_step);
+ set_gdbarch_get_next_pcs (gdbarch, aarch64_software_single_step);
/* Information about registers, etc. */
set_gdbarch_sp_regnum (gdbarch, AARCH64_SP_REGNUM);
@@ -4733,6 +4871,9 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_get_pc_address_flags (gdbarch, aarch64_get_pc_address_flags);
+ if (tdep->has_gcs ())
+ set_gdbarch_shadow_stack_push (gdbarch, aarch64_shadow_stack_push);
+
tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
/* Fetch the updated number of registers after we're done adding all
@@ -4905,6 +5046,11 @@ aarch64_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
pulongest (tdep->sme_tile_pseudo_base));
gdb_printf (file, _("aarch64_dump_tdep: sme_svq = %s\n"),
pulongest (tdep->sme_svq));
+
+ gdb_printf (file, _("aarch64_dump_tdep: gcs_reg_base = %d\n"),
+ tdep->gcs_reg_base);
+ gdb_printf (file, _("aarch64_dump_tdep: gcs_linux_reg_base = %d\n"),
+ tdep->gcs_linux_reg_base);
}
#if GDB_SELF_TEST
@@ -4914,9 +5060,7 @@ static void aarch64_process_record_test (void);
}
#endif
-void _initialize_aarch64_tdep ();
-void
-_initialize_aarch64_tdep ()
+INIT_GDB_FILE (aarch64_tdep)
{
gdbarch_register (bfd_arch_aarch64, aarch64_gdbarch_init,
aarch64_dump_tdep);