ReactOS  0.4.13-dev-464-g6b95727
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 
35 static int myARGC;
36 static char** myARGV;
37 
38 static BOOL (WINAPI *pCheckRemoteDebuggerPresent)(HANDLE,PBOOL);
39 static BOOL (WINAPI *pDebugActiveProcessStop)(DWORD);
40 static BOOL (WINAPI *pDebugSetProcessKillOnExit)(BOOL);
41 static BOOL (WINAPI *pIsDebuggerPresent)(void);
42 
44 
45 static void WINETEST_PRINTF_ATTR(2, 3) test_child_ok(int condition, const char *msg, ...)
46 {
48 
51  va_end(valist);
52  if (!condition) ++child_failures;
53 }
54 
55 /* Copied from the process test */
56 static 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 
65 typedef struct tag_reg_save_value
66 {
67  const char *name;
72 
73 static 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 
88 static 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 
99 static 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, '\\');
105  basename=(basename ? basename+1 : 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 
115 static void save_blackbox(const char* logfile, void* blackbox, int size)
116 {
117  HANDLE hFile;
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 
127 static int load_blackbox(const char* logfile, void* blackbox, int size)
128 {
129  HANDLE hFile;
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 
147 typedef struct
148 {
151 
152 static 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 
173 typedef struct
174 {
175  int argc;
186 
187 static 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 
260 static 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);
283  if (ret == ERROR_ACCESS_DENIED)
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);
298  HeapFree(GetProcessHeap(), 0, cmd);
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);
306  startup.dwFlags = STARTF_USESHOWWINDOW;
307  startup.wShowWindow = SW_SHOWNORMAL;
309  ok(ret, "CreateProcess: err=%d\n", GetLastError());
310  HeapFree(GetProcessHeap(), 0, cmd);
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 
382 static 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 
394  cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+15+1);
395  sprintf(cmd, "%s debugger crash", argv0);
396 
397  memset(&startup, 0, sizeof(startup));
398  startup.cb = sizeof(startup);
399  startup.dwFlags = STARTF_USESHOWWINDOW;
400  startup.wShowWindow = SW_SHOWNORMAL;
402  ok(ret, "CreateProcess: err=%d\n", GetLastError());
403  HeapFree(GetProcessHeap(), 0, cmd);
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 
414 static 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 
504 static 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 
539 static void doChild(int argc, char **argv)
540 {
541  struct child_blackbox blackbox;
542  const char *blackbox_file;
543  HANDLE parent;
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 
595 static 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 
626  HeapFree(GetProcessHeap(), 0, cmd);
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 
659 static 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;
667  HANDLE event;
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());
681  SetEvent(event);
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 
712  HeapFree(GetProcessHeap(), 0, cmd);
713 }
714 
715 static 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 
755  ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, flag, NULL, NULL, &si, &pi);
756  ok(ret, "CreateProcess failed, last error %d.\n", GetLastError());
757  HeapFree(GetProcessHeap(), 0, cmd);
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 
805 START_TEST(debugger)
806 {
807  HMODULE hdll;
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  {
834  test_ExitCode();
841  }
842 }
static void test_debug_loop(int argc, char **argv)
Definition: debugger.c:595
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
static BOOL(WINAPI *pCheckRemoteDebuggerPresent)(HANDLE
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:753
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
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:4023
static int argc
Definition: ServiceArgs.c:12
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3835
#define trace(...)
Definition: kmt_test.h:217
const char * name
Definition: debugger.c:67
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
static void test_debug_children(char *name, DWORD flag, BOOL debug_child)
Definition: debugger.c:715
int winetest_vok(int condition, const char *msg, __winetest_va_list ap)
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define WAIT_ABANDONED
Definition: winbase.h:393
#define ERROR_SUCCESS
Definition: deptool.c:10
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
DWORD dwThreadId
Definition: winbase.h:768
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:158
static void WINETEST_PRINTF_ATTR(2, 3)
Definition: debugger.c:45
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
Definition: ftp_var.h:139
static void basename(LPCWSTR path, LPWSTR name)
Definition: profile.c:38
BOOL WINAPI GetExitCodeProcess(IN HANDLE hProcess, IN LPDWORD lpExitCode)
Definition: proc.c:1198
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
DWORD dwProcessId
Definition: winbase.h:767
#define HKEY_CURRENT_USER
Definition: winreg.h:11
static char ** myARGV
Definition: debugger.c:36
BOOL WINAPI ContinueDebugEvent(IN DWORD dwProcessId, IN DWORD dwThreadId, IN DWORD dwContinueStatus)
Definition: debugger.c:448
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1517
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
int startup(int argc, const char *argv[])
Definition: startup.c:430
char * cmd
Definition: vfdcmd.c:85
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1085
int winetest_interactive
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
static void doChildren(int argc, char **argv)
Definition: debugger.c:659
int32_t INT_PTR
Definition: typedefs.h:62
#define argv
Definition: mplay32.c:18
#define DWORD
Definition: nt_native.h:44
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:546
#define DBG_CONTINUE
Definition: ntstatus.h:47
START_TEST(debugger)
Definition: debugger.c:805
struct _test_info info[]
Definition: SetCursorPos.c:19
static int load_blackbox(const char *logfile, void *blackbox, int size)
Definition: debugger.c:127
#define sprintf(buf, format,...)
Definition: sprintf.c:55
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
static void crash_and_debug(HKEY hkey, const char *argv0, const char *dbgtasks)
Definition: debugger.c:260
#define va_end(ap)
Definition: acmsvcex.h:90
#define ERROR_ACCESS_DENIED
Definition: compat.h:87
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
HANDLE WINAPI DECLSPEC_HOTPATCH OpenEventA(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCSTR lpName)
Definition: synch.c:615
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI DECLSPEC_HOTPATCH SetUnhandledExceptionFilter(IN LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
Definition: except.c:792
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:786
#define GENERIC_WRITE
Definition: nt_native.h:90
#define ok(value,...)
GLenum condition
Definition: glext.h:9255
DWORD dwDebugEventCode
Definition: winbase.h:766
smooth NULL
Definition: ftsmooth.c:416
BOOL WINAPI DeleteFileA(IN LPCSTR lpFileName)
Definition: delete.c:24
char * va_list
Definition: acmsvcex.h:78
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCSTR lpName OPTIONAL)
Definition: synch.c:583
static void get_file_name(char *buf)
Definition: debugger.c:56
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1084
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
#define STARTF_USESHOWWINDOW
Definition: winbase.h:472
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
LONG WINAPI RegCreateKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:1177
#define OPEN_EXISTING
Definition: compat.h:426
static UINT exit_code
Definition: process.c:78
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
static void doChild(int argc, char **argv)
Definition: debugger.c:539
#define EXIT_PROCESS_DEBUG_EVENT
Definition: winbase.h:106
static void test_ExitCode(void)
Definition: debugger.c:414
static int myARGC
Definition: debugger.c:35
static void crash_and_winedbg(HKEY hkey, const char *argv0)
Definition: debugger.c:382
#define WAIT_OBJECT_0
Definition: winbase.h:387
GLsizeiptr size
Definition: glext.h:5919
DWORD cb
Definition: winbase.h:796
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
r parent
Definition: btrfs.c:2708
static void restore_value(HKEY hkey, reg_save_value *saved)
Definition: debugger.c:88
HANDLE WINAPI GetCurrentProcess(VOID)
Definition: proc.c:1168
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:4772
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
unsigned long DWORD
Definition: ntddk_ex.h:95
PVOID HANDLE
Definition: typedefs.h:71
#define SetLastError(x)
Definition: compat.h:409
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
#define DEBUG_PROCESS
Definition: winbase.h:176
_Check_return_ long __cdecl atol(_In_z_ const char *_Str)
static void get_events(const char *name, HANDLE *start_event, HANDLE *done_event)
Definition: debugger.c:99
int winetest_get_mainargs(char ***pargv)
#define WAIT_TIMEOUT
Definition: dderror.h:14
static DWORD pi
Definition: protocol.c:150
BOOL WINAPI WaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent, IN DWORD dwMilliseconds)
Definition: debugger.c:625
#define child_ok
Definition: debugger.c:33
struct tag_reg_save_value reg_save_value
static double zero
Definition: j0_y0.c:96
int ret
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
static DWORD save_value(HKEY hkey, const char *value, reg_save_value *saved)
Definition: debugger.c:73
static LONG child_failures
Definition: debugger.c:43
static PBOOL
Definition: debugger.c:38
#define STATUS_DEBUGGER_INACTIVE
Definition: debugger.c:30
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:819
unsigned char BYTE
Definition: mem.h:68
static char argv0[MAX_PATH]
Definition: shlexec.c:56
#define GENERIC_READ
Definition: compat.h:124
struct _cl_event * event
Definition: glext.h:7739
_In_ HANDLE hFile
Definition: mswsock.h:90
GLsizei const GLfloat * value
Definition: glext.h:6069
#define broken(x)
Definition: _sntprintf.h:21
LONG WINAPI RegDeleteKeyA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey)
Definition: reg.c:1222
HANDLE WINAPI OpenProcess(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwProcessId)
Definition: proc.c:1257
#define CREATE_ALWAYS
Definition: disk.h:72
#define SW_SHOWNORMAL
Definition: winuser.h:764
static void save_blackbox(const char *logfile, void *blackbox, int size)
Definition: debugger.c:115
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
DWORD WINAPI GetTempPathA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2053
static void doDebugger(int argc, char **argv)
Definition: debugger.c:187
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
#define KEY_ALL_ACCESS
Definition: nt_native.h:1041
BOOL WINAPI TerminateProcess(IN HANDLE hProcess, IN UINT uExitCode)
Definition: proc.c:1562
LONG WINAPI RegDeleteValueA(HKEY hKey, LPCSTR lpValueName)
Definition: reg.c:2319
Definition: services.c:325
static void doCrash(int argc, char **argv)
Definition: debugger.c:152
static void test_RemoteDebugger(void)
Definition: debugger.c:504
#define va_start(ap, A)
Definition: acmsvcex.h:91
static PVOID hdll
Definition: shimdbg.c:126
#define skip(...)
#define msg(x)
Definition: auth_time.c:54
Definition: name.c:36
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define const
Definition: zconf.h:230
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define debug(msg)
Definition: key_call.c:71
#define GetProcAddress(x, y)
Definition: compat.h:410
static __ms_va_list valist
Definition: printf.c:59
LONG WINAPI RegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE *lpData, DWORD cbData)
Definition: reg.c:4812
BOOL WINAPI DebugActiveProcess(IN DWORD dwProcessId)
Definition: debugger.c:480
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:399
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:1029
GLfloat GLfloat p
Definition: glext.h:8902
#define INFINITE
Definition: serial.h:102
#define DEBUG_ONLY_THIS_PROCESS
Definition: winbase.h:177
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
#define memset(x, y, z)
Definition: compat.h:39
#define REG_DWORD
Definition: sdbapi.c:596
#define win_skip
Definition: test.h:141
UINT WINAPI GetTempFileNameA(IN LPCSTR lpPathName, IN LPCSTR lpPrefixString, IN UINT uUnique, OUT LPSTR lpTempFileName)
Definition: filename.c:26
#define HeapFree(x, y, z)
Definition: compat.h:394
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
DWORD WINAPI GetCurrentProcessId(VOID)
Definition: proc.c:1188
static HANDLE start_event
Definition: thread.c:140
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define REG_SZ
Definition: layer.c:22
GLuint const GLchar * name
Definition: glext.h:6031