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