]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/exceptions.cc
db18f7ae4a96c1b649bc4f098e3559fd8d8192d8
[newlib-cygwin.git] / winsup / cygwin / exceptions.cc
1 /* exceptions.cc
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #define CYGTLS_HANDLE
13 #include "winsup.h"
14 #include "miscfuncs.h"
15 #include <wingdi.h>
16 #include <winuser.h>
17 #include <imagehlp.h>
18 #include <stdlib.h>
19 #include <syslog.h>
20 #include <wchar.h>
21
22 #include "pinfo.h"
23 #include "cygtls.h"
24 #include "sigproc.h"
25 #include "shared_info.h"
26 #include "perprocess.h"
27 #include "path.h"
28 #include "fhandler.h"
29 #include "dtable.h"
30 #include "cygheap.h"
31 #include "child_info.h"
32 #include "ntdll.h"
33 #include "exception.h"
34
35 #define CALL_HANDLER_RETRY 20
36
37 char debugger_command[2 * NT_MAX_PATH + 20];
38
39 extern "C" {
40 extern void sigdelayed ();
41 };
42
43 extern child_info_spawn *chExeced;
44
45 static BOOL WINAPI ctrl_c_handler (DWORD);
46
47 /* This is set to indicate that we have already exited. */
48
49 static NO_COPY int exit_already = 0;
50 static muto NO_COPY mask_sync;
51
52 NO_COPY static struct
53 {
54 unsigned int code;
55 const char *name;
56 } status_info[] =
57 {
58 #define X(s) s, #s
59 { X (STATUS_ABANDONED_WAIT_0) },
60 { X (STATUS_ACCESS_VIOLATION) },
61 { X (STATUS_ARRAY_BOUNDS_EXCEEDED) },
62 { X (STATUS_BREAKPOINT) },
63 { X (STATUS_CONTROL_C_EXIT) },
64 { X (STATUS_DATATYPE_MISALIGNMENT) },
65 { X (STATUS_FLOAT_DENORMAL_OPERAND) },
66 { X (STATUS_FLOAT_DIVIDE_BY_ZERO) },
67 { X (STATUS_FLOAT_INEXACT_RESULT) },
68 { X (STATUS_FLOAT_INVALID_OPERATION) },
69 { X (STATUS_FLOAT_OVERFLOW) },
70 { X (STATUS_FLOAT_STACK_CHECK) },
71 { X (STATUS_FLOAT_UNDERFLOW) },
72 { X (STATUS_GUARD_PAGE_VIOLATION) },
73 { X (STATUS_ILLEGAL_INSTRUCTION) },
74 { X (STATUS_INTEGER_DIVIDE_BY_ZERO) },
75 { X (STATUS_INTEGER_OVERFLOW) },
76 { X (STATUS_INVALID_DISPOSITION) },
77 { X (STATUS_IN_PAGE_ERROR) },
78 { X (STATUS_NONCONTINUABLE_EXCEPTION) },
79 { X (STATUS_NO_MEMORY) },
80 { X (STATUS_PENDING) },
81 { X (STATUS_PRIVILEGED_INSTRUCTION) },
82 { X (STATUS_SINGLE_STEP) },
83 { X (STATUS_STACK_OVERFLOW) },
84 { X (STATUS_TIMEOUT) },
85 { X (STATUS_USER_APC) },
86 { X (STATUS_WAIT_0) },
87 { 0, 0 }
88 #undef X
89 };
90
91 /* Initialization code. */
92
93 void
94 init_console_handler (bool install_handler)
95 {
96 BOOL res;
97
98 SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
99 SetConsoleCtrlHandler (NULL, FALSE);
100 if (install_handler)
101 res = SetConsoleCtrlHandler (ctrl_c_handler, TRUE);
102 else
103 res = SetConsoleCtrlHandler (NULL, TRUE);
104 if (!res)
105 system_printf ("SetConsoleCtrlHandler failed, %E");
106 }
107
108 extern "C" void
109 error_start_init (const char *buf)
110 {
111 if (!buf || !*buf)
112 {
113 debugger_command[0] = '\0';
114 return;
115 }
116
117 char pgm[NT_MAX_PATH];
118 if (!GetModuleFileName (NULL, pgm, NT_MAX_PATH))
119 strcpy (pgm, "cygwin1.dll");
120 for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\'))
121 *p = '/';
122
123 __small_sprintf (debugger_command, "%s \"%s\"", buf, pgm);
124 }
125
126 static void
127 open_stackdumpfile ()
128 {
129 /* If we have no executable name, or if the CWD handle is NULL,
130 which means, the CWD is a virtual path, don't even try to open
131 a stackdump file. */
132 if (myself->progname[0] && cygheap->cwd.get_handle ())
133 {
134 const WCHAR *p;
135 /* write to progname.stackdump if possible */
136 if (!myself->progname[0])
137 p = L"unknown";
138 else if ((p = wcsrchr (myself->progname, L'\\')))
139 p++;
140 else
141 p = myself->progname;
142
143 WCHAR corefile[wcslen (p) + sizeof (".stackdump")];
144 wcpcpy (wcpcpy(corefile, p), L".stackdump");
145 UNICODE_STRING ucore;
146 OBJECT_ATTRIBUTES attr;
147 /* Create the UNICODE variation of <progname>.stackdump. */
148 RtlInitUnicodeString (&ucore, corefile);
149 /* Create an object attribute which refers to <progname>.stackdump
150 in Cygwin's cwd. Stick to caseinsensitivity. */
151 InitializeObjectAttributes (&attr, &ucore, OBJ_CASE_INSENSITIVE,
152 cygheap->cwd.get_handle (), NULL);
153 HANDLE h;
154 IO_STATUS_BLOCK io;
155 NTSTATUS status;
156 /* Try to open it to dump the stack in it. */
157 status = NtCreateFile (&h, GENERIC_WRITE | SYNCHRONIZE, &attr, &io,
158 NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
159 FILE_SYNCHRONOUS_IO_NONALERT
160 | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0);
161 if (NT_SUCCESS (status))
162 {
163 if (!myself->cygstarted)
164 system_printf ("Dumping stack trace to %S", &ucore);
165 else
166 debug_printf ("Dumping stack trace to %S", &ucore);
167 SetStdHandle (STD_ERROR_HANDLE, h);
168 }
169 }
170 }
171
172 /* Utilities for dumping the stack, etc. */
173
174 static void
175 dump_exception (EXCEPTION_RECORD *e, CONTEXT *in)
176 {
177 const char *exception_name = NULL;
178
179 if (e)
180 {
181 for (int i = 0; status_info[i].name; i++)
182 {
183 if (status_info[i].code == e->ExceptionCode)
184 {
185 exception_name = status_info[i].name;
186 break;
187 }
188 }
189 }
190
191 if (exception_name)
192 small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip);
193 else
194 small_printf ("Signal %d at eip=%08x\r\n", e->ExceptionCode, in->Eip);
195 small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n",
196 in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi);
197 small_printf ("ebp=%08x esp=%08x program=%W, pid %u, thread %s\r\n",
198 in->Ebp, in->Esp, myself->progname, myself->pid, cygthread::name ());
199 small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n",
200 in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs);
201 }
202
203 /* A class for manipulating the stack. */
204 class stack_info
205 {
206 int walk (); /* Uses the "old" method */
207 char *next_offset () {return *((char **) sf.AddrFrame.Offset);}
208 bool needargs;
209 DWORD dummy_frame;
210 public:
211 STACKFRAME sf; /* For storing the stack information */
212 void init (DWORD, bool, bool); /* Called the first time that stack info is needed */
213
214 /* Postfix ++ iterates over the stack, returning zero when nothing is left. */
215 int operator ++(int) { return walk (); }
216 };
217
218 /* The number of parameters used in STACKFRAME */
219 #define NPARAMS (sizeof (thestack.sf.Params) / sizeof (thestack.sf.Params[0]))
220
221 /* This is the main stack frame info for this process. */
222 static NO_COPY stack_info thestack;
223
224 /* Initialize everything needed to start iterating. */
225 void
226 stack_info::init (DWORD ebp, bool wantargs, bool goodframe)
227 {
228 # define debp ((DWORD *) ebp)
229 memset (&sf, 0, sizeof (sf));
230 if (!goodframe)
231 sf.AddrFrame.Offset = ebp;
232 else
233 {
234 dummy_frame = ebp;
235 sf.AddrFrame.Offset = (DWORD) &dummy_frame;
236 }
237 sf.AddrReturn.Offset = debp[1];
238 sf.AddrFrame.Mode = AddrModeFlat;
239 needargs = wantargs;
240 # undef debp
241 }
242
243 extern "C" void _cygwin_exit_return ();
244
245 /* Walk the stack by looking at successive stored 'bp' frames.
246 This is not foolproof. */
247 int
248 stack_info::walk ()
249 {
250 char **ebp;
251
252 if ((void (*) ()) sf.AddrPC.Offset == _cygwin_exit_return)
253 return 0; /* stack frames are exhausted */
254
255 if (((ebp = (char **) next_offset ()) == NULL) || (ebp >= (char **) cygwin_hmodule))
256 return 0;
257
258 sf.AddrFrame.Offset = (DWORD) ebp;
259 sf.AddrPC.Offset = sf.AddrReturn.Offset;
260
261 /* The return address always follows the stack pointer */
262 sf.AddrReturn.Offset = (DWORD) *++ebp;
263
264 if (needargs)
265 {
266 unsigned nparams = NPARAMS;
267
268 /* The arguments follow the return address */
269 sf.Params[0] = (DWORD) *++ebp;
270 /* Hack for XP/2K3 WOW64. If the first stack param points to the
271 application entry point, we can only fetch one additional
272 parameter. Accessing anything beyond this address results in
273 a SEGV. This is fixed in Vista/2K8 WOW64. */
274 if (wincap.has_restricted_stack_args () && sf.Params[0] == 0x401000)
275 nparams = 2;
276 for (unsigned i = 1; i < nparams; i++)
277 sf.Params[i] = (DWORD) *++ebp;
278 }
279
280 return 1;
281 }
282
283 static void
284 stackdump (DWORD ebp, int open_file, bool isexception)
285 {
286 static bool already_dumped;
287
288 if (cygheap->rlim_core == 0UL || (open_file && already_dumped))
289 return;
290
291 if (open_file)
292 open_stackdumpfile ();
293
294 already_dumped = true;
295
296 int i;
297
298 thestack.init (ebp, 1, !isexception); /* Initialize from the input CONTEXT */
299 small_printf ("Stack trace:\r\nFrame Function Args\r\n");
300 for (i = 0; i < 16 && thestack++; i++)
301 {
302 small_printf ("%08x %08x ", thestack.sf.AddrFrame.Offset,
303 thestack.sf.AddrPC.Offset);
304 for (unsigned j = 0; j < NPARAMS; j++)
305 small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]);
306 small_printf (")\r\n");
307 }
308 small_printf ("End of stack trace%s\n",
309 i == 16 ? " (more stack frames may be present)" : "");
310 }
311
312 bool
313 _cygtls::inside_kernel (CONTEXT *cx)
314 {
315 int res;
316 MEMORY_BASIC_INFORMATION m;
317
318 if (!isinitialized ())
319 return true;
320
321 memset (&m, 0, sizeof m);
322 if (!VirtualQuery ((LPCVOID) cx->Eip, &m, sizeof m))
323 sigproc_printf ("couldn't get memory info, pc %p, %E", cx->Eip);
324
325 size_t size = (windows_system_directory_length + 6) * sizeof (WCHAR);
326 PWCHAR checkdir = (PWCHAR) alloca (size);
327 memset (checkdir, 0, size);
328
329 # define h ((HMODULE) m.AllocationBase)
330 /* Apparently Windows 95 can sometimes return bogus addresses from
331 GetThreadContext. These resolve to a strange allocation base.
332 These should *never* be treated as interruptible. */
333 if (!h || m.State != MEM_COMMIT)
334 res = true;
335 else if (h == user_data->hmodule)
336 res = false;
337 else if (!GetModuleFileNameW (h, checkdir, windows_system_directory_length + 6))
338 res = false;
339 else
340 {
341 /* Skip potential long path prefix. */
342 if (!wcsncmp (checkdir, L"\\\\?\\", 4))
343 checkdir += 4;
344 res = !wcsncasecmp (windows_system_directory, checkdir,
345 windows_system_directory_length);
346 }
347 sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->Eip, h, res);
348 # undef h
349 return res;
350 }
351
352 /* Temporary (?) function for external callers to get a stack dump */
353 extern "C" void
354 cygwin_stackdump ()
355 {
356 CONTEXT c;
357 c.ContextFlags = CONTEXT_FULL;
358 GetThreadContext (GetCurrentThread (), &c);
359 stackdump (c.Ebp, 0, 0);
360 }
361
362 #define TIME_TO_WAIT_FOR_DEBUGGER 10000
363
364 extern "C" int
365 try_to_debug (bool waitloop)
366 {
367 debug_printf ("debugger_command '%s'", debugger_command);
368 if (*debugger_command == '\0')
369 return 0;
370 if (being_debugged ())
371 {
372 extern void break_here ();
373 break_here ();
374 return 0;
375 }
376
377 __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());
378
379 LONG prio = GetThreadPriority (GetCurrentThread ());
380 SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
381 PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
382
383 STARTUPINFOW si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
384 si.lpReserved = NULL;
385 si.lpDesktop = NULL;
386 si.dwFlags = 0;
387 si.cb = sizeof (si);
388
389 /* FIXME: need to know handles of all running threads to
390 suspend_all_threads_except (current_thread_id);
391 */
392
393 /* if any of these mutexes is owned, we will fail to start any cygwin app
394 until trapped app exits */
395
396 lock_ttys::release ();
397
398 /* prevent recursive exception handling */
399 PWCHAR rawenv = GetEnvironmentStringsW () ;
400 for (PWCHAR p = rawenv; *p != L'\0'; p = wcschr (p, L'\0') + 1)
401 {
402 if (wcsncmp (p, L"CYGWIN=", wcslen (L"CYGWIN=")) == 0)
403 {
404 PWCHAR q = wcsstr (p, L"error_start") ;
405 /* replace 'error_start=...' with '_rror_start=...' */
406 if (q)
407 {
408 *q = L'_' ;
409 SetEnvironmentVariableW (L"CYGWIN", p + wcslen (L"CYGWIN=")) ;
410 }
411 break ;
412 }
413 }
414
415 console_printf ("*** starting debugger for pid %u, tid %u\n",
416 cygwin_pid (GetCurrentProcessId ()), GetCurrentThreadId ());
417 BOOL dbg;
418 WCHAR dbg_cmd[strlen(debugger_command)];
419 sys_mbstowcs (dbg_cmd, strlen(debugger_command) + 1, debugger_command);
420 dbg = CreateProcessW (NULL,
421 dbg_cmd,
422 NULL,
423 NULL,
424 FALSE,
425 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
426 NULL,
427 NULL,
428 &si,
429 &pi);
430
431 if (!dbg)
432 system_printf ("Failed to start debugger, %E");
433 else
434 {
435 if (!waitloop)
436 return dbg;
437 SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
438 while (!being_debugged ())
439 yield ();
440 Sleep (2000);
441 }
442
443 console_printf ("*** continuing pid %u from debugger call (%d)\n",
444 cygwin_pid (GetCurrentProcessId ()), dbg);
445
446 SetThreadPriority (GetCurrentThread (), prio);
447 return dbg;
448 }
449
450 extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
451 static void __stdcall rtl_unwind (exception_list *, PEXCEPTION_RECORD) __attribute__ ((noinline, regparm (3)));
452 void __stdcall
453 rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e)
454 {
455 __asm__ ("\n\
456 pushl %%ebx \n\
457 pushl %%edi \n\
458 pushl %%esi \n\
459 pushl $0 \n\
460 pushl %1 \n\
461 pushl $1f \n\
462 pushl %0 \n\
463 call _RtlUnwind@16 \n\
464 1: \n\
465 popl %%esi \n\
466 popl %%edi \n\
467 popl %%ebx \n\
468 ": : "r" (frame), "r" (e));
469 }
470
471 /* Main exception handler. */
472
473 extern exception_list *_except_list asm ("%fs:0");
474
475 int
476 exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
477 {
478 static bool NO_COPY debugging;
479 static int NO_COPY recursed;
480 _cygtls& me = _my_tls;
481
482 if (debugging && ++debugging < 500000)
483 {
484 SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
485 return 0;
486 }
487
488 /* If we've already exited, don't do anything here. Returning 1
489 tells Windows to keep looking for an exception handler. */
490 if (exit_already || e->ExceptionFlags)
491 return 1;
492
493 siginfo_t si = {0};
494 si.si_code = SI_KERNEL;
495 /* Coerce win32 value to posix value. */
496 switch (e->ExceptionCode)
497 {
498 case STATUS_FLOAT_DENORMAL_OPERAND:
499 case STATUS_FLOAT_DIVIDE_BY_ZERO:
500 case STATUS_FLOAT_INVALID_OPERATION:
501 case STATUS_FLOAT_STACK_CHECK:
502 si.si_signo = SIGFPE;
503 si.si_code = FPE_FLTSUB;
504 break;
505 case STATUS_FLOAT_INEXACT_RESULT:
506 si.si_signo = SIGFPE;
507 si.si_code = FPE_FLTRES;
508 break;
509 case STATUS_FLOAT_OVERFLOW:
510 si.si_signo = SIGFPE;
511 si.si_code = FPE_FLTOVF;
512 break;
513 case STATUS_FLOAT_UNDERFLOW:
514 si.si_signo = SIGFPE;
515 si.si_code = FPE_FLTUND;
516 break;
517 case STATUS_INTEGER_DIVIDE_BY_ZERO:
518 si.si_signo = SIGFPE;
519 si.si_code = FPE_INTDIV;
520 break;
521 case STATUS_INTEGER_OVERFLOW:
522 si.si_signo = SIGFPE;
523 si.si_code = FPE_INTOVF;
524 break;
525
526 case STATUS_ILLEGAL_INSTRUCTION:
527 si.si_signo = SIGILL;
528 si.si_code = ILL_ILLOPC;
529 break;
530
531 case STATUS_PRIVILEGED_INSTRUCTION:
532 si.si_signo = SIGILL;
533 si.si_code = ILL_PRVOPC;
534 break;
535
536 case STATUS_NONCONTINUABLE_EXCEPTION:
537 si.si_signo = SIGILL;
538 si.si_code = ILL_ILLADR;
539 break;
540
541 case STATUS_TIMEOUT:
542 si.si_signo = SIGALRM;
543 break;
544
545 case STATUS_GUARD_PAGE_VIOLATION:
546 si.si_signo = SIGBUS;
547 si.si_code = BUS_OBJERR;
548 break;
549
550 case STATUS_DATATYPE_MISALIGNMENT:
551 si.si_signo = SIGBUS;
552 si.si_code = BUS_ADRALN;
553 break;
554
555 case STATUS_ACCESS_VIOLATION:
556 switch (mmap_is_attached_or_noreserve ((void *)e->ExceptionInformation[1],
557 1))
558 {
559 case MMAP_NORESERVE_COMMITED:
560 return 0;
561 case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or
562 access to mmap page beyond EOF. */
563 si.si_signo = SIGBUS;
564 si.si_code = BUS_OBJERR;
565 break;
566 default:
567 MEMORY_BASIC_INFORMATION m;
568 VirtualQuery ((PVOID) e->ExceptionInformation[1], &m, sizeof m);
569 si.si_signo = SIGSEGV;
570 si.si_code = m.State == MEM_FREE ? SEGV_MAPERR : SEGV_ACCERR;
571 break;
572 }
573 break;
574
575 case STATUS_ARRAY_BOUNDS_EXCEEDED:
576 case STATUS_IN_PAGE_ERROR:
577 case STATUS_NO_MEMORY:
578 case STATUS_INVALID_DISPOSITION:
579 case STATUS_STACK_OVERFLOW:
580 si.si_signo = SIGSEGV;
581 si.si_code = SEGV_MAPERR;
582 break;
583
584 case STATUS_CONTROL_C_EXIT:
585 si.si_signo = SIGINT;
586 break;
587
588 case STATUS_INVALID_HANDLE:
589 /* CloseHandle will throw this exception if it is given an
590 invalid handle. We don't care about the exception; we just
591 want CloseHandle to return an error. This can be revisited
592 if gcc ever supports Windows style structured exception
593 handling. */
594 return 0;
595
596 default:
597 /* If we don't recognize the exception, we have to assume that
598 we are doing structured exception handling, and we let
599 something else handle it. */
600 return 1;
601 }
602
603 debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
604 debug_printf ("In cygwin_except_handler sig %d at %p", si.si_signo, in->Eip);
605
606 bool masked = !!(me.sigmask & SIGTOMASK (si.si_signo));
607 if (masked)
608 syscall_printf ("signal %d, masked %p", si.si_signo,
609 global_sigs[si.si_signo].sa_mask);
610
611 debug_printf ("In cygwin_except_handler calling %p",
612 global_sigs[si.si_signo].sa_handler);
613
614 DWORD *ebp = (DWORD *) in->Esp;
615 for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--)
616 if (*ebp == in->SegCs && ebp[-1] == in->Eip)
617 {
618 ebp -= 2;
619 break;
620 }
621
622 if (me.andreas)
623 me.andreas->leave (); /* Return from a "san" caught fault */
624
625 me.copy_context (in);
626
627 /* Temporarily replace windows top level SEH with our own handler.
628 We don't want any Windows magic kicking in. This top level frame
629 will be removed automatically after our exception handler returns. */
630 _except_list->handler = handle;
631
632 if (masked
633 || &me == _sig_tls
634 || !cygwin_finished_initializing
635 || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL
636 || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN
637 || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR)
638 {
639 /* Print the exception to the console */
640 if (!myself->cygstarted)
641 for (int i = 0; status_info[i].name; i++)
642 if (status_info[i].code == e->ExceptionCode)
643 {
644 system_printf ("Exception: %s", status_info[i].name);
645 break;
646 }
647
648 /* Another exception could happen while tracing or while exiting.
649 Only do this once. */
650 if (recursed++)
651 system_printf ("Error while dumping state (probably corrupted stack)");
652 else
653 {
654 if (try_to_debug (0))
655 {
656 debugging = true;
657 return 0;
658 }
659
660 rtl_unwind (frame, e);
661 if (cygheap->rlim_core > 0UL)
662 {
663 open_stackdumpfile ();
664 dump_exception (e, in);
665 stackdump ((DWORD) ebp, 0, 1);
666 }
667 }
668
669 if (e->ExceptionCode == STATUS_ACCESS_VIOLATION)
670 {
671 int error_code = 0;
672 if (si.si_code == SEGV_ACCERR) /* Address present */
673 error_code |= 1;
674 if (e->ExceptionInformation[0]) /* Write access */
675 error_code |= 2;
676 if (!me.inside_kernel (in)) /* User space */
677 error_code |= 4;
678 klog (LOG_INFO, "%s[%d]: segfault at %08x rip %08x rsp %08x error %d",
679 __progname, myself->pid,
680 e->ExceptionInformation[1], in->Eip, in->Esp,
681 ((in->Eip >= 0x61000000 && in->Eip < 0x61200000)
682 ? 0 : 4) | (e->ExceptionInformation[0] << 1));
683 }
684
685 /* Flag signal + core dump */
686 me.signal_exit ((cygheap->rlim_core > 0UL ? 0x80 : 0) | si.si_signo);
687 }
688
689 si.si_addr = (si.si_signo == SIGSEGV || si.si_signo == SIGBUS
690 ? (void *) e->ExceptionInformation[1]
691 : (void *) in->Eip);
692 si.si_errno = si.si_pid = si.si_uid = 0;
693 me.incyg++;
694 sig_send (NULL, si, &me); // Signal myself
695 me.incyg--;
696 e->ExceptionFlags = 0;
697 return 0;
698 }
699
700 /* Utilities to call a user supplied exception handler. */
701
702 #define SIG_NONMASKABLE (SIGTOMASK (SIGKILL) | SIGTOMASK (SIGSTOP))
703
704 /* Non-raceable sigsuspend
705 * Note: This implementation is based on the Single UNIX Specification
706 * man page. This indicates that sigsuspend always returns -1 and that
707 * attempts to block unblockable signals will be silently ignored.
708 * This is counter to what appears to be documented in some UNIX
709 * man pages, e.g. Linux.
710 */
711 int __stdcall
712 handle_sigsuspend (sigset_t tempmask)
713 {
714 if (&_my_tls != _main_tls)
715 {
716 cancelable_wait (signal_arrived, INFINITE, cw_cancel_self);
717 return -1;
718 }
719
720 sigset_t oldmask = _my_tls.sigmask; // Remember for restoration
721
722 set_signal_mask (tempmask, _my_tls.sigmask);
723 sigproc_printf ("oldmask %p, newmask %p", oldmask, tempmask);
724
725 pthread_testcancel ();
726 cancelable_wait (signal_arrived, INFINITE);
727
728 set_sig_errno (EINTR); // Per POSIX
729
730 /* A signal dispatch function will have been added to our stack and will
731 be hit eventually. Set the old mask to be restored when the signal
732 handler returns and indicate its presence by modifying deltamask. */
733
734 _my_tls.deltamask |= SIG_NONMASKABLE;
735 _my_tls.oldmask = oldmask; // Will be restored by signal handler
736 return -1;
737 }
738
739 extern DWORD exec_exit; // Possible exit value for exec
740
741 extern "C" {
742 static void
743 sig_handle_tty_stop (int sig)
744 {
745 _my_tls.incyg = 1;
746 /* Silently ignore attempts to suspend if there is no accommodating
747 cygwin parent to deal with this behavior. */
748 if (!myself->cygstarted)
749 {
750 myself->process_state &= ~PID_STOPPED;
751 return;
752 }
753
754 myself->stopsig = sig;
755 myself->alert_parent (sig);
756 sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
757 HANDLE w4[2];
758 w4[0] = sigCONT;
759 w4[1] = signal_arrived;
760 switch (WaitForMultipleObjects (2, w4, TRUE, INFINITE))
761 {
762 case WAIT_OBJECT_0:
763 case WAIT_OBJECT_0 + 1:
764 reset_signal_arrived ();
765 myself->stopsig = SIGCONT;
766 myself->alert_parent (SIGCONT);
767 break;
768 default:
769 api_fatal ("WaitSingleObject failed, %E");
770 break;
771 }
772 _my_tls.incyg = 0;
773 }
774 }
775
776 bool
777 _cygtls::interrupt_now (CONTEXT *cx, int sig, void *handler,
778 struct sigaction& siga)
779 {
780 bool interrupted;
781
782 /* Delay the interrupt if we are
783 1) somehow inside the DLL
784 2) in _sigfe (spinning is true) and about to enter cygwin DLL
785 3) in a Windows DLL. */
786 if (incyg || spinning || inside_kernel (cx))
787 interrupted = false;
788 else
789 {
790 push ((__stack_t) cx->Eip);
791 interrupt_setup (sig, handler, siga);
792 cx->Eip = pop ();
793 SetThreadContext (*this, cx); /* Restart the thread in a new location */
794 interrupted = true;
795 }
796 return interrupted;
797 }
798
799 void __stdcall
800 _cygtls::interrupt_setup (int sig, void *handler, struct sigaction& siga)
801 {
802 push ((__stack_t) sigdelayed);
803 deltamask = siga.sa_mask & ~SIG_NONMASKABLE;
804 sa_flags = siga.sa_flags;
805 func = (void (*) (int)) handler;
806 if (siga.sa_flags & SA_RESETHAND)
807 siga.sa_handler = SIG_DFL;
808 saved_errno = -1; // Flag: no errno to save
809 if (handler == sig_handle_tty_stop)
810 {
811 myself->stopsig = 0;
812 myself->process_state |= PID_STOPPED;
813 }
814
815 this->sig = sig; // Should always be last thing set to avoid a race
816
817 if (!event)
818 threadkill = false;
819 else
820 {
821 HANDLE h = event;
822 event = NULL;
823 SetEvent (h);
824 }
825
826 /* Clear any waiting threads prior to dispatching to handler function */
827 int res = SetEvent (signal_arrived); // For an EINTR case
828 proc_subproc (PROC_CLEARWAIT, 1);
829 sigproc_printf ("armed signal_arrived %p, sig %d, res %d", signal_arrived,
830 sig, res);
831 }
832
833 extern "C" void __stdcall
834 set_sig_errno (int e)
835 {
836 *_my_tls.errno_addr = e;
837 _my_tls.saved_errno = e;
838 // sigproc_printf ("errno %d", e);
839 }
840
841 static int setup_handler (int, void *, struct sigaction&, _cygtls *tls)
842 __attribute__((regparm(3)));
843 static int
844 setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls)
845 {
846 CONTEXT cx;
847 bool interrupted = false;
848
849 if (tls->sig)
850 {
851 sigproc_printf ("trying to send sig %d but signal %d already armed",
852 sig, tls->sig);
853 goto out;
854 }
855
856 for (int i = 0; i < CALL_HANDLER_RETRY; i++)
857 {
858 tls->lock ();
859 if (tls->incyg)
860 {
861 sigproc_printf ("controlled interrupt. stackptr %p, stack %p, stackptr[-1] %p",
862 tls->stackptr, tls->stack, tls->stackptr[-1]);
863 tls->interrupt_setup (sig, handler, siga);
864 interrupted = true;
865 tls->unlock ();
866 break;
867 }
868
869 DWORD res;
870 HANDLE hth = (HANDLE) *tls;
871
872 /* Suspend the thread which will receive the signal.
873 For Windows 95, we also have to ensure that the addresses returned by
874 GetThreadContext are valid.
875 If one of these conditions is not true we loop for a fixed number of times
876 since we don't want to stall the signal handler. FIXME: Will this result in
877 noticeable delays?
878 If the thread is already suspended (which can occur when a program has called
879 SuspendThread on itself) then just queue the signal. */
880
881 sigproc_printf ("suspending thread");
882 res = SuspendThread (hth);
883 /* Just set pending if thread is already suspended */
884 if (res)
885 {
886 ResumeThread (hth);
887 break;
888 }
889 cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
890 if (!GetThreadContext (hth, &cx))
891 system_printf ("couldn't get context of thread, %E");
892 else
893 interrupted = tls->interrupt_now (&cx, sig, handler, siga);
894
895 tls->unlock ();
896 res = ResumeThread (hth);
897 if (interrupted)
898 break;
899
900 sigproc_printf ("couldn't interrupt. trying again.");
901 yield ();
902 }
903
904 out:
905 sigproc_printf ("signal %d %sdelivered", sig, interrupted ? "" : "not ");
906 return interrupted;
907 }
908
909 static inline bool
910 has_visible_window_station ()
911 {
912 HWINSTA station_hdl;
913 USEROBJECTFLAGS uof;
914 DWORD len;
915
916 /* Check if the process is associated with a visible window station.
917 These are processes running on the local desktop as well as processes
918 running in terminal server sessions.
919 Processes running in a service session not explicitely associated
920 with the desktop (using the "Allow service to interact with desktop"
921 property) are running in an invisible window station. */
922 if ((station_hdl = GetProcessWindowStation ())
923 && GetUserObjectInformationW (station_hdl, UOI_FLAGS, &uof,
924 sizeof uof, &len)
925 && (uof.dwFlags & WSF_VISIBLE))
926 return true;
927 return false;
928 }
929
930 /* Keyboard interrupt handler. */
931 static BOOL WINAPI
932 ctrl_c_handler (DWORD type)
933 {
934 static bool saw_close;
935 lock_process now;
936
937 if (!cygwin_finished_initializing)
938 {
939 if (myself->cygstarted) /* Was this process created by a cygwin process? */
940 return TRUE; /* Yes. Let the parent eventually handle CTRL-C issues. */
941 debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT);
942 ExitProcess (STATUS_CONTROL_C_EXIT);
943 }
944
945 _my_tls.remove (INFINITE);
946
947 #if 0
948 if (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
949 proc_subproc (PROC_KILLFORKED, 0);
950 #endif
951
952 /* Return FALSE to prevent an "End task" dialog box from appearing
953 for each Cygwin process window that's open when the computer
954 is shut down or console window is closed. */
955
956 if (type == CTRL_SHUTDOWN_EVENT)
957 {
958 #if 0
959 /* Don't send a signal. Only NT service applications and their child
960 processes will receive this event and the services typically already
961 handle the shutdown action when getting the SERVICE_CONTROL_SHUTDOWN
962 control message. */
963 sig_send (NULL, SIGTERM);
964 #endif
965 return FALSE;
966 }
967
968 if (myself->ctty != -1)
969 {
970 if (type == CTRL_CLOSE_EVENT)
971 {
972 sig_send (NULL, SIGHUP);
973 saw_close = true;
974 return FALSE;
975 }
976 if (!saw_close && type == CTRL_LOGOFF_EVENT)
977 {
978 /* The CTRL_LOGOFF_EVENT is sent when *any* user logs off.
979 The below code sends a SIGHUP only if it is not performing the
980 default activity for SIGHUP. Note that it is possible for two
981 SIGHUP signals to arrive if a process group leader is exiting
982 too. Getting this 100% right is saved for a future cygwin mailing
983 list goad. */
984 if (global_sigs[SIGHUP].sa_handler != SIG_DFL)
985 {
986 sig_send (myself_nowait, SIGHUP);
987 return TRUE;
988 }
989 return FALSE;
990 }
991 }
992
993 if (chExeced)
994 {
995 chExeced->set_saw_ctrl_c ();
996 return TRUE;
997 }
998
999 /* We're only the process group leader when we have a valid pinfo structure.
1000 If we don't have one, then the parent "stub" will handle the signal. */
1001 if (!pinfo (cygwin_pid (GetCurrentProcessId ())))
1002 return TRUE;
1003
1004 tty_min *t = cygwin_shared->tty.get_tty (myself->ctty);
1005 /* Ignore this if we're not the process group leader since it should be handled
1006 *by* the process group leader. */
1007 if (myself->ctty != -1 && t->getpgid () == myself->pid &&
1008 (GetTickCount () - t->last_ctrl_c) >= MIN_CTRL_C_SLOP)
1009 /* Otherwise we just send a SIGINT to the process group and return TRUE (to indicate
1010 that we have handled the signal). At this point, type should be
1011 a CTRL_C_EVENT or CTRL_BREAK_EVENT. */
1012 {
1013 int sig = SIGINT;
1014 /* If intr and quit are both mapped to ^C, send SIGQUIT on ^BREAK */
1015 if (type == CTRL_BREAK_EVENT
1016 && t->ti.c_cc[VINTR] == 3 && t->ti.c_cc[VQUIT] == 3)
1017 sig = SIGQUIT;
1018 t->last_ctrl_c = GetTickCount ();
1019 killsys (-myself->pid, sig);
1020 t->last_ctrl_c = GetTickCount ();
1021 return TRUE;
1022 }
1023
1024 return TRUE;
1025 }
1026
1027 /* Function used by low level sig wrappers. */
1028 extern "C" void __stdcall
1029 set_process_mask (sigset_t newmask)
1030 {
1031 set_signal_mask (newmask, _my_tls.sigmask);
1032 }
1033
1034 extern "C" int
1035 sighold (int sig)
1036 {
1037 /* check that sig is in right range */
1038 if (sig < 0 || sig >= NSIG)
1039 {
1040 set_errno (EINVAL);
1041 syscall_printf ("signal %d out of range", sig);
1042 return -1;
1043 }
1044 mask_sync.acquire (INFINITE);
1045 sigset_t mask = _my_tls.sigmask;
1046 sigaddset (&mask, sig);
1047 set_signal_mask (mask, _my_tls.sigmask);
1048 mask_sync.release ();
1049 return 0;
1050 }
1051
1052 extern "C" int
1053 sigrelse (int sig)
1054 {
1055 /* check that sig is in right range */
1056 if (sig < 0 || sig >= NSIG)
1057 {
1058 set_errno (EINVAL);
1059 syscall_printf ("signal %d out of range", sig);
1060 return -1;
1061 }
1062 mask_sync.acquire (INFINITE);
1063 sigset_t mask = _my_tls.sigmask;
1064 sigdelset (&mask, sig);
1065 set_signal_mask (mask, _my_tls.sigmask);
1066 mask_sync.release ();
1067 return 0;
1068 }
1069
1070 extern "C" _sig_func_ptr
1071 sigset (int sig, _sig_func_ptr func)
1072 {
1073 sig_dispatch_pending ();
1074 _sig_func_ptr prev;
1075
1076 /* check that sig is in right range */
1077 if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
1078 {
1079 set_errno (EINVAL);
1080 syscall_printf ("SIG_ERR = sigset (%d, %p)", sig, func);
1081 return (_sig_func_ptr) SIG_ERR;
1082 }
1083
1084 mask_sync.acquire (INFINITE);
1085 sigset_t mask = _my_tls.sigmask;
1086 /* If sig was in the signal mask return SIG_HOLD, otherwise return the
1087 previous disposition. */
1088 if (sigismember (&mask, sig))
1089 prev = SIG_HOLD;
1090 else
1091 prev = global_sigs[sig].sa_handler;
1092 /* If func is SIG_HOLD, add sig to the signal mask, otherwise set the
1093 disposition to func and remove sig from the signal mask. */
1094 if (func == SIG_HOLD)
1095 sigaddset (&mask, sig);
1096 else
1097 {
1098 /* No error checking. The test which could return SIG_ERR has already
1099 been made above. */
1100 signal (sig, func);
1101 sigdelset (&mask, sig);
1102 }
1103 set_signal_mask (mask, _my_tls.sigmask);
1104 mask_sync.release ();
1105 return prev;
1106 }
1107
1108 extern "C" int
1109 sigignore (int sig)
1110 {
1111 return sigset (sig, SIG_IGN) == SIG_ERR ? -1 : 0;
1112 }
1113
1114 /* Update the signal mask for this process and return the old mask.
1115 Called from sigdelayed */
1116 extern "C" sigset_t
1117 set_process_mask_delta ()
1118 {
1119 mask_sync.acquire (INFINITE);
1120 sigset_t newmask, oldmask;
1121
1122 if (_my_tls.deltamask & SIG_NONMASKABLE)
1123 oldmask = _my_tls.oldmask; /* from handle_sigsuspend */
1124 else
1125 oldmask = _my_tls.sigmask;
1126 newmask = (oldmask | _my_tls.deltamask) & ~SIG_NONMASKABLE;
1127 sigproc_printf ("oldmask %p, newmask %p, deltamask %p", oldmask, newmask,
1128 _my_tls.deltamask);
1129 _my_tls.sigmask = newmask;
1130 mask_sync.release ();
1131 return oldmask;
1132 }
1133
1134 /* Set the signal mask for this process.
1135 Note that some signals are unmaskable, as in UNIX. */
1136 extern "C" void __stdcall
1137 set_signal_mask (sigset_t newmask, sigset_t& oldmask)
1138 {
1139 #ifdef CGF
1140 if (&_my_tls == _sig_tls)
1141 small_printf ("********* waiting in signal thread\n");
1142 #endif
1143 mask_sync.acquire (INFINITE);
1144 newmask &= ~SIG_NONMASKABLE;
1145 sigset_t mask_bits = oldmask & ~newmask;
1146 sigproc_printf ("oldmask %p, newmask %p, mask_bits %p", oldmask, newmask,
1147 mask_bits);
1148 oldmask = newmask;
1149 if (mask_bits)
1150 sig_dispatch_pending (true);
1151 else
1152 sigproc_printf ("not calling sig_dispatch_pending");
1153 mask_sync.release ();
1154 }
1155
1156 int __stdcall
1157 sigpacket::process ()
1158 {
1159 DWORD continue_now;
1160 struct sigaction dummy = global_sigs[SIGSTOP];
1161
1162 if (si.si_signo != SIGCONT)
1163 continue_now = false;
1164 else
1165 {
1166 continue_now = myself->process_state & PID_STOPPED;
1167 myself->stopsig = 0;
1168 myself->process_state &= ~PID_STOPPED;
1169 /* Clear pending stop signals */
1170 sig_clear (SIGSTOP);
1171 sig_clear (SIGTSTP);
1172 sig_clear (SIGTTIN);
1173 sig_clear (SIGTTOU);
1174 }
1175
1176 int rc = 1;
1177
1178 sigproc_printf ("signal %d processing", si.si_signo);
1179 struct sigaction& thissig = global_sigs[si.si_signo];
1180
1181 myself->rusage_self.ru_nsignals++;
1182
1183 bool masked;
1184 void *handler;
1185 if (!hExeced || (void *) thissig.sa_handler == (void *) SIG_IGN)
1186 handler = (void *) thissig.sa_handler;
1187 else if (tls)
1188 return 1;
1189 else
1190 handler = NULL;
1191
1192 _cygtls *use_tls = tls ?: _main_tls;
1193
1194 if (si.si_signo == SIGKILL)
1195 goto exit_sig;
1196 if (si.si_signo == SIGSTOP)
1197 {
1198 sig_clear (SIGCONT);
1199 goto stop;
1200 }
1201
1202 bool insigwait_mask;
1203 if ((masked = ISSTATE (myself, PID_STOPPED)))
1204 insigwait_mask = false;
1205 else if (tls)
1206 insigwait_mask = sigismember (&tls->sigwait_mask, si.si_signo);
1207 else if (!(tls = _cygtls::find_tls (si.si_signo)))
1208 insigwait_mask = false;
1209 else
1210 {
1211 use_tls = tls;
1212 insigwait_mask = true;
1213 }
1214
1215 if (insigwait_mask)
1216 goto thread_specific;
1217
1218 if (masked)
1219 /* nothing to do */;
1220 else if (sigismember (mask, si.si_signo))
1221 masked = true;
1222 else if (tls)
1223 masked = sigismember (&tls->sigmask, si.si_signo);
1224
1225 if (masked)
1226 {
1227 sigproc_printf ("signal %d blocked", si.si_signo);
1228 rc = -1;
1229 goto done;
1230 }
1231
1232 /* Clear pending SIGCONT on stop signals */
1233 if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
1234 sig_clear (SIGCONT);
1235
1236 #ifdef CGF
1237 if (being_debugged ())
1238 {
1239 char sigmsg[sizeof (_CYGWIN_SIGNAL_STRING " 0xffffffff")];
1240 __small_sprintf (sigmsg, _CYGWIN_SIGNAL_STRING " %p", si.si_signo);
1241 OutputDebugString (sigmsg);
1242 }
1243 #endif
1244
1245 if (handler == (void *) SIG_DFL)
1246 {
1247 if (insigwait_mask)
1248 goto thread_specific;
1249 if (si.si_signo == SIGCHLD || si.si_signo == SIGIO || si.si_signo == SIGCONT || si.si_signo == SIGWINCH
1250 || si.si_signo == SIGURG)
1251 {
1252 sigproc_printf ("default signal %d ignored", si.si_signo);
1253 if (continue_now)
1254 SetEvent (signal_arrived);
1255 goto done;
1256 }
1257
1258 if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
1259 goto stop;
1260
1261 goto exit_sig;
1262 }
1263
1264 if (handler == (void *) SIG_IGN)
1265 {
1266 sigproc_printf ("signal %d ignored", si.si_signo);
1267 goto done;
1268 }
1269
1270 if (handler == (void *) SIG_ERR)
1271 goto exit_sig;
1272
1273 use_tls->set_siginfo (this);
1274 goto dosig;
1275
1276 stop:
1277 /* Eat multiple attempts to STOP */
1278 if (ISSTATE (myself, PID_STOPPED))
1279 goto done;
1280 handler = (void *) sig_handle_tty_stop;
1281 thissig = dummy;
1282
1283 dosig:
1284 /* Dispatch to the appropriate function. */
1285 sigproc_printf ("signal %d, about to call %p", si.si_signo, handler);
1286 rc = setup_handler (si.si_signo, handler, thissig, use_tls);
1287
1288 done:
1289 tls = use_tls;
1290 if (continue_now)
1291 SetEvent (sigCONT);
1292 sigproc_printf ("returning %d", rc);
1293 return rc;
1294
1295 thread_specific:
1296 use_tls->sig = si.si_signo;
1297 use_tls->set_siginfo (this);
1298 use_tls->func = NULL;
1299 sigproc_printf ("releasing sigwait for thread");
1300 SetEvent (use_tls->event);
1301 goto done;
1302
1303 exit_sig:
1304 if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT)
1305 {
1306 CONTEXT c;
1307 c.ContextFlags = CONTEXT_FULL;
1308 GetThreadContext (hMainThread, &c);
1309 use_tls->copy_context (&c);
1310 if (cygheap->rlim_core > 0UL)
1311 si.si_signo |= 0x80;
1312 }
1313 sigproc_printf ("signal %d, about to call do_exit", si.si_signo);
1314 use_tls->signal_exit (si.si_signo); /* never returns */
1315 }
1316
1317 /* Cover function to `do_exit' to handle exiting even in presence of more
1318 exceptions. We used to call exit, but a SIGSEGV shouldn't cause atexit
1319 routines to run. */
1320 void
1321 _cygtls::signal_exit (int rc)
1322 {
1323 if (hExeced)
1324 {
1325 sigproc_printf ("terminating captive process");
1326 TerminateProcess (hExeced, sigExeced = rc);
1327 }
1328
1329 signal_debugger (rc & 0x7f);
1330 if ((rc & 0x80) && !try_to_debug ())
1331 stackdump (thread_context.ebp, 1, 1);
1332
1333 lock_process until_exit (true);
1334 if (hExeced || exit_state > ES_PROCESS_LOCKED)
1335 myself.exit (rc);
1336
1337 /* Starve other threads in a vain attempt to stop them from doing something
1338 stupid. */
1339 SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
1340
1341 sigproc_printf ("about to call do_exit (%x)", rc);
1342 do_exit (rc);
1343 }
1344
1345 void
1346 events_init ()
1347 {
1348 mask_sync.init ("mask_sync");
1349 }
1350
1351 void
1352 events_terminate ()
1353 {
1354 exit_already = 1;
1355 }
1356
1357 int
1358 _cygtls::call_signal_handler ()
1359 {
1360 int this_sa_flags = 0;
1361 /* Call signal handler. */
1362 while (sig && func)
1363 {
1364 lock ();
1365 this_sa_flags = sa_flags;
1366 int thissig = sig;
1367 void (*thisfunc) (int) = func;
1368
1369 pop ();
1370 reset_signal_arrived ();
1371 sigset_t this_oldmask = set_process_mask_delta ();
1372 int this_errno = saved_errno;
1373 sig = 0;
1374 unlock (); // make sure synchronized
1375 incyg = 0;
1376 if (!(this_sa_flags & SA_SIGINFO))
1377 {
1378 void (*sigfunc) (int) = thisfunc;
1379 sigfunc (thissig);
1380 }
1381 else
1382 {
1383 siginfo_t thissi = infodata;
1384 void (*sigact) (int, siginfo_t *, void *) = (void (*) (int, siginfo_t *, void *)) thisfunc;
1385 /* no ucontext_t information provided yet */
1386 sigact (thissig, &thissi, NULL);
1387 }
1388 incyg = 1;
1389 set_signal_mask (this_oldmask, _my_tls.sigmask);
1390 if (this_errno >= 0)
1391 set_errno (this_errno);
1392 }
1393
1394 return this_sa_flags & SA_RESTART;
1395 }
1396
1397 extern "C" void __stdcall
1398 reset_signal_arrived ()
1399 {
1400 // NEEDED? WaitForSingleObject (signal_arrived, 10);
1401 ResetEvent (signal_arrived);
1402 sigproc_printf ("reset signal_arrived");
1403 if (_my_tls.stackptr > _my_tls.stack)
1404 debug_printf ("stackptr[-1] %p", _my_tls.stackptr[-1]);
1405 }
1406
1407 void
1408 _cygtls::copy_context (CONTEXT *c)
1409 {
1410 memcpy (&thread_context, c, (&thread_context._internal - (unsigned char *) &thread_context));
1411 }
1412
1413 void
1414 _cygtls::signal_debugger (int sig)
1415 {
1416 if (isinitialized () && being_debugged ())
1417 {
1418 char sigmsg[2 * sizeof (_CYGWIN_SIGNAL_STRING " ffffffff ffffffff")];
1419 __small_sprintf (sigmsg, _CYGWIN_SIGNAL_STRING " %d %p %p", sig, thread_id, &thread_context);
1420 OutputDebugString (sigmsg);
1421 }
1422 }
This page took 0.091542 seconds and 4 git commands to generate.