- Use static IDT entries generated through a macro, instead of dynamically allocating...
[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: Exception Support Code
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gregor Anich
8 * David Welch (welch@cwcom.net)
9 * Skywing (skywing@valhallalegends.com)
10 */
11
12 /*
13 * FIXMES:
14 * - Clean up file (remove all stack functions and use RtlWalkFrameChain/RtlCaptureStackBacktrace)
15 * - Sanitize some context fields.
16 * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
17 * - Forward exceptions to user-mode debugger.
18 */
19
20 /* INCLUDES *****************************************************************/
21
22 #include <ntoskrnl.h>
23
24 #define NDEBUG
25 #include <internal/debug.h>
26
27 #if defined (ALLOC_PRAGMA)
28 #pragma alloc_text(INIT, KeInitExceptions)
29 #endif
30
31 VOID
32 NTAPI
33 Ki386AdjustEsp0(
34 IN PKTRAP_FRAME TrapFrame
35 );
36
37 extern KIDTENTRY KiIdt[];
38
39 /* GLOBALS *****************************************************************/
40
41 #define FLAG_IF (1<<9)
42
43 #define _STR(x) #x
44 #define STR(x) _STR(x)
45
46 #ifndef ARRAY_SIZE
47 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
48 #endif
49
50 extern ULONG init_stack;
51 extern ULONG init_stack_top;
52
53 extern BOOLEAN Ke386NoExecute;
54
55 static char *ExceptionTypeStrings[] =
56 {
57 "Divide Error",
58 "Debug Trap",
59 "NMI",
60 "Breakpoint",
61 "Overflow",
62 "BOUND range exceeded",
63 "Invalid Opcode",
64 "No Math Coprocessor",
65 "Double Fault",
66 "Unknown(9)",
67 "Invalid TSS",
68 "Segment Not Present",
69 "Stack Segment Fault",
70 "General Protection",
71 "Page Fault",
72 "Reserved(15)",
73 "Math Fault",
74 "Alignment Check",
75 "Machine Check",
76 "SIMD Fault"
77 };
78
79 NTSTATUS ExceptionToNtStatus[] =
80 {
81 STATUS_INTEGER_DIVIDE_BY_ZERO,
82 STATUS_SINGLE_STEP,
83 STATUS_ACCESS_VIOLATION,
84 STATUS_BREAKPOINT,
85 STATUS_INTEGER_OVERFLOW,
86 STATUS_ARRAY_BOUNDS_EXCEEDED,
87 STATUS_ILLEGAL_INSTRUCTION,
88 STATUS_FLOAT_INVALID_OPERATION,
89 STATUS_ACCESS_VIOLATION,
90 STATUS_ACCESS_VIOLATION,
91 STATUS_ACCESS_VIOLATION,
92 STATUS_ACCESS_VIOLATION,
93 STATUS_STACK_OVERFLOW,
94 STATUS_ACCESS_VIOLATION,
95 STATUS_ACCESS_VIOLATION,
96 STATUS_ACCESS_VIOLATION, /* RESERVED */
97 STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
98 STATUS_DATATYPE_MISALIGNMENT,
99 STATUS_ACCESS_VIOLATION,
100 STATUS_FLOAT_MULTIPLE_TRAPS,
101 };
102
103 /* FUNCTIONS ****************************************************************/
104
105 BOOLEAN STDCALL
106 KiRosPrintAddress(PVOID address)
107 {
108 PLIST_ENTRY current_entry;
109 PLDR_DATA_TABLE_ENTRY current;
110 extern LIST_ENTRY ModuleListHead;
111 ULONG_PTR RelativeAddress;
112 ULONG i = 0;
113
114 do
115 {
116 current_entry = ModuleListHead.Flink;
117
118 while (current_entry != &ModuleListHead)
119 {
120 current =
121 CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
122
123 if (address >= (PVOID)current->DllBase &&
124 address < (PVOID)((ULONG_PTR)current->DllBase + current->SizeOfImage))
125 {
126 RelativeAddress = (ULONG_PTR) address - (ULONG_PTR) current->DllBase;
127 DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
128 return(TRUE);
129 }
130 current_entry = current_entry->Flink;
131 }
132
133 address = (PVOID)((ULONG_PTR)address & ~(ULONG_PTR)MmSystemRangeStart);
134 } while(++i <= 1);
135
136 return(FALSE);
137 }
138
139 ULONG
140 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
141 {
142 EXCEPTION_RECORD Er;
143
144 Er.ExceptionFlags = 0;
145 Er.ExceptionRecord = NULL;
146 Er.ExceptionAddress = (PVOID)Tf->Eip;
147
148 if (ExceptionNr == 14)
149 {
150 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
151 Er.NumberParameters = 2;
152 Er.ExceptionInformation[0] = Tf->ErrCode & 0x1;
153 Er.ExceptionInformation[1] = (ULONG)Cr2;
154 }
155 else
156 {
157 if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
158 {
159 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
160 }
161 else
162 {
163 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
164 }
165 Er.NumberParameters = 0;
166 }
167
168 /* FIXME: Which exceptions are noncontinuable? */
169 Er.ExceptionFlags = 0;
170
171 KiDispatchException(&Er, NULL, Tf, KernelMode, TRUE);
172
173 return(0);
174 }
175
176 VOID
177 KiDoubleFaultHandler(VOID)
178 {
179 #if 0
180 unsigned int cr2;
181 ULONG StackLimit;
182 ULONG StackBase;
183 ULONG Esp0;
184 ULONG ExceptionNr = 8;
185 KTSS* OldTss;
186 PULONG Frame;
187 ULONG OldCr3;
188 #if 0
189 ULONG i, j;
190 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
191 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
192 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
193 ULONG TraceLength;
194 BOOLEAN FoundRepeat;
195 #endif
196
197 OldTss = KeGetCurrentKPCR()->TSS;
198 Esp0 = OldTss->Esp0;
199
200 /* Get CR2 */
201 cr2 = Ke386GetCr2();
202 if (PsGetCurrentThread() != NULL &&
203 PsGetCurrentThread()->ThreadsProcess != NULL)
204 {
205 OldCr3 = (ULONG)
206 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
207 }
208 else
209 {
210 OldCr3 = 0xBEADF0AL;
211 }
212
213 /*
214 * Check for stack underflow
215 */
216 if (PsGetCurrentThread() != NULL &&
217 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
218 {
219 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
220 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
221 ExceptionNr = 12;
222 }
223
224 /*
225 * Print out the CPU registers
226 */
227 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
228 {
229 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
230 ExceptionNr, 0);
231 }
232 else
233 {
234 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
235 }
236 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
237 KeRosPrintAddress((PVOID)OldTss->Eip);
238 DbgPrint("\n");
239 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
240 DbgPrint("Proc: %x ",PsGetCurrentProcess());
241 if (PsGetCurrentProcess() != NULL)
242 {
243 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
244 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
245 }
246 if (PsGetCurrentThread() != NULL)
247 {
248 DbgPrint("Thrd: %x Tid: %x",
249 PsGetCurrentThread(),
250 PsGetCurrentThread()->Cid.UniqueThread);
251 }
252 DbgPrint("\n");
253 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
254 OldTss->Fs, OldTss->Gs);
255 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
256 OldTss->Ecx);
257 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss->Edx,
258 OldTss->Ebp, OldTss->Esi, Esp0);
259 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
260 if (OldTss->Cs == KGDT_R0_CODE)
261 {
262 DbgPrint("kESP %.8x ", Esp0);
263 if (PsGetCurrentThread() != NULL)
264 {
265 DbgPrint("kernel stack base %x\n",
266 PsGetCurrentThread()->Tcb.StackLimit);
267
268 }
269 }
270 else
271 {
272 DbgPrint("User ESP %.8x\n", OldTss->Esp);
273 }
274 if ((OldTss->Cs & 0xffff) == KGDT_R0_CODE)
275 {
276 if (PsGetCurrentThread() != NULL)
277 {
278 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
279 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
280 }
281 else
282 {
283 StackLimit = (ULONG)init_stack_top;
284 StackBase = (ULONG)init_stack;
285 }
286
287 /*
288 Change to an #if 0 to reduce the amount of information printed on
289 a recursive stack trace.
290 */
291 #if 1
292 DbgPrint("Frames: ");
293 Frame = (PULONG)OldTss->Ebp;
294 while (Frame != NULL && (ULONG)Frame >= StackBase)
295 {
296 KeRosPrintAddress((PVOID)Frame[1]);
297 Frame = (PULONG)Frame[0];
298 DbgPrint("\n");
299 }
300 #else
301 DbgPrint("Frames: ");
302 i = 0;
303 Frame = (PULONG)OldTss->Ebp;
304 while (Frame != NULL && (ULONG)Frame >= StackBase)
305 {
306 StackTrace[i] = (PVOID)Frame[1];
307 Frame = (PULONG)Frame[0];
308 i++;
309 }
310 TraceLength = i;
311
312 i = 0;
313 while (i < TraceLength)
314 {
315 StackRepeatCount[i] = 0;
316 j = i + 1;
317 FoundRepeat = FALSE;
318 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
319 {
320 if (memcmp(&StackTrace[i], &StackTrace[j],
321 (j - i) * sizeof(PVOID)) == 0)
322 {
323 StackRepeatCount[i] = 2;
324 StackRepeatLength[i] = j - i;
325 FoundRepeat = TRUE;
326 }
327 else
328 {
329 j++;
330 }
331 }
332 if (FoundRepeat == FALSE)
333 {
334 i++;
335 continue;
336 }
337 j = j + StackRepeatLength[i];
338 while ((TraceLength - j) >= StackRepeatLength[i] &&
339 FoundRepeat == TRUE)
340 {
341 if (memcmp(&StackTrace[i], &StackTrace[j],
342 StackRepeatLength[i] * sizeof(PVOID)) == 0)
343 {
344 StackRepeatCount[i]++;
345 j = j + StackRepeatLength[i];
346 }
347 else
348 {
349 FoundRepeat = FALSE;
350 }
351 }
352 i = j;
353 }
354
355 i = 0;
356 while (i < TraceLength)
357 {
358 if (StackRepeatCount[i] == 0)
359 {
360 KeRosPrintAddress(StackTrace[i]);
361 i++;
362 }
363 else
364 {
365 DbgPrint("{");
366 if (StackRepeatLength[i] == 0)
367 {
368 for(;;);
369 }
370 for (j = 0; j < StackRepeatLength[i]; j++)
371 {
372 KeRosPrintAddress(StackTrace[i + j]);
373 }
374 DbgPrint("}*%d", StackRepeatCount[i]);
375 i = i + StackRepeatLength[i] * StackRepeatCount[i];
376 }
377 }
378 #endif
379 }
380 #endif
381 DbgPrint("\n");
382 for(;;);
383 }
384
385 VOID
386 NTAPI
387 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
388 {
389 ULONG cr3_;
390 ULONG StackLimit;
391 ULONG Esp0;
392 ULONG ExceptionNr = (ULONG)Tf->DbgArgMark;
393 ULONG cr2 = (ULONG)Tf->DbgArgPointer;
394
395 Esp0 = (ULONG)Tf;
396
397 /*
398 * Print out the CPU registers
399 */
400 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
401 {
402 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
403 ExceptionNr, Tf->ErrCode&0xffff);
404 }
405 else
406 {
407 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrCode&0xffff);
408 }
409 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
410 Tf->SegCs&0xffff, Tf->Eip);
411 KeRosPrintAddress((PVOID)Tf->Eip);
412 DbgPrint("\n");
413 Ke386GetPageTableDirectory(cr3_);
414 DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
415 DbgPrint("Proc: %x ",PsGetCurrentProcess());
416 if (PsGetCurrentProcess() != NULL)
417 {
418 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
419 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
420 }
421 if (PsGetCurrentThread() != NULL)
422 {
423 DbgPrint("Thrd: %x Tid: %x",
424 PsGetCurrentThread(),
425 PsGetCurrentThread()->Cid.UniqueThread);
426 }
427 DbgPrint("\n");
428 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->SegDs&0xffff, Tf->SegEs&0xffff,
429 Tf->SegFs&0xffff, Tf->SegGs&0xfff);
430 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
431 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
432 Tf->Ebp, Tf->Esi, Esp0);
433 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->EFlags);
434 if ((Tf->SegCs&0xffff) == KGDT_R0_CODE)
435 {
436 DbgPrint("kESP %.8x ", Esp0);
437 if (PsGetCurrentThread() != NULL)
438 {
439 DbgPrint("kernel stack base %x\n",
440 PsGetCurrentThread()->Tcb.StackLimit);
441
442 }
443 }
444
445 if (PsGetCurrentThread() != NULL)
446 {
447 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
448 }
449 else
450 {
451 StackLimit = (ULONG)init_stack_top;
452 }
453
454 /*
455 * Dump the stack frames
456 */
457 KeDumpStackFrames((PULONG)Tf->Ebp);
458 }
459
460 ULONG
461 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
462 /*
463 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
464 * message and halt the computer
465 * ARGUMENTS:
466 * Complete CPU context
467 */
468 {
469 ULONG_PTR cr2;
470 NTSTATUS Status;
471 ULONG Esp0;
472
473 ASSERT(ExceptionNr != 14);
474
475 /* Use the address of the trap frame as approximation to the ring0 esp */
476 Esp0 = (ULONG)&Tf->Eip;
477
478 /* Get CR2 */
479 cr2 = Ke386GetCr2();
480 Tf->DbgArgPointer = cr2;
481
482 /*
483 * If this was a V86 mode exception then handle it specially
484 */
485 if (Tf->EFlags & (1 << 17))
486 {
487 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->EFlags, Tf->Eip, ExceptionNr);
488 return(KeV86Exception(ExceptionNr, Tf, cr2));
489 }
490
491 /*
492 * Check for stack underflow, this may be obsolete
493 */
494 if (PsGetCurrentThread() != NULL &&
495 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
496 {
497 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
498 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit, Tf->Eip);
499 ExceptionNr = 12;
500 }
501
502 if (ExceptionNr == 15)
503 {
504 /*
505 * FIXME:
506 * This exception should never occur. The P6 has a bug, which does sometimes deliver
507 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
508 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
509 * sources. Linux does ignore this exception.
510 *
511 * Hartmut Birr
512 */
513 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
514 return(0);
515 }
516
517 /*
518 * Check for a breakpoint that was only for the attention of the debugger.
519 */
520 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
521 {
522 /*
523 EIP is already adjusted by the processor to point to the instruction
524 after the breakpoint.
525 */
526 return(0);
527 }
528
529 /*
530 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
531 */
532 if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
533 {
534 Status = KiHandleFpuFault(Tf, ExceptionNr);
535 if (NT_SUCCESS(Status))
536 {
537 return(0);
538 }
539 }
540
541 /*
542 * Handle user exceptions differently
543 */
544 if ((Tf->SegCs & 0xFFFF) == (KGDT_R3_CODE | RPL_MASK))
545 {
546 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
547 }
548 else
549 {
550 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
551 }
552 }
553
554 ULONG
555 NTAPI
556 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
557 {
558 /* Check if this is user-mode or V86 */
559 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & X86_EFLAGS_VM))
560 {
561 /* Return it directly */
562 return TrapFrame->HardwareEsp;
563 }
564 else
565 {
566 /* Edited frame */
567 if (!(TrapFrame->SegCs & FRAME_EDITED))
568 {
569 /* Return edited value */
570 return TrapFrame->TempEsp;
571 }
572 else
573 {
574 /* Virgin frame, calculate */
575 return (ULONG)&TrapFrame->HardwareEsp;
576 }
577 }
578 }
579
580 VOID
581 NTAPI
582 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
583 IN ULONG Esp)
584 {
585 ULONG Previous = KiEspFromTrapFrame(TrapFrame);
586
587 /* Check if this is user-mode or V86 */
588 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & X86_EFLAGS_VM))
589 {
590 /* Write it directly */
591 TrapFrame->HardwareEsp = Esp;
592 }
593 else
594 {
595 /* Don't allow ESP to be lowered, this is illegal */
596 if (Esp < Previous)
597 {
598 KeBugCheck(SET_OF_INVALID_CONTEXT);
599 }
600
601 /* Create an edit frame, check if it was alrady */
602 if (!(TrapFrame->SegCs & FRAME_EDITED))
603 {
604 /* Update the value */
605 TrapFrame->TempEsp = Esp;
606 }
607 else
608 {
609 /* Check if ESP changed */
610 if (Previous != Esp)
611 {
612 /* Save CS */
613 TrapFrame->TempSegCs = TrapFrame->SegCs;
614 TrapFrame->SegCs &= ~FRAME_EDITED;
615
616 /* Save ESP */
617 TrapFrame->TempEsp = Esp;
618 }
619 }
620 }
621 }
622
623 ULONG
624 NTAPI
625 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
626 {
627 /* If this was V86 Mode */
628 if (TrapFrame->EFlags & X86_EFLAGS_VM)
629 {
630 /* Just return it */
631 return TrapFrame->HardwareSegSs;
632 }
633 else if (TrapFrame->SegCs & MODE_MASK)
634 {
635 /* Usermode, return the User SS */
636 return TrapFrame->HardwareSegSs | RPL_MASK;
637 }
638 else
639 {
640 /* Kernel mode */
641 return KGDT_R0_DATA;
642 }
643 }
644
645 VOID
646 NTAPI
647 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
648 IN ULONG Ss)
649 {
650 /* Remove the high-bits */
651 Ss &= 0xFFFF;
652
653 /* If this was V86 Mode */
654 if (TrapFrame->EFlags & X86_EFLAGS_VM)
655 {
656 /* Just write it */
657 TrapFrame->HardwareSegSs = Ss;
658 }
659 else if (TrapFrame->SegCs & MODE_MASK)
660 {
661 /* Usermode, save the User SS */
662 TrapFrame->HardwareSegSs = Ss | RPL_MASK;
663 }
664 }
665
666 VOID
667 NTAPI
668 KeContextToTrapFrame(IN PCONTEXT Context,
669 IN OUT PKEXCEPTION_FRAME ExceptionFrame,
670 IN OUT PKTRAP_FRAME TrapFrame,
671 IN ULONG ContextFlags,
672 IN KPROCESSOR_MODE PreviousMode)
673 {
674 PFX_SAVE_AREA FxSaveArea;
675 //ULONG i; Future Use
676 BOOLEAN V86Switch = FALSE;
677
678 /* Start with the basic Registers */
679 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
680 {
681 /* Check if we went through a V86 switch */
682 if ((Context->EFlags & X86_EFLAGS_VM) !=
683 (TrapFrame->EFlags & X86_EFLAGS_VM))
684 {
685 /* We did, remember this for later */
686 V86Switch = TRUE;
687 }
688
689 /* Copy EFLAGS. FIXME: Needs to be sanitized */
690 TrapFrame->EFlags = Context->EFlags;
691
692 /* Copy EBP and EIP */
693 TrapFrame->Ebp = Context->Ebp;
694 TrapFrame->Eip = Context->Eip;
695
696 /* Check if we were in V86 Mode */
697 if (TrapFrame->EFlags & X86_EFLAGS_VM)
698 {
699 /* Simply copy the CS value */
700 TrapFrame->SegCs = Context->SegCs;
701 }
702 else
703 {
704 /* We weren't in V86, so sanitize the CS (FIXME!) */
705 TrapFrame->SegCs = Context->SegCs;
706
707 /* Don't let it under 8, that's invalid */
708 if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
709 {
710 /* Force it to User CS */
711 TrapFrame->SegCs = (KGDT_R3_CODE | RPL_MASK);
712 }
713 }
714
715 /* Handle SS Specially for validation */
716 KiSsToTrapFrame(TrapFrame, Context->SegSs);
717
718 /* Write ESP back; take into account Edited Trap Frames */
719 KiEspToTrapFrame(TrapFrame, Context->Esp);
720
721 /* Handle our V86 Bias if we went through a switch */
722 if (V86Switch) Ki386AdjustEsp0(TrapFrame);
723 }
724
725 /* Process the Integer Registers */
726 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
727 {
728 TrapFrame->Eax = Context->Eax;
729 TrapFrame->Ebx = Context->Ebx;
730 TrapFrame->Ecx = Context->Ecx;
731 TrapFrame->Edx = Context->Edx;
732 TrapFrame->Esi = Context->Esi;
733 TrapFrame->Edi = Context->Edi;
734 }
735
736 /* Process the Context Segments */
737 if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
738 {
739 /* Check if we were in V86 Mode */
740 if (TrapFrame->EFlags & X86_EFLAGS_VM)
741 {
742 /* Copy the V86 Segments directlry */
743 TrapFrame->V86Ds = Context->SegDs;
744 TrapFrame->V86Es = Context->SegEs;
745 TrapFrame->V86Fs = Context->SegFs;
746 TrapFrame->V86Gs = Context->SegGs;
747 }
748 else if (!(TrapFrame->SegCs & MODE_MASK))
749 {
750 /* For kernel mode, write the standard values */
751 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
752 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
753 TrapFrame->SegFs = Context->SegFs;
754 TrapFrame->SegGs = 0;
755 }
756 else
757 {
758 /* For user mode, return the values directlry */
759 TrapFrame->SegDs = Context->SegDs;
760 TrapFrame->SegEs = Context->SegEs;
761 TrapFrame->SegFs = Context->SegFs;
762
763 /* Handle GS specially */
764 if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
765 {
766 /* Don't use it, if user */
767 TrapFrame->SegGs = 0;
768 }
769 else
770 {
771 /* Copy it if kernel */
772 TrapFrame->SegGs = Context->SegGs;
773 }
774 }
775 }
776
777 /* Handle the extended registers */
778 if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
779 CONTEXT_EXTENDED_REGISTERS) &&
780 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
781 {
782 /* Get the FX Area */
783 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
784
785 /* Check if NPX is present */
786 if (KeI386NpxPresent)
787 {
788 /* Future use */
789 }
790 }
791
792 /* Handle the floating point state */
793 if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
794 CONTEXT_FLOATING_POINT) &&
795 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
796 {
797 /* Get the FX Area */
798 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
799
800 /* Check if NPX is present */
801 if (KeI386NpxPresent)
802 {
803 /* Future use */
804 }
805 else
806 {
807 /* Future use */
808 }
809 }
810
811 /* Handle the Debug Registers */
812 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
813 {
814 /* FIXME: All these should be sanitized */
815 TrapFrame->Dr0 = Context->Dr0;
816 TrapFrame->Dr1 = Context->Dr1;
817 TrapFrame->Dr2 = Context->Dr2;
818 TrapFrame->Dr3 = Context->Dr3;
819 TrapFrame->Dr6 = Context->Dr6;
820 TrapFrame->Dr7 = Context->Dr7;
821
822 /* Check if usermode */
823 if (PreviousMode != KernelMode)
824 {
825 /* Set the Debug Flag */
826 KeGetCurrentThread()->DispatcherHeader.DebugActive =
827 (Context->Dr7 & DR7_ACTIVE);
828 }
829 }
830
831 /* Handle FPU and Extended Registers */
832 KiContextToFxSaveArea((PFX_SAVE_AREA)(TrapFrame + 1), Context);
833 }
834
835 VOID
836 NTAPI
837 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
838 IN PKEXCEPTION_FRAME ExceptionFrame,
839 IN OUT PCONTEXT Context)
840 {
841 PFX_SAVE_AREA FxSaveArea = NULL;
842
843 /* Start with the Control flags */
844 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
845 {
846 /* EBP, EIP and EFLAGS */
847 Context->Ebp = TrapFrame->Ebp;
848 Context->Eip = TrapFrame->Eip;
849 Context->EFlags = TrapFrame->EFlags;
850
851 /* Return the correct CS */
852 if (!(TrapFrame->SegCs & FRAME_EDITED) &&
853 !(TrapFrame->EFlags & X86_EFLAGS_VM))
854 {
855 /* Get it from the Temp location */
856 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
857 }
858 else
859 {
860 /* Return it directly */
861 Context->SegCs = TrapFrame->SegCs & 0xFFFF;
862 }
863
864 /* Get the Ss and ESP */
865 Context->SegSs = KiSsFromTrapFrame(TrapFrame);
866 Context->Esp = KiEspFromTrapFrame(TrapFrame);
867 }
868
869 /* Handle the Segments */
870 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
871 {
872 /* Do V86 Mode first */
873 if (TrapFrame->EFlags & X86_EFLAGS_VM)
874 {
875 /* Return from the V86 location */
876 Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
877 Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
878 Context->SegEs = TrapFrame->V86Es & 0xFFFF;
879 Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
880 }
881 else
882 {
883 /* Check if this was a Kernel Trap */
884 if (TrapFrame->SegCs == KGDT_R0_CODE)
885 {
886 /* Set valid selectors */
887 TrapFrame->SegGs = 0;
888 TrapFrame->SegFs = KGDT_R0_PCR;
889 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
890 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
891 }
892
893 /* Return the segments */
894 Context->SegGs = TrapFrame->SegGs & 0xFFFF;
895 Context->SegFs = TrapFrame->SegFs & 0xFFFF;
896 Context->SegEs = TrapFrame->SegEs & 0xFFFF;
897 Context->SegDs = TrapFrame->SegDs & 0xFFFF;
898 }
899 }
900
901 /* Handle the simple registers */
902 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
903 {
904 /* Return them directly */
905 Context->Eax = TrapFrame->Eax;
906 Context->Ebx = TrapFrame->Ebx;
907 Context->Ecx = TrapFrame->Ecx;
908 Context->Edx = TrapFrame->Edx;
909 Context->Esi = TrapFrame->Esi;
910 Context->Edi = TrapFrame->Edi;
911 }
912
913 /* Handle extended registers */
914 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
915 CONTEXT_EXTENDED_REGISTERS) &&
916 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
917 {
918 /* Get the FX Save Area */
919 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
920
921 /* Make sure NPX is present */
922 if (KeI386NpxPresent)
923 {
924 /* Future use */
925 }
926
927 /* Old code */
928 FxSaveArea = KiGetFpuState(KeGetCurrentThread());
929 if (FxSaveArea != NULL)
930 {
931 memcpy(Context->ExtendedRegisters, &FxSaveArea->U.FxArea,
932 min(sizeof (Context->ExtendedRegisters), sizeof (FxSaveArea->U.FxArea)) );
933 }
934 else
935 {
936 Context->ContextFlags &= (~CONTEXT_EXTENDED_REGISTERS) | CONTEXT_i386;
937 }
938 }
939
940 /* Handle Floating Point */
941 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
942 CONTEXT_FLOATING_POINT) &&
943 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
944 {
945 /* Get the FX Save Area */
946 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
947
948 /* Make sure we have an NPX */
949 if (KeI386NpxPresent)
950 {
951 /* Future use */
952 }
953 else
954 {
955 /* Future Use */
956 }
957
958 /* Old code */
959 FxSaveArea = KiGetFpuState(KeGetCurrentThread());
960 if (FxSaveArea != NULL)
961 {
962 KiFxSaveAreaToFloatingSaveArea(&Context->FloatSave, FxSaveArea);
963 }
964 else
965 {
966 Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
967 }
968 }
969
970 /* Handle debug registers */
971 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
972 CONTEXT_DEBUG_REGISTERS)
973 {
974 /* Copy the debug registers */
975 Context->Dr0 = TrapFrame->Dr0;
976 Context->Dr1 = TrapFrame->Dr1;
977 Context->Dr2 = TrapFrame->Dr2;
978 Context->Dr3 = TrapFrame->Dr3;
979 Context->Dr6 = TrapFrame->Dr6;
980
981 /* For user-mode, only set DR7 if a debugger is active */
982 if (((TrapFrame->SegCs & MODE_MASK) ||
983 (TrapFrame->EFlags & EFLAGS_V86_MASK)) &&
984 (KeGetCurrentThread()->DispatcherHeader.DebugActive))
985 {
986 /* Copy it over */
987 Context->Dr7 = TrapFrame->Dr7;
988 }
989 else
990 {
991 /* Clear it */
992 Context->Dr7 = 0;
993 }
994 }
995 }
996
997 VOID
998 NTAPI
999 KeDumpStackFrames(PULONG Frame)
1000 {
1001 PULONG StackBase, StackEnd;
1002 MEMORY_BASIC_INFORMATION mbi;
1003 ULONG ResultLength = sizeof(mbi);
1004 NTSTATUS Status;
1005
1006 DbgPrint("Frames:\n");
1007 _SEH_TRY
1008 {
1009 Status = MiQueryVirtualMemory (
1010 (HANDLE)-1,
1011 Frame,
1012 MemoryBasicInformation,
1013 &mbi,
1014 sizeof(mbi),
1015 &ResultLength );
1016 if ( !NT_SUCCESS(Status) )
1017 {
1018 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1019 return;
1020 }
1021
1022 StackBase = Frame;
1023 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1024
1025 while ( Frame >= StackBase && Frame < StackEnd )
1026 {
1027 ULONG Addr = Frame[1];
1028 if (!KeRosPrintAddress((PVOID)Addr))
1029 DbgPrint("<%X>", Addr);
1030 if ( Addr == 0 || Addr == 0xDEADBEEF )
1031 break;
1032 StackBase = Frame;
1033 Frame = (PULONG)Frame[0];
1034 DbgPrint("\n");
1035 }
1036 }
1037 _SEH_HANDLE
1038 {
1039 }
1040 _SEH_END;
1041 DbgPrint("\n");
1042 }
1043
1044 VOID STDCALL
1045 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
1046 {
1047 ULONG i=0;
1048 PULONG StackBase, StackEnd;
1049 MEMORY_BASIC_INFORMATION mbi;
1050 ULONG ResultLength = sizeof(mbi);
1051 NTSTATUS Status;
1052
1053 DbgPrint("Frames: ");
1054 _SEH_TRY
1055 {
1056 if ( !Frame )
1057 {
1058 #if defined __GNUC__
1059 __asm__("mov %%ebp, %0" : "=r" (Frame) : );
1060 #elif defined(_MSC_VER)
1061 __asm mov [Frame], ebp
1062 #endif
1063 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
1064 }
1065
1066 Status = MiQueryVirtualMemory (
1067 (HANDLE)-1,
1068 Frame,
1069 MemoryBasicInformation,
1070 &mbi,
1071 sizeof(mbi),
1072 &ResultLength );
1073 if ( !NT_SUCCESS(Status) )
1074 {
1075 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1076 return;
1077 }
1078
1079 StackBase = Frame;
1080 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1081
1082 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
1083 {
1084 ULONG Addr = Frame[1];
1085 if (!KeRosPrintAddress((PVOID)Addr))
1086 DbgPrint("<%X>", Addr);
1087 if ( Addr == 0 || Addr == 0xDEADBEEF )
1088 break;
1089 StackBase = Frame;
1090 Frame = (PULONG)Frame[0];
1091 DbgPrint(" ");
1092 }
1093 }
1094 _SEH_HANDLE
1095 {
1096 }
1097 _SEH_END;
1098 DbgPrint("\n");
1099 }
1100
1101 ULONG STDCALL
1102 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
1103 {
1104 ULONG Count = 0;
1105 PULONG StackBase, StackEnd, Frame;
1106 MEMORY_BASIC_INFORMATION mbi;
1107 ULONG ResultLength = sizeof(mbi);
1108 NTSTATUS Status;
1109
1110 _SEH_TRY
1111 {
1112 #if defined __GNUC__
1113 __asm__("mov %%ebp, %0" : "=r" (Frame) : );
1114 #elif defined(_MSC_VER)
1115 __asm mov [Frame], ebp
1116 #endif
1117
1118 Status = MiQueryVirtualMemory (
1119 (HANDLE)-1,
1120 Frame,
1121 MemoryBasicInformation,
1122 &mbi,
1123 sizeof(mbi),
1124 &ResultLength );
1125 if ( !NT_SUCCESS(Status) )
1126 {
1127 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1128 return 0;
1129 }
1130
1131 StackBase = Frame;
1132 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1133
1134 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
1135 {
1136 Frames[Count++] = Frame[1];
1137 StackBase = Frame;
1138 Frame = (PULONG)Frame[0];
1139 }
1140 }
1141 _SEH_HANDLE
1142 {
1143 }
1144 _SEH_END;
1145 return Count;
1146 }
1147
1148 VOID
1149 INIT_FUNCTION
1150 NTAPI
1151 KeInitExceptions(VOID)
1152 {
1153 ULONG i;
1154 USHORT FlippedSelector;
1155
1156 /* Loop the IDT */
1157 for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
1158 {
1159 /* Save the current Selector */
1160 FlippedSelector = KiIdt[i].Selector;
1161
1162 /* Flip Selector and Extended Offset */
1163 KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
1164 KiIdt[i].ExtendedOffset = FlippedSelector;
1165 }
1166 }
1167
1168 VOID
1169 NTAPI
1170 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
1171 PKEXCEPTION_FRAME ExceptionFrame,
1172 PKTRAP_FRAME TrapFrame,
1173 KPROCESSOR_MODE PreviousMode,
1174 BOOLEAN FirstChance)
1175 {
1176 CONTEXT Context;
1177 KD_CONTINUE_TYPE Action;
1178 ULONG_PTR Stack, NewStack;
1179 ULONG Size;
1180 BOOLEAN UserDispatch = FALSE;
1181 DPRINT("KiDispatchException() called\n");
1182
1183 /* Increase number of Exception Dispatches */
1184 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
1185
1186 /* Set the context flags */
1187 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
1188
1189 /* Check if User Mode */
1190 if (PreviousMode == UserMode)
1191 {
1192 /* Add the FPU Flag */
1193 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
1194 if (KeI386FxsrPresent) Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
1195 }
1196
1197 /* Get a Context */
1198 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
1199
1200 /* Handle kernel-mode first, it's simpler */
1201 if (PreviousMode == KernelMode)
1202 {
1203 /* Check if this is a first-chance exception */
1204 if (FirstChance == TRUE)
1205 {
1206 /* Break into the debugger for the first time */
1207 Action = KdpEnterDebuggerException(ExceptionRecord,
1208 PreviousMode,
1209 &Context,
1210 TrapFrame,
1211 TRUE,
1212 TRUE);
1213
1214 /* If the debugger said continue, then continue */
1215 if (Action == kdContinue) goto Handled;
1216
1217 /* If the Debugger couldn't handle it, dispatch the exception */
1218 if (RtlDispatchException(ExceptionRecord, &Context))
1219 {
1220 /* It was handled by an exception handler, continue */
1221 goto Handled;
1222 }
1223 }
1224
1225 /* This is a second-chance exception, only for the debugger */
1226 Action = KdpEnterDebuggerException(ExceptionRecord,
1227 PreviousMode,
1228 &Context,
1229 TrapFrame,
1230 FALSE,
1231 FALSE);
1232
1233 /* If the debugger said continue, then continue */
1234 if (Action == kdContinue) goto Handled;
1235
1236 /* Third strike; you're out */
1237 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
1238 ExceptionRecord->ExceptionCode,
1239 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1240 ExceptionRecord->ExceptionInformation[0],
1241 ExceptionRecord->ExceptionInformation[1],
1242 TrapFrame);
1243 }
1244 else
1245 {
1246 /* User mode exception, was it first-chance? */
1247 if (FirstChance)
1248 {
1249 /* Enter Debugger if available */
1250 Action = KdpEnterDebuggerException(ExceptionRecord,
1251 PreviousMode,
1252 &Context,
1253 TrapFrame,
1254 TRUE,
1255 TRUE);
1256
1257 /* Exit if we're continuing */
1258 if (Action == kdContinue) goto Handled;
1259
1260 /* FIXME: Forward exception to user mode debugger */
1261
1262 /* Set up the user-stack */
1263 _SEH_TRY
1264 {
1265 /* Align context size and get stack pointer */
1266 Size = (sizeof(CONTEXT) + 3) & ~3;
1267 Stack = (Context.Esp & ~3) - Size;
1268 DPRINT("Stack: %lx\n", Stack);
1269
1270 /* Probe stack and copy Context */
1271 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
1272 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
1273
1274 /* Align exception record size and get stack pointer */
1275 Size = (sizeof(EXCEPTION_RECORD) -
1276 (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) *
1277 sizeof(ULONG) + 3) & ~3;
1278 NewStack = Stack - Size;
1279 DPRINT("NewStack: %lx\n", NewStack);
1280
1281 /* Probe stack and copy exception record. Don't forget to add the two params */
1282 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
1283 Size + 2 * sizeof(ULONG_PTR),
1284 sizeof(ULONG));
1285 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
1286
1287 /* Now write the two params for the user-mode dispatcher */
1288 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
1289 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
1290
1291 /* Set new Stack Pointer */
1292 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
1293
1294 /* Set EIP to the User-mode Dispathcer */
1295 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
1296 UserDispatch = TRUE;
1297 _SEH_LEAVE;
1298 }
1299 _SEH_HANDLE
1300 {
1301 /* Do second-chance */
1302 }
1303 _SEH_END;
1304 }
1305
1306 /* If we dispatch to user, return now */
1307 if (UserDispatch) return;
1308
1309 /* FIXME: Forward the exception to the debugger for 2nd chance */
1310
1311 /* 3rd strike, kill the thread */
1312 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1313 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
1314 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
1315 ExceptionRecord->ExceptionCode,
1316 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1317 ExceptionRecord->ExceptionInformation[0],
1318 ExceptionRecord->ExceptionInformation[1],
1319 TrapFrame);
1320 }
1321
1322 Handled:
1323 /* Convert the context back into Trap/Exception Frames */
1324 KeContextToTrapFrame(&Context,
1325 NULL,
1326 TrapFrame,
1327 Context.ContextFlags,
1328 PreviousMode);
1329 return;
1330 }
1331
1332 /*
1333 * @implemented
1334 */
1335 NTSTATUS
1336 NTAPI
1337 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1338 {
1339 ULONG OldEip;
1340 PKTHREAD Thread = KeGetCurrentThread();
1341
1342 /* Make sure we can access the TEB */
1343 _SEH_TRY
1344 {
1345 Thread->Teb->ExceptionCode = ExceptionCode;
1346 }
1347 _SEH_HANDLE
1348 {
1349 return(ExceptionCode);
1350 }
1351 _SEH_END;
1352
1353 /* Get the old EIP */
1354 OldEip = Thread->TrapFrame->Eip;
1355
1356 /* Change it to the user-mode dispatcher */
1357 Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1358
1359 /* Return the old EIP */
1360 return((NTSTATUS)OldEip);
1361 }
1362