OSDN Git Service

* exceptions.cc (call_handler): Streamline to use only one call to
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / exceptions.cc
1 /* exceptions.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <stdio.h>
12 #include <errno.h>
13
14 #define Win32_Winsock
15 #include "winsup.h"
16 #include "exceptions.h"
17 #undef DECLSPEC_IMPORT
18 #define DECLSPEC_IMPORT
19 #include <imagehlp.h>
20 #include "autoload.h"
21 #include "sync.h"
22
23 char debugger_command[2 * MAX_PATH + 20];
24
25 extern "C" {
26 static int handle_exceptions (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
27 extern void sigreturn ();
28 extern void sigdelayed ();
29 extern void siglast ();
30 extern DWORD __sigfirst, __siglast;
31 };
32
33 static BOOL WINAPI ctrl_c_handler (DWORD);
34 static void really_exit (int);
35 static char windows_system_directory[1024];
36 static size_t windows_system_directory_length;
37
38 /* This is set to indicate that we have already exited.  */
39
40 static NO_COPY int exit_already = 0;
41 static NO_COPY muto *mask_sync = NULL;
42
43 HMODULE cygwin_hmodule;
44 HANDLE NO_COPY console_handler_thread_waiter = NULL;
45
46 static const struct
47 {
48   unsigned int code;
49   const char *name;
50 } status_info[] NO_COPY =
51 {
52 #define X(s) s, #s
53   { X (STATUS_ABANDONED_WAIT_0) },
54   { X (STATUS_ACCESS_VIOLATION) },
55   { X (STATUS_ARRAY_BOUNDS_EXCEEDED) },
56   { X (STATUS_BREAKPOINT) },
57   { X (STATUS_CONTROL_C_EXIT) },
58   { X (STATUS_DATATYPE_MISALIGNMENT) },
59   { X (STATUS_FLOAT_DENORMAL_OPERAND) },
60   { X (STATUS_FLOAT_DIVIDE_BY_ZERO) },
61   { X (STATUS_FLOAT_INEXACT_RESULT) },
62   { X (STATUS_FLOAT_INVALID_OPERATION) },
63   { X (STATUS_FLOAT_OVERFLOW) },
64   { X (STATUS_FLOAT_STACK_CHECK) },
65   { X (STATUS_FLOAT_UNDERFLOW) },
66   { X (STATUS_GUARD_PAGE_VIOLATION) },
67   { X (STATUS_ILLEGAL_INSTRUCTION) },
68   { X (STATUS_INTEGER_DIVIDE_BY_ZERO) },
69   { X (STATUS_INTEGER_OVERFLOW) },
70   { X (STATUS_INVALID_DISPOSITION) },
71   { X (STATUS_IN_PAGE_ERROR) },
72   { X (STATUS_NONCONTINUABLE_EXCEPTION) },
73   { X (STATUS_NO_MEMORY) },
74   { X (STATUS_PENDING) },
75   { X (STATUS_PRIVILEGED_INSTRUCTION) },
76   { X (STATUS_SINGLE_STEP) },
77   { X (STATUS_STACK_OVERFLOW) },
78   { X (STATUS_TIMEOUT) },
79   { X (STATUS_USER_APC) },
80   { X (STATUS_WAIT_0) },
81   { 0, 0 }
82 #undef X
83 };
84
85 /* Initialization code.  */
86
87 #ifdef __i386__
88
89 // Set up the exception handler for the current thread.  The PowerPC & Mips
90 // use compiler generated tables to set up the exception handlers for each
91 // region of code, and the kernel walks the call list until it finds a region
92 // of code that handles exceptions.  The x86 on the other hand uses segment
93 // register fs, offset 0 to point to the current exception handler.
94
95 asm (".equ __except_list,0");
96
97 extern exception_list *_except_list asm ("%fs:__except_list");
98
99 static void
100 init_exception_handler (exception_list *el)
101 {
102   el->handler = handle_exceptions;
103   el->prev = _except_list;
104   _except_list = el;
105 }
106
107 #define INIT_EXCEPTION_HANDLER(el) init_exception_handler (el)
108 #endif
109
110 void
111 set_console_handler ()
112 {
113   /* Initialize global security attribute stuff */
114
115   sec_none.nLength = sec_none_nih.nLength =
116   sec_all.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
117   sec_none.bInheritHandle = sec_all.bInheritHandle = TRUE;
118   sec_none_nih.bInheritHandle = sec_all_nih.bInheritHandle = FALSE;
119   sec_none.lpSecurityDescriptor = sec_none_nih.lpSecurityDescriptor = NULL;
120   sec_all.lpSecurityDescriptor = sec_all_nih.lpSecurityDescriptor =
121     get_null_sd ();
122
123   /* Allocate the event needed for ctrl_c_handler synchronization with
124      wait_sig. */
125   if (!console_handler_thread_waiter)
126     CreateEvent (&sec_none_nih, TRUE, TRUE, NULL);
127   (void) SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
128   if (!SetConsoleCtrlHandler (ctrl_c_handler, TRUE))
129     system_printf ("SetConsoleCtrlHandler failed, %E");
130 }
131
132 extern "C" void
133 init_exceptions (exception_list *el)
134 {
135 #ifdef INIT_EXCEPTION_HANDLER
136   INIT_EXCEPTION_HANDLER (el);
137 #endif
138 }
139
140 extern "C" void
141 error_start_init (const char *buf)
142 {
143   if (!buf || !*buf)
144     {
145       debugger_command[0] = '\0';
146       return;
147     }
148
149   char myself_posix_name[MAX_PATH];
150
151   /* FIXME: gdb cannot use win32 paths, but what if debugger isn't gdb? */
152   cygwin_conv_to_posix_path (myself->progname, myself_posix_name);
153   __small_sprintf (debugger_command, "%s %s", buf, myself_posix_name);
154 }
155
156 /* Utilities for dumping the stack, etc.  */
157
158 static void
159 exception (EXCEPTION_RECORD *e,  CONTEXT *in)
160 {
161   const char *exception_name = 0;
162
163   if (e)
164     {
165       for (int i = 0; status_info[i].name; i++)
166         {
167           if (status_info[i].code == e->ExceptionCode)
168             {
169               exception_name = status_info[i].name;
170               break;
171             }
172         }
173     }
174
175 #ifdef __i386__
176 #define HAVE_STATUS
177   if (exception_name)
178     small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip);
179   else
180     small_printf ("Exception %d at eip=%08x\r\n", e->ExceptionCode, in->Eip);
181   small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n",
182               in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi);
183   small_printf ("ebp=%08x esp=%08x program=%s\r\n",
184               in->Ebp, in->Esp, myself->progname);
185   small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n",
186               in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs);
187 #endif
188
189 #ifndef HAVE_STATUS
190   system_printf ("Had an exception");
191 #endif
192 }
193
194 extern "C" {
195 static LPVOID __stdcall
196 sfta(HANDLE, DWORD)
197 {
198   return NULL;
199 }
200
201 static DWORD __stdcall
202 sgmb(HANDLE, DWORD)
203 {
204   return 4;
205 }
206
207 #ifdef __i386__
208 /* Print a stack backtrace. */
209
210 #define HAVE_STACK_TRACE
211
212 /* Set from CYGWIN environment variable if want to use old method. */
213 BOOL NO_COPY oldstack = 0;
214
215 /* The function used to load the imagehlp DLL.  Returns TRUE if the
216    DLL was found. */
217 static LoadDLLinitfunc (imagehlp)
218 {
219   imagehlp_handle = LoadLibrary ("imagehlp.dll");
220   return !!imagehlp_handle;
221 }
222
223 LoadDLLinit (imagehlp)  /* Set up storage for imagehlp.dll autoload */
224 LoadDLLfunc (StackWalk, StackWalk@36, imagehlp)
225
226 /* A class for manipulating the stack. */
227 class stack_info
228 {
229   int first_time;               /* True if just starting to iterate. */
230   HANDLE hproc;                 /* Handle of process to inspect. */
231   HANDLE hthread;               /* Handle of thread to inspect. */
232   int (stack_info::*get) (HANDLE, HANDLE); /* Gets the next stack frame */
233 public:
234   STACKFRAME sf;                /* For storing the stack information */
235   int walk (HANDLE, HANDLE);    /* Uses the StackWalk function */
236   int brute_force (HANDLE, HANDLE); /* Uses the "old" method */
237   void init (CONTEXT *);        /* Called the first time that stack info is needed */
238
239   /* The constructor remembers hproc and hthread and determines which stack walking
240      method to use */
241   stack_info (int use_old_stack, HANDLE hp, HANDLE ht): hproc(hp), hthread(ht)
242   {
243     if (!use_old_stack && LoadDLLinitnow (imagehlp))
244       get = &stack_info::walk;
245     else
246       get = &stack_info::brute_force;
247   }
248   /* Postfix ++ iterates over the stack, returning zero when nothing is left. */
249   int operator ++(int) { return (this->*get) (hproc, hthread); }
250 };
251
252 /* The number of parameters used in STACKFRAME */
253 #define NPARAMS (sizeof(thestack->sf.Params) / sizeof(thestack->sf.Params[0]))
254
255 /* This is the main stack frame info for this process. */
256 static stack_info *thestack = NULL;
257 static signal_dispatch sigsave;
258
259 /* Initialize everything needed to start iterating. */
260 void
261 stack_info::init (CONTEXT *cx)
262 {
263   first_time = 1;
264   memset (&sf, 0, sizeof(sf));
265   sf.AddrPC.Offset = cx->Eip;
266   sf.AddrPC.Mode = AddrModeFlat;
267   sf.AddrStack.Offset = cx->Esp;
268   sf.AddrStack.Mode = AddrModeFlat;
269   sf.AddrFrame.Offset = cx->Ebp;
270   sf.AddrFrame.Mode = AddrModeFlat;
271 }
272
273 /* Walk the stack by looking at successive stored 'bp' frames.
274    This is not foolproof. */
275 int
276 stack_info::brute_force (HANDLE, HANDLE)
277 {
278   char **ebp;
279   if (first_time)
280     /* Everything is filled out already */
281     ebp = (char **) sf.AddrFrame.Offset;
282   else if ((ebp = (char **) *(char **) sf.AddrFrame.Offset) != NULL)
283     {
284       sf.AddrFrame.Offset = (DWORD) ebp;
285       sf.AddrPC.Offset = sf.AddrReturn.Offset;
286     }
287   else
288     return 0;
289
290   first_time = 0;
291   if (!sf.AddrPC.Offset)
292     return 0;           /* stack frames are exhausted */
293
294   /* The return address always follows the stack pointer */
295   sf.AddrReturn.Offset = (DWORD) *++ebp;
296
297   /* The arguments follow the return address */
298   for (unsigned i = 0; i < NPARAMS; i++)
299     sf.Params[i] = (DWORD) *++ebp;
300   return 1;
301 }
302
303 /* Use Win32 StackWalk() API to display the stack.  This is theoretically
304    more foolproof than the brute force method above. */
305 int
306 stack_info::walk (HANDLE hproc, HANDLE hthread)
307 {
308 #ifdef SOMEDAY
309   /* It would be nice to get more information (like DLL symbols and module name)
310      for each stack frame but in order to do that we have to call SymInitialize.
311      It doesn't seem to be possible to do this inside of an excaption handler for
312      some reason. */
313   static int initialized = 0;
314   if (!initialized && !SymInitialize(hproc, NULL, TRUE))
315     small_printf("SymInitialize error, %E\n");
316   initialized = 1;
317 #endif
318
319   return StackWalk (IMAGE_FILE_MACHINE_I386, hproc, hthread, &sf, NULL, NULL,
320                     sfta, sgmb, NULL) && !!sf.AddrFrame.Offset;
321 }
322
323 /* Dump the stack using either the old method or the new Win32 API method */
324 void
325 stack (HANDLE hproc, HANDLE hthread, CONTEXT *cx)
326 {
327   int i;
328
329   /* Set this up if it's the first time. */
330   if (!thestack)
331     thestack = new stack_info (oldstack, hproc, hthread);
332
333   thestack->init (cx);  /* Initialize from the input CONTEXT */
334   small_printf ("Stack trace:\r\nFrame     Function  Args\r\n");
335   for (i = 0; i < 16 && (*thestack)++ ; i++)
336     {
337       small_printf ("%08x  %08x ", thestack->sf.AddrFrame.Offset,
338                     thestack->sf.AddrPC.Offset);
339       for (unsigned j = 0; j < NPARAMS; j++)
340         small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack->sf.Params[j]);
341       small_printf (")\r\n");
342     }
343   small_printf ("End of stack trace%s",
344               i == 16 ? " (more stack frames may be present)" : "");
345 }
346
347 /* Temporary (?) function for external callers to get a stack dump */
348 extern "C" void
349 cygwin_stackdump()
350 {
351   CONTEXT c;
352   c.ContextFlags = CONTEXT_FULL;
353   HANDLE h1 = GetCurrentProcess ();
354   HANDLE h2 = GetCurrentThread ();
355   GetThreadContext (h2, &c);
356   stack(h1, h2, &c);
357 }
358
359 static int NO_COPY keep_looping = 0;
360
361 extern "C" int
362 try_to_debug ()
363 {
364   debug_printf ("debugger_command %s", debugger_command);
365   if (*debugger_command == '\0')
366     return 0;
367
368   __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());
369
370   BOOL dbg;
371
372   PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
373
374   STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
375   si.lpReserved = NULL;
376   si.lpDesktop = NULL;
377   si.dwFlags = 0;
378   si.cb = sizeof (si);
379
380   /* FIXME: need to know handles of all running threads to
381      suspend_all_threads_except (current_thread_id);
382   */
383
384   /* if any of these mutexes is owned, we will fail to start any cygwin app
385      until trapped app exits */
386
387   ReleaseMutex (pinfo_mutex);
388   ReleaseMutex (title_mutex);
389
390   dbg = CreateProcess (NULL,
391                        debugger_command,
392                        NULL,
393                        NULL,
394                        FALSE,
395                        CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
396                        NULL,
397                        NULL,
398                        &si,
399                        &pi);
400   if (!dbg)
401     {
402       system_printf ("Failed to start debugger: %E");
403       /* FIXME: need to know handles of all running threads to
404         resume_all_threads_except (current_thread_id);
405       */
406     }
407   else
408     {
409       keep_looping = 1;
410       while (keep_looping)
411         Sleep (10000);
412     }
413
414   return 0;
415 }
416
417 void
418 stackdump (HANDLE hproc, HANDLE hthread, EXCEPTION_RECORD *e, CONTEXT *in)
419 {
420   char *p;
421   if (myself->progname[0])
422     {
423       /* write to progname.stackdump if possible */
424       if ((p = strrchr (myself->progname, '\\')))
425         p++;
426       else
427         p = myself->progname;
428       char corefile[strlen(p) + sizeof(".stackdump")];
429       __small_sprintf (corefile, "%s.stackdump", p);
430       HANDLE h = CreateFile (corefile, GENERIC_WRITE, 0, &sec_none_nih,
431                              CREATE_ALWAYS, 0, 0);
432       if (h != INVALID_HANDLE_VALUE)
433         {
434           system_printf ("Dumping stack trace to %s", corefile);
435           SetStdHandle (STD_ERROR_HANDLE, h);
436         }
437     }
438   if (e)
439     exception (e, in);
440   stack (hproc, hthread, in);
441 }
442
443 /* Main exception handler. */
444
445 static int
446 handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *)
447 {
448   int sig;
449
450   /* If we've already exited, don't do anything here.  Returning 1
451      tells Windows to keep looking for an exception handler.  */
452   if (exit_already)
453     return 1;
454
455   /* Coerce win32 value to posix value.  */
456   switch (e->ExceptionCode)
457     {
458     case STATUS_FLOAT_DENORMAL_OPERAND:
459     case STATUS_FLOAT_DIVIDE_BY_ZERO:
460     case STATUS_FLOAT_INEXACT_RESULT:
461     case STATUS_FLOAT_INVALID_OPERATION:
462     case STATUS_FLOAT_OVERFLOW:
463     case STATUS_FLOAT_STACK_CHECK:
464     case STATUS_FLOAT_UNDERFLOW:
465     case STATUS_INTEGER_DIVIDE_BY_ZERO:
466     case STATUS_INTEGER_OVERFLOW:
467       sig = SIGFPE;
468       break;
469
470     case STATUS_ILLEGAL_INSTRUCTION:
471     case STATUS_PRIVILEGED_INSTRUCTION:
472     case STATUS_NONCONTINUABLE_EXCEPTION:
473       sig = SIGILL;
474       break;
475
476     case STATUS_TIMEOUT:
477       sig = SIGALRM;
478       break;
479
480     case STATUS_ACCESS_VIOLATION:
481     case STATUS_DATATYPE_MISALIGNMENT:
482     case STATUS_ARRAY_BOUNDS_EXCEEDED:
483     case STATUS_GUARD_PAGE_VIOLATION:
484     case STATUS_IN_PAGE_ERROR:
485     case STATUS_NO_MEMORY:
486     case STATUS_INVALID_DISPOSITION:
487     case STATUS_STACK_OVERFLOW:
488       sig = SIGSEGV;
489       break;
490
491     case STATUS_CONTROL_C_EXIT:
492       sig = SIGINT;
493       break;
494
495     case STATUS_INVALID_HANDLE:
496       /* CloseHandle will throw this exception if it is given an
497          invalid handle.  We don't care about the exception; we just
498          want CloseHandle to return an error.  This can be revisited
499          if gcc ever supports Windows style structured exception
500          handling.  */
501       return 0;
502
503     default:
504       /* If we don't recognize the exception, we have to assume that
505          we are doing structured exception handling, and we let
506          something else handle it.  */
507       return 1;
508     }
509
510   debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
511   debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in->Eip);
512
513   if (myself->getsig(sig).sa_mask & SIGTOMASK (sig))
514     syscall_printf ("signal %d, masked %p", sig, myself->getsig(sig).sa_mask);
515
516   if (!myself->progname[0]
517       || (void *) myself->getsig(sig).sa_handler == (void *) SIG_DFL
518       || (void *) myself->getsig(sig).sa_handler == (void *) SIG_IGN
519       || (void *) myself->getsig(sig).sa_handler == (void *) SIG_ERR)
520     {
521       static NO_COPY int traced = 0;
522
523       /* Print the exception to the console */
524       if (e)
525         {
526           for (int i = 0; status_info[i].name; i++)
527             {
528               if (status_info[i].code == e->ExceptionCode)
529                 {
530                   system_printf ("Exception: %s", status_info[i].name);
531                   break;
532                 }
533             }
534         }
535
536       /* Another exception could happen while tracing or while exiting.
537          Only do this once.  */
538       if (traced++)
539         system_printf ("Error while dumping state (probably corrupted stack)");
540       else
541         {
542           HANDLE hthread;
543           DuplicateHandle (hMainProc, GetCurrentThread (),
544                            hMainProc, &hthread, 0, FALSE, DUPLICATE_SAME_ACCESS);
545           stackdump (hMainProc, hthread, e, in);
546         }
547       try_to_debug ();
548       really_exit (EXIT_SIGNAL | sig);
549     }
550
551   debug_printf ("In cygwin_except_handler calling %p",
552                  myself->getsig(sig).sa_handler);
553
554   DWORD *bp = (DWORD *)in->Esp;
555   for (DWORD *bpend = bp - 8; bp > bpend; bp--)
556     if (*bp == in->SegCs && bp[-1] == in->Eip)
557       {
558         bp -= 2;
559         break;
560       }
561
562   in->Ebp = (DWORD) bp;
563   sigsave.cx = in;
564   sig_send (NULL, sig);         // Signal myself
565   sigsave.cx = NULL;
566   return 0;
567 }
568 #endif /* __i386__ */
569
570 #ifndef HAVE_STACK_TRACE
571 void
572 stack (void)
573 {
574   system_printf ("Stack trace not yet supported on this machine.");
575 }
576 #endif
577 }
578
579 /* Utilities to call a user supplied exception handler.  */
580
581 #define SIG_NONMASKABLE (SIGTOMASK (SIGCONT) | SIGTOMASK (SIGKILL) | SIGTOMASK (SIGSTOP))
582
583 #ifdef __i386__
584 #define HAVE_CALL_HANDLER
585
586 /* Non-raceable sigsuspend
587  * Note: This implementation is based on the Single UNIX Specification
588  * man page.  This indicates that sigsuspend always returns -1 and that
589  * attempts to block unblockable signals will be silently ignored.
590  * This is counter to what appears to be documented in some UNIX
591  * man pages, e.g. Linux.
592  */
593 int __stdcall
594 handle_sigsuspend (sigset_t tempmask)
595 {
596   sigset_t oldmask = myself->getsigmask ();     // Remember for restoration
597
598   set_process_mask (tempmask & ~SIG_NONMASKABLE);// Let signals we're
599                                 //  interested in through.
600   sigproc_printf ("old mask %x, new mask %x", oldmask, tempmask);
601
602   WaitForSingleObject (signal_arrived, INFINITE);
603
604   set_sig_errno (EINTR);        // Per POSIX
605
606   /* A signal dispatch function will have been added to our stack and will
607      be hit eventually.  Set the old mask to be restored when the signal
608      handler returns. */
609
610   sigsave.oldmask = oldmask;    // Will be restored by signal handler
611   return -1;
612 }
613
614 extern DWORD exec_exit;         // Possible exit value for exec
615 extern int pending_signals;
616
617 int
618 interruptible (DWORD pc)
619 {
620 #if 0
621   DWORD pchigh = pc & 0xf0000000;
622   return ((pc >= (DWORD) &__sigfirst) && (pc <= (DWORD) &__siglast)) ||
623          !(pchigh == 0xb0000000 || pchigh == 0x70000000 || pchigh == 0x60000000);
624 #else
625   int res = 1;
626   if ((pc >= (DWORD) &__sigfirst) && (pc <= (DWORD) &__siglast))
627     res = 0;
628   else
629     {
630       MEMORY_BASIC_INFORMATION m;
631       memset (&m, 0, sizeof m);
632       if (!VirtualQuery ((LPCVOID) pc, &m, sizeof m))
633         sigproc_printf ("couldn't get memory info, %E");
634
635       char *checkdir = (char *) alloca (windows_system_directory_length);
636 #     define h ((HMODULE) m.AllocationBase)
637       if (h == cygwin_hmodule)
638         res = 0;
639       else if (!GetModuleFileName (h, checkdir, windows_system_directory_length))
640         res = 0;
641       else
642         res = !strncasematch (windows_system_directory, checkdir,
643                               windows_system_directory_length);
644     }
645
646   sigproc_printf ("interruptible %d", res);
647   return res;
648 # undef h
649 #endif
650 }
651
652 static void __stdcall
653 interrupt_setup (int sig, struct sigaction& siga, void *handler, DWORD retaddr)
654 {
655   sigsave.retaddr = retaddr;
656   sigsave.oldmask = myself->getsigmask ();      // Remember for restoration
657   /* FIXME: Not multi-thread aware */
658   set_process_mask (myself->getsigmask () | siga.sa_mask | SIGTOMASK (sig));
659   sigsave.func = (void (*)(int)) handler;
660   sigsave.sig = sig;
661   sigsave.saved_errno = -1;             // Flag: no errno to save
662 }
663
664 static void
665 interrupt_now (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler)
666 {
667   interrupt_setup (sig, siga, handler, ctx->Eip);
668   ctx->Eip = (DWORD) sigdelayed;
669   SetThreadContext (myself->getthread2signal(), ctx); /* Restart the thread */
670 }
671
672 static int
673 interrupt_on_return (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler)
674 {
675   int i;
676
677   if (sigsave.sig)
678     return 0;   /* Already have a signal stacked up */
679
680   /* Set this up if it's the first time. */
681   /* FIXME: Eventually augment to handle more than one thread */
682   if (!thestack)
683     thestack = new stack_info (oldstack, hMainProc, hMainThread);
684
685   thestack->init (ctx);  /* Initialize from the input CONTEXT */
686   for (i = 0; i < 32 && (*thestack)++ ; i++)
687     if (interruptible (thestack->sf.AddrReturn.Offset))
688       {
689         DWORD *addr_retaddr = ((DWORD *)thestack->sf.AddrFrame.Offset) + 1;
690         if (*addr_retaddr  == thestack->sf.AddrReturn.Offset)
691           {
692             interrupt_setup (sig, siga, handler, *addr_retaddr);
693             *addr_retaddr = (DWORD) sigdelayed;
694           }
695         break;
696       }
697
698   return 1;
699 }
700
701 extern "C" void __stdcall
702 set_sig_errno (int e)
703 {
704   set_errno (e);
705   sigsave.saved_errno = e;
706   debug_printf ("errno %d", e);
707 }
708
709 static int
710 call_handler (int sig, struct sigaction& siga, void *handler)
711 {
712   CONTEXT *cx, orig;
713   int interrupted = 1;
714   HANDLE hth;
715   int res;
716
717   if (hExeced != NULL && hExeced != INVALID_HANDLE_VALUE)
718     {
719       SetEvent (signal_arrived);        // For an EINTR case
720       sigproc_printf ("armed signal_arrived");
721       exec_exit = sig;                  // Maybe we'll exit with this value
722       goto out1;
723     }
724   hth = myself->getthread2signal ();
725
726   /* Suspend the thread which will receive the signal.  But first ensure that
727      this thread doesn't have the sync_proc_subproc and mask_sync mutos, since
728      we need those (hack alert).  If the thread-to-be-suspended has either of
729      these mutos, enter a busy loop until it is released.  If the thread is
730      already suspended (which should never occur) then just queue the signal. */
731   for (;;)
732     {
733       sigproc_printf ("suspending mainthread");
734       res = SuspendThread (hth);
735
736       /* FIXME: Make multi-thread aware */
737       for (muto *m = muto_start.next;  m != NULL; m = m->next)
738         if (m->unstable () || m->owner () == maintid)
739           goto keep_looping;
740
741       break;
742
743     keep_looping:
744       sigproc_printf ("suspended thread owns a muto");
745       if (res)
746           goto set_pending;
747
748       ResumeThread (hth);
749       Sleep (0);
750     }
751
752   sigproc_printf ("SuspendThread returned %d", res);
753
754   if (sigsave.cx)
755     {
756       cx = sigsave.cx;
757       sigsave.cx = NULL;
758     }
759   else
760     {
761       cx = &orig;
762       /* FIXME - this does not preserve FPU state */
763       orig.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
764       if (!GetThreadContext (hth, cx))
765         {
766           system_printf ("couldn't get context of main thread, %E");
767           goto out;
768         }
769     }
770
771   if (cx == &orig && interruptible (cx->Eip))
772     interrupt_now (cx, sig, siga, handler);
773   else if (!interrupt_on_return (cx, sig, siga, handler))
774     {
775     set_pending:
776       pending_signals = 1;      /* FIXME: Probably need to be more tricky here */
777       sig_set_pending (sig);
778       interrupted = 0;
779     }
780
781   if (interrupted)
782     {
783       (void) SetEvent (signal_arrived); // For an EINTR case
784       sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res);
785       /* Clear any waiting threads prior to dispatching to handler function */
786       proc_subproc(PROC_CLEARWAIT, 1);
787     }
788
789 out:
790   res = ResumeThread (hth);
791   sigproc_printf ("ResumeThread returned %d", res);
792
793 out1:
794   sigproc_printf ("returning %d", interrupted);
795   return interrupted;
796 }
797 #endif /* i386 */
798
799 #ifndef HAVE_CALL_HANDLER
800 #error "Need to supply machine dependent call_handler"
801 #endif
802
803 /* Keyboard interrupt handler.  */
804 static BOOL WINAPI
805 ctrl_c_handler (DWORD type)
806 {
807   if (type == CTRL_LOGOFF_EVENT)
808     return TRUE;
809
810   /* Wait for sigproc_init to tell us that it's safe to send something.
811      This event will always be in a signalled state when wait_sig is
812      ready to process signals. */
813   (void) WaitForSingleObject (console_handler_thread_waiter, 5000);
814
815   if ((type == CTRL_CLOSE_EVENT) || (type == CTRL_SHUTDOWN_EVENT))
816     /* Return FALSE to prevent an "End task" dialog box from appearing
817        for each Cygwin process window that's open when the computer
818        is shut down or console window is closed. */
819     {
820       sig_send (NULL, SIGHUP);
821       return FALSE;
822     }
823   tty_min *t = cygwin_shared->tty.get_tty(myself->ctty);
824   /* Ignore this if we're not the process group lead since it should be handled
825      *by* the process group leader. */
826   if (t->getpgid () != myself->pid ||
827       (GetTickCount () - t->last_ctrl_c) < MIN_CTRL_C_SLOP)
828     return TRUE;
829   else
830     /* Otherwise we just send a SIGINT to the process group and return TRUE (to indicate
831        that we have handled the signal).  At this point, type should be
832        a CTRL_C_EVENT or CTRL_BREAK_EVENT. */
833     {
834       t->last_ctrl_c = GetTickCount ();
835       kill (-myself->pid, SIGINT);
836       t->last_ctrl_c = GetTickCount ();
837       return TRUE;
838     }
839 }
840
841 /* Set the signal mask for this process.
842  * Note that some signals are unmaskable, as in UNIX.
843  */
844 extern "C" void __stdcall
845 set_process_mask (sigset_t newmask)
846 {
847   extern DWORD sigtid;
848
849   mask_sync->acquire (INFINITE);
850   sigset_t oldmask = myself->getsigmask ();
851   newmask &= ~SIG_NONMASKABLE;
852   sigproc_printf ("old mask = %x, new mask = %x", myself->getsigmask (), newmask);
853   myself->setsigmask (newmask); // Set a new mask
854   mask_sync->release ();
855   if (oldmask != newmask && GetCurrentThreadId () != sigtid)
856     sig_dispatch_pending ();
857   return;
858 }
859
860 extern "C" {
861 static void
862 sig_handle_tty_stop (int sig)
863 {
864 #if 0
865   HANDLE waitbuf[2];
866
867   /* Be sure that process's main thread isn't an owner of vital
868      mutex to prevent cygwin subsystem lockups */
869   waitbuf[0] = pinfo_mutex;
870   waitbuf[1] = title_mutex;
871   WaitForMultipleObjects (2, waitbuf, TRUE, INFINITE);
872   ReleaseMutex (pinfo_mutex);
873   ReleaseMutex (title_mutex);
874 #endif
875   myself->stopsig = sig;
876   myself->process_state |= PID_STOPPED;
877   /* See if we have a living parent.  If so, send it a special signal.
878    * It will figure out exactly which pid has stopped by scanning
879    * its list of subprocesses.
880    */
881   if (my_parent_is_alive ())
882     {
883       pinfo *parent = procinfo(myself->ppid);
884       sig_send (parent, __SIGCHILDSTOPPED);
885     }
886   sigproc_printf ("process %d stopped by signal %d, parent_alive %p",
887                   myself->pid, sig, parent_alive);
888   /* There is a small race here with the above two mutexes */
889   SuspendThread (hMainThread);
890   return;
891 }
892 }
893
894 int __stdcall
895 sig_handle (int sig)
896 {
897   int rc = 0;
898
899   sigproc_printf ("signal %d", sig);
900
901   struct sigaction thissig = myself->getsig(sig);
902   void *handler = (void *) thissig.sa_handler;
903
904   myself->rusage_self.ru_nsignals++;
905
906   /* Clear pending SIGCONT on stop signals */
907   if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
908     sig_clear (SIGCONT);
909
910   if (sig == SIGKILL)
911     goto exit_sig;
912
913   if (sig == SIGSTOP)
914     goto stop;
915
916   /* FIXME: Should we still do this if SIGCONT has a handler? */
917   if (sig == SIGCONT)
918     {
919       myself->stopsig = 0;
920       myself->process_state &= ~PID_STOPPED;
921       /* Clear pending stop signals */
922       sig_clear (SIGSTOP);
923       sig_clear (SIGTSTP);
924       sig_clear (SIGTTIN);
925       sig_clear (SIGTTOU);
926       /* Windows 95 hangs on resuming non-suspended thread */
927       SuspendThread (hMainThread);
928       while (ResumeThread (hMainThread) > 1)
929         ;
930       /* process pending signals */
931       sig_dispatch_pending ();
932     }
933
934 #if 0
935   char sigmsg[24];
936   __small_sprintf (sigmsg, "cygwin: signal %d\n", sig);
937   OutputDebugString (sigmsg);
938 #endif
939
940   if (handler == (void *) SIG_DFL)
941     {
942       if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH)
943         {
944           sigproc_printf ("default signal %d ignored", sig);
945           goto done;
946         }
947
948       if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
949         goto stop;
950
951       goto exit_sig;
952     }
953
954   if (handler == (void *) SIG_IGN)
955     {
956       sigproc_printf ("signal %d ignored", sig);
957       goto done;
958     }
959
960   if (handler == (void *) SIG_ERR)
961     goto exit_sig;
962
963   if ((sig == SIGCHLD) && (thissig.sa_flags & SA_NOCLDSTOP))
964     goto done;
965
966   goto dosig;
967
968 stop:
969   handler = (void *) sig_handle_tty_stop;
970
971 dosig:
972   /* Dispatch to the appropriate function. */
973   sigproc_printf ("signal %d, about to call %p", sig, thissig.sa_handler);
974   rc = call_handler (sig, thissig, handler);
975
976 done:
977   sigproc_printf ("returning %d", rc);
978   return rc;
979
980 exit_sig:
981   if (sig == SIGQUIT || sig == SIGABRT)
982     {
983       stackdump (NULL, NULL, NULL, NULL);
984       try_to_debug ();
985     }
986   sigproc_printf ("signal %d, about to call do_exit", sig);
987   TerminateThread (hMainThread, 0);
988   /* FIXME: This just works around the problem so that we don't attempt to
989      use a resource lock when exiting.  */
990   user_data->resourcelocks->Delete();
991   user_data->resourcelocks->Init();
992   do_exit (EXIT_SIGNAL | (sig << 8));
993   /* Never returns */
994 }
995
996 /* Cover function to `do_exit' to handle exiting even in presence of more
997    exceptions.  We use to call exit, but a SIGSEGV shouldn't cause atexit
998    routines to run.  */
999
1000 static void
1001 really_exit (int rc)
1002 {
1003   /* If the exception handler gets a trap, we could recurse awhile.
1004      If this is non-zero, skip the cleaning up and exit NOW.  */
1005
1006   if (exit_already++)
1007     {
1008       /* We are going down - reset our process_state without locking. */
1009       myself->record_death (FALSE);
1010       ExitProcess (rc);
1011     }
1012
1013   do_exit (rc);
1014 }
1015
1016 HANDLE NO_COPY pinfo_mutex = NULL;
1017 HANDLE NO_COPY title_mutex = NULL;
1018
1019 void
1020 events_init (void)
1021 {
1022   /* pinfo_mutex protects access to process table */
1023
1024   if (!(pinfo_mutex = CreateMutex (&sec_all_nih, FALSE,
1025                                    shared_name ("pinfo_mutex", 0))))
1026     api_fatal ("catastrophic failure - unable to create pinfo_mutex, %E");
1027
1028   ProtectHandle (pinfo_mutex);
1029
1030   /* title_mutex protects modification of console title. It's neccessary
1031      while finding console window handle */
1032
1033   if (!(title_mutex = CreateMutex (&sec_all_nih, FALSE,
1034                                    shared_name ("title_mutex", 0))))
1035     api_fatal ("can't create title mutex, %E");
1036
1037   ProtectHandle (title_mutex);
1038   mask_sync = new_muto (FALSE, NULL);
1039   windows_system_directory[0] = '\0';
1040   (void) GetSystemDirectory (windows_system_directory, sizeof (windows_system_directory) - 2);
1041   char *end = strchr (windows_system_directory, '\0');
1042   if (end == windows_system_directory)
1043     api_fatal ("can't find windows system directory");
1044   if (end[-1] != '\\')
1045     {
1046       *end++ = '\\';
1047       *end = '\0';
1048     }
1049   windows_system_directory_length = end - windows_system_directory;
1050   debug_printf ("windows_system_directory '%s', windows_system_directory_length %d",
1051                 windows_system_directory, windows_system_directory_length);
1052   debug_printf ("cygwin_hmodule %p", cygwin_hmodule);
1053 }
1054
1055 void
1056 events_terminate (void)
1057 {
1058 //CloseHandle (pinfo_mutex);    // Use implicit close on exit to avoid race
1059   ForceCloseHandle (title_mutex);
1060   exit_already = 1;
1061 }
1062
1063 #define pid_offset (unsigned)(((pinfo *)NULL)->pid)
1064 extern "C" {
1065 static void __stdcall
1066 reset_signal_arrived () __attribute__ ((unused));
1067 static void __stdcall
1068 reset_signal_arrived ()
1069 {
1070   (void) ResetEvent (signal_arrived);
1071   sigproc_printf ("reset signal_arrived");
1072 }
1073
1074 void unused_sig_wrapper()
1075 {
1076 /* Signal cleanup stuff.  Cleans up stack (too bad that we didn't
1077    prototype signal handlers as __stdcall), calls _set_process_mask
1078    to restore any mask, restores any potentially clobbered registered
1079    and returns to orignal caller. */
1080 __asm__ volatile ("
1081         .text
1082         .globl  __raise
1083 __raise:
1084         pushl   %%ebp
1085         movl    %%esp,%%ebp
1086         movl    8(%%ebp),%%eax
1087         pushl   %%eax
1088         movl    $_myself,%%eax
1089         pushl   %6(%%eax)
1090         call    __kill
1091         mov     %%ebp,%%esp
1092         popl    %%ebp
1093         ret
1094
1095 _sigreturn:
1096         addl    $4,%%esp
1097         call    _set_process_mask@4
1098         popl    %%eax           # saved errno
1099         testl   %%eax,%%eax     # Is it < 0
1100         jl      1f              # yup.  ignore it
1101         movl    %1,%%ebx
1102         movl    %%eax,(%%ebx)
1103 1:      popl    %%eax
1104         popl    %%ebx
1105         popl    %%ecx
1106         popl    %%edx
1107         popl    %%edi
1108         popl    %%esi
1109         popf
1110         ret
1111
1112 _sigdelayed:
1113         pushl   %2      # original return address
1114         pushf
1115         pushl   %%esi
1116         pushl   %%edi
1117         pushl   %%edx
1118         pushl   %%ecx
1119         pushl   %%ebx
1120         pushl   %%eax
1121         pushl   %7      # saved errno
1122         pushl   %3      # oldmask
1123         pushl   %4      # signal argument
1124         pushl   $_sigreturn
1125
1126         call    _reset_signal_arrived@0
1127 #       pushl   _signal_arrived # Everybody waiting for this should
1128 #       call    _ResetEvent@4   # have woken up by now.
1129         movl    $0,%0
1130
1131         cmpl    $0,_pending_signals
1132         je      2f
1133 ___sigfirst:
1134         pushl   $0
1135         call    _sig_dispatch_pending@4
1136 ___siglast:
1137
1138 2:      jmp     *%5
1139
1140 " : "=m" (sigsave.sig) : "m" (&_impure_ptr->_errno),
1141   "g" (sigsave.retaddr), "g" (sigsave.oldmask), "g" (sigsave.sig),
1142     "g" (sigsave.func), "o" (pid_offset), "g" (sigsave.saved_errno)
1143   );
1144 }
1145 }