]> git.ipfire.org Git - thirdparty/LuaJIT.git/commitdiff
Merge branch 'master' into v2.1
authorMike Pall <mike>
Sun, 29 Sep 2024 14:11:15 +0000 (16:11 +0200)
committerMike Pall <mike>
Sun, 29 Sep 2024 14:11:15 +0000 (16:11 +0200)
1  2 
src/lj_err.c
src/lj_record.c

diff --cc src/lj_err.c
index 414ef477a43b2ef9515982ff63d08ab8fdfeab06,1d1f6b9ebc0613f10d3b90cb4240429c0543d47e..b0ceaa2fa81bb72b91732d272bbe76a265b8e023
@@@ -204,203 -187,19 +204,197 @@@ static void *err_unwind(lua_State *L, v
  
  /* -- External frame unwinding -------------------------------------------- */
  
 -#if defined(__GNUC__) && !LJ_NO_UNWIND && !LJ_ABI_WIN
 +#if LJ_ABI_WIN
  
  /*
 -** We have to use our own definitions instead of the mandatory (!) unwind.h,
 -** since various OS, distros and compilers mess up the header installation.
 +** Someone in Redmond owes me several days of my life. A lot of this is
 +** undocumented or just plain wrong on MSDN. Some of it can be gathered
 +** from 3rd party docs or must be found by trial-and-error. They really
 +** don't want you to write your own language-specific exception handler
 +** or to interact gracefully with MSVC. :-(
  */
  
 -typedef struct _Unwind_Exception
 +#define WIN32_LEAN_AND_MEAN
 +#include <windows.h>
 +
 +#if LJ_TARGET_X86
 +typedef void *UndocumentedDispatcherContext;  /* Unused on x86. */
 +#else
 +/* Taken from: http://www.nynaeve.net/?p=99 */
 +typedef struct UndocumentedDispatcherContext {
 +  ULONG64 ControlPc;
 +  ULONG64 ImageBase;
 +  PRUNTIME_FUNCTION FunctionEntry;
 +  ULONG64 EstablisherFrame;
 +  ULONG64 TargetIp;
 +  PCONTEXT ContextRecord;
 +  void (*LanguageHandler)(void);
 +  PVOID HandlerData;
 +  PUNWIND_HISTORY_TABLE HistoryTable;
 +  ULONG ScopeIndex;
 +  ULONG Fill0;
 +} UndocumentedDispatcherContext;
 +#endif
 +
 +/* Another wild guess. */
 +extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow);
 +
