3131#include "libunwind_ext.h"
3232#include "unwind.h"
3333
34- #if !defined(_LIBUNWIND_ARM_EHABI ) && !defined(__USING_SJLJ_EXCEPTIONS__ )
34+ #if !defined(_LIBUNWIND_ARM_EHABI ) && !defined(__USING_SJLJ_EXCEPTIONS__ ) && \
35+ !defined(__wasm__ )
3536
3637#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
3738
4344// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we
4445// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using
4546// a regular function call to avoid pushing to CET shadow stack again.
46- #if !defined(_LIBUNWIND_USE_CET )
47+ #if !defined(_LIBUNWIND_USE_CET ) && !defined( _LIBUNWIND_USE_GCS )
4748#define __unw_phase2_resume (cursor , fn ) \
4849 do { \
4950 (void)fn; \
7172 __asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext), \
7273 "d"(cetJumpAddress)); \
7374 } while (0)
75+ #elif defined(_LIBUNWIND_TARGET_AARCH64 )
76+ #define __cet_ss_step_size 8
77+ #define __unw_phase2_resume (cursor , fn ) \
78+ do { \
79+ _LIBUNWIND_POP_CET_SSP((fn)); \
80+ void *cetRegContext = __libunwind_cet_get_registers((cursor)); \
81+ void *cetJumpAddress = __libunwind_cet_get_jump_target(); \
82+ __asm__ volatile("mov x0, %0\n\t" \
83+ "br %1\n\t" \
84+ : \
85+ : "r"(cetRegContext), "r"(cetJumpAddress) \
86+ : "x0"); \
87+ } while (0)
7488#endif
7589
7690static _Unwind_Reason_Code
@@ -169,6 +183,10 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
169183}
170184extern int __unw_step_stage2 (unw_cursor_t * );
171185
186+ #if defined(_LIBUNWIND_USE_GCS )
187+ // Enable the GCS target feature to permit gcspop instructions to be used.
188+ __attribute__((target ("gcs" )))
189+ #endif
172190static _Unwind_Reason_Code
173191unwind_phase2 (unw_context_t * uc , unw_cursor_t * cursor , _Unwind_Exception * exception_object ) {
174192 __unw_init_local (cursor , uc );
@@ -179,8 +197,12 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
179197 // uc is initialized by __unw_getcontext in the parent frame. The first stack
180198 // frame walked is unwind_phase2.
181199 unsigned framesWalked = 1 ;
182- #ifdef _LIBUNWIND_USE_CET
200+ #if defined( _LIBUNWIND_USE_CET )
183201 unsigned long shadowStackTop = _get_ssp ();
202+ #elif defined(_LIBUNWIND_USE_GCS )
203+ unsigned long shadowStackTop = 0 ;
204+ if (__chkfeat (_CHKFEAT_GCS ))
205+ shadowStackTop = (unsigned long )__gcspr ();
184206#endif
185207 // Walk each frame until we reach where search phase said to stop.
186208 while (true) {
@@ -237,7 +259,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
237259// against return address stored in CET shadow stack, if the 2 addresses don't
238260// match, it means return address in normal stack has been corrupted, we return
239261// _URC_FATAL_PHASE2_ERROR.
240- #ifdef _LIBUNWIND_USE_CET
262+ #if defined( _LIBUNWIND_USE_CET ) || defined( _LIBUNWIND_USE_GCS )
241263 if (shadowStackTop != 0 ) {
242264 unw_word_t retInNormalStack ;
243265 __unw_get_reg (cursor , UNW_REG_IP , & retInNormalStack );
@@ -305,6 +327,10 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
305327 return _URC_FATAL_PHASE2_ERROR ;
306328}
307329
330+ #if defined(_LIBUNWIND_USE_GCS )
331+ // Enable the GCS target feature to permit gcspop instructions to be used.
332+ __attribute__((target ("gcs" )))
333+ #endif
308334static _Unwind_Reason_Code
309335unwind_phase2_forced (unw_context_t * uc , unw_cursor_t * cursor ,
310336 _Unwind_Exception * exception_object ,
0 commit comments