diff mbox series

[5/8] GDB: aarch64-linux: Implement GCS support in displaced stepping

Message ID 20250608010338.2234530-6-thiago.bauermann@linaro.org
State New
Headers show
Series AArch64 Guarded Control Stack support | expand

Commit Message

Thiago Jung Bauermann June 8, 2025, 1:03 a.m. UTC
When doing displaced step on a branch and link instruction with the Guarded
Control Stack enabled, it's necessary to manually push and pop the GCS
entry for the function call since GDB writes a simple branch instruction
rather than a branch and link instruction in the displaced step buffer.
---
 gdb/NEWS                 |  3 +++
 gdb/aarch64-linux-tdep.c | 30 +++++++++++++++++++++++++
 gdb/aarch64-tdep.c       | 47 +++++++++++++++++++++++++++++++++++-----
 gdb/linux-tdep.h         |  7 ++++++
 4 files changed, 82 insertions(+), 5 deletions(-)

Comments

Eli Zaretskii June 8, 2025, 4:47 a.m. UTC | #1
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Date: Sat,  7 Jun 2025 22:03:16 -0300
> 
> When doing displaced step on a branch and link instruction with the Guarded
> Control Stack enabled, it's necessary to manually push and pop the GCS
> entry for the function call since GDB writes a simple branch instruction
> rather than a branch and link instruction in the displaced step buffer.
> ---
>  gdb/NEWS                 |  3 +++
>  gdb/aarch64-linux-tdep.c | 30 +++++++++++++++++++++++++
>  gdb/aarch64-tdep.c       | 47 +++++++++++++++++++++++++++++++++++-----
>  gdb/linux-tdep.h         |  7 ++++++
>  4 files changed, 82 insertions(+), 5 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index a82b7e3342c5..13a11134600f 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -48,6 +48,9 @@
>  
>   * Add record full support for rv64gc architectures
>  
> +* Debugging Linux programs that use AArch64 Guarded Control Stacks are now
> +  supported.
> +
>  * New commands
>  
>  maintenance check psymtabs

Thanks, the NEWS part is okay.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Thiago Jung Bauermann June 11, 2025, 12:43 a.m. UTC | #2
Eli Zaretskii <eliz@gnu.org> writes:

>> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Date: Sat,  7 Jun 2025 22:03:16 -0300
>> 
>> When doing displaced step on a branch and link instruction with the Guarded
>> Control Stack enabled, it's necessary to manually push and pop the GCS
>> entry for the function call since GDB writes a simple branch instruction
>> rather than a branch and link instruction in the displaced step buffer.
>> ---
>>  gdb/NEWS                 |  3 +++
>>  gdb/aarch64-linux-tdep.c | 30 +++++++++++++++++++++++++
>>  gdb/aarch64-tdep.c       | 47 +++++++++++++++++++++++++++++++++++-----
>>  gdb/linux-tdep.h         |  7 ++++++
>>  4 files changed, 82 insertions(+), 5 deletions(-)
>> 
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index a82b7e3342c5..13a11134600f 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -48,6 +48,9 @@
>>  
>>   * Add record full support for rv64gc architectures
>>  
>> +* Debugging Linux programs that use AArch64 Guarded Control Stacks are now
>> +  supported.
>> +
>>  * New commands
>>  
>>  maintenance check psymtabs
>
> Thanks, the NEWS part is okay.
>
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>

Thanks! Actually I just noticed that I should change "are now supported"
to "is now supported".
Schimpe, Christina June 11, 2025, 9:01 a.m. UTC | #3
> -----Original Message-----
> From: Eli Zaretskii <eliz@gnu.org>
> Sent: Sunday, June 8, 2025 6:47 AM
> To: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 5/8] GDB: aarch64-linux: Implement GCS support in
> displaced stepping
> 
> > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> > Date: Sat,  7 Jun 2025 22:03:16 -0300
> >
> > When doing displaced step on a branch and link instruction with the
> > Guarded Control Stack enabled, it's necessary to manually push and pop
> > the GCS entry for the function call since GDB writes a simple branch
> > instruction rather than a branch and link instruction in the displaced step buffer.
> > ---
> >  gdb/NEWS                 |  3 +++
> >  gdb/aarch64-linux-tdep.c | 30 +++++++++++++++++++++++++
> >  gdb/aarch64-tdep.c       | 47 +++++++++++++++++++++++++++++++++++-----
> >  gdb/linux-tdep.h         |  7 ++++++
> >  4 files changed, 82 insertions(+), 5 deletions(-)
> >
> > diff --git a/gdb/NEWS b/gdb/NEWS
> > index a82b7e3342c5..13a11134600f 100644
> > --- a/gdb/NEWS
> > +++ b/gdb/NEWS
> > @@ -48,6 +48,9 @@
> >
> >   * Add record full support for rv64gc architectures
> >
> > +* Debugging Linux programs that use AArch64 Guarded Control Stacks
> > +are now
> > +  supported.
> > +
> >  * New commands
> >
> >  maintenance check psymtabs
> 
> Thanks, the NEWS part is okay.
> 
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>

