2 * msvcrt C++ exception handling
4 * Copyright 2011 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
29 #define WIN32_NO_STATUS
34 #include "wine/exception.h"
36 #include "wine/debug.h"
38 #include "cppexcept.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
42 struct _DISPATCHER_CONTEXT
;
44 typedef LONG (WINAPI
*PC_LANGUAGE_EXCEPTION_HANDLER
)( EXCEPTION_POINTERS
*ptrs
, ULONG64 frame
);
45 typedef EXCEPTION_DISPOSITION (WINAPI
*PEXCEPTION_ROUTINE
)( EXCEPTION_RECORD
*rec
,
48 struct _DISPATCHER_CONTEXT
*dispatch
);
50 typedef struct _DISPATCHER_CONTEXT
54 PRUNTIME_FUNCTION FunctionEntry
;
55 ULONG64 EstablisherFrame
;
57 PCONTEXT ContextRecord
;
58 PEXCEPTION_ROUTINE LanguageHandler
;
60 PUNWIND_HISTORY_TABLE HistoryTable
;
78 #define TYPE_FLAG_CONST 1
79 #define TYPE_FLAG_VOLATILE 2
80 #define TYPE_FLAG_REFERENCE 8
97 typedef struct __cxx_function_descr
109 } cxx_function_descr
;
111 static inline void* rva_to_ptr(UINT rva
, ULONG64 base
)
113 return rva
? (void*)(base
+rva
) : NULL
;
116 static inline void dump_type(UINT type_rva
, ULONG64 base
)
118 const cxx_type_info
*type
= rva_to_ptr(type_rva
, base
);
120 TRACE("flags %x type %x %s offsets %d,%d,%d size %d copy ctor %x(%p)\n",
121 type
->flags
, type
->type_info
, dbgstr_type_info(rva_to_ptr(type
->type_info
, base
)),
122 type
->offsets
.this_offset
, type
->offsets
.vbase_descr
, type
->offsets
.vbase_offset
,
123 type
->size
, type
->copy_ctor
, rva_to_ptr(type
->copy_ctor
, base
));
126 static void dump_exception_type(const cxx_exception_type
*type
, ULONG64 base
)
128 const cxx_type_info_table
*type_info_table
= rva_to_ptr(type
->type_info_table
, base
);
131 TRACE("flags %x destr %x(%p) handler %x(%p) type info %x(%p)\n",
132 type
->flags
, type
->destructor
, rva_to_ptr(type
->destructor
, base
),
133 type
->custom_handler
, rva_to_ptr(type
->custom_handler
, base
),
134 type
->type_info_table
, type_info_table
);
135 for (i
= 0; i
< type_info_table
->count
; i
++)
138 dump_type(type_info_table
->info
[i
], base
);
142 static void dump_function_descr(const cxx_function_descr
*descr
, ULONG64 image_base
)
144 unwind_info
*unwind_table
= rva_to_ptr(descr
->unwind_table
, image_base
);
145 tryblock_info
*tryblock
= rva_to_ptr(descr
->tryblock
, image_base
);
146 ipmap_info
*ipmap
= rva_to_ptr(descr
->ipmap
, image_base
);
149 TRACE("magic %x\n", descr
->magic
);
150 TRACE("unwind table: %x(%p) %d\n", descr
->unwind_table
, unwind_table
, descr
->unwind_count
);
151 for (i
=0; i
<descr
->unwind_count
; i
++)
153 TRACE(" %d: prev %d func %x(%p)\n", i
, unwind_table
[i
].prev
,
154 unwind_table
[i
].handler
, rva_to_ptr(unwind_table
[i
].handler
, image_base
));
156 TRACE("try table: %x(%p) %d\n", descr
->tryblock
, tryblock
, descr
->tryblock_count
);
157 for (i
=0; i
<descr
->tryblock_count
; i
++)
159 catchblock_info
*catchblock
= rva_to_ptr(tryblock
[i
].catchblock
, image_base
);
161 TRACE(" %d: start %d end %d catchlevel %d catch %x(%p) %d\n", i
,
162 tryblock
[i
].start_level
, tryblock
[i
].end_level
,
163 tryblock
[i
].catch_level
, tryblock
[i
].catchblock
,
164 catchblock
, tryblock
[i
].catchblock_count
);
165 for (j
=0; j
<tryblock
[i
].catchblock_count
; j
++)
167 TRACE(" %d: flags %x offset %d handler %x(%p) frame %x type %x %s\n",
168 j
, catchblock
[j
].flags
, catchblock
[j
].offset
, catchblock
[j
].handler
,
169 rva_to_ptr(catchblock
[j
].handler
, image_base
), catchblock
[j
].frame
,
170 catchblock
[j
].type_info
,
171 dbgstr_type_info(rva_to_ptr(catchblock
[j
].type_info
, image_base
)));
174 TRACE("ipmap: %x(%p) %d\n", descr
->ipmap
, ipmap
, descr
->ipmap_count
);
175 for (i
=0; i
<descr
->ipmap_count
; i
++)
177 TRACE(" %d: ip %x state %d\n", i
, ipmap
[i
].ip
, ipmap
[i
].state
);
179 TRACE("unwind_help %d\n", descr
->unwind_help
);
180 if (descr
->magic
<= CXX_FRAME_MAGIC_VC6
) return;
181 TRACE("expect list: %x\n", descr
->expect_list
);
182 if (descr
->magic
<= CXX_FRAME_MAGIC_VC7
) return;
183 TRACE("flags: %08x\n", descr
->flags
);
186 static inline int ip_to_state(ipmap_info
*ipmap
, UINT count
, int ip
)
188 UINT low
= 0, high
= count
-1, med
;
191 med
= low
+ (high
-low
)/2;
193 if (ipmap
[med
].ip
<= ip
&& ipmap
[med
+1].ip
> ip
)
198 if (ipmap
[med
].ip
< ip
) low
= med
+1;
202 TRACE("%x -> %d\n", ip
, ipmap
[low
].state
);
203 return ipmap
[low
].state
;
206 /* check if the exception type is caught by a given catch block, and return the type that matched */
207 static const cxx_type_info
*find_caught_type(cxx_exception_type
*exc_type
, ULONG64 exc_base
,
208 const type_info
*catch_ti
, UINT catch_flags
)
210 const cxx_type_info_table
*type_info_table
= rva_to_ptr(exc_type
->type_info_table
, exc_base
);
213 for (i
= 0; i
< type_info_table
->count
; i
++)
215 const cxx_type_info
*type
= rva_to_ptr(type_info_table
->info
[i
], exc_base
);
216 const type_info
*ti
= rva_to_ptr(type
->type_info
, exc_base
);
218 if (!catch_ti
) return type
; /* catch(...) matches any type */
221 if (strcmp( catch_ti
->mangled
, ti
->mangled
)) continue;
223 /* type is the same, now check the flags */
224 if ((exc_type
->flags
& TYPE_FLAG_CONST
) &&
225 !(catch_flags
& TYPE_FLAG_CONST
)) continue;
226 if ((exc_type
->flags
& TYPE_FLAG_VOLATILE
) &&
227 !(catch_flags
& TYPE_FLAG_VOLATILE
)) continue;
228 return type
; /* it matched */
233 static inline void copy_exception(void *object
, ULONG64 frame
,
234 DISPATCHER_CONTEXT
*dispatch
,
235 const catchblock_info
*catchblock
,
236 const cxx_type_info
*type
)
238 const type_info
*catch_ti
= rva_to_ptr(catchblock
->type_info
, dispatch
->ImageBase
);
239 void **dest
= rva_to_ptr(catchblock
->offset
, frame
);
241 if (!catch_ti
|| !catch_ti
->mangled
[0]) return;
242 if (!catchblock
->offset
) return;
244 if (catchblock
->flags
& TYPE_FLAG_REFERENCE
)
246 *dest
= get_this_pointer(&type
->offsets
, object
);
248 else if (type
->flags
& CLASS_IS_SIMPLE_TYPE
)
250 memmove(dest
, object
, type
->size
);
251 /* if it is a pointer, adjust it */
252 if (type
->size
== sizeof(void*)) *dest
= get_this_pointer(&type
->offsets
, *dest
);
254 else /* copy the object */
258 if (type
->flags
& CLASS_HAS_VIRTUAL_BASE_CLASS
)
260 void (__cdecl
*copy_ctor
)(void*, void*, int) =
261 rva_to_ptr(type
->copy_ctor
, dispatch
->ImageBase
);
262 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
), 1);
266 void (__cdecl
*copy_ctor
)(void*, void*) =
267 rva_to_ptr(type
->copy_ctor
, dispatch
->ImageBase
);
268 copy_ctor(dest
, get_this_pointer(&type
->offsets
, object
));
272 memmove(dest
, get_this_pointer(&type
->offsets
,object
), type
->size
);
276 static void cxx_local_unwind(ULONG64 frame
, DISPATCHER_CONTEXT
*dispatch
,
277 const cxx_function_descr
*descr
, int last_level
)
279 const unwind_info
*unwind_table
= rva_to_ptr(descr
->unwind_table
, dispatch
->ImageBase
);
280 void (__cdecl
*handler
)(ULONG64 unk
, ULONG64 rbp
);
281 int *unwind_help
= rva_to_ptr(descr
->unwind_help
, frame
);
284 if (unwind_help
[0] == -2)
286 trylevel
= ip_to_state(rva_to_ptr(descr
->ipmap
, dispatch
->ImageBase
),
287 descr
->ipmap_count
, dispatch
->ControlPc
-dispatch
->ImageBase
);
291 trylevel
= unwind_help
[0];
294 TRACE("current level: %d, last level: %d\n", trylevel
, last_level
);
295 while (trylevel
!= last_level
)
297 if (trylevel
<0 || trylevel
>=descr
->unwind_count
)
299 ERR("invalid trylevel %d\n", trylevel
);
302 handler
= rva_to_ptr(unwind_table
[trylevel
].handler
, dispatch
->ImageBase
);
305 TRACE("handler: %p\n", handler
);
308 trylevel
= unwind_table
[trylevel
].prev
;
310 unwind_help
[0] = last_level
;
313 static inline void* WINAPI
call_catch_block(EXCEPTION_RECORD
*rec
)
315 ULONG64 frame
= rec
->ExceptionInformation
[1];
316 const cxx_function_descr
*descr
= (void*)rec
->ExceptionInformation
[2];
317 EXCEPTION_RECORD
*prev_rec
= (void*)rec
->ExceptionInformation
[4];
318 void* (__cdecl
*handler
)(ULONG64 unk
, ULONG64 rbp
) = (void*)rec
->ExceptionInformation
[5];
319 int *unwind_help
= rva_to_ptr(descr
->unwind_help
, frame
);
320 cxx_frame_info frame_info
;
323 TRACE("calling handler %p\n", handler
);
325 /* FIXME: native does local_unwind here in case of exception rethrow */
326 __CxxRegisterExceptionObject(&prev_rec
, &frame_info
);
327 ret_addr
= handler(0, frame
);
328 __CxxUnregisterExceptionObject(&frame_info
, FALSE
);
334 static inline BOOL
cxx_is_consolidate(const EXCEPTION_RECORD
*rec
)
336 return rec
->ExceptionCode
==STATUS_UNWIND_CONSOLIDATE
&& rec
->NumberParameters
==6 &&
337 rec
->ExceptionInformation
[0]==(ULONG_PTR
)call_catch_block
;
340 static inline void find_catch_block(EXCEPTION_RECORD
*rec
, ULONG64 frame
,
341 DISPATCHER_CONTEXT
*dispatch
,
342 const cxx_function_descr
*descr
,
343 cxx_exception_type
*info
, ULONG64 orig_frame
)
345 ULONG64 exc_base
= (rec
->NumberParameters
== 4 ? rec
->ExceptionInformation
[3] : 0);
346 int trylevel
= ip_to_state(rva_to_ptr(descr
->ipmap
, dispatch
->ImageBase
),
347 descr
->ipmap_count
, dispatch
->ControlPc
-dispatch
->ImageBase
);
348 const tryblock_info
*in_catch
;
349 EXCEPTION_RECORD catch_record
;
354 for (i
=descr
->tryblock_count
; i
>0; i
--)
356 in_catch
= rva_to_ptr(descr
->tryblock
, dispatch
->ImageBase
);
357 in_catch
= &in_catch
[i
-1];
359 if (trylevel
>in_catch
->end_level
&& trylevel
<=in_catch
->catch_level
)
365 unwind_help
= rva_to_ptr(descr
->unwind_help
, orig_frame
);
366 if (trylevel
> unwind_help
[1])
367 unwind_help
[0] = unwind_help
[1] = trylevel
;
369 trylevel
= unwind_help
[1];
370 TRACE("current trylevel: %d\n", trylevel
);
372 for (i
=0; i
<descr
->tryblock_count
; i
++)
374 const tryblock_info
*tryblock
= rva_to_ptr(descr
->tryblock
, dispatch
->ImageBase
);
375 tryblock
= &tryblock
[i
];
377 if (trylevel
< tryblock
->start_level
) continue;
378 if (trylevel
> tryblock
->end_level
) continue;
382 if(tryblock
->start_level
<= in_catch
->end_level
) continue;
383 if(tryblock
->end_level
> in_catch
->catch_level
) continue;
386 /* got a try block */
387 for (j
=0; j
<tryblock
->catchblock_count
; j
++)
389 const catchblock_info
*catchblock
= rva_to_ptr(tryblock
->catchblock
, dispatch
->ImageBase
);
390 catchblock
= &catchblock
[j
];
394 const cxx_type_info
*type
= find_caught_type(info
, exc_base
,
395 rva_to_ptr(catchblock
->type_info
, dispatch
->ImageBase
),
399 TRACE("matched type %p in tryblock %d catchblock %d\n", type
, i
, j
);
401 /* copy the exception to its destination on the stack */
402 copy_exception((void*)rec
->ExceptionInformation
[1],
403 orig_frame
, dispatch
, catchblock
, type
);
407 /* no CXX_EXCEPTION only proceed with a catch(...) block*/
408 if (catchblock
->type_info
)
410 TRACE("found catch(...) block\n");
413 /* unwind stack and call catch */
414 memset(&catch_record
, 0, sizeof(catch_record
));
415 catch_record
.ExceptionCode
= STATUS_UNWIND_CONSOLIDATE
;
416 catch_record
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
417 catch_record
.NumberParameters
= 6;
418 catch_record
.ExceptionInformation
[0] = (ULONG_PTR
)call_catch_block
;
419 catch_record
.ExceptionInformation
[1] = orig_frame
;
420 catch_record
.ExceptionInformation
[2] = (ULONG_PTR
)descr
;
421 catch_record
.ExceptionInformation
[3] = tryblock
->start_level
;
422 catch_record
.ExceptionInformation
[4] = (ULONG_PTR
)rec
;
423 catch_record
.ExceptionInformation
[5] =
424 (ULONG_PTR
)rva_to_ptr(catchblock
->handler
, dispatch
->ImageBase
);
425 RtlUnwindEx((void*)frame
, (void*)dispatch
->ControlPc
, &catch_record
, NULL
, &context
, NULL
);
429 TRACE("no matching catch block found\n");
432 static DWORD
cxx_frame_handler(EXCEPTION_RECORD
*rec
, ULONG64 frame
,
433 CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
,
434 const cxx_function_descr
*descr
)
436 int trylevel
= ip_to_state(rva_to_ptr(descr
->ipmap
, dispatch
->ImageBase
),
437 descr
->ipmap_count
, dispatch
->ControlPc
-dispatch
->ImageBase
);
438 cxx_exception_type
*exc_type
;
439 ULONG64 orig_frame
= frame
;
441 DWORD throw_func_off
;
445 if (descr
->magic
<CXX_FRAME_MAGIC_VC6
|| descr
->magic
>CXX_FRAME_MAGIC_VC8
)
447 FIXME("unhandled frame magic %x\n", descr
->magic
);
448 return ExceptionContinueSearch
;
451 if (descr
->magic
>= CXX_FRAME_MAGIC_VC8
&&
452 (descr
->flags
& FUNC_DESCR_SYNCHRONOUS
) &&
453 (rec
->ExceptionCode
!= CXX_EXCEPTION
&&
454 !cxx_is_consolidate(rec
) &&
455 rec
->ExceptionCode
!= STATUS_LONGJUMP
))
456 return ExceptionContinueSearch
; /* handle only c++ exceptions */
458 /* update orig_frame if it's a nested exception */
459 throw_func_off
= RtlLookupFunctionEntry(dispatch
->ControlPc
, &throw_base
, NULL
)->BeginAddress
;
460 throw_func
= rva_to_ptr(throw_func_off
, throw_base
);
461 TRACE("reconstructed handler pointer: %p\n", throw_func
);
462 for (i
=descr
->tryblock_count
; i
>0; i
--)
464 const tryblock_info
*tryblock
= rva_to_ptr(descr
->tryblock
, dispatch
->ImageBase
);
465 tryblock
= &tryblock
[i
-1];
467 if (trylevel
>tryblock
->end_level
&& trylevel
<=tryblock
->catch_level
)
469 for (j
=0; j
<tryblock
->catchblock_count
; j
++)
471 const catchblock_info
*catchblock
= rva_to_ptr(tryblock
->catchblock
, dispatch
->ImageBase
);
472 catchblock
= &catchblock
[j
];
474 if (rva_to_ptr(catchblock
->handler
, dispatch
->ImageBase
) == throw_func
)
476 TRACE("nested exception detected\n");
477 orig_frame
= *(ULONG64
*)rva_to_ptr(catchblock
->frame
, frame
);
478 TRACE("setting orig_frame to %lx\n", orig_frame
);
484 if (rec
->ExceptionFlags
& (EH_UNWINDING
|EH_EXIT_UNWIND
))
486 if (cxx_is_consolidate(rec
))
488 EXCEPTION_RECORD
*new_rec
= (void*)rec
->ExceptionInformation
[4];
489 thread_data_t
*data
= msvcrt_get_thread_data();
492 if (rec
->ExceptionFlags
& EH_TARGET_UNWIND
)
494 const cxx_function_descr
*orig_descr
= (void*)rec
->ExceptionInformation
[2];
495 int end_level
= rec
->ExceptionInformation
[3];
496 orig_frame
= rec
->ExceptionInformation
[1];
498 cxx_local_unwind(orig_frame
, dispatch
, orig_descr
, end_level
);
500 else if(frame
== orig_frame
)
501 cxx_local_unwind(frame
, dispatch
, descr
, -1);
503 /* FIXME: we should only unregister frames registered by call_catch_block here */
504 for (cur
= data
->frame_info_head
; cur
; cur
= cur
->next
)
506 if ((ULONG64
)cur
<= frame
)
508 __CxxUnregisterExceptionObject((cxx_frame_info
*)cur
,
509 new_rec
->ExceptionCode
== CXX_EXCEPTION
&&
510 data
->exc_record
->ExceptionCode
== CXX_EXCEPTION
&&
511 new_rec
->ExceptionInformation
[1] == data
->exc_record
->ExceptionInformation
[1]);
514 return ExceptionContinueSearch
;
517 if (frame
== orig_frame
)
518 cxx_local_unwind(frame
, dispatch
, descr
, -1);
519 return ExceptionContinueSearch
;
521 if (!descr
->tryblock_count
) return ExceptionContinueSearch
;
523 if (rec
->ExceptionCode
== CXX_EXCEPTION
&&
524 rec
->ExceptionInformation
[1] == 0 && rec
->ExceptionInformation
[2] == 0)
526 *rec
= *msvcrt_get_thread_data()->exc_record
;
527 rec
->ExceptionFlags
&= ~EH_UNWINDING
;
529 TRACE("detect rethrow: exception code: %x\n", rec
->ExceptionCode
);
530 if (rec
->ExceptionCode
== CXX_EXCEPTION
)
531 TRACE("re-propage: obj: %lx, type: %lx\n",
532 rec
->ExceptionInformation
[1], rec
->ExceptionInformation
[2]);
536 if (rec
->ExceptionCode
== CXX_EXCEPTION
)
538 exc_type
= (cxx_exception_type
*)rec
->ExceptionInformation
[2];
542 TRACE("handling C++ exception rec %p frame %lx descr %p\n", rec
, frame
, descr
);
543 dump_exception_type(exc_type
, rec
->ExceptionInformation
[3]);
544 dump_function_descr(descr
, dispatch
->ImageBase
);
549 thread_data_t
*data
= msvcrt_get_thread_data();
552 TRACE("handling C exception code %x rec %p frame %lx descr %p\n",
553 rec
->ExceptionCode
, rec
, frame
, descr
);
555 if (data
->se_translator
) {
556 EXCEPTION_POINTERS except_ptrs
;
558 except_ptrs
.ExceptionRecord
= rec
;
559 except_ptrs
.ContextRecord
= context
;
560 data
->se_translator(rec
->ExceptionCode
, &except_ptrs
);
564 find_catch_block(rec
, frame
, dispatch
, descr
, exc_type
, orig_frame
);
565 return ExceptionContinueSearch
;
568 /*********************************************************************
569 * __CxxExceptionFilter (MSVCRT.@)
571 int CDECL
__CxxExceptionFilter( PEXCEPTION_POINTERS ptrs
,
572 const type_info
*ti
, int flags
, void **copy
)
574 FIXME( "%p %p %x %p: not implemented\n", ptrs
, ti
, flags
, copy
);
575 return EXCEPTION_CONTINUE_SEARCH
;
578 /*********************************************************************
579 * __CxxFrameHandler (MSVCRT.@)
581 EXCEPTION_DISPOSITION CDECL
__CxxFrameHandler( EXCEPTION_RECORD
*rec
, ULONG64 frame
,
582 CONTEXT
*context
, DISPATCHER_CONTEXT
*dispatch
)
584 TRACE( "%p %lx %p %p\n", rec
, frame
, context
, dispatch
);
585 return cxx_frame_handler( rec
, frame
, context
, dispatch
,
586 rva_to_ptr(*(UINT
*)dispatch
->HandlerData
, dispatch
->ImageBase
) );
590 /*********************************************************************
591 * __CppXcptFilter (MSVCRT.@)
593 int CDECL
__CppXcptFilter(NTSTATUS ex
, PEXCEPTION_POINTERS ptr
)
595 /* only filter c++ exceptions */
596 if (ex
!= CXX_EXCEPTION
) return EXCEPTION_CONTINUE_SEARCH
;
597 return _XcptFilter( ex
, ptr
);
601 /*********************************************************************
602 * __CxxDetectRethrow (MSVCRT.@)
604 BOOL CDECL
__CxxDetectRethrow(PEXCEPTION_POINTERS ptrs
)
606 PEXCEPTION_RECORD rec
;
611 rec
= ptrs
->ExceptionRecord
;
613 if (rec
->ExceptionCode
== CXX_EXCEPTION
&&
614 rec
->NumberParameters
== 4 &&
615 rec
->ExceptionInformation
[0] == CXX_FRAME_MAGIC_VC6
&&
616 rec
->ExceptionInformation
[2])
618 ptrs
->ExceptionRecord
= msvcrt_get_thread_data()->exc_record
;
621 return (msvcrt_get_thread_data()->exc_record
== rec
);
625 /*********************************************************************
626 * __CxxQueryExceptionSize (MSVCRT.@)
628 unsigned int CDECL
__CxxQueryExceptionSize(void)
630 return sizeof(cxx_exception_type
);
634 /*******************************************************************
637 __ASM_GLOBAL_FUNC( MSVCRT__setjmp
,
638 "jmp " __ASM_NAME("MSVCRT__setjmpex") );
640 /*******************************************************************
641 * _setjmpex (MSVCRT.@)
643 __ASM_GLOBAL_FUNC( MSVCRT__setjmpex
,
644 "movq %rdx,(%rcx)\n\t" /* jmp_buf->Frame */
645 "movq %rbx,0x8(%rcx)\n\t" /* jmp_buf->Rbx */
646 "leaq 0x8(%rsp),%rax\n\t"
647 "movq %rax,0x10(%rcx)\n\t" /* jmp_buf->Rsp */
648 "movq %rbp,0x18(%rcx)\n\t" /* jmp_buf->Rbp */
649 "movq %rsi,0x20(%rcx)\n\t" /* jmp_buf->Rsi */
650 "movq %rdi,0x28(%rcx)\n\t" /* jmp_buf->Rdi */
651 "movq %r12,0x30(%rcx)\n\t" /* jmp_buf->R12 */
652 "movq %r13,0x38(%rcx)\n\t" /* jmp_buf->R13 */
653 "movq %r14,0x40(%rcx)\n\t" /* jmp_buf->R14 */
654 "movq %r15,0x48(%rcx)\n\t" /* jmp_buf->R15 */
655 "movq (%rsp),%rax\n\t"
656 "movq %rax,0x50(%rcx)\n\t" /* jmp_buf->Rip */
657 "movdqa %xmm6,0x60(%rcx)\n\t" /* jmp_buf->Xmm6 */
658 "movdqa %xmm7,0x70(%rcx)\n\t" /* jmp_buf->Xmm7 */
659 "movdqa %xmm8,0x80(%rcx)\n\t" /* jmp_buf->Xmm8 */
660 "movdqa %xmm9,0x90(%rcx)\n\t" /* jmp_buf->Xmm9 */
661 "movdqa %xmm10,0xa0(%rcx)\n\t" /* jmp_buf->Xmm10 */
662 "movdqa %xmm11,0xb0(%rcx)\n\t" /* jmp_buf->Xmm11 */
663 "movdqa %xmm12,0xc0(%rcx)\n\t" /* jmp_buf->Xmm12 */
664 "movdqa %xmm13,0xd0(%rcx)\n\t" /* jmp_buf->Xmm13 */
665 "movdqa %xmm14,0xe0(%rcx)\n\t" /* jmp_buf->Xmm14 */
666 "movdqa %xmm15,0xf0(%rcx)\n\t" /* jmp_buf->Xmm15 */
671 extern void DECLSPEC_NORETURN CDECL
longjmp_set_regs( struct MSVCRT___JUMP_BUFFER
*jmp
, int retval
);
672 __ASM_GLOBAL_FUNC( longjmp_set_regs
,
673 "movq %rdx,%rax\n\t" /* retval */
674 "movq 0x8(%rcx),%rbx\n\t" /* jmp_buf->Rbx */
675 "movq 0x18(%rcx),%rbp\n\t" /* jmp_buf->Rbp */
676 "movq 0x20(%rcx),%rsi\n\t" /* jmp_buf->Rsi */
677 "movq 0x28(%rcx),%rdi\n\t" /* jmp_buf->Rdi */
678 "movq 0x30(%rcx),%r12\n\t" /* jmp_buf->R12 */
679 "movq 0x38(%rcx),%r13\n\t" /* jmp_buf->R13 */
680 "movq 0x40(%rcx),%r14\n\t" /* jmp_buf->R14 */
681 "movq 0x48(%rcx),%r15\n\t" /* jmp_buf->R15 */
682 "movdqa 0x60(%rcx),%xmm6\n\t" /* jmp_buf->Xmm6 */
683 "movdqa 0x70(%rcx),%xmm7\n\t" /* jmp_buf->Xmm7 */
684 "movdqa 0x80(%rcx),%xmm8\n\t" /* jmp_buf->Xmm8 */
685 "movdqa 0x90(%rcx),%xmm9\n\t" /* jmp_buf->Xmm9 */
686 "movdqa 0xa0(%rcx),%xmm10\n\t" /* jmp_buf->Xmm10 */
687 "movdqa 0xb0(%rcx),%xmm11\n\t" /* jmp_buf->Xmm11 */
688 "movdqa 0xc0(%rcx),%xmm12\n\t" /* jmp_buf->Xmm12 */
689 "movdqa 0xd0(%rcx),%xmm13\n\t" /* jmp_buf->Xmm13 */
690 "movdqa 0xe0(%rcx),%xmm14\n\t" /* jmp_buf->Xmm14 */
691 "movdqa 0xf0(%rcx),%xmm15\n\t" /* jmp_buf->Xmm15 */
692 "movq 0x50(%rcx),%rdx\n\t" /* jmp_buf->Rip */
693 "movq 0x10(%rcx),%rsp\n\t" /* jmp_buf->Rsp */
696 /*******************************************************************
699 void __cdecl
MSVCRT_longjmp( struct MSVCRT___JUMP_BUFFER
*jmp
, int retval
)
701 EXCEPTION_RECORD rec
;
703 if (!retval
) retval
= 1;
706 rec
.ExceptionCode
= STATUS_LONGJUMP
;
707 rec
.ExceptionFlags
= 0;
708 rec
.ExceptionRecord
= NULL
;
709 rec
.ExceptionAddress
= NULL
;
710 rec
.NumberParameters
= 1;
711 rec
.ExceptionInformation
[0] = (DWORD_PTR
)jmp
;
712 RtlUnwind( (void *)jmp
->Frame
, (void *)jmp
->Rip
, &rec
, IntToPtr(retval
) );
714 longjmp_set_regs( jmp
, retval
);
717 /*******************************************************************
718 * _local_unwind (MSVCRT.@)
720 void __cdecl
_local_unwind( void *frame
, void *target
)
722 RtlUnwind( frame
, target
, NULL
, 0 );
725 /*********************************************************************
726 * _fpieee_flt (MSVCRT.@)
728 int __cdecl
_fpieee_flt(ULONG exception_code
, EXCEPTION_POINTERS
*ep
,
729 int (__cdecl
*handler
)(_FPIEEE_RECORD
*))
731 FIXME("(%x %p %p) opcode: %s\n", exception_code
, ep
, handler
,
732 wine_dbgstr_longlong(*(ULONG64
*)ep
->ContextRecord
->Rip
));
733 return EXCEPTION_CONTINUE_SEARCH
;
736 #endif /* __x86_64__ */