This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch releases/13.0
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/releases/13.0 by this push:
     new 29a125f64 testing/sig_sp_test: add test for SP context restore on 
signal return
29a125f64 is described below

commit 29a125f64162affe4fa5724a160e6cbf18d2c8de
Author: Andrew Au <[email protected]>
AuthorDate: Sun Jun 21 17:26:28 2026 +0000

    testing/sig_sp_test: add test for SP context restore on signal return
    
    Add a test that verifies modifying SP (REG_R13) in the saved register
    context is honored on signal return. The test pushes values onto the
    stack, triggers SIGALRM, and in the handler advances SP to skip a
    value, then verifies the correct value is popped after signal return.
    
    This exercises the SP relocation fix in arm_sigdeliver.c for ARMv7-M
    and ARMv8-M architectures.
    
    Signed-off-by: Andrew Au <[email protected]>
---
 testing/sig_sp_test/CMakeLists.txt     |  20 ++++
 testing/sig_sp_test/Kconfig            |  31 +++++
 testing/sig_sp_test/Make.defs          |  10 ++
 testing/sig_sp_test/Makefile           |  17 +++
 testing/sig_sp_test/sig_sp_test_main.c | 210 +++++++++++++++++++++++++++++++++
 5 files changed, 288 insertions(+)

