1 /* PR target/104689. Unwind across pac-ret frames with unusual dwarf. */
2 /* { dg-do run } */
3 /* { dg-require-effective-target lp64 } */
4 /* { dg-options "-fexceptions -O2" } */
5
6 #include <unwind.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9
10 #define die() \
11 do { \
12 printf ("%s:%d: reached unexpectedly.\n", __FILE__, __LINE__); \
13 fflush (stdout); \
14 abort (); \
15 } while (0)
16
17
18 /* Code to invoke unwinding with a logging callback. */
19
20 static struct _Unwind_Exception exc;
21
22 static _Unwind_Reason_Code
23 force_unwind_stop (int version, _Unwind_Action actions,
24 _Unwind_Exception_Class exc_class,
25 struct _Unwind_Exception *exc_obj,
26 struct _Unwind_Context *context,
27 void *stop_parameter)
28 {
29 printf ("%s: CFA: %p PC: %p actions: %d\n",
30 __func__,
31 (void *)_Unwind_GetCFA (context),
32 (void *)_Unwind_GetIP (context),
33 (int)actions);
34 if (actions & _UA_END_OF_STACK)
35 die ();
36 return _URC_NO_REASON;
37 }
38
39 static void force_unwind (void)
40 {
41 #ifndef __USING_SJLJ_EXCEPTIONS__
42 _Unwind_ForcedUnwind (&exc, force_unwind_stop, 0);
43 #else
44 _Unwind_SjLj_ForcedUnwind (&exc, force_unwind_stop, 0);
45 #endif
46 }
47
48
49 /* Define functions with unusual pac-ret dwarf via top level asm. */
50
51 #define STR(x) #x
52 #define DW_CFA_val_expression 0x16
53 #define RA_SIGN_STATE 34
54 #define DW_OP_lit0 0x30
55 #define DW_OP_lit1 0x31
56
57 #define cfi_escape(a1, a2, a3, a4) \
58 ".cfi_escape " STR(a1) ", " STR(a2) ", " STR(a3) ", " STR(a4)
59
60 /* Bytes: 0x16 0x22 0x01 0x30 */
61 #define SET_RA_STATE_0 \
62 cfi_escape (DW_CFA_val_expression, RA_SIGN_STATE, 1, DW_OP_lit0)
63
64 /* Bytes: 0x16 0x22 0x01 0x31 */
65 #define SET_RA_STATE_1 \
66 cfi_escape (DW_CFA_val_expression, RA_SIGN_STATE, 1, DW_OP_lit1)
67
68 /* These function call their argument. */
69 void unusual_pac_ret (void *);
70 void unusual_no_pac_ret (void *);
71
72 asm(""
73 ".global unusual_pac_ret\n"
74 ".type unusual_pac_ret, %function\n"
75 "unusual_pac_ret:\n"
76 " .cfi_startproc\n"
77 " " SET_RA_STATE_0 "\n"
78 " hint 25 // paciasp\n"
79 " " SET_RA_STATE_1 "\n"
80 " stp x29, x30, [sp, -16]!\n"
81 " .cfi_def_cfa_offset 16\n"
82 " .cfi_offset 29, -16\n"
83 " .cfi_offset 30, -8\n"
84 " mov x29, sp\n"
85 " blr x0\n"
86 " ldp x29, x30, [sp], 16\n"
87 " .cfi_restore 30\n"
88 " .cfi_restore 29\n"
89 " .cfi_def_cfa_offset 0\n"
90 " hint 29 // autiasp\n"
91 " " SET_RA_STATE_0 "\n"
92 " ret\n"
93 " .cfi_endproc\n");
94
95 asm(""
96 ".global unusual_no_pac_ret\n"
97 ".type unusual_no_pac_ret, %function\n"
98 "unusual_no_pac_ret:\n"
99 " .cfi_startproc\n"
100 " " SET_RA_STATE_0 "\n"
101 " stp x29, x30, [sp, -16]!\n"
102 " .cfi_def_cfa_offset 16\n"
103 " .cfi_offset 29, -16\n"
104 " .cfi_offset 30, -8\n"
105 " mov x29, sp\n"
106 " blr x0\n"
107 " ldp x29, x30, [sp], 16\n"
108 " .cfi_restore 30\n"
109 " .cfi_restore 29\n"
110 " .cfi_def_cfa_offset 0\n"
111 " ret\n"
112 " .cfi_endproc\n");
113
114
115 /* Functions to create a call chain with mixed pac-ret dwarf. */
116
117 __attribute__((target("branch-protection=pac-ret")))
118 static void f2_pac_ret (void)
119 {
120 force_unwind ();
121 die ();
122 }
123
124 __attribute__((target("branch-protection=none")))
125 static void f1_no_pac_ret (void)
126 {
127 unusual_pac_ret (f2_pac_ret);
128 die ();
129 }
130
131 __attribute__((noinline, target("branch-protection=pac-ret")))
132 static void f0_pac_ret (void)
133 {
134 unusual_no_pac_ret (f1_no_pac_ret);
135 die ();
136 }
137
138 static void cleanup_handler (void *p)
139 {
140 printf ("%s: Success.\n", __func__);
141 exit (0);
142 }
143
144 int main ()
145 {
146 char dummy __attribute__((cleanup (cleanup_handler)));
147 f0_pac_ret ();
148 die ();
149 }