- Print CS reg at crash MessageBox (needed for Win16 programs).
[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 "ldt.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  *         UnhandledExceptionFilter   (KERNEL32.537)
68  */
69 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
70 {
71     PDB*                pdb = PROCESS_Current();
72     char                format[256];
73     char                buffer[256];
74     HKEY                hDbgConf;
75     DWORD               bAuto = FALSE;
76     DWORD               ret = EXCEPTION_EXECUTE_HANDLER;
77     int status;
78
79     /* send a last chance event to the debugger */
80     SERVER_START_REQ
81     {
82         struct exception_event_request *req = server_alloc_req( sizeof(*req),
83                                                   sizeof(EXCEPTION_RECORD)+sizeof(CONTEXT) );
84         CONTEXT *context_ptr = server_data_ptr(req);
85         EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
86         req->first   = 0;
87         *rec_ptr     = *epointers->ExceptionRecord;
88         *context_ptr = *epointers->ContextRecord;
89         if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *epointers->ContextRecord = *context_ptr;
90         status = req->status;
91     }
92     SERVER_END_REQ;
93
94     switch (status)
95     {
96     case DBG_CONTINUE: 
97         return EXCEPTION_CONTINUE_EXECUTION;
98     case DBG_EXCEPTION_NOT_HANDLED: 
99         TerminateProcess( GetCurrentProcess(), epointers->ExceptionRecord->ExceptionCode );
100         break; /* not reached */
101     case 0: /* no debugger is present */
102         break;
103     default:    
104         FIXME("Unsupported yet debug continue value %d (please report)\n", status);
105     }
106
107     if (pdb->top_filter)
108     {
109         DWORD ret = pdb->top_filter( epointers );
110         if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
111     }
112
113     /* FIXME: Should check the current error mode */
114
115     if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, 
116                      "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", 
117                      &hDbgConf)) {
118        DWORD    type;
119        DWORD    count;
120        
121        count = sizeof(format);
122        if (RegQueryValueExA(hDbgConf, "Debugger", 0, &type, format, &count))
123           format[0] = 0;
124
125        count = sizeof(bAuto);
126        if (RegQueryValueExA(hDbgConf, "Auto", 0, &type, (char*)&bAuto, &count))
127           bAuto = TRUE;
128        
129        RegCloseKey(hDbgConf);
130     } else {
131        /* format[0] = 0; */
132        strcpy(format, "debugger/winedbg %ld %ld");
133     }
134
135     if (!bAuto && Callout.MessageBoxA) {
136        sprintf( buffer, "Unhandled exception 0x%08lx at address 0x%04lx:0x%08lx.\n"
137                         "Do you wish to debug it ?",
138                 epointers->ExceptionRecord->ExceptionCode,
139                 epointers->ContextRecord->SegCs,
140                 (DWORD)epointers->ExceptionRecord->ExceptionAddress );
141        if (Callout.MessageBoxA( 0, buffer, "Error", MB_YESNO | MB_ICONHAND ) == IDNO) {
142           TRACE("Killing process\n");
143           return EXCEPTION_EXECUTE_HANDLER;
144        }
145     }
146     
147     if (format[0]) {
148        HANDLE                   hEvent;
149        PROCESS_INFORMATION      info;
150        STARTUPINFOA             startup;
151        OBJECT_ATTRIBUTES        attr;
152
153        attr.Length                   = sizeof(attr);
154        attr.RootDirectory            = 0;
155        attr.Attributes               = OBJ_INHERIT;
156        attr.ObjectName               = NULL;
157        attr.SecurityDescriptor       = NULL;
158        attr.SecurityQualityOfService = NULL;
159
160        TRACE("Starting debugger (fmt=%s)\n", format);
161        NtCreateEvent( &hEvent, EVENT_ALL_ACCESS, &attr, FALSE, FALSE );
162        sprintf(buffer, format, GetCurrentProcessId(), hEvent);
163        memset(&startup, 0, sizeof(startup));
164        startup.cb = sizeof(startup);
165        startup.dwFlags = STARTF_USESHOWWINDOW;
166        startup.wShowWindow = SW_SHOWNORMAL;
167        if (CreateProcessA(NULL, buffer, NULL, NULL, 
168                           TRUE, 0, NULL, NULL, &startup, &info)) {
169           WaitForSingleObject(hEvent, INFINITE);
170           ret = EXCEPTION_CONTINUE_SEARCH;
171        } else {
172            ERR("Couldn't start debugger (%s) (%ld)\n"
173                "Read the documentation on how to set up winedbg or another debugger\n",
174                buffer, GetLastError());
175        }
176        CloseHandle(hEvent);
177     } else {
178        ERR("No standard debugger defined in the registry => no debugging session\n");
179     }
180     
181     return ret;
182 }
183
184
185 /***********************************************************************
186  *            SetUnhandledExceptionFilter   (KERNEL32.516)
187  */
188 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
189                                           LPTOP_LEVEL_EXCEPTION_FILTER filter )
190 {
191     PDB *pdb = PROCESS_Current();
192     LPTOP_LEVEL_EXCEPTION_FILTER old = pdb->top_filter;
193     pdb->top_filter = filter;
194     return old;
195 }
196
197
198 /**************************************************************************
199  *           FatalAppExit16   (KERNEL.137)
200  */
201 void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
202 {
203     WARN("AppExit\n");
204     FatalAppExitA( action, str );
205 }
206
207
208 /**************************************************************************
209  *           FatalAppExitA   (KERNEL32.108)
210  */
211 void WINAPI FatalAppExitA( UINT action, LPCSTR str )
212 {
213     WARN("AppExit\n");
214     Callout.MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
215     ExitProcess(0);
216 }
217
218
219 /**************************************************************************
220  *           FatalAppExitW   (KERNEL32.109)
221  */
222 void WINAPI FatalAppExitW( UINT action, LPCWSTR str )
223 {
224     WARN("AppExit\n");
225     Callout.MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
226     ExitProcess(0);
227 }