]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* exceptions.cc |
2 | ||
33ad2bf9 | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
1fd5e000 CF |
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 | ||
4c8d72de | 11 | #include "winsup.h" |
bccd5e0d | 12 | #include <imagehlp.h> |
1fd5e000 | 13 | #include <errno.h> |
e2b3dc25 | 14 | #include <stdlib.h> |
1fd5e000 | 15 | |
1fd5e000 | 16 | #include "exceptions.h" |
bccd5e0d CF |
17 | #include "sync.h" |
18 | #include "sigproc.h" | |
e2ebe117 | 19 | #include "pinfo.h" |
9e2baf8d | 20 | #include "cygerrno.h" |
bccd5e0d | 21 | #include "perthread.h" |
29ac7f89 | 22 | #include "shared_info.h" |
f0338f54 CF |
23 | #include "perprocess.h" |
24 | #include "security.h" | |
1fd5e000 | 25 | |
c0188ae7 CF |
26 | #define CALL_HANDLER_RETRY 20 |
27 | ||
3d0ba393 | 28 | char debugger_command[2 * MAX_PATH + 20]; |
1fd5e000 CF |
29 | |
30 | extern "C" { | |
31 | static int handle_exceptions (EXCEPTION_RECORD *, void *, CONTEXT *, void *); | |
32 | extern void sigreturn (); | |
33 | extern void sigdelayed (); | |
c3d62298 | 34 | extern void sigdelayed0 (); |
1fd5e000 | 35 | extern void siglast (); |
dd11f11f | 36 | extern DWORD __no_sig_start, __no_sig_end; |
1fd5e000 CF |
37 | }; |
38 | ||
f9f2ed0e CF |
39 | extern DWORD sigtid; |
40 | ||
c0a8e8d0 CF |
41 | extern HANDLE hExeced; |
42 | extern DWORD dwExeced; | |
43 | ||
1fd5e000 | 44 | static BOOL WINAPI ctrl_c_handler (DWORD); |
e06f5813 | 45 | static void signal_exit (int) __attribute__ ((noreturn)); |
f02f1f14 CF |
46 | static char windows_system_directory[1024]; |
47 | static size_t windows_system_directory_length; | |
1fd5e000 CF |
48 | |
49 | /* This is set to indicate that we have already exited. */ | |
50 | ||
51 | static NO_COPY int exit_already = 0; | |
52 | static NO_COPY muto *mask_sync = NULL; | |
53 | ||
0cda2f46 | 54 | HMODULE NO_COPY cygwin_hmodule; |
1fd5e000 | 55 | |
bc6ed549 | 56 | NO_COPY static struct |
1fd5e000 CF |
57 | { |
58 | unsigned int code; | |
59 | const char *name; | |
bc6ed549 | 60 | } status_info[] = |
1fd5e000 CF |
61 | { |
62 | #define X(s) s, #s | |
63 | { X (STATUS_ABANDONED_WAIT_0) }, | |
64 | { X (STATUS_ACCESS_VIOLATION) }, | |
65 | { X (STATUS_ARRAY_BOUNDS_EXCEEDED) }, | |
66 | { X (STATUS_BREAKPOINT) }, | |
67 | { X (STATUS_CONTROL_C_EXIT) }, | |
68 | { X (STATUS_DATATYPE_MISALIGNMENT) }, | |
69 | { X (STATUS_FLOAT_DENORMAL_OPERAND) }, | |
70 | { X (STATUS_FLOAT_DIVIDE_BY_ZERO) }, | |
71 | { X (STATUS_FLOAT_INEXACT_RESULT) }, | |
72 | { X (STATUS_FLOAT_INVALID_OPERATION) }, | |
73 | { X (STATUS_FLOAT_OVERFLOW) }, | |
74 | { X (STATUS_FLOAT_STACK_CHECK) }, | |
75 | { X (STATUS_FLOAT_UNDERFLOW) }, | |
76 | { X (STATUS_GUARD_PAGE_VIOLATION) }, | |
77 | { X (STATUS_ILLEGAL_INSTRUCTION) }, | |
78 | { X (STATUS_INTEGER_DIVIDE_BY_ZERO) }, | |
79 | { X (STATUS_INTEGER_OVERFLOW) }, | |
80 | { X (STATUS_INVALID_DISPOSITION) }, | |
81 | { X (STATUS_IN_PAGE_ERROR) }, | |
82 | { X (STATUS_NONCONTINUABLE_EXCEPTION) }, | |
83 | { X (STATUS_NO_MEMORY) }, | |
84 | { X (STATUS_PENDING) }, | |
85 | { X (STATUS_PRIVILEGED_INSTRUCTION) }, | |
86 | { X (STATUS_SINGLE_STEP) }, | |
87 | { X (STATUS_STACK_OVERFLOW) }, | |
88 | { X (STATUS_TIMEOUT) }, | |
89 | { X (STATUS_USER_APC) }, | |
90 | { X (STATUS_WAIT_0) }, | |
91 | { 0, 0 } | |
92 | #undef X | |
93 | }; | |
94 | ||
95 | /* Initialization code. */ | |
96 | ||
97 | #ifdef __i386__ | |
98 | ||
99 | // Set up the exception handler for the current thread. The PowerPC & Mips | |
100 | // use compiler generated tables to set up the exception handlers for each | |
101 | // region of code, and the kernel walks the call list until it finds a region | |
102 | // of code that handles exceptions. The x86 on the other hand uses segment | |
103 | // register fs, offset 0 to point to the current exception handler. | |
104 | ||
105 | asm (".equ __except_list,0"); | |
106 | ||
107 | extern exception_list *_except_list asm ("%fs:__except_list"); | |
108 | ||
109 | static void | |
110 | init_exception_handler (exception_list *el) | |
111 | { | |
112 | el->handler = handle_exceptions; | |
113 | el->prev = _except_list; | |
114 | _except_list = el; | |
115 | } | |
1fd5e000 CF |
116 | #endif |
117 | ||
118 | void | |
c0a8e8d0 | 119 | early_stuff_init () |
1fd5e000 | 120 | { |
c0a8e8d0 CF |
121 | (void) SetConsoleCtrlHandler (ctrl_c_handler, FALSE); |
122 | if (!SetConsoleCtrlHandler (ctrl_c_handler, TRUE)) | |
123 | system_printf ("SetConsoleCtrlHandler failed, %E"); | |
124 | ||
1fd5e000 CF |
125 | /* Initialize global security attribute stuff */ |
126 | ||
127 | sec_none.nLength = sec_none_nih.nLength = | |
128 | sec_all.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES); | |
129 | sec_none.bInheritHandle = sec_all.bInheritHandle = TRUE; | |
130 | sec_none_nih.bInheritHandle = sec_all_nih.bInheritHandle = FALSE; | |
131 | sec_none.lpSecurityDescriptor = sec_none_nih.lpSecurityDescriptor = NULL; | |
132 | sec_all.lpSecurityDescriptor = sec_all_nih.lpSecurityDescriptor = | |
133 | get_null_sd (); | |
1fd5e000 CF |
134 | } |
135 | ||
136 | extern "C" void | |
137 | init_exceptions (exception_list *el) | |
138 | { | |
8abeff1e | 139 | init_exception_handler (el); |
1fd5e000 CF |
140 | } |
141 | ||
142 | extern "C" void | |
143 | error_start_init (const char *buf) | |
144 | { | |
145 | if (!buf || !*buf) | |
146 | { | |
147 | debugger_command[0] = '\0'; | |
148 | return; | |
149 | } | |
150 | ||
56a42791 CF |
151 | char pgm[MAX_PATH + 1]; |
152 | if (!GetModuleFileName (NULL, pgm, MAX_PATH)) | |
153 | strcpy (pgm, "cygwin1.dll"); | |
154 | for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\')) | |
155 | *p = '/'; | |
1fd5e000 | 156 | |
56a42791 | 157 | __small_sprintf (debugger_command, "%s %s", buf, pgm); |
1fd5e000 CF |
158 | } |
159 | ||
8abeff1e CF |
160 | static void |
161 | open_stackdumpfile () | |
162 | { | |
163 | if (myself->progname[0]) | |
164 | { | |
165 | const char *p; | |
166 | /* write to progname.stackdump if possible */ | |
b2bfade3 CF |
167 | if (!myself->progname[0]) |
168 | p = "unknown"; | |
169 | else if ((p = strrchr (myself->progname, '\\'))) | |
8abeff1e CF |
170 | p++; |
171 | else | |
172 | p = myself->progname; | |
173 | char corefile[strlen (p) + sizeof (".stackdump")]; | |
174 | __small_sprintf (corefile, "%s.stackdump", p); | |
175 | HANDLE h = CreateFile (corefile, GENERIC_WRITE, 0, &sec_none_nih, | |
176 | CREATE_ALWAYS, 0, 0); | |
177 | if (h != INVALID_HANDLE_VALUE) | |
178 | { | |
ebd645e7 CF |
179 | if (!myself->ppid_handle) |
180 | system_printf ("Dumping stack trace to %s", corefile); | |
181 | else | |
182 | debug_printf ("Dumping stack trace to %s", corefile); | |
8abeff1e CF |
183 | SetStdHandle (STD_ERROR_HANDLE, h); |
184 | } | |
185 | } | |
186 | } | |
187 | ||
1fd5e000 CF |
188 | /* Utilities for dumping the stack, etc. */ |
189 | ||
190 | static void | |
191 | exception (EXCEPTION_RECORD *e, CONTEXT *in) | |
192 | { | |
20d7f758 | 193 | const char *exception_name = NULL; |
1fd5e000 CF |
194 | |
195 | if (e) | |
196 | { | |
197 | for (int i = 0; status_info[i].name; i++) | |
198 | { | |
199 | if (status_info[i].code == e->ExceptionCode) | |
200 | { | |
201 | exception_name = status_info[i].name; | |
202 | break; | |
203 | } | |
204 | } | |
205 | } | |
206 | ||
207 | #ifdef __i386__ | |
208 | #define HAVE_STATUS | |
209 | if (exception_name) | |
210 | small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip); | |
211 | else | |
212 | small_printf ("Exception %d at eip=%08x\r\n", e->ExceptionCode, in->Eip); | |
213 | small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n", | |
214 | in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi); | |
215 | small_printf ("ebp=%08x esp=%08x program=%s\r\n", | |
216 | in->Ebp, in->Esp, myself->progname); | |
217 | small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n", | |
218 | in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs); | |
219 | #endif | |
220 | ||
221 | #ifndef HAVE_STATUS | |
222 | system_printf ("Had an exception"); | |
223 | #endif | |
224 | } | |
225 | ||
1fd5e000 CF |
226 | #ifdef __i386__ |
227 | /* Print a stack backtrace. */ | |
228 | ||
229 | #define HAVE_STACK_TRACE | |
230 | ||
1fd5e000 CF |
231 | /* A class for manipulating the stack. */ |
232 | class stack_info | |
233 | { | |
1d613351 | 234 | int walk (); /* Uses the "old" method */ |
8366e93b | 235 | char *next_offset () {return *((char **) sf.AddrFrame.Offset);} |
f598d941 CF |
236 | bool needargs; |
237 | DWORD dummy_frame; | |
1fd5e000 | 238 | public: |
f598d941 CF |
239 | STACKFRAME sf; /* For storing the stack information */ |
240 | void init (DWORD, bool, bool); /* Called the first time that stack info is needed */ | |
af1dc7cc | 241 | |
1fd5e000 | 242 | /* Postfix ++ iterates over the stack, returning zero when nothing is left. */ |
af1dc7cc | 243 | int operator ++(int) { return this->walk (); } |
1fd5e000 CF |
244 | }; |
245 | ||
246 | /* The number of parameters used in STACKFRAME */ | |
1d613351 | 247 | #define NPARAMS (sizeof (thestack.sf.Params) / sizeof (thestack.sf.Params[0])) |
1fd5e000 CF |
248 | |
249 | /* This is the main stack frame info for this process. */ | |
af1dc7cc | 250 | static NO_COPY stack_info thestack; |
ac944e37 | 251 | static signal_dispatch sigsave; |
1fd5e000 CF |
252 | |
253 | /* Initialize everything needed to start iterating. */ | |
254 | void | |
f598d941 | 255 | stack_info::init (DWORD ebp, bool wantargs, bool goodframe) |
1fd5e000 | 256 | { |
8abeff1e | 257 | # define debp ((DWORD *) ebp) |
1d613351 | 258 | memset (&sf, 0, sizeof (sf)); |
f598d941 CF |
259 | if (!goodframe) |
260 | sf.AddrFrame.Offset = ebp; | |
261 | else | |
262 | { | |
263 | dummy_frame = ebp; | |
264 | sf.AddrFrame.Offset = (DWORD) &dummy_frame; | |
265 | } | |
8abeff1e | 266 | sf.AddrReturn.Offset = debp[1]; |
1fd5e000 | 267 | sf.AddrFrame.Mode = AddrModeFlat; |
f598d941 | 268 | needargs = wantargs; |
8abeff1e | 269 | # undef debp |
1fd5e000 CF |
270 | } |
271 | ||
272 | /* Walk the stack by looking at successive stored 'bp' frames. | |
273 | This is not foolproof. */ | |
274 | int | |
af1dc7cc | 275 | stack_info::walk () |
1fd5e000 CF |
276 | { |
277 | char **ebp; | |
f598d941 | 278 | if ((ebp = (char **) next_offset ()) == NULL) |
1fd5e000 CF |
279 | return 0; |
280 | ||
f598d941 CF |
281 | sf.AddrFrame.Offset = (DWORD) ebp; |
282 | sf.AddrPC.Offset = sf.AddrReturn.Offset; | |
283 | ||
1fd5e000 CF |
284 | if (!sf.AddrPC.Offset) |
285 | return 0; /* stack frames are exhausted */ | |
286 | ||
287 | /* The return address always follows the stack pointer */ | |
288 | sf.AddrReturn.Offset = (DWORD) *++ebp; | |
289 | ||
f598d941 CF |
290 | if (needargs) |
291 | /* The arguments follow the return address */ | |
292 | for (unsigned i = 0; i < NPARAMS; i++) | |
293 | sf.Params[i] = (DWORD) *++ebp; | |
294 | ||
1fd5e000 CF |
295 | return 1; |
296 | } | |
297 | ||
8366e93b | 298 | static void |
f598d941 | 299 | stackdump (DWORD ebp, int open_file, bool isexception) |
1fd5e000 | 300 | { |
8abeff1e CF |
301 | extern unsigned long rlim_core; |
302 | ||
303 | if (rlim_core == 0UL) | |
304 | return; | |
305 | ||
306 | if (open_file) | |
307 | open_stackdumpfile (); | |
308 | ||
1fd5e000 CF |
309 | int i; |
310 | ||
f598d941 | 311 | thestack.init (ebp, 1, !isexception); /* Initialize from the input CONTEXT */ |
1fd5e000 | 312 | small_printf ("Stack trace:\r\nFrame Function Args\r\n"); |
8366e93b | 313 | for (i = 0; i < 16 && thestack++; i++) |
1fd5e000 | 314 | { |
af1dc7cc CF |
315 | small_printf ("%08x %08x ", thestack.sf.AddrFrame.Offset, |
316 | thestack.sf.AddrPC.Offset); | |
1fd5e000 | 317 | for (unsigned j = 0; j < NPARAMS; j++) |
af1dc7cc | 318 | small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]); |
1fd5e000 CF |
319 | small_printf (")\r\n"); |
320 | } | |
321 | small_printf ("End of stack trace%s", | |
322 | i == 16 ? " (more stack frames may be present)" : ""); | |
323 | } | |
324 | ||
325 | /* Temporary (?) function for external callers to get a stack dump */ | |
326 | extern "C" void | |
1d613351 | 327 | cygwin_stackdump () |
1fd5e000 CF |
328 | { |
329 | CONTEXT c; | |
330 | c.ContextFlags = CONTEXT_FULL; | |
eafa31fb | 331 | GetThreadContext (GetCurrentThread (), &c); |
f598d941 | 332 | stackdump (c.Ebp, 0, 0); |
1fd5e000 CF |
333 | } |
334 | ||
1d613351 CF |
335 | #define TIME_TO_WAIT_FOR_DEBUGGER 10000 |
336 | ||
1fd5e000 | 337 | extern "C" int |
8abeff1e | 338 | try_to_debug (bool waitloop) |
1fd5e000 | 339 | { |
2a6fc028 | 340 | debug_printf ("debugger_command '%s'", debugger_command); |
1fd5e000 CF |
341 | if (*debugger_command == '\0') |
342 | return 0; | |
343 | ||
344 | __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ()); | |
345 | ||
8abeff1e | 346 | SetThreadPriority (hMainThread, THREAD_PRIORITY_HIGHEST); |
01cf5d0f | 347 | PROCESS_INFORMATION pi = {NULL, 0, 0, 0}; |
1fd5e000 | 348 | |
01cf5d0f | 349 | STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}; |
1fd5e000 CF |
350 | si.lpReserved = NULL; |
351 | si.lpDesktop = NULL; | |
352 | si.dwFlags = 0; | |
353 | si.cb = sizeof (si); | |
354 | ||
355 | /* FIXME: need to know handles of all running threads to | |
356 | suspend_all_threads_except (current_thread_id); | |
357 | */ | |
358 | ||
359 | /* if any of these mutexes is owned, we will fail to start any cygwin app | |
360 | until trapped app exits */ | |
361 | ||
1fd5e000 CF |
362 | ReleaseMutex (title_mutex); |
363 | ||
1d613351 CF |
364 | /* prevent recursive exception handling */ |
365 | char* rawenv = GetEnvironmentStrings () ; | |
366 | for (char* p = rawenv; *p != '\0'; p = strchr (p, '\0') + 1) | |
367 | { | |
368 | if (strncmp (p, "CYGWIN=", sizeof ("CYGWIN=") - 1) == 0) | |
369 | { | |
1d613351 CF |
370 | char* q = strstr (p, "error_start") ; |
371 | /* replace 'error_start=...' with '_rror_start=...' */ | |
372 | if (q) *q = '_' ; | |
373 | SetEnvironmentVariable ("CYGWIN", p + sizeof ("CYGWIN=")) ; | |
374 | break ; | |
375 | } | |
376 | } | |
377 | ||
56a42791 | 378 | BOOL dbg; |
1fd5e000 CF |
379 | dbg = CreateProcess (NULL, |
380 | debugger_command, | |
381 | NULL, | |
382 | NULL, | |
383 | FALSE, | |
384 | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, | |
385 | NULL, | |
386 | NULL, | |
387 | &si, | |
388 | &pi); | |
8abeff1e | 389 | |
5a64d869 CF |
390 | if (!dbg) |
391 | system_printf ("Failed to start debugger: %E"); | |
392 | else | |
1fd5e000 | 393 | { |
99138976 | 394 | SetThreadPriority (hMainThread, THREAD_PRIORITY_IDLE); |
8abeff1e CF |
395 | if (!waitloop) |
396 | return 1; | |
918a268c | 397 | while (!being_debugged ()) |
8abeff1e | 398 | /* spin */; |
5a64d869 CF |
399 | Sleep (4000); |
400 | small_printf ("*** continuing from debugger call\n"); | |
1fd5e000 CF |
401 | } |
402 | ||
8abeff1e CF |
403 | /* FIXME: need to know handles of all running threads to |
404 | resume_all_threads_except (current_thread_id); | |
405 | */ | |
406 | return 0; | |
1fd5e000 CF |
407 | } |
408 | ||
409 | /* Main exception handler. */ | |
410 | ||
411 | static int | |
9cec3d45 | 412 | handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *) |
1fd5e000 CF |
413 | { |
414 | int sig; | |
8abeff1e CF |
415 | static int NO_COPY debugging = 0; |
416 | static int NO_COPY recursed = 0; | |
417 | ||
52cd2f88 | 418 | if (debugging && ++debugging < 500000) |
11ba5ef4 CF |
419 | { |
420 | SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL); | |
421 | return 0; | |
422 | } | |
1fd5e000 CF |
423 | |
424 | /* If we've already exited, don't do anything here. Returning 1 | |
425 | tells Windows to keep looking for an exception handler. */ | |
426 | if (exit_already) | |
427 | return 1; | |
428 | ||
429 | /* Coerce win32 value to posix value. */ | |
430 | switch (e->ExceptionCode) | |
431 | { | |
432 | case STATUS_FLOAT_DENORMAL_OPERAND: | |
433 | case STATUS_FLOAT_DIVIDE_BY_ZERO: | |
434 | case STATUS_FLOAT_INEXACT_RESULT: | |
435 | case STATUS_FLOAT_INVALID_OPERATION: | |
436 | case STATUS_FLOAT_OVERFLOW: | |
437 | case STATUS_FLOAT_STACK_CHECK: | |
438 | case STATUS_FLOAT_UNDERFLOW: | |
439 | case STATUS_INTEGER_DIVIDE_BY_ZERO: | |
440 | case STATUS_INTEGER_OVERFLOW: | |
441 | sig = SIGFPE; | |
442 | break; | |
443 | ||
444 | case STATUS_ILLEGAL_INSTRUCTION: | |
445 | case STATUS_PRIVILEGED_INSTRUCTION: | |
446 | case STATUS_NONCONTINUABLE_EXCEPTION: | |
447 | sig = SIGILL; | |
448 | break; | |
449 | ||
450 | case STATUS_TIMEOUT: | |
451 | sig = SIGALRM; | |
452 | break; | |
453 | ||
454 | case STATUS_ACCESS_VIOLATION: | |
455 | case STATUS_DATATYPE_MISALIGNMENT: | |
456 | case STATUS_ARRAY_BOUNDS_EXCEEDED: | |
457 | case STATUS_GUARD_PAGE_VIOLATION: | |
458 | case STATUS_IN_PAGE_ERROR: | |
459 | case STATUS_NO_MEMORY: | |
460 | case STATUS_INVALID_DISPOSITION: | |
461 | case STATUS_STACK_OVERFLOW: | |
462 | sig = SIGSEGV; | |
463 | break; | |
464 | ||
465 | case STATUS_CONTROL_C_EXIT: | |
466 | sig = SIGINT; | |
467 | break; | |
468 | ||
469 | case STATUS_INVALID_HANDLE: | |
470 | /* CloseHandle will throw this exception if it is given an | |
471 | invalid handle. We don't care about the exception; we just | |
472 | want CloseHandle to return an error. This can be revisited | |
473 | if gcc ever supports Windows style structured exception | |
474 | handling. */ | |
475 | return 0; | |
476 | ||
477 | default: | |
478 | /* If we don't recognize the exception, we have to assume that | |
479 | we are doing structured exception handling, and we let | |
480 | something else handle it. */ | |
481 | return 1; | |
482 | } | |
483 | ||
484 | debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp); | |
485 | debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in->Eip); | |
486 | ||
1d613351 CF |
487 | if (myself->getsig (sig).sa_mask & SIGTOMASK (sig)) |
488 | syscall_printf ("signal %d, masked %p", sig, myself->getsig (sig).sa_mask); | |
1fd5e000 | 489 | |
8366e93b | 490 | debug_printf ("In cygwin_except_handler calling %p", |
1d613351 | 491 | myself->getsig (sig).sa_handler); |
8366e93b CF |
492 | |
493 | DWORD *ebp = (DWORD *)in->Esp; | |
494 | for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--) | |
495 | if (*ebp == in->SegCs && ebp[-1] == in->Eip) | |
496 | { | |
497 | ebp -= 2; | |
498 | break; | |
499 | } | |
500 | ||
1fd5e000 | 501 | if (!myself->progname[0] |
f9f2ed0e | 502 | || GetCurrentThreadId () == sigtid |
1d613351 CF |
503 | || (void *) myself->getsig (sig).sa_handler == (void *) SIG_DFL |
504 | || (void *) myself->getsig (sig).sa_handler == (void *) SIG_IGN | |
505 | || (void *) myself->getsig (sig).sa_handler == (void *) SIG_ERR) | |
1fd5e000 | 506 | { |
1fd5e000 CF |
507 | /* Print the exception to the console */ |
508 | if (e) | |
509 | { | |
510 | for (int i = 0; status_info[i].name; i++) | |
511 | { | |
512 | if (status_info[i].code == e->ExceptionCode) | |
513 | { | |
5bba0cb5 CF |
514 | if (!myself->ppid_handle) |
515 | system_printf ("Exception: %s", status_info[i].name); | |
1fd5e000 CF |
516 | break; |
517 | } | |
518 | } | |
519 | } | |
520 | ||
521 | /* Another exception could happen while tracing or while exiting. | |
522 | Only do this once. */ | |
8abeff1e | 523 | if (recursed++) |
1d613351 | 524 | system_printf ("Error while dumping state (probably corrupted stack)"); |
1fd5e000 CF |
525 | else |
526 | { | |
8abeff1e CF |
527 | if (try_to_debug (0)) |
528 | { | |
529 | debugging = 1; | |
530 | return 0; | |
531 | } | |
532 | ||
533 | open_stackdumpfile (); | |
534 | exception (e, in); | |
f598d941 | 535 | stackdump ((DWORD) ebp, 0, 1); |
1fd5e000 | 536 | } |
8abeff1e CF |
537 | |
538 | signal_exit (0x80 | sig); // Flag signal + core dump | |
1fd5e000 CF |
539 | } |
540 | ||
cba63823 | 541 | sig_send (NULL, sig, (DWORD) ebp, 1); // Signal myself |
1fd5e000 CF |
542 | return 0; |
543 | } | |
544 | #endif /* __i386__ */ | |
545 | ||
546 | #ifndef HAVE_STACK_TRACE | |
547 | void | |
548 | stack (void) | |
549 | { | |
550 | system_printf ("Stack trace not yet supported on this machine."); | |
551 | } | |
552 | #endif | |
1fd5e000 CF |
553 | |
554 | /* Utilities to call a user supplied exception handler. */ | |
555 | ||
077ec4cb | 556 | #define SIG_NONMASKABLE (SIGTOMASK (SIGKILL) | SIGTOMASK (SIGSTOP)) |
1fd5e000 CF |
557 | |
558 | #ifdef __i386__ | |
559 | #define HAVE_CALL_HANDLER | |
560 | ||
561 | /* Non-raceable sigsuspend | |
562 | * Note: This implementation is based on the Single UNIX Specification | |
563 | * man page. This indicates that sigsuspend always returns -1 and that | |
564 | * attempts to block unblockable signals will be silently ignored. | |
565 | * This is counter to what appears to be documented in some UNIX | |
566 | * man pages, e.g. Linux. | |
567 | */ | |
568 | int __stdcall | |
569 | handle_sigsuspend (sigset_t tempmask) | |
570 | { | |
70a11195 | 571 | sigframe thisframe (mainthread); |
1fd5e000 CF |
572 | sigset_t oldmask = myself->getsigmask (); // Remember for restoration |
573 | ||
574 | set_process_mask (tempmask & ~SIG_NONMASKABLE);// Let signals we're | |
575 | // interested in through. | |
576 | sigproc_printf ("old mask %x, new mask %x", oldmask, tempmask); | |
577 | ||
1fd5e000 CF |
578 | WaitForSingleObject (signal_arrived, INFINITE); |
579 | ||
580 | set_sig_errno (EINTR); // Per POSIX | |
581 | ||
582 | /* A signal dispatch function will have been added to our stack and will | |
583 | be hit eventually. Set the old mask to be restored when the signal | |
584 | handler returns. */ | |
585 | ||
586 | sigsave.oldmask = oldmask; // Will be restored by signal handler | |
587 | return -1; | |
588 | } | |
589 | ||
590 | extern DWORD exec_exit; // Possible exit value for exec | |
591 | extern int pending_signals; | |
592 | ||
a7cde2b9 CF |
593 | extern "C" { |
594 | static void | |
595 | sig_handle_tty_stop (int sig) | |
596 | { | |
903c330d CF |
597 | /* Silently ignore attempts to suspend if there is no accomodating |
598 | cygwin parent to deal with this behavior. */ | |
599 | if (!myself->ppid_handle) | |
99a5bd2f CF |
600 | { |
601 | myself->process_state &= ~PID_STOPPED; | |
602 | return; | |
603 | } | |
9e73b339 | 604 | |
a7cde2b9 CF |
605 | myself->stopsig = sig; |
606 | /* See if we have a living parent. If so, send it a special signal. | |
607 | * It will figure out exactly which pid has stopped by scanning | |
608 | * its list of subprocesses. | |
609 | */ | |
610 | if (my_parent_is_alive ()) | |
611 | { | |
612 | pinfo parent (myself->ppid); | |
9e73b339 CF |
613 | if (!(parent->getsig (SIGCHLD).sa_flags & SA_NOCLDSTOP)) |
614 | sig_send (parent, SIGCHLD); | |
a7cde2b9 CF |
615 | } |
616 | sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p", | |
617 | myself->pid, sig, myself->ppid_handle); | |
0428827b CF |
618 | if (WaitForSingleObject (sigCONT, INFINITE) != WAIT_OBJECT_0) |
619 | api_fatal ("WaitSingleObject failed, %E"); | |
620 | (void) ResetEvent (sigCONT); | |
a7cde2b9 CF |
621 | return; |
622 | } | |
623 | } | |
624 | ||
f02f1f14 | 625 | int |
6cb613a4 | 626 | interruptible (DWORD pc, int testvalid = 0) |
1fd5e000 | 627 | { |
0cda2f46 | 628 | int res; |
e2fa5023 CF |
629 | MEMORY_BASIC_INFORMATION m; |
630 | ||
631 | memset (&m, 0, sizeof m); | |
632 | if (!VirtualQuery ((LPCVOID) pc, &m, sizeof m)) | |
633 | sigproc_printf ("couldn't get memory info, pc %p, %E", pc); | |
634 | ||
635 | char *checkdir = (char *) alloca (windows_system_directory_length + 4); | |
636 | memset (checkdir, 0, sizeof (checkdir)); | |
637 | ||
638 | # define h ((HMODULE) m.AllocationBase) | |
639 | /* Apparently Windows 95 can sometimes return bogus addresses from | |
640 | GetThreadContext. These resolve to an allocation base == 0. | |
641 | These should *never* be treated as interruptible. */ | |
642 | if (!h || m.State != MEM_COMMIT) | |
643 | res = 0; | |
644 | else if (testvalid) | |
645 | res = 1; /* All we wanted to know was if this was a valid module. */ | |
646 | else if (h == user_data->hmodule) | |
647 | res = 1; | |
648 | else if (h == cygwin_hmodule) | |
649 | res = 0; | |
650 | else if (!GetModuleFileName (h, checkdir, windows_system_directory_length + 2)) | |
8656ee07 CF |
651 | res = 0; |
652 | else | |
e2fa5023 CF |
653 | res = !strncasematch (windows_system_directory, checkdir, |
654 | windows_system_directory_length); | |
7a4078ee | 655 | sigproc_printf ("pc %p, h %p, interruptible %d, testvalid %d", pc, h, res, testvalid); |
e2fa5023 | 656 | # undef h |
8656ee07 | 657 | return res; |
1fd5e000 CF |
658 | } |
659 | ||
efd76e41 CF |
660 | bool |
661 | sigthread::get_winapi_lock (int test) | |
662 | { | |
663 | if (test) | |
63b61cd1 | 664 | return !InterlockedExchange (&winapi_lock, 1); |
efd76e41 CF |
665 | |
666 | /* Need to do a busy loop because we can't block or a potential SuspendThread | |
667 | will hang. */ | |
63b61cd1 | 668 | while (InterlockedExchange (&winapi_lock, 1)) |
efd76e41 CF |
669 | Sleep (1); |
670 | return 1; | |
671 | } | |
672 | ||
673 | void | |
674 | sigthread::release_winapi_lock () | |
675 | { | |
676 | /* Assumes that we have the lock. */ | |
63b61cd1 | 677 | InterlockedExchange (&winapi_lock, 0); |
efd76e41 CF |
678 | } |
679 | ||
2803e941 CF |
680 | static void __stdcall interrupt_setup (int sig, void *handler, DWORD retaddr, |
681 | DWORD *retaddr_on_stack, | |
682 | struct sigaction& siga) | |
683 | __attribute__((regparm(3))); | |
d542443e | 684 | static void __stdcall |
2803e941 CF |
685 | interrupt_setup (int sig, void *handler, DWORD retaddr, DWORD *retaddr_on_stack, |
686 | struct sigaction& siga) | |
1fd5e000 | 687 | { |
d542443e | 688 | sigsave.retaddr = retaddr; |
0cda2f46 | 689 | sigsave.retaddr_on_stack = retaddr_on_stack; |
d542443e | 690 | /* FIXME: Not multi-thread aware */ |
775275aa CF |
691 | sigsave.oldmask = myself->getsigmask (); |
692 | sigsave.newmask = sigsave.oldmask | siga.sa_mask | SIGTOMASK (sig); | |
c3d62298 | 693 | sigsave.sa_flags = siga.sa_flags; |
d542443e CF |
694 | sigsave.func = (void (*)(int)) handler; |
695 | sigsave.sig = sig; | |
696 | sigsave.saved_errno = -1; // Flag: no errno to save | |
a7cde2b9 CF |
697 | if (handler == sig_handle_tty_stop) |
698 | { | |
699 | myself->stopsig = 0; | |
700 | myself->process_state |= PID_STOPPED; | |
701 | } | |
12520587 CF |
702 | /* Clear any waiting threads prior to dispatching to handler function */ |
703 | proc_subproc (PROC_CLEARWAIT, 1); | |
704 | int res = SetEvent (signal_arrived); // For an EINTR case | |
705 | sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res); | |
d542443e | 706 | } |
1fd5e000 | 707 | |
2803e941 | 708 | static bool interrupt_now (CONTEXT *, int, void *, struct sigaction&) __attribute__((regparm(3))); |
dd11f11f | 709 | static bool |
2803e941 | 710 | interrupt_now (CONTEXT *ctx, int sig, void *handler, struct sigaction& siga) |
d542443e | 711 | { |
2803e941 | 712 | interrupt_setup (sig, handler, ctx->Eip, 0, siga); |
d542443e | 713 | ctx->Eip = (DWORD) sigdelayed; |
12520587 | 714 | SetThreadContext (myself->getthread2signal (), ctx); /* Restart the thread in a new location */ |
dd11f11f | 715 | return 1; |
1fd5e000 CF |
716 | } |
717 | ||
166b2571 | 718 | void __stdcall |
0cda2f46 CF |
719 | signal_fixup_after_fork () |
720 | { | |
3cb62bd6 | 721 | if (sigsave.sig) |
0cda2f46 | 722 | { |
3cb62bd6 CF |
723 | sigsave.sig = 0; |
724 | if (sigsave.retaddr_on_stack) | |
725 | { | |
726 | *sigsave.retaddr_on_stack = sigsave.retaddr; | |
727 | set_process_mask (sigsave.oldmask); | |
728 | } | |
0cda2f46 | 729 | } |
3cb62bd6 | 730 | sigproc_init (); |
0cda2f46 | 731 | } |
1d613351 | 732 | |
166b2571 CF |
733 | void __stdcall |
734 | signal_fixup_after_exec (bool isspawn) | |
735 | { | |
736 | /* Set up child's signal handlers */ | |
737 | for (int i = 0; i < NSIG; i++) | |
738 | { | |
c90e1cf1 CF |
739 | myself->getsig (i).sa_mask = 0; |
740 | if (myself->getsig (i).sa_handler != SIG_IGN || isspawn) | |
741 | myself->getsig (i).sa_handler = SIG_DFL; | |
166b2571 CF |
742 | } |
743 | } | |
744 | ||
2803e941 | 745 | static int interrupt_on_return (sigthread *, int, void *, struct sigaction&) __attribute__((regparm(3))); |
d542443e | 746 | static int |
2803e941 | 747 | interrupt_on_return (sigthread *th, int sig, void *handler, struct sigaction& siga) |
1fd5e000 CF |
748 | { |
749 | int i; | |
dd11f11f | 750 | DWORD ebp = th->frame; |
1fd5e000 | 751 | |
dd11f11f CF |
752 | if (!ebp) |
753 | return 0; | |
1fd5e000 | 754 | |
f598d941 | 755 | thestack.init (ebp, 0, 1); /* Initialize from the input CONTEXT */ |
af1dc7cc | 756 | for (i = 0; i < 32 && thestack++ ; i++) |
968d91b2 | 757 | if (th->exception || interruptible (thestack.sf.AddrReturn.Offset)) |
1fd5e000 | 758 | { |
af1dc7cc CF |
759 | DWORD *addr_retaddr = ((DWORD *)thestack.sf.AddrFrame.Offset) + 1; |
760 | if (*addr_retaddr == thestack.sf.AddrReturn.Offset) | |
d542443e | 761 | { |
2803e941 | 762 | interrupt_setup (sig, handler, *addr_retaddr, addr_retaddr, siga); |
d542443e CF |
763 | *addr_retaddr = (DWORD) sigdelayed; |
764 | } | |
55fc91b9 | 765 | return 1; |
1fd5e000 CF |
766 | } |
767 | ||
0d675c5d | 768 | sigproc_printf ("couldn't find a stack frame, i %d\n", i); |
55fc91b9 | 769 | return 0; |
1fd5e000 CF |
770 | } |
771 | ||
772 | extern "C" void __stdcall | |
773 | set_sig_errno (int e) | |
774 | { | |
775 | set_errno (e); | |
776 | sigsave.saved_errno = e; | |
164a681c | 777 | // sigproc_printf ("errno %d", e); |
1fd5e000 CF |
778 | } |
779 | ||
206a8d88 | 780 | static int setup_handler (int, void *, struct sigaction&) __attribute__((regparm(3))); |
1fd5e000 | 781 | static int |
206a8d88 | 782 | setup_handler (int sig, void *handler, struct sigaction& siga) |
1fd5e000 | 783 | { |
af1dc7cc | 784 | CONTEXT cx; |
dd11f11f | 785 | bool interrupted = 0; |
af1dc7cc | 786 | HANDLE hth = NULL; |
1fd5e000 | 787 | int res; |
c0188ae7 | 788 | sigthread *th = NULL; // Initialization needed to shut up gcc |
6201d15e | 789 | |
ac944e37 CF |
790 | if (sigsave.sig) |
791 | goto set_pending; | |
792 | ||
c0188ae7 | 793 | for (int i = 0; !interrupted && i < CALL_HANDLER_RETRY; i++) |
6cb613a4 | 794 | { |
c0188ae7 | 795 | EnterCriticalSection (&mainthread.lock); |
dd11f11f CF |
796 | if (mainthread.frame) |
797 | th = &mainthread; | |
798 | else | |
af1dc7cc | 799 | { |
c0188ae7 CF |
800 | LeaveCriticalSection (&mainthread.lock); |
801 | ||
dd11f11f | 802 | th = NULL; |
dd11f11f CF |
803 | |
804 | hth = myself->getthread2signal (); | |
c0188ae7 | 805 | |
dd11f11f CF |
806 | /* Suspend the thread which will receive the signal. But first ensure that |
807 | this thread doesn't have any mutos. (FIXME: Someday we should just grab | |
808 | all of the mutos rather than checking for them) | |
809 | For Windows 95, we also have to ensure that the addresses returned by GetThreadContext | |
810 | are valid. | |
811 | If one of these conditions is not true we loop for a fixed number of times | |
812 | since we don't want to stall the signal handler. FIXME: Will this result in | |
813 | noticeable delays? | |
814 | If the thread is already suspended (which can occur when a program is stopped) then | |
815 | just queue the signal. */ | |
dd11f11f | 816 | |
efd76e41 CF |
817 | if (!mainthread.get_winapi_lock (1)) |
818 | continue; | |
c0188ae7 CF |
819 | sigproc_printf ("suspending mainthread"); |
820 | res = SuspendThread (hth); | |
efd76e41 CF |
821 | mainthread.release_winapi_lock (); |
822 | if (mainthread.frame) | |
823 | goto resume_thread; /* In case the main thread *just* set the frame */ | |
6cb613a4 | 824 | |
c0188ae7 CF |
825 | /* Just set pending if thread is already suspended */ |
826 | if (res) | |
827 | goto set_pending; | |
6201d15e | 828 | |
c0188ae7 CF |
829 | muto *m; |
830 | /* FIXME: Make multi-thread aware */ | |
831 | for (m = muto_start.next; m != NULL; m = m->next) | |
832 | if (m->unstable () || m->owner () == mainthread.id) | |
833 | { | |
834 | sigproc_printf ("suspended thread owns a muto (%s)", m->name); | |
835 | goto resume_thread; | |
836 | } | |
9aa07a8f | 837 | |
c0188ae7 CF |
838 | EnterCriticalSection (&mainthread.lock); |
839 | if (mainthread.frame) | |
840 | { | |
841 | th = &mainthread; | |
842 | goto try_to_interrupt; | |
dd11f11f | 843 | } |
1d613351 | 844 | |
c0188ae7 | 845 | LeaveCriticalSection (&mainthread.lock); |
8656ee07 | 846 | |
c0188ae7 CF |
847 | cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; |
848 | if (!GetThreadContext (hth, &cx)) | |
849 | system_printf ("couldn't get context of main thread, %E"); | |
850 | else if (!interruptible (cx.Eip, 1)) | |
851 | sigproc_printf ("suspended thread in a strange state pc %p, sp %p", | |
852 | cx.Eip, cx.Esp); | |
853 | else | |
854 | goto try_to_interrupt; | |
855 | ||
856 | resume_thread: | |
857 | ResumeThread (hth); | |
858 | Sleep (0); | |
859 | continue; | |
af1dc7cc | 860 | } |
8656ee07 | 861 | |
c0188ae7 | 862 | try_to_interrupt: |
dd11f11f | 863 | if (th) |
c0188ae7 | 864 | { |
2803e941 | 865 | interrupted = interrupt_on_return (th, sig, handler, siga); |
5e733918 | 866 | LeaveCriticalSection (&th->lock); |
c0188ae7 | 867 | } |
dd11f11f | 868 | else if (interruptible (cx.Eip)) |
2803e941 | 869 | interrupted = interrupt_now (&cx, sig, handler, siga); |
dd11f11f CF |
870 | else |
871 | break; | |
1fd5e000 CF |
872 | } |
873 | ||
b8c8fa17 | 874 | set_pending: |
12520587 CF |
875 | if (interrupted) |
876 | res = 1; | |
877 | else | |
1fd5e000 CF |
878 | { |
879 | pending_signals = 1; /* FIXME: Probably need to be more tricky here */ | |
880 | sig_set_pending (sig); | |
b8c8fa17 CF |
881 | sig_dispatch_pending (1); |
882 | Sleep (0); /* Hopefully, other process will be waking up soon. */ | |
dd11f11f | 883 | sigproc_printf ("couldn't send signal %d", sig); |
1fd5e000 | 884 | } |
d542443e | 885 | |
af1dc7cc | 886 | if (!hth) |
7cf3b655 | 887 | sigproc_printf ("good. Didn't suspend main thread, th %p", th); |
af1dc7cc CF |
888 | else |
889 | { | |
890 | res = ResumeThread (hth); | |
891 | sigproc_printf ("ResumeThread returned %d", res); | |
892 | } | |
68997e88 | 893 | |
d542443e | 894 | sigproc_printf ("returning %d", interrupted); |
f02f1f14 | 895 | return interrupted; |
1fd5e000 CF |
896 | } |
897 | #endif /* i386 */ | |
898 | ||
899 | #ifndef HAVE_CALL_HANDLER | |
206a8d88 | 900 | #error "Need to supply machine dependent setup_handler" |
1fd5e000 CF |
901 | #endif |
902 | ||
06486d9e | 903 | /* Keyboard interrupt handler. */ |
1fd5e000 CF |
904 | static BOOL WINAPI |
905 | ctrl_c_handler (DWORD type) | |
906 | { | |
907 | if (type == CTRL_LOGOFF_EVENT) | |
908 | return TRUE; | |
909 | ||
0cc642a5 CF |
910 | /* Return FALSE to prevent an "End task" dialog box from appearing |
911 | for each Cygwin process window that's open when the computer | |
912 | is shut down or console window is closed. */ | |
913 | if (type == CTRL_SHUTDOWN_EVENT) | |
914 | { | |
915 | sig_send (NULL, SIGTERM); | |
916 | return FALSE; | |
917 | } | |
918 | if (type == CTRL_CLOSE_EVENT) | |
1fd5e000 CF |
919 | { |
920 | sig_send (NULL, SIGHUP); | |
921 | return FALSE; | |
922 | } | |
0cc642a5 | 923 | |
c0a8e8d0 CF |
924 | /* If we are a stub and the new process has a pinfo structure, let it |
925 | handle this signal. */ | |
926 | if (dwExeced && pinfo (dwExeced)) | |
927 | return TRUE; | |
928 | ||
929 | /* We're only the process group leader when we have a valid pinfo structure. | |
930 | If we don't have one, then the parent "stub" will handle the signal. */ | |
d7c16d8d | 931 | if (!pinfo (cygwin_pid (GetCurrentProcessId ()))) |
c0a8e8d0 CF |
932 | return TRUE; |
933 | ||
1d613351 | 934 | tty_min *t = cygwin_shared->tty.get_tty (myself->ctty); |
c0a8e8d0 | 935 | /* Ignore this if we're not the process group leader since it should be handled |
1fd5e000 | 936 | *by* the process group leader. */ |
d72a6559 CF |
937 | if (myself->ctty != -1 && t->getpgid () == myself->pid && |
938 | (GetTickCount () - t->last_ctrl_c) >= MIN_CTRL_C_SLOP) | |
1fd5e000 CF |
939 | /* Otherwise we just send a SIGINT to the process group and return TRUE (to indicate |
940 | that we have handled the signal). At this point, type should be | |
941 | a CTRL_C_EVENT or CTRL_BREAK_EVENT. */ | |
942 | { | |
943 | t->last_ctrl_c = GetTickCount (); | |
944 | kill (-myself->pid, SIGINT); | |
945 | t->last_ctrl_c = GetTickCount (); | |
946 | return TRUE; | |
947 | } | |
c0a8e8d0 | 948 | |
d72a6559 | 949 | return TRUE; |
1fd5e000 CF |
950 | } |
951 | ||
952 | /* Set the signal mask for this process. | |
0d675c5d | 953 | Note that some signals are unmaskable, as in UNIX. */ |
1fd5e000 CF |
954 | extern "C" void __stdcall |
955 | set_process_mask (sigset_t newmask) | |
956 | { | |
70a11195 | 957 | sigframe thisframe (mainthread); |
1fd5e000 | 958 | mask_sync->acquire (INFINITE); |
9aa07a8f | 959 | sigset_t oldmask = myself->getsigmask (); |
1fd5e000 CF |
960 | newmask &= ~SIG_NONMASKABLE; |
961 | sigproc_printf ("old mask = %x, new mask = %x", myself->getsigmask (), newmask); | |
962 | myself->setsigmask (newmask); // Set a new mask | |
963 | mask_sync->release (); | |
9aa07a8f CF |
964 | if (oldmask != newmask && GetCurrentThreadId () != sigtid) |
965 | sig_dispatch_pending (); | |
dd11f11f CF |
966 | else |
967 | sigproc_printf ("not calling sig_dispatch_pending. sigtid %p current %p", | |
968 | sigtid, GetCurrentThreadId ()); | |
1fd5e000 CF |
969 | return; |
970 | } | |
971 | ||
1fd5e000 | 972 | int __stdcall |
06486d9e | 973 | sig_handle (int sig, bool thisproc) |
1fd5e000 CF |
974 | { |
975 | int rc = 0; | |
976 | ||
977 | sigproc_printf ("signal %d", sig); | |
978 | ||
1d613351 | 979 | struct sigaction thissig = myself->getsig (sig); |
1fd5e000 CF |
980 | void *handler = (void *) thissig.sa_handler; |
981 | ||
982 | myself->rusage_self.ru_nsignals++; | |
983 | ||
984 | /* Clear pending SIGCONT on stop signals */ | |
985 | if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) | |
986 | sig_clear (SIGCONT); | |
987 | ||
988 | if (sig == SIGKILL) | |
989 | goto exit_sig; | |
990 | ||
991 | if (sig == SIGSTOP) | |
992 | goto stop; | |
993 | ||
994 | /* FIXME: Should we still do this if SIGCONT has a handler? */ | |
995 | if (sig == SIGCONT) | |
996 | { | |
0428827b | 997 | DWORD stopped = myself->process_state & PID_STOPPED; |
1fd5e000 CF |
998 | myself->stopsig = 0; |
999 | myself->process_state &= ~PID_STOPPED; | |
1000 | /* Clear pending stop signals */ | |
1001 | sig_clear (SIGSTOP); | |
1002 | sig_clear (SIGTSTP); | |
1003 | sig_clear (SIGTTIN); | |
1004 | sig_clear (SIGTTOU); | |
0428827b CF |
1005 | if (stopped) |
1006 | SetEvent (sigCONT); | |
1fd5e000 | 1007 | /* process pending signals */ |
cffaf20b | 1008 | sig_dispatch_pending (1); |
1fd5e000 CF |
1009 | } |
1010 | ||
1011 | #if 0 | |
1012 | char sigmsg[24]; | |
1013 | __small_sprintf (sigmsg, "cygwin: signal %d\n", sig); | |
1014 | OutputDebugString (sigmsg); | |
1015 | #endif | |
1016 | ||
1017 | if (handler == (void *) SIG_DFL) | |
1018 | { | |
fcb76c5d | 1019 | if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH |
2402700d | 1020 | || sig == SIGURG || (thisproc && hExeced && sig == SIGINT)) |
1fd5e000 CF |
1021 | { |
1022 | sigproc_printf ("default signal %d ignored", sig); | |
1023 | goto done; | |
1024 | } | |
1025 | ||
1026 | if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) | |
1027 | goto stop; | |
1028 | ||
1029 | goto exit_sig; | |
1030 | } | |
1031 | ||
1032 | if (handler == (void *) SIG_IGN) | |
1033 | { | |
1034 | sigproc_printf ("signal %d ignored", sig); | |
1035 | goto done; | |
1036 | } | |
1037 | ||
1038 | if (handler == (void *) SIG_ERR) | |
1039 | goto exit_sig; | |
1040 | ||
1fd5e000 CF |
1041 | goto dosig; |
1042 | ||
8abeff1e | 1043 | stop: |
a7cde2b9 CF |
1044 | /* Eat multiple attempts to STOP */ |
1045 | if (ISSTATE (myself, PID_STOPPED)) | |
1046 | goto done; | |
1fd5e000 | 1047 | handler = (void *) sig_handle_tty_stop; |
c3d62298 | 1048 | thissig = myself->getsig (SIGSTOP); |
1fd5e000 | 1049 | |
8abeff1e | 1050 | dosig: |
1fd5e000 | 1051 | /* Dispatch to the appropriate function. */ |
a7cde2b9 | 1052 | sigproc_printf ("signal %d, about to call %p", sig, handler); |
206a8d88 | 1053 | rc = setup_handler (sig, handler, thissig); |
1fd5e000 | 1054 | |
8abeff1e | 1055 | done: |
1fd5e000 CF |
1056 | sigproc_printf ("returning %d", rc); |
1057 | return rc; | |
1058 | ||
8abeff1e | 1059 | exit_sig: |
1fd5e000 CF |
1060 | if (sig == SIGQUIT || sig == SIGABRT) |
1061 | { | |
8366e93b CF |
1062 | CONTEXT c; |
1063 | c.ContextFlags = CONTEXT_FULL; | |
1064 | GetThreadContext (hMainThread, &c); | |
8abeff1e | 1065 | if (!try_to_debug ()) |
f598d941 | 1066 | stackdump (c.Ebp, 1, 1); |
866c04e9 | 1067 | sig |= 0x80; |
1fd5e000 CF |
1068 | } |
1069 | sigproc_printf ("signal %d, about to call do_exit", sig); | |
866c04e9 | 1070 | signal_exit (sig); |
1fd5e000 CF |
1071 | /* Never returns */ |
1072 | } | |
1073 | ||
1074 | /* Cover function to `do_exit' to handle exiting even in presence of more | |
866c04e9 | 1075 | exceptions. We used to call exit, but a SIGSEGV shouldn't cause atexit |
1fd5e000 | 1076 | routines to run. */ |
1fd5e000 | 1077 | static void |
866c04e9 | 1078 | signal_exit (int rc) |
1fd5e000 | 1079 | { |
866c04e9 | 1080 | rc = EXIT_SIGNAL | (rc << 8); |
1fd5e000 | 1081 | if (exit_already++) |
1dc16fc7 | 1082 | myself->exit (rc); |
1fd5e000 | 1083 | |
9149d76e CF |
1084 | /* We'd like to stop the main thread from executing but when we do that it |
1085 | causes random, inexplicable hangs. So, instead, we set up the priority | |
1086 | of this thread really high so that it should do its thing and then exit. */ | |
1087 | (void) SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL); | |
747e5773 | 1088 | (void) SetThreadPriority (hMainThread, THREAD_PRIORITY_IDLE); |
9149d76e CF |
1089 | |
1090 | /* Unlock any main thread mutos since we're executing with prejudice. */ | |
1091 | muto *m; | |
1092 | for (m = muto_start.next; m != NULL; m = m->next) | |
1093 | if (m->unstable () || m->owner () == mainthread.id) | |
1094 | m->reset (); | |
1095 | ||
1096 | user_data->resourcelocks->Delete (); | |
1097 | user_data->resourcelocks->Init (); | |
1098 | ||
4c45a897 CF |
1099 | if (hExeced) |
1100 | TerminateProcess (hExeced, rc); | |
1101 | ||
e2fa5023 | 1102 | sigproc_printf ("about to call do_exit (%x)", rc); |
1fd5e000 CF |
1103 | do_exit (rc); |
1104 | } | |
1105 | ||
1fd5e000 CF |
1106 | HANDLE NO_COPY title_mutex = NULL; |
1107 | ||
1108 | void | |
1109 | events_init (void) | |
1110 | { | |
1fd5e000 CF |
1111 | /* title_mutex protects modification of console title. It's neccessary |
1112 | while finding console window handle */ | |
1113 | ||
1114 | if (!(title_mutex = CreateMutex (&sec_all_nih, FALSE, | |
1115 | shared_name ("title_mutex", 0)))) | |
1116 | api_fatal ("can't create title mutex, %E"); | |
1117 | ||
1118 | ProtectHandle (title_mutex); | |
083abe54 | 1119 | new_muto (mask_sync); |
f02f1f14 CF |
1120 | windows_system_directory[0] = '\0'; |
1121 | (void) GetSystemDirectory (windows_system_directory, sizeof (windows_system_directory) - 2); | |
1122 | char *end = strchr (windows_system_directory, '\0'); | |
1123 | if (end == windows_system_directory) | |
1124 | api_fatal ("can't find windows system directory"); | |
1125 | if (end[-1] != '\\') | |
1126 | { | |
1127 | *end++ = '\\'; | |
1128 | *end = '\0'; | |
1129 | } | |
1130 | windows_system_directory_length = end - windows_system_directory; | |
68997e88 CF |
1131 | debug_printf ("windows_system_directory '%s', windows_system_directory_length %d", |
1132 | windows_system_directory, windows_system_directory_length); | |
1133 | debug_printf ("cygwin_hmodule %p", cygwin_hmodule); | |
1fd5e000 CF |
1134 | } |
1135 | ||
1136 | void | |
1137 | events_terminate (void) | |
1138 | { | |
1fd5e000 CF |
1139 | ForceCloseHandle (title_mutex); |
1140 | exit_already = 1; | |
1141 | } | |
1142 | ||
2a1743c7 | 1143 | extern "C" { |
1ba3935d CF |
1144 | static int __stdcall |
1145 | call_signal_handler_now () | |
1146 | { | |
aed6988a CF |
1147 | if (!sigsave.sig) |
1148 | { | |
1149 | sigproc_printf ("call_signal_handler_now called when no signal active"); | |
1150 | return 0; | |
1151 | } | |
1152 | ||
1ba3935d CF |
1153 | int sa_flags = sigsave.sa_flags; |
1154 | sigproc_printf ("sa_flags %p", sa_flags); | |
1155 | *sigsave.retaddr_on_stack = sigsave.retaddr; | |
1156 | sigdelayed0 (); | |
1157 | return sa_flags & SA_RESTART; | |
1158 | } | |
aa970c61 CF |
1159 | /* This kludge seems to keep a copy of call_signal_handler_now around |
1160 | even when compiling with -finline-functions. */ | |
1161 | static int __stdcall call_signal_handler_now_dummy () | |
1162 | __attribute__((alias ("call_signal_handler_now"))); | |
2a1743c7 CF |
1163 | }; |
1164 | ||
1165 | int | |
1166 | sigframe::call_signal_handler () | |
1167 | { | |
101f820d CF |
1168 | return unregister () ? call_signal_handler_now () : 0; |
1169 | ||
2a1743c7 CF |
1170 | } |
1171 | ||
84c7d409 | 1172 | #define pid_offset (unsigned)(((_pinfo *)NULL)->pid) |
1fd5e000 | 1173 | extern "C" { |
7d72d04c | 1174 | void __stdcall |
8656ee07 CF |
1175 | reset_signal_arrived () |
1176 | { | |
1177 | (void) ResetEvent (signal_arrived); | |
1178 | sigproc_printf ("reset signal_arrived"); | |
1179 | } | |
1180 | ||
1d613351 | 1181 | void unused_sig_wrapper () |
1fd5e000 CF |
1182 | { |
1183 | /* Signal cleanup stuff. Cleans up stack (too bad that we didn't | |
1184 | prototype signal handlers as __stdcall), calls _set_process_mask | |
0826bed5 CF |
1185 | to restore any mask, restores any potentially clobbered registers |
1186 | and returns to original caller. */ | |
2116a175 | 1187 | __asm__ volatile ("\n\ |
12520587 CF |
1188 | .text \n\ |
1189 | _sigreturn: \n\ | |
1190 | addl $4,%%esp # Remove argument \n\ | |
1191 | movl %%esp,%%ebp \n\ | |
1192 | addl $36,%%ebp \n\ | |
1193 | call _set_process_mask@4 \n\ | |
1194 | \n\ | |
1195 | cmpl $0,%4 # Did a signal come in? \n\ | |
1196 | jz 1f # No, if zero \n\ | |
1197 | call _call_signal_handler_now@0 # yes handle the signal \n\ | |
1198 | \n\ | |
1199 | 1: popl %%eax # saved errno \n\ | |
1200 | testl %%eax,%%eax # Is it < 0 \n\ | |
1201 | jl 2f # yup. ignore it \n\ | |
1202 | movl %1,%%ebx \n\ | |
1203 | movl %%eax,(%%ebx) \n\ | |
1204 | 2: popl %%eax \n\ | |
1205 | popl %%ebx \n\ | |
1206 | popl %%ecx \n\ | |
1207 | popl %%edx \n\ | |
1208 | popl %%edi \n\ | |
1209 | popl %%esi \n\ | |
1210 | popf \n\ | |
1211 | popl %%ebp \n\ | |
1212 | ret \n\ | |
1213 | \n\ | |
1214 | __no_sig_start: \n\ | |
1215 | _sigdelayed: \n\ | |
1216 | pushl %2 # original return address \n\ | |
1217 | _sigdelayed0: \n\ | |
1218 | pushl %%ebp \n\ | |
1219 | movl %%esp,%%ebp \n\ | |
1220 | pushf \n\ | |
1221 | pushl %%esi \n\ | |
1222 | pushl %%edi \n\ | |
1223 | pushl %%edx \n\ | |
1224 | pushl %%ecx \n\ | |
1225 | pushl %%ebx \n\ | |
1226 | pushl %%eax \n\ | |
907dc7d0 | 1227 | pushl %6 # saved errno \n\ |
12520587 CF |
1228 | pushl %3 # oldmask \n\ |
1229 | pushl %4 # signal argument \n\ | |
1230 | pushl $_sigreturn \n\ | |
1231 | \n\ | |
1232 | call _reset_signal_arrived@0 \n\ | |
1233 | pushl %5 # signal number \n\ | |
907dc7d0 | 1234 | pushl %7 # newmask \n\ |
12520587 | 1235 | movl $0,%0 # zero the signal number as a \n\ |
2116a175 CF |
1236 | # flag to the signal handler thread\n\ |
1237 | # that it is ok to set up sigsave\n\ | |
12520587 CF |
1238 | \n\ |
1239 | call _set_process_mask@4 \n\ | |
1240 | popl %%eax \n\ | |
1241 | jmp *%%eax \n\ | |
1242 | __no_sig_end: \n\ | |
1fd5e000 CF |
1243 | " : "=m" (sigsave.sig) : "m" (&_impure_ptr->_errno), |
1244 | "g" (sigsave.retaddr), "g" (sigsave.oldmask), "g" (sigsave.sig), | |
907dc7d0 | 1245 | "g" (sigsave.func), "g" (sigsave.saved_errno), "g" (sigsave.newmask) |
1d613351 | 1246 | ); |
1fd5e000 CF |
1247 | } |
1248 | } |