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) ]
18 LPTOP_LEVEL_EXCEPTION_FILTER GlobalTopLevelExceptionFilter
= NULL
;
27 /* Query the current setting */
28 Status
= NtQueryInformationProcess(NtCurrentProcess(),
29 ProcessDefaultHardErrorMode
,
33 if (!NT_SUCCESS(Status
))
35 /* Fail if we couldn't query */
36 SetLastErrorByStatus(Status
);
40 /* Check if NOT failing critical errors was requested */
41 if (ErrMode
& SEM_FAILCRITICALERRORS
)
43 /* Mask it out, since the native API works differently */
44 ErrMode
&= ~SEM_FAILCRITICALERRORS
;
48 /* OR it if the caller didn't, due to different native semantics */
49 ErrMode
|= SEM_FAILCRITICALERRORS
;
61 SetErrorMode(IN UINT uMode
)
63 UINT PrevErrMode
, NewMode
;
66 /* Get the previous mode */
67 PrevErrMode
= GetErrorMode();
70 /* Check if failing critical errors was requested */
71 if (NewMode
& SEM_FAILCRITICALERRORS
)
73 /* Mask it out, since the native API works differently */
74 NewMode
&= ~SEM_FAILCRITICALERRORS
;
78 /* OR it if the caller didn't, due to different native semantics */
79 NewMode
|= SEM_FAILCRITICALERRORS
;
82 /* Set the new mode */
83 Status
= NtSetInformationProcess(NtCurrentProcess(),
84 ProcessDefaultHardErrorMode
,
87 if(!NT_SUCCESS(Status
)) SetLastErrorByStatus(Status
);
89 /* Return the previous mode */
96 LPTOP_LEVEL_EXCEPTION_FILTER
98 SetUnhandledExceptionFilter(
99 IN LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
)
101 return InterlockedExchangePointer(&GlobalTopLevelExceptionFilter
,
102 lpTopLevelExceptionFilter
);
106 * Private helper function to lookup the module name from a given address.
107 * The address can point to anywhere within the module.
110 _module_name_from_addr(const void* addr
, void **module_start_addr
,
111 char* psz
, size_t nChars
)
113 MEMORY_BASIC_INFORMATION mbi
;
114 if (VirtualQuery(addr
, &mbi
, sizeof(mbi
)) != sizeof(mbi
) ||
115 !GetModuleFileNameA((HMODULE
)mbi
.AllocationBase
, psz
, nChars
))
118 *module_start_addr
= 0;
122 *module_start_addr
= (void *)mbi
.AllocationBase
;
129 _dump_context(PCONTEXT pc
)
133 * Print out the CPU registers
135 DbgPrint("CS:EIP %x:%x\n", pc
->SegCs
&0xffff, pc
->Eip
);
136 DbgPrint("DS %x ES %x FS %x GS %x\n", pc
->SegDs
&0xffff, pc
->SegEs
&0xffff,
137 pc
->SegFs
&0xffff, pc
->SegGs
&0xfff);
138 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", pc
->Eax
, pc
->Ebx
, pc
->Ecx
);
139 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", pc
->Edx
,
140 pc
->Ebp
, pc
->Esi
, pc
->Esp
);
141 DbgPrint("EDI: %.8x EFLAGS: %.8x\n", pc
->Edi
, pc
->EFlags
);
142 #elif defined(_M_AMD64)
143 DbgPrint("CS:RIP %x:%I64x\n", pc
->SegCs
&0xffff, pc
->Rip
);
144 DbgPrint("DS %x ES %x FS %x GS %x\n", pc
->SegDs
&0xffff, pc
->SegEs
&0xffff,
145 pc
->SegFs
&0xffff, pc
->SegGs
&0xfff);
146 DbgPrint("RAX: %I64x RBX: %I64x RCX: %I64x RDI: %I64x\n", pc
->Rax
, pc
->Rbx
, pc
->Rcx
, pc
->Rdi
);
147 DbgPrint("RDX: %I64x RBP: %I64x RSI: %I64x RSP: %I64x\n", pc
->Rdx
, pc
->Rbp
, pc
->Rsi
, pc
->Rsp
);
148 DbgPrint("R8: %I64x R9: %I64x R10: %I64x R11: %I64x\n", pc
->R8
, pc
->R9
, pc
->R10
, pc
->R11
);
149 DbgPrint("R12: %I64x R13: %I64x R14: %I64x R15: %I64x\n", pc
->R12
, pc
->R13
, pc
->R14
, pc
->R15
);
150 DbgPrint("EFLAGS: %.8x\n", pc
->EFlags
);
152 #warning Unknown architecture
157 BasepCheckForReadOnlyResource(IN PVOID Ptr
)
160 ULONG Size
, OldProtect
;
161 MEMORY_BASIC_INFORMATION mbi
;
163 LONG Ret
= EXCEPTION_CONTINUE_SEARCH
;
165 /* Check if it was an attempt to write to a read-only image section! */
166 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
168 MemoryBasicInformation
,
172 if (NT_SUCCESS(Status
) &&
173 mbi
.Protect
== PAGE_READONLY
&& mbi
.Type
== MEM_IMAGE
)
175 /* Attempt to treat it as a resource section. We need to
176 use SEH here because we don't know if it's actually a
181 Data
= RtlImageDirectoryEntryToData(mbi
.AllocationBase
,
183 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
187 (ULONG_PTR
)Ptr
>= (ULONG_PTR
)Data
&&
188 (ULONG_PTR
)Ptr
< (ULONG_PTR
)Data
+ Size
)
190 /* The user tried to write into the resources. Make the page
193 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
198 if (NT_SUCCESS(Status
))
200 Ret
= EXCEPTION_CONTINUE_EXECUTION
;
204 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
214 PrintStackTrace(struct _EXCEPTION_POINTERS
*ExceptionInfo
)
217 CHAR szMod
[128] = "";
218 PEXCEPTION_RECORD ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
219 PCONTEXT ContextRecord
= ExceptionInfo
->ContextRecord
;
221 /* Print a stack trace. */
222 DbgPrint("Unhandled exception\n");
223 DbgPrint("ExceptionCode: %8x\n", ExceptionRecord
->ExceptionCode
);
225 if ((NTSTATUS
)ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
226 ExceptionRecord
->NumberParameters
== 2)
228 DbgPrint("Faulting Address: %8x\n", ExceptionRecord
->ExceptionInformation
[1]);
231 _dump_context (ContextRecord
);
232 _module_name_from_addr(ExceptionRecord
->ExceptionAddress
, &StartAddr
, szMod
, sizeof(szMod
));
233 DbgPrint("Address:\n %8x+%-8x %s\n",
235 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
- (ULONG_PTR
)StartAddr
,
238 DbgPrint("Frames:\n");
243 PULONG Frame
= (PULONG
)ContextRecord
->Ebp
;
245 for (i
= 0; Frame
[1] != 0 && Frame
[1] != 0xdeadbeef && i
< 128; i
++)
247 if (IsBadReadPtr((PVOID
)Frame
[1], 4))
249 DbgPrint(" %8x%9s %s\n", Frame
[1], "<invalid address>"," ");
253 _module_name_from_addr((const void*)Frame
[1], &StartAddr
,
254 szMod
, sizeof(szMod
));
255 DbgPrint(" %8x+%-8x %s\n",
257 (ULONG_PTR
)Frame
[1] - (ULONG_PTR
)StartAddr
,
261 if (IsBadReadPtr((PVOID
)Frame
[0], sizeof(*Frame
) * 2))
264 Frame
= (PULONG
)Frame
[0];
267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
269 DbgPrint("<error dumping stack trace: 0x%x>\n", _SEH2_GetExceptionCode());
279 UnhandledExceptionFilter(struct _EXCEPTION_POINTERS
*ExceptionInfo
)
282 HANDLE DebugPort
= NULL
;
284 ULONG_PTR ErrorParameters
[4];
286 PEXCEPTION_RECORD ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
288 if ((NTSTATUS
)ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
289 ExceptionRecord
->NumberParameters
>= 2)
291 switch(ExceptionRecord
->ExceptionInformation
[0])
293 case EXCEPTION_WRITE_FAULT
:
294 /* Change the protection on some write attempts, some InstallShield setups
296 RetValue
= BasepCheckForReadOnlyResource(
297 (PVOID
)ExceptionRecord
->ExceptionInformation
[1]);
298 if (RetValue
== EXCEPTION_CONTINUE_EXECUTION
)
299 return EXCEPTION_CONTINUE_EXECUTION
;
301 case EXCEPTION_EXECUTE_FAULT
:
307 /* Is there a debugger running ? */
308 ErrCode
= NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort
,
309 &DebugPort
, sizeof(HANDLE
), NULL
);
310 if (!NT_SUCCESS(ErrCode
) && ErrCode
!= STATUS_NOT_IMPLEMENTED
)
312 SetLastErrorByStatus(ErrCode
);
313 return EXCEPTION_EXECUTE_HANDLER
;
318 /* Pass the exception to debugger. */
319 DPRINT("Passing exception to debugger\n");
320 return EXCEPTION_CONTINUE_SEARCH
;
323 if (GlobalTopLevelExceptionFilter
)
325 LONG ret
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
326 if (ret
!= EXCEPTION_CONTINUE_SEARCH
)
330 if ((GetErrorMode() & SEM_NOGPFAULTERRORBOX
) == 0)
331 PrintStackTrace(ExceptionInfo
);
333 /* Save exception code and address */
334 ErrorParameters
[0] = (ULONG
)ExceptionRecord
->ExceptionCode
;
335 ErrorParameters
[1] = (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
;
337 if ((NTSTATUS
)ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
)
339 /* get the type of operation that caused the access violation */
340 ErrorParameters
[2] = ExceptionRecord
->ExceptionInformation
[0];
344 ErrorParameters
[2] = ExceptionRecord
->ExceptionInformation
[2];
347 /* Save faulting address */
348 ErrorParameters
[3] = ExceptionRecord
->ExceptionInformation
[1];
350 /* Raise the harderror */
351 ErrCode
= NtRaiseHardError(STATUS_UNHANDLED_EXCEPTION
| 0x10000000,
352 4, 0, ErrorParameters
, OptionOkCancel
, &ErrorResponse
);
354 if (NT_SUCCESS(ErrCode
) && (ErrorResponse
== ResponseCancel
))
356 /* FIXME: Check the result, if the "Cancel" button was
357 clicked run a debugger */
358 DPRINT1("Debugging is not implemented yet\n");
362 * Returning EXCEPTION_EXECUTE_HANDLER means that the code in
363 * the __except block will be executed. Normally this will end up in a
367 return EXCEPTION_EXECUTE_HANDLER
;
375 RaiseException(IN DWORD dwExceptionCode
,
376 IN DWORD dwExceptionFlags
,
377 IN DWORD nNumberOfArguments
,
378 IN CONST ULONG_PTR
*lpArguments OPTIONAL
)
380 EXCEPTION_RECORD ExceptionRecord
;
382 /* Setup the exception record */
383 ExceptionRecord
.ExceptionCode
= dwExceptionCode
;
384 ExceptionRecord
.ExceptionRecord
= NULL
;
385 ExceptionRecord
.ExceptionAddress
= (PVOID
)RaiseException
;
386 ExceptionRecord
.ExceptionFlags
= dwExceptionFlags
& EXCEPTION_NONCONTINUABLE
;
388 /* Check if we have arguments */
392 ExceptionRecord
.NumberParameters
= 0;
396 /* We do, normalize the count */
397 if (nNumberOfArguments
> EXCEPTION_MAXIMUM_PARAMETERS
)
399 nNumberOfArguments
= EXCEPTION_MAXIMUM_PARAMETERS
;
402 /* Set the count of parameters */
403 ExceptionRecord
.NumberParameters
= nNumberOfArguments
;
405 /* Loop each parameter */
406 for (nNumberOfArguments
= 0;
407 (nNumberOfArguments
< ExceptionRecord
.NumberParameters
);
408 nNumberOfArguments
++)
410 /* Copy the exception information */
411 ExceptionRecord
.ExceptionInformation
[nNumberOfArguments
] =
416 if (dwExceptionCode
== 0xeedface)
418 DPRINT1("Delphi Exception at address: %p\n", ExceptionRecord
.ExceptionInformation
[0]);
419 DPRINT1("Exception-Object: %p\n", ExceptionRecord
.ExceptionInformation
[1]);
420 DPRINT1("Exception text: %s\n", ExceptionRecord
.ExceptionInformation
[2]);
423 /* Trace the wine special error and show the modulename and functionname */
424 if (dwExceptionCode
== 0x80000100 /*EXCEPTION_WINE_STUB*/)
426 /* Numbers of parameter must be equal to two */
427 if (ExceptionRecord
.NumberParameters
== 2)
429 DPRINT1("Missing function in : %s\n", ExceptionRecord
.ExceptionInformation
[0]);
430 DPRINT1("with the functionname : %s\n", ExceptionRecord
.ExceptionInformation
[1]);
434 /* Raise the exception */
435 RtlRaiseException(&ExceptionRecord
);