1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 Implementation of exception API functions based on
22 #ifndef FEATURE_PAL_SXS
23 #error FEATURE_PAL_SXS needs to be defined for this file.
24 #endif // !FEATURE_PAL_SXS
26 #include "pal/context.h"
32 #define UNW_LOCAL_ONLY
34 #include <libunwind.h>
36 #ifdef HAVE_LIBUNWIND_PTRACE
37 #include <libunwind-ptrace.h>
38 #endif // HAVE_LIBUNWIND_PTRACE
40 #endif // HAVE_LIBUNWIND_H
43 //----------------------------------------------------------------------
45 //----------------------------------------------------------------------
48 #if UNWIND_CONTEXT_IS_UCONTEXT_T
51 #define ASSIGN_UNWIND_REGS \
60 #elif defined(_ARM64_)
61 #define ASSIGN_UNWIND_REGS \
77 #error unsupported architecture
80 static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
82 #define ASSIGN_REG(reg) MCREG_##reg(unwContext->uc_mcontext) = winContext->reg;
87 static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
90 // Assuming that unw_set_reg() on cursor will point the cursor to the
91 // supposed stack frame is dangerous for libunwind-arm in Linux.
92 // It is because libunwind's unw_cursor_t has other data structure
93 // initialized by unw_init_local(), which are not updated by
95 unwContext->regs[0] = 0;
96 unwContext->regs[1] = 0;
97 unwContext->regs[2] = 0;
98 unwContext->regs[3] = 0;
99 unwContext->regs[4] = winContext->R4;
100 unwContext->regs[5] = winContext->R5;
101 unwContext->regs[6] = winContext->R6;
102 unwContext->regs[7] = winContext->R7;
103 unwContext->regs[8] = winContext->R8;
104 unwContext->regs[9] = winContext->R9;
105 unwContext->regs[10] = winContext->R10;
106 unwContext->regs[11] = winContext->R11;
107 unwContext->regs[12] = 0;
108 unwContext->regs[13] = winContext->Sp;
109 unwContext->regs[14] = winContext->Lr;
110 unwContext->regs[15] = winContext->Pc;
114 static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor)
117 unw_set_reg(cursor, UNW_REG_IP, winContext->Rip);
118 unw_set_reg(cursor, UNW_REG_SP, winContext->Rsp);
119 unw_set_reg(cursor, UNW_X86_64_RBP, winContext->Rbp);
120 unw_set_reg(cursor, UNW_X86_64_RBX, winContext->Rbx);
121 unw_set_reg(cursor, UNW_X86_64_R12, winContext->R12);
122 unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13);
123 unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14);
124 unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15);
129 static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
132 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Rip);
133 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Rsp);
134 unw_get_reg(cursor, UNW_X86_64_RBP, (unw_word_t *) &winContext->Rbp);
135 unw_get_reg(cursor, UNW_X86_64_RBX, (unw_word_t *) &winContext->Rbx);
136 unw_get_reg(cursor, UNW_X86_64_R12, (unw_word_t *) &winContext->R12);
137 unw_get_reg(cursor, UNW_X86_64_R13, (unw_word_t *) &winContext->R13);
138 unw_get_reg(cursor, UNW_X86_64_R14, (unw_word_t *) &winContext->R14);
139 unw_get_reg(cursor, UNW_X86_64_R15, (unw_word_t *) &winContext->R15);
141 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
142 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
143 unw_get_reg(cursor, UNW_ARM_R14, (unw_word_t *) &winContext->Lr);
144 unw_get_reg(cursor, UNW_ARM_R4, (unw_word_t *) &winContext->R4);
145 unw_get_reg(cursor, UNW_ARM_R5, (unw_word_t *) &winContext->R5);
146 unw_get_reg(cursor, UNW_ARM_R6, (unw_word_t *) &winContext->R6);
147 unw_get_reg(cursor, UNW_ARM_R7, (unw_word_t *) &winContext->R7);
148 unw_get_reg(cursor, UNW_ARM_R8, (unw_word_t *) &winContext->R8);
149 unw_get_reg(cursor, UNW_ARM_R9, (unw_word_t *) &winContext->R9);
150 unw_get_reg(cursor, UNW_ARM_R10, (unw_word_t *) &winContext->R10);
151 unw_get_reg(cursor, UNW_ARM_R11, (unw_word_t *) &winContext->R11);
152 #elif defined(_ARM64_)
153 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
154 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
155 unw_get_reg(cursor, UNW_AARCH64_X29, (unw_word_t *) &winContext->Fp);
156 unw_get_reg(cursor, UNW_AARCH64_X30, (unw_word_t *) &winContext->Lr);
157 unw_get_reg(cursor, UNW_AARCH64_X19, (unw_word_t *) &winContext->X19);
158 unw_get_reg(cursor, UNW_AARCH64_X20, (unw_word_t *) &winContext->X20);
159 unw_get_reg(cursor, UNW_AARCH64_X21, (unw_word_t *) &winContext->X21);
160 unw_get_reg(cursor, UNW_AARCH64_X22, (unw_word_t *) &winContext->X22);
161 unw_get_reg(cursor, UNW_AARCH64_X23, (unw_word_t *) &winContext->X23);
162 unw_get_reg(cursor, UNW_AARCH64_X24, (unw_word_t *) &winContext->X24);
163 unw_get_reg(cursor, UNW_AARCH64_X25, (unw_word_t *) &winContext->X25);
164 unw_get_reg(cursor, UNW_AARCH64_X26, (unw_word_t *) &winContext->X26);
165 unw_get_reg(cursor, UNW_AARCH64_X27, (unw_word_t *) &winContext->X27);
166 unw_get_reg(cursor, UNW_AARCH64_X28, (unw_word_t *) &winContext->X28);
168 #error unsupported architecture
172 static void GetContextPointer(unw_cursor_t *cursor, unw_context_t *unwContext, int reg, SIZE_T **contextPointer)
174 #if defined(HAVE_UNW_GET_SAVE_LOC)
175 unw_save_loc_t saveLoc;
176 unw_get_save_loc(cursor, reg, &saveLoc);
177 if (saveLoc.type == UNW_SLT_MEMORY)
179 SIZE_T *pLoc = (SIZE_T *)saveLoc.u.addr;
180 // Filter out fake save locations that point to unwContext
181 if (unwContext == NULL || (pLoc < (SIZE_T *)unwContext) || ((SIZE_T *)(unwContext + 1) <= pLoc))
182 *contextPointer = (SIZE_T *)saveLoc.u.addr;
185 // Returning NULL indicates that we don't have context pointers available
186 *contextPointer = NULL;
190 static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
193 GetContextPointer(cursor, unwContext, UNW_X86_64_RBP, &contextPointers->Rbp);
194 GetContextPointer(cursor, unwContext, UNW_X86_64_RBX, &contextPointers->Rbx);
195 GetContextPointer(cursor, unwContext, UNW_X86_64_R12, &contextPointers->R12);
196 GetContextPointer(cursor, unwContext, UNW_X86_64_R13, &contextPointers->R13);
197 GetContextPointer(cursor, unwContext, UNW_X86_64_R14, &contextPointers->R14);
198 GetContextPointer(cursor, unwContext, UNW_X86_64_R15, &contextPointers->R15);
200 GetContextPointer(cursor, unwContext, UNW_ARM_R4, &contextPointers->R4);
201 GetContextPointer(cursor, unwContext, UNW_ARM_R5, &contextPointers->R5);
202 GetContextPointer(cursor, unwContext, UNW_ARM_R6, &contextPointers->R6);
203 GetContextPointer(cursor, unwContext, UNW_ARM_R7, &contextPointers->R7);
204 GetContextPointer(cursor, unwContext, UNW_ARM_R8, &contextPointers->R8);
205 GetContextPointer(cursor, unwContext, UNW_ARM_R9, &contextPointers->R9);
206 GetContextPointer(cursor, unwContext, UNW_ARM_R10, &contextPointers->R10);
207 GetContextPointer(cursor, unwContext, UNW_ARM_R11, &contextPointers->R11);
208 #elif defined(_ARM64_)
209 GetContextPointer(cursor, unwContext, UNW_AARCH64_X19, &contextPointers->X19);
210 GetContextPointer(cursor, unwContext, UNW_AARCH64_X20, &contextPointers->X20);
211 GetContextPointer(cursor, unwContext, UNW_AARCH64_X21, &contextPointers->X21);
212 GetContextPointer(cursor, unwContext, UNW_AARCH64_X22, &contextPointers->X22);
213 GetContextPointer(cursor, unwContext, UNW_AARCH64_X23, &contextPointers->X23);
214 GetContextPointer(cursor, unwContext, UNW_AARCH64_X24, &contextPointers->X24);
215 GetContextPointer(cursor, unwContext, UNW_AARCH64_X25, &contextPointers->X25);
216 GetContextPointer(cursor, unwContext, UNW_AARCH64_X26, &contextPointers->X26);
217 GetContextPointer(cursor, unwContext, UNW_AARCH64_X27, &contextPointers->X27);
218 GetContextPointer(cursor, unwContext, UNW_AARCH64_X28, &contextPointers->X28);
220 #error unsupported architecture
224 extern int g_common_signal_handler_context_locvar_offset;
226 BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
229 unw_context_t unwContext;
232 DWORD64 curPc = CONTEXTGetPC(context);
235 // Check if the PC is the return address from the SEHProcessException in the common_signal_handler.
236 // If that's the case, extract its local variable containing the native_context_t of the hardware
237 // exception and return that. This skips the hardware signal handler trampoline that the libunwind
238 // cannot cross on some systems.
239 if ((void*)curPc == g_SEHProcessExceptionReturnAddress)
241 ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_EXCEPTION_ACTIVE;
244 contextFlags |= CONTEXT_XSTATE;
246 size_t nativeContext = *(size_t*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
247 CONTEXTFromNativeContext((const native_context_t *)nativeContext, context, contextFlags);
253 if ((context->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0)
255 // The current frame is a source of hardware exception. Due to the fact that
256 // we use the low level unwinder to unwind just one frame a time, the
257 // unwinder doesn't have the signal_frame flag set. So it doesn't
258 // know that it should not decrement the PC before looking up the unwind info.
259 // So we compensate it by incrementing the PC before passing it to the unwinder.
260 // Without it, the unwinder would not find unwind info if the hardware exception
261 // happened in the first instruction of a function.
262 CONTEXTSetPC(context, curPc + 1);
265 #if !UNWIND_CONTEXT_IS_UCONTEXT_T
266 st = unw_getcontext(&unwContext);
273 WinContextToUnwindContext(context, &unwContext);
275 st = unw_init_local(&cursor, &unwContext);
281 #if !UNWIND_CONTEXT_IS_UCONTEXT_T
282 // Set the unwind context to the specified windows context
283 WinContextToUnwindCursor(context, &cursor);
286 st = unw_step(&cursor);
292 // Check if the frame we have unwound to is a frame that caused
293 // synchronous signal, like a hardware exception and record it
294 // in the context flags.
295 if (unw_is_signal_frame(&cursor) > 0)
297 context->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
298 #if defined(_ARM_) || defined(_ARM64_)
299 context->ContextFlags &= ~CONTEXT_UNWOUND_TO_CALL;
300 #endif // _ARM_ || _ARM64_
304 context->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE;
305 #if defined(_ARM_) || defined(_ARM64_)
306 context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
307 #endif // _ARM_ || _ARM64_
310 // Update the passed in windows context to reflect the unwind
312 UnwindContextToWinContext(&cursor, context);
314 // FreeBSD, NetBSD, OSX and Alpine appear to do two different things when unwinding
315 // 1: If it reaches where it cannot unwind anymore, say a
316 // managed frame. It will return 0, but also update the $pc
317 // 2: If it unwinds all the way to _start it will return
318 // 0 from the step, but $pc will stay the same.
319 // So we detect that here and set the $pc to NULL in that case.
320 // This is the default behavior of the libunwind on Linux.
321 if (st == 0 && CONTEXTGetPC(context) == curPc)
323 CONTEXTSetPC(context, 0);
326 if (contextPointers != NULL)
328 GetContextPointers(&cursor, &unwContext, contextPointers);
334 #error don't know how to unwind on this platform
337 // These methods are only used on the AMD64 build
339 #ifdef HAVE_UNW_GET_ACCESSORS
341 static struct LibunwindCallbacksInfoType
344 ReadMemoryWordCallback readMemCallback;
345 } LibunwindCallbacksInfo;
347 static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dilap, void *arg)
352 static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg)
356 ASSERT("Memory write must never be called by libunwind during stackwalk");
360 // access_mem sometimes gets called by _UPT_find_proc_info, in such cases arg has a pointer to libunwind internal data
361 // returned by _UPT_create. It makes it impossible to use arg for passing readMemCallback. That's why we have to use global variable.
362 if (LibunwindCallbacksInfo.readMemCallback((SIZE_T)addr, (SIZE_T *)valp))
372 static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg)
376 ASSERT("Register write must never be called by libunwind during stackwalk");
377 return -UNW_EREADONLYREG;
380 CONTEXT *winContext = LibunwindCallbacksInfo.Context;
385 case UNW_REG_IP: *valp = (unw_word_t) winContext->Rip; break;
386 case UNW_REG_SP: *valp = (unw_word_t) winContext->Rsp; break;
387 case UNW_X86_64_RBP: *valp = (unw_word_t) winContext->Rbp; break;
388 case UNW_X86_64_RBX: *valp = (unw_word_t) winContext->Rbx; break;
389 case UNW_X86_64_R12: *valp = (unw_word_t) winContext->R12; break;
390 case UNW_X86_64_R13: *valp = (unw_word_t) winContext->R13; break;
391 case UNW_X86_64_R14: *valp = (unw_word_t) winContext->R14; break;
392 case UNW_X86_64_R15: *valp = (unw_word_t) winContext->R15; break;
394 case UNW_ARM_R13: *valp = (unw_word_t) winContext->Sp; break;
395 case UNW_ARM_R14: *valp = (unw_word_t) winContext->Lr; break;
396 case UNW_ARM_R15: *valp = (unw_word_t) winContext->Pc; break;
397 case UNW_ARM_R4: *valp = (unw_word_t) winContext->R4; break;
398 case UNW_ARM_R5: *valp = (unw_word_t) winContext->R5; break;
399 case UNW_ARM_R6: *valp = (unw_word_t) winContext->R6; break;
400 case UNW_ARM_R7: *valp = (unw_word_t) winContext->R7; break;
401 case UNW_ARM_R8: *valp = (unw_word_t) winContext->R8; break;
402 case UNW_ARM_R9: *valp = (unw_word_t) winContext->R9; break;
403 case UNW_ARM_R10: *valp = (unw_word_t) winContext->R10; break;
404 case UNW_ARM_R11: *valp = (unw_word_t) winContext->R11; break;
405 #elif defined(_ARM64_)
406 case UNW_REG_IP: *valp = (unw_word_t) winContext->Pc; break;
407 case UNW_REG_SP: *valp = (unw_word_t) winContext->Sp; break;
408 case UNW_AARCH64_X29: *valp = (unw_word_t) winContext->Fp; break;
409 case UNW_AARCH64_X30: *valp = (unw_word_t) winContext->Lr; break;
410 case UNW_AARCH64_X19: *valp = (unw_word_t) winContext->X19; break;
411 case UNW_AARCH64_X20: *valp = (unw_word_t) winContext->X20; break;
412 case UNW_AARCH64_X21: *valp = (unw_word_t) winContext->X21; break;
413 case UNW_AARCH64_X22: *valp = (unw_word_t) winContext->X22; break;
414 case UNW_AARCH64_X23: *valp = (unw_word_t) winContext->X23; break;
415 case UNW_AARCH64_X24: *valp = (unw_word_t) winContext->X24; break;
416 case UNW_AARCH64_X25: *valp = (unw_word_t) winContext->X25; break;
417 case UNW_AARCH64_X26: *valp = (unw_word_t) winContext->X26; break;
418 case UNW_AARCH64_X27: *valp = (unw_word_t) winContext->X27; break;
419 case UNW_AARCH64_X28: *valp = (unw_word_t) winContext->X28; break;
421 #error unsupported architecture
424 ASSERT("Attempt to read an unknown register.");
430 static int access_fpreg(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *fpvalp, int write, void *arg)
432 ASSERT("Not supposed to be ever called");
436 static int resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
438 ASSERT("Not supposed to be ever called");
442 static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, unw_word_t *offp, void *arg)
444 ASSERT("Not supposed to be ever called");
448 int find_proc_info(unw_addr_space_t as,
449 unw_word_t ip, unw_proc_info_t *pip,
450 int need_unwind_info, void *arg)
452 #ifdef HAVE_LIBUNWIND_PTRACE
453 // UNIXTODO: libunwind RPM package on Fedora/CentOS/RedHat doesn't have libunwind-ptrace.so
454 // and we can't use it from a shared library like libmscordaccore.so.
455 // That's why all calls to ptrace parts of libunwind ifdeffed out for now.
456 return _UPT_find_proc_info(as, ip, pip, need_unwind_info, arg);
462 void put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pip, void *arg)
464 #ifdef HAVE_LIBUNWIND_PTRACE
465 return _UPT_put_unwind_info(as, pip, arg);
469 static unw_accessors_t unwind_accessors =
471 .find_proc_info = find_proc_info,
472 .put_unwind_info = put_unwind_info,
473 .get_dyn_info_list_addr = get_dyn_info_list_addr,
474 .access_mem = access_mem,
475 .access_reg = access_reg,
476 .access_fpreg = access_fpreg,
478 .get_proc_name = get_proc_name
481 BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
482 KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
484 ReadMemoryWordCallback readMemCallback)
486 // This function can be executed only by one thread at a time.
487 // The reason for this is that we need to pass context and read mem function to libunwind callbacks
488 // but "arg" is already used by the pointer returned from _UPT_create().
489 // So we resort to using global variables and a lock.
495 // ctor of a static variable is a thread-safe way to initialize critical section exactly once (clang,gcc)
496 InitializeCriticalSection(&cs);
501 CRITICAL_SECTION *cs;
502 LockHolder(CRITICAL_SECTION *cs)
505 EnterCriticalSection(cs);
510 LeaveCriticalSection(cs);
515 LockHolder lockHolder(&lock.cs);
519 unw_addr_space_t addrSpace = 0;
520 void *libunwindUptPtr = NULL;
523 LibunwindCallbacksInfo.Context = context;
524 LibunwindCallbacksInfo.readMemCallback = readMemCallback;
526 addrSpace = unw_create_addr_space(&unwind_accessors, 0);
527 #ifdef HAVE_LIBUNWIND_PTRACE
528 libunwindUptPtr = _UPT_create(pid);
530 st = unw_init_remote(&cursor, addrSpace, libunwindUptPtr);
537 st = unw_step(&cursor);
544 UnwindContextToWinContext(&cursor, context);
546 if (contextPointers != NULL)
548 GetContextPointers(&cursor, NULL, contextPointers);
553 #ifdef HAVE_LIBUNWIND_PTRACE
554 if (libunwindUptPtr != NULL)
556 _UPT_destroy(libunwindUptPtr);
561 unw_destroy_addr_space(addrSpace);
565 #else // HAVE_UNW_GET_ACCESSORS
567 BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
568 KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
570 ReadMemoryWordCallback readMemCallback)
572 //UNIXTODO: Implement for Mac flavor of libunwind
576 #endif // !HAVE_UNW_GET_ACCESSORS
579 struct ExceptionRecords
581 CONTEXT ContextRecord;
582 EXCEPTION_RECORD ExceptionRecord;
585 // Max number of fallback contexts that are used when malloc fails to allocate ExceptionRecords structure
586 static const int MaxFallbackContexts = sizeof(size_t) * 8;
587 // Array of fallback contexts
588 static ExceptionRecords s_fallbackContexts[MaxFallbackContexts];
589 // Bitmap used for allocating fallback contexts - bits set to 1 represent already allocated context.
590 static volatile size_t s_allocatedContextsBitmap = 0;
594 AllocateExceptionRecords
596 Allocate EXCEPTION_RECORD and CONTEXT structures for an exception.
598 exceptionRecord - output pointer to the allocated exception record
599 contextRecord - output pointer to the allocated context record
602 AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord)
604 ExceptionRecords* records;
605 if (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0)
613 bitmap = s_allocatedContextsBitmap;
614 index = __builtin_ffsl(~bitmap) - 1;
620 newBitmap = bitmap | ((size_t)1 << index);
622 while (__sync_val_compare_and_swap(&s_allocatedContextsBitmap, bitmap, newBitmap) != bitmap);
624 records = &s_fallbackContexts[index];
627 *contextRecord = &records->ContextRecord;
628 *exceptionRecord = &records->ExceptionRecord;
633 PAL_FreeExceptionRecords
635 Free EXCEPTION_RECORD and CONTEXT structures of an exception that were allocated by the
636 AllocateExceptionRecords.
638 exceptionRecord - exception record
639 contextRecord - context record
643 PAL_FreeExceptionRecords(IN EXCEPTION_RECORD *exceptionRecord, IN CONTEXT *contextRecord)
645 // Both records are allocated at once and the allocated memory starts at the contextRecord
646 ExceptionRecords* records = (ExceptionRecords*)contextRecord;
647 if ((records >= &s_fallbackContexts[0]) && (records < &s_fallbackContexts[MaxFallbackContexts]))
649 int index = records - &s_fallbackContexts[0];
650 __sync_fetch_and_and(&s_allocatedContextsBitmap, ~((size_t)1 << index));
663 ExceptionRecord - the Windows exception record to throw
666 The name of this function and the name of the ExceptionRecord
667 parameter is used in the sos lldb plugin code to read the exception
668 record. See coreclr\src\ToolBox\SOS\lldbplugin\services.cpp.
670 This function must not be inlined or optimized so the below PAL_VirtualUnwind
671 calls end up with RaiseException caller's context and so the above debugger
672 code finds the function and ExceptionRecord parameter.
675 __attribute__((noinline))
676 __attribute__((optnone))
678 RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord, CONTEXT *ContextRecord)
680 throw PAL_SEHException(ExceptionRecord, ContextRecord);
689 // no PAL_NORETURN, as callers must assume this can return for continuable exceptions.
690 __attribute__((noinline))
693 RaiseException(IN DWORD dwExceptionCode,
694 IN DWORD dwExceptionFlags,
695 IN DWORD nNumberOfArguments,
696 IN CONST ULONG_PTR *lpArguments)
698 // PERF_ENTRY_ONLY is used here because RaiseException may or may not
699 // return. We can not get latency data without PERF_EXIT. For this reason,
700 // PERF_ENTRY_ONLY is used to profile frequency only.
701 PERF_ENTRY_ONLY(RaiseException);
702 ENTRY("RaiseException(dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArguments=%p)\n",
703 dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
705 /* Validate parameters */
706 if (dwExceptionCode & RESERVED_SEH_BIT)
708 WARN("Exception code %08x has bit 28 set; clearing it.\n", dwExceptionCode);
709 dwExceptionCode ^= RESERVED_SEH_BIT;
712 if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS)
714 WARN("Number of arguments (%d) exceeds the limit "
715 "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n",
716 nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS);
717 nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
720 CONTEXT *contextRecord;
721 EXCEPTION_RECORD *exceptionRecord;
722 AllocateExceptionRecords(&exceptionRecord, &contextRecord);
724 ZeroMemory(exceptionRecord, sizeof(EXCEPTION_RECORD));
726 exceptionRecord->ExceptionCode = dwExceptionCode;
727 exceptionRecord->ExceptionFlags = dwExceptionFlags;
728 exceptionRecord->ExceptionRecord = NULL;
729 exceptionRecord->ExceptionAddress = NULL; // will be set by RtlpRaiseException
730 exceptionRecord->NumberParameters = nNumberOfArguments;
731 if (nNumberOfArguments)
733 CopyMemory(exceptionRecord->ExceptionInformation, lpArguments,
734 nNumberOfArguments * sizeof(ULONG_PTR));
737 // Capture the context of RaiseException.
738 ZeroMemory(contextRecord, sizeof(CONTEXT));
739 contextRecord->ContextFlags = CONTEXT_FULL;
740 CONTEXT_CaptureContext(contextRecord);
742 // We have to unwind one level to get the actual context user code could be resumed at.
743 PAL_VirtualUnwind(contextRecord, NULL);
745 exceptionRecord->ExceptionAddress = (void *)CONTEXTGetPC(contextRecord);
747 RtlpRaiseException(exceptionRecord, contextRecord);
749 LOGEXIT("RaiseException returns\n");