ReactOS 0.4.16-dev-117-g38f21f9
debugger.c
Go to the documentation of this file.
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 <windows.h>
25#include <winternl.h>
26#include <winreg.h>
27#include "wine/test.h"
28
29#ifndef STATUS_DEBUGGER_INACTIVE
30#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354)
31#endif
32
33#define child_ok (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_child_ok
34
35static int myARGC;
36static char** myARGV;
37
38static BOOL (WINAPI *pCheckRemoteDebuggerPresent)(HANDLE,PBOOL);
39static BOOL (WINAPI *pDebugActiveProcessStop)(DWORD);
40static BOOL (WINAPI *pDebugSetProcessKillOnExit)(BOOL);
41static BOOL (WINAPI *pIsDebuggerPresent)(void);
42
44
45static void WINETEST_PRINTF_ATTR(2, 3) test_child_ok(int condition, const char *msg, ...)
46{
48
53}
54
55/* Copied from the process test */
56static void get_file_name(char* buf)
57{
58 char path[MAX_PATH];
59
60 buf[0] = '\0';
61 GetTempPathA(sizeof(path), path);
62 GetTempFileNameA(path, "wt", 0, buf);
63}
64
65typedef struct tag_reg_save_value
66{
67 const char *name;
72
73static DWORD save_value(HKEY hkey, const char *value, reg_save_value *saved)
74{
75 DWORD ret;
76 saved->name=value;
77 saved->data=0;
78 saved->size=0;
79 ret=RegQueryValueExA(hkey, value, NULL, &saved->type, NULL, &saved->size);
80 if (ret == ERROR_SUCCESS)
81 {
82 saved->data=HeapAlloc(GetProcessHeap(), 0, saved->size);
83 RegQueryValueExA(hkey, value, NULL, &saved->type, saved->data, &saved->size);
84 }
85 return ret;
86}
87
88static void restore_value(HKEY hkey, reg_save_value *saved)
89{
90 if (saved->data)
91 {
92 RegSetValueExA(hkey, saved->name, 0, saved->type, saved->data, saved->size);
93 HeapFree(GetProcessHeap(), 0, saved->data);
94 }
95 else
96 RegDeleteValueA(hkey, saved->name);
97}
98
99static void get_events(const char* name, HANDLE *start_event, HANDLE *done_event)
100{
101 const char* basename;
102 char* event_name;
103
104 basename=strrchr(name, '\\');
106 event_name=HeapAlloc(GetProcessHeap(), 0, 6+strlen(basename)+1);
107
108 sprintf(event_name, "start_%s", basename);
109 *start_event=CreateEventA(NULL, 0,0, event_name);
110 sprintf(event_name, "done_%s", basename);
111 *done_event=CreateEventA(NULL, 0,0, event_name);
112 HeapFree(GetProcessHeap(), 0, event_name);
113}
114
115static void save_blackbox(const char* logfile, void* blackbox, int size)
116{
118 DWORD written;
119
120 hFile=CreateFileA(logfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
122 return;
123 WriteFile(hFile, blackbox, size, &written, NULL);
125}
126
127static int load_blackbox(const char* logfile, void* blackbox, int size)
128{
130 DWORD read;
131 BOOL ret;
132
133 hFile=CreateFileA(logfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
135 {
136 ok(0, "unable to open '%s'\n", logfile);
137 return 0;
138 }
139 SetLastError(0xdeadbeef);
140 ret=ReadFile(hFile, blackbox, size, &read, NULL);
141 ok(ret, "ReadFile failed: %d\n", GetLastError());
142 ok(read == size, "wrong size for '%s': read=%d\n", logfile, read);
144 return 1;
145}
146
147typedef struct
148{
151
152static void doCrash(int argc, char** argv)
153{
154 volatile char* p;
155
156 /* make sure the exception gets to the debugger */
157 SetErrorMode( 0 );
159
160 if (argc >= 4)
161 {
162 crash_blackbox_t blackbox;
163 blackbox.pid=GetCurrentProcessId();
164 save_blackbox(argv[3], &blackbox, sizeof(blackbox));
165 }
166
167 /* Just crash */
168 trace("child: crashing...\n");
169 p=NULL;
170 *p=0;
171}
172
173typedef struct
174{
175 int argc;
186
187static void doDebugger(int argc, char** argv)
188{
189 const char* logfile;
190 debugger_blackbox_t blackbox;
191 HANDLE start_event = 0, done_event = 0, debug_event;
192
193 blackbox.argc=argc;
194 logfile=(argc >= 4 ? argv[3] : NULL);
195 blackbox.pid=(argc >= 5 ? atol(argv[4]) : 0);
196
197 blackbox.attach_err=0;
198 if (strstr(myARGV[2], "attach"))
199 {
200 blackbox.attach_rc=DebugActiveProcess(blackbox.pid);
201 if (!blackbox.attach_rc)
202 blackbox.attach_err=GetLastError();
203 }
204 else
205 blackbox.attach_rc=TRUE;
206
207 debug_event=(argc >= 6 ? (HANDLE)(INT_PTR)atol(argv[5]) : NULL);
208 blackbox.debug_err=0;
209 if (debug_event && strstr(myARGV[2], "event"))
210 {
211 blackbox.debug_rc=SetEvent(debug_event);
212 if (!blackbox.debug_rc)
213 blackbox.debug_err=GetLastError();
214 }
215 else
216 blackbox.debug_rc=TRUE;
217
218 if (logfile)
219 {
220 get_events(logfile, &start_event, &done_event);
221 }
222
223 if (strstr(myARGV[2], "order"))
224 {
225 trace("debugger: waiting for the start signal...\n");
227 }
228
229 blackbox.nokill_err=0;
230 if (strstr(myARGV[2], "nokill"))
231 {
232 blackbox.nokill_rc=pDebugSetProcessKillOnExit(FALSE);
233 if (!blackbox.nokill_rc)
234 blackbox.nokill_err=GetLastError();
235 }
236 else
237 blackbox.nokill_rc=TRUE;
238
239 blackbox.detach_err=0;
240 if (strstr(myARGV[2], "detach"))
241 {
242 blackbox.detach_rc=pDebugActiveProcessStop(blackbox.pid);
243 if (!blackbox.detach_rc)
244 blackbox.detach_err=GetLastError();
245 }
246 else
247 blackbox.detach_rc=TRUE;
248
249 if (logfile)
250 {
251 save_blackbox(logfile, &blackbox, sizeof(blackbox));
252 }
253 trace("debugger: done debugging...\n");
254 SetEvent(done_event);
255
256 /* Just exit with a known value */
257 ExitProcess(0xdeadbeef);
258}
259
260static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks)
261{
262 static BOOL skip_crash_and_debug = FALSE;
263 BOOL bRet;
264 DWORD ret;
265 HANDLE start_event, done_event;
266 char* cmd;
267 char dbglog[MAX_PATH];
268 char childlog[MAX_PATH];
272 crash_blackbox_t crash_blackbox;
273 debugger_blackbox_t dbg_blackbox;
274 DWORD wait_code;
275
276 if (skip_crash_and_debug)
277 {
278 win_skip("Skipping crash_and_debug\n");
279 return;
280 }
281
282 ret=RegSetValueExA(hkey, "auto", 0, REG_SZ, (BYTE*)"1", 2);
284 {
285 skip_crash_and_debug = TRUE;
286 skip("No write access to change the debugger\n");
287 return;
288 }
289
290 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%d\n", ret);
291
292 get_file_name(dbglog);
293 get_events(dbglog, &start_event, &done_event);
294 cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+10+strlen(dbgtasks)+1+strlen(dbglog)+2+34+1);
295 sprintf(cmd, "%s debugger %s \"%s\" %%ld %%ld", argv0, dbgtasks, dbglog);
296 ret=RegSetValueExA(hkey, "debugger", 0, REG_SZ, (BYTE*)cmd, strlen(cmd)+1);
297 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/debugger: ret=%d\n", ret);
299
300 get_file_name(childlog);
301 cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+16+strlen(dbglog)+2+1);
302 sprintf(cmd, "%s debugger crash \"%s\"", argv0, childlog);
303
304 memset(&startup, 0, sizeof(startup));
305 startup.cb = sizeof(startup);
307 startup.wShowWindow = SW_SHOWNORMAL;
309 ok(ret, "CreateProcess: err=%d\n", GetLastError());
311 CloseHandle(info.hThread);
312
313 /* The process exits... */
314 trace("waiting for child exit...\n");
315 wait_code = WaitForSingleObject(info.hProcess, 30000);
316#if defined(_WIN64) && defined(__MINGW32__)
317 /* Mingw x64 doesn't output proper unwind info */
318 skip_crash_and_debug = broken(wait_code == WAIT_TIMEOUT);
319 if (skip_crash_and_debug)
320 {
322 WaitForSingleObject(info.hProcess, 5000);
323 CloseHandle(info.hProcess);
324 DeleteFileA(dbglog);
325 DeleteFileA(childlog);
326 win_skip("Giving up on child process\n");
327 return;
328 }
329#endif
330 ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n");
331 bRet = GetExitCodeProcess(info.hProcess, &exit_code);
332 ok(bRet, "GetExitCodeProcess failed: err=%d\n", GetLastError());
333 if (strstr(dbgtasks, "code2"))
334 {
335 /* If, after attaching to the debuggee, the debugger exits without
336 * detaching, then the debuggee gets a special exit code.
337 */
339 broken(exit_code == STATUS_ACCESS_VIOLATION) || /* Intermittent Vista+ */
340 broken(exit_code == WAIT_ABANDONED), /* NT4, W2K */
341 "wrong exit code : %08x\n", exit_code);
342 }
343 else
345 broken(exit_code == WAIT_ABANDONED), /* NT4, W2K, W2K3 */
346 "wrong exit code : %08x\n", exit_code);
347 CloseHandle(info.hProcess);
348
349 /* ...before the debugger */
350 if (strstr(dbgtasks, "order"))
351 ok(SetEvent(start_event), "SetEvent(start_event) failed\n");
352
353 trace("waiting for the debugger...\n");
354 wait_code = WaitForSingleObject(done_event, 5000);
355#if defined(_WIN64) && defined(__MINGW32__)
356 /* Mingw x64 doesn't output proper unwind info */
357 skip_crash_and_debug = broken(wait_code == WAIT_TIMEOUT);
358 if (skip_crash_and_debug)
359 {
360 DeleteFileA(dbglog);
361 DeleteFileA(childlog);
362 win_skip("Giving up on debugger\n");
363 return;
364 }
365#endif
366 ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the debugger\n");
367
368 ok(load_blackbox(childlog, &crash_blackbox, sizeof(crash_blackbox)), "failed to open: %s\n", childlog);
369 ok(load_blackbox(dbglog, &dbg_blackbox, sizeof(dbg_blackbox)), "failed to open: %s\n", dbglog);
370
371 ok(dbg_blackbox.argc == 6, "wrong debugger argument count: %d\n", dbg_blackbox.argc);
372 ok(dbg_blackbox.pid == crash_blackbox.pid, "the child and debugged pids don't match: %d != %d\n", crash_blackbox.pid, dbg_blackbox.pid);
373 ok(dbg_blackbox.debug_rc, "debugger: SetEvent(debug_event) failed err=%d\n", dbg_blackbox.debug_err);
374 ok(dbg_blackbox.attach_rc, "DebugActiveProcess(%d) failed err=%d\n", dbg_blackbox.pid, dbg_blackbox.attach_err);
375 ok(dbg_blackbox.nokill_rc, "DebugSetProcessKillOnExit(FALSE) failed err=%d\n", dbg_blackbox.nokill_err);
376 ok(dbg_blackbox.detach_rc, "DebugActiveProcessStop(%d) failed err=%d\n", dbg_blackbox.pid, dbg_blackbox.detach_err);
377
378 DeleteFileA(dbglog);
379 DeleteFileA(childlog);
380}
381
382static void crash_and_winedbg(HKEY hkey, const char* argv0)
383{
384 BOOL bRet;
385 DWORD ret;
386 char* cmd;
390
391 ret=RegSetValueExA(hkey, "auto", 0, REG_SZ, (BYTE*)"1", 2);
392 ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%d\n", ret);
393
395 sprintf(cmd, "%s debugger crash", argv0);
396
397 memset(&startup, 0, sizeof(startup));
398 startup.cb = sizeof(startup);
400 startup.wShowWindow = SW_SHOWNORMAL;
402 ok(ret, "CreateProcess: err=%d\n", GetLastError());
404 CloseHandle(info.hThread);
405
406 trace("waiting for child exit...\n");
407 ok(WaitForSingleObject(info.hProcess, 60000) == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n");
408 bRet = GetExitCodeProcess(info.hProcess, &exit_code);
409 ok(bRet, "GetExitCodeProcess failed: err=%d\n", GetLastError());
410 ok(exit_code == STATUS_ACCESS_VIOLATION, "exit code = %08x\n", exit_code);
411 CloseHandle(info.hProcess);
412}
413
414static void test_ExitCode(void)
415{
416 static const char* AeDebug="Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug";
417 static const char* WineDbg="Software\\Wine\\WineDbg";
418 char test_exe[MAX_PATH];
419 DWORD ret;
420 HKEY hkey;
421 DWORD disposition;
422 reg_save_value auto_value;
423 reg_save_value debugger_value;
424
425 GetModuleFileNameA(GetModuleHandleA(NULL), test_exe, sizeof(test_exe));
427 strcat(test_exe, ".so");
429 {
430 ok(0, "could not find the test executable '%s'\n", test_exe);
431 return;
432 }
433
435 if (ret == ERROR_SUCCESS)
436 {
437 save_value(hkey, "auto", &auto_value);
438 save_value(hkey, "debugger", &debugger_value);
439 trace("HKLM\\%s\\debugger is set to '%s'\n", AeDebug, debugger_value.data);
440 }
441 else if (ret == ERROR_ACCESS_DENIED)
442 {
443 skip("not enough privileges to change the debugger\n");
444 return;
445 }
446 else if (ret != ERROR_FILE_NOT_FOUND)
447 {
448 ok(0, "could not open the AeDebug key: %d\n", ret);
449 return;
450 }
451 else debugger_value.data = NULL;
452
453 if (debugger_value.data && debugger_value.type == REG_SZ &&
454 strstr((char*)debugger_value.data, "winedbg --auto"))
455 {
456 HKEY hkeyWinedbg;
457 ret=RegCreateKeyA(HKEY_CURRENT_USER, WineDbg, &hkeyWinedbg);
458 if (ret == ERROR_SUCCESS)
459 {
460 static DWORD zero;
461 reg_save_value crash_dlg_value;
462 save_value(hkeyWinedbg, "ShowCrashDialog", &crash_dlg_value);
463 RegSetValueExA(hkeyWinedbg, "ShowCrashDialog", 0, REG_DWORD, (BYTE *)&zero, sizeof(DWORD));
464 crash_and_winedbg(hkey, test_exe);
465 restore_value(hkeyWinedbg, &crash_dlg_value);
466 RegCloseKey(hkeyWinedbg);
467 }
468 else
469 ok(0, "Couldn't access WineDbg Key - error %u\n", ret);
470 }
471
473 /* Since the debugging process never sets the debug event, it isn't recognized
474 as a valid debugger and, after the debugger exits, Windows will show a dialog box
475 asking the user what to do */
476 crash_and_debug(hkey, test_exe, "dbg,none");
477 else
478 skip("\"none\" debugger test needs user interaction\n");
479 ok(disposition == REG_OPENED_EXISTING_KEY, "expected REG_OPENED_EXISTING_KEY, got %d\n", disposition);
480 crash_and_debug(hkey, test_exe, "dbg,event,order");
481 crash_and_debug(hkey, test_exe, "dbg,attach,event,code2");
482 if (pDebugSetProcessKillOnExit)
483 crash_and_debug(hkey, test_exe, "dbg,attach,event,nokill");
484 else
485 win_skip("DebugSetProcessKillOnExit is not available\n");
486 if (pDebugActiveProcessStop)
487 crash_and_debug(hkey, test_exe, "dbg,attach,event,detach");
488 else
489 win_skip("DebugActiveProcessStop is not available\n");
490
491 if (disposition == REG_CREATED_NEW_KEY)
492 {
493 RegCloseKey(hkey);
495 }
496 else
497 {
498 restore_value(hkey, &auto_value);
499 restore_value(hkey, &debugger_value);
500 RegCloseKey(hkey);
501 }
502}
503
504static void test_RemoteDebugger(void)
505{
506 BOOL bret, present;
507 if(!pCheckRemoteDebuggerPresent)
508 {
509 win_skip("CheckRemoteDebuggerPresent is not available\n");
510 return;
511 }
512 present = TRUE;
513 SetLastError(0xdeadbeef);
514 bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),&present);
515 ok(bret , "expected CheckRemoteDebuggerPresent to succeed\n");
516 ok(0xdeadbeef == GetLastError(),
517 "expected error to be unchanged, got %d/%x\n",GetLastError(), GetLastError());
518
519 present = TRUE;
520 SetLastError(0xdeadbeef);
521 bret = pCheckRemoteDebuggerPresent(NULL,&present);
522 ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n");
523 ok(present, "expected parameter to be unchanged\n");
525 "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError());
526
527 SetLastError(0xdeadbeef);
528 bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),NULL);
529 ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n");
531 "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError());
532}
533
535{
537};
538
539static void doChild(int argc, char **argv)
540{
541 struct child_blackbox blackbox;
542 const char *blackbox_file;
544 DWORD ppid;
545 BOOL debug;
546 BOOL ret;
547
548 blackbox_file = argv[4];
549 sscanf(argv[3], "%08x", &ppid);
550
552 child_ok(!!parent, "OpenProcess failed, last error %#x.\n", GetLastError());
553
554 ret = pCheckRemoteDebuggerPresent(parent, &debug);
555 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
556 child_ok(!debug, "Expected debug == 0, got %#x.\n", debug);
557
558 ret = DebugActiveProcess(ppid);
559 child_ok(ret, "DebugActiveProcess failed, last error %#x.\n", GetLastError());
560
561 ret = pCheckRemoteDebuggerPresent(parent, &debug);
562 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
563 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
564
565 ret = pDebugActiveProcessStop(ppid);
566 child_ok(ret, "DebugActiveProcessStop failed, last error %#x.\n", GetLastError());
567
568 ret = pCheckRemoteDebuggerPresent(parent, &debug);
569 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
570 child_ok(!debug, "Expected debug == 0, got %#x.\n", debug);
571
573 child_ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
574
575 ret = pIsDebuggerPresent();
576 child_ok(ret, "Expected ret != 0, got %#x.\n", ret);
577 ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug);
578 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
579 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
580
581 NtCurrentTeb()->Peb->BeingDebugged = FALSE;
582
583 ret = pIsDebuggerPresent();
584 child_ok(!ret, "Expected ret != 0, got %#x.\n", ret);
585 ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug);
586 child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
587 child_ok(debug, "Expected debug != 0, got %#x.\n", debug);
588
589 NtCurrentTeb()->Peb->BeingDebugged = TRUE;
590
591 blackbox.failures = child_failures;
592 save_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
593}
594
595static void test_debug_loop(int argc, char **argv)
596{
597 const char *arguments = " debugger child ";
598 struct child_blackbox blackbox;
599 char blackbox_file[MAX_PATH];
601 STARTUPINFOA si;
602 BOOL debug;
603 DWORD pid;
604 char *cmd;
605 BOOL ret;
606
607 if (!pDebugActiveProcessStop || !pCheckRemoteDebuggerPresent)
608 {
609 win_skip("DebugActiveProcessStop or CheckRemoteDebuggerPresent not available, skipping test.\n");
610 return;
611 }
612
615 ok(!ret, "DebugActiveProcess() succeeded on own process.\n");
616
617 get_file_name(blackbox_file);
618 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + strlen(blackbox_file) + 2 + 10);
619 sprintf(cmd, "%s%s%08x \"%s\"", argv[0], arguments, pid, blackbox_file);
620
621 memset(&si, 0, sizeof(si));
622 si.cb = sizeof(si);
624 ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
625
627
628 ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug);
629 ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError());
630 ok(debug, "Expected debug != 0, got %#x.\n", debug);
631
632 for (;;)
633 {
634 DEBUG_EVENT ev;
635
637 ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError());
638 if (!ret) break;
639
641
643 ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
644 if (!ret) break;
645 }
646
647 ret = CloseHandle(pi.hThread);
648 ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
649 ret = CloseHandle(pi.hProcess);
650 ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
651
652 load_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
653 ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures);
654
655 ret = DeleteFileA(blackbox_file);
656 ok(ret, "DeleteFileA failed, last error %#x.\n", GetLastError());
657}
658
659static void doChildren(int argc, char **argv)
660{
661 const char *arguments = "debugger children last";
662 struct child_blackbox blackbox;
663 const char *blackbox_file, *p;
664 char event_name[MAX_PATH];
666 STARTUPINFOA si;
668 char *cmd;
669 BOOL ret;
670
671 if (!strcmp(argv[3], "last")) return;
672
673 blackbox_file = argv[3];
674
675 p = strrchr(blackbox_file, '\\');
676 p = p ? p+1 : blackbox_file;
677 strcpy(event_name, p);
678 strcat(event_name, "_init");
679 event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
680 child_ok(event != NULL, "OpenEvent failed, last error %d.\n", GetLastError());
683
684 p = strrchr(blackbox_file, '\\');
685 p = p ? p+1 : blackbox_file;
686 strcpy(event_name, p);
687 strcat(event_name, "_attach");
688 event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
689 child_ok(event != NULL, "OpenEvent failed, last error %d.\n", GetLastError());
692
693 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + 2);
694 sprintf(cmd, "%s %s", argv[0], arguments);
695
696 memset(&si, 0, sizeof(si));
697 si.cb = sizeof(si);
698 ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
699 child_ok(ret, "CreateProcess failed, last error %d.\n", GetLastError());
700
701 child_ok(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0,
702 "Timed out waiting for the child to exit\n");
703
704 ret = CloseHandle(pi.hThread);
705 child_ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
706 ret = CloseHandle(pi.hProcess);
707 child_ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
708
709 blackbox.failures = child_failures;
710 save_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
711
713}
714
715static void test_debug_children(char *name, DWORD flag, BOOL debug_child)
716{
717 const char *arguments = "debugger children";
718 struct child_blackbox blackbox;
719 char blackbox_file[MAX_PATH], *p;
720 char event_name[MAX_PATH];
722 STARTUPINFOA si;
723 HANDLE event_init, event_attach;
724 char *cmd;
725 BOOL debug, ret;
726 BOOL got_child_event = FALSE;
727
728 if (!pDebugActiveProcessStop || !pCheckRemoteDebuggerPresent)
729 {
730 win_skip("DebugActiveProcessStop or CheckRemoteDebuggerPresent not available, skipping test.\n");
731 return;
732 }
733
734 get_file_name(blackbox_file);
735 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(name) + strlen(arguments) + strlen(blackbox_file) + 5);
736 sprintf(cmd, "%s %s \"%s\"", name, arguments, blackbox_file);
737
738 p = strrchr(blackbox_file, '\\');
739 p = p ? p+1 : blackbox_file;
740 strcpy(event_name, p);
741 strcat(event_name, "_init");
742 event_init = CreateEventA(NULL, FALSE, FALSE, event_name);
743 ok(event_init != NULL, "OpenEvent failed, last error %d.\n", GetLastError());
744
745 p = strrchr(blackbox_file, '\\');
746 p = p ? p+1 : blackbox_file;
747 strcpy(event_name, p);
748 strcat(event_name, "_attach");
749 event_attach = CreateEventA(NULL, FALSE, flag!=0, event_name);
750 ok(event_attach != NULL, "CreateEvent failed, last error %d.\n", GetLastError());
751
752 memset(&si, 0, sizeof(si));
753 si.cb = sizeof(si);
754
756 ok(ret, "CreateProcess failed, last error %d.\n", GetLastError());
758 if (!flag)
759 {
760 WaitForSingleObject(event_init, INFINITE);
761 ret = DebugActiveProcess(pi.dwProcessId);
762 ok(ret, "DebugActiveProcess failed, last error %d.\n", GetLastError());
763 ret = SetEvent(event_attach);
764 ok(ret, "SetEvent failed, last error %d.\n", GetLastError());
765 }
766
767 ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug);
768 ok(ret, "CheckRemoteDebuggerPresent failed, last error %d.\n", GetLastError());
769 ok(debug, "Expected debug != 0, got %x.\n", debug);
770
771 for (;;)
772 {
773 DEBUG_EVENT ev;
774
776 ok(ret, "WaitForDebugEvent failed, last error %d.\n", GetLastError());
777 if (!ret) break;
778
779 if (ev.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT && ev.dwProcessId==pi.dwProcessId) break;
780 else if (ev.dwProcessId != pi.dwProcessId) got_child_event = TRUE;
781
783 ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError());
784 if (!ret) break;
785 }
786 if(debug_child)
787 ok(got_child_event, "didn't get any child events (flag: %x).\n", flag);
788 else
789 ok(!got_child_event, "got child event (flag: %x).\n", flag);
790 CloseHandle(event_init);
791 CloseHandle(event_attach);
792
793 ret = CloseHandle(pi.hThread);
794 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
795 ret = CloseHandle(pi.hProcess);
796 ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
797
798 load_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
799 ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures);
800
801 ret = DeleteFileA(blackbox_file);
802 ok(ret, "DeleteFileA failed, last error %d.\n", GetLastError());
803}
804
805START_TEST(debugger)
806{
808
809 hdll=GetModuleHandleA("kernel32.dll");
810 pCheckRemoteDebuggerPresent=(void*)GetProcAddress(hdll, "CheckRemoteDebuggerPresent");
811 pDebugActiveProcessStop=(void*)GetProcAddress(hdll, "DebugActiveProcessStop");
812 pDebugSetProcessKillOnExit=(void*)GetProcAddress(hdll, "DebugSetProcessKillOnExit");
813 pIsDebuggerPresent=(void*)GetProcAddress(hdll, "IsDebuggerPresent");
814
816 if (myARGC >= 3 && strcmp(myARGV[2], "crash") == 0)
817 {
819 }
820 else if (myARGC >= 3 && strncmp(myARGV[2], "dbg,", 4) == 0)
821 {
823 }
824 else if (myARGC >= 5 && !strcmp(myARGV[2], "child"))
825 {
827 }
828 else if (myARGC >= 4 && !strcmp(myARGV[2], "children"))
829 {
831 }
832 else
833 {
841 }
842}
static int argc
Definition: ServiceArgs.c:12
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define read
Definition: acwin.h:96
static void startup(void)
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define broken(x)
Definition: atltest.h:178
#define START_TEST(x)
Definition: atltest.h:75
#define msg(x)
Definition: auth_time.c:54
#define RegCloseKey(hKey)
Definition: registry.h:49
#define WAIT_TIMEOUT
Definition: dderror.h:14
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LONG WINAPI RegCreateKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:1179
LONG WINAPI RegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE *lpData, DWORD cbData)
Definition: reg.c:4799
LONG WINAPI RegDeleteValueA(HKEY hKey, LPCSTR lpValueName)
Definition: reg.c:2287
LONG WINAPI RegQueryValueExA(_In_ HKEY hkeyorg, _In_ LPCSTR name, _In_ LPDWORD reserved, _Out_opt_ LPDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ LPDWORD count)
Definition: reg.c:4009
LONG WINAPI RegCreateKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ DWORD Reserved, _In_ LPSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_ LPDWORD lpdwDisposition)
Definition: reg.c:1034
LONG WINAPI RegDeleteKeyA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey)
Definition: reg.c:1224
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define SetLastError(x)
Definition: compat.h:752
#define GetProcAddress(x, y)
Definition: compat.h:753
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define HeapAlloc
Definition: compat.h:733
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:740
#define GetCurrentProcess()
Definition: compat.h:759
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
BOOL WINAPI ContinueDebugEvent(IN DWORD dwProcessId, IN DWORD dwThreadId, IN DWORD dwContinueStatus)
Definition: debugger.c:413
BOOL WINAPI DebugActiveProcess(IN DWORD dwProcessId)
Definition: debugger.c:445
BOOL WINAPI WaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent, IN DWORD dwMilliseconds)
Definition: debugger.c:590
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:751
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter(IN LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
Definition: except.c:790
BOOL WINAPI DeleteFileA(IN LPCSTR lpFileName)
Definition: delete.c:24
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:636
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:539
DWORD WINAPI GetTempPathA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2054
BOOL WINAPI GetExitCodeProcess(IN HANDLE hProcess, IN LPDWORD lpExitCode)
Definition: proc.c:1168
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
Definition: proc.c:4747
BOOL WINAPI TerminateProcess(IN HANDLE hProcess, IN UINT uExitCode)
Definition: proc.c:1532
HANDLE WINAPI OpenProcess(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwProcessId)
Definition: proc.c:1227
static void basename(LPCWSTR path, LPWSTR name)
Definition: profile.c:38
r parent
Definition: btrfs.c:3010
#define INFINITE
Definition: serial.h:102
UINT WINAPI GetTempFileNameA(IN LPCSTR lpPathName, IN LPCSTR lpPrefixString, IN UINT uUnique, OUT LPSTR lpTempFileName)
Definition: filename.c:26
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLsizeiptr size
Definition: glext.h:5919
struct _cl_event * event
Definition: glext.h:7739
GLenum condition
Definition: glext.h:9255
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLfloat GLfloat p
Definition: glext.h:8902
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean flag
Definition: glfuncs.h:52
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
_Check_return_ long __cdecl atol(_In_z_ const char *_Str)
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:167
#define NtCurrentTeb
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
#define debug(msg)
Definition: key_call.c:71
#define REG_SZ
Definition: layer.c:22
#define CREATE_ALWAYS
Definition: disk.h:72
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define STATUS_DEBUGGER_INACTIVE
Definition: debugger.c:30
static LONG child_failures
Definition: debugger.c:43
#define child_ok
Definition: debugger.c:33
static void crash_and_winedbg(HKEY hkey, const char *argv0)
Definition: debugger.c:382
static void test_ExitCode(void)
Definition: debugger.c:414
static void test_debug_loop(int argc, char **argv)
Definition: debugger.c:595
static void get_events(const char *name, HANDLE *start_event, HANDLE *done_event)
Definition: debugger.c:99
static void crash_and_debug(HKEY hkey, const char *argv0, const char *dbgtasks)
Definition: debugger.c:260
static int myARGC
Definition: debugger.c:35
static void doChildren(int argc, char **argv)
Definition: debugger.c:659
static void doDebugger(int argc, char **argv)
Definition: debugger.c:187
static DWORD save_value(HKEY hkey, const char *value, reg_save_value *saved)
Definition: debugger.c:73
static void doCrash(int argc, char **argv)
Definition: debugger.c:152
static PBOOL
Definition: debugger.c:38
static char ** myARGV
Definition: debugger.c:36
static void save_blackbox(const char *logfile, void *blackbox, int size)
Definition: debugger.c:115
static void restore_value(HKEY hkey, reg_save_value *saved)
Definition: debugger.c:88
struct tag_reg_save_value reg_save_value
static int load_blackbox(const char *logfile, void *blackbox, int size)
Definition: debugger.c:127
static void doChild(int argc, char **argv)
Definition: debugger.c:539
static void test_debug_children(char *name, DWORD flag, BOOL debug_child)
Definition: debugger.c:715
static void test_RemoteDebugger(void)
Definition: debugger.c:504
static UINT exit_code
Definition: process.c:78
static HANDLE start_event
Definition: thread.c:135
static __ms_va_list valist
Definition: printf.c:66
static refpint_t pi[]
Definition: server.c:96
#define argv
Definition: mplay32.c:18
_In_ HANDLE hFile
Definition: mswsock.h:90
#define BOOL
Definition: nt_native.h:43
#define KEY_ALL_ACCESS
Definition: nt_native.h:1041
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1084
#define DWORD
Definition: nt_native.h:44
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1085
#define GENERIC_WRITE
Definition: nt_native.h:90
#define DBG_CONTINUE
Definition: ntstatus.h:47
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
long LONG
Definition: pedump.c:60
#define get_file_name
Definition: regproc.h:51
#define REG_DWORD
Definition: sdbapi.c:596
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
#define win_skip
Definition: test.h:163
int winetest_interactive
int winetest_get_mainargs(char ***pargv)
int winetest_vok(int condition, const char *msg, __winetest_va_list ap)
#define WINETEST_PRINTF_ATTR(fmt, args)
Definition: test.h:143
#define memset(x, y, z)
Definition: compat.h:39
int zero
Definition: sehframes.cpp:29
static PVOID hdll
Definition: shimdbg.c:126
static char argv0[MAX_PATH]
Definition: shlexec.c:49
DWORD dwDebugEventCode
Definition: winbase.h:788
DWORD dwThreadId
Definition: winbase.h:790
DWORD dwProcessId
Definition: winbase.h:789
DWORD cb
Definition: winbase.h:831
Definition: ftp_var.h:139
Definition: name.c:39
const char * name
Definition: debugger.c:67
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCSTR lpName OPTIONAL)
Definition: synch.c:637
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
HANDLE WINAPI DECLSPEC_HOTPATCH OpenEventA(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCSTR lpName)
Definition: synch.c:669
int32_t INT_PTR
Definition: typedefs.h:64
PVOID HANDLE
Definition: typedefs.h:73
Definition: pdh_main.c:94
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
int ret
#define WAIT_ABANDONED
Definition: winbase.h:412
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define STARTF_USESHOWWINDOW
Definition: winbase.h:491
DWORD WINAPI GetCurrentProcessId(void)
Definition: proc.c:1158
#define EXIT_PROCESS_DEBUG_EVENT
Definition: winbase.h:106
#define DEBUG_ONLY_THIS_PROCESS
Definition: winbase.h:177
#define WAIT_OBJECT_0
Definition: winbase.h:406
#define DEBUG_PROCESS
Definition: winbase.h:176
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3837
#define WINAPI
Definition: msvc.h:6
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define HKEY_CURRENT_USER
Definition: winreg.h:11
#define SW_SHOWNORMAL
Definition: winuser.h:773
unsigned char BYTE
Definition: xxhash.c:193
#define const
Definition: zconf.h:233