winex11.drv: Map coordinates before calling send_mouse_input.
[wine/zf.git] / dlls / kernel32 / tests / debugger.c
blobf035d9165c7a1632d21ef8e9edeca18c03e602bc
1 /*
2 * Unit tests for the debugger facility
4 * Copyright (c) 2007 Francois Gouget for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdio.h>
22 #include <assert.h>
24 #include <ntstatus.h>
25 #define WIN32_NO_STATUS
26 #include <windows.h>
27 #include <winternl.h>
28 #include <winreg.h>
29 #include "wine/test.h"
30 #include "wine/heap.h"
31 #include "wine/rbtree.h"
33 #ifndef STATUS_DEBUGGER_INACTIVE
34 #define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354)
35 #endif
37 #define child_ok (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_child_ok
39 static int myARGC;
40 static char** myARGV;
42 static BOOL (WINAPI *pCheckRemoteDebuggerPresent)(HANDLE,PBOOL);
44 static void (WINAPI *pDbgBreakPoint)(void);
46 static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process);
47 static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process);
48 static NTSTATUS (WINAPI *pNtCreateDebugObject)(HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG);
49 static NTSTATUS (WINAPI *pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,void *,ULONG,ULONG*);
50 static NTSTATUS (WINAPI *pDbgUiConnectToDbg)(void);
51 static HANDLE (WINAPI *pDbgUiGetThreadDebugObject)(void);
52 static void (WINAPI *pDbgUiSetThreadDebugObject)(HANDLE);
53 static DWORD (WINAPI *pGetMappedFileNameW)(HANDLE,void*,WCHAR*,DWORD);
55 static LONG child_failures;
57 static HMODULE ntdll;
59 static void WINAPIV __WINE_PRINTF_ATTR(2, 3) test_child_ok(int condition, const char *msg, ...)
61 __ms_va_list valist;
63 __ms_va_start(valist, msg);
64 winetest_vok(condition, msg, valist);
65 __ms_va_end(valist);
66 if (!condition) ++child_failures;
69 /* Copied from the process test */
70 static void get_file_name(char* buf)
72 char path[MAX_PATH];
74 buf[0] = '\0';
75 GetTempPathA(sizeof(path), path);
76 GetTempFileNameA(path, "wt", 0, buf);
79 typedef struct tag_reg_save_value
81 const char *name;
82 DWORD type;
83 BYTE *data;
84 DWORD size;
85 } reg_save_value;
87 static DWORD save_value(HKEY hkey, const char *value, reg_save_value *saved)
89 DWORD ret;
90 saved->name=value;
91 saved->data=0;
92 saved->size=0;
93 ret=RegQueryValueExA(hkey, value, NULL, &saved->type, NULL, &saved->size);
94 if (ret == ERROR_SUCCESS)
96 saved->data=HeapAlloc(GetProcessHeap(), 0, saved->size);
97 RegQueryValueExA(hkey, value, NULL, &saved->type, saved->data, &saved->size);
99 return ret;
102 static void restore_value(HKEY hkey, reg_save_value *saved)
104 if (saved->data)
106 RegSetValueExA(hkey, saved->name, 0, saved->type, saved->data, saved->size);
107 HeapFree(GetProcessHeap(), 0, saved->data);
109 else
110 RegDeleteValueA(hkey, saved->name);
113 static void get_events(const char* name, HANDLE *start_event, HANDLE *done_event)
115 const char* basename;
116 char* event_name;
118 basename=strrchr(name, '\\');
119 basename=(basename ? basename+1 : name);
120 event_name=HeapAlloc(GetProcessHeap(), 0, 6+strlen(basename)+1);
122 sprintf(event_name, "start_%s", basename);
123 *start_event=CreateEventA(NULL, 0,0, event_name);
124 sprintf(event_name, "done_%s", basename);
125 *done_event=CreateEventA(NULL, 0,0, event_name);
126 HeapFree(GetProcessHeap(), 0, event_name);
129 static void save_blackbox(const char* logfile, void* blackbox, int size, const char *dbgtrace)
131 HANDLE hFile;
132 DWORD written;
134 hFile=CreateFileA(logfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
135 if (hFile == INVALID_HANDLE_VALUE)
136 return;
137 WriteFile(hFile, blackbox, size, &written, NULL);
138 if (dbgtrace && dbgtrace[0])
139 WriteFile(hFile, dbgtrace, strlen(dbgtrace), &written, NULL);
140 CloseHandle(hFile);
143 static int load_blackbox(const char* logfile, void* blackbox, int size)
145 HANDLE hFile;
146 DWORD read;
147 BOOL ret;
148 char buf[4096];
150 hFile=CreateFileA(logfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
151 if (hFile == INVALID_HANDLE_VALUE)
153 ok(0, "unable to open '%s'\n", logfile);
154 return 0;
156 SetLastError(0xdeadbeef);
157 ret=ReadFile(hFile, blackbox, size, &read, NULL);
158 ok(ret, "ReadFile failed: %d\n", GetLastError());
159 ok(read == size, "wrong size for '%s': read=%d\n", logfile, read);
160 ret = ReadFile(hFile, buf, sizeof(buf) - 1, &read, NULL);
161 if (ret && read)
163 buf[read] = 0;
164 trace("debugger traces:\n%s", buf);
166 CloseHandle(hFile);
167 return 1;
170 static DWORD WINAPI thread_proc(void *arg)
172 Sleep(10000);
173 trace("exiting\n");
174 ExitThread(1);
177 static void run_background_thread(void)
179 DWORD tid;
180 HANDLE thread = CreateThread(NULL, 0, thread_proc, NULL, 0, &tid);
181 ok(thread != NULL, "CreateThread failed\n");
182 CloseHandle(thread);
185 static void doCrash(void)
187 volatile char* p;
189 /* make sure the exception gets to the debugger */
190 SetErrorMode( 0 );
191 SetUnhandledExceptionFilter( NULL );
193 run_background_thread();
195 /* Just crash */
196 trace("child: crashing...\n");
197 p=NULL;
198 *p=0;
201 typedef struct
203 int argc;
204 DWORD pid;
205 BOOL debug_rc;
206 DWORD debug_err;
207 BOOL attach_rc;
208 DWORD attach_err;
209 BOOL nokill_rc;
210 DWORD nokill_err;
211 BOOL detach_rc;
212 DWORD detach_err;
213 DWORD failures;
214 } debugger_blackbox_t;
216 struct debugger_context
218 DWORD pid;
219 DEBUG_EVENT ev;
220 unsigned process_cnt;
221 unsigned dll_cnt;
222 void *image_base;
223 DWORD thread_tag;
224 unsigned thread_cnt;
225 struct wine_rb_tree threads;
226 struct debuggee_thread *current_thread;
227 struct debuggee_thread *main_thread;
230 struct debuggee_thread
232 DWORD tid;
233 DWORD tag;
234 HANDLE handle;
235 CONTEXT ctx;
236 struct wine_rb_entry entry;
239 int debuggee_thread_compare(const void *key, const struct wine_rb_entry *entry)
241 struct debuggee_thread *thread = WINE_RB_ENTRY_VALUE(entry, struct debuggee_thread, entry);
242 return memcmp(key, &thread->tid, sizeof(thread->tid));
245 static void add_thread(struct debugger_context *ctx, DWORD tid)
247 struct debuggee_thread *thread;
248 if (!ctx->thread_cnt++) wine_rb_init(&ctx->threads, debuggee_thread_compare);
249 thread = heap_alloc(sizeof(*thread));
250 thread->tid = tid;
251 thread->tag = ctx->thread_tag;
252 thread->handle = NULL;
253 wine_rb_put(&ctx->threads, &tid, &thread->entry);
254 if (!ctx->main_thread) ctx->main_thread = thread;
257 static struct debuggee_thread *get_debuggee_thread(struct debugger_context *ctx, DWORD tid)
259 struct wine_rb_entry *entry = wine_rb_get(&ctx->threads, &tid);
260 ok(entry != NULL, "unknown thread %x\n", tid);
261 return WINE_RB_ENTRY_VALUE(entry, struct debuggee_thread, entry);
264 static void remove_thread(struct debugger_context *ctx, DWORD tid)
266 struct debuggee_thread *thread = get_debuggee_thread(ctx, tid);
268 wine_rb_remove(&ctx->threads, &thread->entry);
269 if (thread->handle) CloseHandle(thread->handle);
270 heap_free(thread);
273 static void *get_ip(const CONTEXT *ctx)
275 #ifdef __i386__
276 return (void *)ctx->Eip;
277 #elif defined(__x86_64__)
278 return (void *)ctx->Rip;
279 #else
280 return NULL;
281 #endif
284 #define fetch_thread_context(a) fetch_thread_context_(__LINE__,a)
285 static void fetch_thread_context_(unsigned line, struct debuggee_thread *thread)
287 BOOL ret;
289 if (!thread->handle)
291 thread->handle = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION,
292 FALSE, thread->tid);
293 ok_(__FILE__,line)(thread->handle != NULL, "OpenThread failed: %u\n", GetLastError());
296 memset(&thread->ctx, 0xaa, sizeof(thread->ctx));
297 thread->ctx.ContextFlags = CONTEXT_FULL;
298 ret = GetThreadContext(thread->handle, &thread->ctx);
299 ok_(__FILE__,line)(ret, "GetThreadContext failed: %u\n", GetLastError());
302 #define set_thread_context(a,b) set_thread_context_(__LINE__,a,b)
303 static void set_thread_context_(unsigned line, struct debugger_context *ctx, struct debuggee_thread *thread)
305 BOOL ret;
306 ret = SetThreadContext(thread->handle, &thread->ctx);
307 ok_(__FILE__,line)(ret, "SetThreadContext failed: %u\n", GetLastError());
310 static void fetch_process_context(struct debugger_context *ctx)
312 struct debuggee_thread *thread;
314 WINE_RB_FOR_EACH_ENTRY(thread, &ctx->threads, struct debuggee_thread, entry)
316 fetch_thread_context(thread);
320 #define WAIT_EVENT_TIMEOUT 20000
321 #define POLL_EVENT_TIMEOUT 200
323 #define next_event(a,b) next_event_(__LINE__,a,b)
324 static void next_event_(unsigned line, struct debugger_context *ctx, unsigned timeout)
326 BOOL ret;
328 ctx->current_thread = NULL;
330 for (;;)
332 if (ctx->process_cnt && ctx->ev.dwDebugEventCode != -1)
334 ret = ContinueDebugEvent(ctx->ev.dwProcessId, ctx->ev.dwThreadId, DBG_CONTINUE);
335 ok_(__FILE__,line)(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
338 ret = WaitForDebugEvent(&ctx->ev, timeout);
339 if (!ret)
341 ok_(__FILE__,line)(GetLastError() == ERROR_SEM_TIMEOUT,
342 "WaitForDebugEvent failed, last error %d.\n", GetLastError());
343 ctx->ev.dwDebugEventCode = -1;
344 return;
347 if (ctx->ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
349 if (!ctx->process_cnt) ctx->pid = ctx->ev.dwProcessId;
350 ctx->process_cnt++;
353 if (ctx->ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) continue; /* ignore for now */
354 if (ctx->ev.dwProcessId == ctx->pid) break;
356 ok_(__FILE__,line)(ctx->process_cnt > 1, "unexpected event pid\n");
359 switch (ctx->ev.dwDebugEventCode)
361 case CREATE_PROCESS_DEBUG_EVENT:
362 add_thread(ctx, ctx->ev.dwThreadId);
363 ctx->image_base = ctx->ev.u.CreateProcessInfo.lpBaseOfImage;
364 break;
365 case EXIT_PROCESS_DEBUG_EVENT:
366 remove_thread(ctx, ctx->ev.dwThreadId);
367 return;
368 case CREATE_THREAD_DEBUG_EVENT:
369 add_thread(ctx, ctx->ev.dwThreadId);
370 break;
371 case EXIT_THREAD_DEBUG_EVENT:
372 remove_thread(ctx, ctx->ev.dwThreadId);
373 return;
374 case LOAD_DLL_DEBUG_EVENT:
375 ok(ctx->ev.u.LoadDll.lpBaseOfDll != ctx->image_base, "process image reported as DLL load event\n");
376 ctx->dll_cnt++;
377 break;
378 case UNLOAD_DLL_DEBUG_EVENT:
379 ctx->dll_cnt--;
380 break;
383 ctx->current_thread = get_debuggee_thread(ctx, ctx->ev.dwThreadId);
386 #define wait_for_breakpoint(a) wait_for_breakpoint_(__LINE__,a)
387 static void wait_for_breakpoint_(unsigned line, struct debugger_context *ctx)
389 do next_event_(line, ctx, WAIT_EVENT_TIMEOUT);
390 while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT
391 || ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT);
393 ok_(__FILE__,line)(ctx->ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx->ev.dwDebugEventCode);
394 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %x\n",
395 ctx->ev.u.Exception.ExceptionRecord.ExceptionCode);
398 static void process_attach_events(struct debugger_context *ctx, BOOL pass_exception)
400 DEBUG_EVENT ev;
401 BOOL ret;
403 ctx->ev.dwDebugEventCode = -1;
404 next_event(ctx, 0);
405 ok(ctx->ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx->ev.dwDebugEventCode);
407 next_event(ctx, 0);
408 if (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) /* Vista+ reports ntdll.dll before reporting threads */
410 ok(ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx->ev.dwDebugEventCode);
411 ok(ctx->ev.u.LoadDll.lpBaseOfDll == ntdll, "The first reported DLL is not ntdll.dll\n");
412 next_event(ctx, 0);
415 while (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
416 next_event(ctx, 0);
420 /* even when there are more pending events, they are not reported until current event is continued */
421 ret = WaitForDebugEvent(&ev, 10);
422 ok(GetLastError() == ERROR_SEM_TIMEOUT, "WaitForDebugEvent returned %x(%u)\n", ret, GetLastError());
424 next_event(ctx, WAIT_EVENT_TIMEOUT);
425 if (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT)
426 ok(ctx->ev.u.LoadDll.lpBaseOfDll != ntdll, "ntdll.dll reported out of order\n");
427 } while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT);
428 ok(ctx->dll_cnt > 2, "dll_cnt = %d\n", ctx->dll_cnt);
430 /* a new thread is created and it executes DbgBreakPoint, which causes the exception */
431 ok(ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx->ev.dwDebugEventCode);
432 if (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
434 DWORD last_thread = ctx->ev.dwThreadId;
435 next_event(ctx, WAIT_EVENT_TIMEOUT);
436 ok(ctx->ev.dwThreadId == last_thread, "unexpected thread\n");
439 ok(ctx->ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx->ev.dwDebugEventCode);
440 ok(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %x\n",
441 ctx->ev.u.Exception.ExceptionRecord.ExceptionCode);
442 ok(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint, "ExceptionAddress != DbgBreakPoint\n");
444 if (pass_exception)
446 ret = ContinueDebugEvent(ctx->ev.dwProcessId, ctx->ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
447 ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
448 ctx->ev.dwDebugEventCode = -1;
451 /* flush debug events */
452 do next_event(ctx, POLL_EVENT_TIMEOUT);
453 while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT
454 || ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || ctx->ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT);
455 ok(ctx->ev.dwDebugEventCode == -1, "dwDebugEventCode = %d\n", ctx->ev.dwDebugEventCode);
458 static void doDebugger(int argc, char** argv)
460 const char* logfile;
461 debugger_blackbox_t blackbox;
462 HANDLE start_event = 0, done_event = 0, debug_event;
463 char buf[4096] = "";
464 struct debugger_context ctx = { 0 };
466 blackbox.argc=argc;
467 logfile=(argc >= 4 ? argv[3] : NULL);
468 blackbox.pid=(argc >= 5 ? atol(argv[4]) : 0);
470 blackbox.attach_err=0;
471 if (strstr(myARGV[2], "attach"))
473 blackbox.attach_rc=DebugActiveProcess(blackbox.pid);
474 if (!blackbox.attach_rc)
475 blackbox.attach_err=GetLastError();
477 else
478 blackbox.attach_rc=TRUE;
480 if (strstr(myARGV[2], "process"))
482 strcat(buf, "processing debug messages\n");
483 process_attach_events(&ctx, FALSE);
486 debug_event=(argc >= 6 ? (HANDLE)(INT_PTR)atol(argv[5]) : NULL);
487 blackbox.debug_err=0;
488 if (debug_event && strstr(myARGV[2], "event"))
490 strcat(buf, "setting event\n");
491 blackbox.debug_rc=SetEvent(debug_event);
492 if (!blackbox.debug_rc)
493 blackbox.debug_err=GetLastError();
495 else
496 blackbox.debug_rc=TRUE;
498 if (strstr(myARGV[2], "process"))
500 next_event(&ctx, WAIT_EVENT_TIMEOUT);
501 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
502 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == STATUS_ACCESS_VIOLATION, "ExceptionCode = %x\n",
503 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
506 if (logfile)
508 get_events(logfile, &start_event, &done_event);
511 if (strstr(myARGV[2], "order"))
513 strcat(buf, "waiting for the start signal...\n");
514 WaitForSingleObject(start_event, INFINITE);
517 blackbox.nokill_err=0;
518 if (strstr(myARGV[2], "nokill"))
520 blackbox.nokill_rc = DebugSetProcessKillOnExit(FALSE);
521 if (!blackbox.nokill_rc)
522 blackbox.nokill_err=GetLastError();
524 else
525 blackbox.nokill_rc=TRUE;
527 blackbox.detach_err=0;
528 if (strstr(myARGV[2], "detach"))
530 blackbox.detach_rc = DebugActiveProcessStop(blackbox.pid);
531 if (!blackbox.detach_rc)
532 blackbox.detach_err=GetLastError();
534 else
535 blackbox.detach_rc=TRUE;
537 if (debug_event && strstr(myARGV[2], "late"))
539 strcat(buf, "setting event\n");
540 blackbox.debug_rc=SetEvent(debug_event);
541 if (!blackbox.debug_rc)
542 blackbox.debug_err=GetLastError();
545 strcat(buf, "done debugging...\n");
546 if (logfile)
548 blackbox.failures = winetest_get_failures();
549 save_blackbox(logfile, &blackbox, sizeof(blackbox), buf);
552 SetEvent(done_event);
554 /* Just exit with a known value */
555 ExitProcess(0xdeadbeef);
558 static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks)
560 static BOOL skip_crash_and_debug = FALSE;
561 BOOL bRet;
562 DWORD ret;
563 HANDLE start_event, done_event;
564 char* cmd;
565 char dbglog[MAX_PATH];
566 PROCESS_INFORMATION info;
567 STARTUPINFOA startup;
568 DWORD exit_code;
569 debugger_blackbox_t dbg_blackbox;
570 DWORD wait_code;
572 if (skip_crash_and_debug)
574 win_skip("Skipping crash_and_debug\n");
575 return;
578 ret=RegSetValueExA(hkey, "auto", 0, REG_SZ, (BYTE*)"1", 2);
579 if (ret == ERROR_ACCESS_DENIED)
581 skip_crash_and_debug = TRUE;
582 skip("No write access to change the debugger\n");
583 return;
586 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%d\n", ret);
588 get_file_name(dbglog);
589 get_events(dbglog, &start_event, &done_event);
590 cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+10+strlen(dbgtasks)+1+strlen(dbglog)+2+34+1);
591 sprintf(cmd, "%s debugger %s \"%s\" %%ld %%ld", argv0, dbgtasks, dbglog);
592 ret=RegSetValueExA(hkey, "debugger", 0, REG_SZ, (BYTE*)cmd, strlen(cmd)+1);
593 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/debugger: ret=%d\n", ret);
594 HeapFree(GetProcessHeap(), 0, cmd);
596 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv0) + 16);
597 sprintf(cmd, "%s debugger crash", argv0);
599 trace("running %s...\n", dbgtasks);
600 memset(&startup, 0, sizeof(startup));
601 startup.cb = sizeof(startup);
602 startup.dwFlags = STARTF_USESHOWWINDOW;
603 startup.wShowWindow = SW_SHOWNORMAL;
604 ret=CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
605 ok(ret, "CreateProcess: err=%d\n", GetLastError());
606 HeapFree(GetProcessHeap(), 0, cmd);
607 CloseHandle(info.hThread);
609 /* The process exits... */
610 trace("waiting for child exit...\n");
611 wait_code = WaitForSingleObject(info.hProcess, 30000);
612 #if defined(_WIN64) && defined(__MINGW32__)
613 /* Mingw x64 doesn't output proper unwind info */
614 skip_crash_and_debug = broken(wait_code == WAIT_TIMEOUT);
615 if (skip_crash_and_debug)
617 TerminateProcess(info.hProcess, WAIT_TIMEOUT);
618 WaitForSingleObject(info.hProcess, 5000);
619 CloseHandle(info.hProcess);
620 DeleteFileA(dbglog);
621 win_skip("Giving up on child process\n");
622 return;
624 #endif
625 ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n");
626 bRet = GetExitCodeProcess(info.hProcess, &exit_code);
627 ok(bRet, "GetExitCodeProcess failed: err=%d\n", GetLastError());
628 if (strstr(dbgtasks, "code2"))
630 /* If, after attaching to the debuggee, the debugger exits without
631 * detaching, then the debuggee gets a special exit code.
633 ok(exit_code == STATUS_DEBUGGER_INACTIVE ||
634 broken(exit_code == STATUS_ACCESS_VIOLATION) || /* Intermittent Vista+ */
635 broken(exit_code == WAIT_ABANDONED), /* NT4, W2K */
636 "wrong exit code : %08x\n", exit_code);
638 else
639 ok(exit_code == STATUS_ACCESS_VIOLATION ||
640 broken(exit_code == WAIT_ABANDONED), /* NT4, W2K, W2K3 */
641 "wrong exit code : %08x\n", exit_code);
642 CloseHandle(info.hProcess);
644 /* ...before the debugger */
645 if (strstr(dbgtasks, "order"))
646 ok(SetEvent(start_event), "SetEvent(start_event) failed\n");
648 trace("waiting for the debugger...\n");
649 wait_code = WaitForSingleObject(done_event, 5000);
650 #if defined(_WIN64) && defined(__MINGW32__)
651 /* Mingw x64 doesn't output proper unwind info */
652 skip_crash_and_debug = broken(wait_code == WAIT_TIMEOUT);
653 if (skip_crash_and_debug)
655 DeleteFileA(dbglog);
656 win_skip("Giving up on debugger\n");
657 return;
659 #endif
660 ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the debugger\n");
662 ok(load_blackbox(dbglog, &dbg_blackbox, sizeof(dbg_blackbox)), "failed to open: %s\n", dbglog);
664 ok(dbg_blackbox.argc == 6, "wrong debugger argument count: %d\n", dbg_blackbox.argc);
665 ok(dbg_blackbox.pid == info.dwProcessId, "the child and debugged pids don't match: %d != %d\n", info.dwProcessId, dbg_blackbox.pid);
666 ok(dbg_blackbox.debug_rc, "debugger: SetEvent(debug_event) failed err=%d\n", dbg_blackbox.debug_err);
667 ok(dbg_blackbox.attach_rc, "DebugActiveProcess(%d) failed err=%d\n", dbg_blackbox.pid, dbg_blackbox.attach_err);
668 ok(dbg_blackbox.nokill_rc, "DebugSetProcessKillOnExit(FALSE) failed err=%d\n", dbg_blackbox.nokill_err);
669 ok(dbg_blackbox.detach_rc, "DebugActiveProcessStop(%d) failed err=%d\n", dbg_blackbox.pid, dbg_blackbox.detach_err);
670 ok(!dbg_blackbox.failures, "debugger reported %u failures\n", dbg_blackbox.failures);
672 DeleteFileA(dbglog);
675 static void crash_and_winedbg(HKEY hkey, const char* argv0)
677 BOOL bRet;
678 DWORD ret;
679 char* cmd;
680 PROCESS_INFORMATION info;
681 STARTUPINFOA startup;
682 DWORD exit_code;
684 ret=RegSetValueExA(hkey, "auto", 0, REG_SZ, (BYTE*)"1", 2);
685 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%d\n", ret);
687 cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+15+1);
688 sprintf(cmd, "%s debugger crash", argv0);
690 memset(&startup, 0, sizeof(startup));
691 startup.cb = sizeof(startup);
692 startup.dwFlags = STARTF_USESHOWWINDOW;
693 startup.wShowWindow = SW_SHOWNORMAL;
694 ret=CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
695 ok(ret, "CreateProcess: err=%d\n", GetLastError());
696 HeapFree(GetProcessHeap(), 0, cmd);
697 CloseHandle(info.hThread);
699 trace("waiting for child exit...\n");
700 ok(WaitForSingleObject(info.hProcess, 60000) == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n");
701 bRet = GetExitCodeProcess(info.hProcess, &exit_code);
702 ok(bRet, "GetExitCodeProcess failed: err=%d\n", GetLastError());
703 ok(exit_code == STATUS_ACCESS_VIOLATION, "exit code = %08x\n", exit_code);
704 CloseHandle(info.hProcess);
707 static void test_ExitCode(void)
709 static const char* AeDebug="Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug";
710 static const char* WineDbg="Software\\Wine\\WineDbg";
711 char test_exe[MAX_PATH];
712 DWORD ret;
713 HKEY hkey;
714 DWORD disposition;
715 reg_save_value auto_value;
716 reg_save_value debugger_value;
718 GetModuleFileNameA(GetModuleHandleA(NULL), test_exe, sizeof(test_exe));
719 if (GetFileAttributesA(test_exe) == INVALID_FILE_ATTRIBUTES)
720 strcat(test_exe, ".so");
721 if (GetFileAttributesA(test_exe) == INVALID_FILE_ATTRIBUTES)
723 ok(0, "could not find the test executable '%s'\n", test_exe);
724 return;
727 ret=RegCreateKeyExA(HKEY_LOCAL_MACHINE, AeDebug, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition);
728 if (ret == ERROR_SUCCESS)
730 save_value(hkey, "auto", &auto_value);
731 save_value(hkey, "debugger", &debugger_value);
732 trace("HKLM\\%s\\debugger is set to '%s'\n", AeDebug, debugger_value.data);
734 else if (ret == ERROR_ACCESS_DENIED)
736 skip("not enough privileges to change the debugger\n");
737 return;
739 else if (ret != ERROR_FILE_NOT_FOUND)
741 ok(0, "could not open the AeDebug key: %d\n", ret);
742 return;
744 else debugger_value.data = NULL;
746 if (debugger_value.data && debugger_value.type == REG_SZ &&
747 strstr((char*)debugger_value.data, "winedbg --auto"))
749 HKEY hkeyWinedbg;
750 ret=RegCreateKeyA(HKEY_CURRENT_USER, WineDbg, &hkeyWinedbg);
751 if (ret == ERROR_SUCCESS)
753 static DWORD zero;
754 reg_save_value crash_dlg_value;
755 save_value(hkeyWinedbg, "ShowCrashDialog", &crash_dlg_value);
756 RegSetValueExA(hkeyWinedbg, "ShowCrashDialog", 0, REG_DWORD, (BYTE *)&zero, sizeof(DWORD));
757 ignore_exceptions(TRUE);
758 crash_and_winedbg(hkey, test_exe);
759 ignore_exceptions(FALSE);
760 restore_value(hkeyWinedbg, &crash_dlg_value);
761 RegCloseKey(hkeyWinedbg);
763 else
764 ok(0, "Couldn't access WineDbg Key - error %u\n", ret);
767 if (winetest_interactive)
768 /* Since the debugging process never sets the debug event, it isn't recognized
769 as a valid debugger and, after the debugger exits, Windows will show a dialog box
770 asking the user what to do */
771 crash_and_debug(hkey, test_exe, "dbg,none");
772 else
773 skip("\"none\" debugger test needs user interaction\n");
774 ok(disposition == REG_OPENED_EXISTING_KEY, "expected REG_OPENED_EXISTING_KEY, got %d\n", disposition);
775 crash_and_debug(hkey, test_exe, "dbg,event,order");
776 crash_and_debug(hkey, test_exe, "dbg,attach,event,code2");
777 crash_and_debug(hkey, test_exe, "dbg,attach,event,nokill");
778 crash_and_debug(hkey, test_exe, "dbg,attach,event,detach");
779 crash_and_debug(hkey, test_exe, "dbg,attach,detach,late");
780 crash_and_debug(hkey, test_exe, "dbg,attach,process,event,detach");
782 if (disposition == REG_CREATED_NEW_KEY)
784 RegCloseKey(hkey);
785 RegDeleteKeyA(HKEY_LOCAL_MACHINE, AeDebug);
787 else
789 restore_value(hkey, &auto_value);
790 restore_value(hkey, &debugger_value);
791 RegCloseKey(hkey);
795 static void test_RemoteDebugger(void)
797 BOOL bret, present;
798 if(!pCheckRemoteDebuggerPresent)
800 win_skip("CheckRemoteDebuggerPresent is not available\n");
801 return;
803 present = TRUE;
804 SetLastError(0xdeadbeef);
805 bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),&present);
806 ok(bret , "expected CheckRemoteDebuggerPresent to succeed\n");
807 ok(0xdeadbeef == GetLastError(),
808 "expected error to be unchanged, got %d/%x\n",GetLastError(), GetLastError());
810 present = TRUE;
811 SetLastError(0xdeadbeef);
812 bret = pCheckRemoteDebuggerPresent(NULL,&present);
813 ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n");
814 ok(present, "expected parameter to be unchanged\n");
815 ok(ERROR_INVALID_PARAMETER == GetLastError(),
816 "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError());
818 SetLastError(0xdeadbeef);
819 bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),NULL);
820 ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n");
821 ok(ERROR_INVALID_PARAMETER == GetLastError(),
822 "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError());
825 struct child_blackbox
827 LONG failures;
830 static void doChild(int argc, char **argv)
832 struct child_blackbox blackbox;
833 const char *blackbox_file;
834 WCHAR path[MAX_PATH];
835 HMODULE mod;
836 HANDLE parent, file, map;
837 DWORD ppid;
838 BOOL debug;
839 BOOL ret;
841 blackbox_file = argv[4];
842 sscanf(argv[3], "%08x", &ppid);
844 parent = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ppid);
845 child_ok(!!parent, "OpenProcess failed, last error %#x.\n", GetLastError());
847 ret = pCheckRemoteDebuggerPresent(parent, &debug);
848 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
849 child_ok(!debug, "Expected debug == 0, got %#x.\n", debug);
851 ret = DebugActiveProcess(ppid);
852 child_ok(ret, "DebugActiveProcess failed, last error %#x.\n", GetLastError());
854 ret = pCheckRemoteDebuggerPresent(parent, &debug);
855 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
856 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
858 ret = DebugActiveProcessStop(ppid);
859 child_ok(ret, "DebugActiveProcessStop failed, last error %#x.\n", GetLastError());
861 ret = pCheckRemoteDebuggerPresent(parent, &debug);
862 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
863 child_ok(!debug, "Expected debug == 0, got %#x.\n", debug);
865 ret = CloseHandle(parent);
866 child_ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
868 ret = IsDebuggerPresent();
869 child_ok(ret, "Expected ret != 0, got %#x.\n", ret);
870 ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug);
871 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
872 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
874 NtCurrentTeb()->Peb->BeingDebugged = FALSE;
876 ret = IsDebuggerPresent();
877 child_ok(!ret, "Expected ret != 0, got %#x.\n", ret);
878 ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug);
879 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
880 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
882 NtCurrentTeb()->Peb->BeingDebugged = TRUE;
884 mod = LoadLibraryW( L"ole32.dll" );
885 FreeLibrary( mod );
887 GetSystemDirectoryW( path, MAX_PATH );
888 wcscat( path, L"\\oleaut32.dll" );
889 file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
890 child_ok( file != INVALID_HANDLE_VALUE, "failed to open %s: %u\n", debugstr_w(path), GetLastError());
891 map = CreateFileMappingW( file, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL );
892 child_ok( map != NULL, "failed to create mapping %s: %u\n", debugstr_w(path), GetLastError() );
893 mod = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 );
894 child_ok( mod != NULL, "failed to map %s: %u\n", debugstr_w(path), GetLastError() );
895 CloseHandle( file );
896 CloseHandle( map );
897 UnmapViewOfFile( mod );
899 blackbox.failures = child_failures;
900 save_blackbox(blackbox_file, &blackbox, sizeof(blackbox), NULL);
903 static HMODULE ole32_mod, oleaut32_mod;
905 static void check_dll_event( HANDLE process, DEBUG_EVENT *ev )
907 WCHAR *p, module[MAX_PATH];
909 switch (ev->dwDebugEventCode)
911 case CREATE_PROCESS_DEBUG_EVENT:
912 break;
913 case LOAD_DLL_DEBUG_EVENT:
914 if (!pGetMappedFileNameW( process, ev->u.LoadDll.lpBaseOfDll, module, MAX_PATH )) module[0] = 0;
915 if ((p = wcsrchr( module, '\\' ))) p++;
916 else p = module;
917 if (!wcsicmp( p, L"ole32.dll" )) ole32_mod = ev->u.LoadDll.lpBaseOfDll;
918 else if (!wcsicmp( p, L"oleaut32.dll" )) oleaut32_mod = ev->u.LoadDll.lpBaseOfDll;
919 break;
920 case UNLOAD_DLL_DEBUG_EVENT:
921 if (ev->u.UnloadDll.lpBaseOfDll == ole32_mod) ole32_mod = (HMODULE)1;
922 if (ev->u.UnloadDll.lpBaseOfDll == oleaut32_mod) oleaut32_mod = (HMODULE)1;
923 break;
927 static void test_debug_loop(int argc, char **argv)
929 const char *arguments = " debugger child ";
930 struct child_blackbox blackbox;
931 char blackbox_file[MAX_PATH];
932 PROCESS_INFORMATION pi;
933 STARTUPINFOA si;
934 BOOL debug;
935 DWORD pid;
936 char *cmd;
937 BOOL ret;
939 if (!pCheckRemoteDebuggerPresent)
941 win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n");
942 return;
945 pid = GetCurrentProcessId();
946 ret = DebugActiveProcess(pid);
947 ok(!ret, "DebugActiveProcess() succeeded on own process.\n");
949 get_file_name(blackbox_file);
950 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + strlen(blackbox_file) + 2 + 10);
951 sprintf(cmd, "%s%s%08x \"%s\"", argv[0], arguments, pid, blackbox_file);
953 memset(&si, 0, sizeof(si));
954 si.cb = sizeof(si);
955 ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
956 ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
958 HeapFree(GetProcessHeap(), 0, cmd);
960 ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug);
961 ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
962 ok(debug, "Expected debug != 0, got %#x.\n", debug);
964 for (;;)
966 DEBUG_EVENT ev;
968 ret = WaitForDebugEvent(&ev, INFINITE);
969 ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError());
970 if (!ret) break;
972 if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
973 check_dll_event( pi.hProcess, &ev );
974 #if defined(__i386__) || defined(__x86_64__)
975 if (ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
976 ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
978 BYTE byte = 0;
979 NtReadVirtualMemory(pi.hProcess, ev.u.Exception.ExceptionRecord.ExceptionAddress, &byte, 1, NULL);
980 ok(byte == 0xcc, "got %02x\n", byte);
982 #endif
983 ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
984 ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
985 if (!ret) break;
988 ok( ole32_mod == (HMODULE)1, "ole32.dll was not reported\n" );
989 ok( oleaut32_mod == (HMODULE)1, "oleaut32.dll was not reported\n" );
991 ret = CloseHandle(pi.hThread);
992 ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
993 ret = CloseHandle(pi.hProcess);
994 ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
996 load_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
997 ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures);
999 ret = DeleteFileA(blackbox_file);
1000 ok(ret, "DeleteFileA failed, last error %#x.\n", GetLastError());
1003 static void doChildren(int argc, char **argv)
1005 const char *arguments = "debugger children last";
1006 struct child_blackbox blackbox;
1007 const char *blackbox_file, *p;
1008 char event_name[MAX_PATH];
1009 PROCESS_INFORMATION pi;
1010 STARTUPINFOA si;
1011 HANDLE event;
1012 char *cmd;
1013 BOOL ret;
1015 if (!strcmp(argv[3], "last")) return;
1017 blackbox_file = argv[3];
1019 run_background_thread();
1021 p = strrchr(blackbox_file, '\\');
1022 p = p ? p+1 : blackbox_file;
1023 strcpy(event_name, p);
1024 strcat(event_name, "_init");
1025 event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
1026 child_ok(event != NULL, "OpenEvent failed, last error %d.\n", GetLastError());
1027 SetEvent(event);
1028 CloseHandle(event);
1030 p = strrchr(blackbox_file, '\\');
1031 p = p ? p+1 : blackbox_file;
1032 strcpy(event_name, p);
1033 strcat(event_name, "_attach");
1034 event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
1035 child_ok(event != NULL, "OpenEvent failed, last error %d.\n", GetLastError());
1036 WaitForSingleObject(event, INFINITE);
1037 CloseHandle(event);
1039 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + 2);
1040 sprintf(cmd, "%s %s", argv[0], arguments);
1042 memset(&si, 0, sizeof(si));
1043 si.cb = sizeof(si);
1044 ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1045 child_ok(ret, "CreateProcess failed, last error %d.\n", GetLastError());
1047 child_ok(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0,
1048 "Timed out waiting for the child to exit\n");
1050 ret = CloseHandle(pi.hThread);
1051 child_ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1052 ret = CloseHandle(pi.hProcess);
1053 child_ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1055 blackbox.failures = child_failures;
1056 save_blackbox(blackbox_file, &blackbox, sizeof(blackbox), NULL);
1058 HeapFree(GetProcessHeap(), 0, cmd);
1061 static void test_debug_children(const char *name, DWORD flag, BOOL debug_child, BOOL pass_exception)
1063 const char *arguments = "debugger children";
1064 struct child_blackbox blackbox;
1065 char blackbox_file[MAX_PATH], *p;
1066 char event_name[MAX_PATH];
1067 PROCESS_INFORMATION pi;
1068 STARTUPINFOA si;
1069 HANDLE event_init, event_attach;
1070 char *cmd;
1071 BOOL debug, ret;
1072 struct debugger_context ctx = { 0 };
1074 if (!pCheckRemoteDebuggerPresent)
1076 win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n");
1077 return;
1080 get_file_name(blackbox_file);
1081 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(name) + strlen(arguments) + strlen(blackbox_file) + 5);
1082 sprintf(cmd, "%s %s \"%s\"", name, arguments, blackbox_file);
1084 p = strrchr(blackbox_file, '\\');
1085 p = p ? p+1 : blackbox_file;
1086 strcpy(event_name, p);
1087 strcat(event_name, "_init");
1088 event_init = CreateEventA(NULL, FALSE, FALSE, event_name);
1089 ok(event_init != NULL, "OpenEvent failed, last error %d.\n", GetLastError());
1091 p = strrchr(blackbox_file, '\\');
1092 p = p ? p+1 : blackbox_file;
1093 strcpy(event_name, p);
1094 strcat(event_name, "_attach");
1095 event_attach = CreateEventA(NULL, FALSE, flag!=0, event_name);
1096 ok(event_attach != NULL, "CreateEvent failed, last error %d.\n", GetLastError());
1098 memset(&si, 0, sizeof(si));
1099 si.cb = sizeof(si);
1101 ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, flag, NULL, NULL, &si, &pi);
1102 ok(ret, "CreateProcess failed, last error %d.\n", GetLastError());
1103 HeapFree(GetProcessHeap(), 0, cmd);
1104 if (!flag)
1106 WaitForSingleObject(event_init, INFINITE);
1107 Sleep(100);
1108 ret = DebugActiveProcess(pi.dwProcessId);
1109 ok(ret, "DebugActiveProcess failed, last error %d.\n", GetLastError());
1112 ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug);
1113 ok(ret, "CheckRemoteDebuggerPresent failed, last error %d.\n", GetLastError());
1114 ok(debug, "Expected debug != 0, got %x.\n", debug);
1116 trace("starting debugger loop\n");
1118 if (flag)
1120 DWORD last_thread;
1122 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1123 ok(ctx.ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1124 ok(ctx.pid == pi.dwProcessId, "unexpected dwProcessId %x\n", ctx.ev.dwProcessId == ctx.pid);
1126 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1127 ok(ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1128 last_thread = ctx.ev.dwThreadId;
1130 wait_for_breakpoint(&ctx);
1131 ok(ctx.dll_cnt > 2, "dll_cnt = %d\n", ctx.dll_cnt);
1133 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1134 ok(ctx.ev.dwThreadId == last_thread, "unexpected thread\n");
1135 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %x\n",
1136 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
1138 /* Except for wxppro and w2008, the initial breakpoint is now somewhere else, possibly within LdrInitShimEngineDynamic,
1139 * It's also catching exceptions and ContinueDebugEvent(DBG_EXCEPTION_NOT_HANDLED) should not crash the child now */
1140 if (broken(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint))
1142 win_skip("Ignoring initial breakpoint address check\n");
1143 pass_exception = FALSE;
1145 else
1147 todo_wine
1148 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress != pDbgBreakPoint, "ExceptionAddress == pDbgBreakPoint\n");
1151 if (pass_exception)
1153 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
1154 ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
1155 ctx.ev.dwDebugEventCode = -1;
1157 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1158 ok(ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1161 else
1163 DWORD last_thread;
1165 process_attach_events(&ctx, pass_exception);
1166 ok(ctx.pid == pi.dwProcessId, "unexpected dwProcessId %x\n", ctx.pid);
1168 ret = DebugBreakProcess(pi.hProcess);
1169 ok(ret, "BreakProcess failed: %u\n", GetLastError());
1171 /* a new thread, which executes DbgBreakPoint, is created */
1172 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1173 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1174 last_thread = ctx.ev.dwThreadId;
1176 if (ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
1177 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1179 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1180 ok(ctx.ev.dwThreadId == last_thread, "unexpected thread\n");
1181 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %x\n",
1182 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
1183 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint, "ExceptionAddress != DbgBreakPoint\n");
1185 ret = SetEvent(event_attach);
1186 ok(ret, "SetEvent failed, last error %d.\n", GetLastError());
1188 if (pass_exception)
1190 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
1191 ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
1192 ctx.ev.dwDebugEventCode = -1;
1196 do next_event(&ctx, WAIT_EVENT_TIMEOUT);
1197 while (ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx.ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT
1198 || ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT);
1200 ok(ctx.ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1201 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_CONTINUE);
1202 ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
1204 if(debug_child)
1205 ok(ctx.process_cnt == 2, "didn't get any child events (flag: %x).\n", flag);
1206 else
1207 ok(ctx.process_cnt == 1, "got child event (flag: %x).\n", flag);
1208 CloseHandle(event_init);
1209 CloseHandle(event_attach);
1211 ret = CloseHandle(pi.hThread);
1212 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1213 ret = CloseHandle(pi.hProcess);
1214 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1216 load_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
1217 ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures);
1219 ret = DeleteFileA(blackbox_file);
1220 ok(ret, "DeleteFileA failed, last error %d.\n", GetLastError());
1223 static void wait_debugger(HANDLE event)
1225 WaitForSingleObject(event, INFINITE);
1226 ExitProcess(0);
1229 #define expect_event(a,b) expect_event_(__LINE__,a,b)
1230 static void expect_event_(unsigned line, struct debugger_context *ctx, DWORD event_code)
1232 next_event(ctx, WAIT_EVENT_TIMEOUT);
1233 ok_(__FILE__,line)(ctx->ev.dwDebugEventCode == event_code, "dwDebugEventCode = %d expected %d\n",
1234 ctx->ev.dwDebugEventCode, event_code);
1237 #define expect_exception(a,b) expect_exception_(__LINE__,a,b)
1238 static void expect_exception_(unsigned line, struct debugger_context *ctx, DWORD exception_code)
1240 expect_event_(line, ctx, EXCEPTION_DEBUG_EVENT);
1241 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == exception_code, "ExceptionCode = %x expected %x\n",
1242 ctx->ev.u.Exception.ExceptionRecord.ExceptionCode, exception_code);
1245 #define expect_breakpoint_exception(a,b) expect_breakpoint_exception_(__LINE__,a,b)
1246 static void expect_breakpoint_exception_(unsigned line, struct debugger_context *ctx, const void *expect_addr)
1248 struct debuggee_thread *thread;
1249 expect_exception_(line, ctx, EXCEPTION_BREAKPOINT);
1250 if (!expect_addr) return;
1251 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == expect_addr,
1252 "ExceptionAddress = %p expected %p\n", ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress, expect_addr);
1253 thread = get_debuggee_thread(ctx, ctx->ev.dwThreadId);
1254 fetch_thread_context(thread);
1255 ok_(__FILE__,line)(get_ip(&thread->ctx) == (char*)expect_addr + 1, "unexpected instruction pointer %p expected %p\n",
1256 get_ip(&thread->ctx), expect_addr);
1259 #define single_step(a,b,c) single_step_(__LINE__,a,b,c)
1260 static void single_step_(unsigned line, struct debugger_context *ctx, struct debuggee_thread *thread, void *expect_addr)
1262 #if defined(__i386__) || defined(__x86_64__)
1263 fetch_thread_context(thread);
1264 thread->ctx.EFlags |= 0x100;
1265 set_thread_context(ctx, thread);
1266 expect_exception_(line, ctx, EXCEPTION_SINGLE_STEP);
1267 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == expect_addr,
1268 "ExceptionAddress = %p expected %p\n", ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress, expect_addr);
1269 fetch_thread_context(thread);
1270 ok_(__FILE__,line)(get_ip(&thread->ctx) == expect_addr, "unexpected instruction pointer %p expected %p\n",
1271 get_ip(&thread->ctx), expect_addr);
1272 ok_(__FILE__,line)(!(thread->ctx.EFlags & 0x100), "EFlags = %x\n", thread->ctx.EFlags);
1273 #endif
1276 static const BYTE loop_code[] = {
1277 #if defined(__i386__) || defined(__x86_64__)
1278 0x90, /* nop */
1279 0x90, /* nop */
1280 0x90, /* nop */
1281 0xe9, 0xf8, 0xff, 0xff, 0xff /* jmp $-8 */
1282 #endif
1285 static const BYTE call_debug_service_code[] = {
1286 #ifdef __i386__
1287 0x53, /* pushl %ebx */
1288 0x57, /* pushl %edi */
1289 0x8b, 0x44, 0x24, 0x0c, /* movl 12(%esp),%eax */
1290 0xb9, 0x11, 0x11, 0x11, 0x11, /* movl $0x11111111,%ecx */
1291 0xba, 0x22, 0x22, 0x22, 0x22, /* movl $0x22222222,%edx */
1292 0xbb, 0x33, 0x33, 0x33, 0x33, /* movl $0x33333333,%ebx */
1293 0xbf, 0x44, 0x44, 0x44, 0x44, /* movl $0x44444444,%edi */
1294 0xcd, 0x2d, /* int $0x2d */
1295 0xeb, /* jmp $+17 */
1296 0x0f, 0x1f, 0x00, /* nop */
1297 0x31, 0xc0, /* xorl %eax,%eax */
1298 0xeb, 0x0c, /* jmp $+14 */
1299 0x90, 0x90, 0x90, 0x90, /* nop */
1300 0x90, 0x90, 0x90, 0x90,
1301 0x90,
1302 0x31, 0xc0, /* xorl %eax,%eax */
1303 0x40, /* incl %eax */
1304 0x5f, /* popl %edi */
1305 0x5b, /* popl %ebx */
1306 0xc3, /* ret */
1307 #elif defined(__x86_64__)
1308 0x53, /* push %rbx */
1309 0x57, /* push %rdi */
1310 0x48, 0x89, 0xc8, /* movl %rcx,%rax */
1311 0x48, 0xb9, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, /* movabs $0x1111111111111111,%rcx */
1312 0x48, 0xba, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* movabs $0x2222222222222222,%rdx */
1313 0x48, 0xbb, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, /* movabs $0x3333333333333333,%rbx */
1314 0x48, 0xbf, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, /* movabs $0x4444444444444444,%rdi */
1315 0xcd, 0x2d, /* int $0x2d */
1316 0xeb, /* jmp $+17 */
1317 0x0f, 0x1f, 0x00, /* nop */
1318 0x48, 0x31, 0xc0, /* xor %rax,%rax */
1319 0xeb, 0x0e, /* jmp $+16 */
1320 0x90, 0x90, 0x90, 0x90, /* nop */
1321 0x90, 0x90, 0x90, 0x90,
1322 0x48, 0x31, 0xc0, /* xor %rax,%rax */
1323 0x48, 0xff, 0xc0, /* inc %rax */
1324 0x5f, /* pop %rdi */
1325 0x5b, /* pop %rbx */
1326 0xc3, /* ret */
1327 #endif
1330 #if defined(__i386__) || defined(__x86_64__)
1331 #define OP_BP 0xcc
1332 #else
1333 #define OP_BP 0
1334 #endif
1336 static void test_debugger(const char *argv0)
1338 static const char arguments[] = " debugger wait ";
1339 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
1340 struct debugger_context ctx = { 0 };
1341 PROCESS_INFORMATION pi;
1342 STARTUPINFOA si;
1343 NTSTATUS status;
1344 HANDLE event, thread;
1345 BYTE *mem, buf[4096], *proc_code, *thread_proc, byte;
1346 unsigned int i, worker_cnt, exception_cnt, skip_reply_later;
1347 struct debuggee_thread *debuggee_thread;
1348 char *cmd;
1349 BOOL ret;
1351 event = CreateEventW(&sa, TRUE, FALSE, NULL);
1352 ok(event != NULL, "CreateEvent failed: %u\n", GetLastError());
1354 cmd = heap_alloc(strlen(argv0) + strlen(arguments) + 16);
1355 sprintf(cmd, "%s%s%x\n", argv0, arguments, (DWORD)(DWORD_PTR)event);
1357 memset(&si, 0, sizeof(si));
1358 si.cb = sizeof(si);
1359 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
1360 ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
1361 heap_free(cmd);
1363 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1364 ok(ctx.ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1366 if ((skip_reply_later = !ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER)))
1367 win_skip("Skipping unsupported DBG_REPLY_LATER tests\n");
1368 else
1370 DEBUG_EVENT de;
1372 de = ctx.ev;
1373 ctx.ev.dwDebugEventCode = -1;
1374 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1375 ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1376 "dwDebugEventCode differs: %x (was %x)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode);
1377 ok(de.dwProcessId == ctx.ev.dwProcessId,
1378 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de.dwProcessId);
1379 ok(de.dwThreadId == ctx.ev.dwThreadId,
1380 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de.dwThreadId);
1382 /* Suspending the thread should prevent other attach debug events
1383 * to be received until it's resumed */
1384 thread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ctx.ev.dwThreadId);
1385 ok(thread != INVALID_HANDLE_VALUE, "OpenThread failed, last error:%u\n", GetLastError());
1387 status = NtSuspendThread(thread, NULL);
1388 ok(!status, "NtSuspendThread failed, last error:%u\n", GetLastError());
1390 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER);
1391 ok(ret, "ContinueDebugEvent failed, last error:%u\n", GetLastError());
1392 ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n");
1394 status = NtResumeThread(thread, NULL);
1395 ok(!status, "NtResumeThread failed, last error:%u\n", GetLastError());
1397 ret = CloseHandle(thread);
1398 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1400 ok(WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent failed.\n");
1401 ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1402 "dwDebugEventCode differs: %x (was %x)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode);
1404 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1405 ok(ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1406 de = ctx.ev;
1408 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER);
1409 ok(ret, "ContinueDebugEvent failed, last error:%u\n", GetLastError());
1411 ctx.ev.dwDebugEventCode = -1;
1412 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1413 ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1414 "dwDebugEventCode differs: %x (was %x)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode);
1415 ok(de.dwProcessId == ctx.ev.dwProcessId,
1416 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de.dwProcessId);
1417 ok(de.dwThreadId == ctx.ev.dwThreadId,
1418 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de.dwThreadId);
1421 wait_for_breakpoint(&ctx);
1422 do next_event(&ctx, POLL_EVENT_TIMEOUT);
1423 while(ctx.ev.dwDebugEventCode != -1);
1425 mem = VirtualAllocEx(pi.hProcess, NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1426 ok(mem != NULL, "VirtualAllocEx failed: %u\n", GetLastError());
1427 proc_code = buf + 1024;
1428 thread_proc = mem + 1024;
1430 if (sizeof(loop_code) > 1)
1432 /* test single-step exceptions */
1433 memset(buf, OP_BP, sizeof(buf));
1434 memcpy(proc_code, &loop_code, sizeof(loop_code));
1435 proc_code[0] = OP_BP; /* set a breakpoint */
1436 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
1437 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1439 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL);
1440 ok(thread != NULL, "CreateRemoteThread failed: %u\n", GetLastError());
1442 expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT);
1443 debuggee_thread = get_debuggee_thread(&ctx, ctx.ev.dwThreadId);
1445 wait_for_breakpoint(&ctx);
1446 fetch_thread_context(debuggee_thread);
1447 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == thread_proc,
1448 "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress);
1449 ok(get_ip(&debuggee_thread->ctx) == thread_proc + 1, "unexpected instruction pointer %p\n",
1450 get_ip(&debuggee_thread->ctx));
1452 single_step(&ctx, debuggee_thread, thread_proc + 2);
1453 single_step(&ctx, debuggee_thread, thread_proc + 3);
1454 single_step(&ctx, debuggee_thread, thread_proc);
1456 byte = 0xc3; /* ret */
1457 ret = WriteProcessMemory(pi.hProcess, thread_proc, &byte, 1, NULL);
1458 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1460 expect_event(&ctx, EXIT_THREAD_DEBUG_EVENT);
1462 else win_skip("loop_code not supported on this architecture\n");
1464 if (sizeof(call_debug_service_code) > 1)
1466 /* test debug service exceptions */
1467 memset(buf, OP_BP, sizeof(buf));
1468 memcpy(proc_code, call_debug_service_code, sizeof(call_debug_service_code));
1469 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
1470 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1472 /* BREAKPOINT_PRINT */
1473 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, (void*)2, 0, NULL);
1474 ok(thread != NULL, "CreateRemoteThread failed: %u\n", GetLastError());
1475 expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT);
1476 expect_breakpoint_exception(&ctx, NULL);
1477 expect_event(&ctx, EXIT_THREAD_DEBUG_EVENT);
1479 /* BREAKPOINT_PROMPT */
1480 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, (void*)1, 0, NULL);
1481 ok(thread != NULL, "CreateRemoteThread failed: %u\n", GetLastError());
1482 expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT);
1483 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1484 /* some 32-bit Windows versions report exception to the debugger */
1485 if (sizeof(void *) == 4 && ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) next_event(&ctx, WAIT_EVENT_TIMEOUT);
1486 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT, "unexpected debug event %u\n", ctx.ev.dwDebugEventCode);
1488 else win_skip("call_debug_service_code not supported on this architecture\n");
1490 if (skip_reply_later)
1491 win_skip("Skipping unsupported DBG_REPLY_LATER tests\n");
1492 else if (sizeof(loop_code) > 1)
1494 HANDLE thread_a, thread_b;
1495 DEBUG_EVENT de_a, de_b;
1497 memset(buf, OP_BP, sizeof(buf));
1498 memcpy(proc_code, &loop_code, sizeof(loop_code));
1499 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
1500 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1502 byte = OP_BP;
1503 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
1504 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1506 thread_a = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL);
1507 ok(thread_a != NULL, "CreateRemoteThread failed: %u\n", GetLastError());
1508 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1509 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1510 de_a = ctx.ev;
1512 thread_b = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL);
1513 ok(thread_b != NULL, "CreateRemoteThread failed: %u\n", GetLastError());
1514 do next_event(&ctx, POLL_EVENT_TIMEOUT);
1515 while(ctx.ev.dwDebugEventCode != CREATE_THREAD_DEBUG_EVENT);
1516 de_b = ctx.ev;
1518 status = NtSuspendThread(thread_b, NULL);
1519 ok(!status, "NtSuspendThread failed, last error:%u\n", GetLastError());
1520 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER);
1521 ok(ret, "ContinueDebugEvent failed, last error:%u\n", GetLastError());
1523 ctx.ev.dwDebugEventCode = -1;
1524 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1525 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT,
1526 "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1527 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1528 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1529 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1530 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1531 de_a = ctx.ev;
1533 byte = 0xc3; /* ret */
1534 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
1535 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1537 ok(pNtSuspendProcess != NULL, "NtSuspendProcess not found\n");
1538 ok(pNtResumeProcess != NULL, "pNtResumeProcess not found\n");
1539 if (pNtSuspendProcess && pNtResumeProcess)
1541 status = pNtSuspendProcess(pi.hProcess);
1542 ok(!status, "NtSuspendProcess failed, last error:%u\n", GetLastError());
1543 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER);
1544 ok(ret, "ContinueDebugEvent failed, last error:%u\n", GetLastError());
1545 ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n");
1547 status = NtResumeThread(thread_b, NULL);
1548 ok(!status, "NtResumeThread failed, last error:%u\n", GetLastError());
1549 ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n");
1551 status = pNtResumeProcess(pi.hProcess);
1552 ok(!status, "pNtResumeProcess failed, last error:%u\n", GetLastError());
1554 else
1556 status = NtResumeThread(thread_b, NULL);
1557 ok(!status, "NtResumeThread failed, last error:%u\n", GetLastError());
1558 ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n");
1561 /* Testing shows that on windows the debug event order between threads
1562 * is not guaranteed.
1564 * Now we expect thread_a to report:
1565 * - its delayed EXCEPTION_DEBUG_EVENT
1566 * - EXIT_THREAD_DEBUG_EVENT
1568 * and thread_b to report:
1569 * - its delayed CREATE_THREAD_DEBUG_EVENT
1570 * - EXIT_THREAD_DEBUG_EVENT
1572 * We should not get EXCEPTION_DEBUG_EVENT from thread_b as we updated
1573 * its instructions before continuing CREATE_THREAD_DEBUG_EVENT.
1575 ctx.ev.dwDebugEventCode = -1;
1576 next_event(&ctx, POLL_EVENT_TIMEOUT);
1578 if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
1580 ok(de_a.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1581 "dwDebugEventCode differs: %x (was %x)\n", ctx.ev.dwDebugEventCode, de_a.dwDebugEventCode);
1582 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1583 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1584 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1585 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1587 next_event(&ctx, POLL_EVENT_TIMEOUT);
1588 if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
1590 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1591 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1592 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1593 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1595 ret = CloseHandle(thread_a);
1596 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1597 thread_a = NULL;
1599 next_event(&ctx, POLL_EVENT_TIMEOUT);
1602 ok(de_b.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1603 "dwDebugEventCode differs: %x (was %x)\n", ctx.ev.dwDebugEventCode, de_b.dwDebugEventCode);
1604 ok(de_b.dwProcessId == ctx.ev.dwProcessId,
1605 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de_b.dwProcessId);
1606 ok(de_b.dwThreadId == ctx.ev.dwThreadId,
1607 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de_b.dwThreadId);
1609 else
1611 ok(de_b.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1612 "dwDebugEventCode differs: %x (was %x)\n", ctx.ev.dwDebugEventCode, de_b.dwDebugEventCode);
1613 ok(de_b.dwProcessId == ctx.ev.dwProcessId,
1614 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de_b.dwProcessId);
1615 ok(de_b.dwThreadId == ctx.ev.dwThreadId,
1616 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de_b.dwThreadId);
1618 next_event(&ctx, POLL_EVENT_TIMEOUT);
1619 if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
1621 ok(de_b.dwProcessId == ctx.ev.dwProcessId,
1622 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de_b.dwProcessId);
1623 ok(de_b.dwThreadId == ctx.ev.dwThreadId,
1624 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de_b.dwThreadId);
1626 ret = CloseHandle(thread_b);
1627 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1628 thread_b = NULL;
1630 next_event(&ctx, POLL_EVENT_TIMEOUT);
1633 ok(de_a.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1634 "dwDebugEventCode differs: %x (was %x)\n", ctx.ev.dwDebugEventCode, de_a.dwDebugEventCode);
1635 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1636 "dwProcessId differs: %x (was %x)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1637 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1638 "dwThreadId differs: %x (was %x)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1641 if (thread_a)
1643 next_event(&ctx, POLL_EVENT_TIMEOUT);
1644 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT,
1645 "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1647 ret = CloseHandle(thread_a);
1648 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1652 if (thread_b)
1654 next_event(&ctx, POLL_EVENT_TIMEOUT);
1655 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT,
1656 "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1658 ret = CloseHandle(thread_b);
1659 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1663 if (sizeof(loop_code) > 1)
1665 struct debuggee_thread *prev_thread;
1667 memset(buf, OP_BP, sizeof(buf));
1668 memcpy(proc_code, &loop_code, sizeof(loop_code));
1669 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
1670 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1672 ctx.thread_tag = 1;
1674 worker_cnt = 20;
1675 for (i = 0; i < worker_cnt; i++)
1677 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL);
1678 ok(thread != NULL, "CreateRemoteThread failed: %u\n", GetLastError());
1680 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1681 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1683 ret = CloseHandle(thread);
1684 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1687 byte = OP_BP;
1688 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
1689 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1691 expect_breakpoint_exception(&ctx, thread_proc + 1);
1692 exception_cnt = 1;
1694 prev_thread = ctx.current_thread;
1695 fetch_process_context(&ctx);
1697 byte = 0xc3; /* ret */
1698 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
1699 ok(ret, "WriteProcessMemory failed: %u\n", GetLastError());
1701 for (;;)
1703 DEBUG_EVENT ev;
1705 /* even when there are more pending events, they are not reported until current event is continued */
1706 ret = WaitForDebugEvent(&ev, 10);
1707 ok(GetLastError() == ERROR_SEM_TIMEOUT, "WaitForDebugEvent returned %x(%u)\n", ret, GetLastError());
1709 next_event(&ctx, POLL_EVENT_TIMEOUT);
1710 if (ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) break;
1711 trace("exception at %p in thread %04x\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress, ctx.ev.dwThreadId);
1712 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %x\n",
1713 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
1714 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == thread_proc + 1,
1715 "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress);
1716 ok(get_ip(&prev_thread->ctx) == thread_proc + 2
1717 || broken(get_ip(&prev_thread->ctx) == thread_proc), /* sometimes observed on win10 */
1718 "unexpected instruction pointer %p\n", get_ip(&prev_thread->ctx));
1719 prev_thread = ctx.current_thread;
1720 exception_cnt++;
1723 /* for some reason sometimes on Windows one thread has a different address. this is always the thread
1724 * with the last reported exception, so we simply skip the check for the last exception unless it's the only one. */
1725 if (exception_cnt == 1)
1726 ok(get_ip(&prev_thread->ctx) == thread_proc + 2, "unexpected instruction pointer %p\n", get_ip(&prev_thread->ctx));
1728 trace("received %u exceptions\n", exception_cnt);
1730 for (;;)
1732 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT
1733 || broken(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT), /* sometimes happens on vista */
1734 "dwDebugEventCode = %d\n", ctx.ev.dwDebugEventCode);
1735 if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT && !--worker_cnt) break;
1736 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1740 SetEvent(event);
1744 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1745 ok (ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "got exception\n");
1747 while (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1749 ret = CloseHandle(event);
1750 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1751 ret = CloseHandle(pi.hThread);
1752 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1753 ret = CloseHandle(pi.hProcess);
1754 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
1757 static DWORD run_child_wait( char *cmd, HANDLE event )
1759 PROCESS_INFORMATION pi;
1760 STARTUPINFOA si = { sizeof(si) };
1761 BOOL ret;
1762 DWORD exit_code;
1764 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
1765 ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
1766 Sleep(200);
1767 CloseHandle( pDbgUiGetThreadDebugObject() );
1768 pDbgUiSetThreadDebugObject( 0 );
1769 SetEvent( event );
1770 WaitForSingleObject( pi.hProcess, 1000 );
1771 ret = GetExitCodeProcess( pi.hProcess, &exit_code );
1772 ok( ret, "GetExitCodeProcess failed err=%d\n", GetLastError());
1773 CloseHandle( pi.hProcess );
1774 CloseHandle( pi.hThread );
1775 return exit_code;
1778 static PROCESS_INFORMATION pi;
1779 static char *cmd;
1781 static DWORD WINAPI debug_and_exit(void *arg)
1783 STARTUPINFOA si = { sizeof(si) };
1784 HANDLE debug;
1785 ULONG val = 0;
1786 NTSTATUS status;
1787 BOOL ret;
1789 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
1790 ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
1791 debug = pDbgUiGetThreadDebugObject();
1792 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1793 &val, sizeof(val), NULL );
1794 ok( !status, "NtSetInformationDebugObject failed %x\n", status );
1795 *(HANDLE *)arg = debug;
1796 Sleep(200);
1797 ExitThread(0);
1800 static DWORD WINAPI debug_and_wait(void *arg)
1802 STARTUPINFOA si = { sizeof(si) };
1803 HANDLE debug = *(HANDLE *)arg;
1804 ULONG val = 0;
1805 NTSTATUS status;
1806 BOOL ret;
1808 pDbgUiSetThreadDebugObject( debug );
1809 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
1810 ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
1811 debug = pDbgUiGetThreadDebugObject();
1812 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1813 &val, sizeof(val), NULL );
1814 ok( !status, "NtSetInformationDebugObject failed %x\n", status );
1815 Sleep(INFINITE);
1816 ExitThread(0);
1819 static DWORD WINAPI create_debug_port(void *arg)
1821 STARTUPINFOA si = { sizeof(si) };
1822 NTSTATUS status = pDbgUiConnectToDbg();
1824 ok( !status, "DbgUiConnectToDbg failed %x\n", status );
1825 *(HANDLE *)arg = pDbgUiGetThreadDebugObject();
1826 Sleep( INFINITE );
1827 ExitThread(0);
1830 static void test_kill_on_exit(const char *argv0)
1832 static const char arguments[] = " debugger wait ";
1833 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
1834 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
1835 NTSTATUS status;
1836 HANDLE event, debug, thread;
1837 DWORD exit_code, tid;
1838 ULONG val;
1840 event = CreateEventW(&sa, FALSE, FALSE, NULL);
1841 ok(event != NULL, "CreateEvent failed: %u\n", GetLastError());
1843 cmd = heap_alloc(strlen(argv0) + strlen(arguments) + 16);
1844 sprintf(cmd, "%s%s%x\n", argv0, arguments, (DWORD)(DWORD_PTR)event);
1846 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 );
1847 ok( !status, "NtCreateDebugObject failed %x\n", status );
1848 pDbgUiSetThreadDebugObject( debug );
1849 exit_code = run_child_wait( cmd, event );
1850 ok( exit_code == 0, "exit code = %08x\n", exit_code);
1852 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
1853 ok( !status, "NtCreateDebugObject failed %x\n", status );
1854 pDbgUiSetThreadDebugObject( debug );
1855 exit_code = run_child_wait( cmd, event );
1856 ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code);
1858 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0xfffe );
1859 ok( status == STATUS_INVALID_PARAMETER, "NtCreateDebugObject failed %x\n", status );
1861 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 );
1862 ok( !status, "NtCreateDebugObject failed %x\n", status );
1863 pDbgUiSetThreadDebugObject( debug );
1864 val = DEBUG_KILL_ON_CLOSE;
1865 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1866 &val, sizeof(val), NULL );
1867 ok( !status, "NtSetInformationDebugObject failed %x\n", status );
1868 exit_code = run_child_wait( cmd, event );
1869 ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code);
1871 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
1872 ok( !status, "NtCreateDebugObject failed %x\n", status );
1873 pDbgUiSetThreadDebugObject( debug );
1874 val = 0;
1875 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1876 &val, sizeof(val), NULL );
1877 ok( !status, "NtSetInformationDebugObject failed %x\n", status );
1878 exit_code = run_child_wait( cmd, event );
1879 ok( exit_code == 0, "exit code = %08x\n", exit_code);
1881 status = pDbgUiConnectToDbg();
1882 ok( !status, "DbgUiConnectToDbg failed %x\n", status );
1883 exit_code = run_child_wait( cmd, event );
1884 ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code);
1886 /* test that threads close the debug port on exit */
1887 thread = CreateThread(NULL, 0, debug_and_exit, &debug, 0, &tid);
1888 WaitForSingleObject( thread, 1000 );
1889 ok( debug != 0, "no debug port\n" );
1890 val = 0;
1891 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1892 &val, sizeof(val), NULL );
1893 ok( status == STATUS_INVALID_HANDLE || broken(status == STATUS_SUCCESS), /* wow64 */
1894 "NtSetInformationDebugObject failed %x\n", status );
1895 SetEvent( event );
1896 if (!status)
1898 WaitForSingleObject( pi.hProcess, 100 );
1899 GetExitCodeProcess( pi.hProcess, &exit_code );
1900 ok( exit_code == STILL_ACTIVE, "exit code = %08x\n", exit_code);
1901 CloseHandle( debug );
1903 WaitForSingleObject( pi.hProcess, 1000 );
1904 GetExitCodeProcess( pi.hProcess, &exit_code );
1905 ok( exit_code == 0, "exit code = %08x\n", exit_code);
1906 CloseHandle( pi.hProcess );
1907 CloseHandle( pi.hThread );
1908 CloseHandle( thread );
1910 /* but not on forced exit */
1911 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
1912 ok( !status, "NtCreateDebugObject failed %x\n", status );
1913 thread = CreateThread(NULL, 0, debug_and_wait, &debug, 0, &tid);
1914 Sleep( 100 );
1915 ok( debug != 0, "no debug port\n" );
1916 val = 1;
1917 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1918 &val, sizeof(val), NULL );
1919 ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status );
1920 TerminateThread( thread, 0 );
1921 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1922 &val, sizeof(val), NULL );
1923 ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status );
1924 WaitForSingleObject( pi.hProcess, 300 );
1925 GetExitCodeProcess( pi.hProcess, &exit_code );
1926 todo_wine
1927 ok( exit_code == STATUS_DEBUGGER_INACTIVE || broken(exit_code == STILL_ACTIVE), /* wow64 */
1928 "exit code = %08x\n", exit_code);
1929 CloseHandle( pi.hProcess );
1930 CloseHandle( pi.hThread );
1931 CloseHandle( thread );
1932 CloseHandle( debug );
1934 debug = 0;
1935 thread = CreateThread(NULL, 0, create_debug_port, &debug, 0, &tid);
1936 Sleep(100);
1937 ok( debug != 0, "no debug port\n" );
1938 val = 0;
1939 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1940 &val, sizeof(val), NULL );
1941 ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status );
1942 TerminateThread( thread, 0 );
1943 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
1944 &val, sizeof(val), NULL );
1945 ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %x\n", status );
1946 CloseHandle( debug );
1947 CloseHandle( thread );
1949 CloseHandle( event );
1950 heap_free(cmd);
1953 START_TEST(debugger)
1955 HMODULE hdll;
1957 hdll=GetModuleHandleA("kernel32.dll");
1958 pCheckRemoteDebuggerPresent=(void*)GetProcAddress(hdll, "CheckRemoteDebuggerPresent");
1959 pGetMappedFileNameW = (void*)GetProcAddress(hdll, "GetMappedFileNameW");
1960 if (!pGetMappedFileNameW) pGetMappedFileNameW = (void*)GetProcAddress(LoadLibraryA("psapi.dll"),
1961 "GetMappedFileNameW");
1962 ntdll = GetModuleHandleA("ntdll.dll");
1963 pDbgBreakPoint = (void*)GetProcAddress(ntdll, "DbgBreakPoint");
1964 pNtSuspendProcess = (void*)GetProcAddress(ntdll, "NtSuspendProcess");
1965 pNtResumeProcess = (void*)GetProcAddress(ntdll, "NtResumeProcess");
1966 pNtCreateDebugObject = (void*)GetProcAddress(ntdll, "NtCreateDebugObject");
1967 pNtSetInformationDebugObject = (void*)GetProcAddress(ntdll, "NtSetInformationDebugObject");
1968 pDbgUiConnectToDbg = (void*)GetProcAddress(ntdll, "DbgUiConnectToDbg");
1969 pDbgUiGetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiGetThreadDebugObject");
1970 pDbgUiSetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiSetThreadDebugObject");
1972 myARGC=winetest_get_mainargs(&myARGV);
1973 if (myARGC >= 3 && strcmp(myARGV[2], "crash") == 0)
1975 doCrash();
1977 else if (myARGC >= 3 && strncmp(myARGV[2], "dbg,", 4) == 0)
1979 doDebugger(myARGC, myARGV);
1981 else if (myARGC >= 5 && !strcmp(myARGV[2], "child"))
1983 doChild(myARGC, myARGV);
1985 else if (myARGC >= 4 && !strcmp(myARGV[2], "children"))
1987 doChildren(myARGC, myARGV);
1989 else if (myARGC >= 4 && !strcmp(myARGV[2], "wait"))
1991 DWORD event;
1992 sscanf(myARGV[3], "%x", &event);
1993 wait_debugger((HANDLE)(DWORD_PTR)event);
1995 else
1997 test_ExitCode();
1998 test_RemoteDebugger();
1999 test_debug_loop(myARGC, myARGV);
2000 test_debug_children(myARGV[0], DEBUG_PROCESS, TRUE, FALSE);
2001 test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE);
2002 test_debug_children(myARGV[0], DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE);
2003 test_debug_children(myARGV[0], 0, FALSE, FALSE);
2004 test_debug_children(myARGV[0], 0, FALSE, TRUE);
2005 test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, TRUE);
2006 test_debugger(myARGV[0]);
2007 test_kill_on_exit(myARGV[0]);