1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS Runtime Library
3 * PURPOSE: User-Mode Exception Support
4 * FILE: lib/rtl/exception.c
5 * PROGRAMERS: Alex Ionescu (alex@relsoft.net)
6 * David Welch <welch@cwcom.net>
7 * Skywing <skywing@valhallalegends.com>
8 * KJK::Hyperion <noog@libero.it>
11 /* INCLUDES *****************************************************************/
18 /* GLOBALS *****************************************************************/
20 PRTLP_UNHANDLED_EXCEPTION_FILTER RtlpUnhandledExceptionFilter
;
22 /* FUNCTIONS ***************************************************************/
24 #if !defined(_M_IX86) && !defined(_M_AMD64)
31 RtlRaiseException(IN PEXCEPTION_RECORD ExceptionRecord
)
36 /* Capture the context */
37 RtlCaptureContext(&Context
);
39 /* Save the exception address */
40 ExceptionRecord
->ExceptionAddress
= _ReturnAddress();
42 /* Write the context flag */
43 Context
.ContextFlags
= CONTEXT_FULL
;
45 /* Check if user mode debugger is active */
46 if (RtlpCheckForActiveDebugger())
48 /* Raise an exception immediately */
49 Status
= ZwRaiseException(ExceptionRecord
, &Context
, TRUE
);
53 /* Dispatch the exception and check if we should continue */
54 if (!RtlDispatchException(ExceptionRecord
, &Context
))
56 /* Raise the exception */
57 Status
= ZwRaiseException(ExceptionRecord
, &Context
, FALSE
);
61 /* Continue, go back to previous context */
62 Status
= ZwContinue(&Context
, FALSE
);
66 /* If we returned, raise a status */
67 RtlRaiseStatus(Status
);
76 #pragma warning(disable:4717) // RtlRaiseStatus is recursive by design
84 RtlRaiseStatus(IN NTSTATUS Status
)
86 EXCEPTION_RECORD ExceptionRecord
;
89 /* Capture the context */
90 RtlCaptureContext(&Context
);
92 /* Create an exception record */
93 ExceptionRecord
.ExceptionAddress
= _ReturnAddress();
94 ExceptionRecord
.ExceptionCode
= Status
;
95 ExceptionRecord
.ExceptionRecord
= NULL
;
96 ExceptionRecord
.NumberParameters
= 0;
97 ExceptionRecord
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
99 /* Write the context flag */
100 Context
.ContextFlags
= CONTEXT_FULL
;
102 /* Check if user mode debugger is active */
103 if (RtlpCheckForActiveDebugger())
105 /* Raise an exception immediately */
106 ZwRaiseException(&ExceptionRecord
, &Context
, TRUE
);
110 /* Dispatch the exception */
111 RtlDispatchException(&ExceptionRecord
, &Context
);
113 /* Raise exception if we got here */
114 Status
= ZwRaiseException(&ExceptionRecord
, &Context
, FALSE
);
117 /* If we returned, raise a status */
118 RtlRaiseStatus(Status
);
132 RtlCaptureStackBackTrace(IN ULONG FramesToSkip
,
133 IN ULONG FramesToCapture
,
134 OUT PVOID
*BackTrace
,
135 OUT PULONG BackTraceHash OPTIONAL
)
137 PVOID Frames
[2 * 64];
141 /* Skip a frame for the caller */
144 /* Don't go past the limit */
145 if ((FramesToCapture
+ FramesToSkip
) >= 128) return 0;
147 /* Do the back trace */
148 FrameCount
= RtlWalkFrameChain(Frames
, FramesToCapture
+ FramesToSkip
, 0);
150 /* Make sure we're not skipping all of them */
151 if (FrameCount
<= FramesToSkip
) return 0;
153 /* Loop all the frames */
154 for (i
= 0; i
< FramesToCapture
; i
++)
156 /* Don't go past the limit */
157 if ((FramesToSkip
+ i
) >= FrameCount
) break;
159 /* Save this entry and hash it */
160 BackTrace
[i
] = Frames
[FramesToSkip
+ i
];
161 Hash
+= PtrToUlong(BackTrace
[i
]);
165 if (BackTraceHash
) *BackTraceHash
= Hash
;
167 /* Clear the other entries and return count */
168 RtlFillMemoryUlong(Frames
, 128, 0);
173 * Private helper function to lookup the module name from a given address.
174 * The address can point to anywhere within the module.
177 _module_name_from_addr(const void* addr
, void **module_start_addr
,
178 char* psz
, size_t nChars
)
181 MEMORY_BASIC_INFORMATION mbi
;
182 if (VirtualQuery(addr
, &mbi
, sizeof(mbi
)) != sizeof(mbi
) ||
183 !GetModuleFileNameA((HMODULE
) mbi
.AllocationBase
, psz
, nChars
))
186 *module_start_addr
= 0;
190 *module_start_addr
= (void *) mbi
.AllocationBase
;
195 *module_start_addr
= 0;
202 _dump_context(PCONTEXT pc
)
206 * Print out the CPU registers
208 DbgPrint("CS:EIP %x:%x\n", pc
->SegCs
& 0xffff, pc
->Eip
);
209 DbgPrint("DS %x ES %x FS %x GS %x\n", pc
->SegDs
& 0xffff, pc
->SegEs
& 0xffff,
210 pc
->SegFs
& 0xffff, pc
->SegGs
& 0xfff);
211 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", pc
->Eax
, pc
->Ebx
, pc
->Ecx
);
212 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", pc
->Edx
,
213 pc
->Ebp
, pc
->Esi
, pc
->Esp
);
214 DbgPrint("EDI: %.8x EFLAGS: %.8x\n", pc
->Edi
, pc
->EFlags
);
215 #elif defined(_M_AMD64)
216 DbgPrint("CS:RIP %x:%I64x\n", pc
->SegCs
& 0xffff, pc
->Rip
);
217 DbgPrint("DS %x ES %x FS %x GS %x\n", pc
->SegDs
& 0xffff, pc
->SegEs
& 0xffff,
218 pc
->SegFs
& 0xffff, pc
->SegGs
& 0xfff);
219 DbgPrint("RAX: %I64x RBX: %I64x RCX: %I64x RDI: %I64x\n", pc
->Rax
, pc
->Rbx
, pc
->Rcx
, pc
->Rdi
);
220 DbgPrint("RDX: %I64x RBP: %I64x RSI: %I64x RSP: %I64x\n", pc
->Rdx
, pc
->Rbp
, pc
->Rsi
, pc
->Rsp
);
221 DbgPrint("R8: %I64x R9: %I64x R10: %I64x R11: %I64x\n", pc
->R8
, pc
->R9
, pc
->R10
, pc
->R11
);
222 DbgPrint("R12: %I64x R13: %I64x R14: %I64x R15: %I64x\n", pc
->R12
, pc
->R13
, pc
->R14
, pc
->R15
);
223 DbgPrint("EFLAGS: %.8x\n", pc
->EFlags
);
224 #elif defined(_M_ARM)
225 DbgPrint("Pc: %lx Lr: %lx Sp: %lx Cpsr: %lx\n", pc
->Pc
, pc
->Lr
, pc
->Sp
, pc
->Cpsr
);
226 DbgPrint("R0: %lx R1: %lx R2: %lx R3: %lx\n", pc
->R0
, pc
->R1
, pc
->R2
, pc
->R3
);
227 DbgPrint("R4: %lx R5: %lx R6: %lx R7: %lx\n", pc
->R4
, pc
->R5
, pc
->R6
, pc
->R7
);
228 DbgPrint("R8: %lx R9: %lx R10: %lx R11: %lx\n", pc
->R8
, pc
->R9
, pc
->R10
, pc
->R11
);
229 DbgPrint("R12: %lx \n", pc
->R12
);
231 #pragma message ("Unknown architecture")
236 PrintStackTrace(struct _EXCEPTION_POINTERS
*ExceptionInfo
)
239 CHAR szMod
[128] = "";
240 PEXCEPTION_RECORD ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
241 PCONTEXT ContextRecord
= ExceptionInfo
->ContextRecord
;
243 /* Print a stack trace. */
244 DbgPrint("Unhandled exception\n");
245 DbgPrint("ExceptionCode: %8x\n", ExceptionRecord
->ExceptionCode
);
247 if ((NTSTATUS
) ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
&&
248 ExceptionRecord
->NumberParameters
== 2)
250 DbgPrint("Faulting Address: %8x\n", ExceptionRecord
->ExceptionInformation
[1]);
253 _dump_context(ContextRecord
);
254 _module_name_from_addr(ExceptionRecord
->ExceptionAddress
, &StartAddr
, szMod
, sizeof(szMod
));
255 DbgPrint("Address:\n %8x+%-8x %s\n",
257 (ULONG_PTR
) ExceptionRecord
->ExceptionAddress
- (ULONG_PTR
) StartAddr
,
260 DbgPrint("Frames:\n");
265 PULONG Frame
= (PULONG
) ContextRecord
->Ebp
;
267 for (i
= 0; Frame
[1] != 0 && Frame
[1] != 0xdeadbeef && i
< 128; i
++)
269 //if (IsBadReadPtr((PVOID) Frame[1], 4))
272 DbgPrint(" %8x%9s %s\n", Frame
[1], "<invalid address>", " ");
276 _module_name_from_addr((const void*) Frame
[1], &StartAddr
,
277 szMod
, sizeof(szMod
));
278 DbgPrint(" %8x+%-8x %s\n",
280 (ULONG_PTR
) Frame
[1] - (ULONG_PTR
) StartAddr
,
284 if (Frame
[0] == 0) break;
285 //if (IsBadReadPtr((PVOID) Frame[0], sizeof(*Frame) * 2))
288 Frame
= (PULONG
) Frame
[0];
291 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
293 DbgPrint("<error dumping stack trace: 0x%x>\n", _SEH2_GetExceptionCode());
305 RtlUnhandledExceptionFilter(IN
struct _EXCEPTION_POINTERS
* ExceptionInfo
)
307 /* This is used by the security cookie checks, and calso called externally */
309 PrintStackTrace(ExceptionInfo
);
310 return ERROR_CALL_NOT_IMPLEMENTED
;
318 RtlSetUnhandledExceptionFilter(IN PRTLP_UNHANDLED_EXCEPTION_FILTER TopLevelExceptionFilter
)
320 /* Set the filter which is used by the CriticalSection package */
321 RtlpUnhandledExceptionFilter
= RtlEncodePointer(TopLevelExceptionFilter
);