1*77aa9ca9SDaniel Kiss // -*- C++ -*-
2*77aa9ca9SDaniel Kiss //===----------------------------------------------------------------------===//
3*77aa9ca9SDaniel Kiss //
4*77aa9ca9SDaniel Kiss // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*77aa9ca9SDaniel Kiss // See https://llvm.org/LICENSE.txt for license information.
6*77aa9ca9SDaniel Kiss // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*77aa9ca9SDaniel Kiss //
8*77aa9ca9SDaniel Kiss //===----------------------------------------------------------------------===//
9*77aa9ca9SDaniel Kiss
10*77aa9ca9SDaniel Kiss // REQUIRES: linux && target={{aarch64-.+}}
11*77aa9ca9SDaniel Kiss
12*77aa9ca9SDaniel Kiss // Basic test for float registers number are accepted.
13*77aa9ca9SDaniel Kiss
14*77aa9ca9SDaniel Kiss #include <dlfcn.h>
15*77aa9ca9SDaniel Kiss #include <stdlib.h>
16*77aa9ca9SDaniel Kiss #include <string.h>
17*77aa9ca9SDaniel Kiss #include <unwind.h>
18*77aa9ca9SDaniel Kiss
frame_handler(struct _Unwind_Context * ctx,void * arg)19*77aa9ca9SDaniel Kiss _Unwind_Reason_Code frame_handler(struct _Unwind_Context *ctx, void *arg) {
20*77aa9ca9SDaniel Kiss (void)arg;
21*77aa9ca9SDaniel Kiss Dl_info info = {0, 0, 0, 0};
22*77aa9ca9SDaniel Kiss
23*77aa9ca9SDaniel Kiss // Unwind util the main is reached, above frames depend on the platform and
24*77aa9ca9SDaniel Kiss // architecture.
25*77aa9ca9SDaniel Kiss if (dladdr(reinterpret_cast<void *>(_Unwind_GetIP(ctx)), &info) &&
26*77aa9ca9SDaniel Kiss info.dli_sname && !strcmp("main", info.dli_sname))
27*77aa9ca9SDaniel Kiss _Exit(0);
28*77aa9ca9SDaniel Kiss
29*77aa9ca9SDaniel Kiss return _URC_NO_REASON;
30*77aa9ca9SDaniel Kiss }
31*77aa9ca9SDaniel Kiss
foo()32*77aa9ca9SDaniel Kiss __attribute__((noinline)) void foo() {
33*77aa9ca9SDaniel Kiss // Provide some CFI directives that instructs the unwinder where given
34*77aa9ca9SDaniel Kiss // float register is.
35*77aa9ca9SDaniel Kiss #if defined(__aarch64__)
36*77aa9ca9SDaniel Kiss // DWARF register number for V0-V31 registers are 64-95.
37*77aa9ca9SDaniel Kiss // Previous value of V0 is saved at offset 0 from CFA.
38*77aa9ca9SDaniel Kiss asm volatile(".cfi_offset 64, 0");
39*77aa9ca9SDaniel Kiss // From now on the previous value of register can't be restored anymore.
40*77aa9ca9SDaniel Kiss asm volatile(".cfi_undefined 65");
41*77aa9ca9SDaniel Kiss asm volatile(".cfi_undefined 95");
42*77aa9ca9SDaniel Kiss // Previous value of V2 is in V30.
43*77aa9ca9SDaniel Kiss asm volatile(".cfi_register 66, 94");
44*77aa9ca9SDaniel Kiss #endif
45*77aa9ca9SDaniel Kiss _Unwind_Backtrace(frame_handler, NULL);
46*77aa9ca9SDaniel Kiss }
47*77aa9ca9SDaniel Kiss
main()48*77aa9ca9SDaniel Kiss int main() {
49*77aa9ca9SDaniel Kiss foo();
50*77aa9ca9SDaniel Kiss return -2;
51*77aa9ca9SDaniel Kiss }
52