The debugger "Auto" registry value should be a string.
[wine] / win32 / except.c
1 /*
2  * Win32 exception functions
3  *
4  * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
5  * Copyright (c) 1999 Alexandre Julliard
6  *
7  * Notes:
8  *  What really happens behind the scenes of those new
9  *  __try{...}__except(..){....}  and
10  *  __try{...}__finally{...}
11  *  statements is simply not documented by Microsoft. There could be different
12  *  reasons for this: 
13  *  One reason could be that they try to hide the fact that exception 
14  *  handling in Win32 looks almost the same as in OS/2 2.x.  
15  *  Another reason could be that Microsoft does not want others to write
16  *  binary compatible implementations of the Win32 API (like us).  
17  *
18  *  Whatever the reason, THIS SUCKS!! Ensuring portabilty or future 
19  *  compatability may be valid reasons to keep some things undocumented. 
20  *  But exception handling is so basic to Win32 that it should be 
21  *  documented!
22  *
23  */
24
25 #include <stdio.h>
26 #include "windef.h"
27 #include "winerror.h"
28 #include "ntddk.h"
29 #include "wine/exception.h"
30 #include "selectors.h"
31 #include "callback.h"
32 #include "process.h"
33 #include "thread.h"
34 #include "stackframe.h"
35 #include "server.h"
36 #include "debugtools.h"
37
38 DEFAULT_DEBUG_CHANNEL(seh);
39
40
41 /*******************************************************************
42  *         RaiseException  (KERNEL32.418)
43  */
44 void WINAPI RaiseException( DWORD code, DWORD flags, DWORD nbargs, const LPDWORD args )
45 {
46     EXCEPTION_RECORD record;
47
48     /* Compose an exception record */ 
49     
50     record.ExceptionCode    = code;
51     record.ExceptionFlags   = flags & EH_NONCONTINUABLE;
52     record.ExceptionRecord  = NULL;
53     record.ExceptionAddress = RaiseException;
54     if (nbargs && args)
55     {
56         if (nbargs > EXCEPTION_MAXIMUM_PARAMETERS) nbargs = EXCEPTION_MAXIMUM_PARAMETERS;
57         record.NumberParameters = nbargs;
58         memcpy( record.ExceptionInformation, args, nbargs * sizeof(*args) );
59     }
60     else record.NumberParameters = 0;
61
62     RtlRaiseException( &record );
63 }
64
65
66 /*******************************************************************
67  *         format_exception_msg
68  */
69 static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer )
70 {
71     const EXCEPTION_RECORD *rec = ptr->ExceptionRecord;
72
73     switch(rec->ExceptionCode)
74     {
75     case EXCEPTION_INT_DIVIDE_BY_ZERO:
76         sprintf( buffer, "Unhandled division by zero" );
77         break;
78     case EXCEPTION_INT_OVERFLOW:
79         sprintf( buffer, "Unhandled overflow" );
80         break;
81     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
82         sprintf( buffer, "Unhandled array bounds" );
83         break;
84     case EXCEPTION_ILLEGAL_INSTRUCTION:
85         sprintf( buffer, "Unhandled illegal instruction" );
86         break;
87     case EXCEPTION_STACK_OVERFLOW:
88         sprintf( buffer, "Unhandled stack overflow" );
89         break;
90     case EXCEPTION_PRIV_INSTRUCTION:
91         sprintf( buffer, "Unhandled priviledged instruction" );
92         break;
93     case EXCEPTION_ACCESS_VIOLATION:
94         if (rec->NumberParameters == 2)
95             sprintf( buffer, "Unhandled page fault on %s access to 0x%08lx",
96                      rec->ExceptionInformation[0] ? "write" : "read",
97                      rec->ExceptionInformation[1]);
98         else
99             sprintf( buffer, "Unhandled page fault");
100         break;
101     case EXCEPTION_DATATYPE_MISALIGNMENT:
102         sprintf( buffer, "Unhandled alignment" );
103         break;
104     case CONTROL_C_EXIT:
105         sprintf( buffer, "Unhandled ^C");
106         break;
107     case EXCEPTION_CRITICAL_SECTION_WAIT:
108         sprintf( buffer, "Critical section %08lx wait failed",
109                  rec->ExceptionInformation[0]);
110         break;
111     case EXCEPTION_WINE_STUB:
112         sprintf( buffer, "Unimplemented function %s.%s called",
113                  (char *)rec->ExceptionInformation[0], (char *)rec->ExceptionInformation[1] );
114         break;
115     case EXCEPTION_VM86_INTx:
116         sprintf( buffer, "Unhandled interrupt %02lx in vm86 mode",
117                  rec->ExceptionInformation[0]);
118         break;
119     case EXCEPTION_VM86_STI:
120         sprintf( buffer, "Unhandled sti in vm86 mode");
121         break;
122     case EXCEPTION_VM86_PICRETURN:
123         sprintf( buffer, "Unhandled PIC return in vm86 mode");
124         break;
125     default:
126         sprintf( buffer, "Unhandled exception 0x%08lx", rec->ExceptionCode);
127         break;
128     }
129 #ifdef __i386__
130     if (ptr->ContextRecord->SegCs != __get_cs())
131         sprintf( buffer+strlen(buffer), " at address 0x%04lx:0x%08lx.\n",
132                  ptr->ContextRecord->SegCs, (DWORD)ptr->ExceptionRecord->ExceptionAddress );
133     else
134 #endif
135     sprintf( buffer+strlen(buffer), " at address 0x%08lx.\n",
136              (DWORD)ptr->ExceptionRecord->ExceptionAddress );
137     strcat( buffer, "Do you wish to debug it ?" );
138 }
139
140
141 /*******************************************************************
142  *         UnhandledExceptionFilter   (KERNEL32.537)
143  */
144 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
145 {
146     PDB*                pdb = PROCESS_Current();
147     char                format[256];
148     char                buffer[256];
149     HKEY                hDbgConf;
150     DWORD               bAuto = FALSE;
151     DWORD               ret = EXCEPTION_EXECUTE_HANDLER;
152     int status;
153
154     /* send a last chance event to the debugger */
155     SERVER_START_REQ
156     {
157         struct exception_event_request *req = server_alloc_req( sizeof(*req),
158                                                   sizeof(EXCEPTION_RECORD)+sizeof(CONTEXT) );
159         CONTEXT *context_ptr = server_data_ptr(req);
160         EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
161         req->first   = 0;
162         *rec_ptr     = *epointers->ExceptionRecord;
163         *context_ptr = *epointers->ContextRecord;
164         if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *epointers->ContextRecord = *context_ptr;
165         status = req->status;
166     }
167     SERVER_END_REQ;
168
169     switch (status)
170     {
171     case DBG_CONTINUE: 
172         return EXCEPTION_CONTINUE_EXECUTION;
173     case DBG_EXCEPTION_NOT_HANDLED: 
174         TerminateProcess( GetCurrentProcess(), epointers->ExceptionRecord->ExceptionCode );
175         break; /* not reached */
176     case 0: /* no debugger is present */
177         break;
178     default:    
179         FIXME("Unsupported yet debug continue value %d (please report)\n", status);
180     }
181
182     if (pdb->top_filter)
183     {
184         DWORD ret = pdb->top_filter( epointers );
185         if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
186     }
187
188     /* FIXME: Should check the current error mode */
189
190     if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, 
191                      "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", 
192                      &hDbgConf)) {
193        DWORD    type;
194        DWORD    count;
195
196        count = sizeof(format);
197        if (RegQueryValueExA(hDbgConf, "Debugger", 0, &type, format, &count))
198           format[0] = 0;
199
200        count = sizeof(bAuto);
201        if (RegQueryValueExA(hDbgConf, "Auto", 0, &type, (char*)&bAuto, &count))
202           bAuto = TRUE;
203        else if (type == REG_SZ)
204        {
205            char autostr[10];
206            count = sizeof(autostr);
207            if (!RegQueryValueExA(hDbgConf, "Auto", 0, &type, autostr, &count))
208                bAuto = atoi(autostr);
209        }
210        RegCloseKey(hDbgConf);
211     } else {
212        /* format[0] = 0; */
213        strcpy(format, "debugger/winedbg %ld %ld");
214     }
215
216     if (!bAuto && Callout.MessageBoxA) {
217         format_exception_msg( epointers, buffer );
218        if (Callout.MessageBoxA( 0, buffer, "Error", MB_YESNO | MB_ICONHAND ) == IDNO) {
219           TRACE("Killing process\n");
220           return EXCEPTION_EXECUTE_HANDLER;
221        }
222     }
223     
224     if (format[0]) {
225        HANDLE                   hEvent;
226        PROCESS_INFORMATION      info;
227        STARTUPINFOA             startup;
228        OBJECT_ATTRIBUTES        attr;
229
230        attr.Length                   = sizeof(attr);
231        attr.RootDirectory            = 0;
232        attr.Attributes               = OBJ_INHERIT;
233        attr.ObjectName               = NULL;
234        attr.SecurityDescriptor       = NULL;
235        attr.SecurityQualityOfService = NULL;
236
237        TRACE("Starting debugger (fmt=%s)\n", format);
238        NtCreateEvent( &hEvent, EVENT_ALL_ACCESS, &attr, FALSE, FALSE );
239        sprintf(buffer, format, GetCurrentProcessId(), hEvent);
240        memset(&startup, 0, sizeof(startup));
241        startup.cb = sizeof(startup);
242        startup.dwFlags = STARTF_USESHOWWINDOW;
243        startup.wShowWindow = SW_SHOWNORMAL;
244        if (CreateProcessA(NULL, buffer, NULL, NULL, 
245                           TRUE, 0, NULL, NULL, &startup, &info)) {
246           WaitForSingleObject(hEvent, INFINITE);
247           ret = EXCEPTION_CONTINUE_SEARCH;
248        } else {
249            ERR("Couldn't start debugger (%s) (%ld)\n"
250                "Read the documentation on how to set up winedbg or another debugger\n",
251                buffer, GetLastError());
252        }
253        CloseHandle(hEvent);
254     } else {
255        ERR("No standard debugger defined in the registry => no debugging session\n");
256     }
257     
258     return ret;
259 }
260
261
262 /***********************************************************************
263  *            SetUnhandledExceptionFilter   (KERNEL32.516)
264  */
265 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
266                                           LPTOP_LEVEL_EXCEPTION_FILTER filter )
267 {
268     PDB *pdb = PROCESS_Current();
269     LPTOP_LEVEL_EXCEPTION_FILTER old = pdb->top_filter;
270     pdb->top_filter = filter;
271     return old;
272 }
273
274
275 /**************************************************************************
276  *           FatalAppExit16   (KERNEL.137)
277  */
278 void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
279 {
280     WARN("AppExit\n");
281     FatalAppExitA( action, str );
282 }
283
284
285 /**************************************************************************
286  *           FatalAppExitA   (KERNEL32.108)
287  */
288 void WINAPI FatalAppExitA( UINT action, LPCSTR str )
289 {
290     WARN("AppExit\n");
291     if (Callout.MessageBoxA)
292         Callout.MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
293     else
294         ERR( "%s\n", debugstr_a(str) );
295     ExitProcess(0);
296 }
297
298
299 /**************************************************************************
300  *           FatalAppExitW   (KERNEL32.109)
301  */
302 void WINAPI FatalAppExitW( UINT action, LPCWSTR str )
303 {
304     WARN("AppExit\n");
305     if (Callout.MessageBoxW)
306         Callout.MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
307     else
308         ERR( "%s\n", debugstr_w(str) );
309     ExitProcess(0);
310 }