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_X86_EBP, (unw_word_t *) &winContext->Ebp);
159 unw_get_reg(cursor, UNW_X86_EBX, (unw_word_t *) &winContext->Ebx);
160 unw_get_reg(cursor, UNW_X86_ESI, (unw_word_t *) &winContext->Esi);
161 unw_get_reg(cursor, UNW_X86_EDI, (unw_word_t *) &winContext->Edi);
163 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
164 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
165 unw_get_reg(cursor, UNW_ARM_R14, (unw_word_t *) &winContext->Lr);
166 unw_get_reg(cursor, UNW_ARM_R4, (unw_word_t *) &winContext->R4);
167 unw_get_reg(cursor, UNW_ARM_R5, (unw_word_t *) &winContext->R5);
168 unw_get_reg(cursor, UNW_ARM_R6, (unw_word_t *) &winContext->R6);
169 unw_get_reg(cursor, UNW_ARM_R7, (unw_word_t *) &winContext->R7);
170 unw_get_reg(cursor, UNW_ARM_R8, (unw_word_t *) &winContext->R8);
171 unw_get_reg(cursor, UNW_ARM_R9, (unw_word_t *) &winContext->R9);
172 unw_get_reg(cursor, UNW_ARM_R10, (unw_word_t *) &winContext->R10);
173 unw_get_reg(cursor, UNW_ARM_R11, (unw_word_t *) &winContext->R11);
174 #elif defined(_ARM64_)
175 unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
176 unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
177 unw_get_reg(cursor, UNW_AARCH64_X29, (unw_word_t *) &winContext->Fp);
178 unw_get_reg(cursor, UNW_AARCH64_X30, (unw_word_t *) &winContext->Lr);
179 unw_get_reg(cursor, UNW_AARCH64_X19, (unw_word_t *) &winContext->X19);
180 unw_get_reg(cursor, UNW_AARCH64_X20, (unw_word_t *) &winContext->X20);
181 unw_get_reg(cursor, UNW_AARCH64_X21, (unw_word_t *) &winContext->X21);
182 unw_get_reg(cursor, UNW_AARCH64_X22, (unw_word_t *) &winContext->X22);
183 unw_get_reg(cursor, UNW_AARCH64_X23, (unw_word_t *) &winContext->X23);
184 unw_get_reg(cursor, UNW_AARCH64_X24, (unw_word_t *) &winContext->X24);
185 unw_get_reg(cursor, UNW_AARCH64_X25, (unw_word_t *) &winContext->X25);
186 unw_get_reg(cursor, UNW_AARCH64_X26, (unw_word_t *) &winContext->X26);
187 unw_get_reg(cursor, UNW_AARCH64_X27, (unw_word_t *) &winContext->X27);
188 unw_get_reg(cursor, UNW_AARCH64_X28, (unw_word_t *) &winContext->X28);
190 #error unsupported architecture
194 static void GetContextPointer(unw_cursor_t *cursor, unw_context_t *unwContext, int reg, SIZE_T **contextPointer)
196 #if defined(HAVE_UNW_GET_SAVE_LOC)
197 unw_save_loc_t saveLoc;
198 unw_get_save_loc(cursor, reg, &saveLoc);
199 if (saveLoc.type == UNW_SLT_MEMORY)
201 SIZE_T *pLoc = (SIZE_T *)saveLoc.u.addr;
202 // Filter out fake save locations that point to unwContext
203 if (unwContext == NULL || (pLoc < (SIZE_T *)unwContext) || ((SIZE_T *)(unwContext + 1) <= pLoc))
204 *contextPointer = (SIZE_T *)saveLoc.u.addr;
207 // Returning NULL indicates that we don't have context pointers available
208 *contextPointer = NULL;
212 static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
215 GetContextPointer(cursor, unwContext, UNW_X86_64_RBP, &contextPointers->Rbp);
216 GetContextPointer(cursor, unwContext, UNW_X86_64_RBX, &contextPointers->Rbx);
217 GetContextPointer(cursor, unwContext, UNW_X86_64_R12, &contextPointers->R12);
218 GetContextPointer(cursor, unwContext, UNW_X86_64_R13, &contextPointers->R13);
219 GetContextPointer(cursor, unwContext, UNW_X86_64_R14, &contextPointers->R14);
220 GetContextPointer(cursor, unwContext, UNW_X86_64_R15, &contextPointers->R15);
222 GetContextPointer(cursor, unwContext, UNW_X86_EBX, &contextPointers->Ebx);
223 GetContextPointer(cursor, unwContext, UNW_X86_EBP, &contextPointers->Ebp);
224 GetContextPointer(cursor, unwContext, UNW_X86_ESI, &contextPointers->Esi);
225 GetContextPointer(cursor, unwContext, UNW_X86_EDI, &contextPointers->Edi);
227 GetContextPointer(cursor, unwContext, UNW_ARM_R4, &contextPointers->R4);
228 GetContextPointer(cursor, unwContext, UNW_ARM_R5, &contextPointers->R5);
229 GetContextPointer(cursor, unwContext, UNW_ARM_R6, &contextPointers->R6);
230 GetContextPointer(cursor, unwContext, UNW_ARM_R7, &contextPointers->R7);
231 GetContextPointer(cursor, unwContext, UNW_ARM_R8, &contextPointers->R8);
232 GetContextPointer(cursor, unwContext, UNW_ARM_R9, &contextPointers->R9);
233 GetContextPointer(cursor, unwContext, UNW_ARM_R10, &contextPointers->R10);
234 GetContextPointer(cursor, unwContext, UNW_ARM_R11, &contextPointers->R11);
235 #elif defined(_ARM64_)
236 GetContextPointer(cursor, unwContext, UNW_AARCH64_X19, &contextPointers->X19);
237 GetContextPointer(cursor, unwContext, UNW_AARCH64_X20, &contextPointers->X20);
238 GetContextPointer(cursor, unwContext, UNW_AARCH64_X21, &contextPointers->X21);
239 GetContextPointer(cursor, unwContext, UNW_AARCH64_X22, &contextPointers->X22);
240 GetContextPointer(cursor, unwContext, UNW_AARCH64_X23, &contextPointers->X23);
241 GetContextPointer(cursor, unwContext, UNW_AARCH64_X24, &contextPointers->X24);
242 GetContextPointer(cursor, unwContext, UNW_AARCH64_X25, &contextPointers->X25);
243 GetContextPointer(cursor, unwContext, UNW_AARCH64_X26, &contextPointers->X26);
244 GetContextPointer(cursor, unwContext, UNW_AARCH64_X27, &contextPointers->X27);
245 GetContextPointer(cursor, unwContext, UNW_AARCH64_X28, &contextPointers->X28);
246 GetContextPointer(cursor, unwContext, UNW_AARCH64_X29, &contextPointers->Fp);
248 #error unsupported architecture
252 extern int g_common_signal_handler_context_locvar_offset;
254 BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
257 unw_context_t unwContext;
260 DWORD64 curPc = CONTEXTGetPC(context);
263 // Check if the PC is the return address from the SEHProcessException in the common_signal_handler.
264 // If that's the case, extract its local variable containing the native_context_t of the hardware
265 // exception and return that. This skips the hardware signal handler trampoline that the libunwind
266 // cannot cross on some systems.
267 if ((void*)curPc == g_SEHProcessExceptionReturnAddress)
269 ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_EXCEPTION_ACTIVE;
272 contextFlags |= CONTEXT_XSTATE;
274 size_t nativeContext = *(size_t*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
275 CONTEXTFromNativeContext((const native_context_t *)nativeContext, context, contextFlags);
281 if ((context->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0)
283 // The current frame is a source of hardware exception. Due to the fact that
284 // we use the low level unwinder to unwind just one frame a time, the
285 // unwinder doesn't have the signal_frame flag set. So it doesn't
286 // know that it should not decrement the PC before looking up the unwind info.
287 // So we compensate it by incrementing the PC before passing it to the unwinder.
288 // Without it, the unwinder would not find unwind info if the hardware exception
289 // happened in the first instruction of a function.
290 CONTEXTSetPC(context, curPc + 1);
293 #if !UNWIND_CONTEXT_IS_UCONTEXT_T
294 st = unw_getcontext(&unwContext);
301 WinContextToUnwindContext(context, &unwContext);
303 st = unw_init_local(&cursor, &unwContext);
309 #if !UNWIND_CONTEXT_IS_UCONTEXT_T
310 // Set the unwind context to the specified windows context
311 WinContextToUnwindCursor(context, &cursor);
314 st = unw_step(&cursor);
320 // Check if the frame we have unwound to is a frame that caused
321 // synchronous signal, like a hardware exception and record it
322 // in the context flags.
323 if (unw_is_signal_frame(&cursor) > 0)
325 context->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
326 #if defined(_ARM_) || defined(_ARM64_) || defined(_X86_)
327 context->ContextFlags &= ~CONTEXT_UNWOUND_TO_CALL;
328 #endif // _ARM_ || _ARM64_
332 context->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE;
333 #if defined(_ARM_) || defined(_ARM64_) || defined(_X86_)
334 context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
335 #endif // _ARM_ || _ARM64_
338 // Update the passed in windows context to reflect the unwind
340 UnwindContextToWinContext(&cursor, context);
342 // FreeBSD, NetBSD, OSX and Alpine appear to do two different things when unwinding
343 // 1: If it reaches where it cannot unwind anymore, say a
344 // managed frame. It will return 0, but also update the $pc
345 // 2: If it unwinds all the way to _start it will return
346 // 0 from the step, but $pc will stay the same.
347 // So we detect that here and set the $pc to NULL in that case.
348 // This is the default behavior of the libunwind on Linux.
349 if (st == 0 && CONTEXTGetPC(context) == curPc)
351 CONTEXTSetPC(context, 0);
354 if (contextPointers != NULL)
356 GetContextPointers(&cursor, &unwContext, contextPointers);
362 #error don't know how to unwind on this platform
365 // These methods are only used on the AMD64 build
367 #ifdef HAVE_UNW_GET_ACCESSORS
369 static struct LibunwindCallbacksInfoType
372 ReadMemoryWordCallback readMemCallback;
373 } LibunwindCallbacksInfo;
375 static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dilap, void *arg)
380 static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg)
384 ASSERT("Memory write must never be called by libunwind during stackwalk");
388 // access_mem sometimes gets called by _UPT_find_proc_info, in such cases arg has a pointer to libunwind internal data
389 // returned by _UPT_create. It makes it impossible to use arg for passing readMemCallback. That's why we have to use global variable.
390 if (LibunwindCallbacksInfo.readMemCallback((SIZE_T)addr, (SIZE_T *)valp))
400 static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg)
404 ASSERT("Register write must never be called by libunwind during stackwalk");
405 return -UNW_EREADONLYREG;
408 CONTEXT *winContext = LibunwindCallbacksInfo.Context;
413 case UNW_REG_IP: *valp = (unw_word_t) winContext->Rip; break;
414 case UNW_REG_SP: *valp = (unw_word_t) winContext->Rsp; break;
415 case UNW_X86_64_RBP: *valp = (unw_word_t) winContext->Rbp; break;
416 case UNW_X86_64_RBX: *valp = (unw_word_t) winContext->Rbx; break;
417 case UNW_X86_64_R12: *valp = (unw_word_t) winContext->R12; break;
418 case UNW_X86_64_R13: *valp = (unw_word_t) winContext->R13; break;
419 case UNW_X86_64_R14: *valp = (unw_word_t) winContext->R14; break;
420 case UNW_X86_64_R15: *valp = (unw_word_t) winContext->R15; break;
422 case UNW_ARM_R13: *valp = (unw_word_t) winContext->Sp; break;
423 case UNW_ARM_R14: *valp = (unw_word_t) winContext->Lr; break;
424 case UNW_ARM_R15: *valp = (unw_word_t) winContext->Pc; break;
425 case UNW_ARM_R4: *valp = (unw_word_t) winContext->R4; break;
426 case UNW_ARM_R5: *valp = (unw_word_t) winContext->R5; break;
427 case UNW_ARM_R6: *valp = (unw_word_t) winContext->R6; break;
428 case UNW_ARM_R7: *valp = (unw_word_t) winContext->R7; break;
429 case UNW_ARM_R8: *valp = (unw_word_t) winContext->R8; break;
430 case UNW_ARM_R9: *valp = (unw_word_t) winContext->R9; break;
431 case UNW_ARM_R10: *valp = (unw_word_t) winContext->R10; break;
432 case UNW_ARM_R11: *valp = (unw_word_t) winContext->R11; break;
433 #elif defined(_ARM64_)
434 case UNW_REG_IP: *valp = (unw_word_t) winContext->Pc; break;
435 case UNW_REG_SP: *valp = (unw_word_t) winContext->Sp; break;
436 case UNW_AARCH64_X29: *valp = (unw_word_t) winContext->Fp; break;
437 case UNW_AARCH64_X30: *valp = (unw_word_t) winContext->Lr; break;
438 case UNW_AARCH64_X19: *valp = (unw_word_t) winContext->X19; break;
439 case UNW_AARCH64_X20: *valp = (unw_word_t) winContext->X20; break;
440 case UNW_AARCH64_X21: *valp = (unw_word_t) winContext->X21; break;
441 case UNW_AARCH64_X22: *valp = (unw_word_t) winContext->X22; break;
442 case UNW_AARCH64_X23: *valp = (unw_word_t) winContext->X23; break;
443 case UNW_AARCH64_X24: *valp = (unw_word_t) winContext->X24; break;
444 case UNW_AARCH64_X25: *valp = (unw_word_t) winContext->X25; break;
445 case UNW_AARCH64_X26: *valp = (unw_word_t) winContext->X26; break;
446 case UNW_AARCH64_X27: *valp = (unw_word_t) winContext->X27; break;
447 case UNW_AARCH64_X28: *valp = (unw_word_t) winContext->X28; break;
449 #error unsupported architecture
452 ASSERT("Attempt to read an unknown register.");
458 static int access_fpreg(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *fpvalp, int write, void *arg)
460 ASSERT("Not supposed to be ever called");
464 static int resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
466 ASSERT("Not supposed to be ever called");
470 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)
472 ASSERT("Not supposed to be ever called");
476 int find_proc_info(unw_addr_space_t as,
477 unw_word_t ip, unw_proc_info_t *pip,
478 int need_unwind_info, void *arg)
480 #ifdef HAVE_LIBUNWIND_PTRACE
481 // UNIXTODO: libunwind RPM package on Fedora/CentOS/RedHat doesn't have libunwind-ptrace.so
482 // and we can't use it from a shared library like libmscordaccore.so.
483 // That's why all calls to ptrace parts of libunwind ifdeffed out for now.
484 return _UPT_find_proc_info(as, ip, pip, need_unwind_info, arg);
490 void put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pip, void *arg)
492 #ifdef HAVE_LIBUNWIND_PTRACE
493 return _UPT_put_unwind_info(as, pip, arg);
497 static unw_accessors_t unwind_accessors =
499 .find_proc_info = find_proc_info,
500 .put_unwind_info = put_unwind_info,
501 .get_dyn_info_list_addr = get_dyn_info_list_addr,
502 .access_mem = access_mem,
503 .access_reg = access_reg,
504 .access_fpreg = access_fpreg,
506 .get_proc_name = get_proc_name
509 BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
510 KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
512 ReadMemoryWordCallback readMemCallback)
514 // This function can be executed only by one thread at a time.
515 // The reason for this is that we need to pass context and read mem function to libunwind callbacks
516 // but "arg" is already used by the pointer returned from _UPT_create().
517 // So we resort to using global variables and a lock.
523 // ctor of a static variable is a thread-safe way to initialize critical section exactly once (clang,gcc)
524 InitializeCriticalSection(&cs);
529 CRITICAL_SECTION *cs;
530 LockHolder(CRITICAL_SECTION *cs)
533 EnterCriticalSection(cs);
538 LeaveCriticalSection(cs);
543 LockHolder lockHolder(&lock.cs);
547 unw_addr_space_t addrSpace = 0;
548 void *libunwindUptPtr = NULL;
551 LibunwindCallbacksInfo.Context = context;
552 LibunwindCallbacksInfo.readMemCallback = readMemCallback;
554 addrSpace = unw_create_addr_space(&unwind_accessors, 0);
555 #ifdef HAVE_LIBUNWIND_PTRACE
556 libunwindUptPtr = _UPT_create(pid);
558 st = unw_init_remote(&cursor, addrSpace, libunwindUptPtr);
565 st = unw_step(&cursor);
572 UnwindContextToWinContext(&cursor, context);
574 if (contextPointers != NULL)
576 GetContextPointers(&cursor, NULL, contextPointers);
581 #ifdef HAVE_LIBUNWIND_PTRACE
582 if (libunwindUptPtr != NULL)
584 _UPT_destroy(libunwindUptPtr);
589 unw_destroy_addr_space(addrSpace);
593 #else // HAVE_UNW_GET_ACCESSORS
595 BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
596 KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
598 ReadMemoryWordCallback readMemCallback)
600 //UNIXTODO: Implement for Mac flavor of libunwind
604 #endif // !HAVE_UNW_GET_ACCESSORS
607 struct ExceptionRecords
609 CONTEXT ContextRecord;
610 EXCEPTION_RECORD ExceptionRecord;
613 // Max number of fallback contexts that are used when malloc fails to allocate ExceptionRecords structure
614 static const int MaxFallbackContexts = sizeof(size_t) * 8;
615 // Array of fallback contexts
616 static ExceptionRecords s_fallbackContexts[MaxFallbackContexts];
617 // Bitmap used for allocating fallback contexts - bits set to 1 represent already allocated context.
618 static volatile size_t s_allocatedContextsBitmap = 0;
622 AllocateExceptionRecords
624 Allocate EXCEPTION_RECORD and CONTEXT structures for an exception.
626 exceptionRecord - output pointer to the allocated exception record
627 contextRecord - output pointer to the allocated context record
630 AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord)
632 ExceptionRecords* records;
633 if (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0)
641 bitmap = s_allocatedContextsBitmap;
642 index = __builtin_ffsl(~bitmap) - 1;
648 newBitmap = bitmap | ((size_t)1 << index);
650 while (__sync_val_compare_and_swap(&s_allocatedContextsBitmap, bitmap, newBitmap) != bitmap);
652 records = &s_fallbackContexts[index];
655 *contextRecord = &records->ContextRecord;
656 *exceptionRecord = &records->ExceptionRecord;
661 PAL_FreeExceptionRecords
663 Free EXCEPTION_RECORD and CONTEXT structures of an exception that were allocated by the
664 AllocateExceptionRecords.
666 exceptionRecord - exception record
667 contextRecord - context record
671 PAL_FreeExceptionRecords(IN EXCEPTION_RECORD *exceptionRecord, IN CONTEXT *contextRecord)
673 // Both records are allocated at once and the allocated memory starts at the contextRecord
674 ExceptionRecords* records = (ExceptionRecords*)contextRecord;
675 if ((records >= &s_fallbackContexts[0]) && (records < &s_fallbackContexts[MaxFallbackContexts]))
677 int index = records - &s_fallbackContexts[0];
678 __sync_fetch_and_and(&s_allocatedContextsBitmap, ~((size_t)1 << index));
691 ExceptionRecord - the Windows exception record to throw
694 The name of this function and the name of the ExceptionRecord
695 parameter is used in the sos lldb plugin code to read the exception
696 record. See coreclr\src\ToolBox\SOS\lldbplugin\services.cpp.
698 This function must not be inlined or optimized so the below PAL_VirtualUnwind
699 calls end up with RaiseException caller's context and so the above debugger
700 code finds the function and ExceptionRecord parameter.
703 __attribute__((noinline))
704 __attribute__((optnone))
706 RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord, CONTEXT *ContextRecord)
708 throw PAL_SEHException(ExceptionRecord, ContextRecord);
717 // no PAL_NORETURN, as callers must assume this can return for continuable exceptions.
718 __attribute__((noinline))
721 RaiseException(IN DWORD dwExceptionCode,
722 IN DWORD dwExceptionFlags,
723 IN DWORD nNumberOfArguments,
724 IN CONST ULONG_PTR *lpArguments)
726 // PERF_ENTRY_ONLY is used here because RaiseException may or may not
727 // return. We can not get latency data without PERF_EXIT. For this reason,
728 // PERF_ENTRY_ONLY is used to profile frequency only.
729 PERF_ENTRY_ONLY(RaiseException);
730 ENTRY("RaiseException(dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArguments=%p)\n",
731 dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
733 /* Validate parameters */
734 if (dwExceptionCode & RESERVED_SEH_BIT)
736 WARN("Exception code %08x has bit 28 set; clearing it.\n", dwExceptionCode);
737 dwExceptionCode ^= RESERVED_SEH_BIT;
740 if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS)
742 WARN("Number of arguments (%d) exceeds the limit "
743 "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n",
744 nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS);
745 nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
748 CONTEXT *contextRecord;
749 EXCEPTION_RECORD *exceptionRecord;
750 AllocateExceptionRecords(&exceptionRecord, &contextRecord);
752 ZeroMemory(exceptionRecord, sizeof(EXCEPTION_RECORD));
754 exceptionRecord->ExceptionCode = dwExceptionCode;
755 exceptionRecord->ExceptionFlags = dwExceptionFlags;
756 exceptionRecord->ExceptionRecord = NULL;
757 exceptionRecord->ExceptionAddress = NULL; // will be set by RtlpRaiseException
758 exceptionRecord->NumberParameters = nNumberOfArguments;
759 if (nNumberOfArguments)
761 CopyMemory(exceptionRecord->ExceptionInformation, lpArguments,
762 nNumberOfArguments * sizeof(ULONG_PTR));
765 // Capture the context of RaiseException.
766 ZeroMemory(contextRecord, sizeof(CONTEXT));
767 contextRecord->ContextFlags = CONTEXT_FULL;
768 CONTEXT_CaptureContext(contextRecord);
770 // We have to unwind one level to get the actual context user code could be resumed at.
771 PAL_VirtualUnwind(contextRecord, NULL);
773 exceptionRecord->ExceptionAddress = (void *)CONTEXTGetPC(contextRecord);
775 RtlpRaiseException(exceptionRecord, contextRecord);
777 LOGEXIT("RaiseException returns\n");