This is the mail archive of the
cygwin-patches
mailing list for the Cygwin project.
[PATCH] Improve strace to log most Windows debug events
- From: Jon TURNEY <jon dot turney at dronecode dot org dot uk>
- To: cygwin-patches at cygwin dot com
- Cc: Jon TURNEY <jon dot turney at dronecode dot org dot uk>
- Date: Wed, 10 Jun 2015 13:05:22 +0100
- Subject: [PATCH] Improve strace to log most Windows debug events
- Authentication-results: sourceware.org; auth=none
Not sure if this is wanted, but on a couple of occasions recently I have been
presented with strace output which contains an exception at an address in an
unknown module (i.e. not in the cygwin DLL or the main executable), so here is a
patch which adds some more information, including DLL load addresses, to help
interpret such straces.
2015-06-07 Jon Turney <jon.turney@dronecode.org.uk>
* strace.cc (proc_child): Log process and thread create and exit,
and DLL load and unload.
(GetFileNameFromHandle): New function.
* Makefile.in (strace.exe): Link against psapi.dll.
Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
---
winsup/utils/ChangeLog | 7 ++++++
winsup/utils/Makefile.in | 2 +-
winsup/utils/strace.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog
index bfdb42a..7561a58 100644
--- a/winsup/utils/ChangeLog
+++ b/winsup/utils/ChangeLog
@@ -1,3 +1,10 @@
+2015-06-07 Jon Turney <jon.turney@dronecode.org.uk>
+
+ * strace.cc (proc_child): Log process and thread create and exit,
+ and DLL load and unload.
+ (GetFileNameFromHandle): New function.
+ * Makefile.in (strace.exe): Link against psapi.dll.
+
2015-04-21 Corinna Vinschen <corinna@vinschen.de>
* tzmap-from-unicode.org: Convert Calcutta to Kolkata.
diff --git a/winsup/utils/Makefile.in b/winsup/utils/Makefile.in
index fe81d87..4dfe349 100644
--- a/winsup/utils/Makefile.in
+++ b/winsup/utils/Makefile.in
@@ -101,7 +101,7 @@ cygcheck.exe: ${CYGCHECK_OBJS}
cygpath.o: CXXFLAGS += -fno-threadsafe-statics
cygpath.exe: CYGWIN_LDFLAGS += -lcygwin -luserenv -lntdll
ps.exe: CYGWIN_LDFLAGS += -lcygwin -lpsapi -lntdll
-strace.exe: MINGW_LDFLAGS += -lntdll
+strace.exe: MINGW_LDFLAGS += -lntdll -lpsapi
ldd.exe:CYGWIN_LDFLAGS += -lpsapi
pldd.exe: CYGWIN_LDFLAGS += -lpsapi
diff --git a/winsup/utils/strace.cc b/winsup/utils/strace.cc
index 73096ab..f54cab5 100644
--- a/winsup/utils/strace.cc
+++ b/winsup/utils/strace.cc
@@ -12,6 +12,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include <windows.h>
+#include <psapi.h>
#include <winternl.h>
#define cygwin_internal cygwin_internal_dontuse
#include <stdio.h>
@@ -637,6 +638,36 @@ handle_output_debug_string (DWORD id, LPVOID p, unsigned mask, FILE *ofile)
fflush (ofile);
}
+// This is a pretty tragic way to convert HANDLE -> filename, but this is the
+// the way MSDN suggest to do it if you want to be portable to Windows versions
+// prior to 6.0, where GetFinalPathNameByHandle() isn't available.
+static BOOL
+GetFileNameFromHandle(HANDLE hFile, WCHAR pszFilename[MAX_PATH+1])
+{
+ HANDLE hFileMap;
+ BOOL result = FALSE;
+
+ // Create a file mapping object.
+ hFileMap = CreateFileMapping (hFile, NULL, PAGE_READONLY, 0, 1, NULL);
+ if (hFileMap)
+ {
+ // Create a file mapping to get the file name.
+ void* pMem = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0, 1);
+ if (pMem)
+ {
+ if (GetMappedFileNameW (GetCurrentProcess (), pMem, pszFilename,
+ MAX_PATH))
+ {
+ result = TRUE;
+ }
+ UnmapViewOfFile(pMem);
+ }
+ CloseHandle(hFileMap);
+ }
+
+ return result;
+}
+
static DWORD
proc_child (unsigned mask, FILE *ofile, pid_t pid)
{
@@ -670,19 +701,38 @@ proc_child (unsigned mask, FILE *ofile, pid_t pid)
switch (ev.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
+ fprintf (ofile, "--- Process %lu created\n", ev.dwProcessId);
if (ev.u.CreateProcessInfo.hFile)
CloseHandle (ev.u.CreateProcessInfo.hFile);
add_child (ev.dwProcessId, ev.u.CreateProcessInfo.hProcess);
break;
case CREATE_THREAD_DEBUG_EVENT:
+ fprintf (ofile, "--- Process %lu thread %lu created\n",
+ ev.dwProcessId, ev.dwThreadId);
break;
case LOAD_DLL_DEBUG_EVENT:
+ {
+ // lpImageName is not always populated, so find the filename for
+ // hFile instead
+ WCHAR dllname[MAX_PATH+1];
+ if (!GetFileNameFromHandle(ev.u.LoadDll.hFile, dllname))
+ wcscpy(dllname, L"(unknown)");
+
+ fprintf (ofile, "--- Process %lu loaded %ls at %p\n",
+ ev.dwProcessId, dllname, ev.u.LoadDll.lpBaseOfDll);
+ }
+
if (ev.u.LoadDll.hFile)
CloseHandle (ev.u.LoadDll.hFile);
break;
+ case UNLOAD_DLL_DEBUG_EVENT:
+ fprintf (ofile, "--- Process %lu unloaded DLL at %p\n",
+ ev.dwProcessId, ev.u.UnloadDll.lpBaseOfDll);
+ break;
+
case OUTPUT_DEBUG_STRING_EVENT:
handle_output_debug_string (ev.dwProcessId,
ev.u.DebugString.lpDebugStringData,
@@ -690,9 +740,17 @@ proc_child (unsigned mask, FILE *ofile, pid_t pid)
break;
case EXIT_PROCESS_DEBUG_EVENT:
+ fprintf (ofile, "--- Process %lu exited with status 0x%lx\n",
+ ev.dwProcessId, ev.u.ExitProcess.dwExitCode);
res = ev.u.ExitProcess.dwExitCode;
remove_child (ev.dwProcessId);
break;
+
+ case EXIT_THREAD_DEBUG_EVENT:
+ fprintf (ofile, "--- Process %lu thread %lu exited with status 0x%lx\n",
+ ev.dwProcessId, ev.dwThreadId, ev.u.ExitThread.dwExitCode);
+ break;
+
case EXCEPTION_DEBUG_EVENT:
if (ev.u.Exception.ExceptionRecord.ExceptionCode
!= (DWORD) STATUS_BREAKPOINT)
--
2.1.4