5d97040501
* child_info.h (CURR_CHILD_INFO_MAGIC): Reset. (child_info::dwProcessId): Delete. (child_info::straced): New variable. (child_info::handle_fork): New member function. * dcrt0.cc (in_forkee): New global variable. (__cygwin_user_data::forkee): Mark as obsolete. (do_global_ctors): Use in_forkee rather than user_data->forkee. (get_cygwin_startup_info): Ditto. Deal with new straced field to allow strace to deal with children of attached processes. (initial_env): Accommodate changes to strace::hello. (child_info_fork::handle_fork): Rename from plain old 'handle_fork'. Move alloc_stack() call elsewhere. (dll_crt0_0): Fill out more of user_data. Reference handle_fork via fork_info. Add some debugging output. (_dll_crt0): Don't wait for sync thread if sync_startup is invalid. Zero sync_startup here. Call alloc_stack() here, if appropriate. (dll_crt0_1): Use in_forkee rather than user_data->forkee. (dll_crt0): Ditto. * malloc_wrapper.cc (malloc_init): Ditto. * dll_init.cc (in_forkee): Remove local static version of this variable. (dll_list::load_after_fork): Don't set in_forkee here. * external.cc (cygwin_internal): Use strace method rather than accessing field directly. * fhandler.cc (fhandler_base::read): Ditto. * fhandler_tty.cc (fhandler_tty_common::__acquire_output_mutex): Ditto. * fork.cc (frok::parent): Invoke strace write_childpid to communicate with potential strace. (child_copy): Add more detail to debugging output. * init.cc (calibration_id): New static variable. (prime_threads): Set sync_startup to invalid handle if we already know about thread_func_ix. Use static calibration_id to hold calibration thread id. * munge_threadfunc (munge_threadfunc): Don't try to debug if we don't find threadfunc_ix. (dll_entry): Avoid calling munge_threadfunc and _cygtls::remove on non-cygwin threads invoked during process startup. * pinfo.cc (set_myself): Always call strace.hello here regardless of DEBUGGING. * sigproc.cc (child_info::child_info): Remove spurious handling of dwProcessId. Set straced as appropriate. * spawn.cc (spawn_guts): Rename ciresrv to ch. Invoke strace write_childpid to communicate with potential strace. * strace.cc: Include child_info.h. (strace::hello): Remove inited test. Use active() method to test if strace has been activated. Handle case where we are started before (mypid): New function. (strace::vsprntf): Try to deal more intelligently with case where progname may not be filled out. Put pid in parentheses if it is a windows pid rather than a cygwin pid. myself has been filled out. (strace::write_childpid): New function for notifying strace about the creation of children. (strace::vprntf): Use strace method rather than accessing field directly. (strace_printf): Ditto. (strace::wm): Ditto. * winsup.h (in_forkee): Declare. * include/sys/strace.h (strace::write_childpid): Declare new function. (strace::attached): Define new function. (strace::active): Ditto. (strace::active_val): Ditto. (_STRACE_ON): Delete. (_STRACE_OFF): Ditto. (define_strace0): Use strace method rather than accessing field directly. (strace_printf_wrap): Ditto. (strace_printf_wrap1): Ditto. *** cygwin utils changes: * strace.cc (nprocesses): Make static global. (quiet): New variable. (strace_active): Ditto. (add_child): Increment nprocesses here. Don't add a child if it is already added (windows bug?). Report on child if not quiet. (get_child): Just return NULL if child not found. (remove_child): Report on child if not quiet. (attach_process): Don't complain if given a windows process. Use windows pid in error. (handle_output_debug_string): Issue error if trying to manipulate a process that we don't know about. Handle _STRACE_CHILD_PID - attach to reported child when we get this. (proc_child): Move nprocesses to file scope. Report on exceptions. (longopts): Implement "--quiet". (opts): Implement "-q". (main): Manipulate quiet flag. * utils.sgml (strace): Add words describing '-q'.
183 lines
4.9 KiB
C++
183 lines
4.9 KiB
C++
/* init.cc
|
|
|
|
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
|
Red Hat, Inc.
|
|
|
|
This file is part of Cygwin.
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
details. */
|
|
|
|
#include "winsup.h"
|
|
#include <stdlib.h>
|
|
#include "thread.h"
|
|
#include "perprocess.h"
|
|
#include "cygtls.h"
|
|
#include "pinfo.h"
|
|
#include <ntdef.h>
|
|
#include "ntdll.h"
|
|
|
|
int NO_COPY dynamically_loaded;
|
|
static char *search_for = (char *) cygthread::stub;
|
|
unsigned threadfunc_ix[8] __attribute__((section (".cygwin_dll_common"), shared));
|
|
DWORD tls_func;
|
|
|
|
HANDLE sync_startup;
|
|
|
|
#define OLDFUNC_OFFSET -1
|
|
|
|
static void WINAPI
|
|
threadfunc_fe (VOID *arg)
|
|
{
|
|
(void)__builtin_return_address(1);
|
|
asm volatile ("andl $-16,%%esp" ::: "%esp");
|
|
_cygtls::call ((DWORD (*) (void *, void *)) (((char **) _tlsbase)[OLDFUNC_OFFSET]), arg);
|
|
}
|
|
|
|
static DWORD WINAPI
|
|
calibration_thread (VOID *arg)
|
|
{
|
|
ExitThread (0);
|
|
}
|
|
|
|
static DWORD calibration_id;
|
|
|
|
/* We need to know where the OS stores the address of the thread function
|
|
on the stack so that we can intercept the call and insert some tls
|
|
stuff on the stack. This function starts a known calibration thread.
|
|
When it starts, a call will be made to dll_entry which will call munge_threadfunc
|
|
looking for the calibration thread offset on the stack. This offset will
|
|
be stored and used by all executing cygwin processes. */
|
|
static void
|
|
prime_threads ()
|
|
{
|
|
if (threadfunc_ix[0])
|
|
sync_startup = INVALID_HANDLE_VALUE;
|
|
else
|
|
{
|
|
search_for = (char *) calibration_thread;
|
|
sync_startup = CreateThread (NULL, 0, calibration_thread, 0, 0, &calibration_id);
|
|
}
|
|
}
|
|
|
|
/* If possible, redirect the thread entry point to a cygwin routine which
|
|
adds tls stuff to the stack. */
|
|
static void
|
|
munge_threadfunc ()
|
|
{
|
|
int i;
|
|
char **ebp = (char **) __builtin_frame_address (0);
|
|
if (!threadfunc_ix[0])
|
|
{
|
|
char **peb;
|
|
char **top = (char **) _tlsbase;
|
|
for (peb = ebp, i = 0; peb < top && i < 7; peb++)
|
|
if (*peb == search_for)
|
|
threadfunc_ix[i++] = peb - ebp;
|
|
if (0 && !threadfunc_ix[0])
|
|
{
|
|
try_to_debug ();
|
|
return;
|
|
}
|
|
}
|
|
|
|
char *threadfunc = ebp[threadfunc_ix[0]];
|
|
if (threadfunc == (char *) calibration_thread)
|
|
/* no need for the overhead */;
|
|
else if (threadfunc_ix[0])
|
|
{
|
|
for (i = 0; threadfunc_ix[i]; i++)
|
|
ebp[threadfunc_ix[i]] = (char *) threadfunc_fe;
|
|
((char **) _tlsbase)[OLDFUNC_OFFSET] = threadfunc;
|
|
}
|
|
}
|
|
|
|
inline static void
|
|
respawn_wow64_process ()
|
|
{
|
|
NTSTATUS ret;
|
|
PROCESS_BASIC_INFORMATION pbi;
|
|
HANDLE parent;
|
|
|
|
BOOL is_wow64_proc = TRUE; /* Opt on the safe side. */
|
|
|
|
/* Unfortunately there's no simpler way to retrieve the
|
|
parent process in NT, as far as I know. Hints welcome. */
|
|
ret = NtQueryInformationProcess (GetCurrentProcess (),
|
|
ProcessBasicInformation,
|
|
(PVOID) &pbi,
|
|
sizeof pbi, NULL);
|
|
if (ret == STATUS_SUCCESS
|
|
&& (parent = OpenProcess (PROCESS_QUERY_INFORMATION,
|
|
FALSE,
|
|
pbi.InheritedFromUniqueProcessId)))
|
|
{
|
|
IsWow64Process (parent, &is_wow64_proc);
|
|
CloseHandle (parent);
|
|
}
|
|
|
|
/* The parent is a real 64 bit process? Respawn! */
|
|
if (!is_wow64_proc)
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si;
|
|
GetStartupInfo (&si);
|
|
if (!CreateProcessA (NULL, GetCommandLineA (), NULL, NULL, TRUE,
|
|
CREATE_DEFAULT_ERROR_MODE
|
|
| GetPriorityClass (GetCurrentProcess ()),
|
|
NULL, NULL, &si, &pi))
|
|
api_fatal ("Failed to create process <%s>, %E", GetCommandLineA ());
|
|
CloseHandle (pi.hThread);
|
|
if (WaitForSingleObject (pi.hProcess, INFINITE) == WAIT_FAILED)
|
|
api_fatal ("Waiting for process %d failed, %E", pi.dwProcessId);
|
|
CloseHandle (pi.hProcess);
|
|
ExitProcess (0);
|
|
}
|
|
}
|
|
|
|
extern void __stdcall dll_crt0_0 ();
|
|
|
|
HMODULE NO_COPY cygwin_hmodule;
|
|
|
|
extern "C" BOOL WINAPI
|
|
dll_entry (HANDLE h, DWORD reason, void *static_load)
|
|
{
|
|
BOOL is_wow64_proc = FALSE;
|
|
// _STRACE_ON;
|
|
|
|
switch (reason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
cygwin_hmodule = (HMODULE) h;
|
|
dynamically_loaded = (static_load == NULL);
|
|
|
|
/* Is the stack at an unusual address? This is, an address which
|
|
is in the usual space occupied by the process image, but below
|
|
the auto load address of DLLs?
|
|
Check if we're running in WOW64 on a 64 bit machine *and* are
|
|
spawned by a genuine 64 bit process. If so, respawn. */
|
|
if (&is_wow64_proc >= (PBOOL) 0x400000
|
|
&& &is_wow64_proc <= (PBOOL) 0x10000000
|
|
&& IsWow64Process (GetCurrentProcess (), &is_wow64_proc)
|
|
&& is_wow64_proc)
|
|
respawn_wow64_process ();
|
|
|
|
dll_crt0_0 ();
|
|
prime_threads (); // this should be the last thing to happen
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
case DLL_THREAD_ATTACH:
|
|
if (!sync_startup || GetCurrentThreadId () == calibration_id)
|
|
munge_threadfunc ();
|
|
break;
|
|
case DLL_THREAD_DETACH:
|
|
if (!sync_startup)
|
|
_my_tls.remove (0);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|