576f91d9a4ab95a9d6f4c214e91cb43017521fa1
[reactos.git] / reactos / ntoskrnl / ke / i386 / usertrap.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/usertrap.c
22 * PURPOSE: Handling usermode exceptions.
23 * PROGRAMMER: David Welch (welch@cwcom.net)
24 * REVISION HISTORY:
25 * 18/11/01: Split from ntoskrnl/ke/i386/exp.c
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <roscfg.h>
32 #include <internal/ntoskrnl.h>
33 #include <internal/ke.h>
34 #include <internal/i386/segment.h>
35 #include <internal/i386/mm.h>
36 #include <internal/module.h>
37 #include <internal/mm.h>
38 #include <internal/ps.h>
39 #include <internal/trap.h>
40 #include <ntdll/ldr.h>
41 #include <internal/safe.h>
42
43 #define NDEBUG
44 #include <internal/debug.h>
45
46 /* GLOBALS *****************************************************************/
47
48 #ifdef DBG
49
50 NTSTATUS
51 LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo,
52 IN ULONG_PTR RelativeAddress,
53 OUT PULONG LineNumber,
54 OUT PCH FileName OPTIONAL,
55 OUT PCH FunctionName OPTIONAL);
56
57 #endif /* DBG */
58
59 static char *ExceptionTypeStrings[] =
60 {
61 "Divide Error",
62 "Debug Trap",
63 "NMI",
64 "Breakpoint",
65 "Overflow",
66 "BOUND range exceeded",
67 "Invalid Opcode",
68 "No Math Coprocessor",
69 "Double Fault",
70 "Unknown(9)",
71 "Invalid TSS",
72 "Segment Not Present",
73 "Stack Segment Fault",
74 "General Protection",
75 "Page Fault",
76 "Math Fault",
77 "Alignment Check",
78 "Machine Check"
79 };
80
81 /* FUNCTIONS ****************************************************************/
82
83 STATIC BOOLEAN
84 print_user_address(PVOID address)
85 {
86 PLIST_ENTRY current_entry;
87 PLDR_MODULE current;
88 PEPROCESS CurrentProcess;
89 PPEB Peb = NULL;
90 ULONG_PTR RelativeAddress;
91 #ifdef DBG
92 NTSTATUS Status;
93 ULONG LineNumber;
94 CHAR FileName[256];
95 CHAR FunctionName[256];
96 #endif
97
98 CurrentProcess = PsGetCurrentProcess();
99 if (NULL != CurrentProcess)
100 {
101 Peb = CurrentProcess->Peb;
102 }
103
104 if (NULL == Peb)
105 {
106 DbgPrint("<%x>", address);
107 return(TRUE);
108 }
109
110 current_entry = Peb->Ldr->InLoadOrderModuleList.Flink;
111
112 while (current_entry != &Peb->Ldr->InLoadOrderModuleList &&
113 current_entry != NULL)
114 {
115 current =
116 CONTAINING_RECORD(current_entry, LDR_MODULE, InLoadOrderModuleList);
117
118 if (address >= (PVOID)current->BaseAddress &&
119 address < (PVOID)(current->BaseAddress + current->SizeOfImage))
120 {
121 RelativeAddress = (ULONG_PTR) address - (ULONG_PTR)current->BaseAddress;
122 #ifdef DBG
123 Status = LdrGetAddressInformation(&current->SymbolInfo,
124 RelativeAddress,
125 &LineNumber,
126 FileName,
127 FunctionName);
128 if (NT_SUCCESS(Status))
129 {
130 DbgPrint("<%wZ: %x (%s:%d (%s))>",
131 &current->BaseDllName, RelativeAddress, FileName, LineNumber, FunctionName);
132 }
133 else
134 {
135 DbgPrint("<%wZ: %x>", &current->BaseDllName, RelativeAddress);
136 }
137 #else /* !DBG */
138 DbgPrint("<%wZ: %x>", &current->BaseDllName, RelativeAddress);
139 #endif /* !DBG */
140
141 return(TRUE);
142 }
143
144 current_entry = current_entry->Flink;
145 }
146 return(FALSE);
147 }
148
149 #if 0
150 /*
151 * Disabled until SEH support is implemented.
152 */
153 ULONG
154 KiUserTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
155 {
156 EXCEPTION_RECORD Er;
157
158 if (ExceptionNr == 0)
159 {
160 Er.ExceptionCode = STATUS_INTEGER_DIVIDE_BY_ZERO;
161 }
162 else if (ExceptionNr == 1)
163 {
164 Er.ExceptionCode = STATUS_SINGLE_STEP;
165 }
166 else if (ExceptionNr == 3)
167 {
168 Er.ExceptionCode = STATUS_BREAKPOINT;
169 }
170 else if (ExceptionNr == 4)
171 {
172 Er.ExceptionCode = STATUS_INTEGER_OVERFLOW;
173 }
174 else if (ExceptionNr == 5)
175 {
176 Er.ExceptionCode = STATUS_ARRAY_BOUNDS_EXCEEDED;
177 }
178 else if (ExceptionNr == 6)
179 {
180 Er.ExceptionCode = STATUS_ILLEGAL_INSTRUCTION;
181 }
182 else
183 {
184 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
185 }
186 Er.ExceptionFlags = 0;
187 Er.ExceptionRecord = NULL;
188 Er.ExceptionAddress = (PVOID)Tf->Eip;
189 if (ExceptionNr == 14)
190 {
191 Er.NumberParameters = 2;
192 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
193 Er.ExceptionInformation[1] = (ULONG)Cr2;
194 }
195 else
196 {
197 Er.NumberParameters = 0;
198 }
199
200
201 KiDispatchException(&Er, 0, Tf, UserMode, TRUE);
202 return(0);
203 }
204 #else
205 ULONG
206 KiUserTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
207 {
208 PULONG Frame;
209 ULONG cr3;
210 ULONG i;
211 ULONG ReturnAddress;
212 ULONG NextFrame;
213 NTSTATUS Status;
214
215 /*
216 * Get the PDBR
217 */
218 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3));
219
220 /*
221 * Print out the CPU registers
222 */
223 if (ExceptionNr < 19)
224 {
225 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
226 ExceptionNr, Tf->ErrorCode&0xffff);
227 }
228 else
229 {
230 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
231 }
232 DbgPrint("CS:EIP %x:%x ", Tf->Cs&0xffff, Tf->Eip);
233 print_user_address((PVOID)Tf->Eip);
234 DbgPrint("\n");
235 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3));
236 DbgPrint("CR2 %x CR3 %x ", Cr2, cr3);
237 DbgPrint("Process: %x ",PsGetCurrentProcess());
238 if (PsGetCurrentProcess() != NULL)
239 {
240 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
241 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
242 }
243 if (PsGetCurrentThread() != NULL)
244 {
245 DbgPrint("Thrd: %x Tid: %x",
246 PsGetCurrentThread(),
247 PsGetCurrentThread()->Cid.UniqueThread);
248 }
249 DbgPrint("\n");
250 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
251 Tf->Fs&0xffff, Tf->Gs&0xfff);
252 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
253 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf->Edx, Tf->Ebp, Tf->Esi);
254 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
255 DbgPrint("SS:ESP %x:%x\n", Tf->Ss, Tf->Esp);
256
257 /*
258 * Dump the stack frames
259 */
260 DbgPrint("Frames: ");
261 i = 1;
262 Frame = (PULONG)Tf->Ebp;
263 while (Frame != NULL && i < 50)
264 {
265 Status = MmSafeCopyFromUser(&ReturnAddress, &Frame[1], sizeof(ULONG));
266 if (!NT_SUCCESS(Status))
267 {
268 DbgPrint("????????\n");
269 break;
270 }
271 print_user_address((PVOID)ReturnAddress);
272 Status = MmSafeCopyFromUser(&NextFrame, &Frame[0], sizeof(ULONG));
273 if (!NT_SUCCESS(Status))
274 {
275 DbgPrint("Frame is inaccessible.\n");
276 break;
277 }
278 if ((NextFrame + sizeof(ULONG)) >= KERNEL_BASE)
279 {
280 DbgPrint("Next frame is in kernel space!\n");
281 break;
282 }
283 if (NextFrame != 0 && NextFrame <= (ULONG)Frame)
284 {
285 DbgPrint("Next frame is not above current frame!\n");
286 break;
287 }
288 Frame = (PULONG)NextFrame;
289 i++;
290 }
291
292 /*
293 * Kill the faulting process
294 */
295 __asm__("sti\n\t");
296 ZwTerminateProcess(NtCurrentProcess(), STATUS_NONCONTINUABLE_EXCEPTION);
297
298 /*
299 * If terminating the process fails then bugcheck
300 */
301 KeBugCheck(0);
302 return(0);
303 }
304 #endif