https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=93bea9f5387921ec40f35c0c45ff240a433db603

commit 93bea9f5387921ec40f35c0c45ff240a433db603
Author: Corinna Vinschen <[email protected]>
Date:   Tue May 17 14:12:32 2022 +0200

    Cygwin: drop i686 exception handling
    
    Leave x86_64 CPU-specific code and #error out when trying to build
    for another target. Access special registers CPU-agnostic.
    
    Signed-off-by: Corinna Vinschen <[email protected]>

Diff:
---
 winsup/cygwin/cygtls.h      |  72 +--------
 winsup/cygwin/exception.h   | 121 ---------------
 winsup/cygwin/exceptions.cc | 363 +++++++++-----------------------------------
 3 files changed, 72 insertions(+), 484 deletions(-)

diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h
index c4702e88a..bfd358268 100644
--- a/winsup/cygwin/cygtls.h
+++ b/winsup/cygwin/cygtls.h
@@ -276,7 +276,6 @@ private:
 extern _cygtls *_main_tls;
 extern _cygtls *_sig_tls;
 
-#ifdef __x86_64__
 class san
 {
   san *_clemente;
@@ -305,53 +304,9 @@ public:
      earlier in the function, so this call serves as a register barrier. */
   void leave () __attribute__ ((returns_twice));
 };
-#else
-class san
-{
-  san *_clemente;
-  jmp_buf _context;
-  uint32_t _c_cnt;
-  uint32_t _w_cnt;
-public:
-  int setup () __attribute__ ((always_inline))
-  {
-    _clemente = _my_tls.andreas;
-    _my_tls.andreas = this;
-    _c_cnt = _my_tls.locals.pathbufs.c_cnt;
-    _w_cnt = _my_tls.locals.pathbufs.w_cnt;
-    return __sjfault (_context);
-  }
-  void leave () __attribute__ ((always_inline))
-  {
-    /* Restore tls_pathbuf counters in case of error. */
-    _my_tls.locals.pathbufs.c_cnt = _c_cnt;
-    _my_tls.locals.pathbufs.w_cnt = _w_cnt;
-    __ljfault (_context, 1);
-  }
-  void reset () __attribute__ ((always_inline))
-  {
-    _my_tls.andreas = _clemente;
-  }
-};
 
-class myfault
-{
-  san sebastian;
-public:
-  ~myfault () __attribute__ ((always_inline)) { sebastian.reset (); }
-  inline int faulted () __attribute__ ((always_inline))
-  {
-    return sebastian.setup ();
-  }
-};
-#endif
-
-/* Exception handling macros.  These are required because SEH differs a lot
-   between 32 and 64 bit.  Essentially, on 64 bit, we have to create compile
-   time SEH tables which define the handler and try/except labels, while on
-   32 bit we can simply set up an SJLJ handler within the myfault class. */
+/* Exception handling macros. This is a handmade SEH try/except. */
 #define __mem_barrier  __asm__ __volatile__ ("" ::: "memory")
-#ifdef __x86_64__
 #define __try \
   { \
     __label__ __l_try, __l_except, __l_endtry; \
@@ -387,31 +342,6 @@ public:
       __mem_barrier; \
   }
 
