[newlib-cygwin/main] Cygwin: signal: make context structures registers handling portable
Corinna Vinschen
corinna@sourceware.org
Mon Jul 14 13:21:43 GMT 2025
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=aeea9ae363f0f73af5eb393fcc6fee2316c31f21
commit aeea9ae363f0f73af5eb393fcc6fee2316c31f21
Author: Radek Bartoň <radek.barton@microsoft.com>
AuthorDate: Wed Jun 4 14:55:34 2025 +0200
Commit: Corinna Vinschen <corinna@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.barton@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
More information about the Cygwin-cvs
mailing list