/*++ Function: RtlpRaiseException Parameters: ExceptionRecord - the Windows exception record to throw Note: The name of this function and the name of the ExceptionRecord parameter is used in the sos lldb plugin code to read the exception record. See coreclr\src\ToolBox\SOS\lldbplugin\debugclient.cpp. --*/ PAL_NORETURN static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord) { // Capture the context of RtlpRaiseException. CONTEXT ContextRecord; ZeroMemory(&ContextRecord, sizeof(CONTEXT)); ContextRecord.ContextFlags = CONTEXT_FULL; CONTEXT_CaptureContext(&ContextRecord); // Find the caller of RtlpRaiseException. PAL_VirtualUnwind(&ContextRecord, NULL); // The frame we're looking at now is RaiseException. We have to unwind one // level further to get the actual context user code could be resumed at. PAL_VirtualUnwind(&ContextRecord, NULL); #if defined(_X86_) ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Eip; #elif defined(_AMD64_) ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Rip; #elif defined(_ARM_) || defined(_ARM64_) ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Pc; #else #error unsupported architecture #endif EXCEPTION_POINTERS pointers; pointers.ExceptionRecord = ExceptionRecord; pointers.ContextRecord = &ContextRecord; SEHRaiseException(InternalGetCurrentThread(), &pointers, 0); }
void PAL_DispatchException(PCONTEXT pContext, PEXCEPTION_RECORD pExRecord) { MSG_SET_THREAD MsgSet; kern_return_t MachRet; EXCEPTION_POINTERS pointers; pointers.ExceptionRecord = pExRecord; pointers.ContextRecord = pContext; // Raise the exception SEHRaiseException(&pointers, 0); // We need to send a message to the worker thread so that it can set our thread context // Setup the heaer MsgSet.m_MsgHdr.msgh_size = sizeof(MsgSet); MsgSet.m_MsgHdr.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MAKE_SEND|MACH_MSG_TYPE_MOVE_RECEIVE); // Simple Message MsgSet.m_MsgHdr.msgh_remote_port = s_ExceptionPort; // Send, dest port MsgSet.m_MsgHdr.msgh_local_port = MACH_PORT_NULL; // We're not expecting a msg back MsgSet.m_MsgHdr.msgh_id = SET_THREAD_MESSAGE_ID; // Message ID MsgSet.m_MsgHdr.msgh_reserved = 0; // Not used // Setup the thread and thread context MsgSet.m_ThreadPort = mach_thread_self(); MsgSet.m_ThreadContext = *pContext; // Send the message to the exception port MachRet = mach_msg(&MsgSet.m_MsgHdr, MACH_SEND_MSG, MsgSet.m_MsgHdr.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (MachRet != KERN_SUCCESS) { UTIL_SetLastErrorFromMach(MachRet); ExitProcess(GetLastError()); } // Make sure we don't do anything while(1) { sched_yield(); } }
/*++ Function: RaiseException See MSDN doc. --*/ VOID PALAPI RaiseException( IN DWORD dwExceptionCode, IN DWORD dwExceptionFlags, IN DWORD nNumberOfArguments, IN CONST ULONG_PTR *lpArguments) { EXCEPTION_RECORD record; EXCEPTION_POINTERS exceptionPointers; CONTEXT context; ENTRY("RaiseException (dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArgs=%p)\n", dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments); /* Validate parameters */ if( dwExceptionCode & RESERVED_SEH_BIT) { WARN("Exception code %08x has bit 28 set : clearing it.\n", dwExceptionCode); dwExceptionCode ^= RESERVED_SEH_BIT; } if( dwExceptionFlags && ( dwExceptionFlags != EXCEPTION_NONCONTINUABLE ) ) { ERROR("Unkown exception flag %08x (ignoring)\n", dwExceptionFlags); } /* Build exception record */ TRACE("Building exception record %p\n", &record); record.ExceptionCode = dwExceptionCode; record.ExceptionAddress = RaiseException; record.ExceptionRecord = NULL; if( lpArguments != NULL ) { if(nNumberOfArguments>EXCEPTION_MAXIMUM_PARAMETERS) { WARN("Number of arguments (%d) exceeds the limit " "EXCEPTION_MAXIMUM_PARAMETERS (%d); truncing the extra" "parameters.\n", nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS); nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS; } memcpy(record.ExceptionInformation, lpArguments, nNumberOfArguments*sizeof(ULONG_PTR)); } record.NumberParameters = nNumberOfArguments; /* from rotor_pal.doc : "all explicitly raised exceptions may be considered non-continuable". */ record.ExceptionFlags = EXCEPTION_NONCONTINUABLE; /* from rotor_pal.h : On non-Win32 platforms, the CONTEXT pointer in the PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers. */ ZeroMemory(&context, sizeof context); context.ContextFlags = CONTEXT_CONTROL; if(!GetThreadContext(GetCurrentThread(),&context)) { WARN("GetThreadContext failed!! ignoring...\n"); } exceptionPointers.ExceptionRecord = &record; exceptionPointers.ContextRecord = &context; /* Let SEHRaiseException do the work */ SEHRaiseException(&exceptionPointers, 0); LOGEXIT("RaiseException returns.\n"); }