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