1*c2c66affSColin Finck /* 2*c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory 3*c2c66affSColin Finck * PROJECT: ReactOS Run-Time Library 4*c2c66affSColin Finck * PURPOSE: User-mode exception support for IA-32 5*c2c66affSColin Finck * FILE: lib/rtl/i386/except.c 6*c2c66affSColin Finck * PROGRAMERS: Alex Ionescu (alex@relsoft.net) 7*c2c66affSColin Finck * Casper S. Hornstrup (chorns@users.sourceforge.net) 8*c2c66affSColin Finck */ 9*c2c66affSColin Finck 10*c2c66affSColin Finck /* INCLUDES *****************************************************************/ 11*c2c66affSColin Finck 12*c2c66affSColin Finck #include <rtl.h> 13*c2c66affSColin Finck #define NDEBUG 14*c2c66affSColin Finck #include <debug.h> 15*c2c66affSColin Finck 16*c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/ 17*c2c66affSColin Finck 18*c2c66affSColin Finck /* 19*c2c66affSColin Finck * @implemented 20*c2c66affSColin Finck */ 21*c2c66affSColin Finck VOID 22*c2c66affSColin Finck NTAPI 23*c2c66affSColin Finck RtlGetCallersAddress(OUT PVOID *CallersAddress, 24*c2c66affSColin Finck OUT PVOID *CallersCaller) 25*c2c66affSColin Finck { 26*c2c66affSColin Finck USHORT FrameCount; 27*c2c66affSColin Finck PVOID BackTrace[2]; 28*c2c66affSColin Finck PULONG BackTraceHash = NULL; 29*c2c66affSColin Finck 30*c2c66affSColin Finck /* Get the tow back trace address */ 31*c2c66affSColin Finck FrameCount = RtlCaptureStackBackTrace(2, 2, &BackTrace[0],BackTraceHash); 32*c2c66affSColin Finck 33*c2c66affSColin Finck /* Only if user want it */ 34*c2c66affSColin Finck if (CallersAddress != NULL) 35*c2c66affSColin Finck { 36*c2c66affSColin Finck /* only when first frames exist */ 37*c2c66affSColin Finck if (FrameCount >= 1) 38*c2c66affSColin Finck { 39*c2c66affSColin Finck *CallersAddress = BackTrace[0]; 40*c2c66affSColin Finck } 41*c2c66affSColin Finck else 42*c2c66affSColin Finck { 43*c2c66affSColin Finck *CallersAddress = NULL; 44*c2c66affSColin Finck } 45*c2c66affSColin Finck } 46*c2c66affSColin Finck 47*c2c66affSColin Finck /* Only if user want it */ 48*c2c66affSColin Finck if (CallersCaller != NULL) 49*c2c66affSColin Finck { 50*c2c66affSColin Finck /* only when second frames exist */ 51*c2c66affSColin Finck if (FrameCount >= 2) 52*c2c66affSColin Finck { 53*c2c66affSColin Finck *CallersCaller = BackTrace[1]; 54*c2c66affSColin Finck } 55*c2c66affSColin Finck else 56*c2c66affSColin Finck { 57*c2c66affSColin Finck *CallersCaller = NULL; 58*c2c66affSColin Finck } 59*c2c66affSColin Finck } 60*c2c66affSColin Finck } 61*c2c66affSColin Finck 62*c2c66affSColin Finck /* 63*c2c66affSColin Finck * @implemented 64*c2c66affSColin Finck */ 65*c2c66affSColin Finck BOOLEAN 66*c2c66affSColin Finck NTAPI 67*c2c66affSColin Finck RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, 68*c2c66affSColin Finck IN PCONTEXT Context) 69*c2c66affSColin Finck { 70*c2c66affSColin Finck PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, NestedFrame = NULL; 71*c2c66affSColin Finck DISPATCHER_CONTEXT DispatcherContext; 72*c2c66affSColin Finck EXCEPTION_RECORD ExceptionRecord2; 73*c2c66affSColin Finck EXCEPTION_DISPOSITION Disposition; 74*c2c66affSColin Finck ULONG_PTR StackLow, StackHigh; 75*c2c66affSColin Finck ULONG_PTR RegistrationFrameEnd; 76*c2c66affSColin Finck 77*c2c66affSColin Finck /* Perform vectored exception handling for user mode */ 78*c2c66affSColin Finck if (RtlCallVectoredExceptionHandlers(ExceptionRecord, Context)) 79*c2c66affSColin Finck { 80*c2c66affSColin Finck /* Exception handled, now call vectored continue handlers */ 81*c2c66affSColin Finck RtlCallVectoredContinueHandlers(ExceptionRecord, Context); 82*c2c66affSColin Finck 83*c2c66affSColin Finck /* Continue execution */ 84*c2c66affSColin Finck return TRUE; 85*c2c66affSColin Finck } 86*c2c66affSColin Finck 87*c2c66affSColin Finck /* Get the current stack limits and registration frame */ 88*c2c66affSColin Finck RtlpGetStackLimits(&StackLow, &StackHigh); 89*c2c66affSColin Finck RegistrationFrame = RtlpGetExceptionList(); 90*c2c66affSColin Finck 91*c2c66affSColin Finck /* Now loop every frame */ 92*c2c66affSColin Finck while (RegistrationFrame != EXCEPTION_CHAIN_END) 93*c2c66affSColin Finck { 94*c2c66affSColin Finck /* Registration chain entries are never NULL */ 95*c2c66affSColin Finck ASSERT(RegistrationFrame != NULL); 96*c2c66affSColin Finck 97*c2c66affSColin Finck /* Find out where it ends */ 98*c2c66affSColin Finck RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame + 99*c2c66affSColin Finck sizeof(EXCEPTION_REGISTRATION_RECORD); 100*c2c66affSColin Finck 101*c2c66affSColin Finck /* Make sure the registration frame is located within the stack */ 102*c2c66affSColin Finck if ((RegistrationFrameEnd > StackHigh) || 103*c2c66affSColin Finck ((ULONG_PTR)RegistrationFrame < StackLow) || 104*c2c66affSColin Finck ((ULONG_PTR)RegistrationFrame & 0x3)) 105*c2c66affSColin Finck { 106*c2c66affSColin Finck /* Check if this happened in the DPC Stack */ 107*c2c66affSColin Finck if (RtlpHandleDpcStackException(RegistrationFrame, 108*c2c66affSColin Finck RegistrationFrameEnd, 109*c2c66affSColin Finck &StackLow, 110*c2c66affSColin Finck &StackHigh)) 111*c2c66affSColin Finck { 112*c2c66affSColin Finck /* Use DPC Stack Limits and restart */ 113*c2c66affSColin Finck continue; 114*c2c66affSColin Finck } 115*c2c66affSColin Finck 116*c2c66affSColin Finck /* Set invalid stack and return false */ 117*c2c66affSColin Finck ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; 118*c2c66affSColin Finck return FALSE; 119*c2c66affSColin Finck } 120*c2c66affSColin Finck 121*c2c66affSColin Finck /* Check if logging is enabled */ 122*c2c66affSColin Finck RtlpCheckLogException(ExceptionRecord, 123*c2c66affSColin Finck Context, 124*c2c66affSColin Finck RegistrationFrame, 125*c2c66affSColin Finck sizeof(*RegistrationFrame)); 126*c2c66affSColin Finck 127*c2c66affSColin Finck /* Call the handler */ 128*c2c66affSColin Finck Disposition = RtlpExecuteHandlerForException(ExceptionRecord, 129*c2c66affSColin Finck RegistrationFrame, 130*c2c66affSColin Finck Context, 131*c2c66affSColin Finck &DispatcherContext, 132*c2c66affSColin Finck RegistrationFrame->Handler); 133*c2c66affSColin Finck 134*c2c66affSColin Finck /* Check if this is a nested frame */ 135*c2c66affSColin Finck if (RegistrationFrame == NestedFrame) 136*c2c66affSColin Finck { 137*c2c66affSColin Finck /* Mask out the flag and the nested frame */ 138*c2c66affSColin Finck ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; 139*c2c66affSColin Finck NestedFrame = NULL; 140*c2c66affSColin Finck } 141*c2c66affSColin Finck 142*c2c66affSColin Finck /* Handle the dispositions */ 143*c2c66affSColin Finck switch (Disposition) 144*c2c66affSColin Finck { 145*c2c66affSColin Finck /* Continue execution */ 146*c2c66affSColin Finck case ExceptionContinueExecution: 147*c2c66affSColin Finck 148*c2c66affSColin Finck /* Check if it was non-continuable */ 149*c2c66affSColin Finck if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) 150*c2c66affSColin Finck { 151*c2c66affSColin Finck /* Set up the exception record */ 152*c2c66affSColin Finck ExceptionRecord2.ExceptionRecord = ExceptionRecord; 153*c2c66affSColin Finck ExceptionRecord2.ExceptionCode = 154*c2c66affSColin Finck STATUS_NONCONTINUABLE_EXCEPTION; 155*c2c66affSColin Finck ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 156*c2c66affSColin Finck ExceptionRecord2.NumberParameters = 0; 157*c2c66affSColin Finck 158*c2c66affSColin Finck /* Raise the exception */ 159*c2c66affSColin Finck RtlRaiseException(&ExceptionRecord2); 160*c2c66affSColin Finck } 161*c2c66affSColin Finck else 162*c2c66affSColin Finck { 163*c2c66affSColin Finck /* In user mode, call any registered vectored continue handlers */ 164*c2c66affSColin Finck RtlCallVectoredContinueHandlers(ExceptionRecord, 165*c2c66affSColin Finck Context); 166*c2c66affSColin Finck 167*c2c66affSColin Finck /* Execution continues */ 168*c2c66affSColin Finck return TRUE; 169*c2c66affSColin Finck } 170*c2c66affSColin Finck 171*c2c66affSColin Finck /* Continue searching */ 172*c2c66affSColin Finck case ExceptionContinueSearch: 173*c2c66affSColin Finck break; 174*c2c66affSColin Finck 175*c2c66affSColin Finck /* Nested exception */ 176*c2c66affSColin Finck case ExceptionNestedException: 177*c2c66affSColin Finck 178*c2c66affSColin Finck /* Turn the nested flag on */ 179*c2c66affSColin Finck ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL; 180*c2c66affSColin Finck 181*c2c66affSColin Finck /* Update the current nested frame */ 182*c2c66affSColin Finck if (DispatcherContext.RegistrationPointer > NestedFrame) 183*c2c66affSColin Finck { 184*c2c66affSColin Finck /* Get the frame from the dispatcher context */ 185*c2c66affSColin Finck NestedFrame = DispatcherContext.RegistrationPointer; 186*c2c66affSColin Finck } 187*c2c66affSColin Finck break; 188*c2c66affSColin Finck 189*c2c66affSColin Finck /* Anything else */ 190*c2c66affSColin Finck default: 191*c2c66affSColin Finck 192*c2c66affSColin Finck /* Set up the exception record */ 193*c2c66affSColin Finck ExceptionRecord2.ExceptionRecord = ExceptionRecord; 194*c2c66affSColin Finck ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION; 195*c2c66affSColin Finck ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 196*c2c66affSColin Finck ExceptionRecord2.NumberParameters = 0; 197*c2c66affSColin Finck 198*c2c66affSColin Finck /* Raise the exception */ 199*c2c66affSColin Finck RtlRaiseException(&ExceptionRecord2); 200*c2c66affSColin Finck break; 201*c2c66affSColin Finck } 202*c2c66affSColin Finck 203*c2c66affSColin Finck /* Go to the next frame */ 204*c2c66affSColin Finck RegistrationFrame = RegistrationFrame->Next; 205*c2c66affSColin Finck } 206*c2c66affSColin Finck 207*c2c66affSColin Finck /* Unhandled, return false */ 208*c2c66affSColin Finck return FALSE; 209*c2c66affSColin Finck } 210*c2c66affSColin Finck 211*c2c66affSColin Finck /* 212*c2c66affSColin Finck * @implemented 213*c2c66affSColin Finck */ 214*c2c66affSColin Finck VOID 215*c2c66affSColin Finck NTAPI 216*c2c66affSColin Finck RtlUnwind(IN PVOID TargetFrame OPTIONAL, 217*c2c66affSColin Finck IN PVOID TargetIp OPTIONAL, 218*c2c66affSColin Finck IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, 219*c2c66affSColin Finck IN PVOID ReturnValue) 220*c2c66affSColin Finck { 221*c2c66affSColin Finck PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, OldFrame; 222*c2c66affSColin Finck DISPATCHER_CONTEXT DispatcherContext; 223*c2c66affSColin Finck EXCEPTION_RECORD ExceptionRecord2, ExceptionRecord3; 224*c2c66affSColin Finck EXCEPTION_DISPOSITION Disposition; 225*c2c66affSColin Finck ULONG_PTR StackLow, StackHigh; 226*c2c66affSColin Finck ULONG_PTR RegistrationFrameEnd; 227*c2c66affSColin Finck CONTEXT LocalContext; 228*c2c66affSColin Finck PCONTEXT Context; 229*c2c66affSColin Finck 230*c2c66affSColin Finck /* Get the current stack limits */ 231*c2c66affSColin Finck RtlpGetStackLimits(&StackLow, &StackHigh); 232*c2c66affSColin Finck 233*c2c66affSColin Finck /* Check if we don't have an exception record */ 234*c2c66affSColin Finck if (!ExceptionRecord) 235*c2c66affSColin Finck { 236*c2c66affSColin Finck /* Overwrite the argument */ 237*c2c66affSColin Finck ExceptionRecord = &ExceptionRecord3; 238*c2c66affSColin Finck 239*c2c66affSColin Finck /* Setup a local one */ 240*c2c66affSColin Finck ExceptionRecord3.ExceptionFlags = 0; 241*c2c66affSColin Finck ExceptionRecord3.ExceptionCode = STATUS_UNWIND; 242*c2c66affSColin Finck ExceptionRecord3.ExceptionRecord = NULL; 243*c2c66affSColin Finck ExceptionRecord3.ExceptionAddress = _ReturnAddress(); 244*c2c66affSColin Finck ExceptionRecord3.NumberParameters = 0; 245*c2c66affSColin Finck } 246*c2c66affSColin Finck 247*c2c66affSColin Finck /* Check if we have a frame */ 248*c2c66affSColin Finck if (TargetFrame) 249*c2c66affSColin Finck { 250*c2c66affSColin Finck /* Set it as unwinding */ 251*c2c66affSColin Finck ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING; 252*c2c66affSColin Finck } 253*c2c66affSColin Finck else 254*c2c66affSColin Finck { 255*c2c66affSColin Finck /* Set the Exit Unwind flag as well */ 256*c2c66affSColin Finck ExceptionRecord->ExceptionFlags |= (EXCEPTION_UNWINDING | 257*c2c66affSColin Finck EXCEPTION_EXIT_UNWIND); 258*c2c66affSColin Finck } 259*c2c66affSColin Finck 260*c2c66affSColin Finck /* Now capture the context */ 261*c2c66affSColin Finck Context = &LocalContext; 262*c2c66affSColin Finck LocalContext.ContextFlags = CONTEXT_INTEGER | 263*c2c66affSColin Finck CONTEXT_CONTROL | 264*c2c66affSColin Finck CONTEXT_SEGMENTS; 265*c2c66affSColin Finck RtlpCaptureContext(Context); 266*c2c66affSColin Finck 267*c2c66affSColin Finck /* Pop the current arguments off */ 268*c2c66affSColin Finck Context->Esp += sizeof(TargetFrame) + 269*c2c66affSColin Finck sizeof(TargetIp) + 270*c2c66affSColin Finck sizeof(ExceptionRecord) + 271*c2c66affSColin Finck sizeof(ReturnValue); 272*c2c66affSColin Finck 273*c2c66affSColin Finck /* Set the new value for EAX */ 274*c2c66affSColin Finck Context->Eax = (ULONG)ReturnValue; 275*c2c66affSColin Finck 276*c2c66affSColin Finck /* Get the current frame */ 277*c2c66affSColin Finck RegistrationFrame = RtlpGetExceptionList(); 278*c2c66affSColin Finck 279*c2c66affSColin Finck /* Now loop every frame */ 280*c2c66affSColin Finck while (RegistrationFrame != EXCEPTION_CHAIN_END) 281*c2c66affSColin Finck { 282*c2c66affSColin Finck /* Registration chain entries are never NULL */ 283*c2c66affSColin Finck ASSERT(RegistrationFrame != NULL); 284*c2c66affSColin Finck 285*c2c66affSColin Finck /* If this is the target */ 286*c2c66affSColin Finck if (RegistrationFrame == TargetFrame) ZwContinue(Context, FALSE); 287*c2c66affSColin Finck 288*c2c66affSColin Finck /* Check if the frame is too low */ 289*c2c66affSColin Finck if ((TargetFrame) && 290*c2c66affSColin Finck ((ULONG_PTR)TargetFrame < (ULONG_PTR)RegistrationFrame)) 291*c2c66affSColin Finck { 292*c2c66affSColin Finck /* Create an invalid unwind exception */ 293*c2c66affSColin Finck ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; 294*c2c66affSColin Finck ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 295*c2c66affSColin Finck ExceptionRecord2.ExceptionRecord = ExceptionRecord; 296*c2c66affSColin Finck ExceptionRecord2.NumberParameters = 0; 297*c2c66affSColin Finck 298*c2c66affSColin Finck /* Raise the exception */ 299*c2c66affSColin Finck RtlRaiseException(&ExceptionRecord2); 300*c2c66affSColin Finck } 301*c2c66affSColin Finck 302*c2c66affSColin Finck /* Find out where it ends */ 303*c2c66affSColin Finck RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame + 304*c2c66affSColin Finck sizeof(EXCEPTION_REGISTRATION_RECORD); 305*c2c66affSColin Finck 306*c2c66affSColin Finck /* Make sure the registration frame is located within the stack */ 307*c2c66affSColin Finck if ((RegistrationFrameEnd > StackHigh) || 308*c2c66affSColin Finck ((ULONG_PTR)RegistrationFrame < StackLow) || 309*c2c66affSColin Finck ((ULONG_PTR)RegistrationFrame & 0x3)) 310*c2c66affSColin Finck { 311*c2c66affSColin Finck /* Check if this happened in the DPC Stack */ 312*c2c66affSColin Finck if (RtlpHandleDpcStackException(RegistrationFrame, 313*c2c66affSColin Finck RegistrationFrameEnd, 314*c2c66affSColin Finck &StackLow, 315*c2c66affSColin Finck &StackHigh)) 316*c2c66affSColin Finck { 317*c2c66affSColin Finck /* Use DPC Stack Limits and restart */ 318*c2c66affSColin Finck continue; 319*c2c66affSColin Finck } 320*c2c66affSColin Finck 321*c2c66affSColin Finck /* Create an invalid stack exception */ 322*c2c66affSColin Finck ExceptionRecord2.ExceptionCode = STATUS_BAD_STACK; 323*c2c66affSColin Finck ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 324*c2c66affSColin Finck ExceptionRecord2.ExceptionRecord = ExceptionRecord; 325*c2c66affSColin Finck ExceptionRecord2.NumberParameters = 0; 326*c2c66affSColin Finck 327*c2c66affSColin Finck /* Raise the exception */ 328*c2c66affSColin Finck RtlRaiseException(&ExceptionRecord2); 329*c2c66affSColin Finck } 330*c2c66affSColin Finck else 331*c2c66affSColin Finck { 332*c2c66affSColin Finck /* Call the handler */ 333*c2c66affSColin Finck Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord, 334*c2c66affSColin Finck RegistrationFrame, 335*c2c66affSColin Finck Context, 336*c2c66affSColin Finck &DispatcherContext, 337*c2c66affSColin Finck RegistrationFrame->Handler); 338*c2c66affSColin Finck switch(Disposition) 339*c2c66affSColin Finck { 340*c2c66affSColin Finck /* Continue searching */ 341*c2c66affSColin Finck case ExceptionContinueSearch: 342*c2c66affSColin Finck break; 343*c2c66affSColin Finck 344*c2c66affSColin Finck /* Collission */ 345*c2c66affSColin Finck case ExceptionCollidedUnwind : 346*c2c66affSColin Finck 347*c2c66affSColin Finck /* Get the original frame */ 348*c2c66affSColin Finck RegistrationFrame = DispatcherContext.RegistrationPointer; 349*c2c66affSColin Finck break; 350*c2c66affSColin Finck 351*c2c66affSColin Finck /* Anything else */ 352*c2c66affSColin Finck default: 353*c2c66affSColin Finck 354*c2c66affSColin Finck /* Set up the exception record */ 355*c2c66affSColin Finck ExceptionRecord2.ExceptionRecord = ExceptionRecord; 356*c2c66affSColin Finck ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION; 357*c2c66affSColin Finck ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 358*c2c66affSColin Finck ExceptionRecord2.NumberParameters = 0; 359*c2c66affSColin Finck 360*c2c66affSColin Finck /* Raise the exception */ 361*c2c66affSColin Finck RtlRaiseException(&ExceptionRecord2); 362*c2c66affSColin Finck break; 363*c2c66affSColin Finck } 364*c2c66affSColin Finck 365*c2c66affSColin Finck /* Go to the next frame */ 366*c2c66affSColin Finck OldFrame = RegistrationFrame; 367*c2c66affSColin Finck RegistrationFrame = RegistrationFrame->Next; 368*c2c66affSColin Finck 369*c2c66affSColin Finck /* Remove this handler */ 370*c2c66affSColin Finck RtlpSetExceptionList(OldFrame); 371*c2c66affSColin Finck } 372*c2c66affSColin Finck } 373*c2c66affSColin Finck 374*c2c66affSColin Finck /* Check if we reached the end */ 375*c2c66affSColin Finck if (TargetFrame == EXCEPTION_CHAIN_END) 376*c2c66affSColin Finck { 377*c2c66affSColin Finck /* Unwind completed, so we don't exit */ 378*c2c66affSColin Finck ZwContinue(Context, FALSE); 379*c2c66affSColin Finck } 380*c2c66affSColin Finck else 381*c2c66affSColin Finck { 382*c2c66affSColin Finck /* This is an exit_unwind or the frame wasn't present in the list */ 383*c2c66affSColin Finck ZwRaiseException(ExceptionRecord, Context, FALSE); 384*c2c66affSColin Finck } 385*c2c66affSColin Finck } 386*c2c66affSColin Finck 387*c2c66affSColin Finck /* EOF */ 388