Reactos
at master 2565 lines 103 kB view raw
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}