v8 152.0.0

Rust bindings to V8
Documentation
//===----------------------------------------------------------------------===//
//
// 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 \
// 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>

/// 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;
  unw_cursor_t cursor;
  unw_getcontext(&context);
  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");
  /// 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-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);
  if (!llu_enabled)
    fprintf(stderr,
            "libunwind: The return address in stack VAPI_NOT_ENABLED is within "
            "the range of VAPI address; set isKnownVapiNotActive to true\n");
  /// Note:
  /// The synthetic VAPI_NOT_ENABLED output would appear after _all_ of the trace
  /// output from the `unw_step` call. Use DEBUG instead of DEBUG-NEXT to allow
  /// for that.
  // DEBUG-LABEL: libunwind: stepWithTBTable: Look up traceback table of func=exit
  // DEBUG-NEXT: libunwind: Possible signal handler frame
  // DEBUG: libunwind: {{.*}} is within the range of VAPI address; set isKnownVapiNotActive
  /// 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`
  if (!llu_enabled)
    fprintf(stderr,
            "libunwind: VAPI: executing return glue VAPI_NOT_ENABLED\n");
  unw_resume(&cursor);
  // DEBUG: libunwind: VAPI: executing return glue
}

void trapper(void) {
  __builtin_debugtrap();
  _Exit(EXIT_FAILURE);
}

int main(void) {
  if (setenv("LIBUNWIND_PRINT_UNWINDING", "1", true) != 0) {
    perror("setenv");
    abort();
  }
  if (atexit(my_atexit_handler) != 0) {
    perror("atexit");
    abort();
  }
  if (signal(SIGTRAP, exit) == SIG_ERR) {
    perror("signal");
    abort();
  }
  trapper();
  _Exit(0);
}