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