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 #define ASSIGN_UNWIND_REGS \
85 #error unsupported architecture
88 static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
90 #define ASSIGN_REG(reg) MCREG_##reg(unwContext->uc_mcontext) = winContext->reg;
95 static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
98 // Assuming that unw_set_reg() on cursor will point the cursor to the
99 // supposed stack frame is dangerous for libunwind-arm in Linux.
100 // It is because libunwind's unw_cursor_t has other data structure
101 // initialized by unw_init_local(), which are not updated by
103 unwContext->regs[0] = 0;
104 unwContext->regs[1] = 0;
105 unwContext->regs[2] = 0;
106 unwContext->regs[3] = 0;
107 unwContext->regs[4] = winContext->R4;
108 unwContext->regs[5] = winContext->R5;
109 unwContext->regs[6] = winContext->R6;
110 unwContext->regs[7] = winContext->R7;
111 unwContext->regs[8] = winContext->R8;
112 unwContext->regs[9] = winContext->R9;
113 unwContext->regs[10] = winContext->R10;
114 unwContext->regs[11] = winContext->R11;
115 unwContext->regs[12] = 0;
116 unwContext->regs[13] = winContext->Sp;
117 unwContext->regs[14] = winContext->Lr;
118 unwContext->regs[15] = winContext->Pc;
122 static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor)
125 unw_set_reg(cursor, UNW_REG_IP, winContext->Rip);
126 unw_set_reg(cursor, UNW_REG_SP, winContext->Rsp);
127 unw_set_reg(cursor, UNW_X86_64_RBP, winContext->Rbp);
128 unw_set_reg(cursor, UNW_X86_64_RBX, winContext->Rbx);
129 unw_set_reg(cursor, UNW_X86_64_R12, winContext->R12);
130 unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13);
131 unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14);
132 unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15);
134 unw_set_reg(cursor, UNW_REG_IP, winContext->Eip);
135 unw_set_reg(cursor, UNW_REG_SP, winContext->Esp);
136 unw_set_reg(cursor, UNW_X86_EBP, winContext->Ebp);
137 unw_set_reg(cursor, UNW_X86_EBX, winContext->Ebx);
138 unw_set_reg(cursor, UNW_X86_ESI, winContext->Esi);
139 unw_set_reg(cursor, UNW_X86_EDI, winContext->Edi);
144 static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
147 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Rip);
148 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Rsp);
149 unw_get_reg(cursor, UNW_X86_64_RBP, (unw_word_t *) &winContext->Rbp);
150 unw_get_reg(cursor, UNW_X86_64_RBX, (unw_word_t *) &winContext->Rbx);
151 unw_get_reg(cursor, UNW_X86_64_R12, (unw_word_t *) &winContext->R12);
152 unw_get_reg(cursor, UNW_X86_64_R13, (unw_word_t *) &winContext->R13);
153 unw_get_reg(cursor, UNW_X86_64_R14, (unw_word_t *) &winContext->R14);
154 unw_get_reg(cursor, UNW_X86_64_R15, (unw_word_t *) &winContext->R15);
156 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Eip);
157 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Esp);
158 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->ResumeEsp);
159 unw_get_reg(cursor, UNW_X86_EBP, (unw_word_t *) &winContext->Ebp);
160 unw_get_reg(cursor, UNW_X86_EBX, (unw_word_t *) &winContext->Ebx);
161 unw_get_reg(cursor, UNW_X86_ESI, (unw_word_t *) &winContext->Esi);
162 unw_get_reg(cursor, UNW_X86_EDI, (unw_word_t *) &winContext->Edi);
164 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
165 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
166 unw_get_reg(cursor, UNW_ARM_R14, (unw_word_t *) &winContext->Lr);
167 unw_get_reg(cursor, UNW_ARM_R4, (unw_word_t *) &winContext->R4);
168 unw_get_reg(cursor, UNW_ARM_R5, (unw_word_t *) &winContext->R5);
169 unw_get_reg(cursor, UNW_ARM_R6, (unw_word_t *) &winContext->R6);
170 unw_get_reg(cursor, UNW_ARM_R7, (unw_word_t *) &winContext->R7);
171 unw_get_reg(cursor, UNW_ARM_R8, (unw_word_t *) &winContext->R8);
172 unw_get_reg(cursor, UNW_ARM_R9, (unw_word_t *) &winContext->R9);
173 unw_get_reg(cursor, UNW_ARM_R10, (unw_word_t *) &winContext->R10);
174 unw_get_reg(cursor, UNW_ARM_R11, (unw_word_t *) &winContext->R11);
175 #elif defined(_ARM64_)
176 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
177 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
178 unw_get_reg(cursor, UNW_AARCH64_X29, (unw_word_t *) &winContext->Fp);
179 unw_get_reg(cursor, UNW_AARCH64_X30, (unw_word_t *) &winContext->Lr);
180 unw_get_reg(cursor, UNW_AARCH64_X19, (unw_word_t *) &winContext->X19);
181 unw_get_reg(cursor, UNW_AARCH64_X20, (unw_word_t *) &winContext->X20);
182 unw_get_reg(cursor, UNW_AARCH64_X21, (unw_word_t *) &winContext->X21);
183 unw_get_reg(cursor, UNW_AARCH64_X22, (unw_word_t *) &winContext->X22);
184 unw_get_reg(cursor, UNW_AARCH64_X23, (unw_word_t *) &winContext->X23);
185 unw_get_reg(cursor, UNW_AARCH64_X24, (unw_word_t *) &winContext->X24);
186 unw_get_reg(cursor, UNW_AARCH64_X25, (unw_word_t *) &winContext->X25);
187 unw_get_reg(cursor, UNW_AARCH64_X26, (unw_word_t *) &winContext->X26);
188 unw_get_reg(cursor, UNW_AARCH64_X27, (unw_word_t *) &winContext->X27);
189 unw_get_reg(cursor, UNW_AARCH64_X28, (unw_word_t *) &winContext->X28);
191 #error unsupported architecture
195 static void GetContextPointer(unw_cursor_t *cursor, unw_context_t *unwContext, int reg, SIZE_T **contextPointer)
197 #if defined(HAVE_UNW_GET_SAVE_LOC)
198 unw_save_loc_t saveLoc;
199 unw_get_save_loc(cursor, reg, &saveLoc);
200 if (saveLoc.type == UNW_SLT_MEMORY)
202 SIZE_T *pLoc = (SIZE_T *)saveLoc.u.addr;
203 // Filter out fake save locations that point to unwContext
204 if (unwContext == NULL || (pLoc < (SIZE_T *)unwContext) || ((SIZE_T *)(unwContext + 1) <= pLoc))
205 *contextPointer = (SIZE_T *)saveLoc.u.addr;
208 // Returning NULL indicates that we don't have context pointers available
209 *contextPointer = NULL;
213 static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
216 GetContextPointer(cursor, unwContext, UNW_X86_64_RBP, &contextPointers->Rbp);
217 GetContextPointer(cursor, unwContext, UNW_X86_64_RBX, &contextPointers->Rbx);
218 GetContextPointer(cursor, unwContext, UNW_X86_64_R12, &contextPointers->R12);
219 GetContextPointer(cursor, unwContext, UNW_X86_64_R13, &contextPointers->R13);
220 GetContextPointer(cursor, unwContext, UNW_X86_64_R14, &contextPointers->R14);
221 GetContextPointer(cursor, unwContext, UNW_X86_64_R15, &contextPointers->R15);
223 GetContextPointer(cursor, unwContext, UNW_X86_EBX, &contextPointers->Ebx);
224 GetContextPointer(cursor, unwContext, UNW_X86_EBP, &contextPointers->Ebp);
225 GetContextPointer(cursor, unwContext, UNW_X86_ESI, &contextPointers->Esi);
226 GetContextPointer(cursor, unwContext, UNW_X86_EDI, &contextPointers->Edi);
228 GetContextPointer(cursor, unwContext, UNW_ARM_R4, &contextPointers->R4);
229 GetContextPointer(cursor, unwContext, UNW_ARM_R5, &contextPointers->R5);
230 GetContextPointer(cursor, unwContext, UNW_ARM_R6, &contextPointers->R6);
231 GetContextPointer(cursor, unwContext, UNW_ARM_R7, &contextPointers->R7);
232 GetContextPointer(cursor, unwContext, UNW_ARM_R8, &contextPointers->R8);
233 GetContextPointer(cursor, unwContext, UNW_ARM_R9, &contextPointers->R9);
234 GetContextPointer(cursor, unwContext, UNW_ARM_R10, &contextPointers->R10);
235 GetContextPointer(cursor, unwContext, UNW_ARM_R11, &contextPointers->R11);
236 #elif defined(_ARM64_)
237 GetContextPointer(cursor, unwContext, UNW_AARCH64_X19, &contextPointers->X19);
238 GetContextPointer(cursor, unwContext, UNW_AARCH64_X20, &contextPointers->X20);
239 GetContextPointer(cursor, unwContext, UNW_AARCH64_X21, &contextPointers->X21);
240 GetContextPointer(cursor, unwContext, UNW_AARCH64_X22, &contextPointers->X22);
241 GetContextPointer(cursor, unwContext, UNW_AARCH64_X23, &contextPointers->X23);
242 GetContextPointer(cursor, unwContext, UNW_AARCH64_X24, &contextPointers->X24);
243 GetContextPointer(cursor, unwContext, UNW_AARCH64_X25, &contextPointers->X25);
244 GetContextPointer(cursor, unwContext, UNW_AARCH64_X26, &contextPointers->X26);
245 GetContextPointer(cursor, unwContext, UNW_AARCH64_X27, &contextPointers->X27);
246 GetContextPointer(cursor, unwContext, UNW_AARCH64_X28, &contextPointers->X28);
247 GetContextPointer(cursor, unwContext, UNW_AARCH64_X29, &contextPointers->Fp);
249 #error unsupported architecture
253 extern int g_common_signal_handler_context_locvar_offset;
255 BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
258 unw_context_t unwContext;
261 DWORD64 curPc = CONTEXTGetPC(context);
264 // Check if the PC is the return address from the SEHProcessException in the common_signal_handler.
265 // If that's the case, extract its local variable containing the native_context_t of the hardware
266 // exception and return that. This skips the hardware signal handler trampoline that the libunwind
267 // cannot cross on some systems.
268 if ((void*)curPc == g_SEHProcessExceptionReturnAddress)
270 ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_EXCEPTION_ACTIVE;
273 contextFlags |= CONTEXT_XSTATE;
275 size_t nativeContext = *(size_t*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
276 CONTEXTFromNativeContext((const native_context_t *)nativeContext, context, contextFlags);
282 if ((context->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0)
284 // The current frame is a source of hardware exception. Due to the fact that
285 // we use the low level unwinder to unwind just one frame a time, the
286 // unwinder doesn't have the signal_frame flag set. So it doesn't
287 // know that it should not decrement the PC before looking up the unwind info.
288 // So we compensate it by incrementing the PC before passing it to the unwinder.
289 // Without it, the unwinder would not find unwind info if the hardware exception
290 // happened in the first instruction of a function.
291 CONTEXTSetPC(context, curPc + 1);
294 #if !UNWIND_CONTEXT_IS_UCONTEXT_T
295 st = unw_getcontext(&unwContext);
302 WinContextToUnwindContext(context, &unwContext);
304 st = unw_init_local(&cursor, &unwContext);
310 #if !UNWIND_CONTEXT_IS_UCONTEXT_T
311 // Set the unwind context to the specified windows context
312 WinContextToUnwindCursor(context, &cursor);
315 st = unw_step(&cursor);
321 // Check if the frame we have unwound to is a frame that caused
322 // synchronous signal, like a hardware exception and record it
323 // in the context flags.
324 if (unw_is_signal_frame(&cursor) > 0)
326 context->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
327 #if defined(_ARM_) || defined(_ARM64_) || defined(_X86_)
328 context->ContextFlags &= ~CONTEXT_UNWOUND_TO_CALL;
329 #endif // _ARM_ || _ARM64_
333 context->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE;
334 #if defined(_ARM_) || defined(_ARM64_) || defined(_X86_)
335 context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
336 #endif // _ARM_ || _ARM64_
339 // Update the passed in windows context to reflect the unwind
341 UnwindContextToWinContext(&cursor, context);
343 // FreeBSD, NetBSD, OSX and Alpine appear to do two different things when unwinding
344 // 1: If it reaches where it cannot unwind anymore, say a
345 // managed frame. It will return 0, but also update the $pc
346 // 2: If it unwinds all the way to _start it will return
347 // 0 from the step, but $pc will stay the same.
348 // So we detect that here and set the $pc to NULL in that case.
349 // This is the default behavior of the libunwind on Linux.
350 if (st == 0 && CONTEXTGetPC(context) == curPc)
352 CONTEXTSetPC(context, 0);
355 if (contextPointers != NULL)
357 GetContextPointers(&cursor, &unwContext, contextPointers);
363 #error don't know how to unwind on this platform
366 // These methods are only used on the AMD64 build
368 #ifdef HAVE_UNW_GET_ACCESSORS
370 static struct LibunwindCallbacksInfoType
373 ReadMemoryWordCallback readMemCallback;
374 } LibunwindCallbacksInfo;
376 static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dilap, void *arg)
381 static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg)
385 ASSERT("Memory write must never be called by libunwind during stackwalk");
389 // access_mem sometimes gets called by _UPT_find_proc_info, in such cases arg has a pointer to libunwind internal data
390 // returned by _UPT_create. It makes it impossible to use arg for passing readMemCallback. That's why we have to use global variable.
391 if (LibunwindCallbacksInfo.readMemCallback((SIZE_T)addr, (SIZE_T *)valp))
401 static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg)
405 ASSERT("Register write must never be called by libunwind during stackwalk");
406 return -UNW_EREADONLYREG;
409 CONTEXT *winContext = LibunwindCallbacksInfo.Context;
414 case UNW_REG_IP: *valp = (unw_word_t) winContext->Rip; break;
415 case UNW_REG_SP: *valp = (unw_word_t) winContext->Rsp; break;
416 case UNW_X86_64_RBP: *valp = (unw_word_t) winContext->Rbp; break;
417 case UNW_X86_64_RBX: *valp = (unw_word_t) winContext->Rbx; break;
418 case UNW_X86_64_R12: *valp = (unw_word_t) winContext->R12; break;
419 case UNW_X86_64_R13: *valp = (unw_word_t) winContext->R13; break;
420 case UNW_X86_64_R14: *valp = (unw_word_t) winContext->R14; break;
421 case UNW_X86_64_R15: *valp = (unw_word_t) winContext->R15; break;
423 case UNW_ARM_R13: *valp = (unw_word_t) winContext->Sp; break;
424 case UNW_ARM_R14: *valp = (unw_word_t) winContext->Lr; break;
425 case UNW_ARM_R15: *valp = (unw_word_t) winContext->Pc; break;
426 case UNW_ARM_R4: *valp = (unw_word_t) winContext->R4; break;
427 case UNW_ARM_R5: *valp = (unw_word_t) winContext->R5; break;
428 case UNW_ARM_R6: *valp = (unw_word_t) winContext->R6; break;
429 case UNW_ARM_R7: *valp = (unw_word_t) winContext->R7; break;
430 case UNW_ARM_R8: *valp = (unw_word_t) winContext->R8; break;
431 case UNW_ARM_R9: *valp = (unw_word_t) winContext->R9; break;
432 case UNW_ARM_R10: *valp = (unw_word_t) winContext->R10; break;
433 case UNW_ARM_R11: *valp = (unw_word_t) winContext->R11; break;
434 #elif defined(_ARM64_)
435 case UNW_REG_IP: *valp = (unw_word_t) winContext->Pc; break;
436 case UNW_REG_SP: *valp = (unw_word_t) winContext->Sp; break;
437 case UNW_AARCH64_X29: *valp = (unw_word_t) winContext->Fp; break;
438 case UNW_AARCH64_X30: *valp = (unw_word_t) winContext->Lr; break;
439 case UNW_AARCH64_X19: *valp = (unw_word_t) winContext->X19; break;
440 case UNW_AARCH64_X20: *valp = (unw_word_t) winContext->X20; break;
441 case UNW_AARCH64_X21: *valp = (unw_word_t) winContext->X21; break;
442 case UNW_AARCH64_X22: *valp = (unw_word_t) winContext->X22; break;
443 case UNW_AARCH64_X23: *valp = (unw_word_t) winContext->X23; break;
444 case UNW_AARCH64_X24: *valp = (unw_word_t) winContext->X24; break;
445 case UNW_AARCH64_X25: *valp = (unw_word_t) winContext->X25; break;
446 case UNW_AARCH64_X26: *valp = (unw_word_t) winContext->X26; break;
447 case UNW_AARCH64_X27: *valp = (unw_word_t) winContext->X27; break;
448 case UNW_AARCH64_X28: *valp = (unw_word_t) winContext->X28; break;
450 #error unsupported architecture
453 ASSERT("Attempt to read an unknown register.");
459 static int access_fpreg(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *fpvalp, int write, void *arg)
461 ASSERT("Not supposed to be ever called");
465 static int resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
467 ASSERT("Not supposed to be ever called");
471 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)
473 ASSERT("Not supposed to be ever called");
477 int find_proc_info(unw_addr_space_t as,
478 unw_word_t ip, unw_proc_info_t *pip,
479 int need_unwind_info, void *arg)
481 #ifdef HAVE_LIBUNWIND_PTRACE
482 // UNIXTODO: libunwind RPM package on Fedora/CentOS/RedHat doesn't have libunwind-ptrace.so
483 // and we can't use it from a shared library like libmscordaccore.so.
484 // That's why all calls to ptrace parts of libunwind ifdeffed out for now.
485 return _UPT_find_proc_info(as, ip, pip, need_unwind_info, arg);
491 void put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pip, void *arg)
493 #ifdef HAVE_LIBUNWIND_PTRACE
494 return _UPT_put_unwind_info(as, pip, arg);
498 static unw_accessors_t unwind_accessors =
500 .find_proc_info = find_proc_info,
501 .put_unwind_info = put_unwind_info,
502 .get_dyn_info_list_addr = get_dyn_info_list_addr,
503 .access_mem = access_mem,
504 .access_reg = access_reg,
505 .access_fpreg = access_fpreg,
507 .get_proc_name = get_proc_name
510 BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
511 KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
513 ReadMemoryWordCallback readMemCallback)
515 // This function can be executed only by one thread at a time.
516 // The reason for this is that we need to pass context and read mem function to libunwind callbacks
517 // but "arg" is already used by the pointer returned from _UPT_create().
518 // So we resort to using global variables and a lock.
524 // ctor of a static variable is a thread-safe way to initialize critical section exactly once (clang,gcc)
525 InitializeCriticalSection(&cs);
530 CRITICAL_SECTION *cs;
531 LockHolder(CRITICAL_SECTION *cs)
534 EnterCriticalSection(cs);
539 LeaveCriticalSection(cs);
544 LockHolder lockHolder(&lock.cs);
548 unw_addr_space_t addrSpace = 0;
549 void *libunwindUptPtr = NULL;
552 LibunwindCallbacksInfo.Context = context;
553 LibunwindCallbacksInfo.readMemCallback = readMemCallback;
555 addrSpace = unw_create_addr_space(&unwind_accessors, 0);
556 #ifdef HAVE_LIBUNWIND_PTRACE
557 libunwindUptPtr = _UPT_create(pid);
559 st = unw_init_remote(&cursor, addrSpace, libunwindUptPtr);
566 st = unw_step(&cursor);
573 UnwindContextToWinContext(&cursor, context);
575 if (contextPointers != NULL)
577 GetContextPointers(&cursor, NULL, contextPointers);
582 #ifdef HAVE_LIBUNWIND_PTRACE
583 if (libunwindUptPtr != NULL)
585 _UPT_destroy(libunwindUptPtr);
590 unw_destroy_addr_space(addrSpace);
594 #else // HAVE_UNW_GET_ACCESSORS
596 BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
597 KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
599 ReadMemoryWordCallback readMemCallback)
601 //UNIXTODO: Implement for Mac flavor of libunwind
605 #endif // !HAVE_UNW_GET_ACCESSORS
608 struct ExceptionRecords
610 CONTEXT ContextRecord;
611 EXCEPTION_RECORD ExceptionRecord;
614 // Max number of fallback contexts that are used when malloc fails to allocate ExceptionRecords structure
615 static const int MaxFallbackContexts = sizeof(size_t) * 8;
616 // Array of fallback contexts
617 static ExceptionRecords s_fallbackContexts[MaxFallbackContexts];
618 // Bitmap used for allocating fallback contexts - bits set to 1 represent already allocated context.
619 static volatile size_t s_allocatedContextsBitmap = 0;
623 AllocateExceptionRecords
625 Allocate EXCEPTION_RECORD and CONTEXT structures for an exception.
627 exceptionRecord - output pointer to the allocated exception record
628 contextRecord - output pointer to the allocated context record
631 AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord)
633 ExceptionRecords* records;
634 if (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0)
642 bitmap = s_allocatedContextsBitmap;
643 index = __builtin_ffsl(~bitmap) - 1;
649 newBitmap = bitmap | ((size_t)1 << index);
651 while (__sync_val_compare_and_swap(&s_allocatedContextsBitmap, bitmap, newBitmap) != bitmap);
653 records = &s_fallbackContexts[index];
656 *contextRecord = &records->ContextRecord;
657 *exceptionRecord = &records->ExceptionRecord;
662 PAL_FreeExceptionRecords
664 Free EXCEPTION_RECORD and CONTEXT structures of an exception that were allocated by the
665 AllocateExceptionRecords.
667 exceptionRecord - exception record
668 contextRecord - context record
672 PAL_FreeExceptionRecords(IN EXCEPTION_RECORD *exceptionRecord, IN CONTEXT *contextRecord)
674 // Both records are allocated at once and the allocated memory starts at the contextRecord
675 ExceptionRecords* records = (ExceptionRecords*)contextRecord;
676 if ((records >= &s_fallbackContexts[0]) && (records < &s_fallbackContexts[MaxFallbackContexts]))
678 int index = records - &s_fallbackContexts[0];
679 __sync_fetch_and_and(&s_allocatedContextsBitmap, ~((size_t)1 << index));
692 ExceptionRecord - the Windows exception record to throw
695 The name of this function and the name of the ExceptionRecord
696 parameter is used in the sos lldb plugin code to read the exception
697 record. See coreclr\src\ToolBox\SOS\lldbplugin\services.cpp.
699 This function must not be inlined or optimized so the below PAL_VirtualUnwind
700 calls end up with RaiseException caller's context and so the above debugger
701 code finds the function and ExceptionRecord parameter.
704 __attribute__((noinline))
705 __attribute__((optnone))
707 RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord, CONTEXT *ContextRecord)
709 throw PAL_SEHException(ExceptionRecord, ContextRecord);
718 // no PAL_NORETURN, as callers must assume this can return for continuable exceptions.
719 __attribute__((noinline))
722 RaiseException(IN DWORD dwExceptionCode,
723 IN DWORD dwExceptionFlags,
724 IN DWORD nNumberOfArguments,
725 IN CONST ULONG_PTR *lpArguments)
727 // PERF_ENTRY_ONLY is used here because RaiseException may or may not
728 // return. We can not get latency data without PERF_EXIT. For this reason,
729 // PERF_ENTRY_ONLY is used to profile frequency only.
730 PERF_ENTRY_ONLY(RaiseException);
731 ENTRY("RaiseException(dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArguments=%p)\n",
732 dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
734 /* Validate parameters */
735 if (dwExceptionCode & RESERVED_SEH_BIT)
737 WARN("Exception code %08x has bit 28 set; clearing it.\n", dwExceptionCode);
738 dwExceptionCode ^= RESERVED_SEH_BIT;
741 if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS)
743 WARN("Number of arguments (%d) exceeds the limit "
744 "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n",
745 nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS);
746 nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
749 CONTEXT *contextRecord;
750 EXCEPTION_RECORD *exceptionRecord;
751 AllocateExceptionRecords(&exceptionRecord, &contextRecord);
753 ZeroMemory(exceptionRecord, sizeof(EXCEPTION_RECORD));
755 exceptionRecord->ExceptionCode = dwExceptionCode;
756 exceptionRecord->ExceptionFlags = dwExceptionFlags;
757 exceptionRecord->ExceptionRecord = NULL;
758 exceptionRecord->ExceptionAddress = NULL; // will be set by RtlpRaiseException
759 exceptionRecord->NumberParameters = nNumberOfArguments;
760 if (nNumberOfArguments)
762 CopyMemory(exceptionRecord->ExceptionInformation, lpArguments,
763 nNumberOfArguments * sizeof(ULONG_PTR));
766 // Capture the context of RaiseException.
767 ZeroMemory(contextRecord, sizeof(CONTEXT));
768 contextRecord->ContextFlags = CONTEXT_FULL;
769 CONTEXT_CaptureContext(contextRecord);
771 // We have to unwind one level to get the actual context user code could be resumed at.
772 PAL_VirtualUnwind(contextRecord, NULL);
774 exceptionRecord->ExceptionAddress = (void *)CONTEXTGetPC(contextRecord);
776 RtlpRaiseException(exceptionRecord, contextRecord);
778 LOGEXIT("RaiseException returns\n");