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.
This commit is contained in:
Michael Natterer 2013-02-23 16:25:58 +01:00
parent e4f24a539e
commit 37d4f656d4
4 changed files with 172 additions and 2 deletions

View file

@ -46,6 +46,8 @@ 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 <pid>) to the plug-in process
(When compiled with Windows, resume the plug-in process with
gimp-debug-resume.exe <pid>)
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 <pid>
The plug-ins pid can be found out by invoking gimp-debug-resume.exe
without parameters. It shows the pid of all running processes.

View file

@ -90,6 +90,7 @@
# define STRICT
# define _WIN32_WINNT 0x0601
# include <windows.h>
# include <tlhelp32.h>
# 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
}

View file

@ -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 = \

110
tools/gimp-debug-resume.c Normal file
View file

@ -0,0 +1,110 @@
/* based on pausep by Daniel Turini
*/
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0502
#include <windows.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <stdio.h>
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;
}