*** cygwin DLL Changes:

* 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'.
This commit is contained in:
Christopher Faylor 2005-12-29 20:46:34 +00:00
parent 10e4168d84
commit 5d97040501
20 changed files with 314 additions and 143 deletions

View File

@ -1,3 +1,73 @@
2005-12-29 Christopher Faylor <cgf@timesys.com>
* 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.
2005-12-28 Christopher Faylor <cgf@timesys.com>
* environ.cc (win_env::add_cache): Don't add variables to the

View File

@ -29,7 +29,7 @@ enum child_info_types
#define EXEC_MAGIC_SIZE sizeof(child_info)
#define CURR_CHILD_INFO_MAGIC 0xb530a54dU
#define CURR_CHILD_INFO_MAGIC 0xc87757a7U
/* NOTE: Do not make gratuitous changes to the names or organization of the
below class. The layout is checksummed to determine compatibility between
@ -48,7 +48,7 @@ public:
init_cygheap *cygheap;
void *cygheap_max;
DWORD cygheap_reserve_sz;
DWORD dwProcessId;
unsigned char straced;
unsigned fhandler_union_cb;
child_info (unsigned, child_info_types, bool);
child_info (): subproc_ready (NULL), parent (NULL) {}
@ -69,6 +69,7 @@ public:
void *stacktop; // location of top of parent stack
void *stackbottom; // location of bottom of parent stack
child_info_fork ();
void handle_fork ();
};
class fhandler_base;

View File

@ -147,7 +147,7 @@ void
_cygtls::remove (DWORD wait)
{
debug_printf ("wait %p", wait);
if (!locals.exitsock || exit_state >= ES_FINAL)
if (1 || !isinitialized () || !locals.exitsock || exit_state >= ES_FINAL)
return;
if (wait)
{

View File

@ -53,6 +53,7 @@ muto NO_COPY lock_process::locker;
bool display_title;
bool strip_title_path;
bool allow_glob = true;
bool NO_COPY in_forkee;
codepage_type current_codepage = ansi_cp;
int __argc_safe;
@ -108,7 +109,7 @@ extern "C"
/* premain */ {NULL, NULL, NULL, NULL},
/* run_ctors_p */ 0,
/* unused */ {0, 0, 0, 0, 0, 0, 0},
/* forkee */ 0,
/* UNUSED forkee */ 0,
/* hmodule */ NULL,
/* api_major */ CYGWIN_VERSION_API_MAJOR,
/* api_minor */ CYGWIN_VERSION_API_MINOR,
@ -141,7 +142,7 @@ do_global_dtors ()
static void __stdcall
do_global_ctors (void (**in_pfunc)(), int force)
{
if (!force && user_data->forkee)
if (!force && in_forkee)
return; // inherit constructed stuff from parent pid
/* Run ctors backwards, so skip the first entry and find how many
@ -554,11 +555,8 @@ initial_env ()
len = GetModuleFileName (NULL, buf, CYG_MAX_PATH);
console_printf ("Sleeping %d, pid %u %s\n", ms, GetCurrentProcessId (), buf);
Sleep (ms);
if (!strace.active && !dynamically_loaded)
{
strace.inited = 0;
strace.hello ();
}
if (!strace.active () && !dynamically_loaded)
strace.hello ();
}
if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
{
@ -611,7 +609,7 @@ get_cygwin_startup_info ()
switch (res->type)
{
case _PROC_FORK:
user_data->forkee = true;
in_forkee = true;
should_be_cb = sizeof (child_info_fork);
/* fall through */;
case _PROC_SPAWN:
@ -622,6 +620,20 @@ get_cygwin_startup_info ()
multiple_cygwin_problem ("proc size", res->cb, should_be_cb);
else if (sizeof (fhandler_union) != res->fhandler_union_cb)
multiple_cygwin_problem ("fhandler size", res->fhandler_union_cb, sizeof (fhandler_union));
if (res->straced)
{
res->ready (false);
#if 0
DWORD prio = GetThreadPriority (GetCurrentThread ());
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
#endif
for (unsigned i = 0; !being_debugged () && i < 10000; i++)
low_priority_sleep (0);
#if 0
SetThreadPriority (GetCurrentThread (), prio);
#endif
strace.hello ();
}
break;
default:
system_printf ("unknown exec type %d", res->type);
@ -641,26 +653,24 @@ get_cygwin_startup_info ()
#define dll_bss_end &_bss_end__
void
handle_fork ()
child_info_fork::handle_fork ()
{
alloc_stack (fork_info);
cygheap_fixup_in_child (false);
memory_init ();
set_myself (NULL);
HANDLE hp = fork_info->parent;
child_copy (hp, false,
child_copy (parent, false,
"dll data", dll_data_start, dll_data_end,
"dll bss", dll_bss_start, dll_bss_end,
"user heap", cygheap->user_heap.base, cygheap->user_heap.ptr,
NULL);
/* step 2 now that the dll has its heap filled in, we can fill in the
user's data and bss since user_data is now filled out. */
child_copy (hp, false,
child_copy (parent, false,
"data", user_data->data_start, user_data->data_end,
"bss", user_data->bss_start, user_data->bss_end,
NULL);
if (fixup_mmaps_after_fork (hp))
if (fixup_mmaps_after_fork (parent))
api_fatal ("recreate_mmaps_after_fork_failed");
}
@ -675,6 +685,8 @@ dll_crt0_0 ()
_impure_ptr->_stdout = &_impure_ptr->__sf[1];
_impure_ptr->_stderr = &_impure_ptr->__sf[2];
_impure_ptr->_current_locale = "C";
user_data->impure_ptr = _impure_ptr;
user_data->impure_ptr_ptr = &_impure_ptr;
wincap.init ();
initial_env ();
mmap_init ();
@ -690,7 +702,6 @@ dll_crt0_0 ()
OpenProcessToken (hMainProc, MAXIMUM_ALLOWED, &hProcToken);
SetErrorMode (SEM_FAILCRITICALERRORS);
device::init ();
do_global_ctors (&__CTOR_LIST__, 1);
cygthread::init ();
@ -704,7 +715,7 @@ dll_crt0_0 ()
switch (child_proc_info->type)
{
case _PROC_FORK:
handle_fork ();
fork_info->handle_fork ();
break;
case _PROC_SPAWN:
case _PROC_EXEC:
@ -747,6 +758,7 @@ dll_crt0_0 ()
DuplicateTokenEx (hProcToken, MAXIMUM_ALLOWED, NULL,
SecurityImpersonation, TokenImpersonation,
&hProcImpToken);
debug_printf ("finished dll_crt0_0 initialization");
}
/* Take over from libc's crt0.o and start the application. Note the
@ -772,7 +784,7 @@ dll_crt0_1 (char *)
/* Initialize pthread mainthread when not forked and it is safe to call new,
otherwise it is reinitalized in fixup_after_fork */
if (!user_data->forkee)
if (!in_forkee)
pthread::init_mainthread ();
#ifdef DEBUGGING
@ -791,7 +803,7 @@ dll_crt0_1 (char *)
#endif
cygbench ("pre-forkee");
if (user_data->forkee)
if (in_forkee)
{
/* If we've played with the stack, stacksize != 0. That means that
fork() was invoked from other than the main thread. Make sure that
@ -946,18 +958,15 @@ initialize_main_tls (char *padding)
extern "C" void __stdcall
_dll_crt0 ()
{
extern DWORD threadfunc_ix;
extern HANDLE sync_startup;
extern unsigned threadfunc_ix;
if (threadfunc_ix)
/* nothing to do */;
else if (!sync_startup)
system_printf ("internal error: sync_startup not called at start. Expect signal problems.");
else
if (sync_startup != INVALID_HANDLE_VALUE)
{
WaitForSingleObject (sync_startup, INFINITE);
CloseHandle (sync_startup);
}
sync_startup = NULL;
if (!threadfunc_ix)
system_printf ("internal error: couldn't determine location of thread function on stack. Expect signal problems.");
@ -968,8 +977,9 @@ _dll_crt0 ()
char padding[CYGTLS_PADSIZE];
if (child_proc_info && child_proc_info->type == _PROC_FORK)
user_data->forkee = true;
debug_printf ("in_forkee %d, fork_info %p", in_forkee, fork_info);
if (in_forkee)
alloc_stack (fork_info);
else
__sinit (_impure_ptr);
@ -981,7 +991,7 @@ void
dll_crt0 (per_process *uptr)
{
/* Set the local copy of the pointer into the user space. */
if (!user_data->forkee && uptr && uptr != user_data)
if (!in_forkee && uptr && uptr != user_data)
{
memcpy (user_data, uptr, per_process_overwrite);
*(user_data->impure_ptr_ptr) = _GLOBAL_REENT;

View File

@ -23,7 +23,6 @@ extern void __stdcall check_sanity_and_sync (per_process *);
dll_list NO_COPY dlls;
static int NO_COPY in_forkee;
static bool dll_global_dtors_recorded;
/* Run destructors for all DLLs on exit. */
@ -283,7 +282,6 @@ release_upto (const char *name, DWORD here)
void
dll_list::load_after_fork (HANDLE parent, dll *first)
{
in_forkee = 1;
int try2 = 0;
dll d;
@ -346,7 +344,7 @@ dll_list::load_after_fork (HANDLE parent, dll *first)
}
next = d.next; /* Get the address of the next DLL. */
}
in_forkee = 0;
in_forkee = false;
}
extern "C" int

View File

@ -218,7 +218,7 @@ cygwin_internal (cygwin_getinfo_types t, ...)
case CW_STRACE_ACTIVE:
{
return strace.active;
return strace.active ();
}
case CW_CYGWIN_PID_TO_WINPID:

View File

@ -772,7 +772,7 @@ fhandler_base::read (void *in_ptr, size_t& len)
len = dst - (char *) ptr;
#ifndef NOSTRACE
if (strace.active)
if (strace.active ())
{
char buf[16 * 6 + 1];
char *p = buf;

View File

@ -112,7 +112,7 @@ DWORD
fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln,
DWORD ms)
{
if (strace.active)
if (strace.active ())
strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms);
DWORD res = WaitForSingleObject (output_mutex, ms);
if (res == WAIT_OBJECT_0)

View File

@ -307,12 +307,14 @@ frok::parent (void *stack_here)
/* Fixup the parent datastructure if needed and resume the child's
main thread. */
if (cygheap->fdtab.need_fixup_before ())
if (c_flags & CREATE_SUSPENDED)
{
cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
ResumeThread (pi.hThread);
}
strace.write_childpid (ch, pi.dwProcessId);
child_pid = cygwin_pid (pi.dwProcessId);
child.init (child_pid, 1, NULL);
@ -662,7 +664,7 @@ child_copy (HANDLE hp, bool write, ...)
res = WriteProcessMemory (hp, here, here, todo, &done);
else
res = ReadProcessMemory (hp, here, here, todo, &done);
debug_printf ("hp %p, low %p, high %p, res %d", hp, low, high, res);
debug_printf ("%s - hp %p low %p, high %p, res %d", what, hp, low, high, res);
if (!res || todo != done)
{
if (!res)

View File

@ -1,6 +1,7 @@
/* sys/strace.h
Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005 Red Hat, Inc.
This file is part of Cygwin.
@ -8,8 +9,6 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
/* sys/strace.h */
/* This file contains routines for tracing system calls and other internal
phenomenon.
@ -33,21 +32,25 @@ details. */
#ifdef __cplusplus
class child_info;
class strace
{
int vsprntf (char *buf, const char *func, const char *infmt, va_list ap);
void write (unsigned category, const char *buf, int count);
unsigned char _active;
public:
int microseconds ();
int version;
int active;
int lmicrosec;
int execing;
int inited;
void hello ();
bool execing;
void hello () __attribute__ ((regparm (1)));
void prntf (unsigned, const char *func, const char *, ...) /*__attribute__ ((regparm(3)))*/;
void vprntf (unsigned, const char *func, const char *, va_list ap) /*__attribute__ ((regparm(3)))*/;
void wm (int message, int word, int lon) __attribute__ ((regparm(3)));
void write_childpid (child_info&, unsigned long) __attribute__ ((regparm (2)));
bool attached () const {return _active == 3;}
bool active () const {return _active & 1;}
unsigned char& active_val () {return _active;}
};
extern strace strace;
@ -56,6 +59,7 @@ extern strace strace;
#define _STRACE_INTERFACE_ACTIVATE_ADDR -1
#define _STRACE_INTERFACE_ACTIVATE_ADDR1 -2
#define _STRACE_CHILD_PID -3
/* Bitmasks of tracing messages to print. */
@ -78,13 +82,6 @@ extern strace strace;
#define _STRACE_MALLOC 0x20000 // trace malloc calls
#define _STRACE_THREAD 0x40000 // thread-locking calls
#define _STRACE_NOTALL 0x80000 // don't include if _STRACE_ALL
#if defined (DEBUGGING)
# define _STRACE_ON strace.active = 1
# define _STRACE_OFF strace.active = 0
#else
# define _STRACE_ON
# define _STRACE_OFF
#endif
#ifdef __cplusplus
extern "C" {
@ -108,7 +105,7 @@ void strace_printf (unsigned, const char *func, const char *, ...);
#define define_strace0(c,...) \
do { \
if ((c & _STRACE_SYSTEM) || strace.active) \
if ((c & _STRACE_SYSTEM) || strace.active ()) \
strace.prntf (c, __PRETTY_FUNCTION__, __VA_ARGS__); \
} \
while (0)
@ -130,13 +127,13 @@ void strace_printf (unsigned, const char *func, const char *, ...);
#else
#define strace_printf_wrap(what, fmt, args...) \
((void) ({\
if ((_STRACE_ ## what & _STRACE_SYSTEM) || strace.active) \
if ((_STRACE_ ## what & _STRACE_SYSTEM) || strace.active ()) \
strace.prntf(_STRACE_ ## what, __PRETTY_FUNCTION__, fmt, ## args); \
0; \
}))
#define strace_printf_wrap1(what, fmt, args...) \
((void) ({\
if ((_STRACE_ ## what & _STRACE_SYSTEM) || strace.active) \
if ((_STRACE_ ## what & _STRACE_SYSTEM) || strace.active ()) \
strace.prntf((_STRACE_ ## what) | _STRACE_NOTALL, __PRETTY_FUNCTION__, fmt, ## args); \
0; \
}))

View File

@ -41,6 +41,8 @@ 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.
@ -50,11 +52,12 @@ calibration_thread (VOID *arg)
static void
prime_threads ()
{
if (!threadfunc_ix[0])
if (threadfunc_ix[0])
sync_startup = INVALID_HANDLE_VALUE;
else
{
DWORD id;
search_for = (char *) calibration_thread;
sync_startup = CreateThread (NULL, 0, calibration_thread, 0, 0, &id);
sync_startup = CreateThread (NULL, 0, calibration_thread, 0, 0, &calibration_id);
}
}
@ -72,7 +75,7 @@ munge_threadfunc ()
for (peb = ebp, i = 0; peb < top && i < 7; peb++)
if (*peb == search_for)
threadfunc_ix[i++] = peb - ebp;
if (!threadfunc_ix[0])
if (0 && !threadfunc_ix[0])
{
try_to_debug ();
return;
@ -82,7 +85,7 @@ munge_threadfunc ()
char *threadfunc = ebp[threadfunc_ix[0]];
if (threadfunc == (char *) calibration_thread)
/* no need for the overhead */;
else
else if (threadfunc_ix[0])
{
for (i = 0; threadfunc_ix[i]; i++)
ebp[threadfunc_ix[i]] = (char *) threadfunc_fe;
@ -166,10 +169,12 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
munge_threadfunc ();
if (!sync_startup || GetCurrentThreadId () == calibration_id)
munge_threadfunc ();
break;
case DLL_THREAD_DETACH:
_my_tls.remove (0);
if (!sync_startup)
_my_tls.remove (0);
break;
}

View File

@ -258,7 +258,7 @@ malloc_init ()
calls to malloc/free/realloc to application provided. This may
happen if some other dll calls cygwin's malloc, but main code provides
its own malloc */
if (!user_data->forkee)
if (!in_forkee)
{
user_data->free (user_data->malloc (16));
if (export_malloc_called)

View File

@ -54,10 +54,7 @@ set_myself (HANDLE h)
myself->dwProcessId = GetCurrentProcessId ();
GetModuleFileName (NULL, myself->progname, sizeof (myself->progname));
#ifndef DEBUGGING
if (!strace.active)
#endif
strace.hello ();
strace.hello ();
debug_printf ("myself->dwProcessId %u", myself->dwProcessId);
if (h)
{

View File

@ -768,7 +768,7 @@ child_info::child_info (unsigned in_cb, child_info_types chtype, bool need_subpr
sigproc_printf ("subproc_ready %p", subproc_ready);
cygheap = ::cygheap;
cygheap_max = ::cygheap_max;
dwProcessId = myself->dwProcessId;
straced = strace.attached ();
/* Create an inheritable handle to pass to the child process. This will
allow the child to duplicate handles from the parent to itself. */
parent = NULL;

View File

@ -424,7 +424,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
pthread_cleanup_push (do_cleanup, (void *) &cleanup);
av newargv;
linebuf one_line;
child_info_spawn ciresrv;
child_info_spawn ch;
path_conv real_path;
bool reset_sendsig = false;
@ -643,11 +643,11 @@ spawn_guts (const char * prog_arg, const char *const *argv,
res = -1;
goto out;
}
ciresrv.set (chtype, real_path.iscygexec ());
ciresrv.moreinfo = moreinfo;
ch.set (chtype, real_path.iscygexec ());
ch.moreinfo = moreinfo;
si.lpReserved2 = (LPBYTE) &ciresrv;
si.cbReserved2 = sizeof (ciresrv);
si.lpReserved2 = (LPBYTE) &ch;
si.cbReserved2 = sizeof (ch);
/* When ruid != euid we create the new process under the current original
account and impersonate in child, this way maintaining the different
@ -731,6 +731,9 @@ spawn_guts (const char * prog_arg, const char *const *argv,
goto out;
}
if (!(flags & CREATE_SUSPENDED))
strace.write_childpid (ch, pi.dwProcessId);
/* Fixup the parent data structures if needed and resume the child's
main thread. */
if (cygheap->fdtab.need_fixup_before ())
@ -818,12 +821,15 @@ spawn_guts (const char * prog_arg, const char *const *argv,
/* Start the child running */
if (flags & CREATE_SUSPENDED)
ResumeThread (pi.hThread);
{
ResumeThread (pi.hThread);
strace.write_childpid (ch, pi.dwProcessId);
}
ForceCloseHandle (pi.hThread);
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
synced = ciresrv.sync (pid, pi.hProcess, INFINITE);
synced = ch.sync (pid, pi.hProcess, INFINITE);
switch (mode)
{

View File

@ -25,6 +25,7 @@ details. */
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "child_info.h"
#define PROTECT(x) x[sizeof (x)-1] = 0
#define CHECK(x) if (x[sizeof (x)-1] != 0) { small_printf ("array bound exceeded %d\n", __LINE__); ExitProcess (1); }
@ -36,27 +37,25 @@ class strace NO_COPY strace;
void
strace::hello ()
{
char buf[30];
if (inited)
{
active ^= 1;
return;
}
inited = 1;
if (!being_debugged ())
if (_active || !being_debugged ())
return;
__small_sprintf (buf, "cYg%8x %x", _STRACE_INTERFACE_ACTIVATE_ADDR, &active);
char buf[30];
__small_sprintf (buf, "cYg%8x %x", _STRACE_INTERFACE_ACTIVATE_ADDR, &_active);
OutputDebugString (buf);
if (active)
if (active ())
{
char pidbuf[40];
if (myself->progname[0])
__small_sprintf (pidbuf, "(pid %d, ppid %d)", myself->pid, myself->ppid ?: 1);
else
{
GetModuleFileName (NULL, myself->progname, sizeof (myself->progname));
__small_sprintf (pidbuf, "(windows pid %d)", GetCurrentProcessId ());
}
prntf (1, NULL, "**********************************************");
prntf (1, NULL, "Program name: %s (pid %d, ppid %d)", myself->progname,
myself->pid ?: GetCurrentProcessId (),
myself->ppid ?: 1);
prntf (1, NULL, "Program name: %s %s", myself->progname, pidbuf);
prntf (1, NULL, "App version: %d.%d, api: %d.%d",
user_data->dll_major, user_data->dll_minor,
user_data->api_major, user_data->api_minor);
@ -65,7 +64,8 @@ strace::hello ()
cygwin_version.api_major, cygwin_version.api_minor);
prntf (1, NULL, "DLL build: %s", cygwin_version.dll_build_date);
prntf (1, NULL, "OS version: Windows %s", wincap.osname ());
prntf (1, NULL, "Heap size: %u", cygheap->user_heap.chunk);
if (cygheap)
prntf (1, NULL, "Heap size: %u", cygheap->user_heap.chunk);
prntf (1, NULL, "**********************************************");
}
}
@ -111,6 +111,16 @@ getfunc (char *in_dst, const char *func)
return dst - in_dst;
}
static char *
mypid (char *buf)
{
if (myself && myself->pid)
__small_sprintf (buf, "%d", myself->pid);
else
__small_sprintf (buf, "(%d)", cygwin_pid (GetCurrentProcessId ()));
return buf;
}
extern "C" char *__progname;
/* sprintf analog for use by output routines. */
@ -122,12 +132,11 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
static NO_COPY bool nonewline = false;
DWORD err = GetLastError ();
const char *tn = cygthread::name ();
char *pn = __progname ?: (myself ? myself->progname : NULL);
int microsec = microseconds ();
lmicrosec = microsec;
__small_sprintf (fmt, "%7d [%s] %s ", microsec, tn, "%s %d%s");
__small_sprintf (fmt, "%7d [%s] %s ", microsec, tn, "%s %s%s");
SetLastError (err);
@ -135,21 +144,33 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
count = 0;
else
{
char *p, progname[CYG_MAX_PATH];
char *pn;
if (!cygwin_finished_initializing)
pn = myself ? myself->progname : NULL;
else if (__progname)
pn = __progname;
else
pn = NULL;
char *p;
char progname[CYG_MAX_PATH];
if (!pn)
p = (char *) "*** unknown ***";
GetModuleFileName (NULL, pn = progname, sizeof (progname));
if (!pn)
/* hmm */;
else if ((p = strrchr (pn, '\\')) != NULL)
p++;
else if ((p = strrchr (pn, '/')) != NULL)
p++;
else
p = pn;
strcpy (progname, p);
if (p != progname)
strcpy (progname, p);
if ((p = strrchr (progname, '.')) != NULL && strcasematch (p, ".exe"))
*p = '\000';
p = progname;
count = __small_sprintf (buf, fmt, p && *p ? p : "?",
(myself && myself->pid) ? myself->pid : GetCurrentProcessId (),
char tmpbuf[20];
count = __small_sprintf (buf, fmt, p && *p ? p : "?", mypid (tmpbuf),
execing ? "!" : "");
if (func)
count += getfunc (buf + count, func);
@ -195,6 +216,20 @@ strace::write (unsigned category, const char *buf, int count)
#undef PREFIX
}
void
strace::write_childpid (child_info& ch, DWORD pid)
{
char buf[30];
if (!attached () || !being_debugged ())
return;
int res =
WaitForSingleObject (ch.subproc_ready, 30000);
do { if ((0x00040 & 0x08000) || active ()) prntf (0x00040, __PRETTY_FUNCTION__, "res %d", res); } while (0);
__small_sprintf (buf, "cYg%8x %x", _STRACE_CHILD_PID, pid);
OutputDebugString (buf);
}
/* Printf function used when tracing system calls.
Warning: DO NOT SET ERRNO HERE! */
@ -229,7 +264,7 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
}
#ifndef NOSTRACE
if (active)
if (active ())
write (category, buf, len);
#endif
SetLastError (err);
@ -249,7 +284,7 @@ strace_printf (unsigned category, const char *func, const char *fmt, ...)
{
va_list ap;
if ((category & _STRACE_SYSTEM) || strace.active)
if ((category & _STRACE_SYSTEM) || strace.active ())
{
va_start (ap, fmt);
strace.vprntf (category, func, fmt, ap);
@ -417,7 +452,7 @@ ta[] =
void
strace::wm (int message, int word, int lon)
{
if (active)
if (active ())
{
int i;

View File

@ -344,6 +344,7 @@ extern SYSTEM_INFO system_info;
/* The title on program start. */
extern char *old_title;
extern bool display_title;
extern bool in_forkee;
extern HANDLE hMainThread;
extern HANDLE hMainProc;

View File

@ -1,3 +1,23 @@
2005-12-29 Christopher Faylor <cgf@timesys.com>
* 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'.
2005-12-29 Christopher Faylor <cgf@timesys.com>
* cygcheck.cc (common_apps): Add crontab, vi, vim.

View File

@ -37,11 +37,15 @@ static int forkdebug = 1;
static int numerror = 1;
static int show_usecs = 1;
static int delta = 1;
static int hhmmss = 0;
static int bufsize = 0;
static int new_window = 0;
static long flush_period = 0;
static int include_hex = 0;
static int hhmmss;
static int bufsize;
static int new_window;
static long flush_period;
static int include_hex;
static int quiet = -1;
static unsigned char strace_active = 1;
static int processes;
static BOOL close_handle (HANDLE h, DWORD ok);
@ -104,18 +108,6 @@ error (int geterrno, const char *fmt, ...)
DWORD lastid = 0;
HANDLE lasth;
#define PROCFLAGS \
PROCESS_ALL_ACCESS /*(PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_VM_WRITE) */
static void
add_child (DWORD id, HANDLE hproc)
{
child_list *c = children.next;
children.next = (child_list *) calloc (1, sizeof (child_list));
children.next->next = c;
lastid = children.next->id = id;
lasth = children.next->hproc = hproc;
}
static child_list *
get_child (DWORD id)
{
@ -124,7 +116,23 @@ get_child (DWORD id)
if (c->id == id)
return c;
error (0, "no process id %d found", id);
return NULL;
}
static void
add_child (DWORD id, HANDLE hproc)
{
if (!get_child (id))
{
child_list *c = children.next;
children.next = (child_list *) calloc (1, sizeof (child_list));
children.next->next = c;
lastid = children.next->id = id;
lasth = children.next->hproc = hproc;
processes++;
if (!quiet)
fprintf (stderr, "Windows process %d attached\n", id);
}
}
static void
@ -139,6 +147,9 @@ remove_child (DWORD id)
child_list *c1 = c->next;
c->next = c1->next;
free (c1);
if (!quiet)
fprintf (stderr, "Windows process %d detached\n", id);
processes--;
return;
}
@ -283,15 +294,11 @@ attach_process (pid_t pid)
{
child_pid = (DWORD) cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid);
if (!child_pid)
{
warn (0, "no such cygwin pid - %d", pid);
child_pid = pid;
}
child_pid = pid;
if (!DebugActiveProcess (child_pid))
error (0, "couldn't attach to pid %d<%d> for debugging", pid, child_pid);
error (0, "couldn't attach to pid %d for debugging", child_pid);
printf ("Attached to pid %d (windows pid %u)\n", pid, (unsigned) child_pid);
return;
}
@ -396,6 +403,8 @@ handle_output_debug_string (DWORD id, LPVOID p, unsigned mask, FILE *ofile)
char alen[3 + 8 + 1];
DWORD nbytes;
child_list *child = get_child (id);
if (!child)
error (0, "no process id %d found", id);
HANDLE hchild = child->hproc;
#define INTROLEN (sizeof (alen) - 1)
@ -423,7 +432,7 @@ handle_output_debug_string (DWORD id, LPVOID p, unsigned mask, FILE *ofile)
else
{
special = len;
if (special == _STRACE_INTERFACE_ACTIVATE_ADDR)
if (special == _STRACE_INTERFACE_ACTIVATE_ADDR || special == _STRACE_CHILD_PID)
len = 17;
}
@ -441,14 +450,20 @@ handle_output_debug_string (DWORD id, LPVOID p, unsigned mask, FILE *ofile)
s = strchr (s, '\0') + 1;
if (special == _STRACE_CHILD_PID)
{
if (!DebugActiveProcess (n))
error (0, "couldn't attach to subprocess %d for debugging, "
"windows error %d", n, GetLastError ());
return;
}
if (special == _STRACE_INTERFACE_ACTIVATE_ADDR)
{
DWORD new_flag = 1;
if (!WriteProcessMemory (hchild, (LPVOID) n, &new_flag,
sizeof (new_flag), &nbytes))
error (0,
"couldn't write strace flag to subprocess at %p, windows error %d",
n, GetLastError ());
if (!WriteProcessMemory (hchild, (LPVOID) n, &strace_active,
sizeof (strace_active), &nbytes))
error (0, "couldn't write strace flag to subprocess at %p, "
"windows error %d", n, GetLastError ());
return;
}
@ -577,7 +592,6 @@ static void
proc_child (unsigned mask, FILE *ofile, pid_t pid)
{
DEBUG_EVENT ev;
int processes = 0;
time_t cur_time, last_time;
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
@ -609,7 +623,6 @@ proc_child (unsigned mask, FILE *ofile, pid_t pid)
if (ev.u.CreateProcessInfo.hFile)
CloseHandle (ev.u.CreateProcessInfo.hFile);
add_child (ev.dwProcessId, ev.u.CreateProcessInfo.hProcess);
processes++;
break;
case CREATE_THREAD_DEBUG_EVENT:
@ -630,22 +643,20 @@ proc_child (unsigned mask, FILE *ofile, pid_t pid)
remove_child (ev.dwProcessId);
break;
case EXCEPTION_DEBUG_EVENT:
if (ev.u.Exception.ExceptionRecord.ExceptionCode !=
STATUS_BREAKPOINT)
if (ev.u.Exception.ExceptionRecord.ExceptionCode != STATUS_BREAKPOINT)
{
status = DBG_EXCEPTION_NOT_HANDLED;
#if 0
fprintf (stderr, "exception %p at %p\n",
ev.u.Exception.ExceptionRecord.ExceptionCode,
ev.u.Exception.ExceptionRecord.ExceptionAddress);
#endif
if (ev.u.Exception.dwFirstChance)
fprintf (ofile, "--- Process %u, exception %p at %p\n", ev.dwProcessId,
ev.u.Exception.ExceptionRecord.ExceptionCode,
ev.u.Exception.ExceptionRecord.ExceptionAddress);
}
break;
}
if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, status))
error (0, "couldn't continue debug event, windows error %d",
GetLastError ());
if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT && --processes == 0)
if (!processes)
break;
}
}
@ -864,6 +875,7 @@ struct option longopts[] = {
{"output", required_argument, NULL, 'o'},
{"no-delta", no_argument, NULL, 'd'},
{"pid", required_argument, NULL, 'p'},
{"quiet", no_argument, NULL, 'q'},
{"timestamp", no_argument, NULL, 't'},
{"toggle", no_argument, NULL, 'T'},
{"trace-children", no_argument, NULL, 'f'},
@ -873,7 +885,7 @@ struct option longopts[] = {
{NULL, 0, NULL, 0}
};
static const char *const opts = "+b:dhHfm:no:p:S:tTuvw";
static const char *const opts = "+b:dhHfm:no:p:qS:tTuvw";
static void
print_version ()
@ -906,6 +918,7 @@ main (int argc, char **argv)
pid_t pid = 0;
int opt;
int toggle = 0;
int sawquiet = -1;
if (load_cygwin ())
{
@ -963,6 +976,13 @@ character #%d.\n", optarg, (int) (endptr - optarg), endptr);
break;
case 'p':
pid = strtoul (optarg, NULL, 10);
strace_active |= 2;
break;
case 'q':
if (sawquiet < 0)
sawquiet = 1;
else
sawquiet ^= 1;
break;
case 'S':
flush_period = strtoul (optarg, NULL, 10);
@ -999,6 +1019,13 @@ character #%d.\n", optarg, (int) (endptr - optarg), endptr);
if (toggle && !pid)
error (0, "must provide a process id to toggle tracing");
if (!pid)
quiet = sawquiet < 0 || !sawquiet;
else if (sawquiet < 0)
quiet = 0;
else
quiet = sawquiet;
if (!mask)
mask = _STRACE_ALL;

View File

@ -1489,6 +1489,8 @@ Trace system calls and signals
numbers for Windows errors
-o, --output=FILENAME set output file to FILENAME
-p, --pid=n attach to executing program with cygwin pid n
-q, --quiet toggle "quiet" flag. Defaults to on if "-p",
off otherwise.
-S, --flush-period=PERIOD flush buffered strace output every PERIOD secs
-t, --timestamp use an absolute hh:mm:ss timestamp insted of
the default microsecond timestamp. Implies -d