public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
@ 2022-02-04  8:41 christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 1/5] gdb/arm: Fix prologue analysis to support vpush christophe.lyon.oss
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: christophe.lyon.oss @ 2022-02-04  8:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: torbjorn.svensson

From: Christophe Lyon <christophe.lyon@foss.st.com>

This patch series introduces support for the multiple stack pointers
on v8-M architecture (MSP_S, MSP_NS, PSP_S, PSP_NS).

This enables to unwind through Secure vs Non-secure context switches.

Along the way, the first patch adds support to detect vpush
instructions in function prologues, which in particular is used in the
CMSE trampolines.

v3 fixes two small silly mistakes in patches 4 and 5.

Christophe Lyon (5):
  gdb/arm: Fix prologue analysis to support vpush
  gdb/arm: Define MSP and PSP registers for M-Profile
  gdb/arm: Introduce arm_cache_init
  gdb/arm: Add support for multiple stack pointers on Cortex-M
  gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add
    unwind-ns-to-s command

 gdb/NEWS                          |   5 +
 gdb/arch/arm.c                    |   6 +
 gdb/arch/arm.h                    |   1 +
 gdb/arm-tdep.c                    | 698 +++++++++++++++++++++++++-----
 gdb/arm-tdep.h                    |  10 +
 gdb/doc/gdb.texinfo               |  10 +
 gdb/features/Makefile             |   1 +
 gdb/features/arm/arm-m-system.c   |  15 +
 gdb/features/arm/arm-m-system.xml |  12 +
 gdb/features/arm/arm-secext.c     |  17 +
 gdb/features/arm/arm-secext.xml   |  15 +
 11 files changed, 691 insertions(+), 99 deletions(-)
 create mode 100644 gdb/features/arm/arm-m-system.c
 create mode 100644 gdb/features/arm/arm-m-system.xml
 create mode 100644 gdb/features/arm/arm-secext.c
 create mode 100644 gdb/features/arm/arm-secext.xml

-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 1/5] gdb/arm: Fix prologue analysis to support vpush
  2022-02-04  8:41 [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M christophe.lyon.oss
@ 2022-02-04  8:41 ` christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 2/5] gdb/arm: Define MSP and PSP registers for M-Profile christophe.lyon.oss
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: christophe.lyon.oss @ 2022-02-04  8:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: torbjorn.svensson, Christophe Lyon

From: Christophe Lyon <christophe.lyon@foss.st.com>

While working on adding support for Non-secure/Secure modes unwinding,
I noticed that the prologue analysis lacked support for vpush, which
is used for instance in the CMSE stub routine.

This patch updates thumb_analyze_prologue accordingly, adding support
for vpush of D-registers.

Signed-off-by: Christophe Lyon <christophe.lyon@foss.st.com>
---
 gdb/arm-tdep.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 7495434484e..7d52d2d78f6 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -896,6 +896,31 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
 		regs[bits (insn, 0, 3)] = addr;
 	    }
 
+	  else if ((insn & 0xff20) == 0xed20    /* vstmdb Rn{!}, { D-registers} */
+		   && (inst2 & 0x0f00) == 0x0b00/* (aka vpush) */
+		   && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+	    {
+	      /* Address SP points to.  */
+	      pv_t addr = regs[bits (insn, 0, 3)];
+
+	      /* Number of registers saved.  */
+	      int number = bits (inst2, 0, 7) >> 1;
+
+	      if (stack.store_would_trash (addr))
+		break;
+
+	      /* Calculate offsets of saved registers.  */
+	      for (; number > 0; number--)
+		{
+		  addr = pv_add_constant (addr, -8);
+		  stack.store (addr, 8, pv_register (ARM_D0_REGNUM + number, 0));
+		}
+
+	      /* Writeback SP if needed.  */
+	      if (insn & 0x0020)
+		regs[bits (insn, 0, 3)] = addr;
+	    }
+
 	  else if ((insn & 0xff50) == 0xe940	/* strd Rt, Rt2,
 						   [Rn, #+/-imm]{!} */
 		   && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 2/5] gdb/arm: Define MSP and PSP registers for M-Profile
  2022-02-04  8:41 [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 1/5] gdb/arm: Fix prologue analysis to support vpush christophe.lyon.oss
@ 2022-02-04  8:41 ` christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 3/5] gdb/arm: Introduce arm_cache_init christophe.lyon.oss
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: christophe.lyon.oss @ 2022-02-04  8:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: torbjorn.svensson, Christophe Lyon

From: Christophe Lyon <christophe.lyon@foss.st.com>

This patch removes the hardcoded access to PSP in
arm_m_exception_cache() and relies on the definition with the XML
descriptions.

Signed-off-by: Christophe Lyon <christophe.lyon@foss.st.com>
---
 gdb/arch/arm.c                    |  6 +++
 gdb/arch/arm.h                    |  1 +
 gdb/arm-tdep.c                    | 80 ++++++++++++++++++++-----------
 gdb/arm-tdep.h                    |  3 ++
 gdb/features/Makefile             |  1 +
 gdb/features/arm/arm-m-system.c   | 15 ++++++
 gdb/features/arm/arm-m-system.xml | 12 +++++
 7 files changed, 89 insertions(+), 29 deletions(-)
 create mode 100644 gdb/features/arm/arm-m-system.c
 create mode 100644 gdb/features/arm/arm-m-system.xml

diff --git a/gdb/arch/arm.c b/gdb/arch/arm.c
index a18b38b9d81..377baf677de 100644
--- a/gdb/arch/arm.c
+++ b/gdb/arch/arm.c
@@ -28,6 +28,7 @@
 #include "../features/arm/arm-m-profile.c"
 #include "../features/arm/arm-m-profile-with-fpa.c"
 #include "../features/arm/arm-m-profile-mve.c"
+#include "../features/arm/arm-m-system.c"
 
 /* See arm.h.  */
 
@@ -446,6 +447,11 @@ arm_create_mprofile_target_description (arm_m_profile_type m_type)
       regnum = create_feature_arm_arm_m_profile_mve (tdesc, regnum);
       break;
 
+    case ARM_M_TYPE_SYSTEM:
+      regnum = create_feature_arm_arm_m_profile (tdesc, regnum);
+      regnum = create_feature_arm_arm_m_system (tdesc, regnum);
+      break;
+
     default:
       error (_("Invalid Arm M type: %d"), m_type);
     }
diff --git a/gdb/arch/arm.h b/gdb/arch/arm.h
index eabcb434f1f..39e96910a4d 100644
--- a/gdb/arch/arm.h
+++ b/gdb/arch/arm.h
@@ -92,6 +92,7 @@ enum arm_m_profile_type {
    ARM_M_TYPE_VFP_D16,
    ARM_M_TYPE_WITH_FPA,
    ARM_M_TYPE_MVE,
+   ARM_M_TYPE_SYSTEM,
    ARM_M_TYPE_INVALID
 };
 
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 7d52d2d78f6..8533851eceb 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -3014,9 +3014,9 @@ arm_m_exception_cache (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
   struct arm_prologue_cache *cache;
   CORE_ADDR lr;
-  CORE_ADDR sp;
   CORE_ADDR unwound_sp;
   LONGEST xpsr;
   uint32_t exc_return;
@@ -3032,7 +3032,6 @@ arm_m_exception_cache (struct frame_info *this_frame)
      to the exception and if FPU is used (causing extended stack frame).  */
 
   lr = get_frame_register_unsigned (this_frame, ARM_LR_REGNUM);
-  sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
 
   /* Check EXC_RETURN indicator bits.  */
   exc_return = (((lr >> 28) & 0xf) == 0xf);
@@ -3041,37 +3040,13 @@ arm_m_exception_cache (struct frame_info *this_frame)
   process_stack_used = ((lr & (1 << 2)) != 0);
   if (exc_return && process_stack_used)
     {
-      /* Thread (process) stack used.
-	 Potentially this could be other register defined by target, but PSP
-	 can be considered a standard name for the "Process Stack Pointer".
-	 To be fully aware of system registers like MSP and PSP, these could
-	 be added to a separate XML arm-m-system-profile that is valid for
-	 ARMv6-M and ARMv7-M architectures. Also to be able to debug eg a
-	 corefile off-line, then these registers must be defined by GDB,
-	 and also be included in the corefile regsets.  */
-
-      int psp_regnum = user_reg_map_name_to_regnum (gdbarch, "psp", -1);
-      if (psp_regnum == -1)
-	{
-	  /* Thread (process) stack could not be fetched,
-	     give warning and exit.  */
-
-	  warning (_("no PSP thread stack unwinding supported."));
-
-	  /* Terminate any further stack unwinding by refer to self.  */
-	  cache->prev_sp = sp;
-	  return cache;
-	}
-      else
-	{
-	  /* Thread (process) stack used, use PSP as SP.  */
-	  unwound_sp = get_frame_register_unsigned (this_frame, psp_regnum);
-	}
+      /* Thread (process) stack used, use PSP as SP.  */
+      unwound_sp = get_frame_register_unsigned (this_frame, tdep->m_profile_psp_regnum);
     }
   else
     {
       /* Main stack used, use MSP as SP.  */
-      unwound_sp = sp;
+      unwound_sp = get_frame_register_unsigned (this_frame, tdep->m_profile_msp_regnum);
     }
 
   /* The hardware saves eight 32-bit words, comprising xPSR,
@@ -9038,6 +9013,10 @@ arm_register_g_packet_guesses (struct gdbarch *gdbarch)
       register_remote_g_packet_guess (gdbarch, ARM_CORE_REGS_SIZE
 				      + ARM_VFP2_REGS_SIZE
 				      + ARM_INT_REGISTER_SIZE, tdesc);
+
+      /* M-profile system (stack pointers).  */
+      tdesc = arm_read_mprofile_description (ARM_M_TYPE_SYSTEM);
+      register_remote_g_packet_guess (gdbarch, 2 * ARM_INT_REGISTER_SIZE, tdesc);
     }
 
   /* Otherwise we don't have a useful guess.  */
@@ -9098,6 +9077,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   bool have_mve = false;
   int mve_vpr_regnum = -1;
   int register_count = ARM_NUM_REGS;
+  bool have_m_profile_sp = false;
+  int m_profile_msp_regnum = -1;
+  int m_profile_psp_regnum = -1;
 
   /* If we have an object to base this architecture on, try to determine
      its ABI.  */
