llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libunwind

Author: Hubert Tong (hubert-reinterpretcast)

<details>
<summary>Changes</summary>

Test detection, during stepping, of the backchain mutation introduced by a VAPI 
call (see https://github.com/llvm/llvm-project/pull/209280). Further, test 
resumption of contexts using cursors obtained while a VAPI is active on the 
thread.

Testing is done via FileCheck inspection of trace output enabled by 
`LIBUNWIND_PRINT_UNWINDING=1`. When Live Library Update is not enabled, 
synthetic trace output is generated by the test program itself.

---------

Assisted-by: IBM Bob

---
Full diff: https://github.com/llvm/llvm-project/pull/209306.diff


1 Files Affected:

- (added) libunwind/test/aix_vapi_unw_resume.pass.cpp (+164) 


``````````diff
diff --git a/libunwind/test/aix_vapi_unw_resume.pass.cpp 
b/libunwind/test/aix_vapi_unw_resume.pass.cpp
new file mode 100644
index 0000000000000..a1426487b4018
--- /dev/null
+++ b/libunwind/test/aix_vapi_unw_resume.pass.cpp
@@ -0,0 +1,164 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: target={{.+}}-aix{{.*}}
+// REQUIRES: has-filecheck
+
+// ADDITIONAL_COMPILE_FLAGS: -fno-inline -fno-exceptions
+
+// RUN: %{build}
+// RUN: %{exec} %t.exe 2>&1 | FileCheck %s
+
+// Tests use of the libunwind C API to step up from a context where the VAPI is
+// active and to resume contexts where
+// - the VAPI is active (and thus VAPI return glue is not called) and
+// - where the VAPI is not active (and thus VAPI return glue _is_ called).
+//
+// In the latter case, which applies not just to the caller of the Virtual API
+// but also to its ancestors, the return glue should always be called (i.e.,
+// each time, without regard for whether the VAPI is currently active).
+
+#include <assert.h>
+#include <libunwind.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __64BIT__
+#define R3 UNW_PPC64_R3
+#else
+#define R3 UNW_PPC_R3
+#endif
+
+extern "C" void *returns_twice_bsearch
+    [[gnu::returns_twice]] (const void *, const void *, size_t, size_t,
+                            int (*)(const void *,
+                                    const void *)) __asm__("bsearch");
+
+static bool llu_enabled;
+static unw_cursor_t bsearch_cursor;
+static unw_cursor_t bsearch_caller_cursor;
+static unw_cursor_t main_cursor;
+
+extern "C" int cmp(const void *pa, const void *pb) {
+  (void)pa;
+  (void)pb;
+
+  fprintf(
+      stderr,
+      "Populate global cursors for `bsearch`, `bsearch_caller`, and 
`main`.\n");
+  // CHECK-LABEL: Populate global cursors
+  unw_context_t context;
+  unw_cursor_t cursor;
+  unw_getcontext(&context);
+  unw_init_local(&cursor, &context);
+  // Step from `cmp` up to `bsearch`.
+  unw_step(&cursor);
+  if (!llu_enabled)
+    fprintf(stderr,
+            "libunwind: the next return address=VAPI_NOT_ENABLED from VAPI\n");
+  // CHECK-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=cmp
+  // CHECK: libunwind: the next return address=[[VAPI_RA:[^ ]*]] from VAPI
+  bsearch_cursor = cursor;
+  // Step from `bsearch` up to `bsearch_caller`.
+  unw_step(&cursor);
+  if (!llu_enabled)
+    fprintf(stderr, "libunwind: return address=VAPI_NOT_ENABLED from VAPI\n");
+  // CHECK-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=bsearch
+  // CHECK: libunwind: return address=[[VAPI_RA]] from VAPI
+  bsearch_caller_cursor = cursor;
+  // Step from `bsearch_caller` up to `main`.
+  unw_step(&cursor);
+  // CHECK-LABEL: libunwind: stepWithTBTable: Look up traceback table of 
func=_Z14bsearch_callerv
+  // CHECK-NOT: VAPI
+  main_cursor = cursor;
+
+  // Test resuming context where VAPI is active.
+  fprintf(stderr,
+          "Return to `bsearch` with r3 set to 0 using the global cursor.\n");
+  unw_set_reg(&bsearch_cursor, R3, (unw_word_t)0);
+  unw_resume(&bsearch_cursor);
+  __builtin_unreachable();
+  // CHECK-LABEL: Return to `bsearch`
+  // CHECK-NOT: VAPI: executing return glue
+}
+
+char bsearch_caller_ret;
+void *bsearch_caller(void) {
+  volatile int state = 0;
+
+  char c;
+  char buf[3];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wuninitialized-const-pointer"
+  void *result = returns_twice_bsearch(&c, buf, 1, 1, cmp);
+#pragma clang diagnostic pop
+  assert(result == &buf[state]);
+
+  // Test resuming context where VAPI is not active. The VAPI return glue 
should
+  // be used each time without regard for whether the VAPI is currently active.
+
+  // `state` is volatile to observe changes in the value between the multiple
+  // returns in `setjmp`/`longjmp`-like usage. We need to spell out the
+  // `volatile` accesses very explicitly thanks to changes in the C++ standard.
+  if ((state = state + 1, state) < 3) {
+    fprintf(stderr,
+            "Return to `bsearch_caller` at the invocation of "
+            "`returns_twice_bsearch` (really `bsearch`) with r3 set to "
+            "&buf[%d] using the global cursor.\n",
+            state);
+    if (!llu_enabled)
+      fprintf(stderr,
+              "libunwind: VAPI: executing return glue VAPI_NOT_ENABLED\n");
+    unw_set_reg(&bsearch_caller_cursor, R3, (unw_word_t)&buf[state]);
+    unw_resume(&bsearch_caller_cursor);
+    __builtin_unreachable();
+    // CHECK-LABEL: Return to `bsearch_caller` {{.*}}&buf[1]
+    // CHECK: libunwind: VAPI: executing return glue
+    // CHECK-LABEL: Return to `bsearch_caller` {{.*}}&buf[2]
+    // CHECK: libunwind: VAPI: executing return glue
+  }
+
+  // Test resuming context where VAPI is not active, one frame up from the VAPI
+  // caller.
+  fprintf(stderr, "Return to `main` at the invocation of `bsearch_caller` with 
"
+                  "r3 set to `&bsearch_caller_ret` using the global 
cursor.\n");
+  if (!llu_enabled)
+    fprintf(stderr,
+            "libunwind: VAPI: executing return glue VAPI_NOT_ENABLED\n");
+  unw_set_reg(&main_cursor, R3, (unw_word_t)&bsearch_caller_ret);
+  unw_resume(&main_cursor);
+  __builtin_unreachable();
+  // CHECK-LABEL: Return to `main`
+  // CHECK: libunwind: VAPI: executing return glue
+}
+
+// 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;
+};
+
+int main(void) {
+  if (setenv("LIBUNWIND_PRINT_UNWINDING", "1", true) != 0) {
+    perror("setenv");
+    abort();
+  }
+
+  FunctionDescriptor *fd = reinterpret_cast<FunctionDescriptor *>(bsearch);
+  llu_enabled =
+      vapi_glue_addr_begin <= fd->entry && fd->entry < vapi_glue_addr_end;
+
+  assert(bsearch_caller() == &bsearch_caller_ret);
+}

``````````

</details>


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

Reply via email to