From 1970fb35d40240448a311cf2fcd371c9d61300cb Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Fri, 5 Mar 2010 12:28:12 +0100 Subject: [PATCH] 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 9acea22821a..d37217a8bd3 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -22,6 +22,7 @@ #include #include +#include #include #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 795a24a2f37..727f3be6182 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;