@@ -9300,6 +9282,35 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       if (!valid_p)
 	return NULL;
 
+      if (is_m)
+	{
+	  feature = tdesc_find_feature (tdesc,
+					"org.gnu.gdb.arm.m-system");
+	  if (feature != nullptr)
+	    {
+	      /* MSP */
+	      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
+						  register_count, "msp");
+	      if (!valid_p)
+		{
+		  warning (_("M-profile is missing required register msp."));
+		  return nullptr;
+		}
+	      have_m_profile_sp = true;
+	      m_profile_msp_regnum = register_count++;
+
+	      /* PSP */
+	      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
+						  register_count, "psp");
+	      if (!valid_p)
+		{
+		  warning (_("M-profile is missing required register psp."));
+		  return nullptr;
+		}
+	      m_profile_psp_regnum = register_count++;
+	    }
+	}
+
       feature = tdesc_find_feature (tdesc,
 				    "org.gnu.gdb.arm.fpa");
       if (feature != NULL)
@@ -9499,6 +9510,13 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       tdep->mve_vpr_regnum = mve_vpr_regnum;
     }
 
+  /* Adjust the M-profile stack pointers settings.  */
+  if (have_m_profile_sp)
+    {
+      tdep->m_profile_msp_regnum = m_profile_msp_regnum;
+      tdep->m_profile_psp_regnum = m_profile_psp_regnum;
+    }
+
   arm_register_g_packet_guesses (gdbarch);
 
   /* Breakpoints.  */
@@ -9771,6 +9789,10 @@ arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 		      tdep->mve_pseudo_base);
   fprintf_unfiltered (file, _("arm_dump_tdep: mve_pseudo_count = %i\n"),
 		      tdep->mve_pseudo_count);
+  fprintf_unfiltered (file, _("arm_dump_tdep: m_profile_msp_regnum = %i\n"),
+		      tdep->m_profile_msp_regnum);
+  fprintf_unfiltered (file, _("arm_dump_tdep: m_profile_psp_regnum = %i\n"),
+		      tdep->m_profile_psp_regnum);
   fprintf_unfiltered (file, _("arm_dump_tdep: Lowest pc = 0x%lx\n"),
 		      (unsigned long) tdep->lowest_pc);
 }
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 9012b9da100..420af43a1fe 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -119,6 +119,9 @@ struct arm_gdbarch_tdep : gdbarch_tdep
   int mve_pseudo_base = 0;	/* Number of the first MVE pseudo register.  */
   int mve_pseudo_count = 0;	/* Total number of MVE pseudo registers.  */
 
+  int m_profile_msp_regnum = 0;	/* M-profile MSP register number.  */
+  int m_profile_psp_regnum = 0;	/* M-profile PSP register number.  */
+
   bool is_m = false;		/* Does the target follow the "M" profile.  */
   CORE_ADDR lowest_pc = 0;	/* Lowest address at which instructions
 				   will appear.  */
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 311176aba28..cb39f54e46e 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -205,6 +205,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	arm/arm-fpa.xml \
 	arm/arm-m-profile.xml \
 	arm/arm-m-profile-mve.xml \
+	arm/arm-m-system.xml \
 	arm/arm-m-profile-with-fpa.xml \
 	arm/arm-vfpv2.xml \
 	arm/arm-vfpv3.xml \
diff --git a/gdb/features/arm/arm-m-system.c b/gdb/features/arm/arm-m-system.c
new file mode 100644
index 00000000000..3fb20a57198
--- /dev/null
+++ b/gdb/features/arm/arm-m-system.c
@@ -0,0 +1,15 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: arm-m-system.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_arm_arm_m_system (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.m-system");
+  tdesc_create_reg (feature, "msp", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "psp", regnum++, 1, NULL, 32, "data_ptr");
+  return regnum;
+}
diff --git a/gdb/features/arm/arm-m-system.xml b/gdb/features/arm/arm-m-system.xml
new file mode 100644
index 00000000000..eb167adb21a
--- /dev/null
+++ b/gdb/features/arm/arm-m-system.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.m-system">
+  <reg name="msp" bitsize="32" type="data_ptr"/>
+  <reg name="psp" bitsize="32" type="data_ptr"/>
+</feature>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 3/5] gdb/arm: Introduce arm_cache_init
  2022-02-04  8:41 [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 1/5] gdb/arm: Fix prologue analysis to support vpush christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 2/5] gdb/arm: Define MSP and PSP registers for M-Profile christophe.lyon.oss
@ 2022-02-04  8:41 ` christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 4/5] gdb/arm: Add support for multiple stack pointers on Cortex-M christophe.lyon.oss
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: christophe.lyon.oss @ 2022-02-04  8:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: torbjorn.svensson, Christophe Lyon

From: Christophe Lyon <christophe.lyon@foss.st.com>

This patch is a preparation for the rest of the series and adds two
arm_cache_init helper functions. It updates every place that updates
cache->saved_regs to call the helper instead.

Signed-off-by: Torbjorn Svensson <torbjorn.svensson@st.com>
Signed-off-by: Christophe Lyon <christophe.lyon@foss.st.com>
---
 gdb/arm-tdep.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 8533851eceb..18b7c18d3cc 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -290,6 +290,23 @@ struct arm_prologue_cache
   trad_frame_saved_reg *saved_regs;
 };
 
+static void
+arm_cache_init (struct arm_prologue_cache *cache, struct gdbarch *gdbarch)
+{
+  cache->framesize = 0;
+  cache->framereg = 0;
+  cache->saved_regs = trad_frame_alloc_saved_regs (gdbarch);
+}
+
+static void
+arm_cache_init (struct arm_prologue_cache *cache, struct frame_info *frame)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  cache->prev_sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
+
+  arm_cache_init (cache, gdbarch);
+}
+
 namespace {
 
 /* Abstract class to read ARM instructions from memory.  */
@@ -1926,7 +1943,7 @@ arm_make_prologue_cache (struct frame_info *this_frame)
   CORE_ADDR unwound_fp;
 
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
-  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  arm_cache_init (cache, this_frame);
 
   arm_scan_prologue (this_frame, cache);
 
@@ -2392,7 +2409,7 @@ arm_exidx_fill_cache (struct frame_info *this_frame, gdb_byte *entry)
 
   struct arm_prologue_cache *cache;
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
-  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  arm_cache_init (cache, this_frame);
 
   for (;;)
     {
@@ -2786,7 +2803,7 @@ arm_make_epilogue_frame_cache (struct frame_info *this_frame)
   int reg;
 
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
-  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  arm_cache_init (cache, this_frame);
 
   /* Still rely on the offset calculated from prologue.  */
   arm_scan_prologue (this_frame, cache);
@@ -2947,7 +2964,7 @@ arm_make_stub_cache (struct frame_info *this_frame)
   struct arm_prologue_cache *cache;
 
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
-  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  arm_cache_init (cache, this_frame);
 
   cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
 
@@ -3025,7 +3042,7 @@ arm_m_exception_cache (struct frame_info *this_frame)
   uint32_t secure_stack_used;
 
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
-  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  arm_cache_init (cache, this_frame);
 
   /* ARMv7-M Architecture Reference "B1.5.6 Exception entry behavior"
      describes which bits in LR that define which stack was used prior
@@ -13611,7 +13628,7 @@ arm_analyze_prologue_test ()
 
       test_arm_instruction_reader mem_reader (insns);
       arm_prologue_cache cache;
-      cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
+      arm_cache_init (&cache, gdbarch);
 
       arm_analyze_prologue (gdbarch, 0, sizeof (insns) - 1, &cache, mem_reader);
     }
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 4/5] gdb/arm: Add support for multiple stack pointers on Cortex-M
  2022-02-04  8:41 [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M christophe.lyon.oss
                   ` (2 preceding siblings ...)
  2022-02-04  8:41 ` [PATCH v3 3/5] gdb/arm: Introduce arm_cache_init christophe.lyon.oss
@ 2022-02-04  8:41 ` christophe.lyon.oss
  2022-02-04  8:41 ` [PATCH v3 5/5] gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add unwind-ns-to-s command christophe.lyon.oss
  2022-02-25  9:54 ` [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M Maxim Kuvyrkov
  5 siblings, 0 replies; 13+ messages in thread
From: christophe.lyon.oss @ 2022-02-04  8:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: torbjorn.svensson, Christophe Lyon

From: Christophe Lyon <christophe.lyon@foss.st.com>

V8-M architecture with Security extension features four stack pointers
to handle Secure and Non-secure modes.

This patch adds support to switch between them as needed during
unwinding, and replaces all updates of cache->prev_sp with calls to
arm_cache_set_prev_sp.

Signed-off-by: Torbjorn Svensson <torbjorn.svensson@st.com>
Signed-off-by: Christophe Lyon <christophe.lyon@foss.st.com>
---
 gdb/arm-tdep.c                  | 257 +++++++++++++++++++++++++++++---
 gdb/arm-tdep.h                  |  11 +-
 gdb/features/arm/arm-secext.c   |  17 +++
 gdb/features/arm/arm-secext.xml |  15 ++
 4 files changed, 279 insertions(+), 21 deletions(-)
 create mode 100644 gdb/features/arm/arm-secext.c
 create mode 100644 gdb/features/arm/arm-secext.xml

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 18b7c18d3cc..79c4cc6206f 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -275,7 +275,21 @@ struct arm_prologue_cache
   /* The stack pointer at the time this frame was created; i.e. the
      caller's stack pointer when this function was called.  It is used
      to identify this frame.  */
-  CORE_ADDR prev_sp;
+  CORE_ADDR sp;
+
+  /* Additional stack pointers used by M-profile with Security extension.  */
+  /* Use msp_s / psp_s to hold the values of msp / psp when there is
+     no Security extension.  */
+  CORE_ADDR msp_s;
+  CORE_ADDR msp_ns;
+  CORE_ADDR psp_s;
+  CORE_ADDR psp_ns;
+
+  /* Active stack pointer.  */
+  int active_sp_regnum;
+
+  bool have_sec_ext;
+  bool is_m;
 
   /* The frame base for this frame is just prev_sp - frame size.
      FRAMESIZE is the distance from the frame pointer to the
@@ -293,6 +307,10 @@ struct arm_prologue_cache
 static void
 arm_cache_init (struct arm_prologue_cache *cache, struct gdbarch *gdbarch)
 {
+  cache->have_sec_ext = false;
+  cache->is_m = false;
+  cache->active_sp_regnum = ARM_SP_REGNUM;
+
   cache->framesize = 0;
   cache->framereg = 0;
   cache->saved_regs = trad_frame_alloc_saved_regs (gdbarch);
@@ -302,9 +320,131 @@ static void
 arm_cache_init (struct arm_prologue_cache *cache, struct frame_info *frame)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
-  cache->prev_sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  cache->sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
 
   arm_cache_init (cache, gdbarch);
+
+  cache->have_sec_ext = tdep->have_sec_ext;
+  cache->is_m = tdep->is_m;
+
+  /* Initialize stack pointers, and flag the active one.  */
+#define INIT_ARM_CACHE_SP(regnum, member) do {			   \
+    CORE_ADDR val = get_frame_register_unsigned (frame, (regnum)); \
+    if (val == cache->sp)					   \
+      {								   \
+	cache->active_sp_regnum = (regnum);			   \
+      }								   \
+    (member) = val;						   \
+  } while (0)
+
+  if (tdep->have_sec_ext)
+    {
+      INIT_ARM_CACHE_SP (tdep->m_profile_msp_s_regnum, cache->msp_s);
+      INIT_ARM_CACHE_SP (tdep->m_profile_psp_s_regnum, cache->psp_s);
+      INIT_ARM_CACHE_SP (tdep->m_profile_msp_ns_regnum, cache->msp_ns);
+      INIT_ARM_CACHE_SP (tdep->m_profile_psp_ns_regnum, cache->psp_ns);
+      /* Use MSP_S as default stack pointer.  */
+      if (cache->active_sp_regnum == ARM_SP_REGNUM)
+	  cache->active_sp_regnum = tdep->m_profile_msp_s_regnum;
+    }
+  else if (tdep->is_m)
+    {
+      INIT_ARM_CACHE_SP (tdep->m_profile_msp_regnum, cache->msp_s);
+      INIT_ARM_CACHE_SP (tdep->m_profile_psp_regnum, cache->psp_s);
+    }
+  else
+    {
+      INIT_ARM_CACHE_SP (ARM_SP_REGNUM, cache->msp_s);
+    }
+  #undef INIT_ARM_CACHE_SP
+}
+
+static gdb::optional<CORE_ADDR>
+arm_cache_get_sp_register (struct arm_prologue_cache *cache, arm_gdbarch_tdep *tdep, int regnum)
+{
+  if (cache->have_sec_ext)
+    {
+      if (regnum == tdep->m_profile_msp_s_regnum)
+	return cache->msp_s;
+      if (regnum == tdep->m_profile_msp_ns_regnum)
+	return cache->msp_ns;
+      if (regnum == tdep->m_profile_psp_s_regnum)
+	return cache->psp_s;
+      if (regnum == tdep->m_profile_psp_ns_regnum)
+	return cache->psp_ns;
+      if (regnum == ARM_SP_REGNUM)
+	return cache->sp;
+    }
+  else if (cache->is_m)
+    {
+      if (regnum == tdep->m_profile_msp_regnum)
+	return cache->msp_s;
+      if (regnum == tdep->m_profile_psp_regnum)
+	return cache->psp_s;
+      if (regnum == ARM_SP_REGNUM)
+	return cache->sp;
+    }
+  else
+    {
+      if (regnum == ARM_SP_REGNUM)
+	return cache->sp;
+    }
+  return {};
+}
+
+static CORE_ADDR
+arm_cache_get_prev_sp (struct arm_prologue_cache *cache, arm_gdbarch_tdep *tdep)
+{
+  gdb::optional<CORE_ADDR> val
+    = arm_cache_get_sp_register (cache, tdep, cache->active_sp_regnum);
+  if (val.has_value ())
+      return *val;
+
+  gdb_assert_not_reached ("Invalid SP selection");
+  return 0;
+}
+
+static void
+arm_cache_set_prev_sp (struct arm_prologue_cache *cache, arm_gdbarch_tdep *tdep, CORE_ADDR val)
+{
+  if (cache->have_sec_ext)
+    {
+      if (cache->active_sp_regnum == tdep->m_profile_msp_s_regnum)
+	cache->msp_s = val;
+      else if (cache->active_sp_regnum == tdep->m_profile_msp_ns_regnum)
+	cache->msp_ns = val;
+      else if (cache->active_sp_regnum == tdep->m_profile_psp_s_regnum)
+	cache->psp_s = val;
+      else if (cache->active_sp_regnum == tdep->m_profile_psp_ns_regnum)
+	cache->psp_ns = val;
+      else if (cache->active_sp_regnum == ARM_SP_REGNUM)
+	cache->sp = val;
+
+      return;
+    }
+  else if (cache->is_m)
+    {
+      if (cache->active_sp_regnum == tdep->m_profile_msp_regnum)
+	cache->msp_s = val;
+      else if (cache->active_sp_regnum == tdep->m_profile_psp_regnum)
+	cache->psp_s = val;
+      else if (cache->active_sp_regnum == ARM_SP_REGNUM)
+	cache->sp = val;
+
+      return;
+    }
+  else
+    {
+      switch (cache->active_sp_regnum)
+	{
+	case ARM_SP_REGNUM:
+	  cache->sp = val;
+	  return;
+	}
+    }
+
+  gdb_assert_not_reached ("Invalid SP selection");
 }
 
 namespace {
@@ -1951,14 +2091,17 @@ arm_make_prologue_cache (struct frame_info *this_frame)
   if (unwound_fp == 0)
     return cache;
 
-  cache->prev_sp = unwound_fp + cache->framesize;
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+
+  arm_cache_set_prev_sp (cache, tdep, unwound_fp + cache->framesize);
 
   /* Calculate actual addresses of saved registers using offsets
      determined by arm_scan_prologue.  */
   for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
     if (cache->saved_regs[reg].is_addr ())
       cache->saved_regs[reg].set_addr (cache->saved_regs[reg].addr ()
-				       + cache->prev_sp);
+				       + arm_cache_get_prev_sp (cache, tdep));
 
   return cache;
 }
