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