Fix previous strangely incomplete NtRaiseException implementation and re-enable the...
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/i386/exp.c
5 * PURPOSE: Handling exceptions
6 *
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Skywing (skywing@valhallalegends.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /*
19 * FIXMES:
20 * - Clean up file.
21 * - Add more exception frame support for non-i386 compatibility.
22 * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
23 * - Implement official stack trace functions (exported) and remove stuff here.
24 * - Forward exceptions to user-mode debugger.
25 * - Wrap Ki NTDLL callbacks in SEH.
26 */
27
28 /* GLOBALS *****************************************************************/
29
30 #define FLAG_IF (1<<9)
31
32 #define _STR(x) #x
33 #define STR(x) _STR(x)
34
35 #ifndef ARRAY_SIZE
36 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
37 #endif
38
39 extern void KiSystemService(void);
40 extern void KiDebugService(void);
41
42 extern VOID KiTrap0(VOID);
43 extern VOID KiTrap1(VOID);
44 extern VOID KiTrap2(VOID);
45 extern VOID KiTrap3(VOID);
46 extern VOID KiTrap4(VOID);
47 extern VOID KiTrap5(VOID);
48 extern VOID KiTrap6(VOID);
49 extern VOID KiTrap7(VOID);
50 extern VOID KiTrap8(VOID);
51 extern VOID KiTrap9(VOID);
52 extern VOID KiTrap10(VOID);
53 extern VOID KiTrap11(VOID);
54 extern VOID KiTrap12(VOID);
55 extern VOID KiTrap13(VOID);
56 extern VOID KiTrap14(VOID);
57 extern VOID KiTrap15(VOID);
58 extern VOID KiTrap16(VOID);
59 extern VOID KiTrap17(VOID);
60 extern VOID KiTrap18(VOID);
61 extern VOID KiTrap19(VOID);
62 extern VOID KiTrapUnknown(VOID);
63
64 extern ULONG init_stack;
65 extern ULONG init_stack_top;
66
67 extern BOOLEAN Ke386NoExecute;
68
69 static char *ExceptionTypeStrings[] =
70 {
71 "Divide Error",
72 "Debug Trap",
73 "NMI",
74 "Breakpoint",
75 "Overflow",
76 "BOUND range exceeded",
77 "Invalid Opcode",
78 "No Math Coprocessor",
79 "Double Fault",
80 "Unknown(9)",
81 "Invalid TSS",
82 "Segment Not Present",
83 "Stack Segment Fault",
84 "General Protection",
85 "Page Fault",
86 "Reserved(15)",
87 "Math Fault",
88 "Alignment Check",
89 "Machine Check",
90 "SIMD Fault"
91 };
92
93 NTSTATUS ExceptionToNtStatus[] =
94 {
95 STATUS_INTEGER_DIVIDE_BY_ZERO,
96 STATUS_SINGLE_STEP,
97 STATUS_ACCESS_VIOLATION,
98 STATUS_BREAKPOINT,
99 STATUS_INTEGER_OVERFLOW,
100 STATUS_ARRAY_BOUNDS_EXCEEDED,
101 STATUS_ILLEGAL_INSTRUCTION,
102 STATUS_FLOAT_INVALID_OPERATION,
103 STATUS_ACCESS_VIOLATION,
104 STATUS_ACCESS_VIOLATION,
105 STATUS_ACCESS_VIOLATION,
106 STATUS_ACCESS_VIOLATION,
107 STATUS_STACK_OVERFLOW,
108 STATUS_ACCESS_VIOLATION,
109 STATUS_ACCESS_VIOLATION,
110 STATUS_ACCESS_VIOLATION, /* RESERVED */
111 STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
112 STATUS_DATATYPE_MISALIGNMENT,
113 STATUS_ACCESS_VIOLATION,
114 STATUS_FLOAT_MULTIPLE_TRAPS,
115 };
116
117 /* FUNCTIONS ****************************************************************/
118
119 BOOLEAN STDCALL
120 KiRosPrintAddress(PVOID address)
121 {
122 PLIST_ENTRY current_entry;
123 PLDR_DATA_TABLE_ENTRY current;
124 extern LIST_ENTRY ModuleListHead;
125 ULONG_PTR RelativeAddress;
126 ULONG i = 0;
127
128 do
129 {
130 current_entry = ModuleListHead.Flink;
131
132 while (current_entry != &ModuleListHead)
133 {
134 current =
135 CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
136
137 if (address >= (PVOID)current->DllBase &&
138 address < (PVOID)((ULONG_PTR)current->DllBase + current->SizeOfImage))
139 {
140 RelativeAddress = (ULONG_PTR) address - (ULONG_PTR) current->DllBase;
141 DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
142 return(TRUE);
143 }
144 current_entry = current_entry->Flink;
145 }
146
147 address = (PVOID)((ULONG_PTR)address & ~(ULONG_PTR)MmSystemRangeStart);
148 } while(++i <= 1);
149
150 return(FALSE);
151 }
152
153 ULONG
154 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
155 {
156 EXCEPTION_RECORD Er;
157
158 Er.ExceptionFlags = 0;
159 Er.ExceptionRecord = NULL;
160 Er.ExceptionAddress = (PVOID)Tf->Eip;
161
162 if (ExceptionNr == 14)
163 {
164 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
165 Er.NumberParameters = 2;
166 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
167 Er.ExceptionInformation[1] = (ULONG)Cr2;
168 }
169 else
170 {
171 if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
172 {
173 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
174 }
175 else
176 {
177 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
178 }
179 Er.NumberParameters = 0;
180 }
181
182 /* FIXME: Which exceptions are noncontinuable? */
183 Er.ExceptionFlags = 0;
184
185 KiDispatchException(&Er, NULL, Tf, KernelMode, TRUE);
186
187 return(0);
188 }
189
190 VOID
191 KiDoubleFaultHandler(VOID)
192 {
193 unsigned int cr2;
194 ULONG StackLimit;
195 ULONG StackBase;
196 ULONG Esp0;
197 ULONG ExceptionNr = 8;
198 KTSS* OldTss;
199 PULONG Frame;
200 ULONG OldCr3;
201 #if 0
202 ULONG i, j;
203 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
204 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
205 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
206 ULONG TraceLength;
207 BOOLEAN FoundRepeat;
208 #endif
209
210 OldTss = KeGetCurrentKPCR()->TSS;
211 Esp0 = OldTss->Esp;
212
213 /* Get CR2 */
214 cr2 = Ke386GetCr2();
215 if (PsGetCurrentThread() != NULL &&
216 PsGetCurrentThread()->ThreadsProcess != NULL)
217 {
218 OldCr3 = (ULONG)
219 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
220 }
221 else
222 {
223 OldCr3 = 0xBEADF0AL;
224 }
225
226 /*
227 * Check for stack underflow
228 */
229 if (PsGetCurrentThread() != NULL &&
230 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
231 {
232 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
233 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
234 ExceptionNr = 12;
235 }
236
237 /*
238 * Print out the CPU registers
239 */
240 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
241 {
242 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
243 ExceptionNr, 0);
244 }
245 else
246 {
247 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
248 }
249 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
250 KeRosPrintAddress((PVOID)OldTss->Eip);
251 DbgPrint("\n");
252 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
253 DbgPrint("Proc: %x ",PsGetCurrentProcess());
254 if (PsGetCurrentProcess() != NULL)
255 {
256 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
257 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
258 }
259 if (PsGetCurrentThread() != NULL)
260 {
261 DbgPrint("Thrd: %x Tid: %x",
262 PsGetCurrentThread(),
263 PsGetCurrentThread()->Cid.UniqueThread);
264 }
265 DbgPrint("\n");
266 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
267 OldTss->Fs, OldTss->Gs);
268 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
269 OldTss->Ecx);
270 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss->Edx,
271 OldTss->Ebp, OldTss->Esi, Esp0);
272 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
273 if (OldTss->Cs == KERNEL_CS)
274 {
275 DbgPrint("kESP %.8x ", Esp0);
276 if (PsGetCurrentThread() != NULL)
277 {
278 DbgPrint("kernel stack base %x\n",
279 PsGetCurrentThread()->Tcb.StackLimit);
280
281 }
282 }
283 else
284 {
285 DbgPrint("User ESP %.8x\n", OldTss->Esp);
286 }
287 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
288 {
289 if (PsGetCurrentThread() != NULL)
290 {
291 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
292 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
293 }
294 else
295 {
296 StackLimit = (ULONG)init_stack_top;
297 StackBase = (ULONG)init_stack;
298 }
299
300 /*
301 Change to an #if 0 to reduce the amount of information printed on
302 a recursive stack trace.
303 */
304 #if 1
305 DbgPrint("Frames: ");
306 Frame = (PULONG)OldTss->Ebp;
307 while (Frame != NULL && (ULONG)Frame >= StackBase)
308 {
309 KeRosPrintAddress((PVOID)Frame[1]);
310 Frame = (PULONG)Frame[0];
311 DbgPrint("\n");
312 }
313 #else
314 DbgPrint("Frames: ");
315 i = 0;
316 Frame = (PULONG)OldTss->Ebp;
317 while (Frame != NULL && (ULONG)Frame >= StackBase)
318 {
319 StackTrace[i] = (PVOID)Frame[1];
320 Frame = (PULONG)Frame[0];
321 i++;
322 }
323 TraceLength = i;
324
325 i = 0;
326 while (i < TraceLength)
327 {
328 StackRepeatCount[i] = 0;
329 j = i + 1;
330 FoundRepeat = FALSE;
331 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
332 {
333 if (memcmp(&StackTrace[i], &StackTrace[j],
334 (j - i) * sizeof(PVOID)) == 0)
335 {
336 StackRepeatCount[i] = 2;
337 StackRepeatLength[i] = j - i;
338 FoundRepeat = TRUE;
339 }
340 else
341 {
342 j++;
343 }
344 }
345 if (FoundRepeat == FALSE)
346 {
347 i++;
348 continue;
349 }
350 j = j + StackRepeatLength[i];
351 while ((TraceLength - j) >= StackRepeatLength[i] &&
352 FoundRepeat == TRUE)
353 {
354 if (memcmp(&StackTrace[i], &StackTrace[j],
355 StackRepeatLength[i] * sizeof(PVOID)) == 0)
356 {
357 StackRepeatCount[i]++;
358 j = j + StackRepeatLength[i];
359 }
360 else
361 {
362 FoundRepeat = FALSE;
363 }
364 }
365 i = j;
366 }
367
368 i = 0;
369 while (i < TraceLength)
370 {
371 if (StackRepeatCount[i] == 0)
372 {
373 KeRosPrintAddress(StackTrace[i]);
374 i++;
375 }
376 else
377 {
378 DbgPrint("{");
379 if (StackRepeatLength[i] == 0)
380 {
381 for(;;);
382 }
383 for (j = 0; j < StackRepeatLength[i]; j++)
384 {
385 KeRosPrintAddress(StackTrace[i + j]);
386 }
387 DbgPrint("}*%d", StackRepeatCount[i]);
388 i = i + StackRepeatLength[i] * StackRepeatCount[i];
389 }
390 }
391 #endif
392 }
393
394 DbgPrint("\n");
395 for(;;);
396 }
397
398 VOID
399 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
400 {
401 ULONG cr3_;
402 ULONG StackLimit;
403 ULONG Esp0;
404 ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
405 ULONG cr2 = (ULONG)Tf->DebugPointer;
406
407 Esp0 = (ULONG)Tf;
408
409 /*
410 * Print out the CPU registers
411 */
412 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
413 {
414 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
415 ExceptionNr, Tf->ErrorCode&0xffff);
416 }
417 else
418 {
419 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
420 }
421 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
422 Tf->Cs&0xffff, Tf->Eip);
423 KeRosPrintAddress((PVOID)Tf->Eip);
424 DbgPrint("\n");
425 Ke386GetPageTableDirectory(cr3_);
426 DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
427 DbgPrint("Proc: %x ",PsGetCurrentProcess());
428 if (PsGetCurrentProcess() != NULL)
429 {
430 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
431 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
432 }
433 if (PsGetCurrentThread() != NULL)
434 {
435 DbgPrint("Thrd: %x Tid: %x",
436 PsGetCurrentThread(),
437 PsGetCurrentThread()->Cid.UniqueThread);
438 }
439 DbgPrint("\n");
440 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
441 Tf->Fs&0xffff, Tf->Gs&0xfff);
442 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
443 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
444 Tf->Ebp, Tf->Esi, Esp0);
445 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
446 if ((Tf->Cs&0xffff) == KERNEL_CS)
447 {
448 DbgPrint("kESP %.8x ", Esp0);
449 if (PsGetCurrentThread() != NULL)
450 {
451 DbgPrint("kernel stack base %x\n",
452 PsGetCurrentThread()->Tcb.StackLimit);
453
454 }
455 }
456
457 if (PsGetCurrentThread() != NULL)
458 {
459 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
460 }
461 else
462 {
463 StackLimit = (ULONG)init_stack_top;
464 }
465
466 /*
467 * Dump the stack frames
468 */
469 KeDumpStackFrames((PULONG)Tf->Ebp);
470 }
471
472 ULONG
473 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
474 /*
475 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
476 * message and halt the computer
477 * ARGUMENTS:
478 * Complete CPU context
479 */
480 {
481 ULONG_PTR cr2;
482 NTSTATUS Status;
483 ULONG Esp0;
484
485 ASSERT(ExceptionNr != 14);
486
487 /* Store the exception number in an unused field in the trap frame. */
488 Tf->DebugArgMark = (PVOID)ExceptionNr;
489
490 /* Use the address of the trap frame as approximation to the ring0 esp */
491 Esp0 = (ULONG)&Tf->Eip;
492
493 /* Get CR2 */
494 cr2 = Ke386GetCr2();
495 Tf->DebugPointer = (PVOID)cr2;
496
497 /*
498 * If this was a V86 mode exception then handle it specially
499 */
500 if (Tf->Eflags & (1 << 17))
501 {
502 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->Eflags, Tf->Eip, ExceptionNr);
503 return(KeV86Exception(ExceptionNr, Tf, cr2));
504 }
505
506 /*
507 * Check for stack underflow, this may be obsolete
508 */
509 if (PsGetCurrentThread() != NULL &&
510 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
511 {
512 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
513 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit, Tf->Eip);
514 ExceptionNr = 12;
515 }
516
517 if (ExceptionNr == 15)
518 {
519 /*
520 * FIXME:
521 * This exception should never occur. The P6 has a bug, which does sometimes deliver
522 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
523 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
524 * sources. Linux does ignore this exception.
525 *
526 * Hartmut Birr
527 */
528 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
529 return(0);
530 }
531
532 /*
533 * Check for a breakpoint that was only for the attention of the debugger.
534 */
535 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
536 {
537 /*
538 EIP is already adjusted by the processor to point to the instruction
539 after the breakpoint.
540 */
541 return(0);
542 }
543
544 /*
545 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
546 */
547 if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
548 {
549 Status = KiHandleFpuFault(Tf, ExceptionNr);
550 if (NT_SUCCESS(Status))
551 {
552 return(0);
553 }
554 }
555
556 /*
557 * Handle user exceptions differently
558 */
559 if ((Tf->Cs & 0xFFFF) == USER_CS)
560 {
561 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
562 }
563 else
564 {
565 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
566 }
567 }
568
569 BOOLEAN
570 STDCALL
571 KeContextToTrapFrame(PCONTEXT Context,
572 PKEXCEPTION_FRAME ExceptionFrame,
573 PKTRAP_FRAME TrapFrame)
574 {
575 /* Start with the basic Registers */
576 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
577 {
578 TrapFrame->Esp = Context->Esp;
579 TrapFrame->Ss = Context->SegSs;
580 TrapFrame->Cs = Context->SegCs;
581 TrapFrame->Eip = Context->Eip;
582 TrapFrame->Eflags = Context->EFlags;
583 TrapFrame->Ebp = Context->Ebp;
584 }
585
586 /* Process the Integer Registers */
587 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
588 {
589 TrapFrame->Eax = Context->Eax;
590 TrapFrame->Ebx = Context->Ebx;
591 TrapFrame->Ecx = Context->Ecx;
592 TrapFrame->Edx = Context->Edx;
593 TrapFrame->Esi = Context->Esi;
594 TrapFrame->Edi = Context->Edi;
595 }
596
597 /* Process the Context Segments */
598 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
599 {
600 TrapFrame->Ds = Context->SegDs;
601 TrapFrame->Es = Context->SegEs;
602 TrapFrame->Fs = Context->SegFs;
603 TrapFrame->Gs = Context->SegGs;
604 }
605
606 /* Handle the Debug Registers */
607 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
608 {
609 TrapFrame->Dr0 = Context->Dr0;
610 TrapFrame->Dr1 = Context->Dr1;
611 TrapFrame->Dr2 = Context->Dr2;
612 TrapFrame->Dr3 = Context->Dr3;
613 TrapFrame->Dr6 = Context->Dr6;
614 TrapFrame->Dr7 = Context->Dr7;
615 }
616
617 /* Handle FPU and Extended Registers */
618 return KiContextToFxSaveArea((PFX_SAVE_AREA)(TrapFrame + 1), Context);
619 }
620
621 VOID
622 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
623 PCONTEXT Context)
624 {
625 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
626 {
627 Context->SegSs = TrapFrame->Ss;
628 Context->Esp = TrapFrame->Esp;
629 Context->SegCs = TrapFrame->Cs;
630 Context->Eip = TrapFrame->Eip;
631 Context->EFlags = TrapFrame->Eflags;
632 Context->Ebp = TrapFrame->Ebp;
633 }
634 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
635 {
636 Context->Eax = TrapFrame->Eax;
637 Context->Ebx = TrapFrame->Ebx;
638 Context->Ecx = TrapFrame->Ecx;
639 /*
640 * NOTE: In the trap frame which is built on entry to a system
641 * call TrapFrame->Edx will actually hold the address of the
642 * previous TrapFrame. I don't believe leaking this information
643 * has security implications. Also EDX holds the address of the
644 * arguments to the system call in progress so it isn't of much
645 * interest to the debugger.
646 */
647 Context->Edx = TrapFrame->Edx;
648 Context->Esi = TrapFrame->Esi;
649 Context->Edi = TrapFrame->Edi;
650 }
651 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
652 {
653 Context->SegDs = TrapFrame->Ds;
654 Context->SegEs = TrapFrame->Es;
655 Context->SegFs = TrapFrame->Fs;
656 Context->SegGs = TrapFrame->Gs;
657 }
658 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
659 {
660 /*
661 * FIXME: Implement this case
662 */
663 Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
664 }
665 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
666 {
667 /*
668 * FIXME: Implement this case
669 *
670 * I think this should only be filled for FPU exceptions, otherwise I
671 * would not know where to get it from as it can be the current state
672 * of the FPU or already saved in the thread's FPU save area.
673 * -blight
674 */
675 Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
676 }
677 #if 0
678 if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
679 {
680 /*
681 * FIXME: Investigate this
682 *
683 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
684 * This should only be filled in case of a SIMD exception I think, so
685 * this is not the right place (like for FPU the state could already be
686 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
687 * -blight
688 */
689 Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS;
690 }
691 #endif
692 }
693
694 VOID
695 KeDumpStackFrames(PULONG Frame)
696 {
697 PULONG StackBase, StackEnd;
698 MEMORY_BASIC_INFORMATION mbi;
699 ULONG ResultLength = sizeof(mbi);
700 NTSTATUS Status;
701
702 DbgPrint("Frames:\n");
703 _SEH_TRY
704 {
705 Status = MiQueryVirtualMemory (
706 (HANDLE)-1,
707 Frame,
708 MemoryBasicInformation,
709 &mbi,
710 sizeof(mbi),
711 &ResultLength );
712 if ( !NT_SUCCESS(Status) )
713 {
714 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
715 return;
716 }
717
718 StackBase = Frame;
719 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
720
721 while ( Frame >= StackBase && Frame < StackEnd )
722 {
723 ULONG Addr = Frame[1];
724 if (!KeRosPrintAddress((PVOID)Addr))
725 DbgPrint("<%X>", Addr);
726 if ( Addr == 0 || Addr == 0xDEADBEEF )
727 break;
728 StackBase = Frame;
729 Frame = (PULONG)Frame[0];
730 DbgPrint("\n");
731 }
732 }
733 _SEH_HANDLE
734 {
735 }
736 _SEH_END;
737 DbgPrint("\n");
738 }
739
740 VOID STDCALL
741 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
742 {
743 ULONG i=0;
744 PULONG StackBase, StackEnd;
745 MEMORY_BASIC_INFORMATION mbi;
746 ULONG ResultLength = sizeof(mbi);
747 NTSTATUS Status;
748
749 DbgPrint("Frames: ");
750 _SEH_TRY
751 {
752 if ( !Frame )
753 {
754 #if defined __GNUC__
755 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
756 #elif defined(_MSC_VER)
757 __asm mov [Frame], ebp
758 #endif
759 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
760 }
761
762 Status = MiQueryVirtualMemory (
763 (HANDLE)-1,
764 Frame,
765 MemoryBasicInformation,
766 &mbi,
767 sizeof(mbi),
768 &ResultLength );
769 if ( !NT_SUCCESS(Status) )
770 {
771 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
772 return;
773 }
774
775 StackBase = Frame;
776 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
777
778 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
779 {
780 ULONG Addr = Frame[1];
781 if (!KeRosPrintAddress((PVOID)Addr))
782 DbgPrint("<%X>", Addr);
783 if ( Addr == 0 || Addr == 0xDEADBEEF )
784 break;
785 StackBase = Frame;
786 Frame = (PULONG)Frame[0];
787 DbgPrint(" ");
788 }
789 }
790 _SEH_HANDLE
791 {
792 }
793 _SEH_END;
794 DbgPrint("\n");
795 }
796
797 ULONG STDCALL
798 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
799 {
800 ULONG Count = 0;
801 PULONG StackBase, StackEnd, Frame;
802 MEMORY_BASIC_INFORMATION mbi;
803 ULONG ResultLength = sizeof(mbi);
804 NTSTATUS Status;
805
806 _SEH_TRY
807 {
808 #if defined __GNUC__
809 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
810 #elif defined(_MSC_VER)
811 __asm mov [Frame], ebp
812 #endif
813
814 Status = MiQueryVirtualMemory (
815 (HANDLE)-1,
816 Frame,
817 MemoryBasicInformation,
818 &mbi,
819 sizeof(mbi),
820 &ResultLength );
821 if ( !NT_SUCCESS(Status) )
822 {
823 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
824 return 0;
825 }
826
827 StackBase = Frame;
828 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
829
830 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
831 {
832 Frames[Count++] = Frame[1];
833 StackBase = Frame;
834 Frame = (PULONG)Frame[0];
835 }
836 }
837 _SEH_HANDLE
838 {
839 }
840 _SEH_END;
841 return Count;
842 }
843
844 static void
845 set_system_call_gate(unsigned int sel, unsigned int func)
846 {
847 DPRINT("sel %x %d\n",sel,sel);
848 KiIdt[sel].a = (((int)func)&0xffff) +
849 (KERNEL_CS << 16);
850 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
851 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
852 }
853
854 static void set_interrupt_gate(unsigned int sel, unsigned int func)
855 {
856 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
857 KiIdt[sel].a = (((int)func)&0xffff) +
858 (KERNEL_CS << 16);
859 KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
860 }
861
862 static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
863 {
864 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
865 ASSERT(dpl <= 3);
866 KiIdt[sel].a = (((int)func)&0xffff) +
867 (KERNEL_CS << 16);
868 KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
869 }
870
871 static void
872 set_task_gate(unsigned int sel, unsigned task_sel)
873 {
874 KiIdt[sel].a = task_sel << 16;
875 KiIdt[sel].b = 0x8500;
876 }
877
878 VOID INIT_FUNCTION
879 KeInitExceptions(VOID)
880 /*
881 * FUNCTION: Initalize CPU exception handling
882 */
883 {
884 int i;
885
886 DPRINT("KeInitExceptions()\n");
887
888 /*
889 * Set up the other gates
890 */
891 set_trap_gate(0, (ULONG)KiTrap0, 0);
892 set_trap_gate(1, (ULONG)KiTrap1, 0);
893 set_trap_gate(2, (ULONG)KiTrap2, 0);
894 set_trap_gate(3, (ULONG)KiTrap3, 3);
895 set_trap_gate(4, (ULONG)KiTrap4, 0);
896 set_trap_gate(5, (ULONG)KiTrap5, 0);
897 set_trap_gate(6, (ULONG)KiTrap6, 0);
898 set_trap_gate(7, (ULONG)KiTrap7, 0);
899 set_task_gate(8, TRAP_TSS_SELECTOR);
900 set_trap_gate(9, (ULONG)KiTrap9, 0);
901 set_trap_gate(10, (ULONG)KiTrap10, 0);
902 set_trap_gate(11, (ULONG)KiTrap11, 0);
903 set_trap_gate(12, (ULONG)KiTrap12, 0);
904 set_trap_gate(13, (ULONG)KiTrap13, 0);
905 set_interrupt_gate(14, (ULONG)KiTrap14);
906 set_trap_gate(15, (ULONG)KiTrap15, 0);
907 set_trap_gate(16, (ULONG)KiTrap16, 0);
908 set_trap_gate(17, (ULONG)KiTrap17, 0);
909 set_trap_gate(18, (ULONG)KiTrap18, 0);
910 set_trap_gate(19, (ULONG)KiTrap19, 0);
911
912 for (i = 20; i < 256; i++)
913 {
914 set_trap_gate(i,(int)KiTrapUnknown, 0);
915 }
916
917 set_system_call_gate(0x2d,(int)KiDebugService);
918 set_system_call_gate(0x2e,(int)KiSystemService);
919 }
920
921 VOID
922 NTAPI
923 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
924 PKEXCEPTION_FRAME ExceptionFrame,
925 PKTRAP_FRAME TrapFrame,
926 KPROCESSOR_MODE PreviousMode,
927 BOOLEAN FirstChance)
928 {
929 CONTEXT Context;
930 KD_CONTINUE_TYPE Action;
931 ULONG_PTR Stack, NewStack;
932 ULONG Size;
933 BOOLEAN UserDispatch = FALSE;
934 DPRINT1("KiDispatchException() called\n");
935
936 /* Increase number of Exception Dispatches */
937 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
938
939 /* Set the context flags */
940 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
941
942 /* Check if User Mode */
943 if (PreviousMode == UserMode)
944 {
945 /* Add the FPU Flag */
946 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
947 }
948
949 /* Get a Context */
950 KeTrapFrameToContext(TrapFrame, &Context);
951
952 /* Handle kernel-mode first, it's simpler */
953 if (PreviousMode == KernelMode)
954 {
955 /* Check if this is a first-chance exception */
956 if (FirstChance == TRUE)
957 {
958 /* Break into the debugger for the first time */
959 Action = KdpEnterDebuggerException(ExceptionRecord,
960 PreviousMode,
961 &Context,
962 TrapFrame,
963 TRUE,
964 TRUE);
965
966 /* If the debugger said continue, then continue */
967 if (Action == kdContinue) goto Handled;
968
969 /* If the Debugger couldn't handle it, dispatch the exception */
970 if (RtlDispatchException(ExceptionRecord, &Context))
971 {
972 /* It was handled by an exception handler, continue */
973 goto Handled;
974 }
975 }
976
977 /* This is a second-chance exception, only for the debugger */
978 Action = KdpEnterDebuggerException(ExceptionRecord,
979 PreviousMode,
980 &Context,
981 TrapFrame,
982 FALSE,
983 FALSE);
984
985 /* If the debugger said continue, then continue */
986 if (Action == kdContinue) goto Handled;
987
988 /* Third strike; you're out */
989 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
990 ExceptionRecord->ExceptionCode,
991 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
992 ExceptionRecord->ExceptionInformation[0],
993 ExceptionRecord->ExceptionInformation[1],
994 TrapFrame);
995 }
996 else
997 {
998 /* User mode exception, was it first-chance? */
999 if (FirstChance)
1000 {
1001 /* Enter Debugger if available */
1002 Action = KdpEnterDebuggerException(ExceptionRecord,
1003 PreviousMode,
1004 &Context,
1005 TrapFrame,
1006 TRUE,
1007 FALSE);
1008
1009 /* Exit if we're continuing */
1010 if (Action == kdContinue) goto Handled;
1011
1012 /* FIXME: Forward exception to user mode debugger */
1013
1014 /* Set up the user-stack */
1015 _SEH_TRY
1016 {
1017 /* Align context size and get stack pointer */
1018 Size = (sizeof(CONTEXT) + 3) & ~3;
1019 Stack = (Context.Esp & ~3) - Size;
1020 DPRINT1("Stack: %lx\n", Stack);
1021
1022 /* Probe stack and copy Context */
1023 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
1024 RtlMoveMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
1025
1026 /* Align exception record size and get stack pointer */
1027 Size = (sizeof(EXCEPTION_RECORD) -
1028 (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) *
1029 sizeof(ULONG) + 3) & ~3;
1030 NewStack = Stack - Size;
1031 DPRINT1("NewStack: %lx\n", NewStack);
1032
1033 /* Probe stack and copy exception record. Don't forget to add the two params */
1034 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
1035 Size + 2 * sizeof(ULONG_PTR),
1036 sizeof(ULONG));
1037 RtlMoveMemory((PVOID)NewStack, ExceptionRecord, Size);
1038
1039 /* Now write the two params for the user-mode dispatcher */
1040 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
1041 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
1042
1043 /* Set new Stack Pointer */
1044 TrapFrame->Esp = NewStack - 2 * sizeof(ULONG_PTR);
1045
1046 /* Set EIP to the User-mode Dispathcer */
1047 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
1048 UserDispatch = TRUE;
1049 _SEH_LEAVE;
1050 }
1051 _SEH_HANDLE
1052 {
1053 /* Do second-chance */
1054 }
1055 _SEH_END;
1056 }
1057
1058 /* If we dispatch to user, return now */
1059 if (UserDispatch) return;
1060
1061 /* FIXME: Forward the exception to the debugger for 2nd chance */
1062
1063 /* 3rd strike, kill the thread */
1064 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1065 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
1066 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
1067 ExceptionRecord->ExceptionCode,
1068 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1069 ExceptionRecord->ExceptionInformation[0],
1070 ExceptionRecord->ExceptionInformation[1],
1071 TrapFrame);
1072 }
1073
1074 Handled:
1075 /* Convert the context back into Trap/Exception Frames */
1076 KeContextToTrapFrame(&Context, NULL, TrapFrame);
1077 return;
1078 }
1079
1080 /*
1081 * @implemented
1082 */
1083 NTSTATUS STDCALL
1084 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1085 {
1086 ULONG OldEip;
1087 PKTHREAD Thread = KeGetCurrentThread();
1088
1089 _SEH_TRY {
1090 Thread->Teb->ExceptionCode = ExceptionCode;
1091 } _SEH_HANDLE {
1092 return(ExceptionCode);
1093 } _SEH_END;
1094
1095 OldEip = Thread->TrapFrame->Eip;
1096 Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1097 return((NTSTATUS)OldEip);
1098 }
1099