@@ -1984,7 +2127,7 @@ arm_prologue_unwind_stop_reason (struct frame_info *this_frame,
     return UNWIND_OUTERMOST;
 
   /* If we've hit a wall, stop.  */
-  if (cache->prev_sp == 0)
+  if (arm_cache_get_prev_sp (cache, tdep) == 0)
     return UNWIND_OUTERMOST;
 
   return UNWIND_NO_REASON;
@@ -2006,6 +2149,9 @@ arm_prologue_this_id (struct frame_info *this_frame,
     *this_cache = arm_make_prologue_cache (this_frame);
   cache = (struct arm_prologue_cache *) *this_cache;
 
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+
   /* Use function start address as part of the frame ID.  If we cannot
      identify the start address (due to missing symbol information),
      fall back to just using the current PC.  */
@@ -2014,7 +2160,7 @@ arm_prologue_this_id (struct frame_info *this_frame,
   if (!func)
     func = pc;
 
-  id = frame_id_build (cache->prev_sp, func);
+  id = frame_id_build (arm_cache_get_prev_sp (cache, tdep), func);
   *this_id = id;
 }
 
@@ -2024,6 +2170,7 @@ arm_prologue_prev_register (struct frame_info *this_frame,
 			    int prev_regnum)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
   struct arm_prologue_cache *cache;
 
   if (*this_cache == NULL)
@@ -2048,7 +2195,8 @@ arm_prologue_prev_register (struct frame_info *this_frame,
      identified by the next frame's stack pointer at the time of the call.
      The value was already reconstructed into PREV_SP.  */
   if (prev_regnum == ARM_SP_REGNUM)
-    return frame_unwind_got_constant (this_frame, prev_regnum, cache->prev_sp);
+    return frame_unwind_got_constant (this_frame, prev_regnum,
+				      arm_cache_get_prev_sp (cache, tdep));
 
   /* The CPSR may have been changed by the call instruction and by the
      called function.  The only bit we can reconstruct is the T bit,
@@ -2686,7 +2834,9 @@ arm_exidx_fill_cache (struct frame_info *this_frame, gdb_byte *entry)
     = vsp - get_frame_register_unsigned (this_frame, cache->framereg);
 
   /* We already got the previous SP.  */
-  cache->prev_sp = vsp;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  arm_cache_set_prev_sp (cache, tdep, vsp);
 
   return cache;
 }
@@ -2809,14 +2959,16 @@ arm_make_epilogue_frame_cache (struct frame_info *this_frame)
   arm_scan_prologue (this_frame, cache);
 
   /* Since we are in epilogue, the SP has been restored.  */
-  cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+  arm_cache_set_prev_sp (cache, tdep, get_frame_register_unsigned (this_frame, ARM_SP_REGNUM));
 
   /* Calculate actual addresses of saved registers using offsets
      determined by arm_scan_prologue.  */
   for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
     if (cache->saved_regs[reg].is_addr ())
       cache->saved_regs[reg].set_addr (cache->saved_regs[reg].addr ()
-				       + cache->prev_sp);
+				       + arm_cache_get_prev_sp (cache, tdep));
 
   return cache;
 }
@@ -2844,7 +2996,9 @@ arm_epilogue_frame_this_id (struct frame_info *this_frame,
   if (func == 0)
     func = pc;
 
-  (*this_id) = frame_id_build (cache->prev_sp, pc);
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+  (*this_id) = frame_id_build (arm_cache_get_prev_sp (cache, tdep), pc);
 }
 
 /* Implementation of function hook 'prev_register' in
@@ -2966,7 +3120,9 @@ arm_make_stub_cache (struct frame_info *this_frame)
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
   arm_cache_init (cache, this_frame);
 
-  cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+  arm_cache_set_prev_sp (cache, tdep, get_frame_register_unsigned (this_frame, ARM_SP_REGNUM));
 
   return cache;
 }
@@ -2984,7 +3140,9 @@ arm_stub_this_id (struct frame_info *this_frame,
     *this_cache = arm_make_stub_cache (this_frame);
   cache = (struct arm_prologue_cache *) *this_cache;
 
-  *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+  *this_id = frame_id_build (arm_cache_get_prev_sp (cache, tdep), get_frame_pc (this_frame));
 }
 
 static int
@@ -3105,12 +3263,12 @@ arm_m_exception_cache (struct frame_info *this_frame)
       cache->saved_regs[ARM_FPSCR_REGNUM].set_addr (unwound_sp + 0x60);
 
       /* Offset 0x64 is reserved.  */
