https://github.com/hubert-reinterpretcast created 
https://github.com/llvm/llvm-project/pull/209662

Further to https://github.com/llvm/llvm-project/pull/209306, test a case where 
a signal handler is a Virtual API function triggered synchronously while the 
VAPI is not active. Resuming an ancestor context of the signal frame should 
call the VAPI return glue.

---------

Assisted-by: IBM Bob

>From 9c59e1ba7e329d81c3c5025123eb5c2a24646ab2 Mon Sep 17 00:00:00 2001
From: Hubert Tong <[email protected]>
Date: Tue, 14 Jul 2026 18:08:18 -0400
Subject: [PATCH 1/7] WIP: Skeleton for libunwind C API test for signal handler
 that is a Virtual API

---
 .../test/aix_vapi_signal_unwind.pass.cpp      | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 libunwind/test/aix_vapi_signal_unwind.pass.cpp

diff --git a/libunwind/test/aix_vapi_signal_unwind.pass.cpp 
b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
new file mode 100644
index 0000000000000..0b79f74b23076
--- /dev/null
+++ b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Tests unwinding where the signal handler is a VAPI function.
+//
+// `exit` is used as the signal handler and the unwinding is done in an atexit 
handler.
+// `__builtin_debugtrap` is used because `raise` is also a VAPI function.
+
+// REQUIRES: target={{.+}}-aix{{.*}}
+// REQUIRES: has-filecheck
+
+// ADDITIONAL_COMPILE_FLAGS: -fno-inline -fno-exceptions
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe 2>&1 | FileCheck %s
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void my_atexit_handler(void) {
+  fprintf(stderr, "Retrieve a cursor to `main` by stepping up.\n");
+  // CHECK: Retrieve a cursor to `main`
+  // TODO
+  fprintf(stderr, "Resume `main` at the call to `trapper.\n");
+  // CHECK: Resume `main`
+  // TODO
+}
+
+void trapper(void) {
+  __builtin_debugtrap();
+  _Exit(EXIT_FAILURE);
+}
+
+int main(void) {
+  if (atexit(my_atexit_handler) != 0) {
+    perror("atexit");
+    abort();
+  }
+  if (signal(SIGTRAP, exit) == SIG_ERR) {
+    perror("signal");
+    abort();
+  }
+  trapper();
+  _Exit(0);
+}

>From a25110566e1ca525b520ced8706f17ea735cabfc Mon Sep 17 00:00:00 2001
From: Hubert Tong <[email protected]>
Date: Tue, 14 Jul 2026 18:31:22 -0400
Subject: [PATCH 2/7] WIP: IBM Bob: Add API calls; enable tracing, add
 DEBUG-LABEL checks

---
 .../test/aix_vapi_signal_unwind.pass.cpp      | 32 +++++++++++++++----
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/libunwind/test/aix_vapi_signal_unwind.pass.cpp 
b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
index 0b79f74b23076..ec288f4434375 100644
--- a/libunwind/test/aix_vapi_signal_unwind.pass.cpp
+++ b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
@@ -17,20 +17,36 @@
 // ADDITIONAL_COMPILE_FLAGS: -fno-inline -fno-exceptions
 
 // RUN: %{build}
-// RUN: %{exec} %t.exe 2>&1 | FileCheck %s
+// RUN: %{exec} %t.exe 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK \
+// RUN:       %if libunwind-assertions-enabled %{ --check-prefix=DEBUG %} \
+// RUN:       %s
 
 #include <errno.h>
+#include <libunwind.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 void my_atexit_handler(void) {
   fprintf(stderr, "Retrieve a cursor to `main` by stepping up.\n");
