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
25 #define WIN32_NO_STATUS
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)
37 #define child_ok (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_child_ok
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
;
59 static void WINAPIV
__WINE_PRINTF_ATTR(2, 3) test_child_ok(int condition
, const char *msg
, ...)
63 __ms_va_start(valist
, msg
);
64 winetest_vok(condition
, msg
, valist
);
66 if (!condition
) ++child_failures
;
69 /* Copied from the process test */
70 static void get_file_name(char* buf
)
75 GetTempPathA(sizeof(path
), path
);
76 GetTempFileNameA(path
, "wt", 0, buf
);
79 typedef struct tag_reg_save_value
87 static DWORD
save_value(HKEY hkey
, const char *value
, reg_save_value
*saved
)
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
);
102 static void restore_value(HKEY hkey
, reg_save_value
*saved
)
106 RegSetValueExA(hkey
, saved
->name
, 0, saved
->type
, saved
->data
, saved
->size
);
107 HeapFree(GetProcessHeap(), 0, saved
->data
);
110 RegDeleteValueA(hkey
, saved
->name
);
113 static void get_events(const char* name
, HANDLE
*start_event
, HANDLE
*done_event
)
115 const char* basename
;
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
)
134 hFile
=CreateFileA(logfile
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
135 if (hFile
== INVALID_HANDLE_VALUE
)
137 WriteFile(hFile
, blackbox
, size
, &written
, NULL
);
138 if (dbgtrace
&& dbgtrace
[0])
139 WriteFile(hFile
, dbgtrace
, strlen(dbgtrace
), &written
, NULL
);
143 static int load_blackbox(const char* logfile
, void* blackbox
, int size
)
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
);
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
);
164 trace("debugger traces:\n%s", buf
);
170 static DWORD WINAPI
thread_proc(void *arg
)
177 static void run_background_thread(void)
180 HANDLE thread
= CreateThread(NULL
, 0, thread_proc
, NULL
, 0, &tid
);
181 ok(thread
!= NULL
, "CreateThread failed\n");
185 static void doCrash(void)
189 /* make sure the exception gets to the debugger */
191 SetUnhandledExceptionFilter( NULL
);
193 run_background_thread();
196 trace("child: crashing...\n");
214 } debugger_blackbox_t
;
216 struct debugger_context
220 unsigned process_cnt
;
225 struct wine_rb_tree threads
;
226 struct debuggee_thread
*current_thread
;
227 struct debuggee_thread
*main_thread
;
230 struct debuggee_thread
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
));
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
);
273 static void *get_ip(const CONTEXT
*ctx
)
276 return (void *)ctx
->Eip
;
277 #elif defined(__x86_64__)
278 return (void *)ctx
->Rip
;
284 #define fetch_thread_context(a) fetch_thread_context_(__LINE__,a)
285 static void fetch_thread_context_(unsigned line
, struct debuggee_thread
*thread
)
291 thread
->handle
= OpenThread(THREAD_GET_CONTEXT
| THREAD_SET_CONTEXT
| THREAD_QUERY_INFORMATION
,
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
)
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
)
328 ctx
->current_thread
= NULL
;
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
);
341 ok_(__FILE__
,line
)(GetLastError() == ERROR_SEM_TIMEOUT
,
342 "WaitForDebugEvent failed, last error %d.\n", GetLastError());
343 ctx
->ev
.dwDebugEventCode
= -1;
347 if (ctx
->ev
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
)
349 if (!ctx
->process_cnt
) ctx
->pid
= ctx
->ev
.dwProcessId
;
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
;
365 case EXIT_PROCESS_DEBUG_EVENT
:
366 remove_thread(ctx
, ctx
->ev
.dwThreadId
);
368 case CREATE_THREAD_DEBUG_EVENT
:
369 add_thread(ctx
, ctx
->ev
.dwThreadId
);
371 case EXIT_THREAD_DEBUG_EVENT
:
372 remove_thread(ctx
, ctx
->ev
.dwThreadId
);
374 case LOAD_DLL_DEBUG_EVENT
:
375 ok(ctx
->ev
.u
.LoadDll
.lpBaseOfDll
!= ctx
->image_base
, "process image reported as DLL load event\n");
378 case UNLOAD_DLL_DEBUG_EVENT
:
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
)
403 ctx
->ev
.dwDebugEventCode
= -1;
405 ok(ctx
->ev
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
, "dwDebugEventCode = %d\n", ctx
->ev
.dwDebugEventCode
);
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");
415 while (ctx
->ev
.dwDebugEventCode
== CREATE_THREAD_DEBUG_EVENT
)
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");
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
)
461 debugger_blackbox_t blackbox
;
462 HANDLE start_event
= 0, done_event
= 0, debug_event
;
464 struct debugger_context ctx
= { 0 };
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();
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();
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
);
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();
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();
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");
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
;
563 HANDLE start_event
, done_event
;
565 char dbglog
[MAX_PATH
];
566 PROCESS_INFORMATION info
;
567 STARTUPINFOA startup
;
569 debugger_blackbox_t dbg_blackbox
;
572 if (skip_crash_and_debug
)
574 win_skip("Skipping crash_and_debug\n");
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");
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
);
621 win_skip("Giving up on child process\n");
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
);
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
)
656 win_skip("Giving up on debugger\n");
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
);
675 static void crash_and_winedbg(HKEY hkey
, const char* argv0
)
680 PROCESS_INFORMATION info
;
681 STARTUPINFOA startup
;
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
];
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
);
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");
739 else if (ret
!= ERROR_FILE_NOT_FOUND
)
741 ok(0, "could not open the AeDebug key: %d\n", ret
);
744 else debugger_value
.data
= NULL
;
746 if (debugger_value
.data
&& debugger_value
.type
== REG_SZ
&&
747 strstr((char*)debugger_value
.data
, "winedbg --auto"))
750 ret
=RegCreateKeyA(HKEY_CURRENT_USER
, WineDbg
, &hkeyWinedbg
);
751 if (ret
== ERROR_SUCCESS
)
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
);
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");
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
)
785 RegDeleteKeyA(HKEY_LOCAL_MACHINE
, AeDebug
);
789 restore_value(hkey
, &auto_value
);
790 restore_value(hkey
, &debugger_value
);
795 static void test_RemoteDebugger(void)
798 if(!pCheckRemoteDebuggerPresent
)
800 win_skip("CheckRemoteDebuggerPresent is not available\n");
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());
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
830 static void doChild(int argc
, char **argv
)
832 struct child_blackbox blackbox
;
833 const char *blackbox_file
;
834 WCHAR path
[MAX_PATH
];
836 HANDLE parent
, file
, map
;
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" );
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() );
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
:
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
++;
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
;
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;
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
;
939 if (!pCheckRemoteDebuggerPresent
)
941 win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n");
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
));
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
);
968 ret
= WaitForDebugEvent(&ev
, INFINITE
);
969 ok(ret
, "WaitForDebugEvent failed, last error %#x.\n", GetLastError());
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
)
979 NtReadVirtualMemory(pi
.hProcess
, ev
.u
.Exception
.ExceptionRecord
.ExceptionAddress
, &byte
, 1, NULL
);
980 ok(byte
== 0xcc, "got %02x\n", byte
);
983 ret
= ContinueDebugEvent(ev
.dwProcessId
, ev
.dwThreadId
, DBG_CONTINUE
);
984 ok(ret
, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
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
;
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());
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
);
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
));
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
;
1069 HANDLE event_init
, event_attach
;
1072 struct debugger_context ctx
= { 0 };
1074 if (!pCheckRemoteDebuggerPresent
)
1076 win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n");
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
));
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
);
1106 WaitForSingleObject(event_init
, INFINITE
);
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");
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
;
1148 ok(ctx
.ev
.u
.Exception
.ExceptionRecord
.ExceptionAddress
!= pDbgBreakPoint
, "ExceptionAddress == pDbgBreakPoint\n");
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
);
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());
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());
1205 ok(ctx
.process_cnt
== 2, "didn't get any child events (flag: %x).\n", flag
);
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
);
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
);
1276 static const BYTE loop_code
[] = {
1277 #if defined(__i386__) || defined(__x86_64__)
1281 0xe9, 0xf8, 0xff, 0xff, 0xff /* jmp $-8 */
1285 static const BYTE call_debug_service_code
[] = {
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,
1302 0x31, 0xc0, /* xorl %eax,%eax */
1303 0x40, /* incl %eax */
1304 0x5f, /* popl %edi */
1305 0x5b, /* popl %ebx */
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 */
1330 #if defined(__i386__) || defined(__x86_64__)
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
;
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
;
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
));
1359 ret
= CreateProcessA(NULL
, cmd
, NULL
, NULL
, TRUE
, DEBUG_PROCESS
, NULL
, NULL
, &si
, &pi
);
1360 ok(ret
, "CreateProcess failed, last error %#x.\n", GetLastError());
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");
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
);
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());
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
);
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
);
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
);
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());
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());
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
);
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());
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
);
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());
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());
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());
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);
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());
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
;
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
);
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
);
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
) };
1764 ret
= CreateProcessA(NULL
, cmd
, NULL
, NULL
, TRUE
, DEBUG_PROCESS
, NULL
, NULL
, &si
, &pi
);
1765 ok(ret
, "CreateProcess failed, last error %#x.\n", GetLastError());
1767 CloseHandle( pDbgUiGetThreadDebugObject() );
1768 pDbgUiSetThreadDebugObject( 0 );
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
);
1778 static PROCESS_INFORMATION pi
;
1781 static DWORD WINAPI
debug_and_exit(void *arg
)
1783 STARTUPINFOA si
= { sizeof(si
) };
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
;
1800 static DWORD WINAPI
debug_and_wait(void *arg
)
1802 STARTUPINFOA si
= { sizeof(si
) };
1803 HANDLE debug
= *(HANDLE
*)arg
;
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
);
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();
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
) };
1836 HANDLE event
, debug
, thread
;
1837 DWORD exit_code
, tid
;
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
);
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" );
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
);
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
);
1915 ok( debug
!= 0, "no debug port\n" );
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
);
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
);
1935 thread
= CreateThread(NULL
, 0, create_debug_port
, &debug
, 0, &tid
);
1937 ok( debug
!= 0, "no debug port\n" );
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
);
1953 START_TEST(debugger
)
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)
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"))
1992 sscanf(myARGV
[3], "%x", &event
);
1993 wait_debugger((HANDLE
)(DWORD_PTR
)event
);
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]);