add a little more debug output in case of unhandled exceptions
[reactos.git] / reactos / lib / kernel32 / except / except.c
1 /* $Id: except.c,v 1.17 2004/09/26 16:54:53 royce Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/misc/except.c
6 * PURPOSE: Exception functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * modified from WINE [ Onno Hovers, (onno@stack.urc.tue.nl) ]
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 #include <k32.h>
14
15 #define NDEBUG
16 #include "../include/debug.h"
17
18 UINT GlobalErrMode = 0;
19 LPTOP_LEVEL_EXCEPTION_FILTER GlobalTopLevelExceptionFilter = NULL;
20
21 UINT GetErrorMode(void)
22 {
23 return GlobalErrMode;
24 }
25
26
27 /*
28 * @implemented
29 */
30 UINT
31 STDCALL
32 SetErrorMode( UINT uMode )
33 {
34 UINT OldErrMode = GetErrorMode();
35 GlobalErrMode = uMode;
36 return OldErrMode;
37 }
38
39
40 /*
41 * @implemented
42 */
43 LPTOP_LEVEL_EXCEPTION_FILTER
44 STDCALL
45 SetUnhandledExceptionFilter(
46 LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
47 )
48 {
49 LPTOP_LEVEL_EXCEPTION_FILTER OldTopLevelExceptionFilter =
50 GlobalTopLevelExceptionFilter;
51 GlobalTopLevelExceptionFilter = lpTopLevelExceptionFilter;
52 return OldTopLevelExceptionFilter;
53 }
54
55
56 /*
57 * Private helper function to lookup the module name from a given address.
58 * The address can point to anywhere within the module.
59 */
60 static const char*
61 _module_name_from_addr(const void* addr, char* psz, size_t nChars)
62 {
63 MEMORY_BASIC_INFORMATION mbi;
64 if (VirtualQuery(addr, &mbi, sizeof(mbi)) != sizeof(mbi) ||
65 !GetModuleFileNameA((HMODULE)mbi.AllocationBase, psz, nChars))
66 {
67 psz[0] = '\0';
68 }
69 return psz;
70 }
71
72 static VOID
73 _dump_context(PCONTEXT pc)
74 {
75 /*
76 * Print out the CPU registers
77 */
78 DbgPrint("CS:EIP %x:%x\n", pc->SegCs&0xffff, pc->Eip );
79 DbgPrint("DS %x ES %x FS %x GS %x\n", pc->SegDs&0xffff, pc->SegEs&0xffff,
80 pc->SegFs&0xffff, pc->SegGs&0xfff);
81 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", pc->Eax, pc->Ebx, pc->Ecx);
82 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", pc->Edx,
83 pc->Ebp, pc->Esi, pc->Esp);
84 DbgPrint("EDI: %.8x EFLAGS: %.8x\n", pc->Edi, pc->EFlags);
85 }
86
87 /*
88 * @unimplemented
89 */
90 LONG STDCALL
91 UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
92 {
93 DWORD RetValue;
94 HANDLE DebugPort = NULL;
95 NTSTATUS ErrCode;
96 static int RescursionTrap = 3;
97
98 #if 0
99 if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION &&
100 ExceptionInfo->ExceptionRecord->ExceptionInformation[0])
101 {
102 RetValue = _BasepCheckForReadOnlyResource(
103 ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
104 if (RetValue == EXCEPTION_CONTINUE_EXECUTION)
105 return EXCEPTION_CONTINUE_EXECUTION;
106 }
107 #endif
108
109 if (--RescursionTrap > 0)
110 {
111 /* Is there a debugger running ? */
112 ErrCode = NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort,
113 &DebugPort, sizeof(HANDLE), NULL);
114 if (!NT_SUCCESS(ErrCode) && ErrCode != STATUS_NOT_IMPLEMENTED)
115 {
116 SetLastErrorByStatus(ErrCode);
117 return EXCEPTION_EXECUTE_HANDLER;
118 }
119
120 if (DebugPort)
121 {
122 /* Pass the exception to debugger. */
123 DPRINT("Passing exception to debugger\n");
124 return EXCEPTION_CONTINUE_SEARCH;
125 }
126
127 /* Run unhandled exception handler. */
128 if (GlobalTopLevelExceptionFilter != NULL)
129 {
130 RetValue = GlobalTopLevelExceptionFilter(ExceptionInfo);
131 if (RetValue == EXCEPTION_EXECUTE_HANDLER)
132 return EXCEPTION_EXECUTE_HANDLER;
133 if (RetValue == EXCEPTION_CONTINUE_EXECUTION)
134 return EXCEPTION_CONTINUE_EXECUTION;
135 }
136 }
137
138 if (RescursionTrap >= 0 && (GetErrorMode() & SEM_NOGPFAULTERRORBOX) == 0)
139 {
140 #ifdef _X86_
141 PULONG Frame;
142 CHAR szMod[128] = "";
143 #endif
144
145 /* Print a stack trace. */
146 DPRINT1("Unhandled exception\n");
147 DPRINT1("Address:\n");
148 DPRINT1(" %8x %s\n",
149 ExceptionInfo->ExceptionRecord->ExceptionAddress,
150 _module_name_from_addr(ExceptionInfo->ExceptionRecord->ExceptionAddress, szMod, sizeof(szMod)));
151 _dump_context ( ExceptionInfo->ContextRecord );
152 #ifdef _X86_
153 DPRINT1("Frames:\n");
154 Frame = (PULONG)ExceptionInfo->ContextRecord->Ebp;
155 while (Frame[1] != 0 && Frame[1] != 0xdeadbeef)
156 {
157 if (IsBadReadPtr((PVOID)Frame[1], 4)) {
158 DPRINT1(" %8x %s\n", Frame[1], "<invalid address>");
159 } else {
160 _module_name_from_addr((const void*)Frame[1], szMod, sizeof(szMod));
161 DPRINT1(" %8x %s\n", Frame[1], szMod);
162 }
163 if (IsBadReadPtr((PVOID)Frame[0], sizeof(*Frame) * 2)) {
164 break;
165 }
166 Frame = (PULONG)Frame[0];
167 }
168 #endif
169 }
170
171 /*
172 * Returning EXCEPTION_EXECUTE_HANDLER means that the code in
173 * the __except block will be executed. Normally this will end up in a
174 * Terminate process.
175 */
176
177 return EXCEPTION_EXECUTE_HANDLER;
178 }
179
180
181 /*
182 * @implemented
183 */
184 VOID
185 STDCALL
186 RaiseException (
187 DWORD dwExceptionCode,
188 DWORD dwExceptionFlags,
189 DWORD nNumberOfArguments,
190 CONST DWORD * lpArguments OPTIONAL
191 )
192 {
193 EXCEPTION_RECORD ExceptionRecord;
194
195 /* Do NOT normalize dwExceptionCode: it will be done in
196 * NTDLL.RtlRaiseException().
197 */
198 ExceptionRecord.ExceptionCode = dwExceptionCode;
199 ExceptionRecord.ExceptionRecord = NULL;
200 ExceptionRecord.ExceptionAddress = (PVOID) RaiseException;
201 /*
202 * Normalize dwExceptionFlags.
203 */
204 ExceptionRecord.ExceptionFlags = (dwExceptionFlags & EXCEPTION_NONCONTINUABLE);
205 /*
206 * Normalize nNumberOfArguments.
207 */
208 if (EXCEPTION_MAXIMUM_PARAMETERS < nNumberOfArguments)
209 {
210 nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
211 }
212 /*
213 * If the exception has no argument,
214 * ignore nNumberOfArguments and lpArguments.
215 */
216 if (NULL == lpArguments)
217 {
218 ExceptionRecord.NumberParameters = 0;
219 }
220 else
221 {
222 ExceptionRecord.NumberParameters = nNumberOfArguments;
223 for ( nNumberOfArguments = 0;
224 (nNumberOfArguments < ExceptionRecord.NumberParameters);
225 nNumberOfArguments ++
226 )
227 {
228 ExceptionRecord.ExceptionInformation [nNumberOfArguments]
229 = *lpArguments ++;
230 }
231 }
232 RtlRaiseException (& ExceptionRecord);
233 }
234
235 /* EOF */