public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] Cygwin: drop i686 exception handling
@ 2022-05-17 12:12 Corinna Vinschen
  0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2022-05-17 12:12 UTC (permalink / raw)
  To: cygwin-cvs

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

commit 93bea9f5387921ec40f35c0c45ff240a433db603
Author: Corinna Vinschen <corinna@vinschen.de>
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 <corinna@vinschen.de>

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 <onno@stack.urc.tue.nl>
-
-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);
 }


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-05-17 12:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-17 12:12 [newlib-cygwin] Cygwin: drop i686 exception handling Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).