blob: 836aadc4c860d312474bef4a2366ab5033353d4e [file] [log] [blame]
Yongqin Liu9fea4092014-10-31 16:37:09 +08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <setjmp.h>
20#include <stdlib.h>
Tamas Zsoldos436f3f12025-04-28 10:07:30 -070021#include <sys/auxv.h>
Elliott Hughesc0d41db2021-04-02 18:02:38 -070022#include <sys/syscall.h>
23#include <unistd.h>
Yongqin Liu9fea4092014-10-31 16:37:09 +080024
Elliott Hughes141b9172021-04-09 17:13:09 -070025#include <android-base/silent_death_test.h>
Florian Mayer4817ca62022-04-15 22:53:51 +000026#include <android-base/test_utils.h>
Elliott Hughes141b9172021-04-09 17:13:09 -070027
Elliott Hughes71ba5892018-02-07 12:44:45 -080028#include "SignalUtils.h"
Elliott Hughes460130b2018-01-31 09:05:26 -080029
Elliott Hughes141b9172021-04-09 17:13:09 -070030using setjmp_DeathTest = SilentDeathTest;
Elliott Hughese657eb42021-02-18 17:11:56 -080031
Yongqin Liu9fea4092014-10-31 16:37:09 +080032TEST(setjmp, setjmp_smoke) {
33 int value;
34 jmp_buf jb;
35 if ((value = setjmp(jb)) == 0) {
36 longjmp(jb, 123);
37 FAIL(); // Unreachable.
38 } else {
39 ASSERT_EQ(123, value);
40 }
41}
42
43TEST(setjmp, _setjmp_smoke) {
44 int value;
45 jmp_buf jb;
46 if ((value = _setjmp(jb)) == 0) {
47 _longjmp(jb, 456);
48 FAIL(); // Unreachable.
49 } else {
50 ASSERT_EQ(456, value);
51 }
52}
53
54TEST(setjmp, sigsetjmp_0_smoke) {
55 int value;
56 sigjmp_buf jb;
57 if ((value = sigsetjmp(jb, 0)) == 0) {
58 siglongjmp(jb, 789);
59 FAIL(); // Unreachable.
60 } else {
61 ASSERT_EQ(789, value);
62 }
63}
64
65TEST(setjmp, sigsetjmp_1_smoke) {
66 int value;
67 sigjmp_buf jb;
68 if ((value = sigsetjmp(jb, 0)) == 0) {
69 siglongjmp(jb, 0xabc);
70 FAIL(); // Unreachable.
71 } else {
72 ASSERT_EQ(0xabc, value);
73 }
74}
75
Elliott Hughes460130b2018-01-31 09:05:26 -080076// Two distinct signal sets.
Elliott Hughes1510a1c2014-12-10 09:31:04 -080077struct SigSets {
78 SigSets() : one(MakeSigSet(0)), two(MakeSigSet(1)) {
Elliott Hughes1c0c0ed2014-12-05 22:24:49 -080079 }
Elliott Hughes1510a1c2014-12-10 09:31:04 -080080
Elliott Hughes460130b2018-01-31 09:05:26 -080081 static sigset64_t MakeSigSet(int offset) {
82 sigset64_t ss;
83 sigemptyset64(&ss);
84 sigaddset64(&ss, SIGUSR1 + offset);
Colin Cross23b986c2022-10-19 15:03:59 -070085#if defined(__BIONIC__)
Josh Gaobaf20fc2018-10-08 17:28:07 -070086 // TIMER_SIGNAL.
87 sigaddset64(&ss, __SIGRTMIN);
Colin Cross23b986c2022-10-19 15:03:59 -070088#endif
Elliott Hughes460130b2018-01-31 09:05:26 -080089 sigaddset64(&ss, SIGRTMIN + offset);
Elliott Hughes1510a1c2014-12-10 09:31:04 -080090 return ss;
91 }
92
Elliott Hughes460130b2018-01-31 09:05:26 -080093 sigset64_t one;
94 sigset64_t two;
Elliott Hughes1510a1c2014-12-10 09:31:04 -080095};
Yongqin Liu9fea4092014-10-31 16:37:09 +080096
Elliott Hughes460130b2018-01-31 09:05:26 -080097void AssertSigmaskEquals(const sigset64_t& expected) {
98 sigset64_t actual;
Yi Kong32bc0fc2018-08-02 17:31:13 -070099 sigprocmask64(SIG_SETMASK, nullptr, &actual);
Elliott Hughes460130b2018-01-31 09:05:26 -0800100 size_t end = sizeof(expected) * 8;
Elliott Hughes1c0c0ed2014-12-05 22:24:49 -0800101 for (size_t i = 1; i <= end; ++i) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800102 EXPECT_EQ(sigismember64(&expected, i), sigismember64(&actual, i)) << i;
Elliott Hughes1c0c0ed2014-12-05 22:24:49 -0800103 }
104}
105
Yongqin Liu9fea4092014-10-31 16:37:09 +0800106TEST(setjmp, _setjmp_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800107 SignalMaskRestorer smr;
108
Yongqin Liu9fea4092014-10-31 16:37:09 +0800109 // _setjmp/_longjmp do not save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800110 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800111 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800112 jmp_buf jb;
113 if (_setjmp(jb) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700114 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800115 _longjmp(jb, 1);
116 FAIL(); // Unreachable.
117 } else {
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800118 AssertSigmaskEquals(ss.two);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800119 }
120}
121
122TEST(setjmp, setjmp_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800123 SignalMaskRestorer smr;
124
Yongqin Liu9fea4092014-10-31 16:37:09 +0800125 // setjmp/longjmp do save/restore the signal mask on bionic, but not on glibc.
126 // This is a BSD versus System V historical accident. POSIX leaves the
127 // behavior unspecified, so any code that cares needs to use sigsetjmp.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800128 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800129 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800130 jmp_buf jb;
131 if (setjmp(jb) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700132 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800133 longjmp(jb, 1);
134 FAIL(); // Unreachable.
135 } else {
Yongqin Liu9fea4092014-10-31 16:37:09 +0800136#if defined(__BIONIC__)
137 // bionic behaves like BSD and does save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800138 AssertSigmaskEquals(ss.one);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800139#else
140 // glibc behaves like System V and doesn't save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800141 AssertSigmaskEquals(ss.two);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800142#endif
143 }
144}
145
146TEST(setjmp, sigsetjmp_0_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800147 SignalMaskRestorer smr;
148
Yongqin Liu9fea4092014-10-31 16:37:09 +0800149 // sigsetjmp(0)/siglongjmp do not save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800150 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800151 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800152 sigjmp_buf sjb;
153 if (sigsetjmp(sjb, 0) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700154 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800155 siglongjmp(sjb, 1);
156 FAIL(); // Unreachable.
157 } else {
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800158 AssertSigmaskEquals(ss.two);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800159 }
160}
161
162TEST(setjmp, sigsetjmp_1_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800163 SignalMaskRestorer smr;
164
Yongqin Liu9fea4092014-10-31 16:37:09 +0800165 // sigsetjmp(1)/siglongjmp does save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800166 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800167 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800168 sigjmp_buf sjb;
169 if (sigsetjmp(sjb, 1) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700170 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800171 siglongjmp(sjb, 1);
172 FAIL(); // Unreachable.
173 } else {
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800174 AssertSigmaskEquals(ss.one);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800175 }
Yongqin Liu9fea4092014-10-31 16:37:09 +0800176}
Elliott Hughes87dd5032015-01-26 20:52:34 -0800177
Elliott Hughes86968d92024-05-21 21:25:50 +0000178#if defined(__arm__) || defined(__aarch64__)
179// arm and arm64 have the same callee save fp registers (8-15),
180// but use different instructions for accessing them.
Yi Kong11f696a2024-05-15 02:30:44 +0900181#if defined(__arm__)
182#define SET_FREG(n, v) asm volatile("vmov.f64 d"#n ", #"#v : : : "d"#n)
183#define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;})
184#define CLEAR_FREG(n) asm volatile("vmov.i64 d"#n ", #0x0" : : : "d"#n)
185#elif defined(__aarch64__)
Elliott Hughes87dd5032015-01-26 20:52:34 -0800186#define SET_FREG(n, v) asm volatile("fmov d"#n ", "#v : : : "d"#n)
Yi Kong11f696a2024-05-15 02:30:44 +0900187#define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; })
Elliott Hughes87dd5032015-01-26 20:52:34 -0800188#define CLEAR_FREG(n) asm volatile("fmov d"#n ", xzr" : : : "d"#n)
Yi Kong11f696a2024-05-15 02:30:44 +0900189#endif
Elliott Hughes87dd5032015-01-26 20:52:34 -0800190#define SET_FREGS \
191 SET_FREG(8, 8.0); SET_FREG(9, 9.0); SET_FREG(10, 10.0); SET_FREG(11, 11.0); \
Elliott Hughes86968d92024-05-21 21:25:50 +0000192 SET_FREG(12, 12.0); SET_FREG(13, 13.0); SET_FREG(14, 14.0); SET_FREG(15, 15.0)
Elliott Hughes87dd5032015-01-26 20:52:34 -0800193#define CLEAR_FREGS \
194 CLEAR_FREG(8); CLEAR_FREG(9); CLEAR_FREG(10); CLEAR_FREG(11); \
Elliott Hughes86968d92024-05-21 21:25:50 +0000195 CLEAR_FREG(12); CLEAR_FREG(13); CLEAR_FREG(14); CLEAR_FREG(15)
Elliott Hughes87dd5032015-01-26 20:52:34 -0800196#define CHECK_FREGS \
Elliott Hughes86968d92024-05-21 21:25:50 +0000197 EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
198 EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \
199 EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \
200 EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15))
201
202#elif defined(__riscv)
203// riscv64 has callee save registers fs0-fs11.
204// TODO: use Zfa to get 1.0 rather than the one_p trick.
205#define SET_FREGS \
206 double one = 1, *one_p = &one; \
207 asm volatile("fmv.d.x fs0, zero ; fld fs1, (%0) ; \
208 fadd.d fs2, fs1, fs1 ; fadd.d fs3, fs2, fs1 ; \
209 fadd.d fs4, fs3, fs1 ; fadd.d fs5, fs4, fs1 ; \
210 fadd.d fs6, fs5, fs1 ; fadd.d fs7, fs6, fs1 ; \
211 fadd.d fs8, fs7, fs1 ; fadd.d fs9, fs8, fs1 ; \
212 fadd.d fs10, fs9, fs1 ; fadd.d fs11, fs10, fs1" \
213 : \
214 : "r"(one_p) \
215 : "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", \
216 "fs6", "fs7", "fs8", "fs9", "fs10", "fs11")
217#define CLEAR_FREGS \
218 asm volatile("fmv.d.x fs0, zero ; fmv.d.x fs1, zero ; \
219 fmv.d.x fs2, zero ; fmv.d.x fs3, zero ; \
220 fmv.d.x fs4, zero ; fmv.d.x fs5, zero ; \
221 fmv.d.x fs6, zero ; fmv.d.x fs7, zero ; \
222 fmv.d.x fs8, zero ; fmv.d.x fs9, zero ; \
223 fmv.d.x fs10, zero ; fmv.d.x fs11, zero" \
224 : : : "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", \
225 "fs6", "fs7", "fs8", "fs9", "fs10", "fs11")
226#define GET_FREG(n) ({ double _r; asm volatile("fmv.d %0, fs"#n : "=f"(_r) : :); _r; })
227#define CHECK_FREGS \
228 EXPECT_EQ(0.0, GET_FREG(0)); EXPECT_EQ(1.0, GET_FREG(1)); \
229 EXPECT_EQ(2.0, GET_FREG(2)); EXPECT_EQ(3.0, GET_FREG(3)); \
230 EXPECT_EQ(4.0, GET_FREG(4)); EXPECT_EQ(5.0, GET_FREG(5)); \
231 EXPECT_EQ(6.0, GET_FREG(6)); EXPECT_EQ(7.0, GET_FREG(7)); \
232 EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
233 EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11))
234
Elliott Hughes87dd5032015-01-26 20:52:34 -0800235#else
Elliott Hughes86968d92024-05-21 21:25:50 +0000236// x86 and x86-64 don't save/restore fp registers.
Elliott Hughes87dd5032015-01-26 20:52:34 -0800237#define SET_FREGS
238#define CLEAR_FREGS
239#define CHECK_FREGS
240#endif
241
242TEST(setjmp, setjmp_fp_registers) {
243 int value;
244 jmp_buf jb;
245 SET_FREGS;
246 if ((value = setjmp(jb)) == 0) {
247 CLEAR_FREGS;
248 longjmp(jb, 123);
249 FAIL(); // Unreachable.
250 } else {
251 ASSERT_EQ(123, value);
252 CHECK_FREGS;
253 }
254}
Josh Gao7fda8d22015-09-10 15:40:24 -0700255
256#if defined(__arm__)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000257#define JB_SIGFLAG_OFFSET 0
Josh Gao7fda8d22015-09-10 15:40:24 -0700258#elif defined(__aarch64__)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000259#define JB_SIGFLAG_OFFSET 0
Josh Gao7fda8d22015-09-10 15:40:24 -0700260#elif defined(__i386__)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000261#define JB_SIGFLAG_OFFSET 8
262#elif defined(__riscv)
263#define JB_SIGFLAG_OFFSET 0
Josh Gao7fda8d22015-09-10 15:40:24 -0700264#elif defined(__x86_64)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000265#define JB_SIGFLAG_OFFSET 8
Josh Gao7fda8d22015-09-10 15:40:24 -0700266#endif
267
Elliott Hughese657eb42021-02-18 17:11:56 -0800268TEST_F(setjmp_DeathTest, setjmp_cookie) {
Josh Gao7fda8d22015-09-10 15:40:24 -0700269 jmp_buf jb;
270 int value = setjmp(jb);
271 ASSERT_EQ(0, value);
272
Elliott Hughese1905ed2022-10-17 23:23:36 +0000273 long* sigflag = reinterpret_cast<long*>(jb) + JB_SIGFLAG_OFFSET;
Josh Gao7fda8d22015-09-10 15:40:24 -0700274
275 // Make sure there's actually a cookie.
276 EXPECT_NE(0, *sigflag & ~1);
277
278 // Wipe it out
279 *sigflag &= 1;
280 EXPECT_DEATH(longjmp(jb, 0), "");
Josh Gao7fda8d22015-09-10 15:40:24 -0700281}
Josh Gaoa4c69132016-03-02 19:03:17 -0800282
Elliott Hughese657eb42021-02-18 17:11:56 -0800283TEST_F(setjmp_DeathTest, setjmp_cookie_checksum) {
Josh Gaoa4c69132016-03-02 19:03:17 -0800284 jmp_buf jb;
285 int value = setjmp(jb);
286
287 if (value == 0) {
288 // Flip a bit.
Predrag Blagojevic32995902016-03-16 15:49:12 +0100289 reinterpret_cast<long*>(jb)[1] ^= 1;
Josh Gaoa4c69132016-03-02 19:03:17 -0800290
291 EXPECT_DEATH(longjmp(jb, 1), "checksum mismatch");
292 } else {
293 fprintf(stderr, "setjmp_cookie_checksum: longjmp succeeded?");
294 }
295}
Peter Collingbourne734beec2018-11-14 12:41:41 -0800296
297__attribute__((noinline)) void call_longjmp(jmp_buf buf) {
298 longjmp(buf, 123);
299}
300
301TEST(setjmp, setjmp_stack) {
302 jmp_buf buf;
303 int value = setjmp(buf);
304 if (value == 0) call_longjmp(buf);
305 EXPECT_EQ(123, value);
306}
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700307
308TEST(setjmp, bug_152210274) {
309 // Ensure that we never have a mangled value in the stack pointer.
310#if defined(__BIONIC__)
311 struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = [](int, siginfo_t*, void*) {}};
312 ASSERT_EQ(0, sigaction(SIGPROF, &sa, 0));
313
314 constexpr size_t kNumThreads = 20;
315
316 // Start a bunch of threads calling setjmp/longjmp.
317 auto jumper = [](void* arg) -> void* {
318 sigset_t set;
319 sigemptyset(&set);
320 sigaddset(&set, SIGPROF);
321 pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
322
323 jmp_buf buf;
324 for (size_t count = 0; count < 100000; ++count) {
325 if (setjmp(buf) != 0) {
326 perror("setjmp");
327 abort();
328 }
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700329 // This will never be true, but the compiler doesn't know that, so the
330 // setjmp won't be removed by DCE. With HWASan/MTE this also acts as a
331 // kind of enforcement that the threads are done before leaving the test.
332 if (*static_cast<size_t*>(arg) != 123) longjmp(buf, 1);
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700333 }
334 return nullptr;
335 };
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700336 pthread_t threads[kNumThreads];
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700337 pid_t tids[kNumThreads] = {};
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700338 size_t var = 123;
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700339 for (size_t i = 0; i < kNumThreads; ++i) {
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700340 ASSERT_EQ(0, pthread_create(&threads[i], nullptr, jumper, &var));
341 tids[i] = pthread_gettid_np(threads[i]);
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700342 }
343
344 // Start the interrupter thread.
345 auto interrupter = [](void* arg) -> void* {
346 pid_t* tids = static_cast<pid_t*>(arg);
347 for (size_t count = 0; count < 1000; ++count) {
348 for (size_t i = 0; i < kNumThreads; i++) {
349 if (tgkill(getpid(), tids[i], SIGPROF) == -1 && errno != ESRCH) {
350 perror("tgkill failed");
351 abort();
352 }
353 }
354 usleep(100);
355 }
356 return nullptr;
357 };
358 pthread_t t;
359 ASSERT_EQ(0, pthread_create(&t, nullptr, interrupter, tids));
360 pthread_join(t, nullptr);
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700361 for (size_t i = 0; i < kNumThreads; i++) {
362 pthread_join(threads[i], nullptr);
363 }
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700364#else
Elliott Hughes14ab3532021-04-08 20:59:50 -0700365 GTEST_SKIP() << "tests uses functions not in glibc";
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700366#endif
367}
Tamas Zsoldos436f3f12025-04-28 10:07:30 -0700368
369#if defined(__aarch64__)
370TEST(setjmp, sigsetjmp_sme) {
371 if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
372 GTEST_SKIP() << "SME is not enabled on device.";
373 }
374
375 uint64_t svcr, za_state;
376 sigjmp_buf jb;
377 __asm__ __volatile__(".arch_extension sme; smstart za");
378 sigsetjmp(jb, 0);
379 __asm__ __volatile__(".arch_extension sme; mrs %0, SVCR" : "=r"(svcr));
380 __asm__ __volatile__(".arch_extension sme; smstop za"); // Turn ZA off anyway.
381 za_state = svcr & 0x2UL;
382 ASSERT_EQ(0UL, za_state);
383}
384
385TEST(setjmp, siglongjmp_sme) {
386 if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
387 GTEST_SKIP() << "SME is not enabled on device.";
388 }
389
390 uint64_t svcr, za_state;
391 int value;
392 sigjmp_buf jb;
393 if ((value = sigsetjmp(jb, 0)) == 0) {
394 __asm__ __volatile__(".arch_extension sme; smstart za");
395 siglongjmp(jb, 789);
396 __asm__ __volatile__(".arch_extension sme; smstop za");
397 FAIL(); // Unreachable.
398 } else {
399 __asm__ __volatile__(".arch_extension sme; mrs %0, SVCR" : "=r"(svcr));
400 __asm__ __volatile__(".arch_extension sme; smstop za"); // Turn ZA off anyway.
401 za_state = svcr & 0x2UL;
402 ASSERT_EQ(789, value);
403 ASSERT_EQ(0UL, za_state);
404 }
405}
406#endif