diff --git a/dlls/msvcrt/except.c b/dlls/msvcrt/except.c index c208ccae175..8a1876ac891 100644 --- a/dlls/msvcrt/except.c +++ b/dlls/msvcrt/except.c @@ -15,6 +15,9 @@ #include "thread.h" #include "msvcrt.h" +#include "msvcrt/setjmp.h" + + DEFAULT_DEBUG_CHANNEL(msvcrt); typedef void (*MSVCRT_sig_handler_func)(void); @@ -227,32 +230,120 @@ int _abnormal_termination(void) return 0; } +/* + * setjmp/longjmp implementation + */ + +#ifdef __i386__ +#define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */ +typedef void (*MSVCRT_unwind_function)(const void*); + +/* + * The signatures of the setjmp/longjmp functions do not match that + * declared in the setjmp header so they don't follow the regular naming + * convention to avoid conflicts. + */ + /******************************************************************* * _setjmp (MSVCRT.@) */ -int MSVCRT__setjmp(LPDWORD* jmpbuf) +void _MSVCRT__setjmp(_JUMP_BUFFER *jmp, CONTEXT86* context) { - FIXME(":(%p): stub\n",jmpbuf); - return 0; + TRACE("(%p)\n",jmp); + jmp->Ebp = context->Ebp; + jmp->Ebx = context->Ebx; + jmp->Edi = context->Edi; + jmp->Esi = context->Esi; + jmp->Esp = context->Esp; + jmp->Eip = context->Eip; + jmp->Registration = (unsigned long)NtCurrentTeb()->except; + if (jmp->Registration == TRYLEVEL_END) + jmp->TryLevel = TRYLEVEL_END; + else + jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel; + TRACE("returning 0\n"); + context->Eax=0; } /******************************************************************* * _setjmp3 (MSVCRT.@) */ -int __cdecl MSVCRT__setjmp3(LPDWORD *jmpbuf, int x) +void _MSVCRT__setjmp3(_JUMP_BUFFER *jmp, int nb_args, CONTEXT86* context) { - FIXME(":(%p %x): stub\n",jmpbuf,x); - return 0; + TRACE("(%p,%d)\n",jmp,nb_args); + jmp->Ebp = context->Ebp; + jmp->Ebx = context->Ebx; + jmp->Edi = context->Edi; + jmp->Esi = context->Esi; + jmp->Esp = context->Esp; + jmp->Eip = context->Eip; + jmp->Cookie = MSVCRT_JMP_MAGIC; + jmp->UnwindFunc = 0; + jmp->Registration = (unsigned long)NtCurrentTeb()->except; + if (jmp->Registration == TRYLEVEL_END) + { + jmp->TryLevel = TRYLEVEL_END; + } + else + { + void **args = ((void**)context->Esp)+2; + + if (nb_args > 0) jmp->UnwindFunc = (unsigned long)*args++; + if (nb_args > 1) jmp->TryLevel = (unsigned long)*args++; + else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel; + if (nb_args > 2) + { + size_t size = (nb_args - 2) * sizeof(DWORD); + memcpy( jmp->UnwindData, args, min( size, sizeof(jmp->UnwindData) )); + } + } + TRACE("returning 0\n"); + context->Eax = 0; } /********************************************************************* * longjmp (MSVCRT.@) */ -void MSVCRT_longjmp(jmp_buf env, int val) +void _MSVCRT_longjmp(_JUMP_BUFFER *jmp, int retval, CONTEXT86* context) { - FIXME("MSVCRT_longjmp semistub, expect crash\n"); - longjmp(env, val); + unsigned long cur_frame = 0; + + TRACE("(%p,%d)\n", jmp, retval); + + cur_frame=(unsigned long)NtCurrentTeb()->except; + TRACE("cur_frame=%lx\n",cur_frame); + + if (cur_frame != jmp->Registration) + _global_unwind2((PEXCEPTION_FRAME)jmp->Registration); + + if (jmp->Registration) + { + if (!IsBadReadPtr(&jmp->Cookie, sizeof(long)) && + jmp->Cookie == MSVCRT_JMP_MAGIC && jmp->UnwindFunc) + { + MSVCRT_unwind_function unwind_func; + + unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc; + unwind_func(jmp); + } + else + _local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration, + jmp->TryLevel); + } + + if (!retval) + retval = 1; + + TRACE("Jump to %lx returning %d\n",jmp->Eip,retval); + context->Ebp = jmp->Ebp; + context->Ebx = jmp->Ebx; + context->Edi = jmp->Edi; + context->Esi = jmp->Esi; + context->Esp = jmp->Esp; + context->Eip = jmp->Eip; + context->Eax = retval; } +#endif /* i386 */ /********************************************************************* * signal (MSVCRT.@) diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index c6b419f0dbc..8495ab8f512 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -432,8 +432,8 @@ debug_channels (msvcrt) @ stub _set_error_mode #(long) @ stub _set_sbh_threshold #(long) @ stub _seterrormode #(long) -@ cdecl _setjmp(ptr) MSVCRT__setjmp -@ cdecl _setjmp3(ptr long) MSVCRT__setjmp3 +@ cdecl -register -noimport -i386 _setjmp(ptr) _MSVCRT__setjmp +@ cdecl -register -noimport -i386 _setjmp3(ptr long) _MSVCRT__setjmp3 @ stub _setmaxstdio #(long) @ cdecl _setmbcp(long) _setmbcp @ cdecl _setmode(long long) _setmode @@ -665,7 +665,7 @@ debug_channels (msvcrt) @ cdecl localtime(ptr) localtime @ forward -noimport log ntdll.log @ cdecl log10(double) log10 -@ cdecl longjmp(long long) MSVCRT_longjmp +@ cdecl -register -noimport -i386 longjmp(ptr long) _MSVCRT_longjmp @ cdecl malloc(long) MSVCRT_malloc @ cdecl mblen(ptr long) MSVCRT_mblen @ forward -noimport mbstowcs ntdll.mbstowcs diff --git a/include/Makefile.in b/include/Makefile.in index b7a4618b976..ce440e2b663 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -65,6 +65,7 @@ INSTALLED_INCLUDES = \ msvcrt/mbstring.h \ msvcrt/process.h \ msvcrt/search.h \ + msvcrt/setjmp.h \ msvcrt/share.h \ msvcrt/stddef.h \ msvcrt/stdio.h \ diff --git a/include/msvcrt/setjmp.h b/include/msvcrt/setjmp.h new file mode 100644 index 00000000000..7781098b366 --- /dev/null +++ b/include/msvcrt/setjmp.h @@ -0,0 +1,58 @@ +/* + * Setjmp/Longjmp definitions + * + * Copyright 2001 Francois Gouget. + */ +#ifndef __WINE_SETJMP_H +#define __WINE_SETJMP_H +#define __WINE_USE_MSVCRT + +#ifdef USE_MSVCRT_PREFIX +#define MSVCRT(x) MSVCRT_##x +#else +#define MSVCRT(x) x +#endif + + +#ifdef __i386__ + +#define _JBLEN 16 +#define _JBTYPE int + +typedef struct __JUMP_BUFFER +{ + unsigned long Ebp; + unsigned long Ebx; + unsigned long Edi; + unsigned long Esi; + unsigned long Esp; + unsigned long Eip; + unsigned long Registration; + unsigned long TryLevel; + /* Start of new struct members */ + unsigned long Cookie; + unsigned long UnwindFunc; + unsigned long UnwindData[6]; +} _JUMP_BUFFER; + +#endif /* __i386__ */ + +typedef _JBTYPE MSVCRT(jmp_buf)[_JBLEN]; + + +#ifdef __cplusplus +extern "C" { +#endif + +int MSVCRT(_setjmp)( MSVCRT(jmp_buf)); +int MSVCRT(longjmp)( MSVCRT(jmp_buf),int); + +#ifdef __cplusplus +} +#endif + +#ifndef USE_MSVCRT_PREFIX +#define setjmp _setjmp +#endif + +#endif /* __WINE_SETJMP_H */