* 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'.
+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
#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
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) {}
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;
_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)
{
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;
/* 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,
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
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))
{
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:
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);
#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");
}
_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 ();
OpenProcessToken (hMainProc, MAXIMUM_ALLOWED, &hProcToken);
SetErrorMode (SEM_FAILCRITICALERRORS);
-
device::init ();
do_global_ctors (&__CTOR_LIST__, 1);
cygthread::init ();
switch (child_proc_info->type)
{
case _PROC_FORK:
- handle_fork ();
+ fork_info->handle_fork ();
break;
case _PROC_SPAWN:
case _PROC_EXEC:
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
/* 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
#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
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.");
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);
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;
dll_list NO_COPY dlls;
-static int NO_COPY in_forkee;
static bool dll_global_dtors_recorded;
/* Run destructors for all DLLs on exit. */
void
dll_list::load_after_fork (HANDLE parent, dll *first)
{
- in_forkee = 1;
int try2 = 0;
dll d;
}
next = d.next; /* Get the address of the next DLL. */
}
- in_forkee = 0;
+ in_forkee = false;
}
extern "C" int
case CW_STRACE_ACTIVE:
{
- return strace.active;
+ return strace.active ();
}
case CW_CYGWIN_PID_TO_WINPID:
len = dst - (char *) ptr;
#ifndef NOSTRACE
- if (strace.active)
+ if (strace.active ())
{
char buf[16 * 6 + 1];
char *p = buf;
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)
/* 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);
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)
/* 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.
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.
#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;
#define _STRACE_INTERFACE_ACTIVATE_ADDR -1
#define _STRACE_INTERFACE_ACTIVATE_ADDR1 -2
+#define _STRACE_CHILD_PID -3
/* Bitmasks of tracing messages to print. */
#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" {
#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)
#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; \
}))
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.
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);
}
}
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;
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;
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;
}
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)
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)
{
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;
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;
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
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 ())
/* 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)
{
#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); }
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);
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, "**********************************************");
}
}
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. */
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);
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);
#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! */
}
#ifndef NOSTRACE
- if (active)
+ if (active ())
write (category, buf, len);
#endif
SetLastError (err);
{
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);
void
strace::wm (int message, int word, int lon)
{
- if (active)
+ if (active ())
{
int i;
/* The title on program start. */
extern char *old_title;
extern bool display_title;
+extern bool in_forkee;
extern HANDLE hMainThread;
extern HANDLE hMainProc;
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.
2005-12-19 Igor Pechtchanski <pechtcha@cs.nyu.edu>
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);
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)
{
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
child_list *c1 = c->next;
c->next = c1->next;
free (c1);
+ if (!quiet)
+ fprintf (stderr, "Windows process %d detached\n", id);
+ processes--;
return;
}
{
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;
}
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)
else
{
special = len;
- if (special == _STRACE_INTERFACE_ACTIVATE_ADDR)
+ if (special == _STRACE_INTERFACE_ACTIVATE_ADDR || special == _STRACE_CHILD_PID)
len = 17;
}
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;
}
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);
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:
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;
}
}
{"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'},
{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 ()
pid_t pid = 0;
int opt;
int toggle = 0;
+ int sawquiet = -1;
if (load_cygwin ())
{
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);
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;
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