Removed .s files.
[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_WINE_STUB:
448             {
449                 char dll[32], name[64];
450                 DEBUG_ProcessGetString( dll, sizeof(dll), DEBUG_CurrThread->process->handle,
451                                         (char *)rec->ExceptionInformation[0] );
452                 DEBUG_ProcessGetString( name, sizeof(name), DEBUG_CurrThread->process->handle,
453                                         (char *)rec->ExceptionInformation[1] );
454                 DEBUG_Printf(DBG_CHN_MESG, "unimplemented function %s.%s called", dll, name );
455             }
456             break;
457         case EXCEPTION_VM86_INTx:
458             DEBUG_Printf(DBG_CHN_MESG, "interrupt %02lx in vm86 mode",
459                          rec->ExceptionInformation[0]);
460             break;
461         case EXCEPTION_VM86_STI:
462             DEBUG_Printf(DBG_CHN_MESG, "sti in vm86 mode");
463             break;
464         case EXCEPTION_VM86_PICRETURN:
465             DEBUG_Printf(DBG_CHN_MESG, "PIC return in vm86 mode");
466             break;
467         default:
468             DEBUG_Printf(DBG_CHN_MESG, "%08lx", rec->ExceptionCode);
469             break;
470         }
471         DEBUG_Printf(DBG_CHN_MESG, "\n");
472     }
473
474     DEBUG_Printf(DBG_CHN_TRACE, 
475                  "Entering debugger     PC=%lx EFL=%08lx mode=%d count=%d\n",
476 #ifdef __i386__
477                  DEBUG_context.Eip, DEBUG_context.EFlags, 
478 #else
479                  0L, 0L,
480 #endif
481                  DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
482
483     if (DEBUG_ExceptionProlog(is_debug, force, rec->ExceptionCode)) {
484         while ((ret = DEBUG_Parser())) {
485             if (DEBUG_ValidateRegisters()) {
486                 if (DEBUG_CurrThread->dbg_exec_mode != EXEC_PASS || first_chance)
487                     break;
488                 DEBUG_Printf(DBG_CHN_MESG, "Cannot pass on last chance exception. You must use cont\n");
489             }
490         }
491     }
492     *cont = DEBUG_ExceptionEpilog();
493
494     DEBUG_Printf(DBG_CHN_TRACE, 
495                  "Exiting debugger      PC=%lx EFL=%08lx mode=%d count=%d\n",
496 #ifdef __i386__
497                  DEBUG_context.Eip, DEBUG_context.EFlags, 
498 #else
499                  0L, 0L,
500 #endif
501                  DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
502
503     return ret;
504 }
505
506 static  BOOL    DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
507 {
508     char                buffer[256];
509     BOOL                ret;
510
511     DEBUG_CurrPid = de->dwProcessId;
512     DEBUG_CurrTid = de->dwThreadId;
513
514     __TRY {
515         ret = TRUE;
516         *cont = 0L;
517         
518         if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL)
519             DEBUG_CurrThread = DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId);
520         else 
521             DEBUG_CurrThread = NULL;
522         
523         switch (de->dwDebugEventCode) {
524         case EXCEPTION_DEBUG_EVENT:
525             if (!DEBUG_CurrThread) {
526                 DEBUG_Printf(DBG_CHN_ERR, "%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
527                              de->dwProcessId, de->dwThreadId);
528                 break;
529             }
530             
531             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exception code=%08lx\n", 
532                          de->dwProcessId, de->dwThreadId, 
533                          de->u.Exception.ExceptionRecord.ExceptionCode);
534
535             if (DEBUG_CurrProcess->continue_on_first_exception) {
536                 DEBUG_CurrProcess->continue_on_first_exception = FALSE;
537                 if (!DBG_IVAR(BreakOnAttach)) {
538                     *cont = DBG_CONTINUE;
539                     break;
540                 }
541             }
542
543             DEBUG_context.ContextFlags =  CONTEXT_CONTROL
544                                         | CONTEXT_INTEGER
545 #ifdef CONTEXT_SEGMENTS
546                                         | CONTEXT_SEGMENTS
547 #endif
548 #ifdef CONTEXT_DEBUG_REGISTERS
549                                         | CONTEXT_DEBUG_REGISTERS
550 #endif
551                                         ;
552
553             if (!GetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context)) {
554                 DEBUG_Printf(DBG_CHN_WARN, "Can't get thread's context\n");
555                 break;
556             }
557             
558             ret = DEBUG_HandleException(&de->u.Exception.ExceptionRecord, 
559                                         de->u.Exception.dwFirstChance, 
560                                         DEBUG_CurrThread->wait_for_first_exception,
561                                         cont);
562             if (DEBUG_CurrThread) {
563                 DEBUG_CurrThread->wait_for_first_exception = 0;
564                 SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
565             }
566             break;
567             
568         case CREATE_THREAD_DEBUG_EVENT:
569             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create thread D @%08lx\n", de->dwProcessId, de->dwThreadId, 
570                          (unsigned long)(LPVOID)de->u.CreateThread.lpStartAddress);
571             
572             if (DEBUG_CurrProcess == NULL) {
573                 DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
574                 break;
575             }
576             if (DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId) != NULL) {
577                 DEBUG_Printf(DBG_CHN_TRACE, "Thread already listed, skipping\n");
578                 break;
579             }
580             
581             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess, 
582                                                de->dwThreadId, 
583                                                de->u.CreateThread.hThread, 
584                                                de->u.CreateThread.lpStartAddress, 
585                                                de->u.CreateThread.lpThreadLocalBase);
586             if (!DEBUG_CurrThread) {
587                 DEBUG_Printf(DBG_CHN_ERR, "Couldn't create thread\n");
588                 break;
589             }
590             DEBUG_InitCurrThread();
591             break;
592             
593         case CREATE_PROCESS_DEBUG_EVENT:
594             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
595                                            de->u.CreateProcessInfo.hProcess, 
596                                            de->u.CreateProcessInfo.lpImageName);
597             
598             /* FIXME unicode ? de->u.CreateProcessInfo.fUnicode */
599             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create process %s @%08lx (%ld<%ld>)\n", 
600                          de->dwProcessId, de->dwThreadId, 
601                          buffer,
602                          (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress,
603                          de->u.CreateProcessInfo.dwDebugInfoFileOffset,
604                          de->u.CreateProcessInfo.nDebugInfoSize);
605             
606             if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL) {
607                 if (DEBUG_CurrProcess->handle) {
608                     DEBUG_Printf(DBG_CHN_ERR, "Skipping already defined process\n");
609                     break;
610                 }
611                 DEBUG_CurrProcess->handle = de->u.CreateProcessInfo.hProcess;
612             } else {
613                 DEBUG_CurrProcess = DEBUG_AddProcess(de->dwProcessId,
614                                                      de->u.CreateProcessInfo.hProcess);
615                 if (DEBUG_CurrProcess == NULL) {
616                     DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
617                     break;
618                 }
619             }
620             
621             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create thread I @%08lx\n", 
622                          de->dwProcessId, de->dwThreadId, 
623                          (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress);
624             
625             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,       
626                                                de->dwThreadId, 
627                                                de->u.CreateProcessInfo.hThread, 
628                                                de->u.CreateProcessInfo.lpStartAddress, 
629                                                de->u.CreateProcessInfo.lpThreadLocalBase);
630             if (!DEBUG_CurrThread) {
631                 DEBUG_Printf(DBG_CHN_ERR, "Couldn't create thread\n");
632                 break;
633             }
634             
635             DEBUG_InitCurrProcess();
636             DEBUG_InitCurrThread();
637
638             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
639                                            DEBUG_CurrThread->process->handle, 
640                                            de->u.CreateProcessInfo.lpImageName);
641             DEBUG_LoadModule32(buffer[0] ? buffer : "<Debugged process>",
642                                de->u.CreateProcessInfo.hFile, 
643                                (DWORD)de->u.CreateProcessInfo.lpBaseOfImage);
644
645             if (buffer[0])  /* we got a process name */
646             {
647                 DWORD type;
648                 if (!GetBinaryTypeA( buffer, &type ))
649                 {
650                     /* not a Windows binary, assume it's a Unix executable then */
651                     DOS_FULL_NAME fullname;
652                     /* HACK!! should fix DEBUG_ReadExecutableDbgInfo to accept DOS filenames */
653                     if (DOSFS_GetFullName( buffer, TRUE, &fullname ))
654                     {
655                         DEBUG_ReadExecutableDbgInfo( fullname.long_name );
656                         break;
657                     }
658                 }
659             }
660             /* if it is a Windows binary, or an invalid or missing file name,
661              * we use wine itself as the main executable */
662             DEBUG_ReadExecutableDbgInfo( "wine" );
663             break;
664             
665         case EXIT_THREAD_DEBUG_EVENT:
666             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exit thread (%ld)\n", 
667                          de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
668             
669             if (DEBUG_CurrThread == NULL) {
670                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
671                 break;
672             }
673             /* FIXME: remove break point set on thread startup */
674             DEBUG_DelThread(DEBUG_CurrThread);
675             break;
676             
677         case EXIT_PROCESS_DEBUG_EVENT:
678             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: exit process (%ld)\n", 
679                          de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
680             
681             if (DEBUG_CurrProcess == NULL) {
682                 DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
683                 break;
684             }
685             /* just in case */
686             DEBUG_SetBreakpoints(FALSE);
687             /* kill last thread */
688             DEBUG_DelThread(DEBUG_CurrProcess->threads);
689             DEBUG_DelProcess(DEBUG_CurrProcess);
690
691             DEBUG_Printf(DBG_CHN_MESG, "Process of pid=%08lx has terminated\n", DEBUG_CurrPid);
692             break;
693             
694         case LOAD_DLL_DEBUG_EVENT:
695             if (DEBUG_CurrThread == NULL) {
696                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
697                 break;
698             }
699             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
700                                            DEBUG_CurrThread->process->handle, 
701                                            de->u.LoadDll.lpImageName);
702             
703             /* FIXME unicode: de->u.LoadDll.fUnicode */
704             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n", 
705                          de->dwProcessId, de->dwThreadId, 
706                          buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
707                          de->u.LoadDll.dwDebugInfoFileOffset,
708                          de->u.LoadDll.nDebugInfoSize);
709             CharUpper(buffer);
710             DEBUG_LoadModule32(buffer, de->u.LoadDll.hFile, (DWORD)de->u.LoadDll.lpBaseOfDll);
711             if (DBG_IVAR(BreakOnDllLoad)) {
712                 DEBUG_Printf(DBG_CHN_MESG, "Stopping on DLL %s loading at %08lx\n", 
713                              buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
714                 ret = DEBUG_Parser();
715             }
716             break;
717             
718         case UNLOAD_DLL_DEBUG_EVENT:
719             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: unload DLL @%08lx\n", de->dwProcessId, de->dwThreadId, 
720                          (unsigned long)de->u.UnloadDll.lpBaseOfDll);
721             break;
722             
723         case OUTPUT_DEBUG_STRING_EVENT:
724             if (DEBUG_CurrThread == NULL) {
725                 DEBUG_Printf(DBG_CHN_ERR, "Unknown thread\n");
726                 break;
727             }
728             
729             DEBUG_ProcessGetString(buffer, sizeof(buffer), 
730                                    DEBUG_CurrThread->process->handle, 
731                                    de->u.DebugString.lpDebugStringData);
732             
733             /* fixme unicode de->u.DebugString.fUnicode ? */
734             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: output debug string (%s)\n", 
735                          de->dwProcessId, de->dwThreadId, buffer);
736             break;
737             
738         case RIP_EVENT:
739             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: rip error=%ld type=%ld\n", 
740                          de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError, 
741                          de->u.RipInfo.dwType);
742             break;
743             
744         default:
745             DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: unknown event (%ld)\n", 
746                          de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
747         }
748         
749     } __EXCEPT(wine_dbg) {
750         *cont = 0;
751         ret = TRUE;
752     }
753     __ENDTRY;
754     return ret;
755 }
756
757 static  DWORD   DEBUG_MainLoop(void)
758 {
759     DEBUG_EVENT         de;
760     DWORD               cont;
761     BOOL                ret;
762
763     DEBUG_Printf(DBG_CHN_MESG, " on pid %lx\n", DEBUG_CurrPid);
764     
765     for (ret = TRUE; ret; ) {
766         /* wait until we get at least one loaded process */
767         while (!DEBUG_ProcessList && (ret = DEBUG_Parser()));
768         if (!ret) break;
769
770         while (ret && DEBUG_ProcessList && WaitForDebugEvent(&de, INFINITE)) {
771             ret = DEBUG_HandleDebugEvent(&de, &cont);
772             ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
773         }
774     };
775     
776     DEBUG_Printf(DBG_CHN_MESG, "WineDbg terminated on pid %lx\n", DEBUG_CurrPid);
777
778     return 0;
779 }
780
781 static  BOOL    DEBUG_Start(LPSTR cmdLine)
782 {
783     PROCESS_INFORMATION info;
784     STARTUPINFOA        startup;
785
786     memset(&startup, 0, sizeof(startup));
787     startup.cb = sizeof(startup);
788     startup.dwFlags = STARTF_USESHOWWINDOW;
789     startup.wShowWindow = SW_SHOWNORMAL;
790     
791     if (!CreateProcess(NULL, cmdLine, NULL, NULL, 
792                        FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info)) {
793         DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
794         return FALSE;
795     }
796     DEBUG_CurrPid = info.dwProcessId;
797     if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0))) return FALSE;
798
799     return TRUE;
800 }
801
802 void    DEBUG_Run(const char* args)
803 {
804     DBG_MODULE* wmod = DEBUG_GetProcessMainModule(DEBUG_CurrProcess);
805     const char* pgm = (wmod) ? wmod->module_name : "none";
806
807     if (args) {
808         DEBUG_Printf(DBG_CHN_MESG, "Run (%s) with '%s'\n", pgm, args);
809     } else {
810         if (!DEBUG_LastCmdLine) {
811             DEBUG_Printf(DBG_CHN_MESG, "Cannot find previously used command line.\n");
812             return;
813         }
814         DEBUG_Start(DEBUG_LastCmdLine);
815     }
816 }
817
818 int DEBUG_main(int argc, char** argv)
819 {
820     DWORD       retv = 0;
821
822 #ifdef DBG_need_heap
823     /* Initialize the debugger heap. */
824     dbg_heap = HeapCreate(HEAP_NO_SERIALIZE, 0x1000, 0x8000000); /* 128MB */
825 #endif
826     
827     /* Initialize the type handling stuff. */
828     DEBUG_InitTypes();
829     DEBUG_InitCVDataTypes();    
830
831     /* Initialize internal vars (types must be initialized before) */
832     if (!DEBUG_IntVarsRW(TRUE)) return -1;
833
834     /* keep it as a guiexe for now, so that Wine won't touch the Unix stdin, 
835      * stdout and stderr streams
836      */
837     if (DBG_IVAR(UseXTerm)) {
838         COORD           pos;
839         
840         /* This is a hack: it forces creation of an xterm, not done by default */
841         pos.X = 0; pos.Y = 1;
842         SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
843     }
844
845     DEBUG_Printf(DBG_CHN_MESG, "Starting WineDbg... ");
846
847     if (argc == 3) {
848         HANDLE  hEvent;
849         DWORD   pid;
850
851         if ((pid = atoi(argv[1])) != 0 && (hEvent = atoi(argv[2])) != 0) {
852             BOOL        ret = DEBUG_Attach(pid, TRUE);
853
854             SetEvent(hEvent);
855             CloseHandle(hEvent);
856             if (!ret) {
857                 DEBUG_Printf(DBG_CHN_ERR, "Can't attach process %ld: %ld\n", 
858                              DEBUG_CurrPid, GetLastError());
859                 goto leave;
860             }
861             DEBUG_CurrPid = pid;
862         }
863     }
864         
865     if (DEBUG_CurrPid == 0 && argc > 1) {
866         int     i, len;
867         LPSTR   cmdLine;
868                 
869         if (!(cmdLine = DBG_alloc(len = 1))) goto oom_leave;
870         cmdLine[0] = '\0';
871
872         for (i = 1; i < argc; i++) {
873             len += strlen(argv[i]) + 1;
874             if (!(cmdLine = DBG_realloc(cmdLine, len))) goto oom_leave;
875             strcat(cmdLine, argv[i]);
876             cmdLine[len - 2] = ' ';
877             cmdLine[len - 1] = '\0';
878         }
879
880         if (!DEBUG_Start(cmdLine)) {
881             DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
882             goto leave;
883         }
884         DBG_free(DEBUG_LastCmdLine);
885         DEBUG_LastCmdLine = cmdLine;
886     }
887
888     retv = DEBUG_MainLoop();
889  leave:
890     /* saves modified variables */
891     DEBUG_IntVarsRW(FALSE);
892
893     return retv;
894
895  oom_leave:
896     DEBUG_Printf(DBG_CHN_MESG, "Out of memory\n");
897     goto leave;
898 }