================ @@ -0,0 +1,164 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// clang-format off + +// REQUIRES: target={{aarch64.*}} +// UNSUPPORTED: target={{.*-windows.*}} + +// The libSystem unwinder does not correctly read UNW_AARCH64_RA_SIGN_STATE, at +// least through OS version 27.0 +// XFAIL: stdlib=apple-libc++ && target={{.*}}-apple-{{.*}}{{(11|12|13|14|15|26)(\.\d+)?}} +// XFAIL: stdlib=apple-libc++ && target={{.*}}-apple-{{.*}}27.0 + +// clang-format on + +#undef NDEBUG +#include "../src/config.h" +#include "support/func_bounds.h" + +#include <assert.h> +#include <inttypes.h> +#include <libunwind.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <unwind.h> + +#if defined(__APPLE__) +#include <sys/sysctl.h> +#endif +#if defined(_LIBUNWIND_HAVE_GETAUXVAL) || defined(_LIBUNWIND_HAVE_ELF_AUX_INFO) +#include <sys/auxv.h> +#endif + +// Note: This test requires FEAT_PAuth (and is setup to pass on other targets). + +#if defined(__APPLE__) +static bool checkHasPAuth() { + int has_pauth = 0; + size_t size = sizeof(has_pauth); + if (sysctlbyname("hw.optional.arm.FEAT_PAuth", &has_pauth, &size, NULL, 0)) + return false; + return has_pauth != 0; +} +#elif defined(_LIBUNWIND_HAVE_GETAUXVAL) +static bool checkHasPAuth() { + constexpr unsigned long hwcap_paca = (1UL << 30); + unsigned long hwcap = getauxval(AT_HWCAP); + return (hwcap & hwcap_paca) != 0; +} +#elif defined(_LIBUNWIND_HAVE_ELF_AUX_INFO) +static bool checkHasPAuth() { + constexpr unsigned long hwcap_paca = (1UL << 30); + unsigned long hwcap = 0; + elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); + return (hwcap & hwcap_paca) != 0; +} +#else +static bool checkHasPAuth() { + // TODO: Support other platforms. + return false; +} +#endif + +FUNC_BOUNDS_DECL(main_func); + +static _Unwind_Reason_Code frame_handler(struct _Unwind_Context *ctx, + void *arg) { + fprintf(stderr, "frame_handler\n"); + uint64_t ra_sign_state = + (uint64_t)_Unwind_GetGR(ctx, UNW_AARCH64_RA_SIGN_STATE); + + fprintf(stderr, "ra_sign_state = 0x%" PRIx64 "\n", ra_sign_state); + + uintptr_t ip = _Unwind_GetIP(ctx); + + fprintf(stderr, "UNW_AARCH64_RA_SIGN_STATE @ 0x%" PRIxPTR " = %" PRIu64 "\n", + ip, ra_sign_state); + + if (ip >= (uintptr_t)FUNC_START(main_func) && + ip < (uintptr_t)FUNC_END(main_func)) { + + // Collect the RA from the callee that will return to main. + *(uint64_t *)arg = ra_sign_state; + + // Unwind until main is reached, above frames depend on the platform and + // architecture. + return _URC_END_OF_STACK; + } + +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + assert(ra_sign_state == 1 || ra_sign_state == 2); +#endif + + return _URC_NO_REASON; +} + +__attribute__((noinline)) extern "C" uintptr_t get_main_ra_sign_state() { + uint64_t sign_state = -1; + _Unwind_Backtrace(frame_handler, &sign_state); + fprintf(stderr, "get_main_ra_sign_state: sign_state = 0x%" PRIx64 "\n", + sign_state); + assert((sign_state & 0x3) == sign_state); + return sign_state; +} + +__attribute__((noinline)) static uint64_t check_vanilla() { + return get_main_ra_sign_state(); +} + +__attribute__((naked, target("pauth"))) static uint64_t check_negate() { + // clang-format off + asm( +#if !defined(__APPLE__) + ".cfi_b_key_frame\n" +#endif + ".cfi_negate_ra_state\n" + "pacibsp\n" + + "stp x29, x30, [sp, #-16]!\n" + ".cfi_def_cfa_offset 16\n" + ".cfi_offset x29, -16\n" + ".cfi_offset x30, -8\n" + + "bl " SYMBOL_NAME(get_main_ra_sign_state) "\n" + + "ldp x29, x30, [sp], #16\n" + ".cfi_def_cfa_offset 0\n" + ".cfi_restore x29\n" + ".cfi_restore x30\n" + + ".cfi_negate_ra_state\n" + "retab"); + // clang-format on +} + +FUNC_ATTR(main_func) int main(int, char **) { + uint64_t ret; + + ret = check_vanilla(); + fprintf(stderr, "check_vanilla: ret = 0x%" PRIx64 "\n", ret); +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + assert(ret == 1 || ret == 2); +#endif ---------------- jroelofs wrote:
This is asserting that the state must either either pauth-signed without the pc discriminator (1), or pauth-lr-signed with the pc discriminator (2), but not unsigned as in vanilla arm64. https://github.com/llvm/llvm-project/pull/209947 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