-      cache->prev_sp = unwound_sp + 0x68;
+      arm_cache_set_prev_sp (cache, tdep, unwound_sp + 0x68);
     }
   else
     {
       /* Standard stack frame type used.  */
-      cache->prev_sp = unwound_sp + 0x20;
+      arm_cache_set_prev_sp (cache, tdep, unwound_sp + 0x20);
     }
 
   /* Check EXC_RETURN bit S if Secure or Non-secure stack used.  */
@@ -3132,7 +3290,7 @@ arm_m_exception_cache (struct frame_info *this_frame)
      previous context's stack pointer.  */
   if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr)
       && (xpsr & (1 << 9)) != 0)
-    cache->prev_sp += 4;
+    arm_cache_set_prev_sp (cache, tdep, arm_cache_get_prev_sp (cache, tdep) + 4);
 
   return cache;
 }
@@ -3152,7 +3310,9 @@ arm_m_exception_this_id (struct frame_info *this_frame,
   cache = (struct arm_prologue_cache *) *this_cache;
 
   /* Our frame ID for a stub frame is the current SP and LR.  */
-  *this_id = frame_id_build (cache->prev_sp,
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+  *this_id = frame_id_build (arm_cache_get_prev_sp (cache, tdep),
 			     get_frame_pc (this_frame));
 }
 
@@ -3171,9 +3331,11 @@ arm_m_exception_prev_register (struct frame_info *this_frame,
   cache = (struct arm_prologue_cache *) *this_cache;
 
   /* The value was already reconstructed into PREV_SP.  */
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
   if (prev_regnum == ARM_SP_REGNUM)
     return frame_unwind_got_constant (this_frame, prev_regnum,
-				      cache->prev_sp);
+				      arm_cache_get_prev_sp (cache, tdep));
 
   return trad_frame_get_prev_register (this_frame, cache->saved_regs,
 				       prev_regnum);
@@ -3218,7 +3380,9 @@ arm_normal_frame_base (struct frame_info *this_frame, void **this_cache)
     *this_cache = arm_make_prologue_cache (this_frame);
   cache = (struct arm_prologue_cache *) *this_cache;
 
-  return cache->prev_sp - cache->framesize;
+  gdbarch *arch = get_frame_arch (this_frame);
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
+  return arm_cache_get_prev_sp (cache, tdep) - cache->framesize;
 }
 
 struct frame_base arm_normal_base = {
@@ -9084,6 +9248,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdesc_arch_data_up tdesc_data;
   int i;
   bool is_m = false;
+  bool have_sec_ext = false;
   int vfp_register_count = 0;
   bool have_s_pseudos = false, have_q_pseudos = false;
   bool have_wmmx_registers = false;
@@ -9097,6 +9262,10 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   bool have_m_profile_sp = false;
   int m_profile_msp_regnum = -1;
   int m_profile_psp_regnum = -1;
+  int m_profile_msp_ns_regnum = -1;
+  int m_profile_psp_ns_regnum = -1;
+  int m_profile_msp_s_regnum = -1;
+  int m_profile_psp_s_regnum = -1;
 
   /* If we have an object to base this architecture on, try to determine
      its ABI.  */
@@ -9469,6 +9638,43 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	      if (have_vfp)
 		have_q_pseudos = true;
 	    }
+
+	  /* Do we have the Security extension?  */
+	  feature = tdesc_find_feature (tdesc,
+					"org.gnu.gdb.arm.secext");
+	  if (feature != nullptr)
+	    {
+	      /* Secure/Non-secure stack pointers.  */
+	      /* MSP_NS */
+	      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
+						 register_count, "msp_ns");
+	      if (valid_p)
+		m_profile_msp_ns_regnum = register_count++;
+
+	      /* PSP_NS */
+	      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
+						 register_count, "psp_ns");
+	      if (valid_p)
+		m_profile_psp_ns_regnum = register_count++;
+
+	      /* MSP_S */
+	      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
+						 register_count, "msp_s");
+	      if (valid_p)
+		m_profile_msp_s_regnum = register_count++;
+
+	      /* PSP_S */
+	      valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
+						 register_count, "psp_s");
+	      if (valid_p)
+		m_profile_psp_s_regnum = register_count++;
+
+	      if (!valid_p)
+		return nullptr;
+
+	      have_sec_ext = true;
+	    }
+	  
 	}
     }
 
@@ -9510,6 +9716,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->arm_abi = arm_abi;
   tdep->fp_model = fp_model;
   tdep->is_m = is_m;
+  tdep->have_sec_ext = have_sec_ext;
   tdep->have_fpa_registers = have_fpa_registers;
   tdep->have_wmmx_registers = have_wmmx_registers;
   gdb_assert (vfp_register_count == 0
@@ -9532,6 +9739,10 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     {
       tdep->m_profile_msp_regnum = m_profile_msp_regnum;
       tdep->m_profile_psp_regnum = m_profile_psp_regnum;
+      tdep->m_profile_msp_ns_regnum = m_profile_msp_ns_regnum;
+      tdep->m_profile_psp_ns_regnum = m_profile_psp_ns_regnum;
+      tdep->m_profile_msp_s_regnum = m_profile_msp_s_regnum;
+      tdep->m_profile_psp_s_regnum = m_profile_psp_s_regnum;
     }
 
   arm_register_g_packet_guesses (gdbarch);
@@ -9810,6 +10021,14 @@ arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 		      tdep->m_profile_msp_regnum);
   fprintf_unfiltered (file, _("arm_dump_tdep: m_profile_psp_regnum = %i\n"),
 		      tdep->m_profile_psp_regnum);
+  fprintf_unfiltered (file, _("arm_dump_tdep: m_profile_msp_ns_regnum = %i\n"),
+		      tdep->m_profile_msp_ns_regnum);
+  fprintf_unfiltered (file, _("arm_dump_tdep: m_profile_psp_ns_regnum = %i\n"),
+		      tdep->m_profile_psp_ns_regnum);
+  fprintf_unfiltered (file, _("arm_dump_tdep: m_profile_msp_s_regnum = %i\n"),
+		      tdep->m_profile_msp_s_regnum);
+  fprintf_unfiltered (file, _("arm_dump_tdep: m_profile_psp_s_regnum = %i\n"),
+		      tdep->m_profile_psp_s_regnum);
   fprintf_unfiltered (file, _("arm_dump_tdep: Lowest pc = 0x%lx\n"),
 		      (unsigned long) tdep->lowest_pc);
 }
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 420af43a1fe..9019955c7d4 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -119,10 +119,17 @@ struct arm_gdbarch_tdep : gdbarch_tdep
   int mve_pseudo_base = 0;	/* Number of the first MVE pseudo register.  */
   int mve_pseudo_count = 0;	/* Total number of MVE pseudo registers.  */
 
-  int m_profile_msp_regnum = 0;	/* M-profile MSP register number.  */
-  int m_profile_psp_regnum = 0;	/* M-profile PSP register number.  */
+  int m_profile_msp_regnum = ARM_SP_REGNUM;	/* M-profile MSP register number.  */
+  int m_profile_psp_regnum = ARM_SP_REGNUM;	/* M-profile PSP register number.  */
+
+  /* Secure and Non-secure stack pointers with security extension.  */
+  int m_profile_msp_ns_regnum = ARM_SP_REGNUM;	/* M-profile MSP_NS register number.  */
+  int m_profile_psp_ns_regnum = ARM_SP_REGNUM;	/* M-profile PSP_NS register number.  */
+  int m_profile_msp_s_regnum = ARM_SP_REGNUM;	/* M-profile MSP_S register number.  */
+  int m_profile_psp_s_regnum = ARM_SP_REGNUM;	/* M-profile PSP_S register number.  */
 
   bool is_m = false;		/* Does the target follow the "M" profile.  */
+  bool have_sec_ext = false;	/* Do we have secure extensions?  */
   CORE_ADDR lowest_pc = 0;	/* Lowest address at which instructions
 				   will appear.  */
 