- #if LJ_TARGET_X64 && defined(MINGW_SDK_INIT)
- /* Workaround for broken MinGW64 declaration. */
- VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx");
- #define RtlUnwindEx RtlUnwindEx_FIXED
- #endif
 +#define LJ_MSVC_EXCODE                ((DWORD)0xe06d7363)
 +#define LJ_GCC_EXCODE         ((DWORD)0x20474343)
 +
 +#define LJ_EXCODE             ((DWORD)0xe24c4a00)
 +#define LJ_EXCODE_MAKE(c)     (LJ_EXCODE | (DWORD)(c))
 +#define LJ_EXCODE_CHECK(cl)   (((cl) ^ LJ_EXCODE) <= 0xff)
 +#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff))
 +
 +/* Windows exception handler for interpreter frame. */
 +LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
 +  void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch)
  {
 -  uint64_t exclass;
 -  void (*excleanup)(int, struct _Unwind_Exception *);
 -  uintptr_t p1, p2;
 -} __attribute__((__aligned__)) _Unwind_Exception;
 +#if LJ_TARGET_X86
 +  void *cf = (char *)f - CFRAME_OFS_SEH;
 +#elif LJ_TARGET_ARM64
 +  void *cf = (char *)f - CFRAME_SIZE;
 +#else
 +  void *cf = f;
 +#endif
 +  lua_State *L = cframe_L(cf);
 +  int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
 +              LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
 +  if ((rec->ExceptionFlags & 6)) {  /* EH_UNWINDING|EH_EXIT_UNWIND */
 +    if (rec->ExceptionCode == STATUS_LONGJUMP &&
 +      rec->ExceptionRecord &&
 +      LJ_EXCODE_CHECK(rec->ExceptionRecord->ExceptionCode)) {
 +      errcode = LJ_EXCODE_ERRCODE(rec->ExceptionRecord->ExceptionCode);
 +      if ((rec->ExceptionFlags & 0x20)) {  /* EH_TARGET_UNWIND */
 +      /* Unwinding is about to finish; revert the ExceptionCode so that
 +      ** RtlRestoreContext does not try to restore from a _JUMP_BUFFER.
 +      */
 +      rec->ExceptionCode = 0;
 +      }
 +    }
 +    /* Unwind internal frames. */
 +    err_unwind(L, cf, errcode);
 +  } else {
 +    void *cf2 = err_unwind(L, cf, 0);
 +    if (cf2) {  /* We catch it, so start unwinding the upper frames. */
 +#if !LJ_TARGET_X86
 +      EXCEPTION_RECORD rec2;
 +#endif
 +      if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
 +        rec->ExceptionCode == LJ_GCC_EXCODE) {
 +#if !LJ_TARGET_CYGWIN
 +      __DestructExceptionObject(rec, 1);
 +#endif
 +      setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
 +      } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) {
 +      /* Don't catch access violations etc. */
 +      return 1;  /* ExceptionContinueSearch */
 +      }
 +#if LJ_TARGET_X86
 +      UNUSED(ctx);
 +      UNUSED(dispatch);
 +      /* Call all handlers for all lower C frames (including ourselves) again
 +      ** with EH_UNWINDING set. Then call the specified function, passing cf
 +      ** and errcode.
 +      */
 +      lj_vm_rtlunwind(cf, (void *)rec,
 +      (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
 +      (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
 +      /* lj_vm_rtlunwind does not return. */
 +#else
 +      if (LJ_EXCODE_CHECK(rec->ExceptionCode)) {
 +      /* For unwind purposes, wrap the EXCEPTION_RECORD in something that
 +      ** looks like a longjmp, so that MSVC will execute C++ destructors in
 +      ** the frames we unwind over. ExceptionInformation[0] should really
 +      ** contain a _JUMP_BUFFER*, but hopefully nobody is looking too closely
 +      ** at this point.
 +      */
 +      rec2.ExceptionCode = STATUS_LONGJUMP;
 +      rec2.ExceptionRecord = rec;
 +      rec2.ExceptionAddress = 0;
 +      rec2.NumberParameters = 1;
 +      rec2.ExceptionInformation[0] = (ULONG_PTR)ctx;
 +      rec = &rec2;
 +      }
 +      /* Unwind the stack and call all handlers for all lower C frames
 +      ** (including ourselves) again with EH_UNWINDING set. Then set
 +      ** stack pointer = f, result = errcode and jump to the specified target.
 +      */
 +      RtlUnwindEx(f, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
 +                            lj_vm_unwind_ff_eh :
 +                            lj_vm_unwind_c_eh),
 +                rec, (void *)(uintptr_t)errcode, dispatch->ContextRecord,
 +                dispatch->HistoryTable);
 +      /* RtlUnwindEx should never return. */
 +#endif
 +    }
 +  }
 +  return 1;  /* ExceptionContinueSearch */
 +}
 +
 +#if LJ_UNWIND_JIT
 +
 +#if LJ_TARGET_X64
 +#define CONTEXT_REG_PC        Rip
 +#elif LJ_TARGET_ARM64
 +#define CONTEXT_REG_PC        Pc
 +#else
 +#error "NYI: Windows arch-specific unwinder for JIT-compiled code"
 +#endif
 +
 +/* Windows unwinder for JIT-compiled code. */
 +static void err_unwind_win_jit(global_State *g, int errcode)
 +{
 +  CONTEXT ctx;
 +  UNWIND_HISTORY_TABLE hist;
 +
 +  memset(&hist, 0, sizeof(hist));
 +  RtlCaptureContext(&ctx);
 +  while (1) {
 +    DWORD64 frame, base, addr = ctx.CONTEXT_REG_PC;
 +    void *hdata;
 +    PRUNTIME_FUNCTION func = RtlLookupFunctionEntry(addr, &base, &hist);
 +    if (!func) {  /* Found frame without .pdata: must be JIT-compiled code. */
 +      ExitNo exitno;
 +      uintptr_t stub = lj_trace_unwind(G2J(g), (uintptr_t)(addr - sizeof(MCode)), &exitno);
 +      if (stub) {  /* Jump to side exit to unwind the trace. */
 +      ctx.CONTEXT_REG_PC = stub;
 +      G2J(g)->exitcode = errcode;
 +      RtlRestoreContext(&ctx, NULL);  /* Does not return. */
 +      }
 +      break;
 +    }
 +    RtlVirtualUnwind(UNW_FLAG_NHANDLER, base, addr, func,
 +                   &ctx, &hdata, &frame, NULL);
 +    if (!addr) break;
 +  }
 +  /* Unwinding failed, if we end up here. */
 +}
 +#endif
 +
 +/* Raise Windows exception. */
 +static void err_raise_ext(global_State *g, int errcode)
 +{
 +#if LJ_UNWIND_JIT
 +  if (tvref(g->jit_base)) {
 +    err_unwind_win_jit(g, errcode);
 +    return;  /* Unwinding failed. */
 +  }
 +#elif LJ_HASJIT
 +  /* Cannot catch on-trace errors for Windows/x86 SEH. Unwind to interpreter. */
 +  setmref(g->jit_base, NULL);
 +#endif
 +  UNUSED(g);
 +  RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
 +}
 +
 +#elif !LJ_NO_UNWIND && (defined(__GNUC__) || defined(__clang__))
 +
 +/*
 +** We have to use our own definitions instead of the mandatory (!) unwind.h,
 +** since various OS, distros and compilers mess up the header installation.
 +*/
  
  typedef struct _Unwind_Context _Unwind_Context;
  
diff --cc src/lj_record.c
Simple merge