-#else /* !__x86_64__ */
-#define __try \
-  { \
-    __label__ __l_endtry; \
-    myfault efault; \
-    if (!efault.faulted ()) \
-      {
-
-#define __leave        \
-       goto __l_endtry
-
-#define __except(__errno) \
-         goto __l_endtry; \
-      } \
-      { \
-       if (__errno) \
-         set_errno (__errno);
-
-#define __endtry \
-      } \
-    __l_endtry: \
-      __mem_barrier; \
-  }
-#endif /* __x86_64__ */
-
 class wait_signal_arrived
 {
 public:
diff --git a/winsup/cygwin/exception.h b/winsup/cygwin/exception.h
index ffff7464b..13159d17b 100644
--- a/winsup/cygwin/exception.h
+++ b/winsup/cygwin/exception.h
@@ -6,125 +6,6 @@ details. */
 
 #pragma once
 
-#ifdef __i386__
-/* Documentation on the innards of 32 bit Windows exception handling (i.e.
-   from the perspective of a compiler implementor) apparently doesn't exist.
-   However, the following came from Onno Hovers <[email protected]>
-
-The first pointer to the chain of handlers is in the thread environment block
-at FS:[0].  This chain has the following format:
-
-typedef struct __EXCEPTION_FRAME
-{
-   struct __EXCEPTION_FRAME    *Prev;    /-* pointer to the previous frame *-/
-   PEXCEPTION_HANDLER          Handler; /-* handler function *-/
-}
-
-You register an exception handler in your compiler with this simple ASM
-sequence:
-   PUSH _MyExceptionHandler
-   PUSH FS:[0]
-   MOV  FS:[0],ESP
-An exception frame MUST be on the stack! The frame may have more fields and
-both Visual C++ and Borland C++ use more fields for themselves.
-
-When an exception occurs the system calls all handlers starting with the
-handler at FS:0, and then the previous etc. until one handler returns
-ExceptionContinueExecution, which is 0. If a handler does not want to handle
-the exception it should just return ExceptionContinueSearch, which is 1.
-
-The handler has the following parameters:
-ehandler (
-          PEXCEPTION_RECORD erecord,
-          PEXCEPTION_FRAME myframe,
-          PCONTEXT context,            /-* context before and after *-/
-          PVOID dispatch)              /-* something *-/
-
-When a handler wants to handle the exception, it has some alternatives:
-
--one is to do do something about the exception condition, like emulating
-an invalid instruction, mapping memory where there was a page fault, etc.
-If the handler wants to have the context of the thread that causes the
-exception changed, it should make that change in the context passed to the
-handler.
-
--the second alternative is to call all exception handlers again, indicating
-that you want them to clean up. This way all the __finally blocks get
-executed. After doing that you change the context passed to the handler so
-the code starts executing in the except block. For this purpose you could
-call RtlUnwind. This (undocumented) function calls all exception handlers
-up to but not including the exception frame passed to it. If NULL is passed
-as exception frame RtlUnwind calls all exception handlers and then exits the
-process. The parameters to RtlUnwind are:
-
-RtlUnwind (
-   PEXCEPTION_FRAME    endframe,
-   PVOID               unusedEip,
-   PEXCEPTION_RECORD   erecord,
-   DWORD               returnEax)
-
-You should set unusedEip to the address where RtlUnwind should return like
-this:
-         PUSH 0
-         PUSH OFFSET ReturnUnwind
-         PUSH 0
-         PUSH 0
-         CALL RtlUnwind
-ReturnUnwind:
-         .....
-
-If no EXCEPTION_RECORD is passed, RtlUnwind makes a default exception
-record. In any case, the ExceptionFlags part of this record has the
-EH_UNWINDING (=2),  flag set. (and EH_EXIT_UNWIND (=4), when NULL is passed as 
the end
-frame.).
-
-The handler for a exception as well as a for unwinds may be executed in the
-thread causing the exception, but may also be executed in another (special
-exception) thread. So it is not wise to make any assumptions about that!
-
-As an alternative you may consider the SetUnhandledExceptionFilter API
-to install your own exception filter. This one is documented.
-*/
-
-/* The January 1994 MSJ has an article entitled "Clearer, More Comprehensive
-   Error Processing with Win32 Structured Exception Handling".  It goes into
-   a teensy bit of detail of the innards of exception handling (i.e. what we
-   have to do).  */
-
-typedef EXCEPTION_DISPOSITION (exception_handler) (EXCEPTION_RECORD *,
-                                                  struct _exception_list *,
-                                                  CONTEXT *,
-                                                  void *);
-
-typedef struct _exception_list
-{
-  struct _exception_list *prev;
-  exception_handler *handler;
-} exception_list;
-
-extern exception_list *_except_list asm ("%fs:0");
-typedef void *PDISPATCHER_CONTEXT;
-
-class exception
-{
-  exception_list el;
-  exception_list *save;
-  static EXCEPTION_DISPOSITION handle (EXCEPTION_RECORD *, exception_list *,
-                                      CONTEXT *, PDISPATCHER_CONTEXT);
-public:
-  exception () __attribute__ ((always_inline))
-  {
-    /* Install SEH handler. */
-    save = _except_list;
-    el.handler = handle;
-    el.prev = _except_list;
-    _except_list = &el;
-  };
-  ~exception () __attribute__ ((always_inline)) { _except_list = save; }
-};
-
-#else /* !__i386__ */
-
 #define exception_list void
 typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT;
 
@@ -159,8 +40,6 @@ public:
 
 LONG CALLBACK myfault_altstack_handler (EXCEPTION_POINTERS *);
 
-#endif /* __i386__ */
-
 class cygwin_exception
 {
   PUINT_PTR framep;
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index f6c390241..2fecd52ec 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -30,15 +30,21 @@ details. */
 #include "posix_timer.h"
 #include "gcc_seh.h"
 
-/* Definitions for code simplification */
+/* 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 _GR(reg)      R ## reg
-# define _AFMT         "%011X"
-# define _ADDR         DWORD64
+#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
-# define _GR(reg)      E ## reg
-# define _AFMT         "%08x"
-# define _ADDR         DWORD
+#error unimplemented for this target
 #endif
 
 #define CALL_HANDLER_RETRY_OUTER 10
@@ -204,20 +210,12 @@ cygwin_exception::dump_exception ()
   small_printf ("rbp=%016X rsp=%016X\r\n", ctx->Rbp, ctx->Rsp);
   small_printf ("program=%W, pid %u, thread %s\r\n",
                myself->progname, myself->pid, mythreadname ());
-#else
-  if (exception_name)
-    small_printf ("Exception: %s at eip=%08x\r\n", exception_name, ctx->Eip);
-  else
-    small_printf ("Signal %d at eip=%08x\r\n", e->ExceptionCode, ctx->Eip);
-  small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n",
-               ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx, ctx->Esi, ctx->Edi);
-  small_printf ("ebp=%08x esp=%08x program=%W, pid %u, thread %s\r\n",
-               ctx->Ebp, ctx->Esp, myself->progname, myself->pid,
-               mythreadname ());
-#endif
   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);
+#else
+#error unimplemented for this target
+#endif
 }
 
 /* A class for manipulating the stack. */
@@ -227,11 +225,9 @@ class stack_info
   char *next_offset () {return *((char **) sf.AddrFrame.Offset);}
   bool needargs;
   PUINT_PTR dummy_frame;
-#ifdef __x86_64__
   CONTEXT c;
   UNWIND_HISTORY_TABLE hist;
   __tlsstack_t *sigstackptr;
-#endif
 public:
   STACKFRAME sf;                /* For storing the stack information */
   void init (PUINT_PTR, bool, PCONTEXT); /* Called the first time that stack 
info is needed */
@@ -250,7 +246,6 @@ static NO_COPY stack_info thestack;
 void
 stack_info::init (PUINT_PTR framep, bool wantargs, PCONTEXT ctx)
 {
-#ifdef __x86_64__
   memset (&hist, 0, sizeof hist);
   if (ctx)
     memcpy (&c, ctx, sizeof c);
@@ -260,7 +255,6 @@ stack_info::init (PUINT_PTR framep, bool wantargs, PCONTEXT 
ctx)
       c.ContextFlags = CONTEXT_ALL;
     }
   sigstackptr = _my_tls.stackptr;
-#endif
   memset (&sf, 0, sizeof (sf));
   if (ctx)
     sf.AddrFrame.Offset = (UINT_PTR) framep;
@@ -277,7 +271,6 @@ stack_info::init (PUINT_PTR framep, bool wantargs, PCONTEXT 
ctx)
 
 extern "C" void _cygwin_exit_return ();
 
-#ifdef __x86_64__
 static inline void
 __unwind_single_frame (PCONTEXT ctx)
 {
@@ -287,19 +280,16 @@ __unwind_single_frame (PCONTEXT ctx)
   DWORD64 establisher;
   PVOID hdl;
 
-  f = RtlLookupFunctionEntry (ctx->Rip, &imagebase, &hist);
+  f = RtlLookupFunctionEntry (ctx->_CX_instPtr, &imagebase, &hist);
   if (f)
-    RtlVirtualUnwind (0, imagebase, ctx->Rip, f, ctx, &hdl, &establisher,
-                     NULL);
+    RtlVirtualUnwind (0, imagebase, ctx->_CX_instPtr, f, ctx, &hdl,
+                     &establisher, NULL);
   else
     {
-      ctx->Rip = *(ULONG_PTR *) ctx->Rsp;
-      ctx->Rsp += 8;
+      ctx->_CX_instPtr = *(ULONG_PTR *) ctx->_CX_stackPtr;
+      ctx->_CX_stackPtr += 8;
     }
 }
-#else
-#define __unwind_single_frame(ctx)
-#endif
 
 /* Walk the stack.
 
@@ -308,57 +298,30 @@ __unwind_single_frame (PCONTEXT ctx)
 int
 stack_info::walk ()
 {
-#ifdef __x86_64__
-  if (!c.Rip)
+  if (!c._CX_instPtr)
     return 0;
 
-  sf.AddrPC.Offset = c.Rip;
-  sf.AddrStack.Offset = c.Rsp;
-  sf.AddrFrame.Offset = c.Rbp;
+  sf.AddrPC.Offset = c._CX_instPtr;
+  sf.AddrStack.Offset = c._CX_stackPtr;
+  sf.AddrFrame.Offset = c._CX_framePtr;
 
-  if ((c.Rip >= (DWORD64)&_sigbe) && (c.Rip < (DWORD64)&_sigdelayed_end))
+  if ((c._CX_instPtr >= (DWORD64)&_sigbe)
+      && (c._CX_instPtr < (DWORD64)&_sigdelayed_end))
     {
       /* _sigbe and sigdelayed don't have SEH unwinding data, so virtually
          unwind the tls sigstack */
-      c.Rip = sigstackptr[-1];
+      c._CX_instPtr = sigstackptr[-1];
       sigstackptr--;
       return 1;
     }
   __unwind_single_frame (&c);
-  if (needargs && c.Rip)
+  if (needargs && c._CX_instPtr)
     {
-      PULONG_PTR p = (PULONG_PTR) c.Rsp;
+      PULONG_PTR p = (PULONG_PTR) c._CX_stackPtr;
       for (unsigned i = 0; i < NPARAMS; ++i)
        sf.Params[i] = p[i + 1];
     }
   return 1;
-#else
-  char **framep;
-
-  if ((void (*) ()) sf.AddrPC.Offset == _cygwin_exit_return)
-    return 0;          /* stack frames are exhausted */
-
-  if (((framep = (char **) next_offset ()) == NULL)
-      || (framep >= (char **) cygwin_hmodule))
-    return 0;
-
-  sf.AddrFrame.Offset = (_ADDR) framep;
-  sf.AddrPC.Offset = sf.AddrReturn.Offset;
-
-  /* The return address always follows the stack pointer */
-  sf.AddrReturn.Offset = (_ADDR) *++framep;
-
-  if (needargs)
-    {
-      unsigned nparams = NPARAMS;
-
-      /* The arguments follow the return address */
-      sf.Params[0] = (_ADDR) *++framep;
-      for (unsigned i = 1; i < nparams; i++)
-       sf.Params[i] = (_ADDR) *++framep;
-    }
-  return 1;
-#endif
 }
 
 void