diff --git a/gdb/features/arm/arm-secext.c b/gdb/features/arm/arm-secext.c
new file mode 100644
index 00000000000..39ef4afb05f
--- /dev/null
+++ b/gdb/features/arm/arm-secext.c
@@ -0,0 +1,17 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: arm-secext.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_arm_arm_m_system (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.secext");
+  tdesc_create_reg (feature, "msp_ns", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "psp_ns", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "msp_s", regnum++, 1, NULL, 32, "data_ptr");
+  tdesc_create_reg (feature, "psp_s", regnum++, 1, NULL, 32, "data_ptr");
+  return regnum;
+}
diff --git a/gdb/features/arm/arm-secext.xml b/gdb/features/arm/arm-secext.xml
new file mode 100644
index 00000000000..52b2c20a982
--- /dev/null
+++ b/gdb/features/arm/arm-secext.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.secext">
+  <!-- We have 4 stack pointers with the security extension.  -->
+  <reg name="msp_ns" bitsize="32" type="data_ptr"/>
+  <reg name="psp_ns" bitsize="32" type="data_ptr"/>
+  <reg name="msp_s" bitsize="32" type="data_ptr"/>
+  <reg name="psp_s" bitsize="32" type="data_ptr"/>
+</feature>
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 5/5] gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add unwind-ns-to-s command
  2022-02-04  8:41 [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M christophe.lyon.oss
                   ` (3 preceding siblings ...)
  2022-02-04  8:41 ` [PATCH v3 4/5] gdb/arm: Add support for multiple stack pointers on Cortex-M christophe.lyon.oss
@ 2022-02-04  8:41 ` christophe.lyon.oss
  2022-02-25  9:54 ` [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M Maxim Kuvyrkov
  5 siblings, 0 replies; 13+ messages in thread
From: christophe.lyon.oss @ 2022-02-04  8:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: torbjorn.svensson, Christophe Lyon

From: Christophe Lyon <christophe.lyon@foss.st.com>

This patch makes use of the support for several stack pointers
introduced by the previous patch to switch between them as needed
during unwinding.

It introduces a new 'unwind-ns-to-s' arm command to enable/disable
mode switching during unwinding. It is enabled by default.

It has been tested using an STM32L5 board (with cortex-m33) and the
sample applications shipped with the STM32Cube development
environment: GTZC_TZSC_MPCBB_TrustZone in
STM32CubeL5/Projects/NUCLEO-L552ZE-Q/Examples/GTZC.

The test consisted in setting breakpoints in various places and check
that the backtrace is correct: SecureFault_Callback (Non-secure mode),
__gnu_cmse_nonsecure_call (before and after the vpush instruction),
SecureFault_Handler (Secure mode).

This implies that we tested only some parts of this patch (only MSP*
were used), but remaining parts seem reasonable.

Signed-off-by: Torbjorn Svensson <torbjorn.svensson@st.com>
Signed-off-by: Christophe Lyon <christophe.lyon@foss.st.com>
---
 gdb/NEWS            |   5 +
 gdb/arm-tdep.c      | 341 ++++++++++++++++++++++++++++++++++++--------
 gdb/doc/gdb.texinfo |  10 ++
 3 files changed, 294 insertions(+), 62 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index eeca1d39b10..0bfa2cfab78 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -4984,6 +4984,11 @@ show arm force-mode
   the current CPSR value for instructions without symbols; previous
   versions of GDB behaved as if "set arm fallback-mode arm".
 
+set arm unwind-ns-to-s
+  Enable unwinding from Non-secure to Secure mode on Cortex-M with
+  Security extension.
+  This can trigger security exception when unwinding exception stack.
+
 set disable-randomization
 show disable-randomization
   Standalone programs run with the virtual address space randomization enabled
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 79c4cc6206f..4192fdf4a9c 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -447,6 +447,36 @@ arm_cache_set_prev_sp (struct arm_prologue_cache *cache, arm_gdbarch_tdep *tdep,
   gdb_assert_not_reached ("Invalid SP selection");
 }
 
+static bool
+arm_cache_is_sp_register (struct arm_prologue_cache *cache, arm_gdbarch_tdep *tdep, int regnum)
+{
+  if ((regnum == ARM_SP_REGNUM)
+      || (regnum == tdep->m_profile_msp_regnum)
+      || (regnum == tdep->m_profile_msp_s_regnum)
+      || (regnum == tdep->m_profile_msp_ns_regnum)
+      || (regnum == tdep->m_profile_psp_regnum)
+      || (regnum == tdep->m_profile_psp_s_regnum)
+      || (regnum == tdep->m_profile_psp_ns_regnum))
+    return true;
+  else
+    return false;
+}
+
+static void
+arm_cache_switch_prev_sp (struct arm_prologue_cache *cache, arm_gdbarch_tdep *tdep,
+			  int sp_regnum)
+{
+  gdb_assert (sp_regnum != ARM_SP_REGNUM);
+  if (cache->have_sec_ext)
+    gdb_assert (sp_regnum != tdep->m_profile_msp_regnum
+		&& sp_regnum != tdep->m_profile_psp_regnum);
+
+  if (!arm_cache_is_sp_register (cache, tdep, sp_regnum))
+    gdb_assert_not_reached ("Invalid SP selection");
+
+  cache->active_sp_regnum = sp_regnum;
+}
+
 namespace {
 
 /* Abstract class to read ARM instructions from memory.  */
@@ -483,6 +513,7 @@ static CORE_ADDR arm_analyze_prologue
 /* See arm-tdep.h.  */
 
 bool arm_apcs_32 = true;
+bool arm_unwind_ns_to_s = true;
 
 /* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode.  */
 
@@ -699,28 +730,43 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
    0xFFFFFFBC    Return to Thread mode using the process stack.  */
 
 static int
-arm_m_addr_is_magic (CORE_ADDR addr)
-{
-  switch (addr)
-    {
-      /* Values from ARMv8-M Architecture Technical Reference.  */
-      case 0xffffffb0:
-      case 0xffffffb8:
-      case 0xffffffbc:
-      /* Values from Tables in B1.5.8 the EXC_RETURN definitions of
-	 the exception return behavior.  */
-      case 0xffffffe1:
-      case 0xffffffe9:
-      case 0xffffffed:
-      case 0xfffffff1:
-      case 0xfffffff9:
-      case 0xfffffffd:
-	/* Address is magic.  */
-	return 1;
+arm_m_addr_is_magic (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  if (tdep->have_sec_ext)
+    {
+      switch ((addr & 0xff000000))
+	{
+	case 0xff000000: /* EXC_RETURN pattern.  */
+	case 0xfe000000: /* FNC_RETURN pattern.  */
+	  return 1;
+	default:
+	  return 0;
+	}
+    }
+  else
+    {
+      switch (addr)
+	{
+	  /* Values from ARMv8-M Architecture Technical Reference.  */
+	case 0xffffffb0:
+	case 0xffffffb8:
+	case 0xffffffbc:
+	  /* Values from Tables in B1.5.8 the EXC_RETURN definitions of
+	     the exception return behavior.  */
+	case 0xffffffe1:
+	case 0xffffffe9:
+	case 0xffffffed:
+	case 0xfffffff1:
+	case 0xfffffff9:
+	case 0xfffffffd:
+	  /* Address is magic.  */
+	  return 1;
 
-      default:
-	/* Address is not magic.  */
-	return 0;
+	default:
+	  /* Address is not magic.  */
+	  return 0;
+	}
     }
 }
 
@@ -732,7 +778,7 @@ arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
 
   /* On M-profile devices, do not strip the low bit from EXC_RETURN
      (the magic exception return address).  */
-  if (tdep->is_m && arm_m_addr_is_magic (val))
+  if (tdep->is_m && arm_m_addr_is_magic (gdbarch, val))
     return val;
 
   if (arm_apcs_32)
@@ -2172,6 +2218,7 @@ arm_prologue_prev_register (struct frame_info *this_frame,
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
   struct arm_prologue_cache *cache;
+  gdb::optional<CORE_ADDR> sp_value;
 
   if (*this_cache == NULL)
     *this_cache = arm_make_prologue_cache (this_frame);
@@ -2198,6 +2245,12 @@ arm_prologue_prev_register (struct frame_info *this_frame,
     return frame_unwind_got_constant (this_frame, prev_regnum,
 				      arm_cache_get_prev_sp (cache, tdep));
 
+  /* The value might be one of the alternative SP, if so, use the
+   * value already constructed.  */
+  sp_value = arm_cache_get_sp_register (cache, tdep, prev_regnum);
+  if (sp_value.has_value ())
+    return frame_unwind_got_constant (this_frame, prev_regnum, *sp_value);
+
   /* The CPSR may have been changed by the call instruction and by the
      called function.  The only bit we can reconstruct is the T bit,
      by checking the low bit of LR as of the call.  This is a reliable
@@ -3188,16 +3241,20 @@ static struct arm_prologue_cache *
 arm_m_exception_cache (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   struct arm_prologue_cache *cache;
   CORE_ADDR lr;
+  CORE_ADDR sp;
   CORE_ADDR unwound_sp;
+  uint32_t sp_r0_offset = 0;
   LONGEST xpsr;
   uint32_t exc_return;
-  uint32_t process_stack_used;
+  uint32_t fnc_return;
   uint32_t extended_frame_used;
-  uint32_t secure_stack_used;
+  uint32_t secure_stack_used = 0;
+  uint32_t default_callee_register_stacking = 0;
+  uint32_t exception_domain_is_secure = 0;
 
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
   arm_cache_init (cache, this_frame);
@@ -3207,35 +3264,124 @@ arm_m_exception_cache (struct frame_info *this_frame)
      to the exception and if FPU is used (causing extended stack frame).  */
 
   lr = get_frame_register_unsigned (this_frame, ARM_LR_REGNUM);
+  sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
 
-  /* Check EXC_RETURN indicator bits.  */
-  exc_return = (((lr >> 28) & 0xf) == 0xf);
+  fnc_return = ((lr & 0xfffffffe) == 0xfefffffe);
+  if (tdep->have_sec_ext && fnc_return)
+    {
+      int actual_sp;
+
+      arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_msp_ns_regnum);
+      arm_cache_set_prev_sp (cache, tdep, sp);
+      if (lr & 1)
+	actual_sp = tdep->m_profile_msp_s_regnum;
+      else
+	actual_sp = tdep->m_profile_msp_ns_regnum;
 
-  /* Check EXC_RETURN bit SPSEL if Main or Thread (process) stack used.  */
-  process_stack_used = ((lr & (1 << 2)) != 0);
-  if (exc_return && process_stack_used)
+      arm_cache_switch_prev_sp (cache, tdep, actual_sp);
+      sp = get_frame_register_unsigned (this_frame, actual_sp);
+
+      cache->saved_regs[ARM_LR_REGNUM].set_addr (sp);
+
+      arm_cache_set_prev_sp (cache, tdep, sp + 8);
+
+      return cache;
+    }
+
+  /* Check EXC_RETURN indicator bits.  */
+  exc_return = (((lr >> 24) & 0xff) == 0xff);
+  if (exc_return)
     {
-      /* Thread (process) stack used, use PSP as SP.  */
-      unwound_sp = get_frame_register_unsigned (this_frame, tdep->m_profile_psp_regnum);
+      /* Check EXC_RETURN bit SPSEL if Main or Thread (process) stack used.  */
+      uint32_t process_stack_used = ((lr & (1 << 2)) != 0);
+
+      if (tdep->have_sec_ext)
+	{
+	  secure_stack_used = ((lr & (1 << 6)) != 0);
+	  default_callee_register_stacking = ((lr & (1 << 5)) != 0);
+	  exception_domain_is_secure = ((lr & (1 << 0)) == 0);
+
+	  /* Unwinding from non-secure to secure can trip security
+	   * measures.  In order to avoid the debugger to be
+	   * intrusive, rely on the user to configure the requested
+	   * mode.
+	   */
+	  if (secure_stack_used && !exception_domain_is_secure
+	      && !arm_unwind_ns_to_s)
+	    {
+	      warning (_("Non-secure to secure stack unwinding disabled."));
+
+	      /* Terminate any further stack unwinding by refer to self.  */
+	      arm_cache_set_prev_sp (cache, tdep, sp);
+	      return cache;
+	    }
+
+	  if (process_stack_used)
+	    {
+	      if (secure_stack_used)
+		/* Secure thread (process) stack used, use PSP_S as SP.  */
+		arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_psp_s_regnum);
+	      else
+		/* Non-secure thread (process) stack used, use PSP_NS as SP.  */
+		arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_psp_ns_regnum);
+	    }
+	  else
+	    {
+	      if (secure_stack_used)
+		/* Secure main stack used, use MSP_S as SP.  */
+		arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_msp_s_regnum);
+	      else
+		/* Non-secure main stack used, use MSP_NS as SP.  */
+		arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_msp_ns_regnum);
+	    }
+	}
+      else
+	{
+	  if (process_stack_used)
+	    /* Thread (process) stack used, use PSP as SP.  */
+	    arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_psp_regnum);
+	  else
+	    /* Main stack used, use MSP as SP.  */
+	    arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_msp_regnum);
+	}
     }
   else
     {
       /* Main stack used, use MSP as SP.  */
-      unwound_sp = get_frame_register_unsigned (this_frame, tdep->m_profile_msp_regnum);
+      arm_cache_switch_prev_sp (cache, tdep, tdep->m_profile_msp_regnum);
+    }
+
+  /* Fetch the SP to use for this frame.  */
+  unwound_sp = arm_cache_get_prev_sp (cache, tdep);
+
+  /* With the Security extension, the hardware saves R4..R11 too.  */
+  if (exc_return && tdep->have_sec_ext && secure_stack_used
+      && (!default_callee_register_stacking || exception_domain_is_secure))
+    {
+      /* Read R4..R11 from the integer callee registers.  */
+      cache->saved_regs[4].set_addr (unwound_sp + 0x08);
+      cache->saved_regs[5].set_addr (unwound_sp + 0x0C);
+      cache->saved_regs[6].set_addr (unwound_sp + 0x10);
+      cache->saved_regs[7].set_addr (unwound_sp + 0x14);
+      cache->saved_regs[8].set_addr (unwound_sp + 0x18);
+      cache->saved_regs[9].set_addr (unwound_sp + 0x1C);
+      cache->saved_regs[10].set_addr (unwound_sp + 0x20);
+      cache->saved_regs[11].set_addr (unwound_sp + 0x24);
+      sp_r0_offset = 0x28;
     }
 
   /* The hardware saves eight 32-bit words, comprising xPSR,
      ReturnAddress, LR (R14), R12, R3, R2, R1, R0.  See details in
      "B1.5.6 Exception entry behavior" in
      "ARMv7-M Architecture Reference Manual".  */
