migrate substitution keywords to SVN
[reactos.git] / reactos / lib / kernel32 / except / except.c
1 /* $Id$
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 = UnhandledExceptionFilter;
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 return InterlockedExchangePointer(&GlobalTopLevelExceptionFilter,
50 lpTopLevelExceptionFilter);
51 }
52
53
54 /*
55 * Private helper function to lookup the module name from a given address.
56 * The address can point to anywhere within the module.
57 */
58 static const char*
59 _module_name_from_addr(const void* addr, char* psz, size_t nChars)
60 {
61 MEMORY_BASIC_INFORMATION mbi;
62 if (VirtualQuery(addr, &mbi, sizeof(mbi)) != sizeof(mbi) ||
63 !GetModuleFileNameA((HMODULE)mbi.AllocationBase, psz, nChars))
64 {
65 psz[0] = '\0';
66 }
67 return psz;
68 }
69
70 static VOID
71 _dump_context(PCONTEXT pc)
72 {
73 /*
74 * Print out the CPU registers
75 */
76 DbgPrint("CS:EIP %x:%x\n", pc->SegCs&0xffff, pc->Eip );
77 DbgPrint("DS %x ES %x FS %x GS %x\n", pc->SegDs&0xffff, pc->SegEs&0xffff,
78 pc->SegFs&0xffff, pc->SegGs&0xfff);
79 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", pc->Eax, pc->Ebx, pc->Ecx);
80 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", pc->Edx,
81 pc->Ebp, pc->Esi, pc->Esp);
82 DbgPrint("EDI: %.8x EFLAGS: %.8x\n", pc->Edi, pc->EFlags);
83 }
84
85 /*
86 * @unimplemented
87 */
88 LONG STDCALL
89 UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
90 {
91 #if 0
92 DWORD RetValue;
93 #endif
94 HANDLE DebugPort = NULL;
95 NTSTATUS ErrCode;
96
97 #if 0
98 if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION &&
99 ExceptionInfo->ExceptionRecord->ExceptionInformation[0])
100 {
101 RetValue = _BasepCheckForReadOnlyResource(
102 ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
103 if (RetValue == EXCEPTION_CONTINUE_EXECUTION)
104 return EXCEPTION_CONTINUE_EXECUTION;
105 }
106 #endif
107
108 /* Is there a debugger running ? */
109 ErrCode = NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort,
110 &DebugPort, sizeof(HANDLE), NULL);
111 if (!NT_SUCCESS(ErrCode) && ErrCode != STATUS_NOT_IMPLEMENTED)
112 {
113 SetLastErrorByStatus(ErrCode);
114 return EXCEPTION_EXECUTE_HANDLER;
115 }
116
117 if (DebugPort)
118 {
119 /* Pass the exception to debugger. */
120 DPRINT("Passing exception to debugger\n");
121 return EXCEPTION_CONTINUE_SEARCH;
122 }
123
124 if ((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 _dump_context ( ExceptionInfo->ContextRecord );
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 */