@@ -379,17 +342,13 @@ cygwin_exception::dumpstack ()
       int i;
 
       thestack.init (framep, 1, ctx);  /* Initialize from the input CONTEXT */
-#ifdef __x86_64__
       small_printf ("Stack trace:\r\nFrame        Function    Args\r\n");
-#else
-      small_printf ("Stack trace:\r\nFrame     Function  Args\r\n");
-#endif
       for (i = 0; i < DUMPSTACK_FRAME_LIMIT && thestack++; i++)
        {
-         small_printf (_AFMT "  " _AFMT, thestack.sf.AddrFrame.Offset,
+         small_printf ("%011X  %011X", thestack.sf.AddrFrame.Offset,
                        thestack.sf.AddrPC.Offset);
          for (unsigned j = 0; j < NPARAMS; j++)
-           small_printf ("%s" _AFMT, j == 0 ? " (" : ", ",
+           small_printf ("%s%011X", j == 0 ? " (" : ", ",
                          thestack.sf.Params[j]);
          small_printf (")\r\n");
        }
@@ -413,8 +372,8 @@ _cygtls::inside_kernel (CONTEXT *cx)
     return true;
 
   memset (&m, 0, sizeof m);
-  if (!VirtualQuery ((LPCVOID) cx->_GR(ip), &m, sizeof m))
-    sigproc_printf ("couldn't get memory info, pc %p, %E", cx->_GR(ip));
+  if (!VirtualQuery ((LPCVOID) cx->_CX_instPtr, &m, sizeof m))
+    sigproc_printf ("couldn't get memory info, pc %p, %E", cx->_CX_instPtr);
 
   size_t size = (windows_system_directory_length + 6) * sizeof (WCHAR);
   PWCHAR checkdir = (PWCHAR) alloca (size);
@@ -439,7 +398,7 @@ _cygtls::inside_kernel (CONTEXT *cx)
       res = wcsncasecmp (windows_system_directory, checkdir,
                         windows_system_directory_length) == 0;
     }
-  sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->_GR(ip), h, res);
+  sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->_CX_instPtr, h, res);
 # undef h
   return res;
 }
