- fixes debugger output
[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 #ifdef __i386__
286         if (DEBUG_IsSelectorSystem(DEBUG_context.SegCs))
287             DEBUG_Printf(DBG_CHN_MESG, " in 32-bit code (0x%08lx).\n", addr.off);
288         else
289             DEBUG_Printf(DBG_CHN_MESG, " in 16-bit code (%04x:%04lx).\n",
290                          LOWORD(addr.seg), addr.off);
291 #else
292         DEBUG_Printf(DBG_CHN_MESG, " (0x%08lx).\n", addr.off);
293 #endif
294     }
295
296     DEBUG_LoadEntryPoints("Loading new modules symbols:\n");
297
298     if (!force && is_debug && 
299         DEBUG_ShouldContinue(&addr,
300                              code, 
301                              DEBUG_CurrThread->dbg_exec_mode, 
302                              &DEBUG_CurrThread->dbg_exec_count))
303         return FALSE;
304
305 #ifdef __i386__
306     switch (newmode = DEBUG_GetSelectorType(addr.seg)) {
307     case 16: case 32: break;
308     default: DEBUG_Printf(DBG_CHN_MESG, "Bad CS (%ld)\n", addr.seg); newmode = 32;
309     }
310 #else
311     newmode = 32;
312 #endif
313     if (newmode != DEBUG_CurrThread->dbg_mode)
314         DEBUG_Printf(DBG_CHN_MESG,"In %d bit mode.\n", DEBUG_CurrThread->dbg_mode = newmode);
315
316     DEBUG_DoDisplay();
317
318     if (is_debug || force) {
319         /*
320          * Do a quiet backtrace so that we have an idea of what the situation
321          * is WRT the source files.
322          */
323         DEBUG_BackTrace(FALSE);
324     } else {
325         /* This is a real crash, dump some info */
326         DEBUG_InfoRegisters();
327         DEBUG_InfoStack();
328 #ifdef __i386__
329         if (DEBUG_CurrThread->dbg_mode == 16) {
330             DEBUG_InfoSegments(DEBUG_context.SegDs >> 3, 1);
331             if (DEBUG_context.SegEs != DEBUG_context.SegDs)
332                 DEBUG_InfoSegments(DEBUG_context.SegEs >> 3, 1);
333         }
334         DEBUG_InfoSegments(DEBUG_context.SegFs >> 3, 1);
335 #endif
336         DEBUG_BackTrace(TRUE);
337     }
338
339     if (!is_debug ||
340         (DEBUG_CurrThread->dbg_exec_mode == EXEC_STEPI_OVER) ||
341         (DEBUG_CurrThread->dbg_exec_mode == EXEC_STEPI_INSTR)) {
342
343         struct list_id list;
344
345         /* Show where we crashed */
346         curr_frame = 0;
347         DEBUG_DisassembleInstruction(&addr);
348
349         /* resets list internal arguments so we can look at source code when needed */
350         DEBUG_FindNearestSymbol(&addr, TRUE, NULL, 0, &list); 
351         if (list.sourcefile) DEBUG_List(&list, NULL, 0);
352     }
353     return TRUE;
354 }
355
356 static  DWORD   DEBUG_ExceptionEpilog(void)
357 {
358     DEBUG_CurrThread->dbg_exec_mode = DEBUG_RestartExecution(DEBUG_CurrThread->dbg_exec_mode, 
359                                                              DEBUG_CurrThread->dbg_exec_count);
360     /*
361      * This will have gotten absorbed into the breakpoint info
362      * if it was used.  Otherwise it would have been ignored.
363      * In any case, we don't mess with it any more.
364      */
365     if (DEBUG_CurrThread->dbg_exec_mode == EXEC_CONT || DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS)
366         DEBUG_CurrThread->dbg_exec_count = 0;
367     
368     return (DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS) ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
369 }
370
371 static  BOOL    DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force, LPDWORD cont)
372 {
373     BOOL        is_debug = FALSE;
374     BOOL        ret = TRUE;
375
376     *cont = DBG_CONTINUE;
377     if (first_chance && !force && !DBG_IVAR(BreakOnFirstChance)) return TRUE;
378
379     switch (rec->ExceptionCode)
380     {
381     case EXCEPTION_BREAKPOINT:
382     case EXCEPTION_SINGLE_STEP:
383         is_debug = TRUE;
384         break;
385     }
386
387     if (!is_debug)
388     {
389         /* print some infos */
390         DEBUG_Printf(DBG_CHN_MESG, "%s: ",
391                       first_chance ? "First chance exception" : "Unhandled exception");
392         switch (rec->ExceptionCode)
393         {
394         case EXCEPTION_INT_DIVIDE_BY_ZERO:
395             DEBUG_Printf(DBG_CHN_MESG, "divide by zero");
396             break;
397         case EXCEPTION_INT_OVERFLOW:
398             DEBUG_Printf(DBG_CHN_MESG, "overflow");
399             break;
400         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
401             DEBUG_Printf(DBG_CHN_MESG, "array bounds ");
402             break;
403         case EXCEPTION_ILLEGAL_INSTRUCTION:
404             DEBUG_Printf(DBG_CHN_MESG, "illegal instruction");
405             break;
406         case EXCEPTION_STACK_OVERFLOW:
407             DEBUG_Printf(DBG_CHN_MESG, "stack overflow");
408             break;
409         case EXCEPTION_PRIV_INSTRUCTION:
410             DEBUG_Printf(DBG_CHN_MESG, "priviledged instruction");
411             break;
412         case EXCEPTION_ACCESS_VIOLATION:
413             if (rec->NumberParameters == 2)
414                 DEBUG_Printf(DBG_CHN_MESG, "page fault on %s access to 0x%08lx", 
415                               rec->ExceptionInformation[0] ? "write" : "read",
416                               rec->ExceptionInformation[1]);
417             else
418                 DEBUG_Printf(DBG_CHN_MESG, "page fault");
419             break;
420         case EXCEPTION_DATATYPE_MISALIGNMENT:
421             DEBUG_Printf(DBG_CHN_MESG, "Alignment");
422             break;
423         case CONTROL_C_EXIT:
424             DEBUG_Printf(DBG_CHN_MESG, "^C");
425             break;
426         case EXCEPTION_CRITICAL_SECTION_WAIT:
427             DEBUG_Printf(DBG_CHN_MESG, "critical section %08lx wait failed", 
428                           rec->ExceptionInformation[0]);
429             if (!DBG_IVAR(BreakOnCritSectTimeOut))
430             {
431                 DEBUG_Printf(DBG_CHN_MESG, "\n");
432                 return TRUE;
433             }
434             break;
435         default:
436             DEBUG_Printf(DBG_CHN_MESG, "%08lx", rec->ExceptionCode);
437             break;
438         }
439         DEBUG_Printf(DBG_CHN_MESG, "\n");
440     }
441
442     DEBUG_Printf(DBG_CHN_TRACE, 
443                  "Entering debugger     PC=%lx EFL=%08lx mode=%d count=%d\n",
444 #ifdef __i386__
445                  DEBUG_context.Eip, DEBUG_context.EFlags, 
446 #else
447                  0L, 0L,
448 #endif
449                  DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
450
451     if (DEBUG_ExceptionProlog(is_debug, force, rec->ExceptionCode)) {
452         while ((ret = DEBUG_Parser())) {
453             if (DEBUG_ValidateRegisters()) {
454                 if (DEBUG_CurrThread->dbg_exec_mode != EXEC_PASS || first_chance)
455                     break;
456                 DEBUG_Printf(DBG_CHN_MESG, "Cannot pass on last chance exception. You must use cont\n");
457             }
458         }
459     }
460     *cont = DEBUG_ExceptionEpilog();
461
462     DEBUG_Printf(DBG_CHN_TRACE, 
463                  "Exiting debugger      PC=%lx EFL=%08lx mode=%d count=%d\n",
464 #ifdef __i386__
465                  DEBUG_context.Eip, DEBUG_context.EFlags, 
466 #else
467                  0L, 0L,
468 #endif
469                  DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
470
471     return ret;
472 }
473
474 static  BOOL    DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
475 {
476     char                buffer[256];
477     BOOL                ret;
478
479     DEBUG_CurrPid = de->dwProcessId;
480     DEBUG_CurrTid = de->dwThreadId;
481
482     __TRY {
483         ret = TRUE;
484         *cont = 0L;
485         
486         if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL)
487             DEBUG_CurrThread = DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId);
488         else 
489             DEBUG_CurrThread = NULL;
490         
491         switch (de->dwDebugEventCode) {
492         case EXCEPTION_DEBUG_EVENT:
493             if (!DEBUG_CurrThread) {
494                 DEBUG_Printf(DBG_CHN_ERR, "%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
495                              de->dwProcessId, de->dwThreadId);
496                 break;
497             }
498             
499             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exception code=%08lx\n", 
500                          de->dwProcessId, de->dwThreadId, 
501                          de->u.Exception.ExceptionRecord.ExceptionCode);
502
503             if (DEBUG_CurrProcess->continue_on_first_exception) {
504                 DEBUG_CurrProcess->continue_on_first_exception = FALSE;
505                 if (!DBG_IVAR(BreakOnAttach)) {
506                     *cont = DBG_CONTINUE;
507                     break;
508                 }
509             }
510
511             DEBUG_context.ContextFlags =  CONTEXT_CONTROL
512                                         | CONTEXT_INTEGER
513 #ifdef CONTEXT_SEGMENTS
514                                         | CONTEXT_SEGMENTS
515 #endif
516 #ifdef CONTEXT_DEBUG_REGISTERS
517                                         | CONTEXT_DEBUG_REGISTERS
518 #endif
519                                         ;
520
521             if (!GetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context)) {
522                 DEBUG_Printf(DBG_CHN_WARN, "Can't get thread's context\n");
523                 break;
524             }
525             
526             ret = DEBUG_HandleException(&de->u.Exception.ExceptionRecord, 
527                                         de->u.Exception.dwFirstChance, 
528                                         DEBUG_CurrThread->wait_for_first_exception,
529                                         cont);
530             if (DEBUG_CurrThread) {
531                 DEBUG_CurrThread->wait_for_first_exception = 0;
532                 SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
533             }
534             break;
535             
536         case CREATE_THREAD_DEBUG_EVENT:
537             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create thread D @%08lx\n", de->dwProcessId, de->dwThreadId, 
538                          (unsigned long)(LPVOID)de->u.CreateThread.lpStartAddress);
539             
540             if (DEBUG_CurrProcess == NULL) {
541                 DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
542                 break;
543             }
544             if (DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId) != NULL) {
545                 DEBUG_Printf(DBG_CHN_TRACE, "Thread already listed, skipping\n");
546                 break;
547             }
548             
549             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess, 
550                                                de->dwThreadId, 
551                                                de->u.CreateThread.hThread, 
552                                                de->u.CreateThread.lpStartAddress, 
553                                                de->u.CreateThread.lpThreadLocalBase);
554             if (!DEBUG_CurrThread) {
555                 DEBUG_Printf(DBG_CHN_ERR, "Couldn't create thread\n");
556                 break;
557             }
558             DEBUG_InitCurrThread();
559             break;
560             
561         case CREATE_PROCESS_DEBUG_EVENT:
562             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
563                                            de->u.CreateProcessInfo.hProcess, 
564                                            de->u.CreateProcessInfo.lpImageName);
565             
566             /* FIXME unicode ? de->u.CreateProcessInfo.fUnicode */
567             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create process %s @%08lx (%ld<%ld>)\n", 
568                          de->dwProcessId, de->dwThreadId, 
569                          buffer,
570                          (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress,
571                          de->u.CreateProcessInfo.dwDebugInfoFileOffset,
572                          de->u.CreateProcessInfo.nDebugInfoSize);
573             
574             if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL) {
575                 if (DEBUG_CurrProcess->handle) {
576                     DEBUG_Printf(DBG_CHN_ERR, "Skipping already defined process\n");
577                     break;
578                 }
579                 DEBUG_CurrProcess->handle = de->u.CreateProcessInfo.hProcess;
580             } else {
581                 DEBUG_CurrProcess = DEBUG_AddProcess(de->dwProcessId,
582                                                      de->u.CreateProcessInfo.hProcess);
583                 if (DEBUG_CurrProcess == NULL) {
584                     DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
585                     break;
586                 }
587             }
588             
589             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create thread I @%08lx\n", 
590                          de->dwProcessId, de->dwThreadId, 
591                          (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress);
592             
593             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,       
594                                                de->dwThreadId, 
595                                                de->u.CreateProcessInfo.hThread, 
596                                                de->u.CreateProcessInfo.lpStartAddress, 
597                                                de->u.CreateProcessInfo.lpThreadLocalBase);
598             if (!DEBUG_CurrThread) {
599                 DEBUG_Printf(DBG_CHN_ERR, "Couldn't create thread\n");
600                 break;
601             }
602             
603             DEBUG_InitCurrProcess();
604             DEBUG_InitCurrThread();
605
606             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
607                                            DEBUG_CurrThread->process->handle, 
608                                            de->u.CreateProcessInfo.lpImageName);
609             DEBUG_LoadModule32(buffer[0] ? buffer : "<Debugged process>",
610                                de->u.CreateProcessInfo.hFile, 
611                                (DWORD)de->u.CreateProcessInfo.lpBaseOfImage);
612
613             if (buffer[0])  /* we got a process name */
614             {
615                 DWORD type;
616                 if (!GetBinaryTypeA( buffer, &type ))
617                 {
618                     /* not a Windows binary, assume it's a Unix executable then */
619                     DOS_FULL_NAME fullname;
620                     /* HACK!! should fix DEBUG_ReadExecutableDbgInfo to accept DOS filenames */
621                     if (DOSFS_GetFullName( buffer, TRUE, &fullname ))
622                     {
623                         DEBUG_ReadExecutableDbgInfo( fullname.long_name );
624                         break;
625                     }
626                 }
627             }
628             /* if it is a Windows binary, or an invalid or missing file name,
629              * we use wine itself as the main executable */
630             DEBUG_ReadExecutableDbgInfo( "wine" );
631             break;
632             
633         case EXIT_THREAD_DEBUG_EVENT:
634             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exit thread (%ld)\n", 
635                          de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
636             
637             if (DEBUG_CurrThread == NULL) {
638                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
639                 break;
640             }
641             /* FIXME: remove break point set on thread startup */
642             DEBUG_DelThread(DEBUG_CurrThread);
643             break;
644             
645         case EXIT_PROCESS_DEBUG_EVENT:
646             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exit process (%ld)\n", 
647                          de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
648             
649             if (DEBUG_CurrProcess == NULL) {
650                 DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
651                 break;
652             }
653             /* just in case */
654             DEBUG_SetBreakpoints(FALSE);
655             /* kill last thread */
656             DEBUG_DelThread(DEBUG_CurrProcess->threads);
657             DEBUG_DelProcess(DEBUG_CurrProcess);
658
659             DEBUG_Printf(DBG_CHN_MESG, "Process of pid=%08lx has terminated\n", DEBUG_CurrPid);
660             break;
661             
662         case LOAD_DLL_DEBUG_EVENT:
663             if (DEBUG_CurrThread == NULL) {
664                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
665                 break;
666             }
667             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
668                                            DEBUG_CurrThread->process->handle, 
669                                            de->u.LoadDll.lpImageName);
670             
671             /* FIXME unicode: de->u.LoadDll.fUnicode */
672             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n", 
673                          de->dwProcessId, de->dwThreadId, 
674                          buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
675                          de->u.LoadDll.dwDebugInfoFileOffset,
676                          de->u.LoadDll.nDebugInfoSize);
677             CharUpper(buffer);
678             DEBUG_LoadModule32(buffer, de->u.LoadDll.hFile, (DWORD)de->u.LoadDll.lpBaseOfDll);
679             if (DBG_IVAR(BreakOnDllLoad)) {
680                 DEBUG_Printf(DBG_CHN_MESG, "Stopping on DLL %s loading at %08lx\n", 
681                              buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
682                 ret = DEBUG_Parser();
683             }
684             break;
685             
686         case UNLOAD_DLL_DEBUG_EVENT:
687             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: unload DLL @%08lx\n", de->dwProcessId, de->dwThreadId, 
688                          (unsigned long)de->u.UnloadDll.lpBaseOfDll);
689             break;
690             
691         case OUTPUT_DEBUG_STRING_EVENT:
692             if (DEBUG_CurrThread == NULL) {
693                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
694                 break;
695             }
696             
697             DEBUG_ProcessGetString(buffer, sizeof(buffer), 
698                                    DEBUG_CurrThread->process->handle, 
699                                    de->u.DebugString.lpDebugStringData);
700             
701             /* fixme unicode de->u.DebugString.fUnicode ? */
702             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: output debug string (%s)\n", 
703                          de->dwProcessId, de->dwThreadId, buffer);
704             break;
705             
706         case RIP_EVENT:
707             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: rip error=%ld type=%ld\n", 
708                          de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError, 
709                          de->u.RipInfo.dwType);
710             break;
711             
712         default:
713             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: unknown event (%ld)\n", 
714                          de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
715         }
716         
717     } __EXCEPT(wine_dbg) {
718         *cont = 0;
719         ret = TRUE;
720     }
721     __ENDTRY;
722     return ret;
723 }
724
725 static  DWORD   DEBUG_MainLoop(void)
726 {
727     DEBUG_EVENT         de;
728     DWORD               cont;
729     BOOL                ret;
730
731     DEBUG_Printf(DBG_CHN_MESG, " on pid %ld\n", DEBUG_CurrPid);
732     
733     for (ret = TRUE; ret; ) {
734         /* wait until we get at least one loaded process */
735         while (!DEBUG_ProcessList && (ret = DEBUG_Parser()));
736         if (!ret) break;
737
738         while (ret && DEBUG_ProcessList && WaitForDebugEvent(&de, INFINITE)) {
739             ret = DEBUG_HandleDebugEvent(&de, &cont);
740             ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
741         }
742     };
743     
744     DEBUG_Printf(DBG_CHN_MESG, "WineDbg terminated on pid %ld\n", DEBUG_CurrPid);
745
746     return 0;
747 }
748
749 static  BOOL    DEBUG_Start(LPSTR cmdLine)
750 {
751     PROCESS_INFORMATION info;
752     STARTUPINFOA        startup;
753
754     memset(&startup, 0, sizeof(startup));
755     startup.cb = sizeof(startup);
756     startup.dwFlags = STARTF_USESHOWWINDOW;
757     startup.wShowWindow = SW_SHOWNORMAL;
758     
759     if (!CreateProcess(NULL, cmdLine, NULL, NULL, 
760                        FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info)) {
761         DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
762         return FALSE;
763     }
764     DEBUG_CurrPid = info.dwProcessId;
765     if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0))) return FALSE;
766
767     return TRUE;
768 }
769
770 void    DEBUG_Run(const char* args)
771 {
772     DBG_MODULE* wmod = DEBUG_GetProcessMainModule(DEBUG_CurrProcess);
773     const char* pgm = (wmod) ? wmod->module_name : "none";
774
775     if (args) {
776         DEBUG_Printf(DBG_CHN_MESG, "Run (%s) with '%s'\n", pgm, args);
777     } else {
778         if (!DEBUG_LastCmdLine) {
779             DEBUG_Printf(DBG_CHN_MESG, "Cannot find previously used command line.\n");
780             return;
781         }
782         DEBUG_Start(DEBUG_LastCmdLine);
783     }
784 }
785
786 int DEBUG_main(int argc, char** argv)
787 {
788     DWORD       retv = 0;
789
790 #ifdef DBG_need_heap
791     /* Initialize the debugger heap. */
792     dbg_heap = HeapCreate(HEAP_NO_SERIALIZE, 0x1000, 0x8000000); /* 128MB */
793 #endif
794     
795     /* Initialize the type handling stuff. */
796     DEBUG_InitTypes();
797     DEBUG_InitCVDataTypes();    
798
799     /* Initialize internal vars (types must be initialized before) */
800     if (!DEBUG_IntVarsRW(TRUE)) return -1;
801
802     /* keep it as a guiexe for now, so that Wine won't touch the Unix stdin, 
803      * stdout and stderr streams
804      */
805     if (DBG_IVAR(UseXTerm)) {
806         COORD           pos;
807         
808         /* This is a hack: it forces creation of an xterm, not done by default */
809         pos.X = 0; pos.Y = 1;
810         SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
811     }
812
813     DEBUG_Printf(DBG_CHN_MESG, "Starting WineDbg... ");
814
815     if (argc == 3) {
816         HANDLE  hEvent;
817         DWORD   pid;
818
819         if ((pid = atoi(argv[1])) != 0 && (hEvent = atoi(argv[2])) != 0) {
820             BOOL        ret = DEBUG_Attach(pid, TRUE);
821
822             SetEvent(hEvent);
823             CloseHandle(hEvent);
824             if (!ret) {
825                 DEBUG_Printf(DBG_CHN_ERR, "Can't attach process %ld: %ld\n", 
826                              DEBUG_CurrPid, GetLastError());
827                 goto leave;
828             }
829             DEBUG_CurrPid = pid;
830         }
831     }
832         
833     if (DEBUG_CurrPid == 0 && argc > 1) {
834         int     i, len;
835         LPSTR   cmdLine;
836                 
837         if (!(cmdLine = DBG_alloc(len = 1))) goto oom_leave;
838         cmdLine[0] = '\0';
839
840         for (i = 1; i < argc; i++) {
841             len += strlen(argv[i]) + 1;
842             if (!(cmdLine = DBG_realloc(cmdLine, len))) goto oom_leave;
843             strcat(cmdLine, argv[i]);
844             cmdLine[len - 2] = ' ';
845             cmdLine[len - 1] = '\0';
846         }
847
848         if (!DEBUG_Start(cmdLine)) {
849             DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
850             goto leave;
851         }
852         DBG_free(DEBUG_LastCmdLine);
853         DEBUG_LastCmdLine = cmdLine;
854     }
855
856     retv = DEBUG_MainLoop();
857  leave:
858     /* saves modified variables */
859     DEBUG_IntVarsRW(FALSE);
860
861     return retv;
862
863  oom_leave:
864     DEBUG_Printf(DBG_CHN_MESG, "Out of memory\n");
865     goto leave;
866 }