Hi Thiago and Eli,

I now realized that I entirely missed the NEWS part in my series for CET
shadow stack... I will add it in v4, which I am currently preparing. 

I wonder though for this series, shouldn't we have a NEWS entry already in the patch
which adds GCS register support?
For ARM SME register support, for instance, it is explicitly listed in the NEWS part. 

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
Luis Machado June 13, 2025, 4:41 p.m. UTC | #4
Hi,

On 6/8/25 02:03, Thiago Jung Bauermann wrote:
> When doing displaced step on a branch and link instruction with the Guarded
> Control Stack enabled, it's necessary to manually push and pop the GCS
> entry for the function call since GDB writes a simple branch instruction
> rather than a branch and link instruction in the displaced step buffer.
> ---
>  gdb/NEWS                 |  3 +++
>  gdb/aarch64-linux-tdep.c | 30 +++++++++++++++++++++++++
>  gdb/aarch64-tdep.c       | 47 +++++++++++++++++++++++++++++++++++-----
>  gdb/linux-tdep.h         |  7 ++++++
>  4 files changed, 82 insertions(+), 5 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index a82b7e3342c5..13a11134600f 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -48,6 +48,9 @@
>  
>   * Add record full support for rv64gc architectures
>  
> +* Debugging Linux programs that use AArch64 Guarded Control Stacks are now
> +  supported.
> +
>  * New commands
>  
>  maintenance check psymtabs
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 24fb151311c4..812486e0d250 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -2534,6 +2534,32 @@ aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, CORE_ADDR address)
>    return true;
>  }
>  
> +/* Implement the "get_shadow_stack_pointer" gdbarch method.  */
> +
> +static std::optional<CORE_ADDR>
> +aarch64_linux_get_shadow_stack_pointer (gdbarch *gdbarch, regcache *regcache,
> +					bool &shadow_stack_enabled)
> +{
> +  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
> +  shadow_stack_enabled = false;
> +
> +  if (!tdep->has_gcs ())
> +    return {};

As I mentioned in the previous patch, will we ever hit a situation in which has_gcs is true
but we don't have the Linux-specific GCS registers?

> +
> +  uint64_t features_enabled;
> +  enum register_status status = regcache->cooked_read (tdep->gcs_linux_reg_base,
> +						       &features_enabled);
> +  if (status != REG_VALID)
> +    error (_("Can't read $gcs_features_enabled."));
> +
> +  CORE_ADDR gcspr;
> +  status = regcache->cooked_read (tdep->gcs_reg_base, &gcspr);
> +  if (status != REG_VALID)
> +    error (_("Can't read $gcspr."));
> +
> +  shadow_stack_enabled = features_enabled & PR_SHADOW_STACK_ENABLE;
> +  return gcspr;
> +}
>  
>  /* AArch64 Linux implementation of the report_signal_info gdbarch
>     hook.  Displays information about possible memory tag violations.  */
> @@ -3103,6 +3129,10 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>       sections.  */
>    set_gdbarch_use_target_description_from_corefile_notes (gdbarch,
>  			    aarch64_use_target_description_from_corefile_notes);
> +
> +  if (tdep->has_gcs ())
> +    set_gdbarch_get_shadow_stack_pointer (gdbarch,
> +					aarch64_linux_get_shadow_stack_pointer);
>  }
>  
>  #if GDB_SELF_TEST
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index d728f60e9e15..4f204f2e4208 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -1911,6 +1911,24 @@ aarch64_push_gcs_entry (regcache *regs, CORE_ADDR lr_value)
>    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;
> +
> +  enum 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
> @@ -3602,6 +3620,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.  */
> @@ -3653,6 +3674,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);
>      }
>  }
>  
> @@ -3811,6 +3838,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);
> @@ -3907,20 +3940,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));
>  
> diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
> index 7083635b976c..21f46e2ef50d 100644
> --- a/gdb/linux-tdep.h
> +++ b/gdb/linux-tdep.h
> @@ -26,6 +26,13 @@
>  struct inferior;
>  struct regcache;
>  
> +/* Flag which enables shadow stack in PR_SET_SHADOW_STACK_STATUS prctl.  */
> +#ifndef PR_SHADOW_STACK_ENABLE
> +#define PR_SHADOW_STACK_ENABLE (1UL << 0)
> +#define PR_SHADOW_STACK_WRITE (1UL << 1)
> +#define PR_SHADOW_STACK_PUSH (1UL << 2)
> +#endif
> +
>  /* Enum used to define the extra fields of the siginfo type used by an
>     architecture.  */
>  enum linux_siginfo_extra_field_values
Thiago Jung Bauermann June 14, 2025, 2:10 a.m. UTC | #5
"Schimpe, Christina" <christina.schimpe@intel.com> writes:

>> -----Original Message-----
>> From: Eli Zaretskii <eliz@gnu.org>
>> Sent: Sunday, June 8, 2025 6:47 AM
>> To: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Cc: gdb-patches@sourceware.org
>> Subject: Re: [PATCH 5/8] GDB: aarch64-linux: Implement GCS support in
>> displaced stepping
>> 
>> > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> > Date: Sat,  7 Jun 2025 22:03:16 -0300
>> >
>> > When doing displaced step on a branch and link instruction with the
>> > Guarded Control Stack enabled, it's necessary to manually push and pop
>> > the GCS entry for the function call since GDB writes a simple branch
>> > instruction rather than a branch and link instruction in the displaced step buffer.
>> > ---
>> >  gdb/NEWS                 |  3 +++
>> >  gdb/aarch64-linux-tdep.c | 30 +++++++++++++++++++++++++
>> >  gdb/aarch64-tdep.c       | 47 +++++++++++++++++++++++++++++++++++-----
>> >  gdb/linux-tdep.h         |  7 ++++++
>> >  4 files changed, 82 insertions(+), 5 deletions(-)
>> >
>> > diff --git a/gdb/NEWS b/gdb/NEWS
>> > index a82b7e3342c5..13a11134600f 100644
>> > --- a/gdb/NEWS
>> > +++ b/gdb/NEWS
>> > @@ -48,6 +48,9 @@
>> >
>> >   * Add record full support for rv64gc architectures
>> >
>> > +* Debugging Linux programs that use AArch64 Guarded Control Stacks
>> > +are now
>> > +  supported.
>> > +
>> >  * New commands
>> >
>> >  maintenance check psymtabs
>> 
>> Thanks, the NEWS part is okay.
>> 
>> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
>
> Hi Thiago and Eli,
>
> I now realized that I entirely missed the NEWS part in my series for CET
> shadow stack... I will add it in v4, which I am currently preparing. 
>
> I wonder though for this series, shouldn't we have a NEWS entry already in the patch
> which adds GCS register support?
> For ARM SME register support, for instance, it is explicitly listed in the NEWS part.

I decided to put the NEWS entry in this patch because in the ones
before, GCS support is incomplete. On the other hand it does make sense
moving it to patch 3 since it's the one adding the target description
feature support. And on yet another hand I will make a separate patch in
v2 for the documentation changes, so to make things simpler I think it
makes sense to move the NEWS entry to it.

In any case, there's not much difference in practice since I expect a
GDB release will either have all these patches applied, or none of them.
Thiago Jung Bauermann June 14, 2025, 3:49 a.m. UTC | #6
Hello,

Luis Machado <luis.machado@arm.com> writes:

> On 6/8/25 02:03, Thiago Jung Bauermann wrote:
>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>> index 24fb151311c4..812486e0d250 100644
>> --- a/gdb/aarch64-linux-tdep.c
>> +++ b/gdb/aarch64-linux-tdep.c
>> @@ -2534,6 +2534,32 @@ aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, CORE_ADDR address)
>>    return true;
>>  }
>>  
>> +/* Implement the "get_shadow_stack_pointer" gdbarch method.  */
>> +
>> +static std::optional<CORE_ADDR>
>> +aarch64_linux_get_shadow_stack_pointer (gdbarch *gdbarch, regcache *regcache,
>> +					bool &shadow_stack_enabled)
>> +{
>> +  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
>> +  shadow_stack_enabled = false;
>> +
>> +  if (!tdep->has_gcs ())
>> +    return {};
>
> As I mentioned in the previous patch, will we ever hit a situation in which has_gcs is
> true but we don't have the Linux-specific GCS registers?

No (as explained in the reply I just sent). But for consistency I
changed the if condition above to check for tdep->has_gcs_linux ().

>> +
>> +  uint64_t features_enabled;
>> +  enum register_status status = regcache->cooked_read (tdep->gcs_linux_reg_base,
>> +						       &features_enabled);
>> +  if (status != REG_VALID)
>> +    error (_("Can't read $gcs_features_enabled."));
>> +
>> +  CORE_ADDR gcspr;
>> +  status = regcache->cooked_read (tdep->gcs_reg_base, &gcspr);
>> +  if (status != REG_VALID)
>> +    error (_("Can't read $gcspr."));
>> +
>> +  shadow_stack_enabled = features_enabled & PR_SHADOW_STACK_ENABLE;
>> +  return gcspr;
>> +}
>>  
>>  /* AArch64 Linux implementation of the report_signal_info gdbarch
>>     hook.  Displays information about possible memory tag violations.  */
diff mbox series

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index a82b7e3342c5..13a11134600f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -48,6 +48,9 @@ 
 
  * Add record full support for rv64gc architectures
 
+* Debugging Linux programs that use AArch64 Guarded Control Stacks are now
+  supported.
+
 * New commands
 
 maintenance check psymtabs
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 24fb151311c4..812486e0d250 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -2534,6 +2534,32 @@  aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, CORE_ADDR address)
   return true;
 }
 
+/* Implement the "get_shadow_stack_pointer" gdbarch method.  */
+
+static std::optional<CORE_ADDR>
+aarch64_linux_get_shadow_stack_pointer (gdbarch *gdbarch, regcache *regcache,
+					bool &shadow_stack_enabled)
+{
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+  shadow_stack_enabled = false;
+
+  if (!tdep->has_gcs ())
+    return {};
+
+  uint64_t features_enabled;
+  enum register_status status = regcache->cooked_read (tdep->gcs_linux_reg_base,
+						       &features_enabled);
+  if (status != REG_VALID)
+    error (_("Can't read $gcs_features_enabled."));
+
+  CORE_ADDR gcspr;
+  status = regcache->cooked_read (tdep->gcs_reg_base, &gcspr);
+  if (status != REG_VALID)
+    error (_("Can't read $gcspr."));
+
+  shadow_stack_enabled = features_enabled & PR_SHADOW_STACK_ENABLE;
+  return gcspr;
+}
 
 /* AArch64 Linux implementation of the report_signal_info gdbarch
    hook.  Displays information about possible memory tag violations.  */
@@ -3103,6 +3129,10 @@  aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
      sections.  */
   set_gdbarch_use_target_description_from_corefile_notes (gdbarch,
 			    aarch64_use_target_description_from_corefile_notes);
+
+  if (tdep->has_gcs ())
+    set_gdbarch_get_shadow_stack_pointer (gdbarch,
+					aarch64_linux_get_shadow_stack_pointer);
 }
 
 #if GDB_SELF_TEST
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index d728f60e9e15..4f204f2e4208 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -1911,6 +1911,24 @@  aarch64_push_gcs_entry (regcache *regs, CORE_ADDR lr_value)
   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;
+
+  enum 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
@@ -3602,6 +3620,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.  */
@@ -3653,6 +3674,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);
     }
 }
 
@@ -3811,6 +3838,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);
@@ -3907,20 +3940,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));
 
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index 7083635b976c..21f46e2ef50d 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -26,6 +26,13 @@ 
 struct inferior;
 struct regcache;
 
+/* Flag which enables shadow stack in PR_SET_SHADOW_STACK_STATUS prctl.  */
+#ifndef PR_SHADOW_STACK_ENABLE
+#define PR_SHADOW_STACK_ENABLE (1UL << 0)
+#define PR_SHADOW_STACK_WRITE (1UL << 1)
+#define PR_SHADOW_STACK_PUSH (1UL << 2)
+#endif
+
 /* Enum used to define the extra fields of the siginfo type used by an
    architecture.  */
 enum linux_siginfo_extra_field_values