-  // CHECK: Retrieve a cursor to `main`
-  // TODO
-  fprintf(stderr, "Resume `main` at the call to `trapper.\n");
-  // CHECK: Resume `main`
-  // TODO
+  // CHECK-LABEL: Retrieve a cursor to `main`
+  unw_context_t context;
+  unw_cursor_t cursor;
+  unw_getcontext(&context);
+  unw_init_local(&cursor, &context);
+  // Step from `my_atexit_handler` up to `exit`.
+  unw_step(&cursor);
+  // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=my_atexit_handler
+  // Step from `exit` (signal handler, VAPI) up to `main`.
+  unw_step(&cursor);
+  // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=exit
+
+  fprintf(stderr, "Resume `main` at the call to `trapper`.\n");
+  // CHECK-LABEL: Resume `main`
+  unw_resume(&cursor);
+  __builtin_unreachable();
+  // DEBUG: libunwind: VAPI: executing return glue
 }
 
 void trapper(void) {
@@ -39,6 +55,10 @@ void trapper(void) {
 }
 
 int main(void) {
+  if (setenv("LIBUNWIND_PRINT_UNWINDING", "1", true) != 0) {
+    perror("setenv");
+    abort();
+  }
   if (atexit(my_atexit_handler) != 0) {
     perror("atexit");
     abort();

>From a3dbb34d6099239eefdafbf77a5c3237326a6868 Mon Sep 17 00:00:00 2001
From: Hubert Tong <[email protected]>
Date: Tue, 14 Jul 2026 19:11:54 -0400
Subject: [PATCH 3/7] Fixup! IBM Bob: Account for `trapper` frame and C++ name
 mangling

---
 libunwind/test/aix_vapi_signal_unwind.pass.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libunwind/test/aix_vapi_signal_unwind.pass.cpp 
b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
index ec288f4434375..76b3c4839e15e 100644
--- a/libunwind/test/aix_vapi_signal_unwind.pass.cpp
+++ b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
@@ -37,10 +37,13 @@ void my_atexit_handler(void) {
   unw_init_local(&cursor, &context);
   // Step from `my_atexit_handler` up to `exit`.
   unw_step(&cursor);
-  // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=my_atexit_handler
-  // Step from `exit` (signal handler, VAPI) up to `main`.
+  // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z17my_atexit_handlerv
+  // Step from `exit` (signal handler, VAPI) up to `trapper`.
   unw_step(&cursor);
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=exit
+  // Step from `trapper` up to `main`.
+  unw_step(&cursor);
+  // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z7trapperv
 
   fprintf(stderr, "Resume `main` at the call to `trapper`.\n");
   // CHECK-LABEL: Resume `main`

>From 9fb71682099774569e72eb1deebd78eeccbaaa5d Mon Sep 17 00:00:00 2001
From: Hubert Tong <[email protected]>
Date: Tue, 14 Jul 2026 19:36:48 -0400
Subject: [PATCH 4/7] Add DEBUG check lines for unw_step calls

---
 libunwind/test/aix_vapi_signal_unwind.pass.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libunwind/test/aix_vapi_signal_unwind.pass.cpp 
b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
index 76b3c4839e15e..1a8465848da97 100644
--- a/libunwind/test/aix_vapi_signal_unwind.pass.cpp
+++ b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
@@ -38,12 +38,16 @@ void my_atexit_handler(void) {
   // Step from `my_atexit_handler` up to `exit`.
   unw_step(&cursor);
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z17my_atexit_handlerv
+  // DEBUG: libunwind: the next return address={{[^ ]*}} from VAPI
+  // DEBUG: libunwind: The next is a signal handler frame
   // Step from `exit` (signal handler, VAPI) up to `trapper`.
   unw_step(&cursor);
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=exit
+  // DEBUG-NEXT: libunwind: Possible signal handler frame
   // Step from `trapper` up to `main`.
   unw_step(&cursor);
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z7trapperv
+  // DEBUG-NOT: VAPI
 
   fprintf(stderr, "Resume `main` at the call to `trapper`.\n");
   // CHECK-LABEL: Resume `main`

>From 8fb0bd8e220ae270c9f3914c01d3b68fd3fa64be Mon Sep 17 00:00:00 2001
From: Hubert Tong <[email protected]>
Date: Tue, 14 Jul 2026 19:47:42 -0400
Subject: [PATCH 5/7] IBM Bob: Add synthetic trace output when LLU is not
 enabled

---
 .../test/aix_vapi_signal_unwind.pass.cpp      | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/libunwind/test/aix_vapi_signal_unwind.pass.cpp 
b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
index 1a8465848da97..c40ffc15de39f 100644
--- a/libunwind/test/aix_vapi_signal_unwind.pass.cpp
+++ b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
@@ -28,7 +28,24 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+// VAPI glue addresses
+constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8b80;
+constexpr uintptr_t vapi_addr_64 = 0x8e00;
+constexpr size_t vapi_size_64 = 0x0200;
+constexpr uintptr_t vapi_glue_addr_begin = vapi_glue_addr_ext_32;
+constexpr uintptr_t vapi_glue_addr_end = vapi_addr_64 + vapi_size_64;
+
+struct FunctionDescriptor {
+  uintptr_t entry;
+  uintptr_t toc;
+  uintptr_t env;
+};
+
 void my_atexit_handler(void) {
+  FunctionDescriptor *fd = reinterpret_cast<FunctionDescriptor *>(exit);
+  bool llu_enabled =
+      vapi_glue_addr_begin <= fd->entry && fd->entry < vapi_glue_addr_end;
+
   fprintf(stderr, "Retrieve a cursor to `main` by stepping up.\n");
   // CHECK-LABEL: Retrieve a cursor to `main`
   unw_context_t context;
@@ -37,6 +54,8 @@ void my_atexit_handler(void) {
   unw_init_local(&cursor, &context);
   // Step from `my_atexit_handler` up to `exit`.
   unw_step(&cursor);
+  if (!llu_enabled)
+    fprintf(stderr, "libunwind: the next return address=VAPI_NOT_ENABLED from 
VAPI\n");
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z17my_atexit_handlerv
   // DEBUG: libunwind: the next return address={{[^ ]*}} from VAPI
   // DEBUG: libunwind: The next is a signal handler frame
@@ -51,6 +70,8 @@ void my_atexit_handler(void) {
 
   fprintf(stderr, "Resume `main` at the call to `trapper`.\n");
   // CHECK-LABEL: Resume `main`
+  if (!llu_enabled)
+    fprintf(stderr, "libunwind: VAPI: executing return glue 
VAPI_NOT_ENABLED\n");
   unw_resume(&cursor);
   __builtin_unreachable();
   // DEBUG: libunwind: VAPI: executing return glue

>From d39d71bb53c22d1897e4f6935ba5613e685f1ef5 Mon Sep 17 00:00:00 2001
From: Hubert Tong <[email protected]>
Date: Tue, 14 Jul 2026 21:43:46 -0400
Subject: [PATCH 6/7] Use DEBUG-DAG to allow for synthetic trace ordering
 difference

---
 .../test/aix_vapi_signal_unwind.pass.cpp      | 44 ++++++++++---------
 1 file changed, 24 insertions(+), 20 deletions(-)

diff --git a/libunwind/test/aix_vapi_signal_unwind.pass.cpp 
b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
index c40ffc15de39f..f9a2aa47c7d16 100644
--- a/libunwind/test/aix_vapi_signal_unwind.pass.cpp
+++ b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
@@ -1,26 +1,26 @@
 
//===----------------------------------------------------------------------===//
 //
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+/// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+/// See https://llvm.org/LICENSE.txt for license information.
+/// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 
//===----------------------------------------------------------------------===//
 
-// Tests unwinding where the signal handler is a VAPI function.
+/// Tests unwinding where the signal handler is a VAPI function.
 //
-// `exit` is used as the signal handler and the unwinding is done in an atexit 
handler.
-// `__builtin_debugtrap` is used because `raise` is also a VAPI function.
+/// `exit` is used as the signal handler and the unwinding is done in an 
atexit handler.
+/// `__builtin_debugtrap` is used because `raise` is also a VAPI function.
 
-// REQUIRES: target={{.+}}-aix{{.*}}
-// REQUIRES: has-filecheck
+/// REQUIRES: target={{.+}}-aix{{.*}}
+/// REQUIRES: has-filecheck
 
-// ADDITIONAL_COMPILE_FLAGS: -fno-inline -fno-exceptions
+/// ADDITIONAL_COMPILE_FLAGS: -fno-inline -fno-exceptions
 
-// RUN: %{build}
-// RUN: %{exec} %t.exe 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK \
-// RUN:       %if libunwind-assertions-enabled %{ --check-prefix=DEBUG %} \
-// RUN:       %s
+/// RUN: %{build}
+/// RUN: %{exec} %t.exe 2>&1 \
+/// RUN: | FileCheck --check-prefix=CHECK \
+/// RUN:       %if libunwind-assertions-enabled %{ --check-prefix=DEBUG %} \
+/// RUN:       %s
 
 #include <errno.h>
 #include <libunwind.h>
@@ -28,7 +28,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-// VAPI glue addresses
+/// VAPI glue addresses
 constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8b80;
 constexpr uintptr_t vapi_addr_64 = 0x8e00;
 constexpr size_t vapi_size_64 = 0x0200;
@@ -52,18 +52,22 @@ void my_atexit_handler(void) {
   unw_cursor_t cursor;
   unw_getcontext(&context);
   unw_init_local(&cursor, &context);
-  // Step from `my_atexit_handler` up to `exit`.
+  /// Step from `my_atexit_handler` up to `exit`.
   unw_step(&cursor);
   if (!llu_enabled)
     fprintf(stderr, "libunwind: the next return address=VAPI_NOT_ENABLED from 
VAPI\n");
+  /// Note:
+  /// The synthetic VAPI_NOT_ENABLED output would appear _after_ the trace
+  /// output indicating that the "next is a signal handler frame". Use 
DEBUG-DAG
+  /// to allow for that.
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z17my_atexit_handlerv
-  // DEBUG: libunwind: the next return address={{[^ ]*}} from VAPI
-  // DEBUG: libunwind: The next is a signal handler frame
-  // Step from `exit` (signal handler, VAPI) up to `trapper`.
+  // DEBUG-DAG: libunwind: the next return address={{[^ ]*}} from VAPI
+  // DEBUG-DAG: libunwind: The next is a signal handler frame
+  /// Step from `exit` (signal handler, VAPI) up to `trapper`.
   unw_step(&cursor);
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=exit
   // DEBUG-NEXT: libunwind: Possible signal handler frame
-  // Step from `trapper` up to `main`.
+  /// Step from `trapper` up to `main`.
   unw_step(&cursor);
   // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z7trapperv
   // DEBUG-NOT: VAPI

>From 33d833c727b197fcd6378baa153701d86974edaa Mon Sep 17 00:00:00 2001
From: Hubert Tong <[email protected]>
Date: Tue, 14 Jul 2026 21:58:54 -0400
Subject: [PATCH 7/7] clang-format

---
 libunwind/test/aix_vapi_signal_unwind.pass.cpp | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/libunwind/test/aix_vapi_signal_unwind.pass.cpp 
b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
index f9a2aa47c7d16..038a0d5d4359d 100644
--- a/libunwind/test/aix_vapi_signal_unwind.pass.cpp
+++ b/libunwind/test/aix_vapi_signal_unwind.pass.cpp
@@ -1,14 +1,15 @@
 
//===----------------------------------------------------------------------===//
 //
-/// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-/// See https://llvm.org/LICENSE.txt for license information.
-/// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 
//===----------------------------------------------------------------------===//
 
 /// Tests unwinding where the signal handler is a VAPI function.
 //
-/// `exit` is used as the signal handler and the unwinding is done in an 
atexit handler.
+/// `exit` is used as the signal handler and the unwinding is done in an atexit
+/// handler.
 /// `__builtin_debugtrap` is used because `raise` is also a VAPI function.
 
 /// REQUIRES: target={{.+}}-aix{{.*}}
@@ -55,7 +56,8 @@ void my_atexit_handler(void) {
   /// Step from `my_atexit_handler` up to `exit`.
   unw_step(&cursor);
   if (!llu_enabled)
-    fprintf(stderr, "libunwind: the next return address=VAPI_NOT_ENABLED from 
VAPI\n");
+    fprintf(stderr,
+            "libunwind: the next return address=VAPI_NOT_ENABLED from VAPI\n");
   /// Note:
   /// The synthetic VAPI_NOT_ENABLED output would appear _after_ the trace
   /// output indicating that the "next is a signal handler frame". Use 
DEBUG-DAG
@@ -75,7 +77,8 @@ void my_atexit_handler(void) {
   fprintf(stderr, "Resume `main` at the call to `trapper`.\n");
   // CHECK-LABEL: Resume `main`
   if (!llu_enabled)
-    fprintf(stderr, "libunwind: VAPI: executing return glue 
VAPI_NOT_ENABLED\n");
+    fprintf(stderr,
+            "libunwind: VAPI: executing return glue VAPI_NOT_ENABLED\n");
   unw_resume(&cursor);
   __builtin_unreachable();
   // DEBUG: libunwind: VAPI: executing return glue

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to