dcc7a85ec5481e9e0a752d6766edc166784ef9c6
[reactos.git] / reactos / lib / kernel32 / except / except.c
1 /* $Id: except.c,v 1.16 2004/08/22 18:49:11 tamlin 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
73 /*
74 * @unimplemented
75 */
76 LONG STDCALL
77 UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
78 {
79 DWORD RetValue;
80 HANDLE DebugPort = NULL;
81 NTSTATUS ErrCode;
82 static int RescursionTrap = 3;
83
84 #if 0
85 if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION &&
86 ExceptionInfo->ExceptionRecord->ExceptionInformation[0])
87 {
88 RetValue = _BasepCheckForReadOnlyResource(
89 ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
90 if (RetValue == EXCEPTION_CONTINUE_EXECUTION)
91 return EXCEPTION_CONTINUE_EXECUTION;
92 }
93 #endif
94
95 if (--RescursionTrap > 0)
96 {
97 /* Is there a debugger running ? */
98 ErrCode = NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort,
99 &DebugPort, sizeof(HANDLE), NULL);
100 if (!NT_SUCCESS(ErrCode) && ErrCode != STATUS_NOT_IMPLEMENTED)
101 {
102 SetLastErrorByStatus(ErrCode);
103 return EXCEPTION_EXECUTE_HANDLER;
104 }
105
106 if (DebugPort)
107 {
108 /* Pass the exception to debugger. */
109 DPRINT("Passing exception to debugger\n");
110 return EXCEPTION_CONTINUE_SEARCH;
111 }
112
113 /* Run unhandled exception handler. */
114 if (GlobalTopLevelExceptionFilter != NULL)
115 {
116 RetValue = GlobalTopLevelExceptionFilter(ExceptionInfo);
117 if (RetValue == EXCEPTION_EXECUTE_HANDLER)
118 return EXCEPTION_EXECUTE_HANDLER;
119 if (RetValue == EXCEPTION_CONTINUE_EXECUTION)
120 return EXCEPTION_CONTINUE_EXECUTION;
121 }
122 }
123
124 if (RescursionTrap >= 0 && (GetErrorMode() & SEM_NOGPFAULTERRORBOX) == 0)
125 {
126 #ifdef _X86_
127 PULONG Frame;
128 CHAR szMod[128] = "";
129 #endif
130
131 /* Print a stack trace. */
132 DPRINT1("Unhandled exception\n");
133 DPRINT1("Address:\n");
134 DPRINT1(" %8x %s\n",
135 ExceptionInfo->ExceptionRecord->ExceptionAddress,
136 _module_name_from_addr(ExceptionInfo->ExceptionRecord->ExceptionAddress, szMod, sizeof(szMod)));
137
138 #ifdef _X86_
139 DPRINT1("Frames:\n");
140 Frame = (PULONG)ExceptionInfo->ContextRecord->Ebp;
141 while (Frame[1] != 0 && Frame[1] != 0xdeadbeef)
142 {
143 if (IsBadReadPtr((PVOID)Frame[1], 4)) {
144 DPRINT1(" %8x %s\n", Frame[1], "<invalid address>");
145 } else {
146 _module_name_from_addr((const void*)Frame[1], szMod, sizeof(szMod));
147 DPRINT1(" %8x %s\n", Frame[1], szMod);
148 }
149 if (IsBadReadPtr((PVOID)Frame[0], sizeof(*Frame) * 2)) {
150 break;
151 }
152 Frame = (PULONG)Frame[0];
153 }
154 #endif
155 }
156
157 /*
158 * Returning EXCEPTION_EXECUTE_HANDLER means that the code in
159 * the __except block will be executed. Normally this will end up in a
160 * Terminate process.
161 */
162
163 return EXCEPTION_EXECUTE_HANDLER;
164 }
165
166
167 /*
168 * @implemented
169 */
170 VOID
171 STDCALL
172 RaiseException (
173 DWORD dwExceptionCode,
174 DWORD dwExceptionFlags,
175 DWORD nNumberOfArguments,
176 CONST DWORD * lpArguments OPTIONAL
177 )
178 {
179 EXCEPTION_RECORD ExceptionRecord;
180
181 /* Do NOT normalize dwExceptionCode: it will be done in
182 * NTDLL.RtlRaiseException().
183 */
184 ExceptionRecord.ExceptionCode = dwExceptionCode;
185 ExceptionRecord.ExceptionRecord = NULL;
186 ExceptionRecord.ExceptionAddress = (PVOID) RaiseException;
187 /*
188 * Normalize dwExceptionFlags.
189 */
190 ExceptionRecord.ExceptionFlags = (dwExceptionFlags & EXCEPTION_NONCONTINUABLE);
191 /*
192 * Normalize nNumberOfArguments.
193 */
194 if (EXCEPTION_MAXIMUM_PARAMETERS < nNumberOfArguments)
195 {
196 nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
197 }
198 /*
199 * If the exception has no argument,
200 * ignore nNumberOfArguments and lpArguments.
201 */
202 if (NULL == lpArguments)
203 {
204 ExceptionRecord.NumberParameters = 0;
205 }
206 else
207 {
208 ExceptionRecord.NumberParameters = nNumberOfArguments;
209 for ( nNumberOfArguments = 0;
210 (nNumberOfArguments < ExceptionRecord.NumberParameters);
211 nNumberOfArguments ++
212 )
213 {
214 ExceptionRecord.ExceptionInformation [nNumberOfArguments]
215 = *lpArguments ++;
216 }
217 }
218 RtlRaiseException (& ExceptionRecord);
219 }
220
221 /* EOF */