@@ -451,7 +410,7 @@ cygwin_stackdump ()
   CONTEXT c;
   c.ContextFlags = CONTEXT_FULL;
   RtlCaptureContext (&c);
-  cygwin_exception exc ((PUINT_PTR) c._GR(bp), &c);
+  cygwin_exception exc ((PUINT_PTR) c._CX_framePtr, &c);
   exc.dumpstack ();
 }
 
@@ -548,35 +507,6 @@ try_to_debug ()
   return dbg;
 }
 
-#ifdef __x86_64__
-/* Don't unwind the stack on x86_64.  It's not necessary to do that from the
-   exception handler. */
-#define rtl_unwind(el,er)
-#else
-static void __reg3 rtl_unwind (exception_list *, PEXCEPTION_RECORD)
-                  __attribute__ ((noinline, regparm (3)));
-
-void __reg3
-rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e)
-{
-  __asm__ ("\n\
-  pushl                %%ebx                                   \n\
-  pushl                %%edi                                   \n\
-  pushl                %%esi                                   \n\
-  pushl                $0                                      \n\
-  pushl                %1                                      \n\
-  pushl                $1f                                     \n\
-  pushl                %0                                      \n\
-  call         _RtlUnwind@16                           \n\
-1:                                                     \n\
-  popl         %%esi                                   \n\
-  popl         %%edi                                   \n\
-  popl         %%ebx                                   \n\
-": : "r" (frame), "r" (e));
-}
-#endif /* __x86_64 */
-
-#ifdef __x86_64__
 /* myfault exception handler. */
 EXCEPTION_DISPOSITION
 exception::myfault (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in,
@@ -610,16 +540,14 @@ myfault_altstack_handler (EXCEPTION_POINTERS *exc)
       /* Unwind the stack manually and call RtlRestoreContext.  This
         is necessary because RtlUnwindEx checks the stack for validity,
         which, as outlined above, fails for the alternate stack. */
-      while (c->Rsp < me.andreas->frame)
+      while (c->_CX_stackPtr < me.andreas->frame)
        __unwind_single_frame (c);
-      c->Rip = me.andreas->ret;
+      c->_CX_instPtr = me.andreas->ret;
       RtlRestoreContext (c, NULL);
     }
   return EXCEPTION_CONTINUE_SEARCH;
 }
 
