x86_64: Handle myfault exceptions when running on alternate signal stack
x86_64 only:
        * cygtls.cc (san::leave): Restore _my_tls.andreas.
        * cygtls.h (class san):  Add _clemente as in 32 bit case.  Add ret and
        frame members.
        (san::san): Handle _my_tls.andreas as on 32 bit.  Take parameter and
        write it to new member ret.  Store current stack pointer in frame.
        (san::~san): New destructor to restore _my_tls.andreas.
        (__try): Use __l_except address as parameter to san::san.
        * dcrt0.cc (dll_crt0_0): Add myfault_altstack_handler as vectored
        continuation handler.
        * exception.h (myfault_altstack_handler): Declare.
        * exceptions.cc (myfault_altstack_handler): New function.  Explain what
        it's good for.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
			
			
This commit is contained in:
		
							parent
							
								
									29a1263227
								
							
						
					
					
						commit
						60f10c64aa
					
				|  | @ -224,5 +224,6 @@ void san::leave () | |||
| { | ||||
|   /* Restore tls_pathbuf counters in case of error. */ | ||||
|   _my_tls.locals.pathbufs._counters = _cnt; | ||||
|   _my_tls.andreas = _clemente; | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -301,11 +301,26 @@ extern _cygtls *_sig_tls; | |||
| #ifdef __x86_64__ | ||||
| class san | ||||
| { | ||||
|   san *_clemente; | ||||
|   uint64_t _cnt; | ||||
| public: | ||||
|   san () __attribute__ ((always_inline)) | ||||
|   DWORD64 ret; | ||||
|   DWORD64 frame; | ||||
| 
 | ||||
|   san (PVOID _ret) __attribute__ ((always_inline)) | ||||
|   { | ||||
|     _clemente = _my_tls.andreas; | ||||
|     _my_tls.andreas = this; | ||||
|     _cnt = _my_tls.locals.pathbufs._counters; | ||||
|     /* myfault_altstack_handler needs the current stack pointer and the
 | ||||
|        address of the _except block to restore the context correctly. | ||||
|        See comment preceeding myfault_altstack_handler in exception.cc. */ | ||||
|     ret = (DWORD64) _ret; | ||||
|     __asm__ volatile ("movq %%rsp,%0": "=o" (frame)); | ||||
|   } | ||||
|   ~san () __attribute__ ((always_inline)) | ||||
|   { | ||||
|     _my_tls.andreas = _clemente; | ||||
|   } | ||||
|   /* This is the first thing called in the __except handler.  The attribute
 | ||||
|      "returns_twice" makes sure that GCC disregards any register value set | ||||
|  | @ -363,7 +378,7 @@ public: | |||
|   { \ | ||||
|     __label__ __l_try, __l_except, __l_endtry; \ | ||||
|     __mem_barrier; \ | ||||
|     san __sebastian; \ | ||||
|     san __sebastian (&&__l_except); \ | ||||
|     __asm__ goto ("\n" \ | ||||
|       "  .seh_handler _ZN9exception7myfaultEP17_EXCEPTION_RECORDPvP8_CONTEXTP19_DISPATCHER_CONTEXT, @except						\n" \ | ||||
|       "  .seh_handlerdata						\n" \ | ||||
|  |  | |||
|  | @ -800,6 +800,11 @@ dll_crt0_0 () | |||
|   if (!dynamically_loaded) | ||||
|     sigproc_init (); | ||||
| 
 | ||||
| #ifdef __x86_64__ | ||||
|   /* See comment preceeding myfault_altstack_handler in exception.cc. */ | ||||
|   AddVectoredContinueHandler (0, myfault_altstack_handler); | ||||
| #endif | ||||
| 
 | ||||
|   debug_printf ("finished dll_crt0_0 initialization"); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -160,6 +160,8 @@ public: | |||
|   } | ||||
| }; | ||||
| 
 | ||||
| LONG CALLBACK myfault_altstack_handler (EXCEPTION_POINTERS *); | ||||
| 
 | ||||
| #endif /* !__x86_64__ */ | ||||
| 
 | ||||
| class cygwin_exception | ||||
|  |  | |||
|  | @ -588,6 +588,50 @@ exception::myfault (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, | |||
|   /* NOTREACHED, make gcc happy. */ | ||||
|   return ExceptionContinueSearch; | ||||
| } | ||||
| 
 | ||||
| /* If another exception occurs while running a signal handler on an alternate
 | ||||
|    signal stack, the normal SEH handlers are skipped, because the OS exception | ||||
|    handling considers the current (alternate) stack "broken".  However, it | ||||
|    still calls vectored exception handlers. | ||||
| 
 | ||||
|    TODO: What we do here is to handle only __try/__except blocks in Cygwin. | ||||
|          "Normal" exceptions will simply exit the process.  Still, better | ||||
| 	 than nothing... */ | ||||
| LONG WINAPI | ||||
| myfault_altstack_handler (EXCEPTION_POINTERS *exc) | ||||
| { | ||||
|   _cygtls& me = _my_tls; | ||||
| 
 | ||||
|   if (me.andreas) | ||||
|     { | ||||
|       PRUNTIME_FUNCTION f; | ||||
|       ULONG64 imagebase; | ||||
|       UNWIND_HISTORY_TABLE hist; | ||||
|       DWORD64 establisher; | ||||
|       PVOID hdl; | ||||
|       CONTEXT *c = exc->ContextRecord; | ||||
| 
 | ||||
|       /* 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) | ||||
| 	{ | ||||
| 	  f = RtlLookupFunctionEntry (c->Rip, &imagebase, &hist); | ||||
| 	  if (f) | ||||
| 	    RtlVirtualUnwind (0, imagebase, c->Rip, f, c, &hdl, &establisher, | ||||
| 			      NULL); | ||||
| 	  else | ||||
| 	    { | ||||
| 	      c->Rip = *(ULONG_PTR *) c->Rsp; | ||||
| 	      c->Rsp += 8; | ||||
| 	    } | ||||
| 	} | ||||
|       c->Rip = me.andreas->ret; | ||||
|       RtlRestoreContext (c, NULL); | ||||
|     } | ||||
|   return EXCEPTION_CONTINUE_SEARCH; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| /* Main exception handler. */ | ||||
|  | @ -697,11 +741,13 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, | |||
|       break; | ||||
| 
 | ||||
|     case STATUS_STACK_OVERFLOW: | ||||
| #if 0 | ||||
|       /* If we encounter a stack overflow, and if the thread has no alternate
 | ||||
|          stack, don't even try to call a signal handler.  This is in line with | ||||
| 	 Linux behaviour and also makes a lot of sense on Windows. */ | ||||
|       if (me.altstack.ss_flags) | ||||
| 	global_sigs[SIGSEGV].sa_handler = SIG_DFL; | ||||
| #endif | ||||
|       /*FALLTHRU*/ | ||||
|     case STATUS_ARRAY_BOUNDS_EXCEEDED: | ||||
|     case STATUS_IN_PAGE_ERROR: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue