From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id 2C0E63858C56; Tue, 17 May 2022 12:12:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2C0E63858C56 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin] Cygwin: drop i686 exception handling X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/master X-Git-Oldrev: 830a9b707caa5e343b6ffce7fcb2d3ca97e3259c X-Git-Newrev: 93bea9f5387921ec40f35c0c45ff240a433db603 Message-Id: <20220517121247.2C0E63858C56@sourceware.org> Date: Tue, 17 May 2022 12:12:47 +0000 (GMT) X-BeenThere: cygwin-cvs@cygwin.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Cygwin core component git logs List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 May 2022 12:12:47 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D93bea9f5387= 921ec40f35c0c45ff240a433db603 commit 93bea9f5387921ec40f35c0c45ff240a433db603 Author: Corinna Vinschen Date: Tue May 17 14:12:32 2022 +0200 Cygwin: drop i686 exception handling =20 Leave x86_64 CPU-specific code and #error out when trying to build for another target. Access special registers CPU-agnostic. =20 Signed-off-by: Corinna Vinschen 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; =20 -#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 =3D _my_tls.andreas; - _my_tls.andreas =3D this; - _c_cnt =3D _my_tls.locals.pathbufs.c_cnt; - _w_cnt =3D _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 =3D _c_cnt; - _my_tls.locals.pathbufs.w_cnt =3D _w_cnt; - __ljfault (_context, 1); - } - void reset () __attribute__ ((always_inline)) - { - _my_tls.andreas =3D _clemente; - } -}; =20 -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 compi= le - 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; \ } =20 -#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. */ =20 #pragma once =20 -#ifdef __i386__ -/* Documentation on the innards of 32 bit Windows exception handling (i.e. - from the perspective of a compiler implementor) apparently doesn't exis= t. - However, the following came from Onno Hovers - -The first pointer to the chain of handlers is in the thread environment bl= ock -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 hand= le -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 t= he -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 (=3D2), flag set. (and EH_EXIT_UNWIND (=3D4), when NULL is p= assed 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 Comprehensi= ve - Error Processing with Win32 Structured Exception Handling". It goes in= to - 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 =3D _except_list; - el.handler =3D handle; - el.prev =3D _except_list; - _except_list =3D ⪙ - }; - ~exception () __attribute__ ((always_inline)) { _except_list =3D save; } -}; - -#else /* !__i386__ */ - #define exception_list void typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; =20 @@ -159,8 +40,6 @@ public: =20 LONG CALLBACK myfault_altstack_handler (EXCEPTION_POINTERS *); =20 -#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" =20 -/* 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 =20 #define CALL_HANDLER_RETRY_OUTER 10 @@ -204,20 +210,12 @@ cygwin_exception::dump_exception () small_printf ("rbp=3D%016X rsp=3D%016X\r\n", ctx->Rbp, ctx->Rsp); small_printf ("program=3D%W, pid %u, thread %s\r\n", myself->progname, myself->pid, mythreadname ()); -#else - if (exception_name) - small_printf ("Exception: %s at eip=3D%08x\r\n", exception_name, ctx->= Eip); - else - small_printf ("Signal %d at eip=3D%08x\r\n", e->ExceptionCode, ctx->Ei= p); - small_printf ("eax=3D%08x ebx=3D%08x ecx=3D%08x edx=3D%08x esi=3D%08x ed= i=3D%08x\r\n", - ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx, ctx->Esi, ctx->Edi); - small_printf ("ebp=3D%08x esp=3D%08x program=3D%W, pid %u, thread %s\r\n= ", - ctx->Ebp, ctx->Esp, myself->progname, myself->pid, - mythreadname ()); -#endif small_printf ("cs=3D%04x ds=3D%04x es=3D%04x fs=3D%04x gs=3D%04x ss=3D%0= 4x\r\n", ctx->SegCs, ctx->SegDs, ctx->SegEs, ctx->SegFs, ctx->SegGs, ctx->SegSs); +#else +#error unimplemented for this target +#endif } =20 /* 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 sta= ck 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, PCON= TEXT ctx) c.ContextFlags =3D CONTEXT_ALL; } sigstackptr =3D _my_tls.stackptr; -#endif memset (&sf, 0, sizeof (sf)); if (ctx) sf.AddrFrame.Offset =3D (UINT_PTR) framep; @@ -277,7 +271,6 @@ stack_info::init (PUINT_PTR framep, bool wantargs, PCON= TEXT ctx) =20 extern "C" void _cygwin_exit_return (); =20 -#ifdef __x86_64__ static inline void __unwind_single_frame (PCONTEXT ctx) { @@ -287,19 +280,16 @@ __unwind_single_frame (PCONTEXT ctx) DWORD64 establisher; PVOID hdl; =20 - f =3D RtlLookupFunctionEntry (ctx->Rip, &imagebase, &hist); + f =3D 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 =3D *(ULONG_PTR *) ctx->Rsp; - ctx->Rsp +=3D 8; + ctx->_CX_instPtr =3D *(ULONG_PTR *) ctx->_CX_stackPtr; + ctx->_CX_stackPtr +=3D 8; } } -#else -#define __unwind_single_frame(ctx) -#endif =20 /* Walk the stack. =20 @@ -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; =20 - sf.AddrPC.Offset =3D c.Rip; - sf.AddrStack.Offset =3D c.Rsp; - sf.AddrFrame.Offset =3D c.Rbp; + sf.AddrPC.Offset =3D c._CX_instPtr; + sf.AddrStack.Offset =3D c._CX_stackPtr; + sf.AddrFrame.Offset =3D c._CX_framePtr; =20 - if ((c.Rip >=3D (DWORD64)&_sigbe) && (c.Rip < (DWORD64)&_sigdelayed_end)) + if ((c._CX_instPtr >=3D (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 =3D sigstackptr[-1]; + c._CX_instPtr =3D sigstackptr[-1]; sigstackptr--; return 1; } __unwind_single_frame (&c); - if (needargs && c.Rip) + if (needargs && c._CX_instPtr) { - PULONG_PTR p =3D (PULONG_PTR) c.Rsp; + PULONG_PTR p =3D (PULONG_PTR) c._CX_stackPtr; for (unsigned i =3D 0; i < NPARAMS; ++i) sf.Params[i] =3D p[i + 1]; } return 1; -#else - char **framep; - - if ((void (*) ()) sf.AddrPC.Offset =3D=3D _cygwin_exit_return) - return 0; /* stack frames are exhausted */ - - if (((framep =3D (char **) next_offset ()) =3D=3D NULL) - || (framep >=3D (char **) cygwin_hmodule)) - return 0; - - sf.AddrFrame.Offset =3D (_ADDR) framep; - sf.AddrPC.Offset =3D sf.AddrReturn.Offset; - - /* The return address always follows the stack pointer */ - sf.AddrReturn.Offset =3D (_ADDR) *++framep; - - if (needargs) - { - unsigned nparams =3D NPARAMS; - - /* The arguments follow the return address */ - sf.Params[0] =3D (_ADDR) *++framep; - for (unsigned i =3D 1; i < nparams; i++) - sf.Params[i] =3D (_ADDR) *++framep; - } - return 1; -#endif } =20 void @@ -379,17 +342,13 @@ cygwin_exception::dumpstack () int i; =20 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 =3D 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 =3D 0; j < NPARAMS; j++) - small_printf ("%s" _AFMT, j =3D=3D 0 ? " (" : ", ", + small_printf ("%s%011X", j =3D=3D 0 ? " (" : ", ", thestack.sf.Params[j]); small_printf (")\r\n"); } @@ -413,8 +372,8 @@ _cygtls::inside_kernel (CONTEXT *cx) return true; =20 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= ); =20 size_t size =3D (windows_system_directory_length + 6) * sizeof (WCHAR); PWCHAR checkdir =3D (PWCHAR) alloca (size); @@ -439,7 +398,7 @@ _cygtls::inside_kernel (CONTEXT *cx) res =3D wcsncasecmp (windows_system_directory, checkdir, windows_system_directory_length) =3D=3D 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 =3D CONTEXT_FULL; RtlCaptureContext (&c); - cygwin_exception exc ((PUINT_PTR) c._GR(bp), &c); + cygwin_exception exc ((PUINT_PTR) c._CX_framePtr, &c); exc.dumpstack (); } =20 @@ -548,35 +507,6 @@ try_to_debug () return dbg; } =20 -#ifdef __x86_64__ -/* Don't unwind the stack on x86_64. It's not necessary to do that from t= he - 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 *i= n, @@ -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 =3D me.andreas->ret; + c->_CX_instPtr =3D me.andreas->ret; RtlRestoreContext (c, NULL); } return EXCEPTION_CONTINUE_SEARCH; } =20 -#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 =3D 0; _cygtls& me =3D _my_tls; =20 -#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; =20 -#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 =20 default: /* If we don't recognize the exception, we have to assume that @@ -777,40 +698,21 @@ exception::handle (EXCEPTION_RECORD *e, exception_lis= t *frame, CONTEXT *in, } =20 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); =20 -#ifdef __x86_64__ - PUINT_PTR framep =3D (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 genera= te - useful stack trace. */ + PUINT_PTR framep =3D (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 case= s, + it allows to generate useful stack trace. */ if (!framep) - framep =3D (PUINT_PTR) in->Rsp; -#else - PUINT_PTR framep =3D (PUINT_PTR) in->_GR(sp); - for (PUINT_PTR bpend =3D (PUINT_PTR) __builtin_frame_address (0); - framep > bpend; - framep--) - if (*framep =3D=3D in->SegCs && framep[-1] =3D=3D in->_GR(ip)) - { - framep -=3D 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 =3D handle; -#endif + framep =3D (PUINT_PTR) in->_CX_stackPtr; =20 if (exit_state >=3D ES_SIGNAL_EXIT && (NTSTATUS) e->ExceptionCode !=3D 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 =3D 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 appare= ntly undefined so we just set those to the faulting instruction too. */ si.si_addr =3D (si.si_signo =3D=3D SIGSEGV || si.si_signo =3D=3D 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 =3D=3D STATUS_STACK_OVERFLOW) @@ -928,7 +830,7 @@ _cygtls::interrupt_now (CONTEXT *cx, siginfo_t& si, voi= d *handler, interrupted =3D false; else { - _ADDR &ip =3D cx->_GR(ip); + DWORD64 &ip =3D cx->_CX_instPtr; push (ip); interrupt_setup (si, handler, siga); ip =3D pop (); @@ -1364,13 +1266,8 @@ signal_exit (int sig, siginfo_t *si, void *) { CONTEXT c; c.ContextFlags =3D 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 =3D 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 =3D retaddr (); #else - context.uc_mcontext.eip =3D 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 =3D retaddr (); -#else - c.Eip =3D retaddr (); -#endif + c._CX_instPtr =3D 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 =3D (PCONTEXT) &ucp->uc_mcontext; set_signal_mask (_my_tls.sigmask, ucp->uc_sigmask); _my_tls.incyg =3D 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; } =20 -#ifdef __x86_64__ - extern "C" int getcontext (ucontext_t *ucp) { @@ -1929,14 +1782,13 @@ getcontext (ucontext_t *ucp) ctx->ContextFlags =3D CONTEXT_FULL; RtlCaptureContext (ctx); __unwind_single_frame (ctx); - /* Successful getcontext is supposed to return 0. If we don't set rax t= o 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: =20 if (getcontext (&ctx) !=3D 0) =20 - assumes that getcontext failed after calling setcontext (&ctx). - Same goes for eax on 32 bit, see assembler implementation below. */ - ucp->uc_mcontext.rax =3D 0; + assumes that getcontext failed after calling setcontext (&ctx). */ + ucp->uc_mcontext._MC_retReg =3D 0; ucp->uc_sigmask =3D ucp->uc_mcontext.oldmask =3D _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 *uc= p) RtlCaptureContext (ctx); __unwind_single_frame (ctx); /* See comment in getcontext. */ - oucp->uc_mcontext.rax =3D 0; + oucp->uc_mcontext._MC_retReg =3D 0; oucp->uc_sigmask =3D oucp->uc_mcontext.oldmask =3D _my_tls.sigmask; return setcontext (ucp); } =20 /* 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 =3D=3D %rbx */ __asm__ (" \n\ .global __cont_link_context \n\ .seh_proc __cont_link_context \n\ @@ -1979,77 +1833,7 @@ __cont_link_context: \n\ "); =20 #else - -/* On 32 bit it's crucial to call RtlCaptureContext in a way which makes s= ure - the callee-saved registers, especially $ebx, are not changed by the cal= ling - 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 ret= urns - 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 seco= nd - half in C to allow easy access to _my_tls. */ - -extern "C" int -__getcontext (ucontext_t *ucp) -{ - ucp->uc_mcontext.eax =3D 0; - ucp->uc_sigmask =3D ucp->uc_mcontext.oldmask =3D _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 =3D 0; - oucp->uc_sigmask =3D oucp->uc_mcontext.oldmask =3D _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 =20 /* makecontext is modelled after GLibc's makecontext. The stack from uc_s= tack @@ -2079,7 +1863,7 @@ makecontext (ucontext_t *ucp, void (*func) (void), in= t argc, ...) sp[0] =3D (uintptr_t) __cont_link_context; /* Fetch arguments and store them on the stack. =20 - x86_64 only: + x86_64: =20 - Store first four args in the AMD64 ABI arg registers. =20 @@ -2114,23 +1898,18 @@ makecontext (ucontext_t *ucp, void (*func) (void), = int argc, ...) break; } #else - sp[i + 1] =3D 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] =3D (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 =3D (uint64_t) func; - ucp->uc_mcontext.rsp =3D (uint64_t) sp; - ucp->uc_mcontext.rbx =3D (uint64_t) (sp + argc + 1); -#else - ucp->uc_mcontext.eip =3D (uint32_t) func; - ucp->uc_mcontext.esp =3D (uint32_t) sp; - ucp->uc_mcontext.ebx =3D (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 =3D (uint64_t) func; + ucp->uc_mcontext._MC_stackPtr =3D (uint64_t) sp; + ucp->uc_mcontext._MC_uclinkReg =3D (uint64_t) (sp + argc + 1); }