Don't keep main exe and dlls handles open when the file is on
[wine] / debugger / winedbg.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /* Wine internal debugger
4  * Interface to Windows debugger API
5  * Eric Pouech (c) 2000
6  */
7
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "debugger.h"
13
14 #include "ntddk.h"
15 #include "thread.h"
16 #include "wincon.h"
17 #include "wingdi.h"
18 #include "winuser.h"
19
20 #include "winreg.h"
21
22 #ifdef DBG_need_heap
23 HANDLE dbg_heap = 0;
24 #endif
25
26 DBG_PROCESS*    DEBUG_CurrProcess = NULL;
27 DBG_THREAD*     DEBUG_CurrThread = NULL;
28 DWORD           DEBUG_CurrTid;
29 DWORD           DEBUG_CurrPid;
30 CONTEXT         DEBUG_context;
31 BOOL            DEBUG_interactiveP = FALSE;
32 int             curr_frame = 0;
33 static char*    DEBUG_LastCmdLine = NULL;
34
35 static DBG_PROCESS* DEBUG_ProcessList = NULL;
36 static int automatic_mode;
37 DBG_INTVAR DEBUG_IntVars[DBG_IV_LAST];
38
39 void    DEBUG_Output(int chn, const char* buffer, int len)
40 {
41     if (DBG_IVAR(ConChannelMask) & chn)
42         WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer, len, NULL, NULL);
43     if (DBG_IVAR(StdChannelMask) & chn)
44         fwrite(buffer, len, 1, stderr);
45 }
46
47 int     DEBUG_Printf(int chn, const char* format, ...)
48 {
49 static    char  buf[4*1024];
50     va_list     valist;
51     int         len;
52
53     va_start(valist, format);
54     len = vsnprintf(buf, sizeof(buf), format, valist);
55     va_end(valist);
56
57     if (len <= -1) {
58         len = sizeof(buf) - 1;
59         buf[len] = 0;
60         buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
61     }
62     DEBUG_Output(chn, buf, len);
63     return len;
64 }
65
66 static  BOOL DEBUG_IntVarsRW(int read)
67 {
68     HKEY        hkey;
69     DWORD       type = REG_DWORD;
70     DWORD       val;
71     DWORD       count = sizeof(val);
72     int         i;
73     DBG_INTVAR* div = DEBUG_IntVars;
74
75     if (read) {
76 /* initializes internal vars table */
77 #define  INTERNAL_VAR(_var,_val,_ref,_typ)                      \
78         div->val = _val; div->name = #_var; div->pval = _ref;   \
79         div->type = _typ; div++;
80 #include "intvar.h"
81 #undef   INTERNAL_VAR
82     }
83
84     if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) {
85         /* since the IVars are not yet setup, DEBUG_Printf doesn't work,
86          * so don't use it */
87         fprintf(stderr, "Cannot create WineDbg key in registry\n");
88         return FALSE;
89     }
90
91     for (i = 0; i < DBG_IV_LAST; i++) {
92         if (read) {
93             if (!DEBUG_IntVars[i].pval) {
94                 if (!RegQueryValueEx(hkey, DEBUG_IntVars[i].name, 0, 
95                                      &type, (LPSTR)&val, &count))
96                     DEBUG_IntVars[i].val = val;
97                 DEBUG_IntVars[i].pval = &DEBUG_IntVars[i].val;
98             } else {
99                 *DEBUG_IntVars[i].pval = 0;
100             }
101         } else {
102             /* FIXME: type should be infered from basic type -if any- of intvar */
103             if (DEBUG_IntVars[i].pval == &DEBUG_IntVars[i].val)
104                 RegSetValueEx(hkey, DEBUG_IntVars[i].name, 0, 
105                               type, (LPCVOID)DEBUG_IntVars[i].pval, count);
106         }
107     }
108     RegCloseKey(hkey);
109     return TRUE;
110 }
111
112 DBG_INTVAR*     DEBUG_GetIntVar(const char* name)
113 {
114     int         i;
115
116     for (i = 0; i < DBG_IV_LAST; i++) {
117         if (!strcmp(DEBUG_IntVars[i].name, name))
118             return &DEBUG_IntVars[i];
119     }
120     return NULL;
121 }
122                        
123 static WINE_EXCEPTION_FILTER(wine_dbg)
124 {
125     DEBUG_Printf(DBG_CHN_MESG, "\nwine_dbg: Exception (%lx) inside debugger, continuing...\n", GetExceptionCode());
126     DEBUG_ExternalDebugger();
127     return EXCEPTION_EXECUTE_HANDLER;
128 }
129
130 DBG_PROCESS*    DEBUG_GetProcess(DWORD pid)
131 {
132     DBG_PROCESS*        p;
133     
134     for (p = DEBUG_ProcessList; p; p = p->next)
135         if (p->pid == pid) break;
136     return p;
137 }
138
139 static  DBG_PROCESS*    DEBUG_AddProcess(DWORD pid, HANDLE h, const char* imageName)
140 {
141     DBG_PROCESS*        p = DBG_alloc(sizeof(DBG_PROCESS));
142     if (!p)
143         return NULL;
144     p->handle = h;
145     p->pid = pid;
146     p->imageName = imageName ? DBG_strdup(imageName) : NULL;
147     p->threads = NULL;
148     p->num_threads = 0;
149     p->continue_on_first_exception = FALSE;
150     p->modules = NULL;
151     p->num_modules = 0;
152     p->next_index = 0;
153     p->dbg_hdr_addr = 0;
154     p->delayed_bp = NULL;
155     p->num_delayed_bp = 0;
156
157     p->next = DEBUG_ProcessList;
158     p->prev = NULL;
159     if (DEBUG_ProcessList) DEBUG_ProcessList->prev = p;
160     DEBUG_ProcessList = p;
161     return p;
162 }
163
164 static  void                    DEBUG_DelThread(DBG_THREAD* p);
165
166 static  void                    DEBUG_DelProcess(DBG_PROCESS* p)
167 {
168     int i;
169
170     if (p->threads != NULL) {
171         DEBUG_Printf(DBG_CHN_ERR, "Shouldn't happen\n");
172         while (p->threads) DEBUG_DelThread(p->threads);
173     }
174     for (i = 0; i < p->num_delayed_bp; i++) {
175         DBG_free(p->delayed_bp[i].name);
176     }
177     DBG_free(p->delayed_bp);
178     if (p->prev) p->prev->next = p->next;
179     if (p->next) p->next->prev = p->prev;
180     if (p == DEBUG_ProcessList) DEBUG_ProcessList = p->next;
181     if (p == DEBUG_CurrProcess) DEBUG_CurrProcess = NULL;
182     DBG_free((char*)p->imageName);
183     DBG_free(p);
184 }
185
186 static  void                    DEBUG_InitCurrProcess(void)
187 {
188 }
189
190 static BOOL DEBUG_ProcessGetString(char* buffer, int size, HANDLE hp, LPSTR addr)
191 {
192     DWORD sz;
193     *(WCHAR*)buffer = 0;
194     return (addr && ReadProcessMemory(hp, addr, buffer, size, &sz));
195 }
196
197 static BOOL DEBUG_ProcessGetStringIndirect(char* buffer, int size, HANDLE hp, LPVOID addr)
198 {
199     LPVOID      ad;
200     DWORD       sz;
201     
202     if (   addr 
203         && ReadProcessMemory(hp, addr, &ad, sizeof(ad), &sz) 
204         && sz == sizeof(ad) 
205         && ad 
206         && ReadProcessMemory(hp, ad, buffer, size, &sz))
207         return TRUE;
208     *(WCHAR*)buffer = 0;
209     return FALSE;
210 }
211
212 DBG_THREAD*     DEBUG_GetThread(DBG_PROCESS* p, DWORD tid)
213 {
214     DBG_THREAD* t;
215     
216     for (t = p->threads; t; t = t->next)
217         if (t->tid == tid) break;
218     return t;
219 }
220
221 static  DBG_THREAD*     DEBUG_AddThread(DBG_PROCESS* p, DWORD tid, 
222                                         HANDLE h, LPVOID start, LPVOID teb)
223 {
224     DBG_THREAD* t = DBG_alloc(sizeof(DBG_THREAD));
225     if (!t)
226         return NULL;
227     
228     t->handle = h;
229     t->tid = tid;
230     t->start = start;
231     t->teb = teb;
232     t->process = p;
233     t->wait_for_first_exception = 0;
234     t->dbg_exec_mode = EXEC_CONT;
235     t->dbg_exec_count = 0;
236     sprintf(t->name, "%08lx", tid);
237
238     p->num_threads++;
239     t->next = p->threads;
240     t->prev = NULL;
241     if (p->threads) p->threads->prev = t;
242     p->threads = t;
243
244     return t;
245 }
246
247 static  void                    DEBUG_InitCurrThread(void)
248 {
249     if (DEBUG_CurrThread->start) {
250         if (DEBUG_CurrThread->process->num_threads == 1 || 
251             DBG_IVAR(BreakAllThreadsStartup)) {
252             DBG_VALUE   value;
253             
254             DEBUG_SetBreakpoints(FALSE);
255             value.type = NULL;
256             value.cookie = DV_TARGET;
257             value.addr.seg = 0;
258             value.addr.off = (DWORD)DEBUG_CurrThread->start;
259             DEBUG_AddBreakpoint(&value, NULL);
260             DEBUG_SetBreakpoints(TRUE);
261         }
262     } else {
263         DEBUG_CurrThread->wait_for_first_exception = 1;
264     }
265 }
266
267 static  void                    DEBUG_DelThread(DBG_THREAD* t)
268 {
269     if (t->prev) t->prev->next = t->next;
270     if (t->next) t->next->prev = t->prev;
271     if (t == t->process->threads) t->process->threads = t->next;
272     t->process->num_threads--;
273     if (t == DEBUG_CurrThread) DEBUG_CurrThread = NULL;
274     DBG_free(t);
275 }
276
277 BOOL                            DEBUG_Attach(DWORD pid, BOOL cofe)
278 {
279     if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0, NULL))) return FALSE;
280
281     if (!DebugActiveProcess(pid)) {
282         DEBUG_Printf(DBG_CHN_MESG, "Can't attach process %lx: error %ld\n", pid, GetLastError());
283         DEBUG_DelProcess(DEBUG_CurrProcess);
284         DEBUG_CurrProcess = NULL;
285         return FALSE;
286     }
287     DEBUG_CurrProcess->continue_on_first_exception = cofe;
288     return TRUE;
289 }
290
291 static  BOOL    DEBUG_ExceptionProlog(BOOL is_debug, BOOL force, DWORD code)
292 {
293     DBG_ADDR    addr;
294     int         newmode;
295
296     DEBUG_GetCurrentAddress(&addr);
297     DEBUG_SuspendExecution();
298
299     if (!is_debug) {
300         if (!addr.seg)
301             DEBUG_Printf(DBG_CHN_MESG, " in 32-bit code (0x%08lx)", addr.off);
302         else
303             switch(DEBUG_GetSelectorType(addr.seg))
304             {
305             case MODE_32:
306                 DEBUG_Printf(DBG_CHN_MESG, " in 32-bit code (%04lx:%08lx)", addr.seg, addr.off);
307                 break;
308             case MODE_16:
309                 DEBUG_Printf(DBG_CHN_MESG, " in 16-bit code (%04lx:%04lx)", addr.seg, addr.off);
310                 break;
311             case MODE_VM86:
312                 DEBUG_Printf(DBG_CHN_MESG, " in vm86 code (%04lx:%04lx)", addr.seg, addr.off);
313                 break;
314             case MODE_INVALID:
315                 DEBUG_Printf(DBG_CHN_MESG, " bad CS (%lx)", addr.seg);
316                 break;
317         }
318         DEBUG_Printf(DBG_CHN_MESG, ".\n");
319     }
320  
321     DEBUG_LoadEntryPoints("Loading new modules symbols:\n");
322
323     if (!force && is_debug && 
324         DEBUG_ShouldContinue(&addr,
325                              code, 
326                              DEBUG_CurrThread->dbg_exec_mode, 
327                              &DEBUG_CurrThread->dbg_exec_count))
328         return FALSE;
329
330     if ((newmode = DEBUG_GetSelectorType(addr.seg)) == MODE_INVALID) newmode = MODE_32;
331     if (newmode != DEBUG_CurrThread->dbg_mode)
332     {
333         static const char * const names[] = { "???", "16-bit", "32-bit", "vm86" };
334         DEBUG_Printf(DBG_CHN_MESG,"In %s mode.\n", names[newmode] );
335         DEBUG_CurrThread->dbg_mode = newmode;
336     }
337
338     DEBUG_DoDisplay();
339
340     if (is_debug || force) {
341         /*
342          * Do a quiet backtrace so that we have an idea of what the situation
343          * is WRT the source files.
344          */
345         DEBUG_BackTrace(DEBUG_CurrTid, FALSE);
346     } else {
347         /* This is a real crash, dump some info */
348         DEBUG_InfoRegisters();
349         DEBUG_InfoStack();
350 #ifdef __i386__
351         if (DEBUG_CurrThread->dbg_mode == MODE_16) {
352             DEBUG_InfoSegments(DEBUG_context.SegDs >> 3, 1);
353             if (DEBUG_context.SegEs != DEBUG_context.SegDs)
354                 DEBUG_InfoSegments(DEBUG_context.SegEs >> 3, 1);
355         }
356         DEBUG_InfoSegments(DEBUG_context.SegFs >> 3, 1);
357 #endif
358         DEBUG_BackTrace(DEBUG_CurrTid, TRUE);
359     }
360
361     if (!is_debug ||
362         (DEBUG_CurrThread->dbg_exec_mode == EXEC_STEPI_OVER) ||
363         (DEBUG_CurrThread->dbg_exec_mode == EXEC_STEPI_INSTR)) {
364
365         struct list_id list;
366
367         /* Show where we crashed */
368         curr_frame = 0;
369         DEBUG_DisassembleInstruction(&addr);
370
371         /* resets list internal arguments so we can look at source code when needed */
372         DEBUG_FindNearestSymbol(&addr, TRUE, NULL, 0, &list); 
373         if (list.sourcefile) DEBUG_List(&list, NULL, 0);
374     }
375     return TRUE;
376 }
377
378 static  DWORD   DEBUG_ExceptionEpilog(void)
379 {
380     DEBUG_CurrThread->dbg_exec_mode = DEBUG_RestartExecution(DEBUG_CurrThread->dbg_exec_mode, 
381                                                              DEBUG_CurrThread->dbg_exec_count);
382     /*
383      * This will have gotten absorbed into the breakpoint info
384      * if it was used.  Otherwise it would have been ignored.
385      * In any case, we don't mess with it any more.
386      */
387     if (DEBUG_CurrThread->dbg_exec_mode == EXEC_CONT || DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS)
388         DEBUG_CurrThread->dbg_exec_count = 0;
389     
390     return (DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS) ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
391 }
392
393 static  BOOL    DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force, LPDWORD cont)
394 {
395     BOOL             is_debug = FALSE;
396     BOOL             ret = TRUE;
397     THREADNAME_INFO *pThreadName;
398     DBG_THREAD      *pThread;
399
400
401     *cont = DBG_CONTINUE;
402
403     switch (rec->ExceptionCode)
404     {
405     case EXCEPTION_BREAKPOINT:
406     case EXCEPTION_SINGLE_STEP:
407         is_debug = TRUE;
408         break;
409     case EXCEPTION_NAME_THREAD:
410         pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation);
411         if (pThreadName->dwThreadID == -1)
412             pThread = DEBUG_CurrThread;
413         else
414             pThread = DEBUG_GetThread(DEBUG_CurrProcess, pThreadName->dwThreadID);
415
416         if (ReadProcessMemory(DEBUG_CurrThread->process->handle, pThreadName->szName,
417                               pThread->name, 9, NULL))
418             DEBUG_Printf (DBG_CHN_MESG,
419                           "Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
420                           pThread->tid, pThread->name);
421         return TRUE;
422     }
423
424     if (first_chance && !is_debug && !force && !DBG_IVAR(BreakOnFirstChance))
425     {
426         /* pass exception to program except for debug exceptions */
427         *cont = is_debug ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED;
428         return TRUE;
429     }
430
431     if (!is_debug)
432     {
433         /* print some infos */
434         DEBUG_Printf(DBG_CHN_MESG, "%s: ",
435                       first_chance ? "First chance exception" : "Unhandled exception");
436         switch (rec->ExceptionCode)
437         {
438         case EXCEPTION_INT_DIVIDE_BY_ZERO:
439             DEBUG_Printf(DBG_CHN_MESG, "divide by zero");
440             break;
441         case EXCEPTION_INT_OVERFLOW:
442             DEBUG_Printf(DBG_CHN_MESG, "overflow");
443             break;
444         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
445             DEBUG_Printf(DBG_CHN_MESG, "array bounds ");
446             break;
447         case EXCEPTION_ILLEGAL_INSTRUCTION:
448             DEBUG_Printf(DBG_CHN_MESG, "illegal instruction");
449             break;
450         case EXCEPTION_STACK_OVERFLOW:
451             DEBUG_Printf(DBG_CHN_MESG, "stack overflow");
452             break;
453         case EXCEPTION_PRIV_INSTRUCTION:
454             DEBUG_Printf(DBG_CHN_MESG, "privileged instruction");
455             break;
456         case EXCEPTION_ACCESS_VIOLATION:
457             if (rec->NumberParameters == 2)
458                 DEBUG_Printf(DBG_CHN_MESG, "page fault on %s access to 0x%08lx", 
459                               rec->ExceptionInformation[0] ? "write" : "read",
460                               rec->ExceptionInformation[1]);
461             else
462                 DEBUG_Printf(DBG_CHN_MESG, "page fault");
463             break;
464         case EXCEPTION_DATATYPE_MISALIGNMENT:
465             DEBUG_Printf(DBG_CHN_MESG, "Alignment");
466             break;
467         case CONTROL_C_EXIT:
468             DEBUG_Printf(DBG_CHN_MESG, "^C");
469             break;
470         case EXCEPTION_CRITICAL_SECTION_WAIT:
471             {
472                 DBG_ADDR        addr;
473
474                 addr.seg = 0;
475                 addr.off = rec->ExceptionInformation[0];
476
477                 DEBUG_Printf(DBG_CHN_MESG, "wait failed on critical section ");
478                 DEBUG_PrintAddress(&addr, DEBUG_CurrThread->dbg_mode, FALSE);
479             }
480             if (!DBG_IVAR(BreakOnCritSectTimeOut))
481             {
482                 DEBUG_Printf(DBG_CHN_MESG, "\n");
483                 return TRUE;
484             }
485             break;
486         case EXCEPTION_WINE_STUB:
487             {
488                 char dll[32], name[64];
489                 DEBUG_ProcessGetString( dll, sizeof(dll), DEBUG_CurrThread->process->handle,
490                                         (char *)rec->ExceptionInformation[0] );
491                 DEBUG_ProcessGetString( name, sizeof(name), DEBUG_CurrThread->process->handle,
492                                         (char *)rec->ExceptionInformation[1] );
493                 DEBUG_Printf(DBG_CHN_MESG, "unimplemented function %s.%s called", dll, name );
494             }
495             break;
496         case EXCEPTION_VM86_INTx:
497             DEBUG_Printf(DBG_CHN_MESG, "interrupt %02lx in vm86 mode",
498                          rec->ExceptionInformation[0]);
499             break;
500         case EXCEPTION_VM86_STI:
501             DEBUG_Printf(DBG_CHN_MESG, "sti in vm86 mode");
502             break;
503         case EXCEPTION_VM86_PICRETURN:
504             DEBUG_Printf(DBG_CHN_MESG, "PIC return in vm86 mode");
505             break;
506         default:
507             DEBUG_Printf(DBG_CHN_MESG, "%08lx", rec->ExceptionCode);
508             break;
509         }
510     }
511
512 #if 0
513     DEBUG_Printf(DBG_CHN_TRACE, 
514                  "Entering debugger     PC=%lx EFL=%08lx mode=%d count=%d\n",
515 #ifdef __i386__
516                  DEBUG_context.Eip, DEBUG_context.EFlags, 
517 #else
518                  0L, 0L,
519 #endif
520                  DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
521 #endif
522
523     if (automatic_mode)
524     {
525         DEBUG_ExceptionProlog(is_debug, FALSE, rec->ExceptionCode);
526         return FALSE;  /* terminate execution */
527     }
528
529     if (DEBUG_ExceptionProlog(is_debug, force, rec->ExceptionCode)) {
530         DEBUG_interactiveP = TRUE;
531         while ((ret = DEBUG_Parser())) {
532             if (DEBUG_ValidateRegisters()) {
533                 if (DEBUG_CurrThread->dbg_exec_mode != EXEC_PASS || first_chance)
534                     break;
535                 DEBUG_Printf(DBG_CHN_MESG, "Cannot pass on last chance exception. You must use cont\n");
536             }
537         }
538         DEBUG_interactiveP = FALSE;
539     }
540     *cont = DEBUG_ExceptionEpilog();
541
542 #if 0
543     DEBUG_Printf(DBG_CHN_TRACE, 
544                  "Exiting debugger      PC=%lx EFL=%08lx mode=%d count=%d\n",
545 #ifdef __i386__
546                  DEBUG_context.Eip, DEBUG_context.EFlags, 
547 #else
548                  0L, 0L,
549 #endif
550                  DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
551 #endif
552
553     return ret;
554 }
555
556 static  BOOL    DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
557 {
558     char                buffer[256];
559     BOOL                ret;
560
561     DEBUG_CurrPid = de->dwProcessId;
562     DEBUG_CurrTid = de->dwThreadId;
563
564     __TRY {
565         ret = TRUE;
566         *cont = 0L;
567         
568         if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL)
569             DEBUG_CurrThread = DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId);
570         else 
571             DEBUG_CurrThread = NULL;
572         
573         switch (de->dwDebugEventCode) {
574         case EXCEPTION_DEBUG_EVENT:
575             if (!DEBUG_CurrThread) {
576                 DEBUG_Printf(DBG_CHN_ERR, "%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
577                              de->dwProcessId, de->dwThreadId);
578                 break;
579             }
580             
581             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exception code=%08lx\n", 
582                          de->dwProcessId, de->dwThreadId, 
583                          de->u.Exception.ExceptionRecord.ExceptionCode);
584
585             if (DEBUG_CurrProcess->continue_on_first_exception) {
586                 DEBUG_CurrProcess->continue_on_first_exception = FALSE;
587                 if (!DBG_IVAR(BreakOnAttach)) {
588                     *cont = DBG_CONTINUE;
589                     break;
590                 }
591             }
592
593             DEBUG_context.ContextFlags =  CONTEXT_CONTROL
594                                         | CONTEXT_INTEGER
595 #ifdef CONTEXT_SEGMENTS
596                                         | CONTEXT_SEGMENTS
597 #endif
598 #ifdef CONTEXT_DEBUG_REGISTERS
599                                         | CONTEXT_DEBUG_REGISTERS
600 #endif
601                                         ;
602
603             if (!GetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context)) {
604                 DEBUG_Printf(DBG_CHN_WARN, "Can't get thread's context\n");
605                 break;
606             }
607             
608             ret = DEBUG_HandleException(&de->u.Exception.ExceptionRecord, 
609                                         de->u.Exception.dwFirstChance, 
610                                         DEBUG_CurrThread->wait_for_first_exception,
611                                         cont);
612             if (DEBUG_CurrThread) {
613                 DEBUG_CurrThread->wait_for_first_exception = 0;
614                 SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
615             }
616             break;
617             
618         case CREATE_THREAD_DEBUG_EVENT:
619             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create thread D @%08lx\n", de->dwProcessId, de->dwThreadId, 
620                          (unsigned long)(LPVOID)de->u.CreateThread.lpStartAddress);
621             
622             if (DEBUG_CurrProcess == NULL) {
623                 DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
624                 break;
625             }
626             if (DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId) != NULL) {
627                 DEBUG_Printf(DBG_CHN_TRACE, "Thread already listed, skipping\n");
628                 break;
629             }
630             
631             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess, 
632                                                de->dwThreadId, 
633                                                de->u.CreateThread.hThread, 
634                                                de->u.CreateThread.lpStartAddress, 
635                                                de->u.CreateThread.lpThreadLocalBase);
636             if (!DEBUG_CurrThread) {
637                 DEBUG_Printf(DBG_CHN_ERR, "Couldn't create thread\n");
638                 break;
639             }
640             DEBUG_InitCurrThread();
641             break;
642             
643         case CREATE_PROCESS_DEBUG_EVENT:
644             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
645                                            de->u.CreateProcessInfo.hProcess, 
646                                            de->u.CreateProcessInfo.lpImageName);
647
648             /* FIXME unicode ? de->u.CreateProcessInfo.fUnicode */
649             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n", 
650                          de->dwProcessId, de->dwThreadId, 
651                          buffer, de->u.CreateProcessInfo.lpImageName,
652                          (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress,
653                          de->u.CreateProcessInfo.dwDebugInfoFileOffset,
654                          de->u.CreateProcessInfo.nDebugInfoSize);
655             
656             if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL) {
657                 if (DEBUG_CurrProcess->handle) {
658                     DEBUG_Printf(DBG_CHN_ERR, "Skipping already defined process\n");
659                     break;
660                 }
661                 DEBUG_CurrProcess->handle = de->u.CreateProcessInfo.hProcess;
662                 if (DEBUG_CurrProcess->imageName == NULL)
663                     DEBUG_CurrProcess->imageName = DBG_strdup(buffer[0] ? buffer : "<Debugged Process>");
664
665             } else {
666                 DEBUG_CurrProcess = DEBUG_AddProcess(de->dwProcessId,
667                                                      de->u.CreateProcessInfo.hProcess,
668                                                      buffer[0] ? buffer : "<Debugged Process>");
669                 if (DEBUG_CurrProcess == NULL) {
670                     DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
671                     break;
672                 }
673             }
674             
675             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create thread I @%08lx\n", 
676                          de->dwProcessId, de->dwThreadId, 
677                          (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress);
678             
679             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,       
680                                                de->dwThreadId, 
681                                                de->u.CreateProcessInfo.hThread, 
682                                                de->u.CreateProcessInfo.lpStartAddress, 
683                                                de->u.CreateProcessInfo.lpThreadLocalBase);
684             if (!DEBUG_CurrThread) {
685                 DEBUG_Printf(DBG_CHN_ERR, "Couldn't create thread\n");
686                 break;
687             }
688             
689             DEBUG_InitCurrProcess();
690             DEBUG_InitCurrThread();
691
692             DEBUG_LoadModule32(DEBUG_CurrProcess->imageName, de->u.CreateProcessInfo.hFile, 
693                                (DWORD)de->u.CreateProcessInfo.lpBaseOfImage);
694
695             if (buffer[0])  /* we got a process name */
696             {
697                 DWORD type;
698                 if (!GetBinaryTypeA( buffer, &type ))
699                 {
700                     /* not a Windows binary, assume it's a Unix executable then */
701                     char unixname[MAX_PATH];
702                     /* HACK!! should fix DEBUG_ReadExecutableDbgInfo to accept DOS filenames */
703                     if (wine_get_unix_file_name( buffer, unixname, sizeof(unixname) ))
704                     {
705                         DEBUG_ReadExecutableDbgInfo( unixname );
706                         break;
707                     }
708                 }
709             }
710             /* if it is a Windows binary, or an invalid or missing file name,
711              * we use wine itself as the main executable */
712             DEBUG_ReadExecutableDbgInfo( "wine" );
713             break;
714             
715         case EXIT_THREAD_DEBUG_EVENT:
716             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exit thread (%ld)\n", 
717                          de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
718             
719             if (DEBUG_CurrThread == NULL) {
720                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
721                 break;
722             }
723             /* FIXME: remove break point set on thread startup */
724             DEBUG_DelThread(DEBUG_CurrThread);
725             break;
726             
727         case EXIT_PROCESS_DEBUG_EVENT:
728             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exit process (%ld)\n", 
729                          de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
730             
731             if (DEBUG_CurrProcess == NULL) {
732                 DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
733                 break;
734             }
735             /* just in case */
736             DEBUG_SetBreakpoints(FALSE);
737             /* kill last thread */
738             DEBUG_DelThread(DEBUG_CurrProcess->threads);
739             DEBUG_DelProcess(DEBUG_CurrProcess);
740
741             DEBUG_Printf(DBG_CHN_MESG, "Process of pid=%08lx has terminated\n", DEBUG_CurrPid);
742             break;
743             
744         case LOAD_DLL_DEBUG_EVENT:
745             if (DEBUG_CurrThread == NULL) {
746                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
747                 break;
748             }
749             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
750                                            DEBUG_CurrThread->process->handle, 
751                                            de->u.LoadDll.lpImageName);
752             
753             /* FIXME unicode: de->u.LoadDll.fUnicode */
754             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n", 
755                          de->dwProcessId, de->dwThreadId, 
756                          buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
757                          de->u.LoadDll.dwDebugInfoFileOffset,
758                          de->u.LoadDll.nDebugInfoSize);
759             _strupr(buffer);
760             DEBUG_LoadModule32(buffer, de->u.LoadDll.hFile, (DWORD)de->u.LoadDll.lpBaseOfDll);
761             DEBUG_CheckDelayedBP();
762             if (DBG_IVAR(BreakOnDllLoad)) {
763                 DEBUG_Printf(DBG_CHN_MESG, "Stopping on DLL %s loading at %08lx\n", 
764                              buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
765                 ret = DEBUG_Parser();
766             }
767             break;
768             
769         case UNLOAD_DLL_DEBUG_EVENT:
770             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: unload DLL @%08lx\n", de->dwProcessId, de->dwThreadId, 
771                          (unsigned long)de->u.UnloadDll.lpBaseOfDll);
772             break;
773             
774         case OUTPUT_DEBUG_STRING_EVENT:
775             if (DEBUG_CurrThread == NULL) {
776                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
777                 break;
778             }
779             
780             DEBUG_ProcessGetString(buffer, sizeof(buffer), 
781                                    DEBUG_CurrThread->process->handle, 
782                                    de->u.DebugString.lpDebugStringData);
783             
784             /* fixme unicode de->u.DebugString.fUnicode ? */
785             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: output debug string (%s)\n", 
786                          de->dwProcessId, de->dwThreadId, buffer);
787             break;
788             
789         case RIP_EVENT:
790             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: rip error=%ld type=%ld\n", 
791                          de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError, 
792                          de->u.RipInfo.dwType);
793             break;
794             
795         default:
796             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: unknown event (%ld)\n", 
797                          de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
798         }
799         
800     } __EXCEPT(wine_dbg) {
801         *cont = 0;
802         ret = TRUE;
803     }
804     __ENDTRY;
805     return ret;
806 }
807
808 static  DWORD   DEBUG_MainLoop(void)
809 {
810     DEBUG_EVENT         de;
811     DWORD               cont;
812     BOOL                ret;
813
814     DEBUG_Printf(DBG_CHN_MESG, " on pid %lx\n", DEBUG_CurrPid);
815     
816     for (ret = TRUE; ret; ) {
817         /* wait until we get at least one loaded process */
818         while (!DEBUG_ProcessList && (ret = DEBUG_Parser()));
819         if (!ret) break;
820
821         while (ret && DEBUG_ProcessList && WaitForDebugEvent(&de, INFINITE)) {
822             ret = DEBUG_HandleDebugEvent(&de, &cont);
823             ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
824         }
825     };
826     
827     DEBUG_Printf(DBG_CHN_MESG, "WineDbg terminated on pid %lx\n", DEBUG_CurrPid);
828
829     return 0;
830 }
831
832 static DWORD DEBUG_AutoMode(void)
833 {
834     DEBUG_EVENT de;
835     DWORD cont;
836     BOOL ret = TRUE;
837
838     DEBUG_Printf(DBG_CHN_MESG, " on pid %lx\n", DEBUG_CurrPid);
839
840     while (ret && DEBUG_ProcessList && WaitForDebugEvent(&de, INFINITE))
841     {
842         ret = DEBUG_HandleDebugEvent(&de, &cont);
843         ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
844     }
845     /* print some extra information */
846     DEBUG_Printf(DBG_CHN_MESG, "Modules:\n");
847     DEBUG_WalkModules();
848     DEBUG_Printf(DBG_CHN_MESG, "Threads:\n");
849     DEBUG_WalkThreads();
850
851     DEBUG_Printf(DBG_CHN_MESG, "WineDbg terminated on pid %lx\n", DEBUG_CurrPid);
852     return 0;
853 }
854
855 static  BOOL    DEBUG_Start(LPSTR cmdLine)
856 {
857     PROCESS_INFORMATION info;
858     STARTUPINFOA        startup;
859
860     memset(&startup, 0, sizeof(startup));
861     startup.cb = sizeof(startup);
862     startup.dwFlags = STARTF_USESHOWWINDOW;
863     startup.wShowWindow = SW_SHOWNORMAL;
864     
865     if (!CreateProcess(NULL, cmdLine, NULL, NULL, 
866                        FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info)) {
867         DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
868         return FALSE;
869     }
870     DEBUG_CurrPid = info.dwProcessId;
871     if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0, NULL))) return FALSE;
872
873     return TRUE;
874 }
875
876 void    DEBUG_Run(const char* args)
877 {
878     DBG_MODULE* wmod = DEBUG_GetProcessMainModule(DEBUG_CurrProcess);
879     const char* pgm = (wmod) ? wmod->module_name : "none";
880
881     if (args) {
882         DEBUG_Printf(DBG_CHN_MESG, "Run (%s) with '%s'\n", pgm, args);
883     } else {
884         if (!DEBUG_LastCmdLine) {
885             DEBUG_Printf(DBG_CHN_MESG, "Cannot find previously used command line.\n");
886             return;
887         }
888         DEBUG_Start(DEBUG_LastCmdLine);
889     }
890 }
891
892 int DEBUG_main(int argc, char** argv)
893 {
894     DWORD       retv = 0;
895
896 #ifdef DBG_need_heap
897     /* Initialize the debugger heap. */
898     dbg_heap = HeapCreate(HEAP_NO_SERIALIZE, 0x1000, 0x8000000); /* 128MB */
899 #endif
900     
901     /* Initialize the type handling stuff. */
902     DEBUG_InitTypes();
903     DEBUG_InitCVDataTypes();    
904
905     /* Initialize internal vars (types must have been initialized before) */
906     if (!DEBUG_IntVarsRW(TRUE)) return -1;
907
908     if (argc > 1 && !strcmp( argv[1], "--auto" ))
909     {
910         argc--;
911         argv++;
912         automatic_mode = 1;
913         /* force some internal variables */
914         DBG_IVAR(UseXTerm) = 0;
915         DBG_IVAR(BreakOnDllLoad) = 0;
916         DBG_IVAR(ConChannelMask) = 0;
917         DBG_IVAR(StdChannelMask) = DBG_CHN_MESG;
918     }
919
920     /* keep it as a guiexe for now, so that Wine won't touch the Unix stdin, 
921      * stdout and stderr streams
922      */
923     if (DBG_IVAR(UseXTerm)) {
924         COORD           pos;
925         
926         /* This is a hack: it forces creation of an xterm, not done by default */
927         pos.X = 0; pos.Y = 1;
928         SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
929     }
930
931     DEBUG_Printf(DBG_CHN_MESG, "WineDbg starting... ");
932         
933     if (argc == 3) {
934         HANDLE  hEvent;
935         DWORD   pid;
936
937         if ((pid = atoi(argv[1])) != 0 && (hEvent = (HANDLE)atoi(argv[2])) != 0) {
938             if (!DEBUG_Attach(pid, TRUE)) {
939                 /* don't care about result */
940                 SetEvent(hEvent);
941                 goto leave;
942             }
943             if (!SetEvent(hEvent)) {
944                 DEBUG_Printf(DBG_CHN_ERR, "Invalid event handle: %p\n", hEvent);
945                 goto leave;
946             }
947             CloseHandle(hEvent);
948             DEBUG_CurrPid = pid;
949         }
950     }
951         
952     if (DEBUG_CurrPid == 0 && argc > 1) {
953         int     i, len;
954         LPSTR   cmdLine;
955                 
956         if (!(cmdLine = DBG_alloc(len = 1))) goto oom_leave;
957         cmdLine[0] = '\0';
958
959         for (i = 1; i < argc; i++) {
960             len += strlen(argv[i]) + 1;
961             if (!(cmdLine = DBG_realloc(cmdLine, len))) goto oom_leave;
962             strcat(cmdLine, argv[i]);
963             cmdLine[len - 2] = ' ';
964             cmdLine[len - 1] = '\0';
965         }
966
967         if (!DEBUG_Start(cmdLine)) {
968             DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
969             goto leave;
970         }
971         DBG_free(DEBUG_LastCmdLine);
972         DEBUG_LastCmdLine = cmdLine;
973     }
974
975     if (automatic_mode)
976     {
977         retv = DEBUG_AutoMode();
978         /* don't save modified variables in auto mode */
979     }
980     else
981     {
982         retv = DEBUG_MainLoop();
983         /* saves modified variables */
984         DEBUG_IntVarsRW(FALSE);
985     }
986
987  leave:
988     return retv;
989
990  oom_leave:
991     DEBUG_Printf(DBG_CHN_MESG, "Out of memory\n");
992     goto leave;
993 }