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