-  cache->saved_regs[0].set_addr (unwound_sp);
-  cache->saved_regs[1].set_addr (unwound_sp + 4);
-  cache->saved_regs[2].set_addr (unwound_sp + 8);
-  cache->saved_regs[3].set_addr (unwound_sp + 12);
-  cache->saved_regs[ARM_IP_REGNUM].set_addr (unwound_sp + 16);
-  cache->saved_regs[ARM_LR_REGNUM].set_addr (unwound_sp + 20);
-  cache->saved_regs[ARM_PC_REGNUM].set_addr (unwound_sp + 24);
-  cache->saved_regs[ARM_PS_REGNUM].set_addr (unwound_sp + 28);
+  cache->saved_regs[0].set_addr (unwound_sp + sp_r0_offset);
+  cache->saved_regs[1].set_addr (unwound_sp + sp_r0_offset + 4);
+  cache->saved_regs[2].set_addr (unwound_sp + sp_r0_offset + 8);
+  cache->saved_regs[3].set_addr (unwound_sp + sp_r0_offset + 12);
+  cache->saved_regs[ARM_IP_REGNUM].set_addr (unwound_sp + sp_r0_offset + 16);
+  cache->saved_regs[ARM_LR_REGNUM].set_addr (unwound_sp + sp_r0_offset + 20);
+  cache->saved_regs[ARM_PC_REGNUM].set_addr (unwound_sp + sp_r0_offset + 24);
+  cache->saved_regs[ARM_PS_REGNUM].set_addr (unwound_sp + sp_r0_offset + 28);
 
   /* Check EXC_RETURN bit FTYPE if extended stack frame (FPU regs stored)
      type used.  */
@@ -3254,41 +3400,43 @@ arm_m_exception_cache (struct frame_info *this_frame)
 	 This register is located at address 0xE000EF34.  */
 
       /* Extended stack frame type used.  */
-      fpu_regs_stack_offset = unwound_sp + 0x20;
+      fpu_regs_stack_offset = unwound_sp + sp_r0_offset + 0x20;
       for (i = 0; i < 16; i++)
 	{
 	  cache->saved_regs[ARM_D0_REGNUM + i].set_addr (fpu_regs_stack_offset);
 	  fpu_regs_stack_offset += 4;
 	}
-      cache->saved_regs[ARM_FPSCR_REGNUM].set_addr (unwound_sp + 0x60);
+      cache->saved_regs[ARM_FPSCR_REGNUM].set_addr (unwound_sp + sp_r0_offset + 0x60);
+      fpu_regs_stack_offset += 4;
 
-      /* Offset 0x64 is reserved.  */
-      arm_cache_set_prev_sp (cache, tdep, unwound_sp + 0x68);
+      if (tdep->have_sec_ext && !default_callee_register_stacking)
+	{
+	  /* Handle floating-point callee saved registers.  */
+	  fpu_regs_stack_offset = 0x90;
+	  for (i = 16; i < 32; i++)
+	    {
+	      cache->saved_regs[ARM_D0_REGNUM + i].set_addr (fpu_regs_stack_offset);
+	      fpu_regs_stack_offset += 4;
+	    }
+
+	  arm_cache_set_prev_sp (cache, tdep, unwound_sp + sp_r0_offset + 0xD0);
+	}
+      else
+	{
+	  /* Offset 0x64 is reserved.  */
+	  arm_cache_set_prev_sp (cache, tdep, unwound_sp + sp_r0_offset + 0x68);
+	}
     }
   else
     {
       /* Standard stack frame type used.  */
-      arm_cache_set_prev_sp (cache, tdep, unwound_sp + 0x20);
-    }
-
-  /* Check EXC_RETURN bit S if Secure or Non-secure stack used.  */
-  secure_stack_used = ((lr & (1 << 6)) != 0);
-  if (exc_return && secure_stack_used)
-    {
-      /* ARMv8-M Exception and interrupt handling is not considered here.
-	 In the ARMv8-M architecture also EXC_RETURN bit S is controlling if
-	 the Secure or Non-secure stack was used. To separate Secure and
-	 Non-secure stacks, processors that are based on the ARMv8-M
-	 architecture support 4 stack pointers: MSP_S, PSP_S, MSP_NS, PSP_NS.
-	 In addition, a stack limit feature is provided using stack limit
-	 registers (accessible using MSR and MRS instructions) in Privileged
-	 level.  */
+      arm_cache_set_prev_sp (cache, tdep, unwound_sp + sp_r0_offset + 0x20);
     }
 
   /* If bit 9 of the saved xPSR is set, then there is a four-byte
      aligner between the top of the 32-byte stack frame and the
      previous context's stack pointer.  */
-  if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr)
+  if (safe_read_memory_integer (unwound_sp + sp_r0_offset + 28, 4, byte_order, &xpsr)
       && (xpsr & (1 << 9)) != 0)
     arm_cache_set_prev_sp (cache, tdep, arm_cache_get_prev_sp (cache, tdep) + 4);
 
@@ -3325,6 +3473,7 @@ arm_m_exception_prev_register (struct frame_info *this_frame,
 			       int prev_regnum)
 {
   struct arm_prologue_cache *cache;
+  gdb::optional<CORE_ADDR> sp_value;
 
   if (*this_cache == NULL)
     *this_cache = arm_m_exception_cache (this_frame);
@@ -3337,6 +3486,21 @@ arm_m_exception_prev_register (struct frame_info *this_frame,
     return frame_unwind_got_constant (this_frame, prev_regnum,
 				      arm_cache_get_prev_sp (cache, tdep));
 
+  /* The value might be one of the alternative SP, if so, use the
+   * value already constructed.  */
+  sp_value = arm_cache_get_sp_register (cache, tdep, prev_regnum);
+  if (sp_value.has_value ())
+    return frame_unwind_got_constant (this_frame, prev_regnum, *sp_value);
+
+  if (prev_regnum == ARM_PC_REGNUM)
+    {
+      CORE_ADDR lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
+      struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+      return frame_unwind_got_constant (this_frame, prev_regnum,
+					arm_addr_bits_remove (gdbarch, lr));
+    }
+
   return trad_frame_get_prev_register (this_frame, cache->saved_regs,
 				       prev_regnum);
 }
@@ -3349,13 +3513,14 @@ arm_m_exception_unwind_sniffer (const struct frame_unwind *self,
 				struct frame_info *this_frame,
 				void **this_prologue_cache)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   CORE_ADDR this_pc = get_frame_pc (this_frame);
 
   /* No need to check is_m; this sniffer is only registered for
      M-profile architectures.  */
 
   /* Check if exception frame returns to a magic PC value.  */
-  return arm_m_addr_is_magic (this_pc);
+  return arm_m_addr_is_magic (gdbarch, this_pc);
 }
 
 /* Frame unwinder for M-profile exceptions.  */
@@ -8771,6 +8936,15 @@ arm_show_force_mode (struct ui_file *file, int from_tty,
 		    arm_force_mode_string);
 }
 
+static void
+arm_show_unwind_ns_to_s (struct ui_file *file, int from_tty,
+			 struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file,
+		    _("Usage of non-secure to secure exception stack unwinding is %s.\n"),
+		    arm_unwind_ns_to_s ? "on" : "off");
+}
+
 /* If the user changes the register disassembly style used for info
    register and other commands, we have to also switch the style used
    in opcodes for disassembly output.  This function is run in the "set
@@ -9676,6 +9850,40 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	    }
 	  
 	}
+      feature = tdesc_find_feature (tdesc,
+				    "org.gnu.gdb.arm.secext");
+      if (feature != nullptr)
+	{
+	  /* Secure/Non-secure stack pointers.  */
+	  /* MSP_NS */
+	  valid_p = tdesc_numbered_register (feature, tdesc_data.get (),
+					     register_count, "msp_ns");
+	  if (valid_p)
+	    m_profile_msp_ns_regnum = register_count++;
+
+	  /* PSP_NS */
+	  valid_p = tdesc_numbered_register (feature, tdesc_data.get (),
+					     register_count, "psp_ns");
+	  if (valid_p)
+	    m_profile_psp_ns_regnum = register_count++;
+
+	  /* MSP_S */
+	  valid_p = tdesc_numbered_register (feature, tdesc_data.get (),
+					     register_count, "msp_s");
+	  if (valid_p)
+	    m_profile_msp_s_regnum = register_count++;
+
+	  /* PSP_S */
+	  valid_p = tdesc_numbered_register (feature, tdesc_data.get (),
+					     register_count, "psp_s");
+	  if (valid_p)
+	    m_profile_psp_s_regnum = register_count++;
+
+	  if (!valid_p)
+	    return NULL;
+
+	  have_sec_ext = true;
+	}
     }
 
   /* If there is already a candidate, use it.  */
