From 37d4f656d49051410c99156d86c8a4cb8ccafa12 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Sat, 23 Feb 2013 16:25:58 +0100 Subject: [PATCH] Bug 678925 - Debugging plugins with windows Apply patch from Hartmut Kuhse that enables plug-in debugging on Windows by stopping the process using Windows API, and providing a small executable "gimp-plugin-resume.exe" to resume the stopped plug-in. --- devel-docs/debug-plug-ins.txt | 9 ++- libgimp/gimp.c | 43 ++++++++++++- tools/Makefile.am | 12 ++++ tools/gimp-debug-resume.c | 110 ++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 tools/gimp-debug-resume.c diff --git a/devel-docs/debug-plug-ins.txt b/devel-docs/debug-plug-ins.txt index f1c874b38a..3e8befa952 100644 --- a/devel-docs/debug-plug-ins.txt +++ b/devel-docs/debug-plug-ins.txt @@ -46,7 +46,9 @@ The steps to debug a plug-in are as follows: 5. Set breakpoints where you want the plug-in to stop in the debugger 6. Send the CONT signal (kill -CONT ) to the plug-in process - + (When compiled with Windows, resume the plug-in process with + gimp-debug-resume.exe ) + 7. Enter "continue" in the debugger. The plug-in will then continue and break at the breakpoints. @@ -105,3 +107,8 @@ GIMP_PLUGIN_DEBUG_WRAPPER=debugger debugger refers to the debugger program, such as valgrind. You can put command line options here too, they will be parsed like they do in the shell. + +When compiled with Windows, the plug-in process is halted by Windows functions. +It must be resumed externally by invoking gimp-debug-resume.exe +The plug-ins pid can be found out by invoking gimp-debug-resume.exe +without parameters. It shows the pid of all running processes. diff --git a/libgimp/gimp.c b/libgimp/gimp.c index 0f6e3860dd..520578084f 100644 --- a/libgimp/gimp.c +++ b/libgimp/gimp.c @@ -90,6 +90,7 @@ # define STRICT # define _WIN32_WINNT 0x0601 # include +# include # undef RGB # define USE_WIN32_SHM 1 #endif @@ -1649,10 +1650,50 @@ static void gimp_debug_stop (void) { #ifndef G_OS_WIN32 + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Waiting for debugger..."); raise (SIGSTOP); + #else - g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Debugging not implemented on Win32"); + + HANDLE hThreadSnap = NULL; + THREADENTRY32 te32 = { 0 }; + pid_t opid = getpid (); + + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Debugging (restart externally): %d", + opid); + + hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) + { + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + "error getting threadsnap - debugging impossible"); + return; + } + + te32.dwSize = sizeof (THREADENTRY32); + + if (Thread32First (hThreadSnap, &te32)) + { + do + { + if (te32.th32OwnerProcessID == opid) + { + HANDLE hThread = OpenThread (THREAD_SUSPEND_RESUME, FALSE, + te32.th32ThreadID); + SuspendThread (hThread); + CloseHandle (hThread); + } + } + while (Thread32Next (hThreadSnap, &te32)); + } + else + { + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "error getting threads"); + } + + CloseHandle (hThreadSnap); + #endif } diff --git a/tools/Makefile.am b/tools/Makefile.am index e78621e281..b2e595e28e 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -10,8 +10,20 @@ endif SUBDIRS = $(D_pdbgen) +if OS_WIN32 + +bin_PROGRAMS = \ + gimptool-2.0 \ + gimp-debug-resume + +gimp_debug_resume_SOURCES = gimp-debug-resume.c + +else + bin_PROGRAMS = gimptool-2.0 +endif + noinst_PROGRAMS = test-clipboard EXTRA_PROGRAMS = \ diff --git a/tools/gimp-debug-resume.c b/tools/gimp-debug-resume.c new file mode 100644 index 0000000000..57633bfa17 --- /dev/null +++ b/tools/gimp-debug-resume.c @@ -0,0 +1,110 @@ +/* based on pausep by Daniel Turini + */ + +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0502 +#include +#include +#include +#include + +static BOOL +resume_process (DWORD dwOwnerPID) +{ + HANDLE hThreadSnap = NULL; + BOOL bRet = FALSE; + THREADENTRY32 te32 = { 0 }; + + hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) + return FALSE; + + te32.dwSize = sizeof (THREADENTRY32); + + if (Thread32First (hThreadSnap, &te32)) + { + do + { + if (te32.th32OwnerProcessID == dwOwnerPID) + { + HANDLE hThread = OpenThread (THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID); + printf ("Resuming Thread: %u\n",te32.th32ThreadID); + ResumeThread (hThread); + CloseHandle (hThread); + } + } + while (Thread32Next (hThreadSnap, &te32)); + bRet = TRUE; + } + else + bRet = FALSE; + + CloseHandle (hThreadSnap); + + return bRet; +} + +static BOOL +process_list (void) +{ + HANDLE hProcessSnap = NULL; + BOOL bRet = FALSE; + PROCESSENTRY32 pe32 = {0}; + + hProcessSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); + + if (hProcessSnap == INVALID_HANDLE_VALUE) + return FALSE; + + pe32.dwSize = sizeof (PROCESSENTRY32); + + if (Process32First (hProcessSnap, &pe32)) + { + do + { + printf ("PID:\t%u\t%s\n", pe32.th32ProcessID, pe32.szExeFile); + } + while (Process32Next (hProcessSnap, &pe32)); + bRet = TRUE; + } + else + bRet = FALSE; + + CloseHandle (hProcessSnap); + + return bRet; +} + +int +main (int argc, + char* argv[]) +{ + DWORD pid; + + if (argc <= 1) + { + process_list (); + } + else if (argc == 2) + { + pid = atoi (argv[1]); + if (pid == 0) + { + printf ("invalid: %s\n", pid); + return 1; + } + else + { + printf ("process: %u\n", pid); + resume_process (pid); + } + } + else + { + printf ("Usage:\n" + "resume : show processlist\n" + "resume PID: resuming thread\n"); + } + + return 0; +}