Mailing-List: contact cygwin-developers-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-developers-owner AT cygwin DOT com Delivered-To: mailing list cygwin-developers AT cygwin DOT com Message-ID: <023901c2051c$92846ad0$6132bc3e@BABEL> From: "Conrad Scott" To: Subject: Problem in strace -p pid Date: Mon, 27 May 2002 02:19:39 +0100 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000 [Sorry: This is rather a long message] I asked last week about how to get 'strace -p pid' working, since it wasn't working for me. I've done some fishing about in the source and found that there seems to be a race condition (on w2k at least) where the child is not yet being debugged (according to IsDebuggerPresent() for example) despite the DebugActiveProcess() call having completed in strace.exe. I've got a fix that seems to work (signalling the target process at a suitable later moment) but I thought I'd just set out my logic here for others to check if they could. This could also form part of a "how-strace-works.txt", on the off-chance I've got it right of course . . . Anyhow, here's my account of how strace works when its attaching to a existing process: 1) strace.exe attachs to the target process for debugging (via DebugActiveProcess()). 2) Then it sends it the magic signal __SIGSTRACE (via cygwin_internal(CW_STRACE_TOGGLE, pid) in external.cc). 3) This signal causes the target process to enter strace.hello() (via the special handling in wait_sig() in sigproc.cc). 4) strace::hello() builds a magic string containing the address of its `active' flag as a hexadecimal string and sends this back to strace.exe (via OutputDebugString () using the special marker value _STRACE_INTERFACE_ACTIVATE_ADDR). 5) strace.exe picks up this magic string (in handle_output_debug_string()) and sets the target process's `active' flag (via WriteProcessMemory() with the address of the `active' flag that it has extracted from the debug string). 6) Now that the `strace.active' flag is set, the target process generates the messages for strace.exe by successive calls to OutputDebugString(). Synchronization in all of this occurs since, when a process is being debugged, calls to OutputDebugString() do not return until the debugger has received the corresponding debug event (via WaitForDebugEvent()) and allowed the target to continue processing (via ContinueDebugEvent()). [* Caveat: I'm unclear that this is *exactly* what happens, as there seems to be some degree of buffering involved, but it's close enough for the current discusion, so far as I can tell. *] There is unfortunately a race, since (on w2k at least) the target process is not being debugged by the time it receives the magic __SIGSTRACE signal. Thus the OutputDebugString() call in strace::hello() does nothing. (To quote the SDK: "If the application has no debugger, the system debugger displays the string. If the application has no debugger and the system debugger is not active, OutputDebugString does nothing.") So strace.exe never receives the magic message and never toggles the `active' flag. Silence reigns. [* Note that other debug events *are* queued up even if no debugger is attached. For example, as soon as strace.exe attaches to the target process it gets a stream of CREATE_THREAD and LOAD_DLL events (amongst others) that I assume are the same as it would get if it started the target itself; that is, they are the messages generated during application launch. See the earlier caveat too in this context. *] My "fix" for this infelicity is for strace.exe to re-signal the target process if it gets into the situation that there are no pending debug events (i.e., the call to WaitForDebugEvent() times out) and it has yet to receive the magic _STRACE_INTERFACE_ACTIVATE_ADDR message. And that works for me (i.e. I can now get back to what I was trying to do in the first place). But does anyone out there know better? If so, please give me at least a little hint. While I'm at it, I was considering making some extensions to strace.exe: for example, to (optionally) display the other debug messages so that you could trace DLLs being loaded and unloaded, for example. Is anyone interested in this? or is there some other preferred mechanism? Anyhow, I'm off to bed now (and tomorrow I'll post off my copyright assignment form so I can then submit a patch, in case it comes to that). // Conrad