-#endif
-
 /* Main exception handler. */
 EXCEPTION_DISPOSITION
 exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in,
@@ -628,11 +556,6 @@ exception::handle (EXCEPTION_RECORD *e, exception_list 
*frame, CONTEXT *in,
   static int NO_COPY debugging = 0;
   _cygtls& me = _my_tls;
 
-#ifdef __i386__
-  if (me.andreas)
-    me.andreas->leave ();      /* Return from a "san" caught fault */
-#endif
-
   if (debugging && ++debugging < 500000)
     {
       SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
@@ -759,7 +682,6 @@ exception::handle (EXCEPTION_RECORD *e, exception_list 
*frame, CONTEXT *in,
         handling.  */
       return ExceptionContinueExecution;
 
-#ifdef __x86_64__
     case STATUS_GCC_THROW:
     case STATUS_GCC_UNWIND:
     case STATUS_GCC_FORCED:
@@ -767,7 +689,6 @@ exception::handle (EXCEPTION_RECORD *e, exception_list 
*frame, CONTEXT *in,
         _Unwind_RaiseException(), GCC expects us to continue all the
         (continuable) GCC exceptions that reach us. */
       return ExceptionContinueExecution;
-#endif
 
     default:
       /* If we don't recognize the exception, we have to assume that
@@ -777,40 +698,21 @@ exception::handle (EXCEPTION_RECORD *e, exception_list 
*frame, CONTEXT *in,
     }
 
   debug_printf ("In cygwin_except_handler exception %y at %p sp %p",
-               e->ExceptionCode, in->_GR(ip), in->_GR(sp));
+               e->ExceptionCode, in->_CX_instPtr, in->_CX_stackPtr);
   debug_printf ("In cygwin_except_handler signal %d at %p",
-               si.si_signo, in->_GR(ip));
+               si.si_signo, in->_CX_instPtr);
 
-#ifdef __x86_64__
-  PUINT_PTR framep = (PUINT_PTR) in->Rbp;
-  /* Sometimes, when a stack is screwed up, Rbp tends to be NULL.  In that
-     case, base the stacktrace on Rsp.  In most cases, it allows to generate
-     useful stack trace. */
+  PUINT_PTR framep = (PUINT_PTR) in->_CX_framePtr;
+  /* Sometimes, when a stack is screwed up, the frame pointer tends to be NULL.
+     In that case, base the stacktrace on the stack pointer.  In most cases,
+     it allows to generate useful stack trace. */
   if (!framep)
-    framep = (PUINT_PTR) in->Rsp;
-#else
-  PUINT_PTR framep = (PUINT_PTR) in->_GR(sp);
-  for (PUINT_PTR bpend = (PUINT_PTR) __builtin_frame_address (0);
-       framep > bpend;
-       framep--)
-    if (*framep == in->SegCs && framep[-1] == in->_GR(ip))
-      {
-       framep -= 2;
-       break;
-      }
-
-  /* Temporarily replace windows top level SEH with our own handler.
-     We don't want any Windows magic kicking in.  This top level frame
-     will be removed automatically after our exception handler returns. */
-  _except_list->handler = handle;
-#endif
+    framep = (PUINT_PTR) in->_CX_stackPtr;
 
   if (exit_state >= ES_SIGNAL_EXIT
       && (NTSTATUS) e->ExceptionCode != STATUS_CONTROL_C_EXIT)
     api_fatal ("Exception during process exit");
-  else if (!try_to_debug ())
-    rtl_unwind (frame, e);
-  else
+  else if (try_to_debug ())
     {
       debugging = 1;
       return ExceptionContinueExecution;
@@ -823,7 +725,7 @@ exception::handle (EXCEPTION_RECORD *e, exception_list 
*frame, CONTEXT *in,
      be the address of the faulting instruction.  Other signals are apparently
      undefined so we just set those to the faulting instruction too.  */
   si.si_addr = (si.si_signo == SIGSEGV || si.si_signo == SIGBUS)
-              ? (void *) e->ExceptionInformation[1] : (void *) in->_GR(ip);
+              ? (void *) e->ExceptionInformation[1] : (void *) in->_CX_instPtr;
   me.incyg++;
   sig_send (NULL, si, &me);    /* Signal myself */
   if ((NTSTATUS) e->ExceptionCode == STATUS_STACK_OVERFLOW)
@@ -928,7 +830,7 @@ _cygtls::interrupt_now (CONTEXT *cx, siginfo_t& si, void 
*handler,
     interrupted = false;
   else
     {
-      _ADDR &ip = cx->_GR(ip);
+      DWORD64 &ip = cx->_CX_instPtr;
       push (ip);
       interrupt_setup (si, handler, siga);
       ip = pop ();
@@ -1364,13 +1266,8 @@ signal_exit (int sig, siginfo_t *si, void *)
          {
            CONTEXT c;
            c.ContextFlags = CONTEXT_FULL;
-#ifdef __x86_64__
            RtlCaptureContext (&c);
            cygwin_exception exc ((PUINT_PTR) __builtin_frame_address (0), &c);
-#else
-           GetThreadContext (GetCurrentThread (), &c);
-           cygwin_exception exc ((PUINT_PTR) __builtin_frame_address (0), &c);
-#endif
            exc.dumpstack ();
          }
        break;
@@ -1691,7 +1588,7 @@ _cygtls::call_signal_handler ()
            {
              /* Software-generated signal.  We're fetching the current
                 context, unwind to the caller and in case we're called
-                from sigdelayed, fix rip/eip accordingly. */
+                from sigdelayed, fix the instruction pointer accordingly. */
              context.uc_mcontext.ctxflags = CONTEXT_FULL;
              RtlCaptureContext ((PCONTEXT) &context.uc_mcontext);
              __unwind_single_frame ((PCONTEXT) &context.uc_mcontext);
@@ -1700,7 +1597,7 @@ _cygtls::call_signal_handler ()
 #ifdef __x86_64__
                  context.uc_mcontext.rip = retaddr ();
 #else
-                 context.uc_mcontext.eip = retaddr ();
+#error unimplemented for this target
 #endif
                }
            }
@@ -1808,39 +1705,7 @@ _cygtls::call_signal_handler ()
                       [WRAPPER] "o" (altstack_wrapper)
                   : "memory");
 #else
-         /* Clobbered regs: ecx, edx, ebp, esp */
-         __asm__ ("\n\
-                  movl  %[NEW_SP], %%eax  # Load alt stack into eax    \n\
-                  subl  $32, %%eax        # Make room on alt stack for \n\
-                                          # clobbered regs and args to \n\
-                                          # signal handler             \n\
-                  movl  %%ecx, 16(%%eax)  # Save clobbered regs        \n\
-                  movl  %%edx, 20(%%eax)                               \n\
-                  movl  %%ebp, 24(%%eax)                               \n\
-                  movl  %%esp, 28(%%eax)                               \n\
-                  movl  %[SIG], %%ecx     # thissig to 1st arg slot    \n\
-                  movl  %%ecx, (%%eax)                                 \n\
-                  leal  %[SI], %%ecx      # &thissi to 2nd arg slot    \n\
-                  movl  %%ecx, 4(%%eax)                                \n\
-                  movl  %[CTX], %%ecx     # thiscontext to 3rd arg slot\n\
-                  movl  %%ecx, 8(%%eax)                                \n\
-                  movl  %[FUNC], %%ecx    # thisfunc to 4th arg slot   \n\
-                  movl  %%ecx, 12(%%eax)                               \n\
-                  leal  %[WRAPPER], %%ecx # thisfunc to ecx            \n\
-                  movl  %%eax, %%esp      # Move alt stack into esp    \n\
-                  call  *%%ecx            # Call thisfunc              \n\
-                  movl  %%esp, %%eax      # Restore clobbered regs     \n\
-                  movl  28(%%eax), %%esp                               \n\
-                  movl  24(%%eax), %%ebp                               \n\
-                  movl  20(%%eax), %%edx                               \n\
-                  movl  16(%%eax), %%eax                               \n"
-                  : : [NEW_SP] "o" (new_sp),
-                      [SIG]    "o" (thissig),
-                      [SI]     "o" (thissi),
-                      [CTX]    "o" (thiscontext),
-                      [FUNC]   "o" (thisfunc),
-                      [WRAPPER] "o" (altstack_wrapper)
-                  : "memory");
+#error unimplemented for this target
 #endif
        }
       else
@@ -1885,11 +1750,7 @@ _cygtls::signal_debugger (siginfo_t& si)
       if (GetThreadContext (th, &c))
        {
          if (incyg)
-#ifdef __x86_64__
-           c.Rip = retaddr ();
-#else
-           c.Eip = retaddr ();
-#endif
+           c._CX_instPtr = retaddr ();
          memcpy (&context.uc_mcontext, &c, sizeof (CONTEXT));
          /* Enough space for 32/64 bit addresses */
          char sigmsg[2 * sizeof (_CYGWIN_SIGNAL_STRING
@@ -1908,20 +1769,12 @@ setcontext (const ucontext_t *ucp)
   PCONTEXT ctx = (PCONTEXT) &ucp->uc_mcontext;
   set_signal_mask (_my_tls.sigmask, ucp->uc_sigmask);
   _my_tls.incyg = true;
-#ifdef __x86_64__
-  /* Apparently a call to NtContinue works on 64 bit as well, but using
-     RtlRestoreContext is the blessed way. */
   RtlRestoreContext (ctx, NULL);
-#else
-  NtContinue (ctx, FALSE);
-#endif
   /* If we got here, something was wrong. */
   set_errno (EINVAL);
   return -1;
 }
 
-#ifdef __x86_64__
-
 extern "C" int
 getcontext (ucontext_t *ucp)
 {
@@ -1929,14 +1782,13 @@ getcontext (ucontext_t *ucp)
   ctx->ContextFlags = CONTEXT_FULL;
   RtlCaptureContext (ctx);
   __unwind_single_frame (ctx);
-  /* Successful getcontext is supposed to return 0.  If we don't set rax to 0
-     here, there's a chance that code like this:
+  /* Successful getcontext is supposed to return 0.  If we don't set the
+     return register to 0 here, there's a chance that code like this:
 
        if (getcontext (&ctx) != 0)
 
-     assumes that getcontext failed after calling setcontext (&ctx).
-     Same goes for eax on 32 bit, see assembler implementation below. */
-  ucp->uc_mcontext.rax = 0;
+     assumes that getcontext failed after calling setcontext (&ctx). */
+  ucp->uc_mcontext._MC_retReg = 0;
   ucp->uc_sigmask = ucp->uc_mcontext.oldmask = _my_tls.sigmask;
   /* Do not touch any other member of ucontext_t. */
   return 0;
@@ -1950,14 +1802,16 @@ swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
   RtlCaptureContext (ctx);
   __unwind_single_frame (ctx);
   /* See comment in getcontext. */
-  oucp->uc_mcontext.rax = 0;
+  oucp->uc_mcontext._MC_retReg = 0;
   oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask;
   return setcontext (ucp);
 }
 
 /* Trampoline function to set the context to uc_link.  The pointer to the
-   address of uc_link is stored in the callee-saved register $rbx.  If uc_link
-   is NULL, call exit. */
+   address of uc_link is stored in a callee-saved register, referenced by
+   _MC_uclinkReg from the C code.  If uc_link is NULL, call exit. */
+#ifdef __x86_64__
+/* _MC_uclinkReg == %rbx */
 __asm__ ("                             \n\
        .global __cont_link_context     \n\
        .seh_proc __cont_link_context   \n\
@@ -1979,77 +1833,7 @@ __cont_link_context:                     \n\
        ");
 
 #else
-
-/* On 32 bit it's crucial to call RtlCaptureContext in a way which makes sure
-   the callee-saved registers, especially $ebx, are not changed by the calling
-   function.  If so, makecontext/__cont_link_context would be broken.
-
-   Amazing, but true:  While on 64 bit RtlCaptureContext returns the exact
-   context of its own caller, as expected, on 32 bit RtlCaptureContext returns
-   the context of the callers caller.  So while we have to unwind another frame
-   on 64 bit, we can skip this step on 32 bit.
-
-   Both functions are split into the first half in assembler, and the second
-   half in C to allow easy access to _my_tls. */
-
-extern "C" int
-__getcontext (ucontext_t *ucp)
-{
-  ucp->uc_mcontext.eax = 0;
-  ucp->uc_sigmask = ucp->uc_mcontext.oldmask = _my_tls.sigmask;
-  return 0;
-}
-
-__asm__ ("                             \n\
-       .global _getcontext             \n\
-_getcontext:                           \n\
-       pushl   %ebp                    \n\
-       movl    %esp, %ebp              \n\
-       movl    8(%esp), %eax           \n\
-       pushl   %eax                    \n\
-       call    _RtlCaptureContext@4    \n\
-       popl    %ebp                    \n\
-       jmp     ___getcontext           \n\
-       nop                             \n\
-       ");
-
-extern "C" int
-__swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
-{
-  oucp->uc_mcontext.eax = 0;
-  oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask;
-  return setcontext (ucp);
-}
-
-__asm__ ("                             \n\
-       .global _swapcontext            \n\
-_swapcontext:                          \n\
-       pushl   %ebp                    \n\
-       movl    %esp, %ebp              \n\
-       movl    8(%esp), %eax           \n\
-       pushl   %eax                    \n\
-       call    _RtlCaptureContext@4    \n\
-       popl    %ebp                    \n\
-       jmp     ___swapcontext          \n\
-       nop                             \n\
-       ");
-
-/* Trampoline function to set the context to uc_link.  The pointer to the
-   address of uc_link is stored in the callee-saved register $ebx.  If uc_link
-   is NULL, call exit. */
-__asm__ ("                             \n\
-       .global ___cont_link_context    \n\
-___cont_link_context:                  \n\
-       movl    %ebx, %esp              \n\
-       movl    (%esp), %eax            \n\
-       testl   %eax, %eax              \n\
-       je      1f                      \n\
-       call    _setcontext             \n\
-       movl    $0xff, (%esp)           \n\
-1:                                     \n\
-       call    _cygwin_exit            \n\
-       nop                             \n\
-       ");
+#error unimplemented for this target
 #endif
 
 /* makecontext is modelled after GLibc's makecontext.  The stack from uc_stack
@@ -2079,7 +1863,7 @@ makecontext (ucontext_t *ucp, void (*func) (void), int 
argc, ...)
   sp[0] = (uintptr_t) __cont_link_context;
   /* Fetch arguments and store them on the stack.
 
-     x86_64 only:
+     x86_64:
 
      - Store first four args in the AMD64 ABI arg registers.
 
@@ -2114,23 +1898,18 @@ makecontext (ucontext_t *ucp, void (*func) (void), int 
argc, ...)
        break;
       }
 #else
-    sp[i + 1] = va_arg (ap, uintptr_t);
+#error unimplemented for this target
 #endif
   va_end (ap);
   /* Store pointer to uc_link at the top of the stack. */
   sp[argc + 1] = (uintptr_t) ucp->uc_link;
   /* Last but not least set the register in the context at ucp so that a
      subsequent setcontext or swapcontext picks up the right values:
-     - Set rip/eip to the target function.
-     - Set rsp/esp to the just computed stack pointer value.
-     - Set rbx/ebx to the address of the pointer to uc_link. */
-#ifdef __x86_64__
-  ucp->uc_mcontext.rip = (uint64_t) func;
-  ucp->uc_mcontext.rsp = (uint64_t) sp;
-  ucp->uc_mcontext.rbx = (uint64_t) (sp + argc + 1);
-#else
-  ucp->uc_mcontext.eip = (uint32_t) func;
-  ucp->uc_mcontext.esp = (uint32_t) sp;
-  ucp->uc_mcontext.ebx = (uint32_t) (sp + argc + 1);
-#endif
+     - Set instruction pointer to the target function.
+     - Set stack pointer to the just computed stack pointer value.
+     - Set Cygwin-specific uclink register to the address of the pointer
+       to uc_link. */
+  ucp->uc_mcontext._MC_instPtr = (uint64_t) func;
+  ucp->uc_mcontext._MC_stackPtr = (uint64_t) sp;
+  ucp->uc_mcontext._MC_uclinkReg = (uint64_t) (sp + argc + 1);
 }

Reply via email to