Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

exceptn.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1993 IBM Corporation and Microsoft Corporation 00004 00005 Module Name: 00006 00007 exceptn.c 00008 00009 Abstract: 00010 00011 This module implements the code necessary to dispatch expections to the 00012 proper mode and invoke the exception dispatcher. 00013 00014 Author: 00015 00016 Rick Simpson 2-Aug-1993 00017 Adapted from MIPS version by David N. Cutler (davec) 3-Apr-1990 00018 00019 Environment: 00020 00021 Kernel mode only. 00022 00023 Revision History: 00024 00025 --*/ 00026 00027 #include "ki.h" 00028 #pragma hdrstop 00029 #define _KXPPC_C_HEADER_ 00030 #include "kxppc.h" 00031 00032 BOOLEAN 00033 KiEmulateDcbz ( 00034 IN OUT PEXCEPTION_RECORD ExceptionRecord, 00035 IN OUT PKEXCEPTION_FRAME ExceptionFrame, 00036 IN OUT PKTRAP_FRAME TrapFrame 00037 ); 00038 00039 // 00040 // Data misalignment exception (auto alignment fixup) control. 00041 // 00042 // If KiEnableAlignmentFaultExceptions is false, then no alignment 00043 // exceptions are raised and all misaligned user and kernel mode data 00044 // references are emulated. 00045 // 00046 // Otherwise if KiEnableAlignmentFaultExceptions is true, then the 00047 // current thread automatic alignment fixup enable determines whether 00048 // emulation is attempted in user mode. 00049 // 00050 // N.B. This default value may be reset from the Registry during init. 00051 // 00052 00053 ULONG KiEnableAlignmentFaultExceptions = TRUE; 00054 00055 // 00056 // Breakpoint is a trap word immediate with a TO field of all ones. 00057 // 00058 00059 #define BREAK_INST (TRAP_INSTR | TO_BREAKPOINT) 00060 00061 // 00062 // Define multiply overflow and divide by zero breakpoint instruction values. 00063 // 00064 00065 #define DIVIDE_BREAKPOINT (TRAP_INSTR | TO_DIVIDE_BY_ZERO) 00066 #define UDIVIDE_BREAKPOINT (TRAP_INSTR | TO_UNCONDITIONAL_DIVIDE_BY_ZERO) 00067 00068 // 00069 // Define external kernel breakpoint and breakin breakpoint instructions. 00070 // 00071 00072 #define KERNEL_BREAKPOINT_INSTRUCTION (BREAK_INSTR | DEBUG_STOP_BREAKPOINT) 00073 #define KDDEBUG_BREAKPOINT (BREAK_INSTR | BREAKIN_BREAKPOINT) 00074 00075 // 00076 // Define available hardware breakpoint register mask 00077 // 00078 ULONG KiBreakPoints; 00079 00080 VOID 00081 KeContextFromKframes ( 00082 IN PKTRAP_FRAME TrapFrame, 00083 IN PKEXCEPTION_FRAME ExceptionFrame, 00084 IN OUT PCONTEXT ContextFrame 00085 ) 00086 00087 /*++ 00088 00089 Routine Description: 00090 00091 This routine moves the selected contents of the specified trap and exception frames 00092 frames into the specified context frame according to the specified context 00093 flags. 00094 00095 Arguments: 00096 00097 TrapFrame - Supplies a pointer to a trap frame from which volatile context 00098 should be copied into the context record. 00099 00100 ExceptionFrame - Supplies a pointer to an exception frame from which context 00101 should be copied into the context record. 00102 00103 ContextFrame - Supplies a pointer to the context frame that receives the 00104 context copied from the trap and exception frames. 00105 00106 Return Value: 00107 00108 None. 00109 00110 --*/ 00111 00112 { 00113 00114 // 00115 // Set control information if specified. 00116 // 00117 00118 if ((ContextFrame->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { 00119 00120 // 00121 // Set machine state, instr address, link, count registers 00122 // 00123 00124 ContextFrame->Msr = TrapFrame->Msr; 00125 ContextFrame->Iar = TrapFrame->Iar; 00126 ContextFrame->Lr = TrapFrame->Lr; 00127 ContextFrame->Ctr = TrapFrame->Ctr; 00128 } 00129 00130 // 00131 // Set integer register contents if specified. 00132 // 00133 00134 if ((ContextFrame->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { 00135 00136 // 00137 // Volatile integer regs in trap frame are 0..12 00138 // 00139 00140 RtlMoveMemory (&ContextFrame->Gpr0, &TrapFrame->Gpr0, 00141 sizeof (ULONG) * 13); 00142 00143 // 00144 // Non-volatile integer regs in exception frame are 13..31 00145 // 00146 00147 RtlMoveMemory (&ContextFrame->Gpr13, &ExceptionFrame->Gpr13, 00148 sizeof (ULONG) * 19); 00149 00150 // 00151 // The CR is made up of volatile and non-volatile fields, 00152 // but the entire CR is saved in the trap frame 00153 // 00154 00155 ContextFrame->Cr = TrapFrame->Cr; 00156 00157 // 00158 // Fixed Point Exception Register (XER) is part of the 00159 // integer state 00160 // 00161 00162 ContextFrame->Xer = TrapFrame->Xer; 00163 } 00164 00165 // 00166 // Set floating register contents if specified. 00167 // 00168 00169 if ((ContextFrame->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { 00170 00171 // 00172 // Volatile floating point regs in trap frame are 0..13 00173 // 00174 00175 RtlMoveMemory(&ContextFrame->Fpr0, &TrapFrame->Fpr0, 00176 sizeof(DOUBLE) * (14)); 00177 00178 // 00179 // Non-volatile floating point regs in exception frame are 14..31 00180 // 00181 00182 RtlMoveMemory(&ContextFrame->Fpr14, &ExceptionFrame->Fpr14, 00183 sizeof(DOUBLE) * (18)); 00184 00185 // 00186 // Set floating point status and control register. 00187 // 00188 00189 ContextFrame->Fpscr = TrapFrame->Fpscr; 00190 } 00191 00192 // 00193 // Fetch Dr register contents if requested. Values may be trash. 00194 // 00195 00196 if ((ContextFrame->ContextFlags & CONTEXT_DEBUG_REGISTERS) == 00197 CONTEXT_DEBUG_REGISTERS) { 00198 00199 ContextFrame->Dr0 = TrapFrame->Dr0; 00200 ContextFrame->Dr1 = TrapFrame->Dr1; 00201 ContextFrame->Dr2 = TrapFrame->Dr2; 00202 ContextFrame->Dr3 = TrapFrame->Dr3; 00203 ContextFrame->Dr6 = TrapFrame->Dr6; 00204 ContextFrame->Dr6 |= KiBreakPoints; 00205 ContextFrame->Dr5 = 0; // Zero initialize unused regs 00206 ContextFrame->Dr4 = 0; 00207 00208 // 00209 // If it's a user mode frame, and the thread doesn't have DRs set, 00210 // and we just return the trash in the frame, we risk accidentally 00211 // making the thread active with trash values on a set. Therefore, 00212 // Dr7 must be set to the number of available data address breakpoint 00213 // registers if we get a non-active user mode frame. 00214 // 00215 00216 if (((TrapFrame->PreviousMode) != KernelMode) && 00217 (KeGetCurrentThread()->DebugActive)) { 00218 00219 ContextFrame->Dr7 = TrapFrame->Dr7; 00220 } else { 00221 00222 ContextFrame->Dr7 = 0; 00223 } 00224 } 00225 00226 return; 00227 } 00228 00229 VOID 00230 KeContextToKframes ( 00231 IN OUT PKTRAP_FRAME TrapFrame, 00232 IN OUT PKEXCEPTION_FRAME ExceptionFrame, 00233 IN PCONTEXT ContextFrame, 00234 IN ULONG ContextFlags, 00235 IN KPROCESSOR_MODE PreviousMode 00236 ) 00237 00238 /*++ 00239 00240 Routine Description: 00241 00242 This routine moves the selected contents of the specified context frame into 00243 the specified trap and exception frames according to the specified context 00244 flags. 00245 00246 Arguments: 00247 00248 TrapFrame - Supplies a pointer to a trap frame that receives the volatile 00249 context from the context record. 00250 00251 ExceptionFrame - Supplies a pointer to an exception frame that receives 00252 the nonvolatile context from the context record. 00253 00254 ContextFrame - Supplies a pointer to a context frame that contains the 00255 context that is to be copied into the trap and exception frames. 00256 00257 ContextFlags - Supplies the set of flags that specify which parts of the 00258 context frame are to be copied into the trap and exception frames. 00259 00260 PreviousMode - Supplies the processor mode for which the trap and exception 00261 frames are being built. 00262 00263 Return Value: 00264 00265 None. 00266 00267 --*/ 00268 00269 { 00270 00271 // 00272 // Set control information if specified. 00273 // 00274 00275 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { 00276 00277 // 00278 // Set instruction address, link, count, and machine state registers 00279 // 00280 00281 TrapFrame->Iar = ContextFrame->Iar; 00282 TrapFrame->Lr = ContextFrame->Lr; 00283 TrapFrame->Ctr = ContextFrame->Ctr; 00284 TrapFrame->Msr = SANITIZE_MSR(ContextFrame->Msr, PreviousMode); 00285 } 00286 00287 // 00288 // Set integer registers contents if specified. 00289 // 00290 00291 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { 00292 00293 // 00294 // Volatile integer regs are 0..12 00295 // 00296 00297 RtlMoveMemory(&TrapFrame->Gpr0, &ContextFrame->Gpr0, 00298 sizeof(ULONG) * (13)); 00299 00300 // 00301 // Non-volatile integer regs are 13..31 00302 // 00303 00304 RtlMoveMemory(&ExceptionFrame->Gpr13, &ContextFrame->Gpr13, 00305 sizeof(ULONG) * (19)); 00306 00307 // 00308 // Copy the Condition Reg and Fixed Point Exception Reg 00309 // 00310 00311 TrapFrame->Cr = ContextFrame->Cr; 00312 TrapFrame->Xer = ContextFrame->Xer; 00313 } 00314 00315 // 00316 // Set floating register contents if specified. 00317 // 00318 00319 if ((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { 00320 00321 // 00322 // Volatile floating point regs are 0..13 00323 // 00324 00325 RtlMoveMemory(&TrapFrame->Fpr0, &ContextFrame->Fpr0, 00326 sizeof(DOUBLE) * (14)); 00327 00328 // 00329 // Non-volatile floating point regs are 14..31 00330 // 00331 00332 RtlMoveMemory(&ExceptionFrame->Fpr14, &ContextFrame->Fpr14, 00333 sizeof(DOUBLE) * (18)); 00334 00335 // 00336 // Set floating point status and control register. 00337 // 00338 00339 TrapFrame->Fpscr = SANITIZE_FPSCR(ContextFrame->Fpscr, PreviousMode); 00340 } 00341 00342 // 00343 // Set debug register state if specified. If previous mode is user 00344 // mode (i.e. it's a user frame we're setting) and if effect will be to 00345 // cause at least one of the debug register enable bits in Dr7 00346 // to be set then set DebugActive to the enable bit mask. 00347 // 00348 00349 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) { 00350 00351 // 00352 // Set the debug control register for the 601 and 604 00353 // indicating the number of address breakpoints supported. 00354 // 00355 00356 TrapFrame->Dr0 = SANITIZE_DRADDR(ContextFrame->Dr0, PreviousMode); 00357 TrapFrame->Dr1 = SANITIZE_DRADDR(ContextFrame->Dr1, PreviousMode); 00358 TrapFrame->Dr2 = SANITIZE_DRADDR(ContextFrame->Dr2, PreviousMode); 00359 TrapFrame->Dr3 = SANITIZE_DRADDR(ContextFrame->Dr3, PreviousMode); 00360 TrapFrame->Dr6 = SANITIZE_DR6(ContextFrame->Dr6, PreviousMode); 00361 TrapFrame->Dr7 = SANITIZE_DR7(ContextFrame->Dr7, PreviousMode); 00362 00363 if (PreviousMode != KernelMode) { 00364 KeGetPcr()->DebugActive = KeGetCurrentThread()->DebugActive = 00365 (UCHAR)(TrapFrame->Dr7 & DR7_ACTIVE); 00366 } 00367 } 00368 00369 return; 00370 } 00371 00372 VOID 00373 KiDispatchException ( 00374 IN PEXCEPTION_RECORD ExceptionRecord, 00375 IN PKEXCEPTION_FRAME ExceptionFrame, 00376 IN PKTRAP_FRAME TrapFrame, 00377 IN KPROCESSOR_MODE PreviousMode, 00378 IN BOOLEAN FirstChance 00379 ) 00380 00381 /*++ 00382 00383 Routine Description: 00384 00385 This function is called to dispatch an exception to the proper mode and 00386 to cause the exception dispatcher to be called. 00387 00388 If the exception is a data misalignment, this is the first chance for 00389 handling the exception, and the current thread has enabled automatic 00390 alignment fixup, then an attempt is made to emulate the unaligned 00391 reference. 00392 00393 If the exception is a floating exception (N.B. the pseudo status 00394 STATUS_FLOAT_STACK_CHECK is used to signify this), we convert the 00395 exception code to the correct STATUS based on the FPSCR. 00396 It is up to the handler to figure out what to do to emulate/repair 00397 the operation. 00398 00399 If the exception is neither a data misalignment nor a floating point 00400 exception and the the previous mode is kernel, then the exception 00401 dispatcher is called directly to process the exception. Otherwise the 00402 exception record, exception frame, and trap frame contents are copied 00403 to the user mode stack. The contents of the exception frame and trap 00404 are then modified such that when control is returned, execution will 00405 commence in user mode in a routine which will call the exception 00406 dispatcher. 00407 00408 Arguments: 00409 00410 ExceptionRecord - Supplies a pointer to an exception record. 00411 00412 ExceptionFrame - Supplies a pointer to an exception frame. 00413 00414 TrapFrame - Supplies a pointer to a trap frame. 00415 00416 PreviousMode - Supplies the previous processor mode. 00417 00418 FirstChance - Supplies a boolean variable that specifies whether this 00419 is the first (TRUE) or second (FALSE) time that this exception has 00420 been processed. 00421 00422 Return Value: 00423 00424 None. 00425 00426 --*/ 00427 00428 { 00429 00430 CONTEXT ContextFrame; 00431 EXCEPTION_RECORD ExceptionRecord1; 00432 LONG Length; 00433 BOOLEAN UserApcPending; 00434 00435 // 00436 // If the exception is a data misalignment, this is the first chance for 00437 // handling the exception, and the current thread has enabled automatic 00438 // alignment fixup, then attempt to emulate the unaligned reference. 00439 // 00440 // We always emulate dcbz, even if the thread hasn't enabled automatic 00441 // alignment fixup. This is because the hardware declares an alignment 00442 // fault if dcbz is attempted on noncached memory. 00443 // 00444 00445 if (ExceptionRecord->ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) { 00446 if (FirstChance != FALSE) { 00447 00448 // 00449 // If alignment fault exceptions are not enabled, then no exception 00450 // should be raised and the data reference should be emulated. 00451 // 00452 00453 if ((KiEnableAlignmentFaultExceptions == FALSE) || 00454 (KeGetCurrentThread()->AutoAlignment != FALSE) || 00455 (KeGetCurrentThread()->ApcState.Process->AutoAlignment != FALSE)) { 00456 if (KiEmulateReference(ExceptionRecord, ExceptionFrame, TrapFrame) != FALSE) { 00457 KeGetCurrentPrcb()->KeAlignmentFixupCount += 1; 00458 goto Handled2; 00459 } 00460 } else { 00461 if (KiEmulateDcbz(ExceptionRecord, ExceptionFrame, TrapFrame) != FALSE) { 00462 KeGetCurrentPrcb()->KeAlignmentFixupCount += 1; 00463 goto Handled2; 00464 } 00465 } 00466 } 00467 } 00468 00469 // 00470 // If the exception is a breakpoint, then translate it to an appropriate 00471 // exception code if it is a division by zero or an integer overflow 00472 // caused by multiplication. 00473 // 00474 00475 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) { 00476 00477 ULONG Instr = ExceptionRecord->ExceptionInformation[0]; 00478 00479 if ((Instr & 0xffe0ffff) == DIVIDE_BREAKPOINT || 00480 (Instr & 0xffe0ffff) == UDIVIDE_BREAKPOINT) { 00481 ExceptionRecord->ExceptionCode = STATUS_INTEGER_DIVIDE_BY_ZERO; 00482 } else if (Instr == KDDEBUG_BREAKPOINT) { 00483 TrapFrame->Iar += 4; 00484 } 00485 } 00486 00487 // 00488 // If the exception is a floating point exception, then the 00489 // ExceptionCode was set to STATUS_FLOAT_STACK_CHECK. We now sort 00490 // that out and set a more correct STATUS code. We clear the 00491 // exception enable bit in the FPSCR of the exception being reported 00492 // to eliminate floating point exception recursion. 00493 // 00494 00495 if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_STACK_CHECK) { 00496 00497 PFPSCR Fpscr = (PFPSCR)(&TrapFrame->Fpscr); 00498 00499 if ((Fpscr->XE == 1) && (Fpscr->XX == 1)) { 00500 00501 ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT; 00502 Fpscr->XE = 0; 00503 00504 } 00505 else if ((Fpscr->ZE == 1) && (Fpscr->ZX == 1)) { 00506 00507 ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO; 00508 Fpscr->ZE = 0; 00509 00510 } 00511 else if ((Fpscr->UE == 1) && (Fpscr->UX == 1)) { 00512 00513 ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW; 00514 Fpscr->UE = 0; 00515 00516 } 00517 00518 else if ((Fpscr->OE == 1) && (Fpscr->OX == 1)) { 00519 00520 ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW; 00521 Fpscr->OE = 0; 00522 00523 } 00524 else { 00525 00526 // Must be some form of Invalid Operation 00527 00528 ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION; 00529 Fpscr->VE = 0; 00530 } 00531 } 00532 00533 // 00534 // Move machine state from trap and exception frames to a context frame, 00535 // and increment the number of exceptions dispatched. 00536 // 00537 00538 ContextFrame.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 00539 KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame); 00540 KeGetCurrentPrcb()->KeExceptionDispatchCount += 1; 00541 00542 // 00543 // Select the method of handling the exception based on the previous mode. 00544 // 00545 00546 if (PreviousMode == KernelMode) { 00547 00548 // 00549 // Previous mode was kernel. 00550 // 00551 // If this is the first chance, the kernel debugger is active, and 00552 // the exception is a kernel breakpoint, then give the kernel debugger 00553 // a chance to handle the exception. 00554 // 00555 // If this is the first chance and the kernel debugger is not active 00556 // or does not handle the exception, then attempt to find a frame 00557 // handler to handle the exception. 00558 // 00559 // If this is the second chance or the exception is not handled, then 00560 // if the kernel debugger is active, then give the kernel debugger a 00561 // second chance to handle the exception. If the kernel debugger does 00562 // not handle the exception, then bug check. 00563 // 00564 00565 if (FirstChance != FALSE) { 00566 00567 // 00568 // If the kernel debugger is active, the exception is a breakpoint, 00569 // and the breakpoint is handled by the kernel debugger, then give 00570 // the kernel debugger a chance to handle the exception. 00571 // 00572 00573 if ((KiDebugRoutine != NULL) && 00574 ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) || 00575 (ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)) && 00576 (KdIsThisAKdTrap(ExceptionRecord, 00577 &ContextFrame, 00578 KernelMode) != FALSE)) { 00579 00580 if (((KiDebugRoutine) (TrapFrame, 00581 ExceptionFrame, 00582 ExceptionRecord, 00583 &ContextFrame, 00584 KernelMode, 00585 FALSE)) != FALSE) { 00586 00587 goto Handled1; 00588 } 00589 } 00590 00591 // 00592 // This is the first chance to handle the exception. 00593 // 00594 00595 if (RtlDispatchException(ExceptionRecord, &ContextFrame) != FALSE) { 00596 goto Handled1; 00597 } 00598 } 00599 00600 // 00601 // This is the second chance to handle the exception. 00602 // 00603 00604 if (KiDebugRoutine != NULL) { 00605 if (((KiDebugRoutine) (TrapFrame, 00606 ExceptionFrame, 00607 ExceptionRecord, 00608 &ContextFrame, 00609 PreviousMode, 00610 TRUE)) != FALSE) { 00611 goto Handled1; 00612 } 00613 } 00614 00615 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 00616 ExceptionRecord->ExceptionCode, 00617 (ULONG)ExceptionRecord->ExceptionAddress, 00618 ExceptionRecord->ExceptionInformation[0], 00619 ExceptionRecord->ExceptionInformation[1]); 00620 00621 } else { 00622 00623 // 00624 // Previous mode was user. 00625 // 00626 // If this is the first chance, the kernel debugger is active, the 00627 // exception is a kernel breakpoint, and the current process is not 00628 // being debugged, or the current process is being debugged, but the 00629 // the breakpoint is not a kernel breakpoint instruction, then give 00630 // the kernel debugger a chance to handle the exception. 00631 // 00632 // If this is the first chance and the current process has a debugger 00633 // port, then send a message to the debugger port and wait for a reply. 00634 // If the debugger handles the exception, then continue execution. Else 00635 // transfer the exception information to the user stack, transition to 00636 // user mode, and attempt to dispatch the exception to a frame based 00637 // handler. If a frame based handler handles the exception, then continue 00638 // execution. Otherwise, execute the raise exception system service 00639 // which will call this routine a second time to process the exception. 00640 // 00641 // If this is the second chance and the current process has a debugger 00642 // port, then send a message to the debugger port and wait for a reply. 00643 // If the debugger handles the exception, then continue execution. Else 00644 // if the current process has a subsystem port, then send a message to 00645 // the subsystem port and wait for a reply. If the subsystem handles the 00646 // exception, then continue execution. Else terminate the thread. 00647 // 00648 00649 if (FirstChance != FALSE) { 00650 00651 // 00652 // If the kernel debugger is active, the exception is a kernel 00653 // breakpoint, and the current process is not being debugged, 00654 // or the current process is being debugged, but the breakpoint 00655 // is not a kernel breakpoint instruction, then give the kernel 00656 // debugger a chance to handle the exception. 00657 // 00658 00659 if ((KiDebugRoutine != NULL) && 00660 ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) || 00661 (ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)) && 00662 (KdIsThisAKdTrap(ExceptionRecord, 00663 &ContextFrame, 00664 UserMode) != FALSE) && 00665 ((PsGetCurrentProcess()->DebugPort == NULL) || 00666 ((PsGetCurrentProcess()->DebugPort != NULL) && 00667 (ExceptionRecord->ExceptionInformation[0] != 00668 KERNEL_BREAKPOINT_INSTRUCTION)))) { 00669 00670 if (((KiDebugRoutine) (TrapFrame, 00671 ExceptionFrame, 00672 ExceptionRecord, 00673 &ContextFrame, 00674 UserMode, 00675 FALSE)) != FALSE) { 00676 00677 goto Handled1; 00678 } 00679 } 00680 00681 // 00682 // This is the first chance to handle the exception. 00683 // 00684 00685 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) { 00686 TrapFrame->Fpscr = SANITIZE_FPSCR(TrapFrame->Fpscr, UserMode); 00687 goto Handled2; 00688 } 00689 00690 // 00691 // Transfer exception information to the user stack, transition 00692 // to user mode, and attempt to dispatch the exception to a frame 00693 // based handler. 00694 // 00695 // We are running on the kernel stack now. On the user stack, we 00696 // build a stack frame containing the following: 00697 // 00698 // | | 00699 // |-----------------------------------| 00700 // | | 00701 // | Stack frame header | 00702 // | | 00703 // |- - - - - - - - - - - - - - - - - -| 00704 // | | 00705 // | Exception record | 00706 // | | 00707 // |- - - - - - - - - - - - - - - - - -| 00708 // | | 00709 // | Context record | 00710 // | | 00711 // | | 00712 // | | 00713 // |- - - - - - - - - - - - - - - - - -| 00714 // | Saved TOC for backtrack | 00715 // |- - - - - - - - - - - - - - - - - -| 00716 // | | 00717 // | | 00718 // | STK_SLACK_SPACE | 00719 // | | 00720 // | | 00721 // | | 00722 // |- - - - - - - - - - - - - - - - - -| 00723 // | | 00724 // | User's stack frame | 00725 // | | 00726 // | | 00727 // 00728 // This stack frame is for KiUserExceptionDispatcher, the assembly 00729 // langauge routine that effects transfer in user mode to 00730 // RtlDispatchException. KiUserExceptionDispatcher is passed 00731 // pointers to the Exception Record and Context Record as 00732 // parameters. 00733 00734 repeat: 00735 try { 00736 00737 // 00738 // Compute positions on user stack of items shown above 00739 // 00740 00741 ULONG Length = (sizeof (STACK_FRAME_HEADER) + sizeof (EXCEPTION_RECORD) + 00742 sizeof (CONTEXT) + sizeof (ULONG) + STK_SLACK_SPACE + 7) & (~7); 00743 00744 ULONG UserStack = (ContextFrame.Gpr1 & (~7)) - Length; 00745 ULONG ExceptSlot = UserStack + sizeof (STACK_FRAME_HEADER); 00746 ULONG ContextSlot = ExceptSlot + sizeof (EXCEPTION_RECORD); 00747 ULONG TocSlot = ContextSlot + sizeof (CONTEXT); 00748 00749 // 00750 // Probe user stack area for writeability and then transfer the 00751 // exception record and context record to the user stack area. 00752 // 00753 00754 ProbeForWrite((PCHAR) UserStack, ContextFrame.Gpr1 - UserStack, sizeof(QUAD)); 00755 RtlMoveMemory((PVOID) ExceptSlot, ExceptionRecord, sizeof (EXCEPTION_RECORD)); 00756 RtlMoveMemory((PVOID) ContextSlot, &ContextFrame, sizeof (CONTEXT)); 00757 00758 // 00759 // Fill in TOC value as if it had been saved by prologue to 00760 // KiUserExceptionDispatcher 00761 // 00762 00763 *((PULONG) TocSlot) = ContextFrame.Gpr2; 00764 00765 // 00766 // Set back chain from newly-constructed stack frame 00767 // 00768 00769 *((PULONG) UserStack) = ContextFrame.Gpr1; 00770 00771 // 00772 // Set address of exception record, context record, 00773 // and the new stack pointer in the current trap frame. 00774 // 00775 00776 TrapFrame->Gpr1 = UserStack; // Stack pointer 00777 TrapFrame->Gpr3 = ExceptSlot; // First parameter 00778 TrapFrame->Gpr4 = ContextSlot; // Second parameter 00779 00780 // 00781 // Sanitize the floating status register so a recursive 00782 // exception will not occur. 00783 // 00784 00785 TrapFrame->Fpscr = SANITIZE_FPSCR(ContextFrame.Fpscr, UserMode); 00786 00787 // 00788 // Set the execution address and TOC pointer of the exception 00789 // routine that will call the exception dispatcher and then return 00790 // to the trap handler. The trap handler will restore the exception 00791 // and trap frame context and continue execution in the routine 00792 // that will call the exception dispatcher. 00793 // 00794 00795 { 00796 PULONG FnDesc = (PULONG) KeUserExceptionDispatcher; 00797 TrapFrame->Iar = FnDesc[0]; 00798 TrapFrame->Gpr2 = FnDesc[1]; 00799 } 00800 00801 return; 00802 00803 // 00804 // If an exception occurs, then copy the new exception information 00805 // to an exception record and handle the exception. 00806 // 00807 00808 } except (KiCopyInformation(&ExceptionRecord1, 00809 (GetExceptionInformation())->ExceptionRecord)) { 00810 00811 // 00812 // If the exception is a stack overflow, then attempt 00813 // to raise the stack overflow exception. Otherwise, 00814 // the user's stack is not accessible, or is misaligned, 00815 // and second chance processing is performed. 00816 // 00817 00818 if (ExceptionRecord1.ExceptionCode == STATUS_STACK_OVERFLOW) { 00819 ExceptionRecord1.ExceptionAddress = ExceptionRecord->ExceptionAddress; 00820 RtlMoveMemory((PVOID)ExceptionRecord, 00821 &ExceptionRecord1, sizeof(EXCEPTION_RECORD)); 00822 goto repeat; 00823 } 00824 } 00825 } 00826 00827 // 00828 // This is the second chance to handle the exception. 00829 // 00830 00831 UserApcPending = KeGetCurrentThread()->ApcState.UserApcPending; 00832 if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) { 00833 TrapFrame->Fpscr = SANITIZE_FPSCR(TrapFrame->Fpscr, UserMode); 00834 goto Handled2; 00835 00836 } else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) { 00837 // 00838 // If a user APC was not previously pending and one is now 00839 // pending, then the thread has been terminated and the PC 00840 // must be forced to a legal address so an infinite loop does 00841 // not occur for the case where a jump to an unmapped address 00842 // occurred. 00843 // 00844 00845 if ((UserApcPending == FALSE) && 00846 (KeGetCurrentThread()->ApcState.UserApcPending != FALSE)) { 00847 // TEMPORARY .... PAT 00848 // Commenting out reference to USPCR (a known legal address .. 00849 // TrapFrame->Iar = (ULONG)USPCR; 00850 } 00851 00852 TrapFrame->Fpscr = SANITIZE_FPSCR(TrapFrame->Fpscr, UserMode); 00853 goto Handled2; 00854 00855 } else { 00856 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode); 00857 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 00858 ExceptionRecord->ExceptionCode, 00859 (ULONG)ExceptionRecord->ExceptionAddress, 00860 ExceptionRecord->ExceptionInformation[0], 00861 ExceptionRecord->ExceptionInformation[1]); 00862 } 00863 } 00864 00865 // 00866 // Move machine state from context frame to trap and exception frames and 00867 // then return to continue execution with the restored state. 00868 // 00869 00870 Handled1: 00871 KeContextToKframes(TrapFrame, ExceptionFrame, &ContextFrame, 00872 ContextFrame.ContextFlags, PreviousMode); 00873 00874 // 00875 // Exception was handled by the debugger or the associated subsystem 00876 // and state was modified, if necessary, using the get state and set 00877 // state capabilities. Therefore the context frame does not need to 00878 // be transfered to the trap and exception frames. 00879 // 00880 00881 Handled2: 00882 return; 00883 } 00884 00885 ULONG 00886 KiCopyInformation ( 00887 IN OUT PEXCEPTION_RECORD ExceptionRecord1, 00888 IN PEXCEPTION_RECORD ExceptionRecord2 00889 ) 00890 00891 /*++ 00892 00893 Routine Description: 00894 00895 This function is called from an exception filter to copy the exception 00896 information from one exception record to another when an exception occurs. 00897 00898 Arguments: 00899 00900 ExceptionRecord1 - Supplies a pointer to the destination exception record. 00901 00902 ExceptionRecord2 - Supplies a pointer to the source exception record. 00903 00904 Return Value: 00905 00906 A value of EXCEPTION_EXECUTE_HANDLER is returned as the function value. 00907 00908 --*/ 00909 00910 { 00911 00912 // 00913 // Copy one exception record to another and return value that causes 00914 // an exception handler to be executed. 00915 // 00916 00917 RtlMoveMemory((PVOID)ExceptionRecord1, 00918 (PVOID)ExceptionRecord2, 00919 sizeof(EXCEPTION_RECORD)); 00920 00921 return EXCEPTION_EXECUTE_HANDLER; 00922 } 00923 00924 NTSTATUS 00925 KeRaiseUserException( 00926 IN NTSTATUS ExceptionCode 00927 ) 00928 00929 /*++ 00930 00931 Routine Description: 00932 00933 This function causes an exception to be raised in the calling thread's user-mode 00934 context. It does this by editing the trap frame the kernel was entered with to 00935 point to trampoline code that raises the requested exception. 00936 00937 Arguments: 00938 00939 ExceptionCode - Supplies the status value to be used as the exception 00940 code for the exception that is to be raised. 00941 00942 Return Value: 00943 00944 The status value that should be returned by the caller. 00945 00946 --*/ 00947 00948 { 00949 PKTRAP_FRAME TrapFrame; 00950 PULONG FnDesc; 00951 00952 ASSERT(KeGetPreviousMode() == UserMode); 00953 00954 TrapFrame = KeGetCurrentThread()->TrapFrame; 00955 FnDesc = (PULONG)KeRaiseUserExceptionDispatcher; 00956 00957 TrapFrame->Iar = FnDesc[0]; 00958 TrapFrame->Gpr2 = FnDesc[1]; 00959 00960 return(ExceptionCode); 00961 }

Generated on Sat May 15 19:39:57 2004 for test by doxygen 1.3.7