Message ID | 20250608010338.2234530-5-thiago.bauermann@linaro.org |
---|---|
State | New |
Headers | show |
Series | AArch64 Guarded Control Stack support | expand |
Hi Thiago, Please see my feedback below. > -----Original Message----- > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org> > Sent: Sunday, June 8, 2025 3:03 AM > To: gdb-patches@sourceware.org > Subject: [PATCH 4/8] GDB: aarch64-linux: GCS support in Linux signals > > The signal frame can have a GCS context, so teach GDB how to use it. > > Also, there's a new SEGV sigcode when the inferior does an illegal memory access > in the Guarded Control Stack, so display a message when that is the case. > --- > gdb/aarch64-linux-tdep.c | 83 ++++++++++++++++++++++++++++++++---- > gdb/arch/aarch64-gcs-linux.h | 4 ++ > gdb/doc/gdb.texinfo | 8 ++++ > 3 files changed, 86 insertions(+), 9 deletions(-) > > diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index > ce213bb482b9..24fb151311c4 100644 > --- a/gdb/aarch64-linux-tdep.c > +++ b/gdb/aarch64-linux-tdep.c > @@ -165,6 +165,7 @@ > #define AARCH64_ZA_MAGIC 0x54366345 > #define AARCH64_TPIDR2_MAGIC 0x54504902 > #define AARCH64_ZT_MAGIC 0x5a544e01 > +#define AARCH64_GCS_MAGIC 0x47435300 > > /* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC. */ > #define AARCH64_EXTRA_DATAP_OFFSET 8 > @@ -206,6 +207,11 @@ > the signal context state. */ > #define AARCH64_SME2_CONTEXT_REGS_OFFSET 16 > > +/* GCSPR register value offset in the GCS signal frame context. */ > +#define AARCH64_GCS_CONTEXT_GCSPR_OFFSET 8 > +/* features_enabled value offset in the GCS signal frame context. */ > +#define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET 16 > + > /* Holds information about the signal frame. */ struct aarch64_linux_sigframe { > @@ -246,6 +252,13 @@ struct aarch64_linux_sigframe > bool za_payload = false; > /* True if we have a ZT entry in the signal context, false otherwise. */ > bool zt_available = false; > + > + /* True if we have a GCS entry in the signal context, false > + otherwise. */ bool gcs_availabe = false; > + /* The Guarded Control Stack Pointer Register. */ uint64_t gcspr; > + /* Flags indicating which GCS features are enabled for the thread. > + */ uint64_t gcs_features_enabled; > }; > > /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the @@ > -526,6 +539,39 @@ aarch64_linux_read_signal_frame_info (const > frame_info_ptr &this_frame, > signal_frame.zt_section = section; > signal_frame.zt_available = true; > > + section += size; > + break; > + } > + case AARCH64_GCS_MAGIC: > + { > + gdb_byte buf[8]; > + > + /* Extract the GCSPR. */ > + if (target_read_memory (section + > AARCH64_GCS_CONTEXT_GCSPR_OFFSET, > + buf, 8) != 0) > + { > + warning (_("Failed to read the GCSPR from the GCS signal frame" > + " context.")); > + section += size; > + break; > + } > + > + signal_frame.gcspr = extract_unsigned_integer (buf, byte_order); > + > + /* Extract the features_enabled field. */ > + if (target_read_memory (section > + + > AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET, > + buf, sizeof (buf)) != 0) > + { > + warning (_("Failed to read the enabled features from the GCS" > + " signal frame context.")); > + section += size; > + break; > + } > + > + signal_frame.gcs_features_enabled > + = extract_unsigned_integer (buf, byte_order); > + signal_frame.gcs_availabe = true; > section += size; > break; > } > @@ -703,6 +749,19 @@ aarch64_linux_sigframe_init (const struct tramp_frame > *self, > + AARCH64_TPIDR2_CONTEXT_TPIDR2_OFFSET); > } > > + /* Restore the GCS registers, if the target supports it and if there is > + an entry for them. */ > + if (signal_frame.gcs_availabe && tdep->has_gcs ()) > + { > + /* Restore GCSPR. */ > + trad_frame_set_reg_value (this_cache, tdep->gcs_reg_base, > + signal_frame.gcspr); > + /* Restore gcs_features_enabled. */ > + trad_frame_set_reg_value (this_cache, tdep->gcs_linux_reg_base, > + signal_frame.gcs_features_enabled); > + /* gcs_features_locked isn't present in the GCS signal context. */ > + } > + > trad_frame_set_id (this_cache, frame_id_build (signal_frame.sp, func)); } > > @@ -2486,17 +2545,18 @@ aarch64_linux_report_signal_info (struct gdbarch > *gdbarch, { > aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> > (gdbarch); > > - if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV) > + if (!(tdep->has_mte () || tdep->has_gcs ()) || siggnal != > + GDB_SIGNAL_SEGV) > return; > > CORE_ADDR fault_addr = 0; > - long si_code = 0; > + long si_code = 0, si_errno = 0; > > try > { > /* Sigcode tells us if the segfault is actually a memory tag > violation. */ > si_code = parse_and_eval_long ("$_siginfo.si_code"); > + si_errno = parse_and_eval_long ("$_siginfo.si_errno"); > > fault_addr > = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr"); > @@ -2507,13 +2567,18 @@ aarch64_linux_report_signal_info (struct gdbarch > *gdbarch, > return; > } > > - /* If this is not a memory tag violation, just return. */ > - if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR) > + const char *meaning; > + > + if (si_code == SEGV_MTEAERR || si_code == SEGV_MTESERR) > + meaning = _("Memory tag violation"); else if (si_code == > + SEGV_CPERR && si_errno == 0) > + meaning = _("Guarded Control Stack error"); else > return; > > uiout->text ("\n"); > > - uiout->field_string ("sigcode-meaning", _("Memory tag violation")); > + uiout->field_string ("sigcode-meaning", meaning); > > /* For synchronous faults, show additional information. */ > if (si_code == SEGV_MTESERR) > @@ -2539,7 +2604,7 @@ aarch64_linux_report_signal_info (struct gdbarch > *gdbarch, > uiout->field_string ("logical-tag", hex_string (ltag)); > } > } > - else > + else if (si_code != SEGV_CPERR) > { > uiout->text ("\n"); > uiout->text (_("Fault address unavailable")); @@ -2838,9 +2903,6 @@ > aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) > /* Register a hook for checking if an address is tagged or not. */ > set_gdbarch_tagged_address_p (gdbarch, > aarch64_linux_tagged_address_p); > > - set_gdbarch_report_signal_info (gdbarch, > - aarch64_linux_report_signal_info); > - > /* Core file helpers. */ > > /* Core file helper to create a memory tag section for a particular @@ - > 2857,6 +2919,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct > gdbarch *gdbarch) > > aarch64_linux_decode_memtag_section); > } > > + if (tdep->has_mte () || tdep->has_gcs ()) > + set_gdbarch_report_signal_info (gdbarch, > + aarch64_linux_report_signal_info); > + > /* Initialize the aarch64_linux_record_tdep. */ > /* These values are the size of the type that will be used in a system > call. They are obtained from Linux Kernel source. */ diff --git > a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h index > 9366caa7289a..853e748faf2d 100644 > --- a/gdb/arch/aarch64-gcs-linux.h > +++ b/gdb/arch/aarch64-gcs-linux.h > @@ -41,4 +41,8 @@ struct user_gcs > > #endif /* GCS_MAGIC */ > > +#ifndef SEGV_CPERR > +#define SEGV_CPERR 10 /* Control protection error. */ #endif For CET shadow stack we see the same si code. Would it make sense to make this part of the patch generic ? Christina Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928
On 6/8/25 02:03, Thiago Jung Bauermann wrote: > The signal frame can have a GCS context, so teach GDB how to use it. > > Also, there's a new SEGV sigcode when the inferior does an illegal > memory access in the Guarded Control Stack, so display a message when > that is the case. > --- > gdb/aarch64-linux-tdep.c | 83 ++++++++++++++++++++++++++++++++---- > gdb/arch/aarch64-gcs-linux.h | 4 ++ > gdb/doc/gdb.texinfo | 8 ++++ > 3 files changed, 86 insertions(+), 9 deletions(-) > > diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c > index ce213bb482b9..24fb151311c4 100644 > --- a/gdb/aarch64-linux-tdep.c > +++ b/gdb/aarch64-linux-tdep.c > @@ -165,6 +165,7 @@ > #define AARCH64_ZA_MAGIC 0x54366345 > #define AARCH64_TPIDR2_MAGIC 0x54504902 > #define AARCH64_ZT_MAGIC 0x5a544e01 > +#define AARCH64_GCS_MAGIC 0x47435300 > > /* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC. */ > #define AARCH64_EXTRA_DATAP_OFFSET 8 > @@ -206,6 +207,11 @@ > the signal context state. */ > #define AARCH64_SME2_CONTEXT_REGS_OFFSET 16 > > +/* GCSPR register value offset in the GCS signal frame context. */ > +#define AARCH64_GCS_CONTEXT_GCSPR_OFFSET 8 > +/* features_enabled value offset in the GCS signal frame context. */ > +#define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET 16 > + > /* Holds information about the signal frame. */ > struct aarch64_linux_sigframe > { > @@ -246,6 +252,13 @@ struct aarch64_linux_sigframe > bool za_payload = false; > /* True if we have a ZT entry in the signal context, false otherwise. */ > bool zt_available = false; > + > + /* True if we have a GCS entry in the signal context, false otherwise. */ > + bool gcs_availabe = false; > + /* The Guarded Control Stack Pointer Register. */ > + uint64_t gcspr; > + /* Flags indicating which GCS features are enabled for the thread. */ > + uint64_t gcs_features_enabled; > }; > > /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the > @@ -526,6 +539,39 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame, > signal_frame.zt_section = section; > signal_frame.zt_available = true; > > + section += size; > + break; > + } > + case AARCH64_GCS_MAGIC: > + { > + gdb_byte buf[8]; > + > + /* Extract the GCSPR. */ > + if (target_read_memory (section + AARCH64_GCS_CONTEXT_GCSPR_OFFSET, > + buf, 8) != 0) > + { > + warning (_("Failed to read the GCSPR from the GCS signal frame" Naming is hard, but would this read better? "Failed to read the GCS pointer from the GCS signal frame" > + " context.")); > + section += size; > + break; > + } > + > + signal_frame.gcspr = extract_unsigned_integer (buf, byte_order); > + > + /* Extract the features_enabled field. */ > + if (target_read_memory (section > + + AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET, > + buf, sizeof (buf)) != 0) > + { > + warning (_("Failed to read the enabled features from the GCS" > + " signal frame context.")); > + section += size; > + break; > + } > + > + signal_frame.gcs_features_enabled > + = extract_unsigned_integer (buf, byte_order); > + signal_frame.gcs_availabe = true; > section += size; > break; > } > @@ -703,6 +749,19 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, > + AARCH64_TPIDR2_CONTEXT_TPIDR2_OFFSET); > } > > + /* Restore the GCS registers, if the target supports it and if there is > + an entry for them. */ > + if (signal_frame.gcs_availabe && tdep->has_gcs ()) This checks tdep->has_gcs(), but assumes Linux-specific gcs_feature_enabled is available. I'm not sure if it would be possible to have gcs but not have the Linux-specific gcs registers. But the logic seems like it would allow that. Are there any concerns with that situation here? > + { > + /* Restore GCSPR. */ > + trad_frame_set_reg_value (this_cache, tdep->gcs_reg_base, > + signal_frame.gcspr); > + /* Restore gcs_features_enabled. */ > + trad_frame_set_reg_value (this_cache, tdep->gcs_linux_reg_base, > + signal_frame.gcs_features_enabled); > + /* gcs_features_locked isn't present in the GCS signal context. */ > + } > + > trad_frame_set_id (this_cache, frame_id_build (signal_frame.sp, func)); > } > > @@ -2486,17 +2545,18 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, > { > aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch); > > - if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV) > + if (!(tdep->has_mte () || tdep->has_gcs ()) || siggnal != GDB_SIGNAL_SEGV) > return; > > CORE_ADDR fault_addr = 0; > - long si_code = 0; > + long si_code = 0, si_errno = 0; > > try > { > /* Sigcode tells us if the segfault is actually a memory tag > violation. */ > si_code = parse_and_eval_long ("$_siginfo.si_code"); > + si_errno = parse_and_eval_long ("$_siginfo.si_errno"); > > fault_addr > = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr"); > @@ -2507,13 +2567,18 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, > return; > } > > - /* If this is not a memory tag violation, just return. */ > - if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR) > + const char *meaning; > + > + if (si_code == SEGV_MTEAERR || si_code == SEGV_MTESERR) > + meaning = _("Memory tag violation"); > + else if (si_code == SEGV_CPERR && si_errno == 0) > + meaning = _("Guarded Control Stack error"); > + else > return; > > uiout->text ("\n"); > > - uiout->field_string ("sigcode-meaning", _("Memory tag violation")); > + uiout->field_string ("sigcode-meaning", meaning); > > /* For synchronous faults, show additional information. */ > if (si_code == SEGV_MTESERR) > @@ -2539,7 +2604,7 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, > uiout->field_string ("logical-tag", hex_string (ltag)); > } > } > - else > + else if (si_code != SEGV_CPERR) > { > uiout->text ("\n"); > uiout->text (_("Fault address unavailable")); > @@ -2838,9 +2903,6 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) > /* Register a hook for checking if an address is tagged or not. */ > set_gdbarch_tagged_address_p (gdbarch, aarch64_linux_tagged_address_p); > > - set_gdbarch_report_signal_info (gdbarch, > - aarch64_linux_report_signal_info); > - > /* Core file helpers. */ > > /* Core file helper to create a memory tag section for a particular > @@ -2857,6 +2919,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) > aarch64_linux_decode_memtag_section); > } > > + if (tdep->has_mte () || tdep->has_gcs ()) > + set_gdbarch_report_signal_info (gdbarch, aarch64_linux_report_signal_info); > + > /* Initialize the aarch64_linux_record_tdep. */ > /* These values are the size of the type that will be used in a system > call. They are obtained from Linux Kernel source. */ > diff --git a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h > index 9366caa7289a..853e748faf2d 100644 > --- a/gdb/arch/aarch64-gcs-linux.h > +++ b/gdb/arch/aarch64-gcs-linux.h > @@ -41,4 +41,8 @@ struct user_gcs > > #endif /* GCS_MAGIC */ > > +#ifndef SEGV_CPERR > +#define SEGV_CPERR 10 /* Control protection error. */ > +#endif > + > #endif /* ARCH_AARCH64_GCS_LINUX_H */ > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 03f419e90436..1b35fa029884 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -26994,6 +26994,14 @@ information, see the > @uref{https://www.kernel.org/doc/html/latest/arch/arm64/gcs.html,ignored, > documentation} in the Linux kernel. > > +To aid debugging, @value{GDBN} will note when SIGSEGV signals are generated > +as a result of a Guarded Control Stack error: > + > +@smallexample > +Program received signal SIGSEGV, Segmentation fault > +Guarded Control Stack error. > +@end smallexample > + > @node x86 > @subsection x86 >
Hello Christina, "Schimpe, Christina" <christina.schimpe@intel.com> writes: > Please see my feedback below. Thanks! >> -----Original Message----- >> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org> >> Sent: Sunday, June 8, 2025 3:03 AM >> To: gdb-patches@sourceware.org >> Subject: [PATCH 4/8] GDB: aarch64-linux: GCS support in Linux signals >> >> a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h index >> 9366caa7289a..853e748faf2d 100644 >> --- a/gdb/arch/aarch64-gcs-linux.h >> +++ b/gdb/arch/aarch64-gcs-linux.h >> @@ -41,4 +41,8 @@ struct user_gcs >> >> #endif /* GCS_MAGIC */ >> >> +#ifndef SEGV_CPERR >> +#define SEGV_CPERR 10 /* Control protection error. */ #endif > > For CET shadow stack we see the same si code. > Would it make sense to make this part of the patch generic ? Indeed, I hadn't noticed. For v2 I moved the definition to gdb/linux-tdep.h.
Luis Machado <luis.machado@arm.com> writes: > On 6/8/25 02:03, Thiago Jung Bauermann wrote: >> @@ -526,6 +539,39 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame, >> signal_frame.zt_section = section; >> signal_frame.zt_available = true; >> >> + section += size; >> + break; >> + } >> + case AARCH64_GCS_MAGIC: >> + { >> + gdb_byte buf[8]; >> + >> + /* Extract the GCSPR. */ >> + if (target_read_memory (section + AARCH64_GCS_CONTEXT_GCSPR_OFFSET, >> + buf, 8) != 0) >> + { >> + warning (_("Failed to read the GCSPR from the GCS signal frame" > > Naming is hard, but would this read better? > > "Failed to read the GCS pointer from the GCS signal frame" I agree. I adopted your wording. >> + " context.")); >> + section += size; >> + break; >> + } >> + >> + signal_frame.gcspr = extract_unsigned_integer (buf, byte_order); >> + >> + /* Extract the features_enabled field. */ >> + if (target_read_memory (section >> + + AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET, >> + buf, sizeof (buf)) != 0) >> + { >> + warning (_("Failed to read the enabled features from the GCS" >> + " signal frame context.")); >> + section += size; >> + break; >> + } >> + >> + signal_frame.gcs_features_enabled >> + = extract_unsigned_integer (buf, byte_order); >> + signal_frame.gcs_availabe = true; >> section += size; >> break; >> } >> @@ -703,6 +749,19 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, >> + AARCH64_TPIDR2_CONTEXT_TPIDR2_OFFSET); >> } >> >> + /* Restore the GCS registers, if the target supports it and if there is >> + an entry for them. */ >> + if (signal_frame.gcs_availabe && tdep->has_gcs ()) > > This checks tdep->has_gcs(), but assumes Linux-specific gcs_feature_enabled is > available. I'm not sure if it would be possible to have gcs but not have the > Linux-specific gcs registers. But the logic seems like it would allow that. > > Are there any concerns with that situation here? Christina had a similar concern. Since this patch series only supports GCS in Linux userspace programs, it shouldn't happen in GDB that a target description has org.gnu.gdb.aarch64.gcs.linux but not org.gnu.gdb.aarch64.gcs or vice-versa. The patches I sent already check that if ….gcs.linux is present then ….gcs needs to be as well. For the other way around, for v2 I'm adding the following check to aarch64_linux_init_abi: if (tdep->has_gcs () && !tdep->has_gcs_linux ()) error (_("Incomplete GCS support in the target: missing Linux feature")); In addition, I'm changing the if condition above to check for tdep->has_gcs_linux () instead of tdep->has_gcs (). >> + { >> + /* Restore GCSPR. */ >> + trad_frame_set_reg_value (this_cache, tdep->gcs_reg_base, >> + signal_frame.gcspr); >> + /* Restore gcs_features_enabled. */ >> + trad_frame_set_reg_value (this_cache, tdep->gcs_linux_reg_base, >> + signal_frame.gcs_features_enabled); >> + /* gcs_features_locked isn't present in the GCS signal context. */ >> + } >> + >> trad_frame_set_id (this_cache, frame_id_build (signal_frame.sp, func)); >> } >>
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index ce213bb482b9..24fb151311c4 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -165,6 +165,7 @@ #define AARCH64_ZA_MAGIC 0x54366345 #define AARCH64_TPIDR2_MAGIC 0x54504902 #define AARCH64_ZT_MAGIC 0x5a544e01 +#define AARCH64_GCS_MAGIC 0x47435300 /* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC. */ #define AARCH64_EXTRA_DATAP_OFFSET 8 @@ -206,6 +207,11 @@ the signal context state. */ #define AARCH64_SME2_CONTEXT_REGS_OFFSET 16 +/* GCSPR register value offset in the GCS signal frame context. */ +#define AARCH64_GCS_CONTEXT_GCSPR_OFFSET 8 +/* features_enabled value offset in the GCS signal frame context. */ +#define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET 16 + /* Holds information about the signal frame. */ struct aarch64_linux_sigframe { @@ -246,6 +252,13 @@ struct aarch64_linux_sigframe bool za_payload = false; /* True if we have a ZT entry in the signal context, false otherwise. */ bool zt_available = false; + + /* True if we have a GCS entry in the signal context, false otherwise. */ + bool gcs_availabe = false; + /* The Guarded Control Stack Pointer Register. */ + uint64_t gcspr; + /* Flags indicating which GCS features are enabled for the thread. */ + uint64_t gcs_features_enabled; }; /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the @@ -526,6 +539,39 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame, signal_frame.zt_section = section; signal_frame.zt_available = true; + section += size; + break; + } + case AARCH64_GCS_MAGIC: + { + gdb_byte buf[8]; + + /* Extract the GCSPR. */ + if (target_read_memory (section + AARCH64_GCS_CONTEXT_GCSPR_OFFSET, + buf, 8) != 0) + { + warning (_("Failed to read the GCSPR from the GCS signal frame" + " context.")); + section += size; + break; + } + + signal_frame.gcspr = extract_unsigned_integer (buf, byte_order); + + /* Extract the features_enabled field. */ + if (target_read_memory (section + + AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET, + buf, sizeof (buf)) != 0) + { + warning (_("Failed to read the enabled features from the GCS" + " signal frame context.")); + section += size; + break; + } + + signal_frame.gcs_features_enabled + = extract_unsigned_integer (buf, byte_order); + signal_frame.gcs_availabe = true; section += size; break; } @@ -703,6 +749,19 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, + AARCH64_TPIDR2_CONTEXT_TPIDR2_OFFSET); } + /* Restore the GCS registers, if the target supports it and if there is + an entry for them. */ + if (signal_frame.gcs_availabe && tdep->has_gcs ()) + { + /* Restore GCSPR. */ + trad_frame_set_reg_value (this_cache, tdep->gcs_reg_base, + signal_frame.gcspr); + /* Restore gcs_features_enabled. */ + trad_frame_set_reg_value (this_cache, tdep->gcs_linux_reg_base, + signal_frame.gcs_features_enabled); + /* gcs_features_locked isn't present in the GCS signal context. */ + } + trad_frame_set_id (this_cache, frame_id_build (signal_frame.sp, func)); } @@ -2486,17 +2545,18 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, { aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch); - if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV) + if (!(tdep->has_mte () || tdep->has_gcs ()) || siggnal != GDB_SIGNAL_SEGV) return; CORE_ADDR fault_addr = 0; - long si_code = 0; + long si_code = 0, si_errno = 0; try { /* Sigcode tells us if the segfault is actually a memory tag violation. */ si_code = parse_and_eval_long ("$_siginfo.si_code"); + si_errno = parse_and_eval_long ("$_siginfo.si_errno"); fault_addr = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr"); @@ -2507,13 +2567,18 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, return; } - /* If this is not a memory tag violation, just return. */ - if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR) + const char *meaning; + + if (si_code == SEGV_MTEAERR || si_code == SEGV_MTESERR) + meaning = _("Memory tag violation"); + else if (si_code == SEGV_CPERR && si_errno == 0) + meaning = _("Guarded Control Stack error"); + else return; uiout->text ("\n"); - uiout->field_string ("sigcode-meaning", _("Memory tag violation")); + uiout->field_string ("sigcode-meaning", meaning); /* For synchronous faults, show additional information. */ if (si_code == SEGV_MTESERR) @@ -2539,7 +2604,7 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, uiout->field_string ("logical-tag", hex_string (ltag)); } } - else + else if (si_code != SEGV_CPERR) { uiout->text ("\n"); uiout->text (_("Fault address unavailable")); @@ -2838,9 +2903,6 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* Register a hook for checking if an address is tagged or not. */ set_gdbarch_tagged_address_p (gdbarch, aarch64_linux_tagged_address_p); - set_gdbarch_report_signal_info (gdbarch, - aarch64_linux_report_signal_info); - /* Core file helpers. */ /* Core file helper to create a memory tag section for a particular @@ -2857,6 +2919,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) aarch64_linux_decode_memtag_section); } + if (tdep->has_mte () || tdep->has_gcs ()) + set_gdbarch_report_signal_info (gdbarch, aarch64_linux_report_signal_info); + /* Initialize the aarch64_linux_record_tdep. */ /* These values are the size of the type that will be used in a system call. They are obtained from Linux Kernel source. */ diff --git a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h index 9366caa7289a..853e748faf2d 100644 --- a/gdb/arch/aarch64-gcs-linux.h +++ b/gdb/arch/aarch64-gcs-linux.h @@ -41,4 +41,8 @@ struct user_gcs #endif /* GCS_MAGIC */ +#ifndef SEGV_CPERR +#define SEGV_CPERR 10 /* Control protection error. */ +#endif + #endif /* ARCH_AARCH64_GCS_LINUX_H */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 03f419e90436..1b35fa029884 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -26994,6 +26994,14 @@ information, see the @uref{https://www.kernel.org/doc/html/latest/arch/arm64/gcs.html,ignored, documentation} in the Linux kernel. +To aid debugging, @value{GDBN} will note when SIGSEGV signals are generated +as a result of a Guarded Control Stack error: + +@smallexample +Program received signal SIGSEGV, Segmentation fault +Guarded Control Stack error. +@end smallexample + @node x86 @subsection x86