917f74a3b5d9b33986ca4f4e14003bda097d91ff
[reactos.git] / reactos / lib / rtl / exception.c
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>
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <rtl.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* FUNCTIONS ***************************************************************/
19
20 /*
21 * @implemented
22 */
23 VOID
24 NTAPI
25 RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
26 {
27 CONTEXT Context;
28 NTSTATUS Status;
29
30 /* Capture the context */
31 RtlCaptureContext(&Context);
32
33 /* Save the exception address */
34 ExceptionRecord->ExceptionAddress = RtlpGetExceptionAddress();
35
36 /* Write the context flag */
37 Context.ContextFlags = CONTEXT_FULL;
38
39 /* Check if we're being debugged (user-mode only) */
40 if (!RtlpCheckForActiveDebugger(TRUE))
41 {
42 /* Raise an exception immediately */
43 Status = ZwRaiseException(ExceptionRecord, &Context, TRUE);
44 }
45 else
46 {
47 /* Dispatch the exception and check if we should continue */
48 if (RtlDispatchException(ExceptionRecord, &Context))
49 {
50 /* Raise the exception */
51 Status = ZwRaiseException(ExceptionRecord, &Context, FALSE);
52 }
53 else
54 {
55 /* Continue, go back to previous context */
56 Status = ZwContinue(&Context, FALSE);
57 }
58 }
59
60 /* If we returned, raise a status */
61 RtlRaiseStatus(Status);
62 }
63
64 /*
65 * @implemented
66 */
67 VOID
68 NTAPI
69 RtlRaiseStatus(NTSTATUS Status)
70 {
71 EXCEPTION_RECORD ExceptionRecord;
72 CONTEXT Context;
73
74 /* Capture the context */
75 RtlCaptureContext(&Context);
76
77 /* Add one argument to ESP */
78 Context.Esp += sizeof(PVOID);
79
80 /* Create an exception record */
81 ExceptionRecord.ExceptionAddress = RtlpGetExceptionAddress();
82 ExceptionRecord.ExceptionCode = Status;
83 ExceptionRecord.ExceptionRecord = NULL;
84 ExceptionRecord.NumberParameters = 0;
85 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
86
87 /* Write the context flag */
88 Context.ContextFlags = CONTEXT_FULL;
89
90 /* Check if we're being debugged (user-mode only) */
91 if (!RtlpCheckForActiveDebugger(TRUE))
92 {
93 /* Raise an exception immediately */
94 ZwRaiseException(&ExceptionRecord, &Context, TRUE);
95 }
96 else
97 {
98 /* Dispatch the exception */
99 RtlDispatchException(&ExceptionRecord, &Context);
100
101 /* Raise exception if we got here */
102 Status = ZwRaiseException(&ExceptionRecord, &Context, FALSE);
103 }
104
105 /* If we returned, raise a status */
106 RtlRaiseStatus(Status);
107 }
108
109 /*
110 * @implemented
111 */
112 ULONG
113 NTAPI
114 RtlWalkFrameChain(OUT PVOID *Callers,
115 IN ULONG Count,
116 IN ULONG Flags)
117 {
118 PULONG Stack, NewStack;
119 ULONG Eip;
120 ULONG_PTR StackBegin, StackEnd;
121 BOOLEAN Result, StopSearch = FALSE;
122 ULONG i = 0;
123
124 /* Get current EBP */
125 #ifdef _M_IX86
126 #if defined __GNUC__
127 __asm__("mov %%ebp, %0" : "=r" (Stack) : );
128 #elif defined(_MSC_VER)
129 __asm mov Stack, ebp
130 #endif
131 #endif
132
133 /* Set it as the stack begin limit as well */
134 StackBegin = (ULONG_PTR)Stack;
135
136 /* Check if we're called for non-logging mode */
137 if (!Flags)
138 {
139 /* Get the actual safe limits */
140 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
141 &StackBegin,
142 &StackEnd);
143 if (!Result) return 0;
144 }
145
146 /* Loop the frames */
147 for (i = 0; i < Count; i++)
148 {
149 /* Check if we're past the stack */
150 if ((ULONG_PTR)Stack >= StackEnd) break;
151
152 /* Check if this is the first entry */
153 #if 0
154 if (!i)
155 {
156 if ((ULONG_PTR)Stack != StackBegin) break;
157 }
158 else
159 {
160 if ((ULONG_PTR)Stack == StackBegin) break;
161 }
162 #endif
163
164 /* Make sure there's enough frames */
165 if ((StackEnd - (ULONG_PTR)Stack) < (2 * sizeof(ULONG_PTR))) break;
166
167 /* Get new stack and EIP */
168 NewStack = (PULONG)Stack[0];
169 Eip = Stack[1];
170
171 /* Check if the new pointer is above the oldone and past the end */
172 if (!((Stack < NewStack) && ((ULONG_PTR)NewStack < StackEnd)))
173 {
174 /* Stop searching after this entry */
175 StopSearch = TRUE;
176 }
177
178 /* Also make sure that the EIP isn't a stack address */
179 if ((StackBegin < Eip) && (Eip < StackEnd)) break;
180
181 /* Save this frame */
182 Callers[i] = (PVOID)Eip;
183
184 /* Check if we should continue */
185 if (StopSearch) break;
186
187 /* Move to the next stack */
188 Stack = NewStack;
189 }
190
191 /* Return frames parsed */
192 return i;
193 }
194
195 /*
196 * @implemented
197 */
198 USHORT
199 NTAPI
200 RtlCaptureStackBackTrace(IN ULONG FramesToSkip,
201 IN ULONG FramesToCapture,
202 OUT PVOID *BackTrace,
203 OUT PULONG BackTraceHash OPTIONAL)
204 {
205 PVOID Frames[2 * 64];
206 ULONG FrameCount;
207 ULONG Hash = 0, i;
208
209 /* Skip a frame for the caller */
210 FramesToSkip++;
211
212 /* Don't go past the limit */
213 if ((FramesToCapture + FramesToSkip) >= 128) return 0;
214
215 /* Do the back trace */
216 FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 0);
217
218 /* Make sure we're not skipping all of them */
219 if (FrameCount <= FramesToSkip) return 0;
220
221 /* Loop all the frames */
222 for (i = 0; i < FramesToCapture; i++)
223 {
224 /* Don't go past the limit */
225 if ((FramesToSkip + i) >= FrameCount) break;
226
227 /* Save this entry and hash it */
228 BackTrace[i] = Frames[FramesToSkip + i];
229 Hash += PtrToUlong(BackTrace[i]);
230 }
231
232 /* Write the hash */
233 if (BackTraceHash) *BackTraceHash = Hash;
234
235 /* Clear the other entries and return count */
236 RtlFillMemoryUlong(Frames, 128, 0);
237 return (USHORT)i;
238 }
239
240 /*
241 * @unimplemented
242 */
243 LONG
244 NTAPI
245 RtlUnhandledExceptionFilter(IN struct _EXCEPTION_POINTERS* ExceptionInfo)
246 {
247 UNIMPLEMENTED;
248 return ERROR_CALL_NOT_IMPLEMENTED;
249 }
250
251 /* EOF */