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