/*++ 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 PALAPI RaiseException(IN DWORD dwExceptionCode, IN DWORD dwExceptionFlags, IN DWORD nNumberOfArguments, IN CONST ULONG_PTR *lpArguments) { // PERF_ENTRY_ONLY is used here because RaiseException may or may not // return. We can not get latency data without PERF_EXIT. For this reason, // PERF_ENTRY_ONLY is used to profile frequency only. PERF_ENTRY_ONLY(RaiseException); ENTRY("RaiseException(dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArguments=%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 (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS) { WARN("Number of arguments (%d) exceeds the limit " "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n", nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS); nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS; } CONTEXT *contextRecord; EXCEPTION_RECORD *exceptionRecord; AllocateExceptionRecords(&exceptionRecord, &contextRecord); ZeroMemory(exceptionRecord, sizeof(EXCEPTION_RECORD)); exceptionRecord->ExceptionCode = dwExceptionCode; exceptionRecord->ExceptionFlags = dwExceptionFlags; exceptionRecord->ExceptionRecord = NULL; exceptionRecord->ExceptionAddress = NULL; // will be set by RtlpRaiseException exceptionRecord->NumberParameters = nNumberOfArguments; if (nNumberOfArguments) { CopyMemory(exceptionRecord->ExceptionInformation, lpArguments, nNumberOfArguments * sizeof(ULONG_PTR)); } // Capture the context of RaiseException. ZeroMemory(contextRecord, sizeof(CONTEXT)); contextRecord->ContextFlags = CONTEXT_FULL; CONTEXT_CaptureContext(contextRecord); // We have to unwind one level to get the actual context user code could be resumed at. PAL_VirtualUnwind(contextRecord, NULL); exceptionRecord->ExceptionAddress = (void *)CONTEXTGetPC(contextRecord); RtlpRaiseException(exceptionRecord, contextRecord); LOGEXIT("RaiseException returns\n"); }