improved exception handling
[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 <sys/stat.h>
11 #include "debugger.h"
12
13 #include "thread.h"
14 #include "process.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17
18 #include "winreg.h"
19 #include "debugtools.h"
20 #include "options.h"
21
22 #ifdef DBG_need_heap
23 HANDLE dbg_heap = 0;
24 #endif
25
26 DEFAULT_DEBUG_CHANNEL(winedbg);
27     
28 DBG_PROCESS*    DEBUG_CurrProcess = NULL;
29 DBG_THREAD*     DEBUG_CurrThread = NULL;
30 CONTEXT         DEBUG_context;
31
32 static DBG_PROCESS* proc = NULL;
33 static BOOL bBreakAllThreads = FALSE;
34
35 static  BOOL DEBUG_Init(void)
36 {
37     HKEY        hkey;
38     DWORD       type;
39     DWORD       val;
40     DWORD       count = sizeof(val);
41
42     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) {
43         if (!RegQueryValueExA(hkey, "BreakAllThreadsStartup", 0, &type, (LPSTR)&val, &count)) {
44             bBreakAllThreads = val;
45         }
46         RegCloseKey(hkey);
47     }
48     return TRUE;
49 }
50                        
51 static WINE_EXCEPTION_FILTER(wine_dbg)
52 {
53     DEBUG_ExternalDebugger();
54     fprintf(stderr, "\nwine_dbg: Exception %lx\n", GetExceptionCode());
55     return EXCEPTION_EXECUTE_HANDLER;
56 }
57
58 static  DBG_PROCESS*    DEBUG_GetProcess(DWORD pid)
59 {
60     DBG_PROCESS*        p;
61     
62     for (p = proc; p; p = p->next)
63         if (p->pid == pid) break;
64     return p;
65 }
66
67 static  DBG_PROCESS*    DEBUG_AddProcess(DWORD pid, HANDLE h)
68 {
69     DBG_PROCESS*        p = DBG_alloc(sizeof(DBG_PROCESS));
70     if (!p)
71         return NULL;
72     p->handle = h;
73     p->pid = pid;
74     p->threads = NULL;
75     p->num_threads = 0;
76     p->modules = NULL;
77     p->next_index = 0;
78
79     p->next = proc;
80     p->prev = NULL;
81     if (proc) proc->prev = p;
82     proc = p;
83     return p;
84 }
85
86 static  void                    DEBUG_DelThread(DBG_THREAD* p);
87
88 static  void                    DEBUG_DelProcess(DBG_PROCESS* p)
89 {
90     if (p->threads != NULL) {
91         ERR("Shouldn't happen\n");
92         while (p->threads) DEBUG_DelThread(p->threads);
93     }
94     if (p->prev) p->prev->next = p->next;
95     if (p->next) p->next->prev = p->prev;
96     if (p == proc) proc = p->next;
97     DBG_free(p);
98 }
99
100 static  void                    DEBUG_InitCurrProcess(void)
101 {
102 #ifdef DBG_need_heap
103     /*
104      * Initialize the debugger heap.
105      */
106     dbg_heap = HeapCreate(HEAP_NO_SERIALIZE, 0x1000, 0x8000000); /* 128MB */
107 #endif
108     
109     /*
110      * Initialize the type handling stuff.
111      */
112     DEBUG_InitTypes();
113     DEBUG_InitCVDataTypes();
114     
115     /*
116      * In some cases we can read the stabs information directly
117      * from the executable.  If this is the case, we don't need
118      * to bother with trying to read a symbol file, as the stabs
119      * also have line number and local variable information.
120      * As long as gcc is used for the compiler, stabs will
121      * be the default.  On SVr4, DWARF could be used, but we
122      * don't grok that yet, and in this case we fall back to using
123      * the wine.sym file.
124      */
125     if( DEBUG_ReadExecutableDbgInfo() == FALSE )
126     {
127         char*           symfilename = "wine.sym";
128         struct stat     statbuf;
129         HKEY            hWineConf, hkey;
130         DWORD           count;
131         char            symbolTableFile[256];
132         
133         if (-1 == stat(symfilename, &statbuf) )
134             symfilename = LIBDIR "wine.sym";
135         
136         strcpy(symbolTableFile, symfilename);
137         if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", &hWineConf)) {
138             if (!RegOpenKeyA(hWineConf, "wine", &hkey)) {
139                 count = sizeof(symbolTableFile);
140                 RegQueryValueA(hkey, "SymbolTableFile", symbolTableFile, &count);
141                 RegCloseKey(hkey);
142             }
143             RegCloseKey(hWineConf);
144         }
145         DEBUG_ReadSymbolTable(symbolTableFile);
146     }
147     DEBUG_LoadEntryPoints(NULL);
148     DEBUG_ProcessDeferredDebug();
149 }
150
151 static BOOL DEBUG_ProcessGetString(char* buffer, int size, HANDLE hp, LPSTR addr)
152 {
153     DWORD sz;
154     *(WCHAR*)buffer = 0;
155     return (addr && ReadProcessMemory(hp, addr, buffer, size, &sz));
156 }
157
158 static BOOL DEBUG_ProcessGetStringIndirect(char* buffer, int size, HANDLE hp, LPVOID addr)
159 {
160     LPVOID      ad;
161     DWORD       sz;
162     
163     if (   addr 
164         && ReadProcessMemory(hp, addr, &ad, sizeof(ad), &sz) 
165         && sz == sizeof(ad) 
166         && ad 
167         && ReadProcessMemory(hp, ad, buffer, size, &sz))
168         return TRUE;
169     *(WCHAR*)buffer = 0;
170     return FALSE;
171 }
172
173 static  DBG_THREAD*     DEBUG_GetThread(DBG_PROCESS* p, DWORD tid)
174 {
175     DBG_THREAD* t;
176     
177     for (t = p->threads; t; t = t->next)
178         if (t->tid == tid) break;
179     return t;
180 }
181
182 static  DBG_THREAD*     DEBUG_AddThread(DBG_PROCESS* p, DWORD tid, 
183                                         HANDLE h, LPVOID start, LPVOID teb)
184 {
185     DBG_THREAD* t = DBG_alloc(sizeof(DBG_THREAD));
186     if (!t)
187         return NULL;
188     
189     t->handle = h;
190     t->tid = tid;
191     t->start = start;
192     t->teb = teb;
193     t->process = p;
194     t->wait_for_first_exception = 0;
195     t->dbg_exec_mode = EXEC_CONT;
196     t->dbg_exec_count = 0;
197
198     p->num_threads++;
199     t->next = p->threads;
200     t->prev = NULL;
201     if (p->threads) p->threads->prev = t;
202     p->threads = t;
203
204     return t;
205 }
206
207 static  void                    DEBUG_InitCurrThread(void)
208 {
209     if (!Options.debug) return;
210
211     if (DEBUG_CurrThread->start) {
212         if (DEBUG_CurrThread->process->num_threads == 1 || bBreakAllThreads) {
213             DBG_VALUE   value;
214             
215             DEBUG_SetBreakpoints(FALSE);
216             value.type = NULL;
217             value.cookie = DV_TARGET;
218             value.addr.seg = 0;
219             value.addr.off = (DWORD)DEBUG_CurrThread->start;
220             DEBUG_AddBreakpoint(&value);
221             DEBUG_SetBreakpoints(TRUE);
222         }
223     } else {
224         DEBUG_CurrThread->wait_for_first_exception = 1;
225     }
226 }
227
228 static  void                    DEBUG_DelThread(DBG_THREAD* t)
229 {
230     if (t->prev) t->prev->next = t->next;
231     if (t->next) t->next->prev = t->prev;
232     if (t == t->process->threads) t->process->threads = t->next;
233     t->process->num_threads--;
234     DBG_free(t);
235 }
236
237 static  BOOL    DEBUG_HandleException( EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force )
238 {
239     BOOL        is_debug = FALSE;
240     BOOL        ret;
241
242     if (first_chance && !Options.debug && !force ) return 0;  /* pass to app first */
243
244     switch (rec->ExceptionCode)
245     {
246     case EXCEPTION_BREAKPOINT:
247     case EXCEPTION_SINGLE_STEP:
248         is_debug = TRUE;
249         break;
250     case CONTROL_C_EXIT:
251         if (!Options.debug) DEBUG_Exit(0);
252         break;
253     }
254
255     if (!is_debug)
256     {
257         /* print some infos */
258         fprintf( stderr, "%s: ",
259                  first_chance ? "First chance exception" : "Unhandled exception" );
260         switch(rec->ExceptionCode)
261         {
262         case EXCEPTION_INT_DIVIDE_BY_ZERO:
263             fprintf( stderr, "divide by zero" );
264             break;
265         case EXCEPTION_INT_OVERFLOW:
266             fprintf( stderr, "overflow" );
267             break;
268         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
269             fprintf( stderr, "array bounds " );
270             break;
271         case EXCEPTION_ILLEGAL_INSTRUCTION:
272             fprintf( stderr, "illegal instruction" );
273             break;
274         case EXCEPTION_STACK_OVERFLOW:
275             fprintf( stderr, "stack overflow" );
276             break;
277         case EXCEPTION_PRIV_INSTRUCTION:
278             fprintf( stderr, "priviledged instruction" );
279             break;
280         case EXCEPTION_ACCESS_VIOLATION:
281             if (rec->NumberParameters == 2)
282                 fprintf( stderr, "page fault on %s access to 0x%08lx", 
283                          rec->ExceptionInformation[0] ? "write" : "read",
284                          rec->ExceptionInformation[1] );
285             else
286                 fprintf( stderr, "page fault" );
287             break;
288         case EXCEPTION_DATATYPE_MISALIGNMENT:
289             fprintf( stderr, "Alignment" );
290             break;
291         case CONTROL_C_EXIT:
292             fprintf( stderr, "^C" );
293             break;
294         case EXCEPTION_CRITICAL_SECTION_WAIT:
295             fprintf( stderr, "critical section %08lx wait failed", 
296                      rec->ExceptionInformation[0] );
297             break;
298         default:
299             fprintf( stderr, "%08lx", rec->ExceptionCode );
300             break;
301         }
302     }
303
304 #if 1
305     fprintf(stderr, "Entering debugger  PC=%lx EFL=%08lx mode=%d count=%d\n",
306             DEBUG_context.Eip, DEBUG_context.EFlags, 
307             DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
308 #endif
309
310     ret = DEBUG_Main( is_debug, force, rec->ExceptionCode );
311 #if 1
312     fprintf(stderr, "Exiting debugger   PC=%lx EFL=%08lx mode=%d count=%d\n",
313             DEBUG_context.Eip, DEBUG_context.EFlags, 
314             DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
315 #endif
316
317     return ret;
318 }
319
320 static  DWORD   DEBUG_HandleDebugEvent(DEBUG_EVENT* de)
321 {
322     char                buffer[256];
323     DWORD               cont;
324     
325     __TRY {
326         cont = 0L;
327         
328         if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL)
329             DEBUG_CurrThread = DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId);
330         else 
331             DEBUG_CurrThread = NULL;
332         
333         switch (de->dwDebugEventCode) {
334         case EXCEPTION_DEBUG_EVENT:
335             if (!DEBUG_CurrThread) break;
336             
337             TRACE("%08lx:%08lx: exception code=%08lx %d\n", 
338                   de->dwProcessId, de->dwThreadId, 
339                   de->u.Exception.ExceptionRecord.ExceptionCode,
340                   DEBUG_CurrThread->wait_for_first_exception);
341             
342             DEBUG_context.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS|CONTEXT_DEBUG_REGISTERS;
343             if (!GetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context)) {
344                 WARN("Can't get thread's context\n");
345                 break;
346             }
347             
348             TRACE("%p:%p\n", de->u.Exception.ExceptionRecord.ExceptionAddress, 
349                   (void*)DEBUG_context.Eip);
350             
351             cont = DEBUG_HandleException(&de->u.Exception.ExceptionRecord, 
352                                          de->u.Exception.dwFirstChance, 
353                                          DEBUG_CurrThread->wait_for_first_exception);
354             
355             if (DEBUG_CurrThread->wait_for_first_exception) {
356                 DEBUG_CurrThread->wait_for_first_exception = 0;
357 #ifdef __i386__
358                 DEBUG_context.Eip--;
359 #endif
360             }
361             SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
362             break;
363             
364         case CREATE_THREAD_DEBUG_EVENT:
365             TRACE("%08lx:%08lx: create thread D @%p\n", de->dwProcessId, de->dwThreadId, 
366                   de->u.CreateThread.lpStartAddress);
367             
368             if (DEBUG_CurrProcess == NULL) {
369                 ERR("Unknown process\n");
370                 break;
371             }
372             if (DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId) != NULL) {
373                 TRACE("Thread already listed, skipping\n");
374                 break;
375             }
376             
377             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess, 
378                                                de->dwThreadId, 
379                                                de->u.CreateThread.hThread, 
380                                                de->u.CreateThread.lpStartAddress, 
381                                                de->u.CreateThread.lpThreadLocalBase);
382             if (!DEBUG_CurrThread) {
383                 ERR("Couldn't create thread\n");
384                 break;
385             }
386             DEBUG_InitCurrThread();
387             break;
388             
389         case CREATE_PROCESS_DEBUG_EVENT:
390             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
391                                            de->u.CreateProcessInfo.hProcess, 
392                                            de->u.LoadDll.lpImageName);
393             
394             /* FIXME unicode ? de->u.CreateProcessInfo.fUnicode */
395             TRACE("%08lx:%08lx: create process %s @%p\n", 
396                   de->dwProcessId, de->dwThreadId, 
397                   buffer,
398                   de->u.CreateProcessInfo.lpStartAddress);
399             
400             if (DEBUG_GetProcess(de->dwProcessId) != NULL) {
401                 TRACE("Skipping already defined process\n");
402                 break;
403             }
404             DEBUG_CurrProcess = DEBUG_AddProcess(de->dwProcessId,
405                                                  de->u.CreateProcessInfo.hProcess);
406             if (DEBUG_CurrProcess == NULL) {
407                 ERR("Unknown process\n");
408                 break;
409             }
410             
411             TRACE("%08lx:%08lx: create thread I @%p\n", de->dwProcessId, de->dwThreadId, 
412                   de->u.CreateProcessInfo.lpStartAddress);
413             
414             DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,       
415                                                de->dwThreadId, 
416                                                de->u.CreateProcessInfo.hThread, 
417                                                de->u.CreateProcessInfo.lpStartAddress, 
418                                                de->u.CreateProcessInfo.lpThreadLocalBase);
419             if (!DEBUG_CurrThread) {
420                 ERR("Couldn't create thread\n");
421                 break;
422             }
423             
424             DEBUG_InitCurrProcess();
425             DEBUG_InitCurrThread();
426 #ifdef _WE_SUPPORT_THE_STAB_TYPES_USED_BY_MINGW_TOO
427             /* so far, process name is not set */
428             DEBUG_RegisterDebugInfo((DWORD)de->u.CreateProcessInfo.lpBaseOfImage, 
429                                     "wine-exec");
430 #endif
431             break;
432             
433         case EXIT_THREAD_DEBUG_EVENT:
434             TRACE("%08lx:%08lx: exit thread (%ld)\n", 
435                   de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
436             
437             if (DEBUG_CurrThread == NULL) {
438                 ERR("Unknown thread\n");
439                 break;
440             }
441             /* FIXME: remove break point set on thread startup */
442             DEBUG_DelThread(DEBUG_CurrThread);
443             break;
444             
445         case EXIT_PROCESS_DEBUG_EVENT:
446             TRACE("%08lx:%08lx: exit process (%ld)\n", 
447                   de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
448             
449             if (DEBUG_CurrProcess == NULL) {
450                 ERR("Unknown process\n");
451                 break;
452             }
453             /* kill last thread */
454             DEBUG_DelThread(DEBUG_CurrProcess->threads);
455             /* FIXME: remove break point set on thread startup */
456             DEBUG_DelProcess(DEBUG_CurrProcess);
457             break;
458             
459         case LOAD_DLL_DEBUG_EVENT:
460             if (DEBUG_CurrThread == NULL) {
461                 ERR("Unknown thread\n");
462                 break;
463             }
464             DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
465                                            DEBUG_CurrThread->process->handle, 
466                                            de->u.LoadDll.lpImageName);
467             
468             /* FIXME unicode: de->u.LoadDll.fUnicode */
469             TRACE("%08lx:%08lx: loads DLL %s @%p\n", de->dwProcessId, de->dwThreadId, 
470                   buffer, de->u.LoadDll.lpBaseOfDll);
471             CharUpperA(buffer);
472             DEBUG_LoadModule32( buffer, (DWORD)de->u.LoadDll.lpBaseOfDll);
473             break;
474             
475         case UNLOAD_DLL_DEBUG_EVENT:
476             TRACE("%08lx:%08lx: unload DLL @%p\n", de->dwProcessId, de->dwThreadId, 
477                   de->u.UnloadDll.lpBaseOfDll);
478             break;
479             
480         case OUTPUT_DEBUG_STRING_EVENT:
481             if (DEBUG_CurrThread == NULL) {
482                 ERR("Unknown thread\n");
483                 break;
484             }
485             
486             DEBUG_ProcessGetString(buffer, sizeof(buffer), 
487                                    DEBUG_CurrThread->process->handle, 
488                                    de->u.DebugString.lpDebugStringData);
489             
490             /* fixme unicode de->u.DebugString.fUnicode ? */
491             TRACE("%08lx:%08lx: output debug string (%s)\n", 
492                   de->dwProcessId, de->dwThreadId, 
493                   buffer);
494             break;
495             
496         case RIP_EVENT:
497             TRACE("%08lx:%08lx: rip error=%ld type=%ld\n", 
498                   de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError, 
499                   de->u.RipInfo.dwType);
500             break;
501             
502         default:
503             TRACE("%08lx:%08lx: unknown event (%ld)\n", 
504                   de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
505         }
506         
507     } __EXCEPT(wine_dbg) {
508         cont = 0;
509     }
510     __ENDTRY;
511
512     return cont;
513 }
514
515 static  DWORD   CALLBACK        DEBUG_MainLoop(DWORD pid)
516 {
517     DEBUG_EVENT         de;
518     DWORD               cont;
519
520     DEBUG_Init();
521
522     while (WaitForDebugEvent(&de, INFINITE)) {
523         cont = DEBUG_HandleDebugEvent(&de);
524         ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
525     }
526     
527     TRACE("WineDbg terminated on pid %ld\n", pid);
528     
529     return 0L;
530 }
531
532 static  DWORD   CALLBACK        DEBUG_StarterFromPID(LPVOID pid)
533 {
534     TRACE("WineDbg started on pid %ld\n", (DWORD)pid);
535     
536     if (!DebugActiveProcess((DWORD)pid)) {
537         TRACE("Can't debug process %ld: %ld\n", (DWORD)pid, GetLastError());
538         return 0;
539     }
540     return DEBUG_MainLoop((DWORD)pid);
541 }
542
543 void    DEBUG_Attach(DWORD pid)
544 {
545     CreateThread(NULL, 0, DEBUG_StarterFromPID, (LPVOID)pid, 0, NULL);
546 }
547
548 struct dsfcl {
549     HANDLE      hEvent;
550     LPSTR       lpCmdLine;
551     int         showWindow;
552     DWORD       error;
553 };
554
555 static  DWORD   CALLBACK        DEBUG_StarterFromCmdLine(LPVOID p)
556 {
557     PROCESS_INFORMATION info;
558     STARTUPINFOA        startup;
559     BOOL                ok = TRUE;
560
561     memset(&startup, 0, sizeof(startup));
562     startup.cb = sizeof(startup);
563     startup.dwFlags = STARTF_USESHOWWINDOW;
564     startup.wShowWindow = ((struct dsfcl*)p)->showWindow;
565
566     /* any value >= 32 will do, simulate a correct handle value */
567     ((struct dsfcl*)p)->error = 0xFFFFFFFF;
568     if (!CreateProcessA(NULL, ((struct dsfcl*)p)->lpCmdLine, NULL, NULL, 
569                         FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info)) {
570         ((struct dsfcl*)p)->error = GetLastError();
571         ok = FALSE;
572     }
573     SetEvent(((struct dsfcl*)p)->hEvent);
574     if (ok) DEBUG_MainLoop(info.dwProcessId);
575
576     return 0;
577 }
578
579 DWORD   DEBUG_WinExec(LPSTR lpCmdLine, int sw)
580 {
581     struct dsfcl        s;
582     BOOL                ret;
583
584     if ((s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL))) {
585         s.lpCmdLine = lpCmdLine;
586         s.showWindow = sw;
587         if (CreateThread(NULL, 0, DEBUG_StarterFromCmdLine, (LPVOID)&s, 0, NULL)) {
588             WaitForSingleObject(s.hEvent, INFINITE);
589             ret = s.error;
590         } else {
591             ret = 3; /* (dummy) error value for non created thread */
592         }
593         CloseHandle(s.hEvent);
594     } else {
595         ret = 1; /* (dummy) error value for non created event */
596     }
597     return ret;
598 }