diff --git a/testing/sig_sp_test/CMakeLists.txt 
b/testing/sig_sp_test/CMakeLists.txt
new file mode 100644
index 000000000..ed82f11be
--- /dev/null
+++ b/testing/sig_sp_test/CMakeLists.txt
@@ -0,0 +1,20 @@
+# 
##############################################################################
+# apps/testing/sig_sp_test/CMakeLists.txt
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# 
##############################################################################
+
+if(CONFIG_TESTING_SIG_SP_TEST)
+  nuttx_add_application(
+    NAME
+    ${CONFIG_TESTING_SIG_SP_TEST_PROGNAME}
+    PRIORITY
+    ${CONFIG_TESTING_SIG_SP_TEST_PRIORITY}
+    STACKSIZE
+    ${CONFIG_TESTING_SIG_SP_TEST_STACKSIZE}
+    MODULE
+    ${CONFIG_TESTING_SIG_SP_TEST}
+    SRCS
+    sig_sp_test_main.c)
+endif()
diff --git a/testing/sig_sp_test/Kconfig b/testing/sig_sp_test/Kconfig
new file mode 100644
index 000000000..1c32a53f2
--- /dev/null
+++ b/testing/sig_sp_test/Kconfig
@@ -0,0 +1,31 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config TESTING_SIG_SP_TEST
+       tristate "Signal SP restore test"
+       default n
+       depends on BUILD_FLAT && ARCH_ARM
+       ---help---
+               Test that modifying SP (REG_R13) in saved register context
+               during a signal handler is honored on exception return.
+
+               This verifies the SP context relocation in arm_sigdeliver.
+               Only available for flat builds on ARM.
+
+if TESTING_SIG_SP_TEST
+
+config TESTING_SIG_SP_TEST_PROGNAME
+       string "Program name"
+       default "sig_sp_test"
+
+config TESTING_SIG_SP_TEST_PRIORITY
+       int "Task priority"
+       default 100
+
+config TESTING_SIG_SP_TEST_STACKSIZE
+       int "Stack size"
+       default 4096
+
+endif
diff --git a/testing/sig_sp_test/Make.defs b/testing/sig_sp_test/Make.defs
new file mode 100644
index 000000000..57974a46c
--- /dev/null
+++ b/testing/sig_sp_test/Make.defs
@@ -0,0 +1,10 @@
+############################################################################
+# apps/testing/sig_sp_test/Make.defs
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+############################################################################
+
+ifneq ($(CONFIG_TESTING_SIG_SP_TEST),)
+CONFIGURED_APPS += $(APPDIR)/testing/sig_sp_test
+endif
diff --git a/testing/sig_sp_test/Makefile b/testing/sig_sp_test/Makefile
new file mode 100644
index 000000000..af73ec99e
--- /dev/null
+++ b/testing/sig_sp_test/Makefile
@@ -0,0 +1,17 @@
+############################################################################
+# apps/testing/sig_sp_test/Makefile
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+PROGNAME  = $(CONFIG_TESTING_SIG_SP_TEST_PROGNAME)
+PRIORITY  = $(CONFIG_TESTING_SIG_SP_TEST_PRIORITY)
+STACKSIZE = $(CONFIG_TESTING_SIG_SP_TEST_STACKSIZE)
+MODULE    = $(CONFIG_TESTING_SIG_SP_TEST)
+
+MAINSRC = sig_sp_test_main.c
+
+include $(APPDIR)/Application.mk
diff --git a/testing/sig_sp_test/sig_sp_test_main.c 
b/testing/sig_sp_test/sig_sp_test_main.c
new file mode 100644
index 000000000..e6df0a3bd
--- /dev/null
+++ b/testing/sig_sp_test/sig_sp_test_main.c
@@ -0,0 +1,210 @@
+/****************************************************************************
+ * apps/testing/sig_sp_test/sig_sp_test_main.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Test: Verify that modifying SP (REG_R13) in the saved register context
+ * is honored on context restore (exception return path).
+ *
+ * Scenario (simulates runtime unwinding past a trampoline):
+ *   1. Push values 1 and 2 onto the stack (simulating a trampoline push)
+ *   2. Busy-wait for a timer signal (SIGALRM)
+ *   3. In the handler, "emulate a pop" by advancing SP by 4
+ *      (simulating a runtime deciding the top frame was a stub)
+ *   4. Redirect PC to resume_after_signal
+ *   5. After signal return, pop a value — it should be 1
+ *
+ * This exercises:
+ *   - The SP relocation fix in arm_exception.S
+ *   - The backward sliding copy (new SP > old SP, stack shrinks)
+ *   - A realistic use case: unwinding past a trampoline frame
+ *
+ * Requirements:
+ *   - Flat build only (accesses nxsched_self() for saved_regs)
+ *   - ARM architecture (uses ARMv7-M register layout)
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <nuttx/arch.h>
+#include <nuttx/sched.h>
+#include <arch/irq.h>
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static volatile int g_result = -1;
+static volatile int g_ready = 0;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: verify_result
+ *
+ * Description:
+ *   Called with the popped value in r0. Verifies it equals 1.
+ ****************************************************************************/
+
+void __attribute__((noinline, used)) verify_result(uint32_t value)
+{
+  printf("sig_sp_test: popped value = %lu (expected 1)\n",
+         (unsigned long)value);
+
+  if (value == 1)
+    {
+      printf("sig_sp_test: PASS\n");
+      g_result = 0;
+    }
+  else
+    {
+      printf("sig_sp_test: FAIL - expected 1, got %lu\n",
+             (unsigned long)value);
+      g_result = 1;
+    }
+
+  exit(g_result);
+}
+
+/****************************************************************************
+ * Name: resume_after_signal
+ *
+ * Description:
+ *   We land here after the signal handler adjusts SP and PC.
+ *   Stack now has [SP] = 1 (the '2' was skipped by SP += 4).
+ *   Pop one value and verify it equals 1.
+ ****************************************************************************/
+
+static void __attribute__((naked, used)) resume_after_signal(void)
+{
+  __asm__ __volatile__(
+    "pop  {r0}\n\t"
+    "b    verify_result\n\t"
+  );
+}
+
+/****************************************************************************
+ * Name: sigalrm_handler
+ *
+ * Description:
+ *   Called from the timer interrupt path (async signal delivery).
+ *   Accesses saved_regs via nxsched_self() to modify the context
+ *   that will be restored after signal return.
+ ****************************************************************************/
+
+static void sigalrm_handler(int signo, siginfo_t *info, void *ucontext)
+{
+  struct tcb_s *rtcb = nxsched_self();
+  uint32_t *regs;
+
+  (void)signo;
+  (void)info;
+  (void)ucontext;
+
+  regs = rtcb->xcp.saved_regs;
+  if (regs == NULL)
+    {
+      printf("sig_sp_test: ERROR - saved_regs is NULL\n");
+      exit(2);
+    }
+
+  printf("sig_sp_test: handler - PC=0x%08lx SP=0x%08lx\n",
+         (unsigned long)regs[REG_R15],
+         (unsigned long)regs[REG_R13]);
+
+  /* Only act when the main code is ready (in the asm loop) */
+
+  if (!g_ready)
+    {
+      alarm(1);
+      return;
+    }
+
+  /* Emulate a pop: advance SP by 4 (skip top-of-stack value '2') */
+
+  regs[REG_R13] += 4;
+
+  /* Redirect execution to resume_after_signal */
+
+  regs[REG_R15] = ((uint32_t)(uintptr_t)resume_after_signal) & ~1u;
+  regs[REG_XPSR] |= (1 << 24);
+
+  printf("sig_sp_test: handler - new SP=0x%08lx PC=0x%08lx\n",
+         (unsigned long)regs[REG_R13],
+         (unsigned long)regs[REG_R15]);
+}
+
+/****************************************************************************
+ * Name: wait_with_values_on_stack
+ *
+ * Description:
+ *   Push 1 and 2 on the stack, set g_ready, then loop forever.
+ *   The alarm handler will redirect us out of the loop.
+ *   Stack after pushes: [SP] = 2, [SP+4] = 1
+ ****************************************************************************/
+
+static void __attribute__((naked, used)) wait_with_values_on_stack(void)
+{
+  __asm__ __volatile__(
+    "mov  r0, #1\n\t"
+    "push {r0}\n\t"
+    "mov  r0, #2\n\t"
+    "push {r0}\n\t"
+    "ldr  r0, =g_ready\n\t"
+    "mov  r1, #1\n\t"
+    "str  r1, [r0]\n\t"
+    "1: nop\n\t"
+    "b    1b\n\t"
+  );
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * sig_sp_test_main
+ ****************************************************************************/
+
+int main(int argc, char *argv[])
+{
+  struct sigaction sa;
+
+  (void)argc;
+  (void)argv;
+
+  printf("sig_sp_test: Signal SP restore test\n");
+  printf("sig_sp_test: push 1, push 2, alarm, handler SP+=4, pop => 1\n");
+
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_sigaction = sigalrm_handler;
+  sa.sa_flags = SA_SIGINFO;
+  sigemptyset(&sa.sa_mask);
+
+  if (sigaction(SIGALRM, &sa, NULL) < 0)
+    {
+      printf("sig_sp_test: ERROR sigaction failed\n");
+      return 1;
+    }
+
+  alarm(1);
+  wait_with_values_on_stack();
+
+  /* Should never reach here */
+
+  printf("sig_sp_test: ERROR - returned from wait\n");
+  return 1;
+}

Reply via email to