https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=aeea9ae363f0f73af5eb393fcc6fee2316c31f21
commit aeea9ae363f0f73af5eb393fcc6fee2316c31f21 Author: Radek Bartoň <radek.bar...@microsoft.com> AuthorDate: Wed Jun 4 14:55:34 2025 +0200 Commit: Corinna Vinschen <cori...@vinschen.de> CommitDate: Mon Jul 14 15:20:05 2025 +0200 Cygwin: signal: make context structures registers handling portable This patch extracts macros from winsup/cygwin/exceptions.cc serving for portable register access to context structures into a separate local header winsup/cygwin/local_includes/register.h and implements their AArch64 counterparts. Then, it adds AArch64 declaration of __mcontext structure based on mingw-w64-headers/include/winnt.h header to winsup/cygwin/include/cygwin/singal.h header. Then, it includes the registers.h header and uses the macros where applicable, namely at: - winsup/cygwin/exceptions.cc - winsup/cygwin/profil.c - winsup/cygwin/tread.cc The motivation is to make usage of the context structures portable without unnecessary #if defined(__x86_64__) while implementations of signal handling code will be developed later, e.g. implementation of makecontext. Signed-off-by: Radek Bartoň <radek.bar...@microsoft.com> Diff: --- winsup/cygwin/exceptions.cc | 51 ++++++++++++---------- winsup/cygwin/include/cygwin/signal.h | 77 ++++++++++++++++++++++++++++++++- winsup/cygwin/local_includes/register.h | 25 +++++++++++ winsup/cygwin/profil.c | 7 +-- winsup/cygwin/thread.cc | 3 +- winsup/utils/profiler.cc | 7 +-- 6 files changed, 135 insertions(+), 35 deletions(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index f79978f732e3..8308464312bc 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -28,25 +28,9 @@ details. */ #include "ntdll.h" #include "exception.h" #include "posix_timer.h" +#include "register.h" #include "gcc_seh.h" -/* Define macros for CPU-agnostic register access. The _CX_foo - macros are for access into CONTEXT, the _MC_foo ones for access into - mcontext. The idea is to access the registers in terms of their job, - not in terms of their name on the given target. */ -#ifdef __x86_64__ -#define _CX_instPtr Rip -#define _CX_stackPtr Rsp -#define _CX_framePtr Rbp -/* For special register access inside mcontext. */ -#define _MC_retReg rax -#define _MC_instPtr rip -#define _MC_stackPtr rsp -#define _MC_uclinkReg rbx /* MUST be callee-saved reg */ -#else -#error unimplemented for this target -#endif - #define CALL_HANDLER_RETRY_OUTER 10 #define CALL_HANDLER_RETRY_INNER 10 #define DUMPSTACK_FRAME_LIMIT 32 @@ -230,7 +214,7 @@ cygwin_exception::dump_exception () } } -#ifdef __x86_64__ +#if defined(__x86_64__) if (exception_name) small_printf ("Exception: %s at rip=%012X\r\n", exception_name, ctx->Rip); else @@ -250,6 +234,31 @@ cygwin_exception::dump_exception () small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n", ctx->SegCs, ctx->SegDs, ctx->SegEs, ctx->SegFs, ctx->SegGs, ctx->SegSs); +#elif defined(__aarch64__) + if (exception_name) + small_printf ("Exception: %s at pc=%012X\r\n", exception_name, ctx->Pc); + else + small_printf ("Signal %d at pc=%012X\r\n", e->ExceptionCode, ctx->Pc); + small_printf ("x0=%016X x1=%016X x2=%016X x3=%016X\r\n", + ctx->X0, ctx->X1, ctx->X2, ctx->X3); + small_printf ("x4=%016X x5=%016X x6=%016X x7=%016X\r\n", + ctx->X4, ctx->X5, ctx->X6, ctx->X7); + small_printf ("x8=%016X x9=%016X x10=%016X x11=%016X\r\n", + ctx->X8, ctx->X9, ctx->X10, ctx->X11); + small_printf ("x12=%016X x13=%016X x14=%016X x15=%016X\r\n", + ctx->X12, ctx->X13, ctx->X14, ctx->X15); + small_printf ("x16=%016X x17=%016X x18=%016X x19=%016X\r\n", + ctx->X16, ctx->X17, ctx->X18, ctx->X19); + small_printf ("x20=%016X x21=%016X x22=%016X x23=%016X\r\n", + ctx->X20, ctx->X21, ctx->X22, ctx->X23); + small_printf ("x24=%016X x25=%016X x26=%016X x27=%016X\r\n", + ctx->X24, ctx->X25, ctx->X26, ctx->X27); + small_printf ("x28=%016X fp=%016X lr=%016X sp=%016X\r\n", + ctx->X28, ctx->Fp, ctx->Lr, ctx->Sp); + small_printf ("program=%W, pid %u, thread %s\r\n", + myself->progname, myself->pid, mythreadname ()); + small_printf ("fpcr=%016X fpsr=%016X\r\n", + ctx->Fpcr, ctx->Fpsr); #else #error unimplemented for this target #endif @@ -1781,11 +1790,7 @@ _cygtls::call_signal_handler () __unwind_single_frame ((PCONTEXT) &context1.uc_mcontext); if (stackptr > stack) { -#ifdef __x86_64__ - context1.uc_mcontext.rip = retaddr (); -#else -#error unimplemented for this target -#endif + context1.uc_mcontext._MC_instPtr = retaddr (); } } diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h index de728bedecfa..4e9eafba79ca 100644 --- a/winsup/cygwin/include/cygwin/signal.h +++ b/winsup/cygwin/include/cygwin/signal.h @@ -19,7 +19,7 @@ extern "C" { Define a struct __mcontext, which should be identical in layout to the Win32 API type CONTEXT with the addition of oldmask and cr2 fields at the end. */ -#ifdef __x86_64__ +#if defined(__x86_64__) struct _uc_fpxreg { __uint16_t significand[4]; @@ -98,6 +98,81 @@ struct __attribute__ ((__aligned__ (16))) __mcontext __uint64_t cr2; }; +#elif defined(__aarch64__) + +/* Based on mingw-w64-headers/include/winnt.h. */ + +#define ARM64_MAX_BREAKPOINTS 8 +#define ARM64_MAX_WATCHPOINTS 2 + +union _neon128 +{ + struct + { + __uint64_t low; + __int64_t high; + }; + double d[2]; + float s[4]; + __uint16_t h[8]; + __uint8_t b[16]; +}; + +struct __attribute__ ((__aligned__ (16))) __mcontext +{ + __uint32_t ctxflags; + __uint32_t cpsr; + union + { + struct + { + __uint64_t x0; + __uint64_t x1; + __uint64_t x2; + __uint64_t x3; + __uint64_t x4; + __uint64_t x5; + __uint64_t x6; + __uint64_t x7; + __uint64_t x8; + __uint64_t x9; + __uint64_t x10; + __uint64_t x11; + __uint64_t x12; + __uint64_t x13; + __uint64_t x14; + __uint64_t x15; + __uint64_t x16; + __uint64_t x17; + __uint64_t x18; + __uint64_t x19; + __uint64_t x20; + __uint64_t x21; + __uint64_t x22; + __uint64_t x23; + __uint64_t x24; + __uint64_t x25; + __uint64_t x26; + __uint64_t x27; + __uint64_t x28; + __uint64_t fp; + __uint64_t lr; + }; + __uint64_t x[31]; + }; + __uint64_t sp; + __uint64_t pc; + union _neon128 v[32]; + __uint32_t fpcr; + __uint32_t fpsr; + __uint32_t bcr[ARM64_MAX_BREAKPOINTS]; + __uint64_t bvr[ARM64_MAX_BREAKPOINTS]; + __uint32_t wcr[ARM64_MAX_WATCHPOINTS]; + __uint64_t wvr[ARM64_MAX_WATCHPOINTS]; + __uint64_t oldmask; + __uint64_t cr2; +}; + #else #error unimplemented for this target #endif diff --git a/winsup/cygwin/local_includes/register.h b/winsup/cygwin/local_includes/register.h new file mode 100644 index 000000000000..1ddfe2ec0b7a --- /dev/null +++ b/winsup/cygwin/local_includes/register.h @@ -0,0 +1,25 @@ +/* Define macros for CPU-agnostic register access. The _CX_foo + macros are for access into CONTEXT, the _MC_foo ones for access into + mcontext. The idea is to access the registers in terms of their job, + not in terms of their name on the given target. */ +#if defined(__x86_64__) +#define _CX_instPtr Rip +#define _CX_stackPtr Rsp +#define _CX_framePtr Rbp +/* For special register access inside mcontext. */ +#define _MC_retReg rax +#define _MC_instPtr rip +#define _MC_stackPtr rsp +#define _MC_uclinkReg rbx /* MUST be callee-saved reg */ +#elif defined(__aarch64__) +#define _CX_instPtr Pc +#define _CX_stackPtr Sp +#define _CX_framePtr Fp +/* For special register access inside mcontext. */ +#define _MC_retReg x0 +#define _MC_instPtr pc +#define _MC_stackPtr sp +#define _MC_uclinkReg x19 /* MUST be callee-saved reg */ +#else +#error unimplemented for this target +#endif diff --git a/winsup/cygwin/profil.c b/winsup/cygwin/profil.c index 30b37244afcd..9578ab1dfe52 100644 --- a/winsup/cygwin/profil.c +++ b/winsup/cygwin/profil.c @@ -21,6 +21,7 @@ #include <errno.h> #include <pthread.h> #include "profil.h" +#include "register.h" #define SLEEPTIME (1000 / PROF_HZ) @@ -42,11 +43,7 @@ get_thrpc (HANDLE thr) ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; pc = (size_t) - 1; if (GetThreadContext (thr, &ctx)) { -#ifdef __x86_64__ - pc = ctx.Rip; -#else -#error unimplemented for this target -#endif + pc = ctx._CX_instPtr; } ResumeThread (thr); return pc; diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 510e2be933f1..b462e2f9f95d 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -32,6 +32,7 @@ details. */ #include "ntdll.h" #include "cygwait.h" #include "exception.h" +#include "register.h" /* For Linux compatibility, the length of a thread name is 16 characters. */ #define THRNAMELEN 16 @@ -629,7 +630,7 @@ pthread::cancel () threadlist_t *tl_entry = cygheap->find_tls (cygtls); if (!cygtls->inside_kernel (&context)) { - context.Rip = (ULONG_PTR) pthread::static_cancel_self; + context._CX_instPtr = (ULONG_PTR) pthread::static_cancel_self; SetThreadContext (win32_obj_id, &context); } cygheap->unlock_tls (tl_entry); diff --git a/winsup/utils/profiler.cc b/winsup/utils/profiler.cc index 4fe900b7fe67..04c6b3ed3ce5 100644 --- a/winsup/utils/profiler.cc +++ b/winsup/utils/profiler.cc @@ -33,6 +33,7 @@ typedef uint16_t u_int16_t; // Non-standard sized type needed by ancient gmon.h #define NO_GLOBALS_H #include "gmon.h" #include "path.h" +#include "register.h" /* Undo this #define from winsup.h. */ #ifdef ExitThread @@ -193,11 +194,7 @@ sample (CONTEXT *context, HANDLE h) return 0ULL; } else -#ifdef __x86_64__ - return context->Rip; -#else -#error unimplemented for this target -#endif + return context->_CX_instPtr; } void