2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/misc/except.c
5 * PURPOSE: Exception functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * modified from WINE [ Onno Hovers, (onno@stack.urc.tue.nl) ]
12 /* INCLUDES *******************************************************************/
20 * Private helper function to lookup the module name from a given address.
21 * The address can point to anywhere within the module.
24 _module_name_from_addr(const void* addr
, void **module_start_addr
,
25 char* psz
, size_t nChars
)
27 MEMORY_BASIC_INFORMATION mbi
;
28 if (VirtualQuery(addr
, &mbi
, sizeof(mbi
)) != sizeof(mbi
) ||
29 !GetModuleFileNameA((HMODULE
)mbi
.AllocationBase
, psz
, nChars
))
32 *module_start_addr
= 0;
36 *module_start_addr
= (void *)mbi
.AllocationBase
;
43 _dump_context(PCONTEXT pc
)
47 * Print out the CPU registers
49 DbgPrint("CS:EIP %x:%x\n", pc
->SegCs
&0xffff, pc
->Eip
);
50 DbgPrint("DS %x ES %x FS %x GS %x\n", pc
->SegDs
&0xffff, pc
->SegEs
&0xffff,
51 pc
->SegFs
&0xffff, pc
->SegGs
&0xfff);
52 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", pc
->Eax
, pc
->Ebx
, pc
->Ecx
);
53 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", pc
->Edx
,
54 pc
->Ebp
, pc
->Esi
, pc
->Esp
);
55 DbgPrint("EDI: %.8x EFLAGS: %.8x\n", pc
->Edi
, pc
->EFlags
);
56 #elif defined(_M_AMD64)
57 DbgPrint("CS:RIP %x:%I64x\n", pc
->SegCs
&0xffff, pc
->Rip
);
58 DbgPrint("DS %x ES %x FS %x GS %x\n", pc
->SegDs
&0xffff, pc
->SegEs
&0xffff,
59 pc
->SegFs
&0xffff, pc
->SegGs
&0xfff);
60 DbgPrint("RAX: %I64x RBX: %I64x RCX: %I64x RDI: %I64x\n", pc
->Rax
, pc
->Rbx
, pc
->Rcx
, pc
->Rdi
);
61 DbgPrint("RDX: %I64x RBP: %I64x RSI: %I64x RSP: %I64x\n", pc
->Rdx
, pc
->Rbp
, pc
->Rsi
, pc
->Rsp
);
62 DbgPrint("R8: %I64x R9: %I64x R10: %I64x R11: %I64x\n", pc
->R8
, pc
->R9
, pc
->R10
, pc
->R11
);
63 DbgPrint("R12: %I64x R13: %I64x R14: %I64x R15: %I64x\n", pc
->R12
, pc
->R13
, pc
->R14
, pc
->R15
);
64 DbgPrint("EFLAGS: %.8x\n", pc
->EFlags
);
66 #warning Unknown architecture
71 PrintStackTrace(struct _EXCEPTION_POINTERS
*ExceptionInfo
)
75 PEXCEPTION_RECORD ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
76 PCONTEXT ContextRecord
= ExceptionInfo
->ContextRecord
;
78 /* Print a stack trace. */
79 DbgPrint("Unhandled exception\n");
80 DbgPrint("ExceptionCode: %8x\n", ExceptionRecord
->ExceptionCode
);
82 if ((NTSTATUS
)ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
83 ExceptionRecord
->NumberParameters
== 2)
85 DbgPrint("Faulting Address: %8x\n", ExceptionRecord
->ExceptionInformation
[1]);
88 _dump_context (ContextRecord
);
89 _module_name_from_addr(ExceptionRecord
->ExceptionAddress
, &StartAddr
, szMod
, sizeof(szMod
));
90 DbgPrint("Address:\n %8x+%-8x %s\n",
92 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
- (ULONG_PTR
)StartAddr
,
95 DbgPrint("Frames:\n");
100 PULONG Frame
= (PULONG
)ContextRecord
->Ebp
;
102 for (i
= 0; Frame
[1] != 0 && Frame
[1] != 0xdeadbeef && i
< 128; i
++)
104 if (IsBadReadPtr((PVOID
)Frame
[1], 4))
106 DbgPrint(" %8x%9s %s\n", Frame
[1], "<invalid address>"," ");
110 _module_name_from_addr((const void*)Frame
[1], &StartAddr
,
111 szMod
, sizeof(szMod
));
112 DbgPrint(" %8x+%-8x %s\n",
114 (ULONG_PTR
)Frame
[1] - (ULONG_PTR
)StartAddr
,
118 if (IsBadReadPtr((PVOID
)Frame
[0], sizeof(*Frame
) * 2))
121 Frame
= (PULONG
)Frame
[0];
124 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
126 DbgPrint("<error dumping stack trace: 0x%x>\n", _SEH2_GetExceptionCode());
132 /* GLOBALS ********************************************************************/
134 LPTOP_LEVEL_EXCEPTION_FILTER GlobalTopLevelExceptionFilter
;
135 DWORD g_dwLastErrorToBreakOn
;
137 /* FUNCTIONS ******************************************************************/
141 BasepCheckForReadOnlyResource(IN PVOID Ptr
)
144 ULONG Size
, OldProtect
;
145 MEMORY_BASIC_INFORMATION mbi
;
147 LONG Ret
= EXCEPTION_CONTINUE_SEARCH
;
149 /* Check if it was an attempt to write to a read-only image section! */
150 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
152 MemoryBasicInformation
,
156 if (NT_SUCCESS(Status
) &&
157 mbi
.Protect
== PAGE_READONLY
&& mbi
.Type
== MEM_IMAGE
)
159 /* Attempt to treat it as a resource section. We need to
160 use SEH here because we don't know if it's actually a
164 Data
= RtlImageDirectoryEntryToData(mbi
.AllocationBase
,
166 IMAGE_DIRECTORY_ENTRY_RESOURCE
,
170 (ULONG_PTR
)Ptr
>= (ULONG_PTR
)Data
&&
171 (ULONG_PTR
)Ptr
< (ULONG_PTR
)Data
+ Size
)
173 /* The user tried to write into the resources. Make the page
176 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
181 if (NT_SUCCESS(Status
))
183 Ret
= EXCEPTION_CONTINUE_EXECUTION
;
187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
203 /* Query the current setting */
204 Status
= NtQueryInformationProcess(NtCurrentProcess(),
205 ProcessDefaultHardErrorMode
,
209 if (!NT_SUCCESS(Status
))
211 /* Fail if we couldn't query */
212 BaseSetLastNTError(Status
);
216 /* Check if NOT failing critical errors was requested */
217 if (ErrMode
& SEM_FAILCRITICALERRORS
)
219 /* Mask it out, since the native API works differently */
220 ErrMode
&= ~SEM_FAILCRITICALERRORS
;
224 /* OR it if the caller didn't, due to different native semantics */
225 ErrMode
|= SEM_FAILCRITICALERRORS
;
228 /* Return the mode */
236 UnhandledExceptionFilter(struct _EXCEPTION_POINTERS
*ExceptionInfo
)
239 HANDLE DebugPort
= NULL
;
241 ULONG_PTR ErrorParameters
[4];
243 PEXCEPTION_RECORD ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
244 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
246 if ((NTSTATUS
)ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
247 ExceptionRecord
->NumberParameters
>= 2)
249 switch(ExceptionRecord
->ExceptionInformation
[0])
251 case EXCEPTION_WRITE_FAULT
:
252 /* Change the protection on some write attempts, some InstallShield setups
254 RetValue
= BasepCheckForReadOnlyResource(
255 (PVOID
)ExceptionRecord
->ExceptionInformation
[1]);
256 if (RetValue
== EXCEPTION_CONTINUE_EXECUTION
)
257 return EXCEPTION_CONTINUE_EXECUTION
;
259 case EXCEPTION_EXECUTE_FAULT
:
265 /* Is there a debugger running ? */
266 ErrCode
= NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort
,
267 &DebugPort
, sizeof(HANDLE
), NULL
);
268 if (!NT_SUCCESS(ErrCode
) && ErrCode
!= STATUS_NOT_IMPLEMENTED
)
270 BaseSetLastNTError(ErrCode
);
271 return EXCEPTION_EXECUTE_HANDLER
;
276 /* Pass the exception to debugger. */
277 DPRINT("Passing exception to debugger\n");
278 return EXCEPTION_CONTINUE_SEARCH
;
281 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
284 LONG ret
= RealFilter(ExceptionInfo
);
285 if (ret
!= EXCEPTION_CONTINUE_SEARCH
)
289 if ((GetErrorMode() & SEM_NOGPFAULTERRORBOX
) == 0)
290 PrintStackTrace(ExceptionInfo
);
292 /* Save exception code and address */
293 ErrorParameters
[0] = (ULONG
)ExceptionRecord
->ExceptionCode
;
294 ErrorParameters
[1] = (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
;
296 if ((NTSTATUS
)ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
)
298 /* get the type of operation that caused the access violation */
299 ErrorParameters
[2] = ExceptionRecord
->ExceptionInformation
[0];
303 ErrorParameters
[2] = ExceptionRecord
->ExceptionInformation
[2];
306 /* Save faulting address */
307 ErrorParameters
[3] = ExceptionRecord
->ExceptionInformation
[1];
309 /* Raise the harderror */
310 ErrCode
= NtRaiseHardError(STATUS_UNHANDLED_EXCEPTION
,
311 4, 0, ErrorParameters
, OptionOkCancel
, &ErrorResponse
);
313 if (NT_SUCCESS(ErrCode
) && (ErrorResponse
== ResponseCancel
))
315 /* FIXME: Check the result, if the "Cancel" button was
316 clicked run a debugger */
317 DPRINT1("Debugging is not implemented yet\n");
321 * Returning EXCEPTION_EXECUTE_HANDLER means that the code in
322 * the __except block will be executed. Normally this will end up in a
326 return EXCEPTION_EXECUTE_HANDLER
;
334 RaiseException(IN DWORD dwExceptionCode
,
335 IN DWORD dwExceptionFlags
,
336 IN DWORD nNumberOfArguments
,
337 IN CONST ULONG_PTR
*lpArguments OPTIONAL
)
339 EXCEPTION_RECORD ExceptionRecord
;
341 /* Setup the exception record */
342 ExceptionRecord
.ExceptionCode
= dwExceptionCode
;
343 ExceptionRecord
.ExceptionRecord
= NULL
;
344 ExceptionRecord
.ExceptionAddress
= (PVOID
)RaiseException
;
345 ExceptionRecord
.ExceptionFlags
= dwExceptionFlags
& EXCEPTION_NONCONTINUABLE
;
347 /* Check if we have arguments */
351 ExceptionRecord
.NumberParameters
= 0;
355 /* We do, normalize the count */
356 if (nNumberOfArguments
> EXCEPTION_MAXIMUM_PARAMETERS
)
358 nNumberOfArguments
= EXCEPTION_MAXIMUM_PARAMETERS
;
361 /* Set the count of parameters and copy them */
362 ExceptionRecord
.NumberParameters
= nNumberOfArguments
;
363 RtlCopyMemory(ExceptionRecord
.ExceptionInformation
,
365 nNumberOfArguments
* sizeof(ULONG
));
368 /* Better handling of Delphi Exceptions... a ReactOS Hack */
369 if (dwExceptionCode
== 0xeedface || dwExceptionCode
== 0xeedfade)
371 DPRINT1("Delphi Exception at address: %p\n", ExceptionRecord
.ExceptionInformation
[0]);
372 DPRINT1("Exception-Object: %p\n", ExceptionRecord
.ExceptionInformation
[1]);
373 DPRINT1("Exception text: %lx\n", ExceptionRecord
.ExceptionInformation
[2]);
376 /* Trace the wine special error and show the modulename and functionname */
377 if (dwExceptionCode
== 0x80000100 /*EXCEPTION_WINE_STUB*/)
379 /* Numbers of parameter must be equal to two */
380 if (ExceptionRecord
.NumberParameters
== 2)
382 DPRINT1("Missing function in : %s\n", ExceptionRecord
.ExceptionInformation
[0]);
383 DPRINT1("with the functionname : %s\n", ExceptionRecord
.ExceptionInformation
[1]);
387 /* Raise the exception */
388 RtlRaiseException(&ExceptionRecord
);
396 SetErrorMode(IN UINT uMode
)
398 UINT PrevErrMode
, NewMode
;
400 /* Get the previous mode */
401 PrevErrMode
= GetErrorMode();
404 /* Check if failing critical errors was requested */
405 if (NewMode
& SEM_FAILCRITICALERRORS
)
407 /* Mask it out, since the native API works differently */
408 NewMode
&= ~SEM_FAILCRITICALERRORS
;
412 /* OR it if the caller didn't, due to different native semantics */
413 NewMode
|= SEM_FAILCRITICALERRORS
;
416 /* Always keep no alignment faults if they were set */
417 NewMode
|= (PrevErrMode
& SEM_NOALIGNMENTFAULTEXCEPT
);
419 /* Set the new mode */
420 NtSetInformationProcess(NtCurrentProcess(),
421 ProcessDefaultHardErrorMode
,
425 /* Return the previous mode */
432 LPTOP_LEVEL_EXCEPTION_FILTER
435 SetUnhandledExceptionFilter(IN LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
)
437 PVOID EncodedPointer
, EncodedOldPointer
;
439 EncodedPointer
= RtlEncodePointer(lpTopLevelExceptionFilter
);
440 EncodedOldPointer
= InterlockedExchangePointer((PVOID
*)&GlobalTopLevelExceptionFilter
,
442 return RtlDecodePointer(EncodedOldPointer
);
450 IsBadReadPtr(IN LPCVOID lp
,
454 BOOLEAN Result
= FALSE
;
455 volatile CHAR
*Current
;
459 if (!ucb
) return FALSE
;
460 if (!lp
) return TRUE
;
462 /* Get the page size */
463 PageSize
= BaseStaticServerData
->SysInfo
.PageSize
;
465 /* Calculate start and end */
466 Current
= (volatile CHAR
*)lp
;
467 Last
= (PCHAR
)((ULONG_PTR
)lp
+ ucb
- 1);
469 /* Another quick failure case */
470 if (Last
< Current
) return TRUE
;
475 /* Do an initial probe */
478 /* Align the addresses */
479 Current
= (volatile CHAR
*)ROUND_DOWN(Current
, PageSize
);
480 Last
= (PCHAR
)ROUND_DOWN(Last
, PageSize
);
482 /* Probe the entire range */
483 while (Current
!= Last
)
489 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
491 /* We hit an exception, so return true */
496 /* Return exception status */
505 IsBadHugeReadPtr(LPCVOID lp
,
508 /* Implementation is the same on 32-bit */
509 return IsBadReadPtr(lp
, ucb
);
517 IsBadCodePtr(FARPROC lpfn
)
519 /* Executing has the same privileges as reading */
520 return IsBadReadPtr((LPVOID
)lpfn
, 1);
528 IsBadWritePtr(IN LPVOID lp
,
532 BOOLEAN Result
= FALSE
;
533 volatile CHAR
*Current
;
537 if (!ucb
) return FALSE
;
538 if (!lp
) return TRUE
;
540 /* Get the page size */
541 PageSize
= BaseStaticServerData
->SysInfo
.PageSize
;
543 /* Calculate start and end */
544 Current
= (volatile CHAR
*)lp
;
545 Last
= (PCHAR
)((ULONG_PTR
)lp
+ ucb
- 1);
547 /* Another quick failure case */
548 if (Last
< Current
) return TRUE
;
553 /* Do an initial probe */
556 /* Align the addresses */
557 Current
= (volatile CHAR
*)ROUND_DOWN(Current
, PageSize
);
558 Last
= (PCHAR
)ROUND_DOWN(Last
, PageSize
);
560 /* Probe the entire range */
561 while (Current
!= Last
)
567 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
569 /* We hit an exception, so return true */
574 /* Return exception status */
583 IsBadHugeWritePtr(IN LPVOID lp
,
586 /* Implementation is the same on 32-bit */
587 return IsBadWritePtr(lp
, ucb
);
595 IsBadStringPtrW(IN LPCWSTR lpsz
,
598 BOOLEAN Result
= FALSE
;
599 volatile WCHAR
*Current
;
604 if (!ucchMax
) return FALSE
;
605 if (!lpsz
) return TRUE
;
607 /* Calculate start and end */
608 Current
= (volatile WCHAR
*)lpsz
;
609 Last
= (PWCHAR
)((ULONG_PTR
)lpsz
+ (ucchMax
* 2) - 2);
614 /* Probe the entire range */
616 while ((Char
) && (Current
!= Last
)) Char
= *Current
++;
618 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
620 /* We hit an exception, so return true */
625 /* Return exception status */
634 IsBadStringPtrA(IN LPCSTR lpsz
,
637 BOOLEAN Result
= FALSE
;
638 volatile CHAR
*Current
;
643 if (!ucchMax
) return FALSE
;
644 if (!lpsz
) return TRUE
;
646 /* Calculate start and end */
647 Current
= (volatile CHAR
*)lpsz
;
648 Last
= (PCHAR
)((ULONG_PTR
)lpsz
+ ucchMax
- 1);
653 /* Probe the entire range */
655 while ((Char
) && (Current
!= Last
)) Char
= *Current
++;
657 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
659 /* We hit an exception, so return true */
664 /* Return exception status */
673 SetLastError(IN DWORD dwErrCode
)
675 /* Break if a debugger requested checking for this error code */
676 if ((g_dwLastErrorToBreakOn
) && (g_dwLastErrorToBreakOn
== dwErrCode
)) DbgBreakPoint();
678 /* Set last error if it's a new error */
679 if (NtCurrentTeb()->LastErrorValue
!= dwErrCode
) NtCurrentTeb()->LastErrorValue
= dwErrCode
;
687 BaseSetLastNTError(IN NTSTATUS Status
)
691 /* Convert from NT to Win32, then set */
692 dwErrCode
= RtlNtStatusToDosError(Status
);
693 SetLastError(dwErrCode
);
704 /* Return the current value */
705 return NtCurrentTeb()->LastErrorValue
;