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