Reactos
1/*
2 * Unit tests for the debugger facility
3 *
4 * Copyright (c) 2007 Francois Gouget for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21#include <stdio.h>
22#include <assert.h>
23
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"
32
33#ifndef STATUS_DEBUGGER_INACTIVE
34#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354)
35#endif
36
37#define child_ok (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_child_ok
38
39static int myARGC;
40static char** myARGV;
41static BOOL is_wow64;
42
43static BOOL (WINAPI *pCheckRemoteDebuggerPresent)(HANDLE,PBOOL);
44
45static void (WINAPI *pDbgBreakPoint)(void);
46
47static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process);
48static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process);
49static NTSTATUS (WINAPI *pNtCreateDebugObject)(HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG);
50static NTSTATUS (WINAPI *pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,void *,ULONG,ULONG*);
51static NTSTATUS (WINAPI *pDbgUiConnectToDbg)(void);
52static HANDLE (WINAPI *pDbgUiGetThreadDebugObject)(void);
53static void (WINAPI *pDbgUiSetThreadDebugObject)(HANDLE);
54static DWORD (WINAPI *pGetMappedFileNameW)(HANDLE,void*,WCHAR*,DWORD);
55static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
56
57static LONG child_failures;
58
59static HMODULE ntdll;
60
61static void WINAPIV __WINE_PRINTF_ATTR(2, 3) test_child_ok(int condition, const char *msg, ...)
62{
63 va_list valist;
64
65 va_start(valist, msg);
66 winetest_vok(condition, msg, valist);
67 va_end(valist);
68 if (!condition) ++child_failures;
69}
70
71/* Copied from the process test */
72static void get_file_name(char* buf)
73{
74 char path[MAX_PATH];
75
76 buf[0] = '\0';
77 GetTempPathA(sizeof(path), path);
78 GetTempFileNameA(path, "wt", 0, buf);
79}
80
81typedef struct tag_reg_save_value
82{
83 const char *name;
84 DWORD type;
85 BYTE *data;
86 DWORD size;
87} reg_save_value;
88
89static DWORD save_value(HKEY hkey, const char *value, reg_save_value *saved)
90{
91 DWORD ret;
92 saved->name=value;
93 saved->data=0;
94 saved->size=0;
95 ret=RegQueryValueExA(hkey, value, NULL, &saved->type, NULL, &saved->size);
96 if (ret == ERROR_SUCCESS)
97 {
98 saved->data=HeapAlloc(GetProcessHeap(), 0, saved->size);
99 RegQueryValueExA(hkey, value, NULL, &saved->type, saved->data, &saved->size);
100 }
101 return ret;
102}
103
104static void restore_value(HKEY hkey, reg_save_value *saved)
105{
106 if (saved->data)
107 {
108 RegSetValueExA(hkey, saved->name, 0, saved->type, saved->data, saved->size);
109 HeapFree(GetProcessHeap(), 0, saved->data);
110 }
111 else
112 RegDeleteValueA(hkey, saved->name);
113}
114
115static void get_events(const char* name, HANDLE *start_event, HANDLE *done_event)
116{
117 const char* basename;
118 char* event_name;
119
120 basename=strrchr(name, '\\');
121 basename=(basename ? basename+1 : name);
122 event_name=HeapAlloc(GetProcessHeap(), 0, 6+strlen(basename)+1);
123
124 sprintf(event_name, "start_%s", basename);
125 *start_event=CreateEventA(NULL, 0,0, event_name);
126 sprintf(event_name, "done_%s", basename);
127 *done_event=CreateEventA(NULL, 0,0, event_name);
128 HeapFree(GetProcessHeap(), 0, event_name);
129}
130
131static void save_blackbox(const char* logfile, void* blackbox, int size, const char *dbgtrace)
132{
133 HANDLE hFile;
134 DWORD written;
135 BOOL ret;
136
137 hFile = CreateFileA(logfile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0);
138 ok(hFile != INVALID_HANDLE_VALUE, "Couldn't create %s: %lu\n", logfile, GetLastError());
139 if (hFile == INVALID_HANDLE_VALUE)
140 return;
141 ret = WriteFile(hFile, blackbox, size, &written, NULL);
142 ok(ret && written == size, "Error writing\n");
143 if (dbgtrace && dbgtrace[0])
144 {
145 ret = WriteFile(hFile, dbgtrace, strlen(dbgtrace), &written, NULL);
146 ok(ret && written == strlen(dbgtrace), "Error writing\n");
147 }
148 CloseHandle(hFile);
149}
150
151#define load_blackbox(a, b, c) _load_blackbox(__LINE__, (a), (b), (c))
152static int _load_blackbox(unsigned int line, const char* logfile, void* blackbox, int size)
153{
154 HANDLE hFile;
155 DWORD read;
156 BOOL ret;
157 char buf[4096];
158
159 hFile = CreateFileA(logfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
160 if (hFile == INVALID_HANDLE_VALUE)
161 {
162 ok_(__FILE__, line)(0, "unable to open '%s': %#lx\n", logfile, GetLastError());
163 return 0;
164 }
165 SetLastError(0xdeadbeef);
166 ret = ReadFile(hFile, blackbox, size, &read, NULL);
167 ok(ret, "ReadFile failed: %ld\n", GetLastError());
168#ifdef __REACTOS__
169 ok(read == size || broken(read == 0) /* WS03 */, "wrong size for '%s': read=%ld\n", logfile, read);
170#else
171 ok(read == size, "wrong size for '%s': read=%ld\n", logfile, read);
172#endif
173 ret = ReadFile(hFile, buf, sizeof(buf) - 1, &read, NULL);
174 if (ret && read)
175 {
176 buf[read] = 0;
177 trace("debugger traces:>>>\n%s\n<<< Done.\n", buf);
178 }
179 CloseHandle(hFile);
180 return 1;
181}
182
183static DWORD WINAPI thread_proc(void *arg)
184{
185 Sleep(10000);
186 trace("exiting\n");
187 ExitThread(1);
188}
189
190static void run_background_thread(void)
191{
192 DWORD tid;
193 HANDLE thread = CreateThread(NULL, 0, thread_proc, NULL, 0, &tid);
194 ok(thread != NULL, "CreateThread failed\n");
195 CloseHandle(thread);
196}
197
198static void doCrash(void)
199{
200 volatile char* p;
201
202 /* make sure the exception gets to the debugger */
203 SetErrorMode( 0 );
204 SetUnhandledExceptionFilter( NULL );
205
206 run_background_thread();
207
208 /* Just crash */
209 trace("child: crashing...\n");
210 p=NULL;
211 *p=0;
212}
213
214typedef struct
215{
216 int argc;
217 DWORD pid;
218 BOOL debug_rc;
219 DWORD debug_err;
220 BOOL attach_rc;
221 DWORD attach_err;
222 BOOL nokill_rc;
223 DWORD nokill_err;
224 BOOL detach_rc;
225 DWORD detach_err;
226 DWORD failures;
227} debugger_blackbox_t;
228
229struct debugger_context
230{
231 DWORD pid;
232 DEBUG_EVENT ev;
233 unsigned process_cnt;
234 unsigned dll_cnt;
235 void *image_base;
236 DWORD thread_tag;
237 unsigned thread_cnt;
238 struct wine_rb_tree threads;
239 struct debuggee_thread *current_thread;
240 struct debuggee_thread *main_thread;
241};
242
243struct debuggee_thread
244{
245 DWORD tid;
246 DWORD tag;
247 HANDLE handle;
248 CONTEXT ctx;
249 struct wine_rb_entry entry;
250};
251
252int debuggee_thread_compare(const void *key, const struct wine_rb_entry *entry)
253{
254 struct debuggee_thread *thread = WINE_RB_ENTRY_VALUE(entry, struct debuggee_thread, entry);
255 return memcmp(key, &thread->tid, sizeof(thread->tid));
256}
257
258static void add_thread(struct debugger_context *ctx, DWORD tid)
259{
260 struct debuggee_thread *thread;
261 if (!ctx->thread_cnt++) wine_rb_init(&ctx->threads, debuggee_thread_compare);
262 thread = heap_alloc(sizeof(*thread));
263 thread->tid = tid;
264 thread->tag = ctx->thread_tag;
265 thread->handle = NULL;
266 wine_rb_put(&ctx->threads, &tid, &thread->entry);
267 if (!ctx->main_thread) ctx->main_thread = thread;
268}
269
270static struct debuggee_thread *get_debuggee_thread(struct debugger_context *ctx, DWORD tid)
271{
272 struct wine_rb_entry *entry = wine_rb_get(&ctx->threads, &tid);
273 ok(entry != NULL, "unknown thread %lx\n", tid);
274 return WINE_RB_ENTRY_VALUE(entry, struct debuggee_thread, entry);
275}
276
277static void remove_thread(struct debugger_context *ctx, DWORD tid)
278{
279 struct debuggee_thread *thread = get_debuggee_thread(ctx, tid);
280
281 wine_rb_remove(&ctx->threads, &thread->entry);
282 if (thread->handle) CloseHandle(thread->handle);
283 heap_free(thread);
284}
285
286static void *get_ip(const CONTEXT *ctx)
287{
288#ifdef __i386__
289 return (void *)ctx->Eip;
290#elif defined(__x86_64__)
291 return (void *)ctx->Rip;
292#else
293 return NULL;
294#endif
295}
296
297static void set_ip(CONTEXT *ctx, void *ip)
298{
299#ifdef __i386__
300 ctx->Eip = (DWORD_PTR)ip;
301#elif defined(__x86_64__)
302 ctx->Rip = (DWORD_PTR)ip;
303#endif
304}
305
306#define fetch_thread_context(a) fetch_thread_context_(__LINE__,a)
307static void fetch_thread_context_(unsigned line, struct debuggee_thread *thread)
308{
309 BOOL ret;
310
311 if (!thread->handle)
312 {
313 thread->handle = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION,
314 FALSE, thread->tid);
315 ok_(__FILE__,line)(thread->handle != NULL, "OpenThread failed: %lu\n", GetLastError());
316 }
317
318 memset(&thread->ctx, 0xaa, sizeof(thread->ctx));
319 thread->ctx.ContextFlags = CONTEXT_FULL;
320 ret = GetThreadContext(thread->handle, &thread->ctx);
321 ok_(__FILE__,line)(ret, "GetThreadContext failed: %lu\n", GetLastError());
322}
323
324#define set_thread_context(a,b) set_thread_context_(__LINE__,a,b)
325static void set_thread_context_(unsigned line, struct debugger_context *ctx, struct debuggee_thread *thread)
326{
327 BOOL ret;
328 ret = SetThreadContext(thread->handle, &thread->ctx);
329 ok_(__FILE__,line)(ret, "SetThreadContext failed: %lu\n", GetLastError());
330}
331
332#define WAIT_EVENT_TIMEOUT 20000
333#define POLL_EVENT_TIMEOUT 200
334
335#define next_event(a,b) next_event_(__LINE__,a,b)
336static void next_event_(unsigned line, struct debugger_context *ctx, unsigned timeout)
337{
338 BOOL ret;
339
340 ctx->current_thread = NULL;
341
342 for (;;)
343 {
344 if (ctx->process_cnt && ctx->ev.dwDebugEventCode != -1)
345 {
346 ret = ContinueDebugEvent(ctx->ev.dwProcessId, ctx->ev.dwThreadId, DBG_CONTINUE);
347 ok_(__FILE__,line)(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError());
348 }
349
350 ret = WaitForDebugEvent(&ctx->ev, timeout);
351 if (!ret)
352 {
353 ok_(__FILE__,line)(GetLastError() == ERROR_SEM_TIMEOUT,
354 "WaitForDebugEvent failed, last error %ld.\n", GetLastError());
355 ctx->ev.dwDebugEventCode = -1;
356 return;
357 }
358
359 if (ctx->ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
360 {
361 if (!ctx->process_cnt) ctx->pid = ctx->ev.dwProcessId;
362 ctx->process_cnt++;
363 }
364
365 if (ctx->ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) continue; /* ignore for now */
366 if (ctx->ev.dwProcessId == ctx->pid) break;
367
368 ok_(__FILE__,line)(ctx->process_cnt > 1, "unexpected event pid\n");
369 }
370
371 switch (ctx->ev.dwDebugEventCode)
372 {
373 case CREATE_PROCESS_DEBUG_EVENT:
374 add_thread(ctx, ctx->ev.dwThreadId);
375 ctx->image_base = ctx->ev.u.CreateProcessInfo.lpBaseOfImage;
376 break;
377 case EXIT_PROCESS_DEBUG_EVENT:
378 remove_thread(ctx, ctx->ev.dwThreadId);
379 return;
380 case CREATE_THREAD_DEBUG_EVENT:
381 add_thread(ctx, ctx->ev.dwThreadId);
382 break;
383 case EXIT_THREAD_DEBUG_EVENT:
384 remove_thread(ctx, ctx->ev.dwThreadId);
385 return;
386 case LOAD_DLL_DEBUG_EVENT:
387 ok(ctx->ev.u.LoadDll.lpBaseOfDll != ctx->image_base, "process image reported as DLL load event\n");
388 ctx->dll_cnt++;
389 break;
390 case UNLOAD_DLL_DEBUG_EVENT:
391 ctx->dll_cnt--;
392 break;
393 }
394
395 ctx->current_thread = get_debuggee_thread(ctx, ctx->ev.dwThreadId);
396}
397
398static DWORD event_mask(DWORD ev)
399{
400 return (ev >= 1 && ev <= 7) ? (1LU << ev) : 0;
401}
402
403#define next_event_filter(a, b,c) next_event_filter_(__LINE__, (a), (b), (c))
404static void next_event_filter_(unsigned line, struct debugger_context *ctx, DWORD timeout, DWORD mask)
405{
406 do
407 {
408 next_event_(line, ctx, timeout);
409 } while (event_mask(ctx->ev.dwDebugEventCode) & mask);
410}
411
412#define wait_for_breakpoint(a) wait_for_breakpoint_(__LINE__,a)
413static void wait_for_breakpoint_(unsigned line, struct debugger_context *ctx)
414{
415 next_event_filter_(line, ctx, WAIT_EVENT_TIMEOUT,
416 event_mask(LOAD_DLL_DEBUG_EVENT) | event_mask(UNLOAD_DLL_DEBUG_EVENT) | event_mask(CREATE_THREAD_DEBUG_EVENT));
417
418 ok_(__FILE__,line)(ctx->ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode);
419 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n",
420 ctx->ev.u.Exception.ExceptionRecord.ExceptionCode);
421}
422
423#define check_thread_running(h) ok(_check_thread_suspend_count(h) == 0, "Expecting running thread\n")
424#define check_thread_suspended(h) ok(_check_thread_suspend_count(h) > 0, "Expecting suspended thread\n")
425
426static LONG _check_thread_suspend_count(HANDLE h)
427{
428 DWORD suspend_count;
429
430 suspend_count = SuspendThread(h);
431 if (suspend_count != (DWORD)-1 && ResumeThread(h) == (DWORD)-1)
432 return (DWORD)-2;
433 return suspend_count;
434}
435
436static void process_attach_events(struct debugger_context *ctx, BOOL pass_exception)
437{
438 DEBUG_EVENT ev;
439 BOOL ret;
440 HANDLE prev_thread;
441
442 ctx->ev.dwDebugEventCode = -1;
443 next_event(ctx, 0);
444 ok(ctx->ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode);
445
446 todo_wine
447 check_thread_suspended(ctx->ev.u.CreateProcessInfo.hThread);
448 prev_thread = ctx->ev.u.CreateProcessInfo.hThread;
449 next_event(ctx, 0);
450
451 if (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) /* Vista+ reports ntdll.dll before reporting threads */
452 {
453 ok(ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode);
454 ok(ctx->ev.u.LoadDll.lpBaseOfDll == ntdll, "The first reported DLL is not ntdll.dll\n");
455 next_event(ctx, 0);
456 }
457
458 while (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
459 {
460 todo_wine
461 check_thread_suspended(ctx->ev.u.CreateThread.hThread);
462 check_thread_running(prev_thread);
463 prev_thread = ctx->ev.u.CreateThread.hThread;
464 next_event(ctx, 0);
465 }
466
467 do
468 {
469 /* even when there are more pending events, they are not reported until current event is continued */
470 ret = WaitForDebugEvent(&ev, 10);
471 ok(GetLastError() == ERROR_SEM_TIMEOUT, "WaitForDebugEvent returned %x(%lu)\n", ret, GetLastError());
472
473 next_event(ctx, WAIT_EVENT_TIMEOUT);
474 if (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT)
475 ok(ctx->ev.u.LoadDll.lpBaseOfDll != ntdll, "ntdll.dll reported out of order\n");
476 } while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT);
477 ok(ctx->dll_cnt > 2, "dll_cnt = %d\n", ctx->dll_cnt);
478
479 /* a new thread is created and it executes DbgBreakPoint, which causes the exception */
480 /* Win11 doesn't generate it at this point (Win <= 10 do) */
481 if (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
482 {
483 DWORD last_threads[5];
484 unsigned thd_idx = 0, i;
485
486 check_thread_running(prev_thread);
487
488 /* sometimes (at least Win10) several thread creations are reported here */
489 do
490 {
491 check_thread_running(ctx->ev.u.CreateThread.hThread);
492 if (thd_idx < ARRAY_SIZE(last_threads))
493 last_threads[thd_idx++] = ctx->ev.dwThreadId;
494 next_event(ctx, WAIT_EVENT_TIMEOUT);
495 } while (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT);
496 ok(thd_idx <= ARRAY_SIZE(last_threads), "too many threads created\n");
497 for (i = 0; i < thd_idx; i++)
498 if (last_threads[i] == ctx->ev.dwThreadId) break;
499 ok(i < thd_idx, "unexpected thread\n");
500
501 ok(ctx->ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode);
502 ok(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n",
503 ctx->ev.u.Exception.ExceptionRecord.ExceptionCode);
504 ok(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint, "ExceptionAddress != DbgBreakPoint\n");
505
506 if (pass_exception)
507 {
508 ret = ContinueDebugEvent(ctx->ev.dwProcessId, ctx->ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
509 ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError());
510 ctx->ev.dwDebugEventCode = -1;
511 }
512 }
513
514 /* flush debug events */
515 do next_event(ctx, POLL_EVENT_TIMEOUT);
516 while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT
517 || ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || ctx->ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT);
518 ok(ctx->ev.dwDebugEventCode == -1, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode);
519}
520
521static void doDebugger(int argc, char** argv)
522{
523 const char* logfile;
524 debugger_blackbox_t blackbox;
525 HANDLE start_event = 0, done_event = 0, debug_event;
526 char buf[4096] = "";
527 struct debugger_context ctx = { 0 };
528
529 blackbox.argc=argc;
530 logfile=(argc >= 4 ? argv[3] : NULL);
531 blackbox.pid=(argc >= 5 ? atol(argv[4]) : 0);
532
533 blackbox.attach_err=0;
534 if (strstr(myARGV[2], "attach"))
535 {
536 blackbox.attach_rc=DebugActiveProcess(blackbox.pid);
537 if (!blackbox.attach_rc)
538 blackbox.attach_err=GetLastError();
539 }
540 else
541 blackbox.attach_rc=TRUE;
542
543 if (strstr(myARGV[2], "process"))
544 {
545 strcat(buf, "processing debug messages\n");
546 process_attach_events(&ctx, FALSE);
547 }
548
549 debug_event=(argc >= 6 ? (HANDLE)(INT_PTR)atol(argv[5]) : NULL);
550 blackbox.debug_err=0;
551 if (debug_event && strstr(myARGV[2], "event"))
552 {
553 strcat(buf, "setting event\n");
554 blackbox.debug_rc=SetEvent(debug_event);
555 if (!blackbox.debug_rc)
556 blackbox.debug_err=GetLastError();
557 }
558 else
559 blackbox.debug_rc=TRUE;
560
561 if (strstr(myARGV[2], "process"))
562 {
563 next_event(&ctx, WAIT_EVENT_TIMEOUT);
564 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
565 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == STATUS_ACCESS_VIOLATION, "ExceptionCode = %lx\n",
566 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
567 }
568
569 if (logfile)
570 {
571 get_events(logfile, &start_event, &done_event);
572 }
573
574 if (strstr(myARGV[2], "order"))
575 {
576 strcat(buf, "waiting for the start signal...\n");
577 WaitForSingleObject(start_event, INFINITE);
578 }
579
580 blackbox.nokill_err=0;
581 if (strstr(myARGV[2], "nokill"))
582 {
583 blackbox.nokill_rc = DebugSetProcessKillOnExit(FALSE);
584 if (!blackbox.nokill_rc)
585 blackbox.nokill_err=GetLastError();
586 }
587 else
588 blackbox.nokill_rc=TRUE;
589
590 blackbox.detach_err=0;
591 if (strstr(myARGV[2], "detach"))
592 {
593 blackbox.detach_rc = DebugActiveProcessStop(blackbox.pid);
594 if (!blackbox.detach_rc)
595 blackbox.detach_err=GetLastError();
596 }
597 else
598 blackbox.detach_rc=TRUE;
599
600 if (debug_event && strstr(myARGV[2], "late"))
601 {
602 strcat(buf, "setting event\n");
603 blackbox.debug_rc=SetEvent(debug_event);
604 if (!blackbox.debug_rc)
605 blackbox.debug_err=GetLastError();
606 }
607
608 strcat(buf, "done debugging...\n");
609 if (logfile)
610 {
611 blackbox.failures = winetest_get_failures();
612 save_blackbox(logfile, &blackbox, sizeof(blackbox), buf);
613 }
614
615 SetEvent(done_event);
616
617 /* Just exit with a known value */
618 ExitProcess(0xdeadbeef);
619}
620
621static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks)
622{
623 static BOOL skip_crash_and_debug = FALSE;
624 BOOL bRet;
625 DWORD ret;
626 HANDLE start_event, done_event;
627 char* cmd;
628 char dbglog[MAX_PATH];
629 PROCESS_INFORMATION info;
630 STARTUPINFOA startup;
631 DWORD exit_code;
632 debugger_blackbox_t dbg_blackbox;
633 DWORD wait_code;
634
635 if (skip_crash_and_debug)
636 {
637 win_skip("Skipping crash_and_debug\n");
638 return;
639 }
640
641 ret=RegSetValueExA(hkey, "auto", 0, REG_SZ, (BYTE*)"1", 2);
642 if (ret == ERROR_ACCESS_DENIED)
643 {
644 skip_crash_and_debug = TRUE;
645 skip("No write access to change the debugger\n");
646 return;
647 }
648
649 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%ld\n", ret);
650
651 get_file_name(dbglog);
652 get_events(dbglog, &start_event, &done_event);
653 cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+10+strlen(dbgtasks)+1+strlen(dbglog)+2+34+1);
654 sprintf(cmd, "%s debugger %s \"%s\" %%ld %%ld", argv0, dbgtasks, dbglog);
655 ret=RegSetValueExA(hkey, "debugger", 0, REG_SZ, (BYTE*)cmd, strlen(cmd)+1);
656 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/debugger: ret=%ld\n", ret);
657 HeapFree(GetProcessHeap(), 0, cmd);
658
659 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv0) + 16);
660 sprintf(cmd, "%s debugger crash", argv0);
661
662 trace("running %s...\n", dbgtasks);
663 memset(&startup, 0, sizeof(startup));
664 startup.cb = sizeof(startup);
665 startup.dwFlags = STARTF_USESHOWWINDOW;
666 startup.wShowWindow = SW_SHOWNORMAL;
667 ret=CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
668 ok(ret, "CreateProcess: err=%ld\n", GetLastError());
669 HeapFree(GetProcessHeap(), 0, cmd);
670 CloseHandle(info.hThread);
671
672 /* The process exits... */
673 trace("waiting for child exit...\n");
674 wait_code = WaitForSingleObject(info.hProcess, 30000);
675#if defined(_WIN64) && defined(__MINGW32__)
676 /* Mingw x64 doesn't output proper unwind info */
677 skip_crash_and_debug = broken(wait_code == WAIT_TIMEOUT);
678 if (skip_crash_and_debug)
679 {
680 TerminateProcess(info.hProcess, WAIT_TIMEOUT);
681 WaitForSingleObject(info.hProcess, 5000);
682 CloseHandle(info.hProcess);
683 DeleteFileA(dbglog);
684 win_skip("Giving up on child process\n");
685 return;
686 }
687#endif
688 ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n");
689 bRet = GetExitCodeProcess(info.hProcess, &exit_code);
690 ok(bRet, "GetExitCodeProcess failed: err=%ld\n", GetLastError());
691 if (strstr(dbgtasks, "code2"))
692 {
693 /* If, after attaching to the debuggee, the debugger exits without
694 * detaching, then the debuggee gets a special exit code.
695 */
696 ok(exit_code == STATUS_DEBUGGER_INACTIVE ||
697 broken(exit_code == STATUS_ACCESS_VIOLATION) || /* Intermittent Vista+ */
698 broken(exit_code == WAIT_ABANDONED), /* NT4, W2K */
699 "wrong exit code : %08lx\n", exit_code);
700 }
701 else
702 ok(exit_code == STATUS_ACCESS_VIOLATION ||
703 broken(exit_code == WAIT_ABANDONED), /* NT4, W2K, W2K3 */
704 "wrong exit code : %08lx\n", exit_code);
705 CloseHandle(info.hProcess);
706
707 /* ...before the debugger */
708 if (strstr(dbgtasks, "order"))
709 ok(SetEvent(start_event), "SetEvent(start_event) failed\n");
710
711 trace("waiting for the debugger...\n");
712 wait_code = WaitForSingleObject(done_event, 5000);
713#if defined(_WIN64) && defined(__MINGW32__)
714 /* Mingw x64 doesn't output proper unwind info */
715 skip_crash_and_debug = broken(wait_code == WAIT_TIMEOUT);
716 if (skip_crash_and_debug)
717 {
718 DeleteFileA(dbglog);
719 win_skip("Giving up on debugger\n");
720 return;
721 }
722#endif
723 ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the debugger\n");
724
725 ok(load_blackbox(dbglog, &dbg_blackbox, sizeof(dbg_blackbox)), "failed to open: %s\n", dbglog);
726
727 ok(dbg_blackbox.argc == 6, "wrong debugger argument count: %d\n", dbg_blackbox.argc);
728 ok(dbg_blackbox.pid == info.dwProcessId, "the child and debugged pids don't match: %ld != %ld\n", info.dwProcessId, dbg_blackbox.pid);
729 ok(dbg_blackbox.debug_rc, "debugger: SetEvent(debug_event) failed err=%ld\n", dbg_blackbox.debug_err);
730 ok(dbg_blackbox.attach_rc, "DebugActiveProcess(%ld) failed err=%ld\n", dbg_blackbox.pid, dbg_blackbox.attach_err);
731 ok(dbg_blackbox.nokill_rc, "DebugSetProcessKillOnExit(FALSE) failed err=%ld\n", dbg_blackbox.nokill_err);
732 ok(dbg_blackbox.detach_rc, "DebugActiveProcessStop(%ld) failed err=%ld\n", dbg_blackbox.pid, dbg_blackbox.detach_err);
733 ok(!dbg_blackbox.failures, "debugger reported %lu failures\n", dbg_blackbox.failures);
734
735 DeleteFileA(dbglog);
736}
737
738static void crash_and_winedbg(HKEY hkey, const char* argv0)
739{
740 BOOL bRet;
741 DWORD ret;
742 char* cmd;
743 PROCESS_INFORMATION info;
744 STARTUPINFOA startup;
745 DWORD exit_code;
746
747 ret=RegSetValueExA(hkey, "auto", 0, REG_SZ, (BYTE*)"1", 2);
748 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%ld\n", ret);
749
750 cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+15+1);
751 sprintf(cmd, "%s debugger crash", argv0);
752
753 memset(&startup, 0, sizeof(startup));
754 startup.cb = sizeof(startup);
755 startup.dwFlags = STARTF_USESHOWWINDOW;
756 startup.wShowWindow = SW_SHOWNORMAL;
757 ret=CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
758 ok(ret, "CreateProcess: err=%ld\n", GetLastError());
759 HeapFree(GetProcessHeap(), 0, cmd);
760 CloseHandle(info.hThread);
761
762 trace("waiting for child exit...\n");
763 ok(WaitForSingleObject(info.hProcess, 60000) == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n");
764 bRet = GetExitCodeProcess(info.hProcess, &exit_code);
765 ok(bRet, "GetExitCodeProcess failed: err=%ld\n", GetLastError());
766 ok(exit_code == STATUS_ACCESS_VIOLATION, "exit code = %08lx\n", exit_code);
767 CloseHandle(info.hProcess);
768}
769
770static void test_ExitCode(void)
771{
772 static const char* AeDebug="Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug";
773 static const char* WineDbg="Software\\Wine\\WineDbg";
774 char test_exe[MAX_PATH];
775 DWORD ret;
776 HKEY hkey;
777 DWORD disposition;
778 reg_save_value auto_value;
779 reg_save_value debugger_value;
780
781 GetModuleFileNameA(GetModuleHandleA(NULL), test_exe, sizeof(test_exe));
782 if (GetFileAttributesA(test_exe) == INVALID_FILE_ATTRIBUTES)
783 strcat(test_exe, ".so");
784 if (GetFileAttributesA(test_exe) == INVALID_FILE_ATTRIBUTES)
785 {
786 ok(0, "could not find the test executable '%s'\n", test_exe);
787 return;
788 }
789
790 ret=RegCreateKeyExA(HKEY_LOCAL_MACHINE, AeDebug, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition);
791 if (ret == ERROR_SUCCESS)
792 {
793 save_value(hkey, "auto", &auto_value);
794 save_value(hkey, "debugger", &debugger_value);
795 trace("HKLM\\%s\\debugger is set to '%s'\n", AeDebug, debugger_value.data);
796 }
797 else if (ret == ERROR_ACCESS_DENIED)
798 {
799 skip("not enough privileges to change the debugger\n");
800 return;
801 }
802 else if (ret != ERROR_FILE_NOT_FOUND)
803 {
804 ok(0, "could not open the AeDebug key: %ld\n", ret);
805 return;
806 }
807 else
808 {
809 auto_value.data = NULL;
810 debugger_value.data = NULL;
811 }
812
813 if (debugger_value.data && debugger_value.type == REG_SZ &&
814 strstr((char*)debugger_value.data, "winedbg --auto"))
815 {
816 HKEY hkeyWinedbg;
817 ret=RegCreateKeyA(HKEY_CURRENT_USER, WineDbg, &hkeyWinedbg);
818 if (ret == ERROR_SUCCESS)
819 {
820 static DWORD zero;
821 reg_save_value crash_dlg_value;
822 save_value(hkeyWinedbg, "ShowCrashDialog", &crash_dlg_value);
823 RegSetValueExA(hkeyWinedbg, "ShowCrashDialog", 0, REG_DWORD, (BYTE *)&zero, sizeof(DWORD));
824 ignore_exceptions(TRUE);
825 crash_and_winedbg(hkey, test_exe);
826 ignore_exceptions(FALSE);
827 restore_value(hkeyWinedbg, &crash_dlg_value);
828 RegCloseKey(hkeyWinedbg);
829 }
830 else
831 ok(0, "Couldn't access WineDbg Key - error %lu\n", ret);
832 }
833
834 if (winetest_interactive)
835 /* Since the debugging process never sets the debug event, it isn't recognized
836 as a valid debugger and, after the debugger exits, Windows will show a dialog box
837 asking the user what to do */
838 crash_and_debug(hkey, test_exe, "dbg,none");
839 else
840 skip("\"none\" debugger test needs user interaction\n");
841 ok(disposition == REG_OPENED_EXISTING_KEY, "expected REG_OPENED_EXISTING_KEY, got %ld\n", disposition);
842 crash_and_debug(hkey, test_exe, "dbg,event,order");
843 crash_and_debug(hkey, test_exe, "dbg,attach,event,code2");
844 crash_and_debug(hkey, test_exe, "dbg,attach,event,nokill");
845 crash_and_debug(hkey, test_exe, "dbg,attach,event,detach");
846 crash_and_debug(hkey, test_exe, "dbg,attach,detach,late");
847 crash_and_debug(hkey, test_exe, "dbg,attach,process,event,detach");
848
849 if (disposition == REG_CREATED_NEW_KEY)
850 {
851 RegCloseKey(hkey);
852 RegDeleteKeyA(HKEY_LOCAL_MACHINE, AeDebug);
853 }
854 else
855 {
856 restore_value(hkey, &auto_value);
857 restore_value(hkey, &debugger_value);
858 RegCloseKey(hkey);
859 }
860}
861
862static void test_RemoteDebugger(void)
863{
864 BOOL bret, present;
865 if(!pCheckRemoteDebuggerPresent)
866 {
867 win_skip("CheckRemoteDebuggerPresent is not available\n");
868 return;
869 }
870 present = TRUE;
871 SetLastError(0xdeadbeef);
872 bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),&present);
873 ok(bret , "expected CheckRemoteDebuggerPresent to succeed\n");
874 ok(0xdeadbeef == GetLastError(),
875 "expected error to be unchanged, got %ld/%lx\n",GetLastError(), GetLastError());
876
877 present = TRUE;
878 SetLastError(0xdeadbeef);
879 bret = pCheckRemoteDebuggerPresent(NULL,&present);
880 ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n");
881 ok(present, "expected parameter to be unchanged\n");
882 ok(ERROR_INVALID_PARAMETER == GetLastError(),
883 "expected error ERROR_INVALID_PARAMETER, got %ld/%lx\n",GetLastError(), GetLastError());
884
885 SetLastError(0xdeadbeef);
886 bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),NULL);
887 ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n");
888 ok(ERROR_INVALID_PARAMETER == GetLastError(),
889 "expected error ERROR_INVALID_PARAMETER, got %ld/%lx\n",GetLastError(), GetLastError());
890}
891
892struct child_blackbox
893{
894 LONG failures;
895};
896
897static void doChild(int argc, char **argv)
898{
899 struct child_blackbox blackbox;
900 const char *blackbox_file;
901 WCHAR path[MAX_PATH];
902 HMODULE mod;
903 HANDLE parent, file, map;
904 DWORD ppid;
905 BOOL debug;
906 BOOL ret;
907
908 blackbox_file = argv[4];
909 sscanf(argv[3], "%08lx", &ppid);
910
911 parent = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ppid);
912 child_ok(!!parent, "OpenProcess failed, last error %#lx.\n", GetLastError());
913
914 ret = pCheckRemoteDebuggerPresent(parent, &debug);
915 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError());
916 child_ok(!debug, "Expected debug == 0, got %#x.\n", debug);
917
918 ret = DebugActiveProcess(ppid);
919 child_ok(ret, "DebugActiveProcess failed, last error %#lx.\n", GetLastError());
920
921 ret = pCheckRemoteDebuggerPresent(parent, &debug);
922 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError());
923 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
924
925 ret = DebugActiveProcessStop(ppid);
926 child_ok(ret, "DebugActiveProcessStop failed, last error %#lx.\n", GetLastError());
927
928 ret = pCheckRemoteDebuggerPresent(parent, &debug);
929 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError());
930 child_ok(!debug, "Expected debug == 0, got %#x.\n", debug);
931
932 ret = CloseHandle(parent);
933 child_ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError());
934
935 ret = IsDebuggerPresent();
936 child_ok(ret, "Expected ret != 0, got %#x.\n", ret);
937 ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug);
938 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError());
939 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
940
941 NtCurrentTeb()->Peb->BeingDebugged = FALSE;
942
943 ret = IsDebuggerPresent();
944 child_ok(!ret, "Expected ret != 0, got %#x.\n", ret);
945 ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug);
946 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError());
947 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
948
949 NtCurrentTeb()->Peb->BeingDebugged = TRUE;
950
951 mod = LoadLibraryW( L"ole32.dll" );
952 FreeLibrary( mod );
953
954 GetSystemDirectoryW( path, MAX_PATH );
955 wcscat( path, L"\\oleaut32.dll" );
956 file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
957 child_ok( file != INVALID_HANDLE_VALUE, "failed to open %s: %lu\n", debugstr_w(path), GetLastError());
958 map = CreateFileMappingW( file, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL );
959 child_ok( map != NULL, "failed to create mapping %s: %lu\n", debugstr_w(path), GetLastError() );
960 mod = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 );
961 child_ok( mod != NULL, "failed to map %s: %lu\n", debugstr_w(path), GetLastError() );
962 CloseHandle( file );
963 CloseHandle( map );
964 UnmapViewOfFile( mod );
965
966 if (sizeof(void *) > sizeof(int))
967 {
968 GetSystemWow64DirectoryW( path, MAX_PATH );
969 wcscat( path, L"\\oleacc.dll" );
970 }
971 else if (is_wow64)
972 {
973#ifdef __REACTOS__
974 static wchar_t expected_path[MAX_PATH];
975 GetWindowsDirectoryW(expected_path, MAX_PATH);
976 wcscat(expected_path, L"\\sysnative\\oleacc.dll");
977 wcscpy( path, expected_path );
978#else
979 wcscpy( path, L"c:\\windows\\sysnative\\oleacc.dll" );
980#endif
981 }
982 else goto done;
983
984 file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
985 child_ok( file != INVALID_HANDLE_VALUE, "failed to open %s: %lu\n", debugstr_w(path), GetLastError());
986 map = CreateFileMappingW( file, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL );
987 child_ok( map != NULL, "failed to create mapping %s: %lu\n", debugstr_w(path), GetLastError() );
988 mod = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 );
989 child_ok( mod != NULL, "failed to map %s: %lu\n", debugstr_w(path), GetLastError() );
990 CloseHandle( file );
991 CloseHandle( map );
992 UnmapViewOfFile( mod );
993
994done:
995 blackbox.failures = child_failures;
996 save_blackbox(blackbox_file, &blackbox, sizeof(blackbox), NULL);
997}
998
999static HMODULE ole32_mod, oleaut32_mod, oleacc_mod;
1000
1001static void check_dll_event( HANDLE process, DEBUG_EVENT *ev )
1002{
1003 WCHAR *p, module[MAX_PATH];
1004
1005 switch (ev->dwDebugEventCode)
1006 {
1007 case CREATE_PROCESS_DEBUG_EVENT:
1008 break;
1009 case LOAD_DLL_DEBUG_EVENT:
1010 if (!pGetMappedFileNameW( process, ev->u.LoadDll.lpBaseOfDll, module, MAX_PATH )) module[0] = 0;
1011 if ((p = wcsrchr( module, '\\' ))) p++;
1012 else p = module;
1013 if (!wcsicmp( p, L"ole32.dll" )) ole32_mod = ev->u.LoadDll.lpBaseOfDll;
1014 else if (!wcsicmp( p, L"oleaut32.dll" )) oleaut32_mod = ev->u.LoadDll.lpBaseOfDll;
1015 else if (!wcsicmp( p, L"oleacc.dll" )) oleacc_mod = ev->u.LoadDll.lpBaseOfDll;
1016 break;
1017 case UNLOAD_DLL_DEBUG_EVENT:
1018 if (ev->u.UnloadDll.lpBaseOfDll == ole32_mod) ole32_mod = (HMODULE)1;
1019 if (ev->u.UnloadDll.lpBaseOfDll == oleaut32_mod) oleaut32_mod = (HMODULE)1;
1020 if (ev->u.UnloadDll.lpBaseOfDll == oleacc_mod) oleacc_mod = (HMODULE)1;
1021 break;
1022 }
1023}
1024
1025static void test_debug_loop(int argc, char **argv)
1026{
1027 const char *arguments = " debugger child ";
1028 struct child_blackbox blackbox;
1029 char blackbox_file[MAX_PATH];
1030 PROCESS_INFORMATION pi;
1031 STARTUPINFOA si;
1032 BOOL debug;
1033 DWORD pid;
1034 char *cmd;
1035 BOOL ret;
1036
1037 if (!pCheckRemoteDebuggerPresent)
1038 {
1039 win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n");
1040 return;
1041 }
1042#if defined(__REACTOS__) && defined(_WIN64)
1043 if (is_reactos()) {
1044 /* In theory this should be caught below and exit. In practice stack
1045 * corruption occurs and the test crashes after exiting this function. */
1046 skip("FIXME: Skipping test on ReactOS x64 because it is 64bit only!\n");
1047 return;
1048 }
1049#endif
1050 if (sizeof(void *) > sizeof(int))
1051 {
1052 WCHAR buffer[MAX_PATH];
1053 GetSystemWow64DirectoryW( buffer, MAX_PATH );
1054 wcscat( buffer, L"\\oleacc.dll" );
1055 if (GetFileAttributesW( buffer ) == INVALID_FILE_ATTRIBUTES)
1056 {
1057 skip("Skipping test on 64bit only configuration\n");
1058 return;
1059 }
1060 }
1061
1062 pid = GetCurrentProcessId();
1063 ret = DebugActiveProcess(pid);
1064 ok(!ret, "DebugActiveProcess() succeeded on own process.\n");
1065
1066 get_file_name(blackbox_file);
1067 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + strlen(blackbox_file) + 2 + 10);
1068 sprintf(cmd, "%s%s%08lx \"%s\"", argv[0], arguments, pid, blackbox_file);
1069
1070 memset(&si, 0, sizeof(si));
1071 si.cb = sizeof(si);
1072 ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
1073 ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError());
1074
1075 HeapFree(GetProcessHeap(), 0, cmd);
1076
1077 ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug);
1078 ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError());
1079 ok(debug, "Expected debug != 0, got %#x.\n", debug);
1080
1081 for (;;)
1082 {
1083 DEBUG_EVENT ev;
1084
1085 ret = WaitForDebugEvent(&ev, INFINITE);
1086 ok(ret, "WaitForDebugEvent failed, last error %#lx.\n", GetLastError());
1087 if (!ret) break;
1088
1089 if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
1090 check_dll_event( pi.hProcess, &ev );
1091#if defined(__i386__) || defined(__x86_64__)
1092 if (ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
1093 ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
1094 {
1095 BYTE byte = 0;
1096 NtReadVirtualMemory(pi.hProcess, ev.u.Exception.ExceptionRecord.ExceptionAddress, &byte, 1, NULL);
1097 ok(byte == 0xcc, "got %02x\n", byte);
1098 }
1099#endif
1100 ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
1101 ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError());
1102 if (!ret) break;
1103 }
1104
1105 /* sometimes not all unload events are sent on win7 */
1106 ok( ole32_mod == (HMODULE)1 || broken( ole32_mod != NULL ), "ole32.dll was not reported\n" );
1107 ok( oleaut32_mod == (HMODULE)1, "oleaut32.dll was not reported\n" );
1108#ifdef _WIN64
1109 ok( oleacc_mod == (HMODULE)1, "oleacc.dll was not reported\n" );
1110#else
1111 ok( oleacc_mod == NULL, "oleacc.dll was reported\n" );
1112#endif
1113
1114 ret = CloseHandle(pi.hThread);
1115 ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError());
1116 ret = CloseHandle(pi.hProcess);
1117 ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError());
1118
1119 load_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
1120 ok(!blackbox.failures, "Got %ld failures from child process.\n", blackbox.failures);
1121
1122 ret = DeleteFileA(blackbox_file);
1123 ok(ret, "DeleteFileA failed, last error %#lx.\n", GetLastError());
1124}
1125
1126struct find_main_window
1127{
1128 DWORD pid;
1129 unsigned count;
1130 HWND windows[5];
1131};
1132
1133static BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
1134{
1135 struct find_main_window* fmw = (struct find_main_window*)lParam;
1136 DWORD pid = 0;
1137
1138 if (GetWindowThreadProcessId(handle, &pid) && fmw->pid == pid &&
1139 !GetWindow(handle, GW_OWNER))
1140 {
1141 ok(fmw->count < ARRAY_SIZE(fmw->windows), "Too many windows\n");
1142 if (fmw->count < ARRAY_SIZE(fmw->windows))
1143 fmw->windows[fmw->count++] = handle;
1144 }
1145 return TRUE;
1146}
1147
1148static void close_main_windows(DWORD pid)
1149{
1150 struct find_main_window fmw = {pid, 0};
1151 unsigned i;
1152
1153 EnumWindows(enum_windows_callback, (LPARAM)&fmw);
1154 ok(fmw.count, "no window found\n");
1155 for (i = 0; i < fmw.count; i++)
1156 PostMessageA(fmw.windows[i], WM_CLOSE, 0, 0);
1157}
1158
1159static void test_debug_loop_wow64(void)
1160{
1161 WCHAR buffer[MAX_PATH], *p;
1162 PROCESS_INFORMATION pi;
1163 STARTUPINFOW si;
1164 BOOL ret;
1165 unsigned order = 0, bp_order = 0, bpwx_order = 0, num_ntdll = 0, num_wow64 = 0;
1166
1167 /* checking conditions for running this test */
1168#if defined(__REACTOS__) && defined(_WIN64)
1169 if (is_reactos()) {
1170 skip("FIXME: ReactOS x64 does not have WoW64 yet!\n");
1171 return;
1172 }
1173#endif
1174 if (GetSystemWow64DirectoryW( buffer, ARRAY_SIZE(buffer) ) && sizeof(void*) > sizeof(int) && pGetMappedFileNameW)
1175 {
1176 wcscat( buffer, L"\\msinfo32.exe" );
1177 ret = GetFileAttributesW( buffer ) != INVALID_FILE_ATTRIBUTES;
1178 }
1179 else ret = FALSE;
1180 if (!ret)
1181 {
1182 skip("Skipping test on incompatible config\n");
1183 return;
1184 }
1185 memset( &si, 0, sizeof(si) );
1186 si.cb = sizeof(si);
1187 ret = CreateProcessW( NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi );
1188 ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError());
1189
1190 for (;;)
1191 {
1192 DEBUG_EVENT ev;
1193
1194 ++order;
1195 ret = WaitForDebugEvent( &ev, 2000 );
1196 if (!ret) break;
1197
1198 switch (ev.dwDebugEventCode)
1199 {
1200 case CREATE_PROCESS_DEBUG_EVENT:
1201 break;
1202 case LOAD_DLL_DEBUG_EVENT:
1203 if (!pGetMappedFileNameW( pi.hProcess, ev.u.LoadDll.lpBaseOfDll, buffer, ARRAY_SIZE(buffer) )) buffer[0] = L'\0';
1204 if ((p = wcsrchr( buffer, '\\' ))) p++;
1205 else p = buffer;
1206 if (!wcsnicmp( p, L"wow64", 5 ) || !wcsicmp( p, L"xtajit.dll" ))
1207 {
1208 /* on Win10, wow64cpu's load dll event is received after first exception */
1209 ok(bpwx_order == 0, "loaddll for wow64 DLLs should appear before exception\n");
1210 num_wow64++;
1211 }
1212 else if (!wcsicmp( p, L"ntdll.dll" ))
1213 {
1214 ok(bp_order == 0 && bpwx_order == 0, "loaddll on ntdll should appear before exception\n");
1215 num_ntdll++;
1216 }
1217 break;
1218 case EXCEPTION_DEBUG_EVENT:
1219 if (ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
1220 bp_order = order;
1221 else if (ev.u.Exception.ExceptionRecord.ExceptionCode == STATUS_WX86_BREAKPOINT)
1222 bpwx_order = order;
1223 }
1224 ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
1225 ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError());
1226 if (!ret) break;
1227 }
1228
1229 /* gracefully terminates msinfo32 */
1230 close_main_windows( pi.dwProcessId );
1231
1232 /* eat up the remaining events... not generating unload dll events in case of process termination */
1233 for (;;)
1234 {
1235 DEBUG_EVENT ev;
1236
1237 ret = WaitForDebugEvent( &ev, 2000 );
1238 if (!ret || ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
1239 switch (ev.dwDebugEventCode)
1240 {
1241 default:
1242 ok(0, "Unexpected event: %lu\n", ev.dwDebugEventCode);
1243 /* fall through */
1244 case EXIT_THREAD_DEBUG_EVENT:
1245 ret = ContinueDebugEvent( ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE );
1246 ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError());
1247 break;
1248 }
1249 }
1250
1251 ret = WaitForSingleObject( pi.hProcess, 2000 );
1252 if (ret != WAIT_OBJECT_0)
1253 {
1254 DWORD ec;
1255 ret = GetExitCodeProcess( pi.hProcess, &ec );
1256 ok(ret, "GetExitCodeProcess failed: %lu\n", GetLastError());
1257 ok(ec != STILL_ACTIVE, "GetExitCodeProcess still active\n");
1258 }
1259 for (;;)
1260 {
1261 DEBUG_EVENT ev;
1262
1263 ret = WaitForDebugEvent( &ev, 2000 );
1264 if (!ret || ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
1265 switch (ev.dwDebugEventCode)
1266 {
1267 default:
1268 ok(0, "Unexpected event: %lu\n", ev.dwDebugEventCode);
1269 /* fall through */
1270 case EXIT_THREAD_DEBUG_EVENT:
1271 ret = ContinueDebugEvent( ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE );
1272 ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError());
1273 break;
1274 }
1275 }
1276 ret = CloseHandle( pi.hThread );
1277 ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError());
1278 ret = CloseHandle( pi.hProcess );
1279 ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError());
1280
1281 if (strcmp( winetest_platform, "wine" ) || num_wow64) /* windows or new wine wow */
1282 {
1283 ok(num_ntdll == 2, "Expecting two ntdll instances\n");
1284 ok(num_wow64 >= 3, "Expecting more than 3 wow64*.dll\n");
1285 }
1286 else /* Wine's old wow, or 32/64 bit only configurations */
1287 {
1288 ok(num_ntdll == 1, "Expecting one ntdll instances\n");
1289 ok(num_wow64 == 0, "Expecting more no wow64*.dll\n");
1290 }
1291 ok(bp_order, "Expecting 1 bp exceptions\n");
1292 todo_wine
1293 {
1294 ok(bpwx_order, "Expecting 1 bpwx exceptions\n");
1295 ok(bp_order < bpwx_order, "Out of order bp exceptions\n");
1296 }
1297}
1298
1299static void doChildren(int argc, char **argv)
1300{
1301 const char *arguments = "debugger children last";
1302 struct child_blackbox blackbox;
1303 const char *blackbox_file, *p;
1304 char event_name[MAX_PATH];
1305 PROCESS_INFORMATION pi;
1306 STARTUPINFOA si;
1307 HANDLE event;
1308 char *cmd;
1309 BOOL ret;
1310
1311 if (!strcmp(argv[3], "last")) return;
1312
1313 blackbox_file = argv[3];
1314
1315 run_background_thread();
1316
1317 p = strrchr(blackbox_file, '\\');
1318 p = p ? p+1 : blackbox_file;
1319 strcpy(event_name, p);
1320 strcat(event_name, "_init");
1321 event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
1322 child_ok(event != NULL, "OpenEvent failed, last error %ld.\n", GetLastError());
1323 SetEvent(event);
1324 CloseHandle(event);
1325
1326 p = strrchr(blackbox_file, '\\');
1327 p = p ? p+1 : blackbox_file;
1328 strcpy(event_name, p);
1329 strcat(event_name, "_attach");
1330 event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
1331 child_ok(event != NULL, "OpenEvent failed, last error %ld.\n", GetLastError());
1332 WaitForSingleObject(event, INFINITE);
1333 CloseHandle(event);
1334
1335 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + 2);
1336 sprintf(cmd, "%s %s", argv[0], arguments);
1337
1338 memset(&si, 0, sizeof(si));
1339 si.cb = sizeof(si);
1340 ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1341 child_ok(ret, "CreateProcess failed, last error %ld.\n", GetLastError());
1342
1343 child_ok(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0,
1344 "Timed out waiting for the child to exit\n");
1345
1346 ret = CloseHandle(pi.hThread);
1347 child_ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1348 ret = CloseHandle(pi.hProcess);
1349 child_ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1350
1351 blackbox.failures = child_failures;
1352 save_blackbox(blackbox_file, &blackbox, sizeof(blackbox), NULL);
1353
1354 HeapFree(GetProcessHeap(), 0, cmd);
1355}
1356
1357static void test_debug_children(const char *name, DWORD flag, BOOL debug_child, BOOL pass_exception)
1358{
1359 const char *arguments = "debugger children";
1360#ifdef __REACTOS__
1361 struct child_blackbox blackbox = {0};
1362#else
1363 struct child_blackbox blackbox;
1364#endif
1365 char blackbox_file[MAX_PATH], *p;
1366 char event_name[MAX_PATH];
1367 PROCESS_INFORMATION pi;
1368 STARTUPINFOA si;
1369 HANDLE event_init, event_attach;
1370 char *cmd;
1371 BOOL debug, ret;
1372 struct debugger_context ctx = { 0 };
1373
1374 if (!pCheckRemoteDebuggerPresent)
1375 {
1376 win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n");
1377 return;
1378 }
1379
1380 get_file_name(blackbox_file);
1381 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(name) + strlen(arguments) + strlen(blackbox_file) + 5);
1382 sprintf(cmd, "%s %s \"%s\"", name, arguments, blackbox_file);
1383
1384 p = strrchr(blackbox_file, '\\');
1385 p = p ? p+1 : blackbox_file;
1386 strcpy(event_name, p);
1387 strcat(event_name, "_init");
1388 event_init = CreateEventA(NULL, FALSE, FALSE, event_name);
1389 ok(event_init != NULL, "OpenEvent failed, last error %ld.\n", GetLastError());
1390
1391 p = strrchr(blackbox_file, '\\');
1392 p = p ? p+1 : blackbox_file;
1393 strcpy(event_name, p);
1394 strcat(event_name, "_attach");
1395 event_attach = CreateEventA(NULL, FALSE, flag!=0, event_name);
1396 ok(event_attach != NULL, "CreateEvent failed, last error %ld.\n", GetLastError());
1397
1398 memset(&si, 0, sizeof(si));
1399 si.cb = sizeof(si);
1400
1401 ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, flag, NULL, NULL, &si, &pi);
1402 ok(ret, "CreateProcess failed, last error %ld.\n", GetLastError());
1403 HeapFree(GetProcessHeap(), 0, cmd);
1404 if (!flag)
1405 {
1406 WaitForSingleObject(event_init, INFINITE);
1407 Sleep(100);
1408 ret = DebugActiveProcess(pi.dwProcessId);
1409 ok(ret, "DebugActiveProcess failed, last error %ld.\n", GetLastError());
1410 }
1411
1412 ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug);
1413 ok(ret, "CheckRemoteDebuggerPresent failed, last error %ld.\n", GetLastError());
1414 ok(debug, "Expected debug != 0, got %x.\n", debug);
1415
1416 trace("starting debugger loop\n");
1417
1418 if (flag)
1419 {
1420 DWORD last_thread;
1421
1422 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1423 ok(ctx.ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1424 ok(ctx.pid == pi.dwProcessId, "unexpected dwProcessId %x\n", ctx.ev.dwProcessId == ctx.pid);
1425
1426 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1427 ok(ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1428 last_thread = ctx.ev.dwThreadId;
1429
1430 wait_for_breakpoint(&ctx);
1431 ok(ctx.dll_cnt > 2, "dll_cnt = %d\n", ctx.dll_cnt);
1432
1433 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1434 ok(ctx.ev.dwThreadId == last_thread, "unexpected thread\n");
1435 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n",
1436 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
1437
1438 /* Except for wxppro and w2008, the initial breakpoint is now somewhere else, possibly within LdrInitShimEngineDynamic,
1439 * It's also catching exceptions and ContinueDebugEvent(DBG_EXCEPTION_NOT_HANDLED) should not crash the child now */
1440#ifdef __REACTOS__
1441 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress != pDbgBreakPoint || broken(GetNTVersion() <= _WIN32_WINNT_VISTA), "ExceptionAddress == pDbgBreakPoint\n");
1442#else
1443 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress != pDbgBreakPoint, "ExceptionAddress == pDbgBreakPoint\n");
1444#endif
1445
1446 if (pass_exception)
1447 {
1448 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
1449 ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError());
1450 ctx.ev.dwDebugEventCode = -1;
1451
1452 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1453#ifdef __REACTOS__
1454 ok(ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT || broken(GetNTVersion() <= _WIN32_WINNT_WS03), "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1455#else
1456 ok(ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1457#endif
1458 }
1459 }
1460 else
1461 {
1462 DWORD last_thread;
1463
1464 process_attach_events(&ctx, pass_exception);
1465 ok(ctx.pid == pi.dwProcessId, "unexpected dwProcessId %lx\n", ctx.pid);
1466
1467 ret = DebugBreakProcess(pi.hProcess);
1468 ok(ret, "BreakProcess failed: %lu\n", GetLastError());
1469
1470 /* a new thread, which executes DbgBreakPoint, is created */
1471 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1472 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1473 last_thread = ctx.ev.dwThreadId;
1474
1475 if (ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
1476 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1477
1478 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1479 ok(ctx.ev.dwThreadId == last_thread, "unexpected thread\n");
1480 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n",
1481 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
1482 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint, "ExceptionAddress != DbgBreakPoint\n");
1483
1484 ret = SetEvent(event_attach);
1485 ok(ret, "SetEvent failed, last error %ld.\n", GetLastError());
1486
1487 if (pass_exception)
1488 {
1489 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
1490 ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError());
1491 ctx.ev.dwDebugEventCode = -1;
1492 }
1493 }
1494
1495 do next_event(&ctx, WAIT_EVENT_TIMEOUT);
1496 while (ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx.ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT
1497 || ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT);
1498
1499#ifdef __REACTOS__
1500 ok(ctx.ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT || broken(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) /* WS03 */, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1501#else
1502 ok(ctx.ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1503#endif
1504 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_CONTINUE);
1505 ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError());
1506
1507 if(debug_child)
1508 ok(ctx.process_cnt == 2, "didn't get any child events (flag: %lx).\n", flag);
1509 else
1510 ok(ctx.process_cnt == 1, "got child event (flag: %lx).\n", flag);
1511 CloseHandle(event_init);
1512 CloseHandle(event_attach);
1513
1514 ret = CloseHandle(pi.hThread);
1515 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1516 ret = CloseHandle(pi.hProcess);
1517 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1518
1519 load_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
1520 ok(!blackbox.failures, "Got %ld failures from child process.\n", blackbox.failures);
1521
1522 ret = DeleteFileA(blackbox_file);
1523 ok(ret, "DeleteFileA failed, last error %ld.\n", GetLastError());
1524}
1525
1526static void wait_debugger(HANDLE event, unsigned int cnt)
1527{
1528 while (cnt--) WaitForSingleObject(event, INFINITE);
1529 ExitProcess(0);
1530}
1531
1532#define expect_event(a,b) expect_event_(__LINE__,a,b)
1533static void expect_event_(unsigned line, struct debugger_context *ctx, DWORD event_code)
1534{
1535 next_event(ctx, WAIT_EVENT_TIMEOUT);
1536 ok_(__FILE__,line)(ctx->ev.dwDebugEventCode == event_code, "dwDebugEventCode = %ld expected %ld\n",
1537 ctx->ev.dwDebugEventCode, event_code);
1538}
1539
1540#define expect_exception(a,b) expect_exception_(__LINE__,a,b)
1541static void expect_exception_(unsigned line, struct debugger_context *ctx, DWORD exception_code)
1542{
1543 expect_event_(line, ctx, EXCEPTION_DEBUG_EVENT);
1544 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == exception_code, "ExceptionCode = %lx expected %lx\n",
1545 ctx->ev.u.Exception.ExceptionRecord.ExceptionCode, exception_code);
1546}
1547
1548#define check_breakpoint_exception(a,b) expect_breakpoint_exception_(__LINE__,a,b)
1549static void check_breakpoint_exception_(unsigned line, struct debugger_context *ctx, const void *expect_addr)
1550{
1551 struct debuggee_thread *thread;
1552 if (!expect_addr) return;
1553 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == expect_addr,
1554 "ExceptionAddress = %p expected %p\n", ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress, expect_addr);
1555 thread = get_debuggee_thread(ctx, ctx->ev.dwThreadId);
1556 fetch_thread_context(thread);
1557 ok_(__FILE__,line)(get_ip(&thread->ctx) == (char*)expect_addr + 1, "unexpected instruction pointer %p expected %p\n",
1558 get_ip(&thread->ctx), expect_addr);
1559}
1560
1561#define expect_breakpoint_exception(a,b) expect_breakpoint_exception_(__LINE__,a,b)
1562static void expect_breakpoint_exception_(unsigned line, struct debugger_context *ctx, const void *expect_addr)
1563{
1564 expect_exception_(line, ctx, EXCEPTION_BREAKPOINT);
1565 check_breakpoint_exception_(line, ctx, expect_addr);
1566}
1567
1568#define single_step(a,b,c) single_step_(__LINE__,a,b,c)
1569static void single_step_(unsigned line, struct debugger_context *ctx, struct debuggee_thread *thread, void *expect_addr)
1570{
1571#if defined(__i386__) || defined(__x86_64__)
1572 fetch_thread_context(thread);
1573 thread->ctx.EFlags |= 0x100;
1574 set_thread_context(ctx, thread);
1575 expect_exception_(line, ctx, EXCEPTION_SINGLE_STEP);
1576 ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == expect_addr,
1577 "ExceptionAddress = %p expected %p\n", ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress, expect_addr);
1578 fetch_thread_context(thread);
1579 ok_(__FILE__,line)(get_ip(&thread->ctx) == expect_addr, "unexpected instruction pointer %p expected %p\n",
1580 get_ip(&thread->ctx), expect_addr);
1581 ok_(__FILE__,line)(!(thread->ctx.EFlags & 0x100), "EFlags = %lx\n", thread->ctx.EFlags);
1582#endif
1583}
1584
1585static const BYTE loop_code[] = {
1586#if defined(__i386__) || defined(__x86_64__)
1587 0x90, /* nop */
1588 0x90, /* nop */
1589 0x90, /* nop */
1590 0xe9, 0xf8, 0xff, 0xff, 0xff /* jmp $-8 */
1591#endif
1592};
1593
1594static const BYTE call_debug_service_code[] = {
1595#ifdef __i386__
1596 0x53, /* pushl %ebx */
1597 0x57, /* pushl %edi */
1598 0x8b, 0x44, 0x24, 0x0c, /* movl 12(%esp),%eax */
1599 0xb9, 0x11, 0x11, 0x11, 0x11, /* movl $0x11111111,%ecx */
1600 0xba, 0x22, 0x22, 0x22, 0x22, /* movl $0x22222222,%edx */
1601 0xbb, 0x33, 0x33, 0x33, 0x33, /* movl $0x33333333,%ebx */
1602 0xbf, 0x44, 0x44, 0x44, 0x44, /* movl $0x44444444,%edi */
1603 0xcd, 0x2d, /* int $0x2d */
1604 0xeb, /* jmp $+17 */
1605 0x0f, 0x1f, 0x00, /* nop */
1606 0x31, 0xc0, /* xorl %eax,%eax */
1607 0xeb, 0x0c, /* jmp $+14 */
1608 0x90, 0x90, 0x90, 0x90, /* nop */
1609 0x90, 0x90, 0x90, 0x90,
1610 0x90,
1611 0x31, 0xc0, /* xorl %eax,%eax */
1612 0x40, /* incl %eax */
1613 0x5f, /* popl %edi */
1614 0x5b, /* popl %ebx */
1615 0xc3, /* ret */
1616#elif defined(__x86_64__)
1617 0x53, /* push %rbx */
1618 0x57, /* push %rdi */
1619 0x48, 0x89, 0xc8, /* movl %rcx,%rax */
1620 0x48, 0xb9, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, /* movabs $0x1111111111111111,%rcx */
1621 0x48, 0xba, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* movabs $0x2222222222222222,%rdx */
1622 0x48, 0xbb, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, /* movabs $0x3333333333333333,%rbx */
1623 0x48, 0xbf, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, /* movabs $0x4444444444444444,%rdi */
1624 0xcd, 0x2d, /* int $0x2d */
1625 0xeb, /* jmp $+17 */
1626 0x0f, 0x1f, 0x00, /* nop */
1627 0x48, 0x31, 0xc0, /* xor %rax,%rax */
1628 0xeb, 0x0e, /* jmp $+16 */
1629 0x90, 0x90, 0x90, 0x90, /* nop */
1630 0x90, 0x90, 0x90, 0x90,
1631 0x48, 0x31, 0xc0, /* xor %rax,%rax */
1632 0x48, 0xff, 0xc0, /* inc %rax */
1633 0x5f, /* pop %rdi */
1634 0x5b, /* pop %rbx */
1635 0xc3, /* ret */
1636#endif
1637};
1638
1639#if defined(__i386__) || defined(__x86_64__)
1640#define OP_BP 0xcc
1641#else
1642#define OP_BP 0
1643#endif
1644
1645static void test_debugger(const char *argv0)
1646{
1647 static const char arguments[] = " debugger wait ";
1648 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
1649 struct debugger_context ctx = { 0 };
1650 PROCESS_INFORMATION pi;
1651 STARTUPINFOA si;
1652 NTSTATUS status;
1653 HANDLE event, thread;
1654 BYTE *mem, buf[4096], *proc_code, *thread_proc, byte;
1655 unsigned int i, worker_cnt, exception_cnt, skip_reply_later;
1656 struct debuggee_thread *debuggee_thread;
1657 char *cmd;
1658 BOOL ret;
1659
1660 event = CreateEventW(&sa, FALSE, FALSE, NULL);
1661 ok(event != NULL, "CreateEvent failed: %lu\n", GetLastError());
1662
1663 cmd = heap_alloc(strlen(argv0) + strlen(arguments) + 16);
1664 sprintf(cmd, "%s%s%lx %u\n", argv0, arguments, (DWORD)(DWORD_PTR)event, OP_BP ? 3 : 1);
1665
1666 memset(&si, 0, sizeof(si));
1667 si.cb = sizeof(si);
1668 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
1669 ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError());
1670 heap_free(cmd);
1671
1672 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1673 ok(ctx.ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1674
1675 if ((skip_reply_later = !ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER)))
1676 win_skip("Skipping unsupported DBG_REPLY_LATER tests\n");
1677 else
1678 {
1679 DEBUG_EVENT de;
1680
1681 de = ctx.ev;
1682 ctx.ev.dwDebugEventCode = -1;
1683 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1684 ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1685 "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode);
1686 ok(de.dwProcessId == ctx.ev.dwProcessId,
1687 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de.dwProcessId);
1688 ok(de.dwThreadId == ctx.ev.dwThreadId,
1689 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de.dwThreadId);
1690
1691 /* Suspending the thread should prevent other attach debug events
1692 * to be received until it's resumed */
1693 thread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ctx.ev.dwThreadId);
1694 ok(thread != INVALID_HANDLE_VALUE, "OpenThread failed, last error:%lu\n", GetLastError());
1695
1696 status = NtSuspendThread(thread, NULL);
1697 ok(!status, "NtSuspendThread failed, last error:%lu\n", GetLastError());
1698
1699 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER);
1700 ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError());
1701 ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n");
1702
1703 status = NtResumeThread(thread, NULL);
1704 ok(!status, "NtResumeThread failed, last error:%lu\n", GetLastError());
1705
1706 ret = CloseHandle(thread);
1707 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1708
1709 ok(WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent failed.\n");
1710 ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1711 "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode);
1712
1713 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1714 ok(ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1715 de = ctx.ev;
1716
1717 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER);
1718 ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError());
1719
1720 ctx.ev.dwDebugEventCode = -1;
1721 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1722 ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1723 "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode);
1724 ok(de.dwProcessId == ctx.ev.dwProcessId,
1725 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de.dwProcessId);
1726 ok(de.dwThreadId == ctx.ev.dwThreadId,
1727 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de.dwThreadId);
1728 }
1729
1730 wait_for_breakpoint(&ctx);
1731 do next_event(&ctx, POLL_EVENT_TIMEOUT);
1732 while(ctx.ev.dwDebugEventCode != -1);
1733
1734 mem = VirtualAllocEx(pi.hProcess, NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1735 ok(mem != NULL, "VirtualAllocEx failed: %lu\n", GetLastError());
1736 proc_code = buf + 1024;
1737 thread_proc = mem + 1024;
1738
1739 if (sizeof(loop_code) > 1)
1740 {
1741 /* test single-step exceptions */
1742 memset(buf, OP_BP, sizeof(buf));
1743 memcpy(proc_code, &loop_code, sizeof(loop_code));
1744 proc_code[0] = OP_BP; /* set a breakpoint */
1745 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
1746 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
1747
1748 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL);
1749 ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError());
1750
1751 expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT);
1752 debuggee_thread = get_debuggee_thread(&ctx, ctx.ev.dwThreadId);
1753
1754 wait_for_breakpoint(&ctx);
1755 fetch_thread_context(debuggee_thread);
1756 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == thread_proc,
1757 "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress);
1758 ok(get_ip(&debuggee_thread->ctx) == thread_proc + 1, "unexpected instruction pointer %p\n",
1759 get_ip(&debuggee_thread->ctx));
1760
1761 single_step(&ctx, debuggee_thread, thread_proc + 2);
1762 single_step(&ctx, debuggee_thread, thread_proc + 3);
1763 single_step(&ctx, debuggee_thread, thread_proc);
1764
1765 byte = 0xc3; /* ret */
1766 ret = WriteProcessMemory(pi.hProcess, thread_proc, &byte, 1, NULL);
1767 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
1768
1769 expect_event(&ctx, EXIT_THREAD_DEBUG_EVENT);
1770 }
1771 else todo_wine win_skip("loop_code not supported on this architecture\n");
1772
1773 if (sizeof(call_debug_service_code) > 1)
1774 {
1775 /* test debug service exceptions */
1776 memset(buf, OP_BP, sizeof(buf));
1777 memcpy(proc_code, call_debug_service_code, sizeof(call_debug_service_code));
1778 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
1779 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
1780
1781 /* BREAKPOINT_PRINT */
1782#ifndef __REACTOS__ // These tests don't pass on WS03-Win10 1607
1783 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, (void*)2, 0, NULL);
1784 ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError());
1785 expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT);
1786 expect_breakpoint_exception(&ctx, NULL);
1787 expect_event(&ctx, EXIT_THREAD_DEBUG_EVENT);
1788#endif
1789
1790 /* BREAKPOINT_PROMPT */
1791 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, (void*)1, 0, NULL);
1792 ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError());
1793 expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT);
1794 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1795 /* some 32-bit Windows versions report exception to the debugger */
1796 if (sizeof(void *) == 4 && ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) next_event(&ctx, WAIT_EVENT_TIMEOUT);
1797#if defined(__REACTOS__) && defined(_WIN64)
1798 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT || broken(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) /* Win8+ x64 */, "unexpected debug event %lu\n", ctx.ev.dwDebugEventCode);
1799#else
1800 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT, "unexpected debug event %lu\n", ctx.ev.dwDebugEventCode);
1801#endif
1802 }
1803 else todo_wine win_skip("call_debug_service_code not supported on this architecture\n");
1804
1805 if (skip_reply_later)
1806 win_skip("Skipping unsupported DBG_REPLY_LATER tests\n");
1807 else if (sizeof(loop_code) > 1)
1808 {
1809 HANDLE thread_a, thread_b;
1810 DEBUG_EVENT de_a, de_b;
1811
1812 memset(buf, OP_BP, sizeof(buf));
1813 memcpy(proc_code, &loop_code, sizeof(loop_code));
1814 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
1815 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
1816
1817 byte = OP_BP;
1818 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
1819 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
1820
1821 thread_a = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL);
1822 ok(thread_a != NULL, "CreateRemoteThread failed: %lu\n", GetLastError());
1823 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1824 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1825 de_a = ctx.ev;
1826
1827 thread_b = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL);
1828 ok(thread_b != NULL, "CreateRemoteThread failed: %lu\n", GetLastError());
1829 do next_event(&ctx, POLL_EVENT_TIMEOUT);
1830 while(ctx.ev.dwDebugEventCode != CREATE_THREAD_DEBUG_EVENT);
1831 de_b = ctx.ev;
1832
1833 status = NtSuspendThread(thread_b, NULL);
1834 ok(!status, "NtSuspendThread failed, last error:%lu\n", GetLastError());
1835 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER);
1836 ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError());
1837
1838 ctx.ev.dwDebugEventCode = -1;
1839 next_event(&ctx, WAIT_EVENT_TIMEOUT);
1840 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT,
1841 "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1842 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1843 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1844 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1845 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1846 de_a = ctx.ev;
1847
1848 byte = 0xc3; /* ret */
1849 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
1850 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
1851
1852 ok(pNtSuspendProcess != NULL, "NtSuspendProcess not found\n");
1853 ok(pNtResumeProcess != NULL, "pNtResumeProcess not found\n");
1854 if (pNtSuspendProcess && pNtResumeProcess)
1855 {
1856 DWORD action = DBG_REPLY_LATER;
1857 status = pNtSuspendProcess(pi.hProcess);
1858 ok(!status, "NtSuspendProcess failed, last error:%lu\n", GetLastError());
1859 do
1860 {
1861 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, action);
1862 ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError());
1863 ret = WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT);
1864 ok(!ret || ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "WaitForDebugEvent succeeded.\n");
1865 if (ret) add_thread(&ctx, ctx.ev.dwThreadId);
1866 action = DBG_CONTINUE;
1867 } while (ret);
1868
1869 status = NtResumeThread(thread_b, NULL);
1870 ok(!status, "NtResumeThread failed, last error:%lu\n", GetLastError());
1871 while (WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT))
1872 {
1873 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "Unexpected debug event %lx\n", ctx.ev.dwDebugEventCode);
1874 if (ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
1875 {
1876 add_thread(&ctx, ctx.ev.dwThreadId);
1877 ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_CONTINUE);
1878 ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError());
1879 }
1880 }
1881
1882 status = pNtResumeProcess(pi.hProcess);
1883 ok(!status, "pNtResumeProcess failed, last error:%lu\n", GetLastError());
1884 }
1885 else
1886 {
1887 status = NtResumeThread(thread_b, NULL);
1888 ok(!status, "NtResumeThread failed, last error:%lu\n", GetLastError());
1889 ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n");
1890 }
1891
1892 /* Testing shows that on windows the debug event order between threads
1893 * is not guaranteed.
1894 *
1895 * Now we expect thread_a to report:
1896 * - its delayed EXCEPTION_DEBUG_EVENT
1897 * - EXIT_THREAD_DEBUG_EVENT
1898 *
1899 * and thread_b to report:
1900 * - its delayed CREATE_THREAD_DEBUG_EVENT
1901 * - EXIT_THREAD_DEBUG_EVENT
1902 *
1903 * We should not get EXCEPTION_DEBUG_EVENT from thread_b as we updated
1904 * its instructions before continuing CREATE_THREAD_DEBUG_EVENT.
1905 */
1906 ctx.ev.dwDebugEventCode = -1;
1907 next_event(&ctx, POLL_EVENT_TIMEOUT);
1908
1909 if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
1910 {
1911 ok(de_a.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1912 "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_a.dwDebugEventCode);
1913 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1914 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1915 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1916 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1917
1918 next_event(&ctx, POLL_EVENT_TIMEOUT);
1919 if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
1920 {
1921 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1922 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1923 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1924 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1925
1926 ret = CloseHandle(thread_a);
1927 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1928 thread_a = NULL;
1929
1930 next_event(&ctx, POLL_EVENT_TIMEOUT);
1931 }
1932
1933 ok(de_b.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1934 "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_b.dwDebugEventCode);
1935 ok(de_b.dwProcessId == ctx.ev.dwProcessId,
1936 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_b.dwProcessId);
1937 ok(de_b.dwThreadId == ctx.ev.dwThreadId,
1938 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_b.dwThreadId);
1939 }
1940 else
1941 {
1942 ok(de_b.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1943 "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_b.dwDebugEventCode);
1944 ok(de_b.dwProcessId == ctx.ev.dwProcessId,
1945 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_b.dwProcessId);
1946 ok(de_b.dwThreadId == ctx.ev.dwThreadId,
1947 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_b.dwThreadId);
1948
1949 next_event(&ctx, POLL_EVENT_TIMEOUT);
1950 if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
1951 {
1952 ok(de_b.dwProcessId == ctx.ev.dwProcessId,
1953 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_b.dwProcessId);
1954 ok(de_b.dwThreadId == ctx.ev.dwThreadId,
1955 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_b.dwThreadId);
1956
1957 ret = CloseHandle(thread_b);
1958 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1959 thread_b = NULL;
1960
1961 next_event(&ctx, POLL_EVENT_TIMEOUT);
1962 }
1963
1964 ok(de_a.dwDebugEventCode == ctx.ev.dwDebugEventCode,
1965 "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_a.dwDebugEventCode);
1966 ok(de_a.dwProcessId == ctx.ev.dwProcessId,
1967 "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId);
1968 ok(de_a.dwThreadId == ctx.ev.dwThreadId,
1969 "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId);
1970 }
1971
1972 if (thread_a)
1973 {
1974 next_event(&ctx, POLL_EVENT_TIMEOUT);
1975 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT,
1976 "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1977
1978 ret = CloseHandle(thread_a);
1979 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1980 }
1981
1982
1983 if (thread_b)
1984 {
1985 next_event(&ctx, POLL_EVENT_TIMEOUT);
1986 ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT,
1987 "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
1988
1989 ret = CloseHandle(thread_b);
1990 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
1991 }
1992 }
1993
1994 if (sizeof(loop_code) > 1)
1995 {
1996 unsigned event_order = 0;
1997
1998 memset(buf, OP_BP, sizeof(buf));
1999 memcpy(proc_code, &loop_code, sizeof(loop_code));
2000 ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL);
2001 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
2002
2003 ctx.thread_tag = 1;
2004
2005 worker_cnt = 20;
2006 for (i = 0; i < worker_cnt; i++)
2007 {
2008 DWORD tid;
2009 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, &tid);
2010 ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError());
2011
2012 do
2013 {
2014 next_event(&ctx, WAIT_EVENT_TIMEOUT);
2015#if defined(__REACTOS__) && defined(_WIN64)
2016 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || broken(GetNTVersion() >= EXCEPTION_DEBUG_EVENT) /* Win8+ x64 */, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
2017#else
2018 ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
2019#endif
2020 } while (ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT && ctx.ev.dwThreadId != tid);
2021#if defined(__REACTOS__) && defined(_WIN64)
2022 ok(ctx.ev.u.CreateThread.lpStartAddress == (void*)thread_proc || broken(GetNTVersion() != _WIN32_WINNT_WIN7), "Unexpected thread's start address\n");
2023#elif defined(__REACTOS__)
2024 ok(ctx.ev.u.CreateThread.lpStartAddress == (void*)thread_proc || broken(GetNTVersion() <= _WIN32_WINNT_VISTA), "Unexpected thread's start address\n");
2025#else
2026 ok(ctx.ev.u.CreateThread.lpStartAddress == (void*)thread_proc, "Unexpected thread's start address\n");
2027#endif
2028
2029 ret = CloseHandle(thread);
2030 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
2031 }
2032
2033 byte = OP_BP;
2034 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
2035 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
2036
2037 wait_for_breakpoint(&ctx);
2038#if defined(__REACTOS__) && defined(_WIN64)
2039 if (GetNTVersion() < _WIN32_WINNT_WIN8)
2040#endif
2041 check_breakpoint_exception(&ctx, thread_proc + 1);
2042 exception_cnt = 1;
2043
2044 byte = 0xc3; /* ret */
2045 ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL);
2046 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
2047
2048 /* One would expect that we get all exception debug events (for the worker threads
2049 * that hit the BP instruction), then the exit thread events for all created threads.
2050 * It happens that on Windows, the exception & exit thread events can be intertwined.
2051 * So detect this situation.
2052 */
2053#if defined(__REACTOS__) && defined(_WIN64)
2054 if (GetNTVersion() >= _WIN32_WINNT_WIN8 || is_reactos()) {
2055 skip("These tests run far too long on Windows 8+ x64 and ReactOS x64.\n");
2056 } else {
2057#endif
2058 for (;;)
2059 {
2060 DEBUG_EVENT ev;
2061
2062 fetch_thread_context(ctx.current_thread);
2063 ok(get_ip(&ctx.current_thread->ctx) == thread_proc + 2
2064 || broken(get_ip(&ctx.current_thread->ctx) == thread_proc), /* sometimes observed on win10 */
2065 "unexpected instruction pointer2 %p (%p)\n", get_ip(&ctx.current_thread->ctx), thread_proc);
2066 /* even when there are more pending events, they are not reported until current event is continued */
2067 ret = WaitForDebugEvent(&ev, 10);
2068 ok(GetLastError() == ERROR_SEM_TIMEOUT, "WaitForDebugEvent returned %x(%lu)\n", ret, GetLastError());
2069
2070 for (;;)
2071 {
2072 next_event_filter(&ctx, POLL_EVENT_TIMEOUT, event_mask(CREATE_THREAD_DEBUG_EVENT));
2073 if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) break;
2074 if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
2075 {
2076 if (event_order == 0) event_order = 1; /* first exit thread event */
2077 if (!--worker_cnt) break;
2078 }
2079 }
2080 if (!worker_cnt) break;
2081
2082 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
2083 trace("exception at %p in thread %04lx\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress, ctx.ev.dwThreadId);
2084 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n",
2085 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
2086 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == thread_proc + 1,
2087 "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress);
2088 exception_cnt++;
2089 if (event_order == 1) event_order = 2; /* exception debug event after exit thread event */
2090 }
2091
2092 trace("received %u exceptions\n", exception_cnt);
2093 ok(!worker_cnt, "Missing %u exit thread events\n", worker_cnt);
2094 ok(event_order == 1 || broken(event_order == 2), "Intertwined exit thread & exception debug events\n");
2095 }
2096#if defined(__REACTOS__) && defined(_WIN64)
2097 }
2098#endif
2099
2100 if (OP_BP)
2101 {
2102 CONTEXT orig_context;
2103 char instr, *ip;
2104
2105 /* main thread sleeps inside ntdll waiting for the event. set breakpoint there and make sure
2106 * ntdll can handle that. */
2107 SuspendThread(ctx.main_thread->handle);
2108
2109 fetch_thread_context(ctx.main_thread);
2110 ret = ReadProcessMemory(pi.hProcess, get_ip(&ctx.main_thread->ctx), &instr, 1, NULL);
2111 ok(ret, "ReadProcessMemory failed: %lu\n", GetLastError());
2112
2113 orig_context = ctx.main_thread->ctx;
2114 ip = get_ip(&ctx.main_thread->ctx);
2115
2116#if defined(__i386__)
2117 ctx.main_thread->ctx.Eax = 101;
2118 ctx.main_thread->ctx.Ebx = 102;
2119 ctx.main_thread->ctx.Ecx = 103;
2120 ctx.main_thread->ctx.Edx = 104;
2121 ctx.main_thread->ctx.Esi = 105;
2122 ctx.main_thread->ctx.Edi = 106;
2123#elif defined(__x86_64__)
2124 ctx.main_thread->ctx.Rax = 101;
2125 ctx.main_thread->ctx.Rbx = 102;
2126 ctx.main_thread->ctx.Rcx = 103;
2127 ctx.main_thread->ctx.Rdx = 104;
2128 ctx.main_thread->ctx.Rsi = 105;
2129 ctx.main_thread->ctx.Rdi = 106;
2130 ctx.main_thread->ctx.R8 = 107;
2131 ctx.main_thread->ctx.R9 = 108;
2132 ctx.main_thread->ctx.R10 = 109;
2133 ctx.main_thread->ctx.R11 = 110;
2134 ctx.main_thread->ctx.R12 = 111;
2135 ctx.main_thread->ctx.R13 = 112;
2136 ctx.main_thread->ctx.R14 = 113;
2137 ctx.main_thread->ctx.R15 = 114;
2138#endif
2139 set_thread_context(&ctx, ctx.main_thread);
2140
2141 fetch_thread_context(ctx.main_thread);
2142#if defined(__i386__)
2143 /* win2k8 do not preserve eax, rcx and edx; newer versions do */
2144 ok(ctx.main_thread->ctx.Ebx == 102, "Ebx = %lx\n", ctx.main_thread->ctx.Ebx);
2145 ok(ctx.main_thread->ctx.Esi == 105, "Esi = %lx\n", ctx.main_thread->ctx.Esi);
2146 ok(ctx.main_thread->ctx.Edi == 106, "Edi = %lx\n", ctx.main_thread->ctx.Edi);
2147#elif defined(__x86_64__)
2148 ok(ctx.main_thread->ctx.Rax == 101, "Rax = %I64x\n", ctx.main_thread->ctx.Rax);
2149 ok(ctx.main_thread->ctx.Rbx == 102, "Rbx = %I64x\n", ctx.main_thread->ctx.Rbx);
2150 ok(ctx.main_thread->ctx.Rcx == 103, "Rcx = %I64x\n", ctx.main_thread->ctx.Rcx);
2151 ok(ctx.main_thread->ctx.Rdx == 104, "Rdx = %I64x\n", ctx.main_thread->ctx.Rdx);
2152 ok(ctx.main_thread->ctx.Rsi == 105, "Rsi = %I64x\n", ctx.main_thread->ctx.Rsi);
2153 ok(ctx.main_thread->ctx.Rdi == 106, "Rdi = %I64x\n", ctx.main_thread->ctx.Rdi);
2154 ok(ctx.main_thread->ctx.R8 == 107, "R8 = %I64x\n", ctx.main_thread->ctx.R8);
2155 ok(ctx.main_thread->ctx.R9 == 108, "R9 = %I64x\n", ctx.main_thread->ctx.R9);
2156 ok(ctx.main_thread->ctx.R10 == 109, "R10 = %I64x\n", ctx.main_thread->ctx.R10);
2157 ok(ctx.main_thread->ctx.R11 == 110, "R11 = %I64x\n", ctx.main_thread->ctx.R11);
2158 ok(ctx.main_thread->ctx.R12 == 111, "R12 = %I64x\n", ctx.main_thread->ctx.R12);
2159 ok(ctx.main_thread->ctx.R13 == 112, "R13 = %I64x\n", ctx.main_thread->ctx.R13);
2160 ok(ctx.main_thread->ctx.R14 == 113, "R14 = %I64x\n", ctx.main_thread->ctx.R14);
2161 ok(ctx.main_thread->ctx.R15 == 114, "R15 = %I64x\n", ctx.main_thread->ctx.R15);
2162#endif
2163
2164 byte = OP_BP;
2165 ret = WriteProcessMemory(pi.hProcess, ip, &byte, 1, NULL);
2166 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
2167
2168 SetEvent(event);
2169 ResumeThread(ctx.main_thread->handle);
2170
2171 next_event_filter(&ctx, 2000, event_mask(CREATE_THREAD_DEBUG_EVENT));
2172 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
2173 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n",
2174 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
2175 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == ip,
2176 "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress);
2177
2178 fetch_thread_context(ctx.main_thread);
2179 ok(get_ip(&ctx.main_thread->ctx) == ip + 1, "unexpected instruction pointer %p\n", get_ip(&ctx.main_thread->ctx));
2180
2181#if defined(__i386__)
2182 ok(ctx.main_thread->ctx.Eax == 0, "Eax = %lx\n", ctx.main_thread->ctx.Eax);
2183 ok(ctx.main_thread->ctx.Ebx == 102, "Ebx = %lx\n", ctx.main_thread->ctx.Ebx);
2184 ok(ctx.main_thread->ctx.Ecx != 103, "Ecx = %lx\n", ctx.main_thread->ctx.Ecx);
2185 ok(ctx.main_thread->ctx.Edx != 104, "Edx = %lx\n", ctx.main_thread->ctx.Edx);
2186 ok(ctx.main_thread->ctx.Esi == 105, "Esi = %lx\n", ctx.main_thread->ctx.Esi);
2187 ok(ctx.main_thread->ctx.Edi == 106, "Edi = %lx\n", ctx.main_thread->ctx.Edi);
2188#elif defined(__x86_64__)
2189 ok(ctx.main_thread->ctx.Rax == 0, "Rax = %I64x\n", ctx.main_thread->ctx.Rax);
2190 ok(ctx.main_thread->ctx.Rbx == 102, "Rbx = %I64x\n", ctx.main_thread->ctx.Rbx);
2191 ok(ctx.main_thread->ctx.Rcx != 103, "Rcx = %I64x\n", ctx.main_thread->ctx.Rcx);
2192 ok(ctx.main_thread->ctx.Rdx != 104, "Rdx = %I64x\n", ctx.main_thread->ctx.Rdx);
2193 ok(ctx.main_thread->ctx.Rsi == 105, "Rsi = %I64x\n", ctx.main_thread->ctx.Rsi);
2194 ok(ctx.main_thread->ctx.Rdi == 106, "Rdi = %I64x\n", ctx.main_thread->ctx.Rdi);
2195 ok(ctx.main_thread->ctx.R8 != 107, "R8 = %I64x\n", ctx.main_thread->ctx.R8);
2196 ok(ctx.main_thread->ctx.R9 != 108, "R9 = %I64x\n", ctx.main_thread->ctx.R9);
2197 ok(ctx.main_thread->ctx.R10 != 109, "R10 = %I64x\n", ctx.main_thread->ctx.R10);
2198 ok(ctx.main_thread->ctx.R11 != 110, "R11 = %I64x\n", ctx.main_thread->ctx.R11);
2199 ok(ctx.main_thread->ctx.R12 == 111, "R12 = %I64x\n", ctx.main_thread->ctx.R12);
2200 ok(ctx.main_thread->ctx.R13 == 112, "R13 = %I64x\n", ctx.main_thread->ctx.R13);
2201 ok(ctx.main_thread->ctx.R14 == 113, "R14 = %I64x\n", ctx.main_thread->ctx.R14);
2202 ok(ctx.main_thread->ctx.R15 == 114, "R15 = %I64x\n", ctx.main_thread->ctx.R15);
2203#endif
2204
2205 ctx.main_thread->ctx = orig_context;
2206 set_ip(&ctx.main_thread->ctx, ip);
2207 set_thread_context(&ctx, ctx.main_thread);
2208
2209 ret = WriteProcessMemory(pi.hProcess, ip, &instr, 1, NULL);
2210 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
2211
2212 memset(buf + 10, 0x90, 10); /* nop */
2213 ret = WriteProcessMemory(pi.hProcess, mem + 10, buf + 10, 10, NULL);
2214 ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError());
2215
2216 next_event(&ctx, POLL_EVENT_TIMEOUT);
2217
2218 /* try single step while debuggee is in a syscall */
2219 fetch_thread_context(ctx.main_thread);
2220 orig_context = ctx.main_thread->ctx;
2221 ip = get_ip(&ctx.main_thread->ctx);
2222
2223#if defined(__i386__)
2224 ctx.main_thread->ctx.EFlags |= 0x100;
2225 ctx.main_thread->ctx.Eip = (ULONG_PTR)mem + 10;
2226#elif defined(__x86_64__)
2227 ctx.main_thread->ctx.EFlags |= 0x100;
2228 ctx.main_thread->ctx.Rip = (ULONG64)mem + 10;
2229#endif
2230 set_thread_context(&ctx, ctx.main_thread);
2231
2232 SetEvent(event);
2233
2234 next_event(&ctx, WAIT_EVENT_TIMEOUT);
2235 if (sizeof(void*) != 4 || ctx.ev.u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT)
2236 {
2237 ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode);
2238 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP, "ExceptionCode = %lx\n",
2239 ctx.ev.u.Exception.ExceptionRecord.ExceptionCode);
2240 ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == mem + 10 ||
2241 ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == mem + 11,
2242 "ExceptionAddress = %p expected %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress, mem + 10);
2243
2244 fetch_thread_context(ctx.main_thread);
2245 ok(get_ip(&ctx.main_thread->ctx) == ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress,
2246 "ip = %p\n", get_ip(&ctx.main_thread->ctx));
2247
2248 }
2249 else win_skip("got breakpoint instead of single step exception\n");
2250
2251 ctx.main_thread->ctx = orig_context;
2252 set_thread_context(&ctx, ctx.main_thread);
2253 }
2254
2255 SetEvent(event);
2256
2257#if defined(__REACTOS__) && defined(_MSC_VER)
2258 if (is_reactos()) {
2259 skip("This test doesn't work correctly on MSVC ReactOS.\n");
2260 } else {
2261#endif
2262 do
2263 {
2264 next_event(&ctx, WAIT_EVENT_TIMEOUT);
2265 ok (ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "got exception\n");
2266 if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) break;
2267 }
2268 while (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
2269 if (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) TerminateProcess(pi.hProcess, 0);
2270#if defined(__REACTOS__) && defined(_MSC_VER)
2271 }
2272#endif
2273
2274 ret = CloseHandle(event);
2275 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
2276 ret = CloseHandle(pi.hThread);
2277 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
2278 ret = CloseHandle(pi.hProcess);
2279 ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
2280}
2281
2282static DWORD run_child_wait( char *cmd, HANDLE event )
2283{
2284 PROCESS_INFORMATION pi;
2285 STARTUPINFOA si = { sizeof(si) };
2286 BOOL ret;
2287 DWORD exit_code;
2288
2289 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
2290 ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError());
2291 Sleep(200);
2292 CloseHandle( pDbgUiGetThreadDebugObject() );
2293 pDbgUiSetThreadDebugObject( 0 );
2294 SetEvent( event );
2295 WaitForSingleObject( pi.hProcess, 1000 );
2296 ret = GetExitCodeProcess( pi.hProcess, &exit_code );
2297 ok( ret, "GetExitCodeProcess failed err=%ld\n", GetLastError());
2298 CloseHandle( pi.hProcess );
2299 CloseHandle( pi.hThread );
2300 return exit_code;
2301}
2302
2303static PROCESS_INFORMATION pi;
2304static char *cmd;
2305
2306static DWORD WINAPI debug_and_exit(void *arg)
2307{
2308 STARTUPINFOA si = { sizeof(si) };
2309 HANDLE debug;
2310 ULONG val = 0;
2311 NTSTATUS status;
2312 BOOL ret;
2313
2314 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
2315 ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError());
2316 debug = pDbgUiGetThreadDebugObject();
2317 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2318 &val, sizeof(val), NULL );
2319 ok( !status, "NtSetInformationDebugObject failed %lx\n", status );
2320 *(HANDLE *)arg = debug;
2321 Sleep(200);
2322 ExitThread(0);
2323}
2324
2325static DWORD WINAPI debug_and_wait(void *arg)
2326{
2327 STARTUPINFOA si = { sizeof(si) };
2328 HANDLE debug = *(HANDLE *)arg;
2329 ULONG val = 0;
2330 NTSTATUS status;
2331 BOOL ret;
2332
2333 pDbgUiSetThreadDebugObject( debug );
2334 ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
2335 ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError());
2336 debug = pDbgUiGetThreadDebugObject();
2337 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2338 &val, sizeof(val), NULL );
2339 ok( !status, "NtSetInformationDebugObject failed %lx\n", status );
2340 Sleep(INFINITE);
2341 ExitThread(0);
2342}
2343
2344static DWORD WINAPI create_debug_port(void *arg)
2345{
2346 STARTUPINFOA si = { sizeof(si) };
2347 NTSTATUS status = pDbgUiConnectToDbg();
2348
2349 ok( !status, "DbgUiConnectToDbg failed %lx\n", status );
2350 *(HANDLE *)arg = pDbgUiGetThreadDebugObject();
2351 Sleep( INFINITE );
2352 ExitThread(0);
2353}
2354
2355static void test_kill_on_exit(const char *argv0)
2356{
2357 static const char arguments[] = " debugger wait ";
2358 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
2359 OBJECT_ATTRIBUTES attr = { sizeof(attr) };
2360 NTSTATUS status;
2361 HANDLE event, debug, thread;
2362 DWORD exit_code, tid;
2363 ULONG val;
2364 BOOL ret;
2365
2366 event = CreateEventW(&sa, FALSE, FALSE, NULL);
2367 ok(event != NULL, "CreateEvent failed: %lu\n", GetLastError());
2368
2369 cmd = heap_alloc(strlen(argv0) + strlen(arguments) + 16);
2370 sprintf(cmd, "%s%s%lx\n", argv0, arguments, (DWORD)(DWORD_PTR)event);
2371
2372 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 );
2373 ok( !status, "NtCreateDebugObject failed %lx\n", status );
2374 pDbgUiSetThreadDebugObject( debug );
2375 exit_code = run_child_wait( cmd, event );
2376 ok( exit_code == 0, "exit code = %08lx\n", exit_code);
2377
2378 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
2379 ok( !status, "NtCreateDebugObject failed %lx\n", status );
2380 pDbgUiSetThreadDebugObject( debug );
2381 exit_code = run_child_wait( cmd, event );
2382 ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08lx\n", exit_code);
2383
2384 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0xfffe );
2385 ok( status == STATUS_INVALID_PARAMETER, "NtCreateDebugObject failed %lx\n", status );
2386
2387 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 );
2388 ok( !status, "NtCreateDebugObject failed %lx\n", status );
2389 pDbgUiSetThreadDebugObject( debug );
2390 val = DEBUG_KILL_ON_CLOSE;
2391 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2392 &val, sizeof(val), NULL );
2393 ok( !status, "NtSetInformationDebugObject failed %lx\n", status );
2394 exit_code = run_child_wait( cmd, event );
2395 ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08lx\n", exit_code);
2396
2397 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
2398 ok( !status, "NtCreateDebugObject failed %lx\n", status );
2399 pDbgUiSetThreadDebugObject( debug );
2400 val = 0;
2401 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2402 &val, sizeof(val), NULL );
2403 ok( !status, "NtSetInformationDebugObject failed %lx\n", status );
2404 exit_code = run_child_wait( cmd, event );
2405 ok( exit_code == 0, "exit code = %08lx\n", exit_code);
2406
2407 status = pDbgUiConnectToDbg();
2408 ok( !status, "DbgUiConnectToDbg failed %lx\n", status );
2409 exit_code = run_child_wait( cmd, event );
2410 ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08lx\n", exit_code);
2411
2412 /* test that threads close the debug port on exit */
2413 thread = CreateThread(NULL, 0, debug_and_exit, &debug, 0, &tid);
2414 WaitForSingleObject( thread, 1000 );
2415 ok( debug != 0, "no debug port\n" );
2416 val = 0;
2417 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2418 &val, sizeof(val), NULL );
2419 ok( status == STATUS_INVALID_HANDLE || broken(status == STATUS_SUCCESS), /* wow64 */
2420 "NtSetInformationDebugObject failed %lx\n", status );
2421 SetEvent( event );
2422 if (!status)
2423 {
2424 WaitForSingleObject( pi.hProcess, 100 );
2425 GetExitCodeProcess( pi.hProcess, &exit_code );
2426 ok( exit_code == STILL_ACTIVE, "exit code = %08lx\n", exit_code);
2427 CloseHandle( debug );
2428 }
2429 WaitForSingleObject( pi.hProcess, 1000 );
2430 GetExitCodeProcess( pi.hProcess, &exit_code );
2431 ok( exit_code == 0, "exit code = %08lx\n", exit_code);
2432 CloseHandle( pi.hProcess );
2433 CloseHandle( pi.hThread );
2434 CloseHandle( thread );
2435
2436 /* checking on forced exit */
2437 status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
2438 ok( !status, "NtCreateDebugObject failed %lx\n", status );
2439 thread = CreateThread(NULL, 0, debug_and_wait, &debug, 0, &tid);
2440 Sleep( 100 );
2441 ok( debug != 0, "no debug port\n" );
2442 val = DEBUG_KILL_ON_CLOSE;
2443 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2444 &val, sizeof(val), NULL );
2445 ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %lx\n", status );
2446 TerminateThread( thread, 0 );
2447
2448 status = WaitForSingleObject( pi.hProcess, 1500 );
2449 if (status != WAIT_OBJECT_0)
2450 {
2451 todo_wine /* Wine doesn't handle debug port of TerminateThread */
2452 ok(broken(sizeof(void*) == sizeof(int)), /* happens consistently on 32bit on Win7, 10 & 11 */
2453 "Terminating thread should terminate debuggee\n");
2454
2455 ret = TerminateProcess( pi.hProcess, 0 );
2456 ok(ret, "TerminateProcess failed: %lu\n", GetLastError());
2457 CloseHandle( debug );
2458 }
2459 else
2460 {
2461 ok(status == WAIT_OBJECT_0, "debuggee didn't terminate %lx\n", status);
2462 ret = GetExitCodeProcess( pi.hProcess, &exit_code );
2463 ok(ret, "No exit code: %lu\n", GetLastError());
2464 todo_wine
2465 ok( exit_code == STATUS_DEBUGGER_INACTIVE || broken(exit_code == STILL_ACTIVE), /* wow64 */
2466 "exit code = %08lx\n", exit_code);
2467 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2468 &val, sizeof(val), NULL );
2469 todo_wine
2470 ok( status == STATUS_INVALID_HANDLE, "NtSetInformationDebugObject failed %lx\n", status );
2471 }
2472
2473 CloseHandle( pi.hProcess );
2474 CloseHandle( pi.hThread );
2475 CloseHandle( thread );
2476
2477 debug = 0;
2478 thread = CreateThread(NULL, 0, create_debug_port, &debug, 0, &tid);
2479 Sleep(100);
2480 ok( debug != 0, "no debug port\n" );
2481 val = 0;
2482 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2483 &val, sizeof(val), NULL );
2484 ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %lx\n", status );
2485 TerminateThread( thread, 0 );
2486 Sleep( 200 );
2487 status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
2488 &val, sizeof(val), NULL );
2489 todo_wine
2490 ok( status == STATUS_INVALID_HANDLE || broken( status == STATUS_SUCCESS ),
2491 "NtSetInformationDebugObject failed %lx\n", status );
2492 if (status != STATUS_INVALID_HANDLE) CloseHandle( debug );
2493 CloseHandle( thread );
2494
2495 CloseHandle( event );
2496 heap_free(cmd);
2497}
2498
2499START_TEST(debugger)
2500{
2501 HMODULE hdll;
2502
2503 hdll=GetModuleHandleA("kernel32.dll");
2504 pCheckRemoteDebuggerPresent=(void*)GetProcAddress(hdll, "CheckRemoteDebuggerPresent");
2505 pIsWow64Process=(void*)GetProcAddress(hdll, "IsWow64Process");
2506 pGetMappedFileNameW = (void*)GetProcAddress(hdll, "GetMappedFileNameW");
2507 if (!pGetMappedFileNameW) pGetMappedFileNameW = (void*)GetProcAddress(LoadLibraryA("psapi.dll"),
2508 "GetMappedFileNameW");
2509 ntdll = GetModuleHandleA("ntdll.dll");
2510 pDbgBreakPoint = (void*)GetProcAddress(ntdll, "DbgBreakPoint");
2511 pNtSuspendProcess = (void*)GetProcAddress(ntdll, "NtSuspendProcess");
2512 pNtResumeProcess = (void*)GetProcAddress(ntdll, "NtResumeProcess");
2513 pNtCreateDebugObject = (void*)GetProcAddress(ntdll, "NtCreateDebugObject");
2514 pNtSetInformationDebugObject = (void*)GetProcAddress(ntdll, "NtSetInformationDebugObject");
2515 pDbgUiConnectToDbg = (void*)GetProcAddress(ntdll, "DbgUiConnectToDbg");
2516 pDbgUiGetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiGetThreadDebugObject");
2517 pDbgUiSetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiSetThreadDebugObject");
2518
2519#ifdef __arm__
2520 /* mask thumb bit for address comparisons */
2521 pDbgBreakPoint = (void *)((ULONG_PTR)pDbgBreakPoint & ~1);
2522#endif
2523
2524 if (pIsWow64Process) pIsWow64Process( GetCurrentProcess(), &is_wow64 );
2525
2526 myARGC=winetest_get_mainargs(&myARGV);
2527 if (myARGC >= 3 && strcmp(myARGV[2], "crash") == 0)
2528 {
2529 doCrash();
2530 }
2531 else if (myARGC >= 3 && strncmp(myARGV[2], "dbg,", 4) == 0)
2532 {
2533 doDebugger(myARGC, myARGV);
2534 }
2535 else if (myARGC >= 5 && !strcmp(myARGV[2], "child"))
2536 {
2537 doChild(myARGC, myARGV);
2538 }
2539 else if (myARGC >= 4 && !strcmp(myARGV[2], "children"))
2540 {
2541 doChildren(myARGC, myARGV);
2542 }
2543 else if (myARGC >= 4 && !strcmp(myARGV[2], "wait"))
2544 {
2545 DWORD event, cnt = 1;
2546 sscanf(myARGV[3], "%lx", &event);
2547 if (myARGC >= 5) cnt = atoi(myARGV[4]);
2548 wait_debugger((HANDLE)(DWORD_PTR)event, cnt);
2549 }
2550 else
2551 {
2552 test_ExitCode();
2553 test_RemoteDebugger();
2554 test_debug_loop(myARGC, myARGV);
2555 test_debug_loop_wow64();
2556 test_debug_children(myARGV[0], DEBUG_PROCESS, TRUE, FALSE);
2557 test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE);
2558 test_debug_children(myARGV[0], DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE);
2559 test_debug_children(myARGV[0], 0, FALSE, FALSE);
2560 test_debug_children(myARGV[0], 0, FALSE, TRUE);
2561 test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, TRUE);
2562 test_debugger(myARGV[0]);
2563 test_kill_on_exit(myARGV[0]);
2564 }
2565}