@@ -10150,6 +10358,15 @@ vfp - VFP co-processor."),
 			NULL, NULL, arm_show_force_mode,
 			&setarmcmdlist, &showarmcmdlist);
 
+  /* Add a command to stop triggering security exception when
+   * unwinding exception stack.  */
+  add_setshow_boolean_cmd ("unwind-ns-to-s", no_class, &arm_unwind_ns_to_s,
+			   _("Set usage of non-secure to secure exception stack unwinding."),
+			   _("Show usage of non-secure to secure exception stack unwinding."),
+			   _("When on, the debugger can trigger memory access traps."),
+			   NULL, arm_show_unwind_ns_to_s,
+			   &setarmcmdlist, &showarmcmdlist);
+
   /* Debugging flag.  */
   add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
 			   _("Set ARM debugging."),
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9d507795993..87590159308 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24895,6 +24895,16 @@ of @samp{set arm fallback-mode}.
 @item show arm force-mode
 Show the current forced instruction mode.
 
+@item set arm unwind-ns-to-s
+This command enables unwinding from Non-secure to Secure mode on
+Cortex-M with Security extension.
+This can trigger security exceptions when unwinding the exception
+stack.
+It is enabled by default.
+
+@item show arm unwind-ns-to-s
+Show whether unwind from Non-secure to Secure mode is enabled.
+
 @item set debug arm
 Toggle whether to display ARM-specific debugging messages from the ARM
 target support subsystem.
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
  2022-02-04  8:41 [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M christophe.lyon.oss
                   ` (4 preceding siblings ...)
  2022-02-04  8:41 ` [PATCH v3 5/5] gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add unwind-ns-to-s command christophe.lyon.oss
@ 2022-02-25  9:54 ` Maxim Kuvyrkov
  2022-02-27 11:35   ` Joel Brobecker
  5 siblings, 1 reply; 13+ messages in thread
From: Maxim Kuvyrkov @ 2022-02-25  9:54 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, torbjorn.svensson, Yvan Roux, Christophe Lyon

Hi Luis,

Will you be able to review this patch series from Christophe?

Thank you,

--
Maxim Kuvyrkov
https://www.linaro.org

> On 4 Feb 2022, at 11:41, Christophe Lyon via Gdb-patches <gdb-patches@sourceware.org> wrote:
> 
> From: Christophe Lyon <christophe.lyon@foss.st.com>
> 
> This patch series introduces support for the multiple stack pointers
> on v8-M architecture (MSP_S, MSP_NS, PSP_S, PSP_NS).
> 
> This enables to unwind through Secure vs Non-secure context switches.
> 
> Along the way, the first patch adds support to detect vpush
> instructions in function prologues, which in particular is used in the
> CMSE trampolines.
> 
> v3 fixes two small silly mistakes in patches 4 and 5.
> 
> Christophe Lyon (5):
>  gdb/arm: Fix prologue analysis to support vpush
>  gdb/arm: Define MSP and PSP registers for M-Profile
>  gdb/arm: Introduce arm_cache_init
>  gdb/arm: Add support for multiple stack pointers on Cortex-M
>  gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add
>    unwind-ns-to-s command
> 
> gdb/NEWS                          |   5 +
> gdb/arch/arm.c                    |   6 +
> gdb/arch/arm.h                    |   1 +
> gdb/arm-tdep.c                    | 698 +++++++++++++++++++++++++-----
> gdb/arm-tdep.h                    |  10 +
> gdb/doc/gdb.texinfo               |  10 +
> gdb/features/Makefile             |   1 +
> gdb/features/arm/arm-m-system.c   |  15 +
> gdb/features/arm/arm-m-system.xml |  12 +
> gdb/features/arm/arm-secext.c     |  17 +
> gdb/features/arm/arm-secext.xml   |  15 +
> 11 files changed, 691 insertions(+), 99 deletions(-)
> create mode 100644 gdb/features/arm/arm-m-system.c
> create mode 100644 gdb/features/arm/arm-m-system.xml
> create mode 100644 gdb/features/arm/arm-secext.c
> create mode 100644 gdb/features/arm/arm-secext.xml
> 
> -- 
> 2.25.1
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
  2022-02-25  9:54 ` [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M Maxim Kuvyrkov
@ 2022-02-27 11:35   ` Joel Brobecker
  2022-02-28 10:38     ` Christophe Lyon
  0 siblings, 1 reply; 13+ messages in thread
From: Joel Brobecker @ 2022-02-27 11:35 UTC (permalink / raw)
  To: Maxim Kuvyrkov via Gdb-patches
  Cc: Luis Machado, torbjorn.svensson, Yvan Roux, Joel Brobecker

> Will you be able to review this patch series from Christophe?

I see that the v3 series was posted on Feb 4th, while on Feb 6th
I reviewed v2 :-(. This is really unfortunate that we don't have
a better system for tracking whether a version of a series is
trully the latest version.

Can you take a look at the comments and question I asked in v2,
and publish a v4 which takes those into account? Please Cc: me
on the submission of the patches, this will help me remember
to prioritize those patches.

> 
> Thank you,
> 
> --
> Maxim Kuvyrkov
> https://www.linaro.org
> 
> > On 4 Feb 2022, at 11:41, Christophe Lyon via Gdb-patches <gdb-patches@sourceware.org> wrote:
> > 
> > From: Christophe Lyon <christophe.lyon@foss.st.com>
> > 
> > This patch series introduces support for the multiple stack pointers
> > on v8-M architecture (MSP_S, MSP_NS, PSP_S, PSP_NS).
> > 
> > This enables to unwind through Secure vs Non-secure context switches.
> > 
> > Along the way, the first patch adds support to detect vpush
> > instructions in function prologues, which in particular is used in the
> > CMSE trampolines.
> > 
> > v3 fixes two small silly mistakes in patches 4 and 5.
> > 
> > Christophe Lyon (5):
> >  gdb/arm: Fix prologue analysis to support vpush
> >  gdb/arm: Define MSP and PSP registers for M-Profile
> >  gdb/arm: Introduce arm_cache_init
> >  gdb/arm: Add support for multiple stack pointers on Cortex-M
> >  gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add
> >    unwind-ns-to-s command
> > 
> > gdb/NEWS                          |   5 +
> > gdb/arch/arm.c                    |   6 +
> > gdb/arch/arm.h                    |   1 +
> > gdb/arm-tdep.c                    | 698 +++++++++++++++++++++++++-----
> > gdb/arm-tdep.h                    |  10 +
> > gdb/doc/gdb.texinfo               |  10 +
> > gdb/features/Makefile             |   1 +
> > gdb/features/arm/arm-m-system.c   |  15 +
> > gdb/features/arm/arm-m-system.xml |  12 +
> > gdb/features/arm/arm-secext.c     |  17 +
> > gdb/features/arm/arm-secext.xml   |  15 +
> > 11 files changed, 691 insertions(+), 99 deletions(-)
> > create mode 100644 gdb/features/arm/arm-m-system.c
> > create mode 100644 gdb/features/arm/arm-m-system.xml
> > create mode 100644 gdb/features/arm/arm-secext.c
> > create mode 100644 gdb/features/arm/arm-secext.xml
> > 
> > -- 
> > 2.25.1
> > 
> 

-- 
Joel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
  2022-02-27 11:35   ` Joel Brobecker
@ 2022-02-28 10:38     ` Christophe Lyon
  2022-03-06 10:48       ` Joel Brobecker
  0 siblings, 1 reply; 13+ messages in thread
From: Christophe Lyon @ 2022-02-28 10:38 UTC (permalink / raw)
  To: Joel Brobecker, Maxim Kuvyrkov via Gdb-patches
  Cc: torbjorn.svensson, Yvan Roux, Luis Machado


On 2/27/22 12:35, Joel Brobecker via Gdb-patches wrote:
>> Will you be able to review this patch series from Christophe?
> I see that the v3 series was posted on Feb 4th, while on Feb 6th
> I reviewed v2 :-(. This is really unfortunate that we don't have
> a better system for tracking whether a version of a series is
> trully the latest version.

No problem, there's not much difference between v2 and v3,

so your comments still apply. I should have answered earlier.

>
> Can you take a look at the comments and question I asked in v2,
> and publish a v4 which takes those into account? Please Cc: me
> on the submission of the patches, this will help me remember
> to prioritize those patches.


Sure!


Luis and I changed jobs at the same time, so there's a bit

of lag :-)


Thanks,


Christophe


>
>> Thank you,
>>
>> --
>> Maxim Kuvyrkov
>> https://www.linaro.org
>>
>>> On 4 Feb 2022, at 11:41, Christophe Lyon via Gdb-patches <gdb-patches@sourceware.org> wrote:
>>>
>>> From: Christophe Lyon <christophe.lyon@foss.st.com>
>>>
>>> This patch series introduces support for the multiple stack pointers
>>> on v8-M architecture (MSP_S, MSP_NS, PSP_S, PSP_NS).
>>>
>>> This enables to unwind through Secure vs Non-secure context switches.
>>>
>>> Along the way, the first patch adds support to detect vpush
>>> instructions in function prologues, which in particular is used in the
>>> CMSE trampolines.
>>>
>>> v3 fixes two small silly mistakes in patches 4 and 5.
>>>
>>> Christophe Lyon (5):
>>>   gdb/arm: Fix prologue analysis to support vpush
>>>   gdb/arm: Define MSP and PSP registers for M-Profile
>>>   gdb/arm: Introduce arm_cache_init
>>>   gdb/arm: Add support for multiple stack pointers on Cortex-M
>>>   gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add
>>>     unwind-ns-to-s command
>>>
>>> gdb/NEWS                          |   5 +
>>> gdb/arch/arm.c                    |   6 +
>>> gdb/arch/arm.h                    |   1 +
>>> gdb/arm-tdep.c                    | 698 +++++++++++++++++++++++++-----
>>> gdb/arm-tdep.h                    |  10 +
>>> gdb/doc/gdb.texinfo               |  10 +
>>> gdb/features/Makefile             |   1 +
>>> gdb/features/arm/arm-m-system.c   |  15 +
>>> gdb/features/arm/arm-m-system.xml |  12 +
>>> gdb/features/arm/arm-secext.c     |  17 +
>>> gdb/features/arm/arm-secext.xml   |  15 +
>>> 11 files changed, 691 insertions(+), 99 deletions(-)
>>> create mode 100644 gdb/features/arm/arm-m-system.c
>>> create mode 100644 gdb/features/arm/arm-m-system.xml
>>> create mode 100644 gdb/features/arm/arm-secext.c
>>> create mode 100644 gdb/features/arm/arm-secext.xml
>>>
>>> -- 
>>> 2.25.1
>>>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
  2022-02-28 10:38     ` Christophe Lyon
@ 2022-03-06 10:48       ` Joel Brobecker
  2022-03-06 21:19         ` Christophe Lyon
  0 siblings, 1 reply; 13+ messages in thread
From: Joel Brobecker @ 2022-03-06 10:48 UTC (permalink / raw)
  To: Christophe Lyon
  Cc: Joel Brobecker, Maxim Kuvyrkov via Gdb-patches,
	torbjorn.svensson, Yvan Roux, Luis Machado

> > > Will you be able to review this patch series from Christophe?
> > I see that the v3 series was posted on Feb 4th, while on Feb 6th
> > I reviewed v2 :-(. This is really unfortunate that we don't have
> > a better system for tracking whether a version of a series is
> > trully the latest version.
> 
> No problem, there's not much difference between v2 and v3,
> so your comments still apply. I should have answered earlier.
> 
> > 
> > Can you take a look at the comments and question I asked in v2,
> > and publish a v4 which takes those into account? Please Cc: me
> > on the submission of the patches, this will help me remember
> > to prioritize those patches.
> 
> 
> Sure!
> 
> Luis and I changed jobs at the same time, so there's a bit
> of lag :-)

No problem!

Just for the avoidance of doubt and you don't end up waiting on me,
my understanding is that the next step is for you to produce a v4
with some of my comments addressed, and to post answers/questions
for my comments. Is that right?

-- 
Joel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
  2022-03-06 10:48       ` Joel Brobecker
@ 2022-03-06 21:19         ` Christophe Lyon
  2022-03-11  9:40           ` Yvan Roux
  0 siblings, 1 reply; 13+ messages in thread
From: Christophe Lyon @ 2022-03-06 21:19 UTC (permalink / raw)
  To: Joel Brobecker
  Cc: Maxim Kuvyrkov via Gdb-patches, torbjorn.svensson, Yvan Roux,
	Luis Machado



On 3/6/22 11:48, Joel Brobecker wrote:
>>>> Will you be able to review this patch series from Christophe?
>>> I see that the v3 series was posted on Feb 4th, while on Feb 6th
>>> I reviewed v2 :-(. This is really unfortunate that we don't have
>>> a better system for tracking whether a version of a series is
>>> trully the latest version.
>>
>> No problem, there's not much difference between v2 and v3,
>> so your comments still apply. I should have answered earlier.
>>
>>>
>>> Can you take a look at the comments and question I asked in v2,
>>> and publish a v4 which takes those into account? Please Cc: me
>>> on the submission of the patches, this will help me remember
>>> to prioritize those patches.
>>
>>
>> Sure!
>>
>> Luis and I changed jobs at the same time, so there's a bit
>> of lag :-)
> 
> No problem!
> 
> Just for the avoidance of doubt and you don't end up waiting on me,
> my understanding is that the next step is for you to produce a v4
> with some of my comments addressed, and to post answers/questions
> for my comments. Is that right?
> 

Yes, that's what I meant :-)

Thanks,

Christophe

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
  2022-03-06 21:19         ` Christophe Lyon
@ 2022-03-11  9:40           ` Yvan Roux
  2022-03-11  9:47             ` Christophe Lyon
  0 siblings, 1 reply; 13+ messages in thread
From: Yvan Roux @ 2022-03-11  9:40 UTC (permalink / raw)
  To: Christophe Lyon
  Cc: Joel Brobecker, torbjorn.svensson, Maxim Kuvyrkov via Gdb-patches

Hi,

I'll let Christophe address the comments and update the patchset, but I was
able to test it on an arm linux plateform I don't see any regression in the
testsuite.

Sorry I wasn't on the list when the patches were submitted, but I think there
is a small issue this one:

[PATCH v3 1/5] gdb/arm: Fix prologue analysis to support vpush

+	      /* Calculate offsets of saved registers.  */
+	      for (; number > 0; number--)
+		{
+		  addr = pv_add_constant (addr, -8);
+		  stack.store (addr, 8, pv_register (ARM_D0_REGNUM + number, 0));
+		}

Here the D registers to store are computed by adding number to D0 but the first
register should be the one encoded by D:Vd value which are bits 6 of insn and
15..12 of inst2

Cheers,
Yvan

On Sun, Mar 06, 2022 at 10:19:52PM +0100, Christophe Lyon via Gdb-patches wrote:
> 
> 
> On 3/6/22 11:48, Joel Brobecker wrote:
> > > > > Will you be able to review this patch series from Christophe?
> > > > I see that the v3 series was posted on Feb 4th, while on Feb 6th
> > > > I reviewed v2 :-(. This is really unfortunate that we don't have
> > > > a better system for tracking whether a version of a series is
> > > > trully the latest version.
> > > 
> > > No problem, there's not much difference between v2 and v3,
> > > so your comments still apply. I should have answered earlier.
> > > 
> > > > 
> > > > Can you take a look at the comments and question I asked in v2,
> > > > and publish a v4 which takes those into account? Please Cc: me
> > > > on the submission of the patches, this will help me remember
> > > > to prioritize those patches.
> > > 
> > > 
> > > Sure!
> > > 
> > > Luis and I changed jobs at the same time, so there's a bit
> > > of lag :-)
> > 
> > No problem!
> > 
> > Just for the avoidance of doubt and you don't end up waiting on me,
> > my understanding is that the next step is for you to produce a v4
> > with some of my comments addressed, and to post answers/questions
> > for my comments. Is that right?
> > 
> 
> Yes, that's what I meant :-)
> 
> Thanks,
> 
> Christophe

-- 
Y.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M
  2022-03-11  9:40           ` Yvan Roux
@ 2022-03-11  9:47             ` Christophe Lyon
  0 siblings, 0 replies; 13+ messages in thread
From: Christophe Lyon @ 2022-03-11  9:47 UTC (permalink / raw)
  To: Yvan Roux
  Cc: Joel Brobecker, torbjorn.svensson,
	Maxim Kuvyrkov via Gdb-patches, Luis Machado



On 3/11/22 10:40, Yvan Roux wrote:
> Hi,
> 
> I'll let Christophe address the comments and update the patchset, but I was
> able to test it on an arm linux plateform I don't see any regression in the
> testsuite.

Thanks, good news!

> 
> Sorry I wasn't on the list when the patches were submitted, but I think there
> is a small issue this one:
> 
> [PATCH v3 1/5] gdb/arm: Fix prologue analysis to support vpush
> 
> +	      /* Calculate offsets of saved registers.  */
> +	      for (; number > 0; number--)
> +		{
> +		  addr = pv_add_constant (addr, -8);
> +		  stack.store (addr, 8, pv_register (ARM_D0_REGNUM + number, 0));
> +		}
> 
> Here the D registers to store are computed by adding number to D0 but the first
> register should be the one encoded by D:Vd value which are bits 6 of insn and
> 15..12 of inst2
> 

Indeed, thanks for noticing.

I have a WIP patchset we plan to submit shortly.

Thanks,

Christophe

> Cheers,
> Yvan
> 
> On Sun, Mar 06, 2022 at 10:19:52PM +0100, Christophe Lyon via Gdb-patches wrote:
>>
>>
>> On 3/6/22 11:48, Joel Brobecker wrote:
>>>>>> Will you be able to review this patch series from Christophe?
>>>>> I see that the v3 series was posted on Feb 4th, while on Feb 6th
>>>>> I reviewed v2 :-(. This is really unfortunate that we don't have
>>>>> a better system for tracking whether a version of a series is
>>>>> trully the latest version.
>>>>
>>>> No problem, there's not much difference between v2 and v3,
>>>> so your comments still apply. I should have answered earlier.
>>>>
>>>>>
>>>>> Can you take a look at the comments and question I asked in v2,
>>>>> and publish a v4 which takes those into account? Please Cc: me
>>>>> on the submission of the patches, this will help me remember
>>>>> to prioritize those patches.
>>>>
>>>>
>>>> Sure!
>>>>
>>>> Luis and I changed jobs at the same time, so there's a bit
>>>> of lag :-)
>>>
>>> No problem!
>>>
>>> Just for the avoidance of doubt and you don't end up waiting on me,
>>> my understanding is that the next step is for you to produce a v4
>>> with some of my comments addressed, and to post answers/questions
>>> for my comments. Is that right?
>>>
>>
>> Yes, that's what I meant :-)
>>
>> Thanks,
>>
>> Christophe
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-03-11  9:47 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-04  8:41 [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M christophe.lyon.oss
2022-02-04  8:41 ` [PATCH v3 1/5] gdb/arm: Fix prologue analysis to support vpush christophe.lyon.oss
2022-02-04  8:41 ` [PATCH v3 2/5] gdb/arm: Define MSP and PSP registers for M-Profile christophe.lyon.oss
2022-02-04  8:41 ` [PATCH v3 3/5] gdb/arm: Introduce arm_cache_init christophe.lyon.oss
2022-02-04  8:41 ` [PATCH v3 4/5] gdb/arm: Add support for multiple stack pointers on Cortex-M christophe.lyon.oss
2022-02-04  8:41 ` [PATCH v3 5/5] gdb/arm: Extend arm_m_addr_is_magic to support FNC_RETURN, add unwind-ns-to-s command christophe.lyon.oss
2022-02-25  9:54 ` [PATCH v3 0/5] arm: Add support for multiple stacks on Cortex-M Maxim Kuvyrkov
2022-02-27 11:35   ` Joel Brobecker
2022-02-28 10:38     ` Christophe Lyon
2022-03-06 10:48       ` Joel Brobecker
2022-03-06 21:19         ` Christophe Lyon
2022-03-11  9:40           ` Yvan Roux
2022-03-11  9:47             ` Christophe Lyon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).