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