Henri Verbeet : server: Allow the debugger to be debugged.
Alexandre Julliard
julliard at winehq.org
Fri Mar 5 09:42:57 CST 2010
Module: wine
Branch: master
Commit: 1970fb35d40240448a311cf2fcd371c9d61300cb
URL: http://source.winehq.org/git/wine.git/?a=commit;h=1970fb35d40240448a311cf2fcd371c9d61300cb
Author: Henri Verbeet <hverbeet at codeweavers.com>
Date: Fri Mar 5 12:28:12 2010 +0100
server: Allow the debugger to be debugged.
---
dlls/kernel32/tests/debugger.c | 114 ++++++++++++++++++++++++++++++++++++++++
server/debugger.c | 6 --
2 files changed, 114 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c
index 9acea22..d37217a 100644
--- a/dlls/kernel32/tests/debugger.c
+++ b/dlls/kernel32/tests/debugger.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <windows.h>
+#include <winternl.h>
#include <winreg.h>
#include "wine/test.h"
@@ -29,6 +30,14 @@
#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354)
#endif
+#ifdef __GNUC__
+#define PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
+#else
+#define PRINTF_ATTR(fmt,args)
+#endif
+
+#define child_ok (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_child_ok
+
static int myARGC;
static char** myARGV;
@@ -36,6 +45,18 @@ static BOOL (WINAPI *pCheckRemoteDebuggerPresent)(HANDLE,PBOOL);
static BOOL (WINAPI *pDebugActiveProcessStop)(DWORD);
static BOOL (WINAPI *pDebugSetProcessKillOnExit)(BOOL);
+static LONG child_failures;
+
+static void PRINTF_ATTR(2, 3) test_child_ok(int condition, const char *msg, ...)
+{
+ va_list valist;
+
+ va_start(valist, msg);
+ winetest_vok(condition, msg, valist);
+ va_end(valist);
+ if (!condition) ++child_failures;
+}
+
/* Copied from the process test */
static void get_file_name(char* buf)
{
@@ -466,6 +487,94 @@ static void test_RemoteDebugger(void)
"expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError());
}
+struct child_blackbox
+{
+ LONG failures;
+};
+
+static void doChild(int argc, char **argv)
+{
+ struct child_blackbox blackbox;
+ const char *blackbox_file;
+ HANDLE parent;
+ DWORD ppid;
+ BOOL ret;
+
+ blackbox_file = argv[4];
+ sscanf(argv[3], "%08x", &ppid);
+
+ parent = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ppid);
+ child_ok(!!parent, "OpenProcess failed, last error %#x.\n", GetLastError());
+
+ ret = DebugActiveProcess(ppid);
+ child_ok(ret, "DebugActiveProcess failed, last error %#x.\n", GetLastError());
+
+ ret = pDebugActiveProcessStop(ppid);
+ child_ok(ret, "DebugActiveProcessStop failed, last error %#x.\n", GetLastError());
+
+ ret = CloseHandle(parent);
+ child_ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+
+ blackbox.failures = child_failures;
+ save_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
+}
+
+static void test_debug_loop(int argc, char **argv)
+{
+ const char *arguments = " debugger child ";
+ struct child_blackbox blackbox;
+ char blackbox_file[MAX_PATH];
+ PROCESS_INFORMATION pi;
+ STARTUPINFOA si;
+ DWORD pid;
+ char *cmd;
+ BOOL ret;
+
+ if (!pDebugActiveProcessStop)
+ {
+ win_skip("DebugActiveProcessStop not available, skipping test.\n");
+ return;
+ }
+
+ pid = GetCurrentProcessId();
+ get_file_name(blackbox_file);
+ cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + strlen(blackbox_file) + 10);
+ sprintf(cmd, "%s%s%08x %s", argv[0], arguments, pid, blackbox_file);
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
+ ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
+
+ HeapFree(GetProcessHeap(), 0, cmd);
+
+ for (;;)
+ {
+ DEBUG_EVENT ev;
+
+ ret = WaitForDebugEvent(&ev, INFINITE);
+ ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError());
+ if (!ret) break;
+
+ if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
+
+ ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+ ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
+ if (!ret) break;
+ }
+
+ ret = CloseHandle(pi.hThread);
+ ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+ ret = CloseHandle(pi.hProcess);
+ ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+
+ load_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
+ ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures);
+
+ ret = DeleteFileA(blackbox_file);
+ ok(ret, "DeleteFileA failed, last error %#x.\n", GetLastError());
+}
+
START_TEST(debugger)
{
HMODULE hdll;
@@ -484,9 +593,14 @@ START_TEST(debugger)
{
doDebugger(myARGC, myARGV);
}
+ else if (myARGC >= 5 && !strcmp(myARGV[2], "child"))
+ {
+ doChild(myARGC, myARGV);
+ }
else
{
test_ExitCode();
test_RemoteDebugger();
+ test_debug_loop(myARGC, myARGV);
}
}
diff --git a/server/debugger.c b/server/debugger.c
index 795a24a..727f3be 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -420,16 +420,10 @@ void generate_debug_event( struct thread *thread, int code, const void *arg )
/* attach a process to a debugger thread and suspend it */
static int debugger_attach( struct process *process, struct thread *debugger )
{
- struct thread *thread;
-
if (process->debugger) goto error; /* already being debugged */
if (!is_process_init_done( process )) goto error; /* still starting up */
if (list_empty( &process->thread_list )) goto error; /* no thread running in the process */
- /* make sure we don't create a debugging loop */
- for (thread = debugger; thread; thread = thread->process->debugger)
- if (thread->process == process) goto error;
-
/* don't let a debugger debug its console... won't work */
if (debugger->process->console && console_get_renderer(debugger->process->console)->process == process)
goto error;
More information about the wine-cvs
mailing list