]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* dcrt0.cc -- essentially the main() for the Cygwin dll |
2 | ||
66a83f3e | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
e1212c43 | 4 | 2007, 2008, 2009, 2010 |
66a83f3e | 5 | Red Hat, Inc. |
1fd5e000 CF |
6 | |
7 | This file is part of Cygwin. | |
8 | ||
9 | This software is a copyrighted work licensed under the terms of the | |
10 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
11 | details. */ | |
12 | ||
4c8d72de | 13 | #include "winsup.h" |
ade47a34 | 14 | #include "miscfuncs.h" |
1fd5e000 CF |
15 | #include <unistd.h> |
16 | #include <stdlib.h> | |
1fd5e000 | 17 | #include "glob.h" |
1fd5e000 | 18 | #include <ctype.h> |
161211d1 | 19 | #include <locale.h> |
66a83f3e | 20 | #include "environ.h" |
bccd5e0d | 21 | #include "sigproc.h" |
e2ebe117 | 22 | #include "pinfo.h" |
9e2baf8d | 23 | #include "cygerrno.h" |
f0338f54 | 24 | #define NEED_VFORK |
95a8465b | 25 | #include "perprocess.h" |
ac5561f2 | 26 | #include "path.h" |
7ac61736 | 27 | #include "fhandler.h" |
47063f00 | 28 | #include "dtable.h" |
0381fec6 | 29 | #include "cygheap.h" |
77f4a250 | 30 | #include "child_info_magic.h" |
8cb359d9 | 31 | #include "cygtls.h" |
29ac7f89 | 32 | #include "shared_info.h" |
f0338f54 | 33 | #include "cygwin_version.h" |
f0338f54 | 34 | #include "dll_init.h" |
2d1d1eb1 | 35 | #include "heap.h" |
8c4fc35e | 36 | #include "tls_pbuf.h" |
98a97ac6 | 37 | #include "exception.h" |
53c24915 | 38 | #include "cygxdr.h" |
893a8b78 | 39 | #include "ntdll.h" |
1fd5e000 CF |
40 | |
41 | #define MAX_AT_FILE_LEVEL 10 | |
42 | ||
0312ede4 | 43 | #define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0])) |
14a3bc2f | 44 | |
66a83f3e | 45 | extern "C" void cygwin_exit (int) __attribute__ ((noreturn)); |
fac0681d CF |
46 | extern "C" void __sinit (_reent *); |
47 | ||
66a83f3e CF |
48 | static int NO_COPY envc; |
49 | static char NO_COPY **envp; | |
179cae11 | 50 | |
66a83f3e | 51 | static char title_buf[TITLESIZE + 1]; |
1fd5e000 | 52 | |
3c4f2024 CF |
53 | bool NO_COPY jit_debug; |
54 | ||
1fd5e000 | 55 | static void |
3ac78fd6 | 56 | do_global_dtors () |
1fd5e000 | 57 | { |
dda06573 CF |
58 | void (**pfunc) () = user_data->dtors; |
59 | if (pfunc) | |
1fd5e000 | 60 | { |
dda06573 | 61 | user_data->dtors = NULL; |
1fd5e000 CF |
62 | while (*++pfunc) |
63 | (*pfunc) (); | |
64 | } | |
65 | } | |
66 | ||
67 | static void __stdcall | |
68 | do_global_ctors (void (**in_pfunc)(), int force) | |
69 | { | |
5d970405 | 70 | if (!force && in_forkee) |
29d52c8a | 71 | return; // inherit constructed stuff from parent pid |
1fd5e000 CF |
72 | |
73 | /* Run ctors backwards, so skip the first entry and find how many | |
74 | there are, then run them. */ | |
75 | ||
29d52c8a | 76 | void (**pfunc) () = in_pfunc; |
1fd5e000 CF |
77 | |
78 | while (*++pfunc) | |
79 | ; | |
80 | while (--pfunc > in_pfunc) | |
81 | (*pfunc) (); | |
1fd5e000 CF |
82 | } |
83 | ||
1fd5e000 | 84 | /* |
052e90e9 CF |
85 | * Replaces @file in the command line with the contents of the file. |
86 | * There may be multiple @file's in a single command line | |
87 | * A \@file is replaced with @file so that echo \@foo would print | |
88 | * @foo and not the contents of foo. | |
1fd5e000 | 89 | */ |
2e008fb9 | 90 | static bool __stdcall |
eafa31fb | 91 | insert_file (char *name, char *&cmd) |
1fd5e000 CF |
92 | { |
93 | HANDLE f; | |
94 | DWORD size; | |
8c4fc35e CV |
95 | tmp_pathbuf tp; |
96 | ||
97 | PWCHAR wname = tp.w_get (); | |
023266aa | 98 | sys_mbstowcs (wname, NT_MAX_PATH, name + 1); |
8c4fc35e CV |
99 | f = CreateFileW (wname, |
100 | GENERIC_READ, /* open for reading */ | |
101 | FILE_SHARE_READ, /* share for reading */ | |
102 | &sec_none_nih, /* default security */ | |
103 | OPEN_EXISTING, /* existing file only */ | |
104 | FILE_ATTRIBUTE_NORMAL,/* normal file */ | |
105 | NULL); /* no attr. template */ | |
1fd5e000 CF |
106 | |
107 | if (f == INVALID_HANDLE_VALUE) | |
108 | { | |
109 | debug_printf ("couldn't open file '%s', %E", name); | |
2e008fb9 | 110 | return false; |
1fd5e000 CF |
111 | } |
112 | ||
113 | /* This only supports files up to about 4 billion bytes in | |
114 | size. I am making the bold assumption that this is big | |
115 | enough for this feature */ | |
116 | size = GetFileSize (f, NULL); | |
117 | if (size == 0xFFFFFFFF) | |
118 | { | |
119 | debug_printf ("couldn't get file size for '%s', %E", name); | |
2e008fb9 | 120 | return false; |
1fd5e000 CF |
121 | } |
122 | ||
123 | int new_size = strlen (cmd) + size + 2; | |
124 | char *tmp = (char *) malloc (new_size); | |
125 | if (!tmp) | |
126 | { | |
127 | debug_printf ("malloc failed, %E"); | |
2e008fb9 | 128 | return false; |
1fd5e000 CF |
129 | } |
130 | ||
131 | /* realloc passed as it should */ | |
132 | DWORD rf_read; | |
133 | BOOL rf_result; | |
134 | rf_result = ReadFile (f, tmp, size, &rf_read, NULL); | |
135 | CloseHandle (f); | |
136 | if (!rf_result || (rf_read != size)) | |
137 | { | |
138 | debug_printf ("ReadFile failed, %E"); | |
2e008fb9 | 139 | return false; |
1fd5e000 CF |
140 | } |
141 | ||
142 | tmp[size++] = ' '; | |
143 | strcpy (tmp + size, cmd); | |
144 | cmd = tmp; | |
2e008fb9 | 145 | return true; |
1fd5e000 CF |
146 | } |
147 | ||
148 | static inline int | |
149 | isquote (char c) | |
150 | { | |
151 | char ch = c; | |
152 | return ch == '"' || ch == '\''; | |
153 | } | |
154 | ||
155 | /* Step over a run of characters delimited by quotes */ | |
8e382d80 | 156 | static /*__inline*/ char * |
9cec3d45 | 157 | quoted (char *cmd, int winshell) |
1fd5e000 CF |
158 | { |
159 | char *p; | |
160 | char quote = *cmd; | |
161 | ||
b0e82b74 | 162 | if (!winshell) |
1fd5e000 | 163 | { |
b0e82b74 CF |
164 | char *p; |
165 | strcpy (cmd, cmd + 1); | |
de9e39f7 | 166 | if (*(p = strechr (cmd, quote))) |
b0e82b74 | 167 | strcpy (p, p + 1); |
99d7d12a | 168 | return p; |
1fd5e000 CF |
169 | } |
170 | ||
4eafa56e | 171 | const char *s = quote == '\'' ? "'" : "\\\""; |
b0e82b74 CF |
172 | /* This must have been run from a Windows shell, so preserve |
173 | quotes for globify to play with later. */ | |
4eafa56e CF |
174 | while (*cmd && *++cmd) |
175 | if ((p = strpbrk (cmd, s)) == NULL) | |
b0e82b74 CF |
176 | { |
177 | cmd = strchr (cmd, '\0'); // no closing quote | |
178 | break; | |
179 | } | |
b0e82b74 CF |
180 | else if (*p == '\\') |
181 | cmd = ++p; | |
4eafa56e | 182 | else if (quote == '"' && p[1] == '"') |
b0e82b74 CF |
183 | { |
184 | *p = '\\'; | |
185 | cmd = ++p; // a quoted quote | |
186 | } | |
187 | else | |
188 | { | |
189 | cmd = p + 1; // point to after end | |
190 | break; | |
191 | } | |
192 | return cmd; | |
1fd5e000 CF |
193 | } |
194 | ||
195 | /* Perform a glob on word if it contains wildcard characters. | |
196 | Also quote every character between quotes to force glob to | |
197 | treat the characters literally. */ | |
198 | static int __stdcall | |
199 | globify (char *word, char **&argv, int &argc, int &argvlen) | |
200 | { | |
201 | if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL) | |
202 | return 0; | |
203 | ||
204 | int n = 0; | |
205 | char *p, *s; | |
75858e8a | 206 | int dos_spec = isdrive (word); |
0312ede4 | 207 | if (!dos_spec && isquote (*word) && word[1] && word[2]) |
75858e8a | 208 | dos_spec = isdrive (word + 1); |
1fd5e000 CF |
209 | |
210 | /* We'll need more space if there are quoting characters in | |
211 | word. If that is the case, doubling the size of the | |
212 | string should provide more than enough space. */ | |
213 | if (strpbrk (word, "'\"")) | |
214 | n = strlen (word); | |
215 | char pattern[strlen (word) + ((dos_spec + 1) * n) + 1]; | |
216 | ||
217 | /* Fill pattern with characters from word, quoting any | |
218 | characters found within quotes. */ | |
219 | for (p = pattern, s = word; *s != '\000'; s++, p++) | |
220 | if (!isquote (*s)) | |
221 | { | |
222 | if (dos_spec && *s == '\\') | |
223 | *p++ = '\\'; | |
224 | *p = *s; | |
225 | } | |
226 | else | |
227 | { | |
228 | char quote = *s; | |
229 | while (*++s && *s != quote) | |
230 | { | |
25ba8f30 | 231 | if (dos_spec || *s != '\\') |
c845acff | 232 | /* nothing */; |
c845acff | 233 | else if (s[1] == quote || s[1] == '\\') |
1fd5e000 CF |
234 | s++; |
235 | *p++ = '\\'; | |
855762d6 | 236 | size_t cnt = isascii (*s) ? 1 : mbtowc (NULL, s, MB_CUR_MAX); |
0351fbd5 CV |
237 | if (cnt <= 1 || cnt == (size_t)-1) |
238 | *p++ = *s; | |
239 | else | |
240 | { | |
241 | --s; | |
242 | while (cnt-- > 0) | |
243 | *p++ = *++s; | |
244 | } | |
1fd5e000 CF |
245 | } |
246 | if (*s == quote) | |
247 | p--; | |
248 | if (*s == '\0') | |
249 | break; | |
250 | } | |
251 | ||
252 | *p = '\0'; | |
253 | ||
254 | glob_t gl; | |
255 | gl.gl_offs = 0; | |
256 | ||
257 | /* Attempt to match the argument. Return just word (minus quoting) if no match. */ | |
258 | if (glob (pattern, GLOB_TILDE | GLOB_NOCHECK | GLOB_BRACE | GLOB_QUOTE, NULL, &gl) || !gl.gl_pathc) | |
259 | return 0; | |
260 | ||
261 | /* Allocate enough space in argv for the matched filenames. */ | |
262 | n = argc; | |
263 | if ((argc += gl.gl_pathc) > argvlen) | |
264 | { | |
265 | argvlen = argc + 10; | |
266 | argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0])); | |
267 | } | |
268 | ||
269 | /* Copy the matched filenames to argv. */ | |
270 | char **gv = gl.gl_pathv; | |
271 | char **av = argv + n; | |
272 | while (*gv) | |
273 | { | |
f70389b5 | 274 | debug_printf ("argv[%d] = '%s'", n++, *gv); |
1fd5e000 CF |
275 | *av++ = *gv++; |
276 | } | |
277 | ||
278 | /* Clean up after glob. */ | |
279 | free (gl.gl_pathv); | |
280 | return 1; | |
281 | } | |
282 | ||
283 | /* Build argv, argc from string passed from Windows. */ | |
284 | ||
285 | static void __stdcall | |
286 | build_argv (char *cmd, char **&argv, int &argc, int winshell) | |
287 | { | |
288 | int argvlen = 0; | |
1fd5e000 CF |
289 | int nesting = 0; // monitor "nesting" from insert_file |
290 | ||
291 | argc = 0; | |
292 | argvlen = 0; | |
293 | argv = NULL; | |
294 | ||
295 | /* Scan command line until there is nothing left. */ | |
296 | while (*cmd) | |
297 | { | |
298 | /* Ignore spaces */ | |
299 | if (issep (*cmd)) | |
300 | { | |
301 | cmd++; | |
302 | continue; | |
303 | } | |
304 | ||
305 | /* Found the beginning of an argument. */ | |
306 | char *word = cmd; | |
307 | char *sawquote = NULL; | |
308 | while (*cmd) | |
309 | { | |
310 | if (*cmd != '"' && (!winshell || *cmd != '\'')) | |
311 | cmd++; // Skip over this character | |
312 | else | |
313 | /* Skip over characters until the closing quote */ | |
314 | { | |
315 | sawquote = cmd; | |
2768430b | 316 | cmd = quoted (cmd, winshell && argc > 0); |
1fd5e000 CF |
317 | } |
318 | if (issep (*cmd)) // End of argument if space | |
319 | break; | |
320 | } | |
321 | if (*cmd) | |
322 | *cmd++ = '\0'; // Terminate `word' | |
323 | ||
324 | /* Possibly look for @file construction assuming that this isn't | |
325 | the very first argument and the @ wasn't quoted */ | |
326 | if (argc && sawquote != word && *word == '@') | |
327 | { | |
328 | if (++nesting > MAX_AT_FILE_LEVEL) | |
329 | api_fatal ("Too many levels of nesting for %s", word); | |
eafa31fb | 330 | if (insert_file (word, cmd)) |
1fd5e000 | 331 | continue; // There's new stuff in cmd now |
1fd5e000 CF |
332 | } |
333 | ||
334 | /* See if we need to allocate more space for argv */ | |
335 | if (argc >= argvlen) | |
336 | { | |
337 | argvlen = argc + 10; | |
338 | argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0])); | |
339 | } | |
340 | ||
341 | /* Add word to argv file after (optional) wildcard expansion. */ | |
342 | if (!winshell || !argc || !globify (word, argv, argc, argvlen)) | |
343 | { | |
f70389b5 | 344 | debug_printf ("argv[%d] = '%s'", argc, word); |
1fd5e000 CF |
345 | argv[argc++] = word; |
346 | } | |
347 | } | |
348 | ||
349 | argv[argc] = NULL; | |
b0e82b74 CF |
350 | |
351 | debug_printf ("argc %d", argc); | |
1fd5e000 CF |
352 | } |
353 | ||
354 | /* sanity and sync check */ | |
355 | void __stdcall | |
356 | check_sanity_and_sync (per_process *p) | |
357 | { | |
358 | /* Sanity check to make sure developers didn't change the per_process */ | |
359 | /* struct without updating SIZEOF_PER_PROCESS [it makes them think twice */ | |
360 | /* about changing it]. */ | |
361 | if (sizeof (per_process) != SIZEOF_PER_PROCESS) | |
c16548b2 | 362 | api_fatal ("per_process sanity check failed"); |
1fd5e000 CF |
363 | |
364 | /* Make sure that the app and the dll are in sync. */ | |
365 | ||
366 | /* Complain if older than last incompatible change */ | |
367 | if (p->dll_major < CYGWIN_VERSION_DLL_EPOCH) | |
368 | api_fatal ("cygwin DLL and APP are out of sync -- DLL version mismatch %d < %d", | |
369 | p->dll_major, CYGWIN_VERSION_DLL_EPOCH); | |
370 | ||
371 | /* magic_biscuit != 0 if using the old style version numbering scheme. */ | |
372 | if (p->magic_biscuit != SIZEOF_PER_PROCESS) | |
373 | api_fatal ("Incompatible cygwin .dll -- incompatible per_process info %d != %d", | |
374 | p->magic_biscuit, SIZEOF_PER_PROCESS); | |
375 | ||
376 | /* Complain if incompatible API changes made */ | |
876083f3 CF |
377 | if (p->api_major > cygwin_version.api_major) |
378 | api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d > %d", | |
1fd5e000 | 379 | p->api_major, cygwin_version.api_major); |
284c5ea0 CF |
380 | |
381 | /* This is a kludge to work around a version of _cygwin_common_crt0 | |
382 | which overwrote the cxx_malloc field with the local DLL copy. | |
383 | Hilarity ensues if the DLL is not loaded while the process | |
384 | is forking. */ | |
385 | __cygwin_user_data.cxx_malloc = &default_cygwin_cxx_malloc; | |
1fd5e000 CF |
386 | } |
387 | ||
6ea3e429 | 388 | child_info NO_COPY *child_proc_info = NULL; |
1fd5e000 | 389 | |
39fc0d36 | 390 | #define CYGWIN_GUARD (PAGE_EXECUTE_READWRITE | PAGE_GUARD) |
e13ea334 | 391 | |
9dbb0bc3 CF |
392 | void |
393 | child_info_fork::alloc_stack_hard_way (volatile char *b) | |
1fd5e000 CF |
394 | { |
395 | void *new_stack_pointer; | |
396 | MEMORY_BASIC_INFORMATION m; | |
b0e82b74 CF |
397 | void *newbase; |
398 | int newlen; | |
39fc0d36 | 399 | bool guard; |
1fd5e000 | 400 | |
1a6aafd0 CF |
401 | if (!VirtualQuery ((LPCVOID) &b, &m, sizeof m)) |
402 | api_fatal ("fork: couldn't get stack info, %E"); | |
403 | ||
404 | LPBYTE curbot = (LPBYTE) m.BaseAddress + m.RegionSize; | |
405 | ||
9dbb0bc3 | 406 | if (stacktop > (LPBYTE) m.AllocationBase && stacktop < curbot) |
b0e82b74 CF |
407 | { |
408 | newbase = curbot; | |
9dbb0bc3 | 409 | newlen = (LPBYTE) stackbottom - (LPBYTE) curbot; |
39fc0d36 | 410 | guard = false; |
b0e82b74 CF |
411 | } |
412 | else | |
413 | { | |
39fc0d36 CF |
414 | newbase = (LPBYTE) stacktop - (128 * 1024); |
415 | newlen = (LPBYTE) stackbottom - (LPBYTE) newbase; | |
416 | guard = true; | |
b0e82b74 | 417 | } |
39fc0d36 | 418 | |
b0e82b74 | 419 | if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS)) |
1fd5e000 | 420 | api_fatal ("fork: can't reserve memory for stack %p - %p, %E", |
9dbb0bc3 | 421 | stacktop, stackbottom); |
39fc0d36 | 422 | new_stack_pointer = (void *) ((LPBYTE) stackbottom - (stacksize += 8192)); |
9dbb0bc3 | 423 | if (!VirtualAlloc (new_stack_pointer, stacksize, MEM_COMMIT, |
1fd5e000 CF |
424 | PAGE_EXECUTE_READWRITE)) |
425 | api_fatal ("fork: can't commit memory for stack %p(%d), %E", | |
9dbb0bc3 | 426 | new_stack_pointer, stacksize); |
1fd5e000 CF |
427 | if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m)) |
428 | api_fatal ("fork: couldn't get new stack info, %E"); | |
39fc0d36 CF |
429 | |
430 | if (guard) | |
b0e82b74 | 431 | { |
39fc0d36 | 432 | m.BaseAddress = (LPBYTE) m.BaseAddress - 1; |
b0e82b74 | 433 | if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT, |
a54ad580 | 434 | CYGWIN_GUARD)) |
b0e82b74 CF |
435 | api_fatal ("fork: couldn't allocate new stack guard page %p, %E", |
436 | m.BaseAddress); | |
437 | } | |
1fd5e000 CF |
438 | if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m)) |
439 | api_fatal ("fork: couldn't get new stack info, %E"); | |
9dbb0bc3 | 440 | stacktop = m.BaseAddress; |
c21e74cc | 441 | b[0] = '\0'; |
1fd5e000 CF |
442 | } |
443 | ||
280fdd0b CF |
444 | void *getstack (void *) __attribute__ ((noinline)); |
445 | volatile char * | |
e7f6a31b | 446 | getstack (volatile char * volatile p) |
280fdd0b | 447 | { |
e7f6a31b CF |
448 | *p ^= 1; |
449 | *p ^= 1; | |
280fdd0b CF |
450 | return p - 4096; |
451 | } | |
452 | ||
1fd5e000 CF |
453 | /* extend the stack prior to fork longjmp */ |
454 | ||
9dbb0bc3 CF |
455 | void |
456 | child_info_fork::alloc_stack () | |
1fd5e000 | 457 | { |
e7f6a31b | 458 | volatile char * volatile esp; |
280fdd0b | 459 | __asm__ volatile ("movl %%esp,%0": "=r" (esp)); |
9dbb0bc3 CF |
460 | if (_tlsbase != stackbottom) |
461 | alloc_stack_hard_way (esp); | |
c21e74cc | 462 | else |
280fdd0b | 463 | { |
9dbb0bc3 CF |
464 | char *st = (char *) stacktop - 4096; |
465 | while (_tlstop >= st) | |
280fdd0b | 466 | esp = getstack (esp); |
9dbb0bc3 | 467 | stacksize = 0; |
280fdd0b | 468 | } |
1fd5e000 CF |
469 | } |
470 | ||
35016286 | 471 | extern "C" void |
2d1d1eb1 CF |
472 | break_here () |
473 | { | |
35016286 CF |
474 | static int NO_COPY sent_break; |
475 | if (!sent_break++) | |
476 | DebugBreak (); | |
2d1d1eb1 CF |
477 | debug_printf ("break here"); |
478 | } | |
2d1d1eb1 | 479 | |
1fd5e000 | 480 | static void |
0e061ecf | 481 | initial_env () |
1fd5e000 | 482 | { |
5ab0b5cf | 483 | if (GetEnvironmentVariableA ("CYGWIN_TESTING", NULL, 0)) |
d795119c | 484 | _cygwin_testing = 1; |
0e061ecf | 485 | |
2d1d1eb1 | 486 | #ifdef DEBUGGING |
5ab0b5cf | 487 | char buf[NT_MAX_PATH]; |
2d1d1eb1 | 488 | DWORD len; |
d795119c | 489 | |
5ab0b5cf | 490 | if (GetEnvironmentVariableA ("CYGWIN_SLEEP", buf, sizeof (buf) - 1)) |
2d1d1eb1 CF |
491 | { |
492 | DWORD ms = atoi (buf); | |
1feea0bf | 493 | console_printf ("Sleeping %d, pid %u %P\n", ms, GetCurrentProcessId ()); |
f6936c48 | 494 | Sleep (ms); |
5d970405 CF |
495 | if (!strace.active () && !dynamically_loaded) |
496 | strace.hello (); | |
2d1d1eb1 | 497 | } |
5ab0b5cf | 498 | if (GetEnvironmentVariableA ("CYGWIN_DEBUG", buf, sizeof (buf) - 1)) |
2d1d1eb1 | 499 | { |
7b4b41ab CV |
500 | char buf1[NT_MAX_PATH]; |
501 | len = GetModuleFileName (NULL, buf1, NT_MAX_PATH); | |
2d1d1eb1 CF |
502 | strlwr (buf1); |
503 | strlwr (buf); | |
491e84c6 | 504 | char *p = strpbrk (buf, ":="); |
2d1d1eb1 CF |
505 | if (!p) |
506 | p = (char *) "gdb.exe -nw"; | |
507 | else | |
508 | *p++ = '\0'; | |
509 | if (strstr (buf1, buf)) | |
510 | { | |
511 | error_start_init (p); | |
3c4f2024 | 512 | jit_debug = true; |
2d1d1eb1 | 513 | try_to_debug (); |
0e061ecf | 514 | console_printf ("*** Sending Break. gdb may issue spurious SIGTRAP message.\n"); |
2d1d1eb1 CF |
515 | break_here (); |
516 | } | |
517 | } | |
518 | #endif | |
1fd5e000 | 519 | |
2d1d1eb1 | 520 | } |
b0e82b74 | 521 | |
1cd8ccec CF |
522 | child_info * |
523 | get_cygwin_startup_info () | |
2d1d1eb1 | 524 | { |
1cd8ccec | 525 | STARTUPINFO si; |
fe4283af | 526 | |
2d1d1eb1 | 527 | GetStartupInfo (&si); |
1cd8ccec | 528 | child_info *res = (child_info *) si.lpReserved2; |
c6674b53 | 529 | |
1cd8ccec | 530 | if (si.cbReserved2 < EXEC_MAGIC_SIZE || !res |
c16548b2 | 531 | || res->intro != PROC_MAGIC_GENERIC || res->magic != CHILD_INFO_MAGIC) |
1cd8ccec | 532 | res = NULL; |
2d1d1eb1 CF |
533 | else |
534 | { | |
1cd8ccec CF |
535 | if ((res->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC) |
536 | multiple_cygwin_problem ("proc intro", res->intro, 0); | |
1cd8ccec CF |
537 | else if (res->cygheap != (void *) &_cygheap_start) |
538 | multiple_cygwin_problem ("cygheap base", (DWORD) res->cygheap, | |
2d1d1eb1 | 539 | (DWORD) &_cygheap_start); |
1cd8ccec | 540 | |
2d1d1eb1 | 541 | unsigned should_be_cb = 0; |
1cd8ccec | 542 | switch (res->type) |
2d1d1eb1 CF |
543 | { |
544 | case _PROC_FORK: | |
5d970405 | 545 | in_forkee = true; |
2d1d1eb1 CF |
546 | should_be_cb = sizeof (child_info_fork); |
547 | /* fall through */; | |
548 | case _PROC_SPAWN: | |
549 | case _PROC_EXEC: | |
550 | if (!should_be_cb) | |
54dd79bb | 551 | should_be_cb = sizeof (child_info_spawn); |
1cd8ccec CF |
552 | if (should_be_cb != res->cb) |
553 | multiple_cygwin_problem ("proc size", res->cb, should_be_cb); | |
554 | else if (sizeof (fhandler_union) != res->fhandler_union_cb) | |
555 | multiple_cygwin_problem ("fhandler size", res->fhandler_union_cb, sizeof (fhandler_union)); | |
c1494e03 | 556 | if (res->isstraced ()) |
5d970405 CF |
557 | { |
558 | res->ready (false); | |
5d970405 | 559 | for (unsigned i = 0; !being_debugged () && i < 10000; i++) |
084ea510 | 560 | yield (); |
5d970405 CF |
561 | strace.hello (); |
562 | } | |
2380dfe1 | 563 | break; |
2d1d1eb1 | 564 | default: |
1cd8ccec | 565 | system_printf ("unknown exec type %d", res->type); |
2d1d1eb1 CF |
566 | /* intentionally fall through */ |
567 | case _PROC_WHOOPS: | |
1cd8ccec | 568 | res = NULL; |
2d1d1eb1 CF |
569 | break; |
570 | } | |
571 | } | |
572 | ||
1cd8ccec CF |
573 | return res; |
574 | } | |
575 | ||
ad02bb70 CF |
576 | #define dll_data_start &_data_start__ |
577 | #define dll_data_end &_data_end__ | |
578 | #define dll_bss_start &_bss_start__ | |
579 | #define dll_bss_end &_bss_end__ | |
580 | ||
581 | void | |
5d970405 | 582 | child_info_fork::handle_fork () |
ad02bb70 | 583 | { |
ad02bb70 | 584 | cygheap_fixup_in_child (false); |
71f53a2f | 585 | memory_init (false); |
9ac42168 | 586 | myself.thisproc (NULL); |
12b33712 CF |
587 | myself->uid = cygheap->user.real_uid; |
588 | myself->gid = cygheap->user.real_gid; | |
589 | ||
5d970405 | 590 | child_copy (parent, false, |
ad02bb70 CF |
591 | "dll data", dll_data_start, dll_data_end, |
592 | "dll bss", dll_bss_start, dll_bss_end, | |
593 | "user heap", cygheap->user_heap.base, cygheap->user_heap.ptr, | |
594 | NULL); | |
27f564e9 CF |
595 | |
596 | /* Do the relocations here. These will actually likely be overwritten by the | |
597 | below child_copy but we do them here in case there is a read-only section | |
598 | which does not get copied by fork. */ | |
599 | _pei386_runtime_relocator (user_data); | |
600 | ||
ad02bb70 CF |
601 | /* step 2 now that the dll has its heap filled in, we can fill in the |
602 | user's data and bss since user_data is now filled out. */ | |
5d970405 | 603 | child_copy (parent, false, |
ad02bb70 CF |
604 | "data", user_data->data_start, user_data->data_end, |
605 | "bss", user_data->bss_start, user_data->bss_end, | |
606 | NULL); | |
607 | ||
5d970405 | 608 | if (fixup_mmaps_after_fork (parent)) |
ad02bb70 CF |
609 | api_fatal ("recreate_mmaps_after_fork_failed"); |
610 | } | |
611 | ||
c1494e03 CF |
612 | void |
613 | child_info_spawn::handle_spawn () | |
614 | { | |
a998dd70 | 615 | extern void fixup_lockf_after_exec (); |
c1494e03 CF |
616 | HANDLE h; |
617 | cygheap_fixup_in_child (true); | |
71f53a2f | 618 | memory_init (false); |
c1494e03 | 619 | if (!moreinfo->myself_pinfo || |
f16706de CV |
620 | !DuplicateHandle (GetCurrentProcess (), moreinfo->myself_pinfo, |
621 | GetCurrentProcess (), &h, 0, | |
c1494e03 CF |
622 | FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) |
623 | h = NULL; | |
9ac42168 | 624 | myself.thisproc (h); |
c1494e03 CF |
625 | __argc = moreinfo->argc; |
626 | __argv = moreinfo->argv; | |
627 | envp = moreinfo->envp; | |
628 | envc = moreinfo->envc; | |
629 | if (!dynamically_loaded) | |
630 | cygheap->fdtab.fixup_after_exec (); | |
c16548b2 CF |
631 | if (__stdin >= 0) |
632 | cygheap->fdtab.move_fd (__stdin, 0); | |
633 | if (__stdout >= 0) | |
634 | cygheap->fdtab.move_fd (__stdout, 1); | |
5558de95 | 635 | cygheap->user.groups.clear_supp (); |
c16548b2 | 636 | |
578e142a | 637 | ready (true); |
2346864a CF |
638 | |
639 | /* Need to do this after debug_fixup_after_fork_exec or DEBUGGING handling of | |
640 | handles might get confused. */ | |
641 | CloseHandle (child_proc_info->parent); | |
642 | child_proc_info->parent = NULL; | |
643 | ||
c1494e03 CF |
644 | signal_fixup_after_exec (); |
645 | if (moreinfo->old_title) | |
646 | { | |
647 | old_title = strcpy (title_buf, moreinfo->old_title); | |
648 | cfree (moreinfo->old_title); | |
649 | } | |
a998dd70 | 650 | fixup_lockf_after_exec (); |
c1494e03 CF |
651 | } |
652 | ||
06281845 CV |
653 | #if 0 |
654 | /* Setting the TS-aware flag in the application's PE header is sufficient. | |
655 | Just keep this in as a reminder. */ | |
656 | ||
babd4a9c CV |
657 | static DEP_SYSTEM_POLICY_TYPE dep_system_policy = (DEP_SYSTEM_POLICY_TYPE) -1; |
658 | ||
659 | static void | |
660 | disable_dep () | |
661 | { | |
662 | DWORD ppolicy; | |
663 | BOOL perm; | |
664 | ||
665 | if (dep_system_policy < 0) | |
666 | { | |
667 | dep_system_policy = GetSystemDEPPolicy (); | |
668 | debug_printf ("DEP System Policy: %d", (int) dep_system_policy); | |
669 | } | |
670 | if (dep_system_policy < OptIn) | |
671 | return; | |
f16706de | 672 | if (!GetProcessDEPPolicy (GetCurrentProcess (), &ppolicy, &perm)) |
babd4a9c CV |
673 | { |
674 | debug_printf ("GetProcessDEPPolicy: %E"); | |
675 | return; | |
676 | } | |
677 | debug_printf ("DEP Process Policy: %d (permanent = %d)", ppolicy, perm); | |
678 | if (ppolicy > 0 && !perm && !SetProcessDEPPolicy (0)) | |
679 | debug_printf ("SetProcessDEPPolicy: %E"); | |
680 | } | |
06281845 | 681 | #endif |
babd4a9c | 682 | |
893a8b78 CV |
683 | /* Retrieve and store system directory for later use. Note that the |
684 | directory is stored with a trailing backslash! */ | |
685 | static void | |
686 | init_windows_system_directory () | |
687 | { | |
688 | windows_system_directory_length = | |
689 | GetSystemDirectoryW (windows_system_directory, MAX_PATH); | |
690 | if (windows_system_directory_length == 0) | |
691 | api_fatal ("can't find windows system directory"); | |
692 | windows_system_directory[windows_system_directory_length++] = L'\\'; | |
693 | windows_system_directory[windows_system_directory_length] = L'\0'; | |
694 | } | |
695 | ||
1cd8ccec CF |
696 | void __stdcall |
697 | dll_crt0_0 () | |
698 | { | |
893a8b78 | 699 | init_windows_system_directory (); |
2b91e0da | 700 | init_global_security (); |
bbca1e4c CF |
701 | initial_env (); |
702 | ||
346cdb43 | 703 | SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); |
d4d63ebf | 704 | |
82c925af | 705 | lock_process::init (); |
280fdd0b CF |
706 | _impure_ptr = _GLOBAL_REENT; |
707 | _impure_ptr->_stdin = &_impure_ptr->__sf[0]; | |
708 | _impure_ptr->_stdout = &_impure_ptr->__sf[1]; | |
709 | _impure_ptr->_stderr = &_impure_ptr->__sf[2]; | |
710 | _impure_ptr->_current_locale = "C"; | |
5d970405 CF |
711 | user_data->impure_ptr = _impure_ptr; |
712 | user_data->impure_ptr_ptr = &_impure_ptr; | |
1cd8ccec | 713 | |
1b71ce00 CV |
714 | DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), |
715 | GetCurrentProcess (), &hMainThread, | |
716 | 0, false, DUPLICATE_SAME_ACCESS); | |
717 | ||
f16706de | 718 | OpenProcessToken (GetCurrentProcess (), MAXIMUM_ALLOWED, &hProcToken); |
5fbf573c | 719 | set_cygwin_privileges (hProcToken); |
1cd8ccec | 720 | |
2d1d1eb1 | 721 | device::init (); |
2d1d1eb1 CF |
722 | do_global_ctors (&__CTOR_LIST__, 1); |
723 | cygthread::init (); | |
b0e82b74 | 724 | |
1cd8ccec | 725 | child_proc_info = get_cygwin_startup_info (); |
fdb28b5e | 726 | if (!child_proc_info) |
71f53a2f | 727 | memory_init (true); |
fdb28b5e | 728 | else |
b0e82b74 | 729 | { |
1cd8ccec | 730 | cygwin_user_h = child_proc_info->user_h; |
77f4a250 | 731 | switch (child_proc_info->type) |
b0e82b74 | 732 | { |
57013c31 | 733 | case _PROC_FORK: |
5d970405 | 734 | fork_info->handle_fork (); |
b0e82b74 | 735 | break; |
57013c31 | 736 | case _PROC_SPAWN: |
57013c31 | 737 | case _PROC_EXEC: |
c1494e03 | 738 | spawn_info->handle_spawn (); |
b0e82b74 CF |
739 | break; |
740 | } | |
741 | } | |
1fd5e000 | 742 | |
0ce97eb4 CF |
743 | user_data->threadinterface->Init (); |
744 | ||
e431827c | 745 | _cygtls::init (); |
2d1d1eb1 CF |
746 | |
747 | /* Initialize events */ | |
748 | events_init (); | |
71d59a92 | 749 | tty_list::init_session (); |
2d1d1eb1 | 750 | |
06281845 CV |
751 | #if 0 |
752 | /* Setting the TS-aware flag in the application's PE header is sufficient. | |
753 | Just keep this in as a reminder. */ | |
babd4a9c | 754 | |
06281845 | 755 | /* The disable_dep function disables DEP for all Cygwin processes if |
babd4a9c CV |
756 | the process runs on a Windows Server 2008 with Terminal Services |
757 | installed. This combination (TS+DEP) breaks *some* Cygwin | |
758 | applications. The Terminal Service specific DLL tsappcmp.dll | |
759 | changes the page protection of some pages in the application's text | |
760 | segment from PAGE_EXECUTE_WRITECOPY to PAGE_WRITECOPY for no | |
761 | apparent reason. This occurs before any Cygwin or applicaton code | |
762 | had a chance to run. MS has no explanation for this so far, but is | |
763 | rather busy trying to avoid giving support for this problem (as of | |
764 | 2008-11-11). | |
765 | ||
766 | Unfortunately disabling DEP seems to have a not negligible | |
767 | performance hit. In the long run, either MS has to fix their | |
768 | problem, or we have to find a better workaround, if any exists. | |
769 | Idle idea: Adding EXECUTE protection to all text segment pages? */ | |
770 | if (wincap.ts_has_dep_problem ()) | |
771 | disable_dep (); | |
06281845 | 772 | #endif |
babd4a9c | 773 | |
6c6eb02b CF |
774 | /* Initialize signal processing here, early, in the hopes that the creation |
775 | of a thread early in the process will cause more predictability in memory | |
776 | layout for the main thread. */ | |
b6473313 | 777 | if (!wincap.has_buggy_thread_startup () && !dynamically_loaded) |
6c6eb02b CF |
778 | sigproc_init (); |
779 | ||
5d970405 | 780 | debug_printf ("finished dll_crt0_0 initialization"); |
2d1d1eb1 CF |
781 | } |
782 | ||
783 | /* Take over from libc's crt0.o and start the application. Note the | |
784 | various special cases when Cygwin DLL is being runtime loaded (as | |
785 | opposed to being link-time loaded by Cygwin apps) from a non | |
786 | cygwin app via LoadLibrary. */ | |
2346864a CF |
787 | void |
788 | dll_crt0_1 (void *) | |
2d1d1eb1 | 789 | { |
0ca6c6b8 CV |
790 | extern void initial_setlocale (); |
791 | ||
b6473313 | 792 | if (wincap.has_buggy_thread_startup () || dynamically_loaded) |
58569753 | 793 | sigproc_init (); |
2d1d1eb1 | 794 | check_sanity_and_sync (user_data); |
e643b202 | 795 | |
038af334 CF |
796 | /* Initialize malloc and then call user_shared_initialize since it relies |
797 | on a functioning malloc and it's possible that the user's program may | |
798 | have overridden malloc. We only know about that at this stage, | |
799 | unfortunately. */ | |
800 | malloc_init (); | |
cef5dfd7 | 801 | user_shared->initialize (); |
e643b202 | 802 | |
6a7bea70 CF |
803 | #ifdef CGF |
804 | int i = 0; | |
0d339267 CF |
805 | const int n = 2 * 1024 * 1024; |
806 | while (i--) | |
807 | small_printf ("cmalloc returns %p\n", cmalloc (HEAP_STR, n)); | |
6a7bea70 | 808 | #endif |
2d1d1eb1 | 809 | |
1b71ce00 CV |
810 | ProtectHandle (hMainThread); |
811 | ||
9749fd08 CV |
812 | cygheap->cwd.init (); |
813 | ||
9a4d574b | 814 | /* Initialize pthread mainthread when not forked and it is safe to call new, |
c8fa3426 | 815 | otherwise it is reinitalized in fixup_after_fork */ |
5d970405 | 816 | if (!in_forkee) |
27f564e9 CF |
817 | { |
818 | pthread::init_mainthread (); | |
819 | _pei386_runtime_relocator (user_data); | |
820 | } | |
f8c8e13b | 821 | |
b9621e8d CF |
822 | #ifdef DEBUGGING |
823 | strace.microseconds (); | |
824 | #endif | |
825 | ||
12b33712 | 826 | create_signal_arrived (); /* FIXME: move into wait_sig? */ |
a9c46162 | 827 | |
3d0ba393 CF |
828 | /* Initialize debug muto, if DLL is built with --enable-debugging. |
829 | Need to do this before any helper threads start. */ | |
830 | debug_init (); | |
831 | ||
f7239090 | 832 | #ifdef NEWVFORK |
0381fec6 | 833 | cygheap->fdtab.vfork_child_fixup (); |
9661a0c8 | 834 | main_vfork = vfork_storage.create (); |
f7239090 | 835 | #endif |
6e8f36bc | 836 | |
166b2571 | 837 | cygbench ("pre-forkee"); |
5d970405 | 838 | if (in_forkee) |
1fd5e000 CF |
839 | { |
840 | /* If we've played with the stack, stacksize != 0. That means that | |
841 | fork() was invoked from other than the main thread. Make sure that | |
842 | frame pointer is referencing the new stack so that the OS knows what | |
843 | to do when it needs to increase the size of the stack. | |
844 | ||
845 | NOTE: Don't do anything that involves the stack until you've completed | |
846 | this step. */ | |
b0e82b74 | 847 | if (fork_info->stacksize) |
1fd5e000 | 848 | { |
c350feda CF |
849 | _tlsbase = (char *) fork_info->stackbottom; |
850 | _tlstop = (char *) fork_info->stacktop; | |
1fd5e000 | 851 | } |
39fc0d36 | 852 | |
d584454c | 853 | longjmp (fork_info->jmp, true); |
1fd5e000 CF |
854 | } |
855 | ||
b6473313 CF |
856 | __sinit (_impure_ptr); |
857 | ||
84aeff41 CF |
858 | #ifdef DEBUGGING |
859 | { | |
860 | extern void fork_init (); | |
861 | fork_init (); | |
862 | } | |
863 | #endif | |
81010d21 | 864 | pinfo_init (envp, envc); |
84aeff41 | 865 | |
1fd5e000 | 866 | if (!old_title && GetConsoleTitle (title_buf, TITLESIZE)) |
12b33712 | 867 | old_title = title_buf; |
1fd5e000 | 868 | |
0381fec6 | 869 | /* Allocate cygheap->fdtab */ |
e2ebe117 | 870 | dtable_init (); |
1fd5e000 | 871 | |
81010d21 CF |
872 | uinfo_init (); /* initialize user info */ |
873 | ||
1fd5e000 | 874 | /* Connect to tty. */ |
71d59a92 | 875 | tty::init_session (); |
1fd5e000 | 876 | |
1afba8e5 CF |
877 | /* Set internal locale to the environment settings. */ |
878 | initial_setlocale (); | |
879 | ||
b0e82b74 | 880 | if (!__argc) |
1fd5e000 | 881 | { |
1597484c | 882 | PWCHAR wline = GetCommandLineW (); |
6542ddc3 | 883 | size_t size = sys_wcstombs (NULL, 0, wline); |
1597484c CV |
884 | char *line = (char *) alloca (size); |
885 | sys_wcstombs (line, size, wline); | |
ee1d77e4 | 886 | |
b0e82b74 CF |
887 | /* Scan the command line and build argv. Expand wildcards if not |
888 | called from another cygwin process. */ | |
889 | build_argv (line, __argv, __argc, | |
890 | NOTSTATE (myself, PID_CYGPARENT) && allow_glob); | |
891 | ||
892 | /* Convert argv[0] to posix rules if it's currently blatantly | |
893 | win32 style. */ | |
894 | if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\'))) | |
895 | { | |
7b4b41ab | 896 | char *new_argv0 = (char *) malloc (NT_MAX_PATH); |
edab6053 CV |
897 | cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, __argv[0], |
898 | new_argv0, NT_MAX_PATH); | |
76832a5b | 899 | __argv[0] = (char *) realloc (new_argv0, strlen (new_argv0) + 1); |
b0e82b74 | 900 | } |
1fd5e000 CF |
901 | } |
902 | ||
3ef50005 | 903 | __argc_safe = __argc; |
b0e82b74 CF |
904 | if (user_data->premain[0]) |
905 | for (unsigned int i = 0; i < PREMAIN_LEN / 2; i++) | |
95a8465b | 906 | user_data->premain[i] (__argc, __argv, user_data); |
b0e82b74 | 907 | |
1ac6d1a1 | 908 | /* Set up standard fds in file descriptor table. */ |
083abe54 | 909 | cygheap->fdtab.stdio_init (); |
1ac6d1a1 | 910 | |
1fd5e000 | 911 | /* Set up __progname for getopt error call. */ |
eba23038 CV |
912 | if (__argv[0] && (__progname = strrchr (__argv[0], '/'))) |
913 | ++__progname; | |
914 | else | |
915 | __progname = __argv[0]; | |
916 | if (__progname) | |
917 | { | |
918 | char *cp = strchr (__progname, '\0') - 4; | |
c69d873f | 919 | if (cp > __progname && ascii_strcasematch (cp, ".exe")) |
eba23038 CV |
920 | *cp = '\0'; |
921 | } | |
1fd5e000 | 922 | |
1dc16fc7 CF |
923 | /* Set new console title if appropriate. */ |
924 | ||
925 | if (display_title && !dynamically_loaded) | |
926 | { | |
927 | char *cp = __progname; | |
928 | if (strip_title_path) | |
929 | for (char *ptr = cp; *ptr && *ptr != ' '; ptr++) | |
930 | if (isdirsep (*ptr)) | |
931 | cp = ptr + 1; | |
932 | set_console_title (cp); | |
933 | } | |
934 | ||
53c24915 | 935 | (void) xdr_set_vprintf (&cygxdr_vwarnx); |
e431827c | 936 | cygwin_finished_initializing = true; |
2eb392bd CF |
937 | /* Call init of loaded dlls. */ |
938 | dlls.init (); | |
1fd5e000 | 939 | |
14a3bc2f | 940 | /* Execute any specified "premain" functions */ |
737a86d3 | 941 | if (user_data->premain[PREMAIN_LEN / 2]) |
14a3bc2f | 942 | for (unsigned int i = PREMAIN_LEN / 2; i < PREMAIN_LEN; i++) |
95a8465b | 943 | user_data->premain[i] (__argc, __argv, user_data); |
14a3bc2f | 944 | |
6c6eb02b | 945 | set_errno (0); |
2eb392bd | 946 | |
5bc584ba | 947 | if (dynamically_loaded) |
6c6eb02b | 948 | return; |
5bc584ba | 949 | |
6ccb6bcf | 950 | /* Disable case-insensitive globbing */ |
2e008fb9 | 951 | ignore_case_with_glob = false; |
6ccb6bcf | 952 | |
b0e82b74 | 953 | MALLOC_CHECK; |
166b2571 | 954 | cygbench (__progname); |
29d52c8a | 955 | |
b1d9a0bd | 956 | ld_preload (); |
41d184bb CV |
957 | /* Per POSIX set the default application locale back to "C". */ |
958 | _setlocale_r (_REENT, LC_CTYPE, "C"); | |
6c6eb02b | 959 | |
64b30629 | 960 | if (user_data->main) |
a586e5b6 | 961 | cygwin_exit (user_data->main (__argc, __argv, *user_data->envptr)); |
b23b1716 CF |
962 | __asm__ (" \n\ |
963 | .global __cygwin_exit_return \n\ | |
964 | __cygwin_exit_return: \n\ | |
965 | "); | |
1fd5e000 CF |
966 | } |
967 | ||
72f8054f CF |
968 | extern "C" void __stdcall |
969 | _dll_crt0 () | |
1fd5e000 | 970 | { |
2eb392bd | 971 | main_environ = user_data->envptr; |
5d970405 | 972 | if (in_forkee) |
b6473313 | 973 | fork_info->alloc_stack (); |
5e0f482f | 974 | |
b6473313 | 975 | _main_tls = &_my_tls; |
38229bcd | 976 | _main_tls->call ((DWORD (*) (void *, void *)) dll_crt0_1, NULL); |
1fd5e000 CF |
977 | } |
978 | ||
14a3bc2f CF |
979 | void |
980 | dll_crt0 (per_process *uptr) | |
981 | { | |
982 | /* Set the local copy of the pointer into the user space. */ | |
5d970405 | 983 | if (!in_forkee && uptr && uptr != user_data) |
737a86d3 CF |
984 | { |
985 | memcpy (user_data, uptr, per_process_overwrite); | |
22a1a24f | 986 | *(user_data->impure_ptr_ptr) = _GLOBAL_REENT; |
737a86d3 | 987 | } |
72f8054f | 988 | _dll_crt0 (); |
14a3bc2f CF |
989 | } |
990 | ||
6e780c8b | 991 | /* This must be called by anyone who uses LoadLibrary to load cygwin1.dll. |
4fe79f1c CF |
992 | You must have CYGTLS_PADSIZE bytes reserved at the bottom of the stack |
993 | calling this function, and that storage must not be overwritten until you | |
994 | unload cygwin1.dll, as it is used for _my_tls. It is best to load | |
995 | cygwin1.dll before spawning any additional threads in your process. | |
1cd06583 | 996 | |
4fe79f1c CF |
997 | See winsup/testsuite/cygload for an example of how to use cygwin1.dll |
998 | from MSVC and non-cygwin MinGW applications. */ | |
737a86d3 | 999 | extern "C" void |
48b87053 DD |
1000 | cygwin_dll_init () |
1001 | { | |
48b87053 DD |
1002 | static char **envp; |
1003 | static int _fmode; | |
48b87053 | 1004 | |
48b87053 DD |
1005 | user_data->magic_biscuit = sizeof (per_process); |
1006 | ||
48b87053 DD |
1007 | user_data->envptr = &envp; |
1008 | user_data->fmode_ptr = &_fmode; | |
1009 | ||
29b35f7a | 1010 | _dll_crt0 (); |
48b87053 DD |
1011 | } |
1012 | ||
1fd5e000 CF |
1013 | extern "C" void |
1014 | __main (void) | |
1015 | { | |
900f2071 | 1016 | /* Ordering is critical here. DLL ctors have already been |
824d8518 | 1017 | run as they were being loaded, so we should stack the |
900f2071 CV |
1018 | queued call to DLL dtors now. */ |
1019 | atexit (dll_global_dtors); | |
2e008fb9 | 1020 | do_global_ctors (user_data->ctors, false); |
b6473313 CF |
1021 | /* Now we have run global ctors, register their dtors. |
1022 | ||
1023 | At exit, global dtors will run first, so the app can still | |
900f2071 CV |
1024 | use shared library functions while terminating; then the |
1025 | DLLs will be destroyed; finally newlib will shut down stdio | |
1026 | and terminate itself. */ | |
b6473313 | 1027 | atexit (do_global_dtors); |
b6473313 | 1028 | sig_dispatch_pending (true); |
1fd5e000 CF |
1029 | } |
1030 | ||
3400b4fc | 1031 | void __stdcall |
1fd5e000 CF |
1032 | do_exit (int status) |
1033 | { | |
ce40c6ba CF |
1034 | syscall_printf ("do_exit (%d), exit_state %d", status, exit_state); |
1035 | ||
f7239090 | 1036 | #ifdef NEWVFORK |
ce40c6ba CF |
1037 | vfork_save *vf = vfork_storage.val (); |
1038 | if (vf != NULL && vf->pid < 0) | |
1039 | { | |
1040 | exit_state = ES_NOT_EXITING; | |
1041 | vf->restore_exit (status); | |
1042 | } | |
f7239090 | 1043 | #endif |
ce40c6ba | 1044 | |
267e201d | 1045 | lock_process until_exit (true); |
b739751d | 1046 | |
3400b4fc CF |
1047 | if (exit_state < ES_EVENTS_TERMINATE) |
1048 | { | |
1049 | exit_state = ES_EVENTS_TERMINATE; | |
1050 | events_terminate (); | |
1051 | } | |
1052 | ||
1fd5e000 | 1053 | UINT n = (UINT) status; |
c4ec64d7 CF |
1054 | if (exit_state < ES_THREADTERM) |
1055 | { | |
1056 | exit_state = ES_THREADTERM; | |
1057 | cygthread::terminate (); | |
1058 | } | |
1059 | ||
1fd5e000 CF |
1060 | if (exit_state < ES_SIGNAL) |
1061 | { | |
1062 | exit_state = ES_SIGNAL; | |
8cb359d9 CF |
1063 | signal (SIGCHLD, SIG_IGN); |
1064 | signal (SIGHUP, SIG_IGN); | |
1065 | signal (SIGINT, SIG_IGN); | |
1066 | signal (SIGQUIT, SIG_IGN); | |
1fd5e000 CF |
1067 | } |
1068 | ||
166b2571 | 1069 | if (exit_state < ES_CLOSEALL) |
1fd5e000 CF |
1070 | { |
1071 | exit_state = ES_CLOSEALL; | |
f9fb1149 | 1072 | close_all_files (); |
1fd5e000 CF |
1073 | } |
1074 | ||
3f5046a5 | 1075 | myself->stopsig = 0; |
1fd5e000 | 1076 | |
3f5046a5 CF |
1077 | if (exit_state < ES_HUP_PGRP) |
1078 | { | |
1079 | exit_state = ES_HUP_PGRP; | |
1fd5e000 | 1080 | /* Kill orphaned children on group leader exit */ |
f8f9b12e | 1081 | if (myself->has_pgid_children && myself->pid == myself->pgid) |
1fd5e000 | 1082 | { |
985d0e68 | 1083 | siginfo_t si = {0}; |
f6936c48 CF |
1084 | si.si_signo = -SIGHUP; |
1085 | si.si_code = SI_KERNEL; | |
1fd5e000 CF |
1086 | sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children", |
1087 | myself->pid, myself->pgid); | |
f6936c48 | 1088 | kill_pgrp (myself->pgid, si); |
1fd5e000 | 1089 | } |
3f5046a5 | 1090 | } |
1fd5e000 | 1091 | |
3f5046a5 CF |
1092 | if (exit_state < ES_HUP_SID) |
1093 | { | |
1094 | exit_state = ES_HUP_SID; | |
1fd5e000 | 1095 | /* Kill the foreground process group on session leader exit */ |
b98ebf54 | 1096 | if (getpgrp () > 0 && myself->pid == myself->sid && real_tty_attached (myself)) |
1fd5e000 CF |
1097 | { |
1098 | tty *tp = cygwin_shared->tty[myself->ctty]; | |
1099 | sigproc_printf ("%d == sid %d, send SIGHUP to children", | |
1100 | myself->pid, myself->sid); | |
1101 | ||
45a7e957 | 1102 | /* CGF FIXME: This can't be right. */ |
1fd5e000 | 1103 | if (tp->getsid () == myself->sid) |
083abe54 | 1104 | tp->kill_pgrp (SIGHUP); |
1fd5e000 | 1105 | } |
ec300c99 | 1106 | |
3f5046a5 CF |
1107 | } |
1108 | ||
a611ae50 CF |
1109 | if (exit_state < ES_TITLE) |
1110 | { | |
1111 | exit_state = ES_TITLE; | |
1112 | /* restore console title */ | |
1113 | if (old_title && display_title) | |
1114 | set_console_title (old_title); | |
1115 | } | |
1116 | ||
3f5046a5 CF |
1117 | if (exit_state < ES_TTY_TERMINATE) |
1118 | { | |
1119 | exit_state = ES_TTY_TERMINATE; | |
71d59a92 | 1120 | cygwin_shared->tty.terminate (); |
1fd5e000 CF |
1121 | } |
1122 | ||
2380dfe1 | 1123 | myself.exit (n); |
1fd5e000 CF |
1124 | } |
1125 | ||
005c3065 | 1126 | extern "C" int |
fc6a0dc8 | 1127 | cygwin_atexit (void (*fn) (void)) |
005c3065 CF |
1128 | { |
1129 | int res; | |
fc6a0dc8 CF |
1130 | dll *d = dlls.find ((void *) _my_tls.retaddr ()); |
1131 | res = d ? __cxa_atexit ((void (*) (void *)) fn, NULL, d) : atexit (fn); | |
005c3065 CF |
1132 | return res; |
1133 | } | |
1134 | ||
1135 | extern "C" void | |
1136 | cygwin_exit (int n) | |
1137 | { | |
c019a66c | 1138 | exit_state = ES_EXIT_STARTING; |
005c3065 CF |
1139 | exit (n); |
1140 | } | |
1141 | ||
1fd5e000 CF |
1142 | extern "C" void |
1143 | _exit (int n) | |
1144 | { | |
8cb359d9 | 1145 | do_exit (((DWORD) n & 0xff) << 8); |
1fd5e000 CF |
1146 | } |
1147 | ||
74434376 CF |
1148 | extern "C" void cygwin_stackdump (); |
1149 | ||
1fd5e000 CF |
1150 | extern "C" void |
1151 | __api_fatal (const char *fmt, ...) | |
1152 | { | |
1153 | char buf[4096]; | |
1154 | va_list ap; | |
1155 | ||
1156 | va_start (ap, fmt); | |
17f3068d | 1157 | int n = __small_sprintf (buf, "%P: *** fatal error - "); |
2d1d1eb1 | 1158 | __small_vsprintf (buf + n, fmt, ap); |
1fd5e000 | 1159 | va_end (ap); |
a16b738d | 1160 | strace.prntf (_STRACE_SYSTEM, NULL, "%s", buf); |
1fd5e000 | 1161 | |
1fd5e000 | 1162 | #ifdef DEBUGGING |
0c55f6ed | 1163 | try_to_debug (); |
1fd5e000 | 1164 | #endif |
74434376 | 1165 | cygwin_stackdump (); |
84d38174 | 1166 | myself.exit (__api_fatal_exit_val); |
1fd5e000 CF |
1167 | } |
1168 | ||
d3fee5ec | 1169 | void |
77f4a250 | 1170 | multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned version) |
d3fee5ec | 1171 | { |
6d8bd861 | 1172 | if (_cygwin_testing && (strstr (what, "proc") || strstr (what, "cygheap"))) |
aaf219f0 | 1173 | { |
6d8bd861 | 1174 | child_proc_info->type = _PROC_WHOOPS; |
aaf219f0 CF |
1175 | return; |
1176 | } | |
5daa0835 | 1177 | |
5ab0b5cf | 1178 | if (GetEnvironmentVariableA ("CYGWIN_MISMATCH_OK", NULL, 0)) |
5daa0835 CF |
1179 | return; |
1180 | ||
1181 | if (CYGWIN_VERSION_MAGIC_VERSION (magic_version) == version) | |
1182 | system_printf ("%s magic number mismatch detected - %p/%p", what, magic_version, version); | |
1183 | else | |
2d76a612 CF |
1184 | api_fatal ("%s mismatch detected - %p/%p.\n\ |
1185 | This problem is probably due to using incompatible versions of the cygwin DLL.\n\ | |
d3fee5ec | 1186 | Search for cygwin1.dll using the Windows Start->Find/Search facility\n\ |
77f4a250 CF |
1187 | and delete all but the most recent version. The most recent version *should*\n\ |
1188 | reside in x:\\cygwin\\bin, where 'x' is the drive on which you have\n\ | |
2d76a612 CF |
1189 | installed the cygwin distribution. Rebooting is also suggested if you\n\ |
1190 | are unable to find another cygwin DLL.", | |
1191 | what, magic_version, version); | |
d3fee5ec CF |
1192 | } |
1193 | ||
166b2571 CF |
1194 | #ifdef DEBUGGING |
1195 | void __stdcall | |
1196 | cygbench (const char *s) | |
1197 | { | |
5ab0b5cf | 1198 | if (GetEnvironmentVariableA ("CYGWIN_BENCH", NULL, 0)) |
166b2571 CF |
1199 | small_printf ("%05d ***** %s : %10d\n", GetCurrentProcessId (), s, strace.microseconds ()); |
1200 | } | |
1201 | #endif |