diff options
| author | Mike Pall <mike> | 2010-01-05 22:39:46 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2010-01-05 22:39:46 +0100 |
| commit | c31ac26fb9803d4b09c27668b7c2d9a01385c9ba (patch) | |
| tree | 620bc1af468b94d4676f5b6e335b5983e9f1ef8b /src | |
| parent | b3e3bad0ffffe9e1a23c658b99810c687905005d (diff) | |
| download | luajit-c31ac26fb9803d4b09c27668b7c2d9a01385c9ba.tar.gz luajit-c31ac26fb9803d4b09c27668b7c2d9a01385c9ba.tar.bz2 luajit-c31ac26fb9803d4b09c27668b7c2d9a01385c9ba.zip | |
Add support for WIN64 exception handling to external unwinder.
Modify unwinding to always return _ff or _c unwind type.
Generate PE object .pdata/.xdata sections for x64 interpreter.
Can drop r12-r15 saves in Windows/x64 interpreter now.
Diffstat (limited to 'src')
| -rw-r--r-- | src/buildvm_peobj.c | 70 | ||||
| -rw-r--r-- | src/buildvm_x86.dasc | 30 | ||||
| -rw-r--r-- | src/buildvm_x86.h | 2 | ||||
| -rw-r--r-- | src/lj_err.c | 98 | ||||
| -rw-r--r-- | src/lj_frame.h | 21 |
5 files changed, 177 insertions, 44 deletions
diff --git a/src/buildvm_peobj.c b/src/buildvm_peobj.c index d45f3c97..68af79c7 100644 --- a/src/buildvm_peobj.c +++ b/src/buildvm_peobj.c | |||
| @@ -90,6 +90,7 @@ typedef struct PEsymaux { | |||
| 90 | #define PEOBJ_ARCH_TARGET 0x8664 | 90 | #define PEOBJ_ARCH_TARGET 0x8664 |
| 91 | #define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */ | 91 | #define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */ |
| 92 | #define PEOBJ_RELOC_DIR32 0x02 | 92 | #define PEOBJ_RELOC_DIR32 0x02 |
| 93 | #define PEOBJ_RELOC_ADDR32NB 0x03 | ||
| 93 | #define PEOBJ_SYM_PREFIX "" | 94 | #define PEOBJ_SYM_PREFIX "" |
| 94 | #endif | 95 | #endif |
| 95 | 96 | ||
| @@ -98,7 +99,10 @@ enum { | |||
| 98 | PEOBJ_SECT_ABS = -2, | 99 | PEOBJ_SECT_ABS = -2, |
| 99 | PEOBJ_SECT_UNDEF = -1, | 100 | PEOBJ_SECT_UNDEF = -1, |
| 100 | PEOBJ_SECT_TEXT, | 101 | PEOBJ_SECT_TEXT, |
| 101 | /* TODO: add .pdata/.xdata for x64. */ | 102 | #if LJ_TARGET_X64 |
| 103 | PEOBJ_SECT_PDATA, | ||
| 104 | PEOBJ_SECT_XDATA, | ||
| 105 | #endif | ||
| 102 | PEOBJ_SECT_RDATA, | 106 | PEOBJ_SECT_RDATA, |
| 103 | PEOBJ_SECT_RDATA_Z, | 107 | PEOBJ_SECT_RDATA_Z, |
| 104 | PEOBJ_NSECTIONS | 108 | PEOBJ_NSECTIONS |
| @@ -196,6 +200,24 @@ void emit_peobj(BuildCtx *ctx) | |||
| 196 | /* Flags: 60 = read+execute, 50 = align16, 20 = code. */ | 200 | /* Flags: 60 = read+execute, 50 = align16, 20 = code. */ |
| 197 | pesect[PEOBJ_SECT_TEXT].flags = 0x60500020; | 201 | pesect[PEOBJ_SECT_TEXT].flags = 0x60500020; |
| 198 | 202 | ||
| 203 | #if LJ_TARGET_X64 | ||
| 204 | memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1); | ||
| 205 | pesect[PEOBJ_SECT_PDATA].ofs = sofs; | ||
| 206 | sofs += (pesect[PEOBJ_SECT_PDATA].size = 3*4); | ||
| 207 | pesect[PEOBJ_SECT_PDATA].relocofs = sofs; | ||
| 208 | sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 3) * PEOBJ_RELOC_SIZE; | ||
| 209 | /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ | ||
| 210 | pesect[PEOBJ_SECT_PDATA].flags = 0x40300040; | ||
| 211 | |||
| 212 | memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1); | ||
| 213 | pesect[PEOBJ_SECT_XDATA].ofs = sofs; | ||
| 214 | sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4); /* See below. */ | ||
| 215 | pesect[PEOBJ_SECT_XDATA].relocofs = sofs; | ||
| 216 | sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; | ||
| 217 | /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ | ||
| 218 | pesect[PEOBJ_SECT_XDATA].flags = 0x40300040; | ||
| 219 | #endif | ||
| 220 | |||
| 199 | memcpy(pesect[PEOBJ_SECT_RDATA].name, ".rdata", sizeof(".rdata")-1); | 221 | memcpy(pesect[PEOBJ_SECT_RDATA].name, ".rdata", sizeof(".rdata")-1); |
| 200 | pesect[PEOBJ_SECT_RDATA].ofs = sofs; | 222 | pesect[PEOBJ_SECT_RDATA].ofs = sofs; |
| 201 | sofs += (pesect[PEOBJ_SECT_RDATA].size = ctx->npc*sizeof(uint16_t)); | 223 | sofs += (pesect[PEOBJ_SECT_RDATA].size = ctx->npc*sizeof(uint16_t)); |
| @@ -228,6 +250,9 @@ void emit_peobj(BuildCtx *ctx) | |||
| 228 | #if !LJ_HASJIT | 250 | #if !LJ_HASJIT |
| 229 | pehdr.nsyms -= 7; | 251 | pehdr.nsyms -= 7; |
| 230 | #endif | 252 | #endif |
| 253 | #if LJ_TARGET_X64 | ||
| 254 | pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win64. */ | ||
| 255 | #endif | ||
| 231 | 256 | ||
| 232 | /* Write PE object header and all sections. */ | 257 | /* Write PE object header and all sections. */ |
| 233 | owrite(ctx, &pehdr, sizeof(PEheader)); | 258 | owrite(ctx, &pehdr, sizeof(PEheader)); |
| @@ -243,6 +268,41 @@ void emit_peobj(BuildCtx *ctx) | |||
| 243 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); | 268 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); |
| 244 | } | 269 | } |
| 245 | 270 | ||
| 271 | #if LJ_TARGET_X64 | ||
| 272 | { /* Write .pdata section. */ | ||
| 273 | uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */ | ||
| 274 | PEreloc reloc; | ||
| 275 | pdata[0] = 0; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 0; | ||
| 276 | owrite(ctx, &pdata, sizeof(pdata)); | ||
| 277 | reloc.vaddr = 0; reloc.symidx = 1+2+relocsyms+2+2+1; | ||
| 278 | reloc.type = PEOBJ_RELOC_ADDR32NB; | ||
| 279 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); | ||
| 280 | reloc.vaddr = 4; reloc.symidx = 1+2+relocsyms+2+2+1; | ||
| 281 | reloc.type = PEOBJ_RELOC_ADDR32NB; | ||
| 282 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); | ||
| 283 | reloc.vaddr = 8; reloc.symidx = 1+2+relocsyms+2; | ||
| 284 | reloc.type = PEOBJ_RELOC_ADDR32NB; | ||
| 285 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); | ||
| 286 | } | ||
| 287 | { /* Write .xdata section. */ | ||
| 288 | uint16_t xdata[8+2]; | ||
| 289 | PEreloc reloc; | ||
| 290 | xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhander/ehandler, prolog size 0. */ | ||
| 291 | xdata[1] = 5; /* Number of unwind codes, no frame pointer. */ | ||
| 292 | xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */ | ||
| 293 | xdata[3] = 0x3000; /* Push rbx. */ | ||
| 294 | xdata[4] = 0x6000; /* Push rsi. */ | ||
| 295 | xdata[5] = 0x7000; /* Push rdi. */ | ||
| 296 | xdata[6] = 0x5000; /* Push rbp. */ | ||
| 297 | xdata[7] = 0; /* Alignment. */ | ||
| 298 | xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */ | ||
| 299 | owrite(ctx, &xdata, sizeof(xdata)); | ||
| 300 | reloc.vaddr = sizeof(xdata)-4; reloc.symidx = 1+2+relocsyms+2+2; | ||
| 301 | reloc.type = PEOBJ_RELOC_ADDR32NB; | ||
| 302 | owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); | ||
| 303 | } | ||
| 304 | #endif | ||
| 305 | |||
| 246 | /* Write .rdata section. */ | 306 | /* Write .rdata section. */ |
| 247 | for (i = 0; i < ctx->npc; i++) { | 307 | for (i = 0; i < ctx->npc; i++) { |
| 248 | uint16_t pcofs = (uint16_t)ctx->sym_ofs[i]; | 308 | uint16_t pcofs = (uint16_t)ctx->sym_ofs[i]; |
| @@ -279,6 +339,14 @@ void emit_peobj(BuildCtx *ctx) | |||
| 279 | emit_peobj_sym(ctx, name, 0, | 339 | emit_peobj_sym(ctx, name, 0, |
| 280 | PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); | 340 | PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); |
| 281 | } | 341 | } |
| 342 | |||
| 343 | #if LJ_TARGET_X64 | ||
| 344 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); | ||
| 345 | emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); | ||
| 346 | emit_peobj_sym(ctx, PEOBJ_SYM_PREFIX "lj_err_unwind_win64", 0, | ||
| 347 | PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); | ||
| 348 | #endif | ||
| 349 | |||
| 282 | emit_peobj_sym(ctx, PEOBJ_SYM_PREFIX LABEL_ASM_BEGIN, 0, | 350 | emit_peobj_sym(ctx, PEOBJ_SYM_PREFIX LABEL_ASM_BEGIN, 0, |
| 283 | PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN); | 351 | PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN); |
| 284 | for (i = nzsym; i < ctx->nsym; i++) { | 352 | for (i = nzsym; i < ctx->nsym; i++) { |
diff --git a/src/buildvm_x86.dasc b/src/buildvm_x86.dasc index be2ee71e..e40ca6d7 100644 --- a/src/buildvm_x86.dasc +++ b/src/buildvm_x86.dasc | |||
| @@ -168,28 +168,22 @@ | |||
| 168 | |.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--). | 168 | |.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--). |
| 169 | |.macro saveregs | 169 | |.macro saveregs |
| 170 | | push rbp; push rdi; push rsi; push rbx | 170 | | push rbp; push rdi; push rsi; push rbx |
| 171 | | push r15; push r14; push r13; push r12 | ||
| 172 | | sub rsp, CFRAME_SPACE | 171 | | sub rsp, CFRAME_SPACE |
| 173 | |.endmacro | 172 | |.endmacro |
| 174 | |.macro restoreregs | 173 | |.macro restoreregs |
| 175 | | add rsp, CFRAME_SPACE | 174 | | add rsp, CFRAME_SPACE |
| 176 | | pop r12; pop r13; pop r14; pop r15 | ||
| 177 | | pop rbx; pop rsi; pop rdi; pop rbp | 175 | | pop rbx; pop rsi; pop rdi; pop rbp |
| 178 | |.endmacro | 176 | |.endmacro |
| 179 | | | 177 | | |
| 180 | |.define SAVE_CFRAME, aword [rsp+aword*17] | 178 | |.define SAVE_CFRAME, aword [rsp+aword*13] |
| 181 | |.define SAVE_PC, dword [rsp+dword*33] | 179 | |.define SAVE_PC, dword [rsp+dword*25] |
| 182 | |.define SAVE_L, dword [rsp+dword*32] | 180 | |.define SAVE_L, dword [rsp+dword*24] |
| 183 | |.define SAVE_ERRF, dword [rsp+dword*31] | 181 | |.define SAVE_ERRF, dword [rsp+dword*23] |
| 184 | |.define SAVE_NRES, dword [rsp+dword*30] | 182 | |.define SAVE_NRES, dword [rsp+dword*22] |
| 185 | |.define TMP2, dword [rsp+dword*29] | 183 | |.define TMP2, dword [rsp+dword*21] |
| 186 | |.define TMP1, dword [rsp+dword*28] | 184 | |.define TMP1, dword [rsp+dword*20] |
| 187 | |//----- 16 byte aligned, ^^^ 32 byte register save area, owned by interpreter | 185 | |//----- 16 byte aligned, ^^^ 32 byte register save area, owned by interpreter |
| 188 | |.define SAVE_RET, aword [rsp+aword*13] //<-- rsp entering interpreter. | 186 | |.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter. |
| 189 | |.define SAVE_R8, aword [rsp+aword*12] | ||
| 190 | |.define SAVE_R7, aword [rsp+aword*11] | ||
| 191 | |.define SAVE_R6, aword [rsp+aword*10] | ||
| 192 | |.define SAVE_R5, aword [rsp+aword*9] | ||
| 193 | |.define SAVE_R4, aword [rsp+aword*8] | 187 | |.define SAVE_R4, aword [rsp+aword*8] |
| 194 | |.define SAVE_R3, aword [rsp+aword*7] | 188 | |.define SAVE_R3, aword [rsp+aword*7] |
| 195 | |.define SAVE_R2, aword [rsp+aword*6] | 189 | |.define SAVE_R2, aword [rsp+aword*6] |
| @@ -202,7 +196,7 @@ | |||
| 202 | |//----- 16 byte aligned, ^^^ 32 byte register save area, owned by callee | 196 | |//----- 16 byte aligned, ^^^ 32 byte register save area, owned by callee |
| 203 | | | 197 | | |
| 204 | |// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ). | 198 | |// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ). |
| 205 | |.define TMPQ, qword [rsp+aword*14] | 199 | |.define TMPQ, qword [rsp+aword*10] |
| 206 | |.define MULTRES, TMP2 | 200 | |.define MULTRES, TMP2 |
| 207 | |.define TMPa, ARG5 | 201 | |.define TMPa, ARG5 |
| 208 | |.define ARG5d, dword [rsp+aword*4] | 202 | |.define ARG5d, dword [rsp+aword*4] |
| @@ -861,10 +855,12 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse) | |||
| 861 | | mov dword [RA+RD*8-4], LJ_TNIL // Ensure one valid arg. | 855 | | mov dword [RA+RD*8-4], LJ_TNIL // Ensure one valid arg. |
| 862 | | mov RC, RA // ... in [RC] | 856 | | mov RC, RA // ... in [RC] |
| 863 | | mov PC, [RB-12] // Restore PC from [cont|PC]. | 857 | | mov PC, [RB-12] // Restore PC from [cont|PC]. |
| 864 | | mov RA, dword [RB-16] | ||
| 865 | |.if X64 | 858 | |.if X64 |
| 859 | | movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug. | ||
| 866 | | lea KBASEa, qword [=>0] | 860 | | lea KBASEa, qword [=>0] |
| 867 | | add RAa, KBASEa | 861 | | add RAa, KBASEa |
| 862 | |.else | ||
| 863 | | mov RA, dword [RB-16] | ||
| 868 | |.endif | 864 | |.endif |
| 869 | | mov LFUNC:KBASE, [BASE-8] | 865 | | mov LFUNC:KBASE, [BASE-8] |
| 870 | | mov PROTO:KBASE, LFUNC:KBASE->pt | 866 | | mov PROTO:KBASE, LFUNC:KBASE->pt |
| @@ -1854,7 +1850,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse) | |||
| 1854 | |.ffunc coroutine_yield | 1850 | |.ffunc coroutine_yield |
| 1855 | | mov L:RB, SAVE_L | 1851 | | mov L:RB, SAVE_L |
| 1856 | | mov [RA-4], PC | 1852 | | mov [RA-4], PC |
| 1857 | | test aword L:RB->cframe, CFRAME_CANYIELD | 1853 | | test aword L:RB->cframe, CFRAME_RESUME |
| 1858 | | jz ->fff_fallback | 1854 | | jz ->fff_fallback |
| 1859 | | mov L:RB->base, RA | 1855 | | mov L:RB->base, RA |
| 1860 | | lea RC, [RA+NARGS:RC*8-8] | 1856 | | lea RC, [RA+NARGS:RC*8-8] |
diff --git a/src/buildvm_x86.h b/src/buildvm_x86.h index 030ac179..68f27f93 100644 --- a/src/buildvm_x86.h +++ b/src/buildvm_x86.h | |||
| @@ -1177,7 +1177,7 @@ static void build_subroutines(BuildCtx *ctx, int cmov, int sse) | |||
| 1177 | dasm_put(Dst, 3443, Dt1(->top), Dt1(->base), Dt8(->upvalue[0].gcr), Dt1(->cframe), Dt1(->status), LUA_YIELD, Dt1(->top), Dt1(->base)); | 1177 | dasm_put(Dst, 3443, Dt1(->top), Dt1(->base), Dt8(->upvalue[0].gcr), Dt1(->cframe), Dt1(->status), LUA_YIELD, Dt1(->top), Dt1(->base)); |
| 1178 | dasm_put(Dst, 3523, Dt1(->maxstack), Dt1(->top), Dt1(->base), Dt1(->top), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->base)); | 1178 | dasm_put(Dst, 3523, Dt1(->maxstack), Dt1(->top), Dt1(->base), Dt1(->top), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->base)); |
| 1179 | dasm_put(Dst, 3631, LUA_YIELD, Dt1(->base), Dt1(->top), Dt1(->top), Dt1(->maxstack), FRAME_TYPE); | 1179 | dasm_put(Dst, 3631, LUA_YIELD, Dt1(->base), Dt1(->top), Dt1(->top), Dt1(->maxstack), FRAME_TYPE); |
| 1180 | dasm_put(Dst, 3727, Dt1(->top), Dt1(->base), Dt1(->cframe), CFRAME_CANYIELD, Dt1(->base), Dt1(->top), Dt1(->cframe), LUA_YIELD, Dt1(->status)); | 1180 | dasm_put(Dst, 3727, Dt1(->top), Dt1(->base), Dt1(->cframe), CFRAME_RESUME, Dt1(->base), Dt1(->top), Dt1(->cframe), LUA_YIELD, Dt1(->status)); |
| 1181 | if (sse) { | 1181 | if (sse) { |
| 1182 | dasm_put(Dst, 3813, 1+1, LJ_TISNUM); | 1182 | dasm_put(Dst, 3813, 1+1, LJ_TISNUM); |
| 1183 | } else { | 1183 | } else { |
diff --git a/src/lj_err.c b/src/lj_err.c index b2e7f5f8..b8070250 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
| @@ -493,7 +493,7 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
| 493 | L->cframe = NULL; | 493 | L->cframe = NULL; |
| 494 | L->status = cast_byte(errcode); | 494 | L->status = cast_byte(errcode); |
| 495 | } | 495 | } |
| 496 | return cframe_raw(cf); | 496 | return cf; |
| 497 | } | 497 | } |
| 498 | if (errcode) { | 498 | if (errcode) { |
| 499 | L->cframe = cframe_prev(cf); | 499 | L->cframe = cframe_prev(cf); |
| @@ -514,9 +514,8 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
| 514 | L->cframe = cf; | 514 | L->cframe = cf; |
| 515 | L->base = frame_prevd(frame) + 1; | 515 | L->base = frame_prevd(frame) + 1; |
| 516 | unwindstack(L, L->base); | 516 | unwindstack(L, L->base); |
| 517 | return NULL; /* Call special handler. */ | ||
| 518 | } | 517 | } |
| 519 | return cf; | 518 | return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); |
| 520 | } | 519 | } |
| 521 | } | 520 | } |
| 522 | /* No C frame. */ | 521 | /* No C frame. */ |
| @@ -528,7 +527,7 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
| 528 | G(L)->panic(L); | 527 | G(L)->panic(L); |
| 529 | exit(EXIT_FAILURE); | 528 | exit(EXIT_FAILURE); |
| 530 | } | 529 | } |
| 531 | return L; /* Anything not-NULL will do. */ | 530 | return L; /* Anything non-NULL will do. */ |
| 532 | } | 531 | } |
| 533 | 532 | ||
| 534 | /* -- External frame unwinding -------------------------------------------- */ | 533 | /* -- External frame unwinding -------------------------------------------- */ |
| @@ -574,12 +573,12 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions, | |||
| 574 | errcode = LUA_ERRRUN; | 573 | errcode = LUA_ERRRUN; |
| 575 | } | 574 | } |
| 576 | #if LJ_UNWIND_EXT | 575 | #if LJ_UNWIND_EXT |
| 577 | if (err_unwind(L, cf, errcode)) { | 576 | cf = err_unwind(L, cf, errcode); |
| 577 | if (cf) { | ||
| 578 | _Unwind_SetGR(ctx, 0, errcode); | 578 | _Unwind_SetGR(ctx, 0, errcode); |
| 579 | _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_c_eh); | 579 | _Unwind_SetIP(ctx, (_Unwind_Ptr)(cframe_unwind_ff(cf) ? |
| 580 | return _URC_INSTALL_CONTEXT; | 580 | lj_vm_unwind_ff_eh : |
| 581 | } else if ((actions & _UA_HANDLER_FRAME)) { | 581 | lj_vm_unwind_c_eh)); |
| 582 | _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_ff_eh); | ||
| 583 | return _URC_INSTALL_CONTEXT; | 582 | return _URC_INSTALL_CONTEXT; |
| 584 | } | 583 | } |
| 585 | #else | 584 | #else |
| @@ -607,20 +606,89 @@ static void err_raise_ext(int errcode) | |||
| 607 | 606 | ||
| 608 | #elif defined(_WIN64) | 607 | #elif defined(_WIN64) |
| 609 | 608 | ||
| 609 | /* | ||
| 610 | ** Someone in Redmond owes me several days of my life. A lot of this is | ||
| 611 | ** undocumented or just plain wrong on MSDN. Some of it can be gathered | ||
| 612 | ** from 3rd party docs or must be found by trial-and-error. They really | ||
| 613 | ** don't want you to write your own language-specific exception handler | ||
| 614 | ** or to interact gracefully with MSVC. :-( | ||
| 615 | ** | ||
| 616 | ** Apparently MSVC doesn't call C++ destructors for foreign exceptions | ||
| 617 | ** unless you compile your C++ code with /EHa. Unfortunately this means | ||
| 618 | ** catch (...) also catches things like access violations. The use of | ||
| 619 | ** _set_se_translator doesn't really help, because it requires /EHa, too. | ||
| 620 | */ | ||
| 621 | |||
| 610 | #define WIN32_LEAN_AND_MEAN | 622 | #define WIN32_LEAN_AND_MEAN |
| 611 | #include <windows.h> | 623 | #include <windows.h> |
| 612 | 624 | ||
| 613 | #define LJ_EXCODE ((DWORD)0x024c4a00) | 625 | /* Taken from: http://www.nynaeve.net/?p=99 */ |
| 626 | typedef struct UndocumentedDispatcherContext { | ||
| 627 | ULONG64 ControlPc; | ||
| 628 | ULONG64 ImageBase; | ||
| 629 | PRUNTIME_FUNCTION FunctionEntry; | ||
| 630 | ULONG64 EstablisherFrame; | ||
| 631 | ULONG64 TargetIp; | ||
| 632 | PCONTEXT ContextRecord; | ||
| 633 | PEXCEPTION_ROUTINE LanguageHandler; | ||
| 634 | PVOID HandlerData; | ||
| 635 | PUNWIND_HISTORY_TABLE HistoryTable; | ||
| 636 | ULONG ScopeIndex; | ||
| 637 | ULONG Fill0; | ||
| 638 | } UndocumentedDispatcherContext; | ||
| 639 | |||
| 640 | #ifdef _MSC_VER | ||
| 641 | /* Another wild guess. */ | ||
| 642 | extern __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | ||
| 643 | #endif | ||
| 644 | |||
| 645 | #define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) | ||
| 646 | |||
| 647 | #define LJ_EXCODE ((DWORD)0xe24c4a00) | ||
| 614 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) | 648 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) |
| 615 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | 649 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) |
| 616 | #define LJ_EXCODE_ERRCODE(cl) (cast_int((cl) & 0xff)) | 650 | #define LJ_EXCODE_ERRCODE(cl) (cast_int((cl) & 0xff)) |
| 617 | 651 | ||
| 618 | /* NYI: Win64 exception handler for interpreter frame. */ | 652 | /* Win64 exception handler for interpreter frame. */ |
| 653 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | ||
| 654 | void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | ||
| 655 | { | ||
| 656 | lua_State *L = cframe_L(cf); | ||
| 657 | if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ | ||
| 658 | err_unwind(L, cf, 1); /* Unwind internal frames. */ | ||
| 659 | } else { | ||
| 660 | void *cf2 = err_unwind(L, cf, 0); | ||
| 661 | if (cf2) { /* We catch it, so start unwinding the upper frames. */ | ||
| 662 | int errcode; | ||
| 663 | if (LJ_EXCODE_CHECK(rec->ExceptionCode)) { | ||
| 664 | errcode = LJ_EXCODE_ERRCODE(rec->ExceptionCode); | ||
| 665 | } else if (rec->ExceptionCode == LJ_MSVC_EXCODE) { | ||
| 666 | #ifdef _MSC_VER | ||
| 667 | __DestructExceptionObject(rec, 1); | ||
| 668 | #endif | ||
| 669 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | ||
| 670 | errcode = LUA_ERRRUN; | ||
| 671 | } else { /* Don't catch access violations etc. */ | ||
| 672 | return ExceptionContinueSearch; | ||
| 673 | } | ||
| 674 | /* Unwind the stack and call all handlers for all lower C frames | ||
| 675 | ** (including ourselves) again with EH_UNWINDING set. Then set | ||
| 676 | ** rsp = cf, rax = errcode and jump to the specified target. | ||
| 677 | */ | ||
| 678 | RtlUnwindEx(cf, (void *)(cframe_unwind_ff(cf2) ? | ||
| 679 | lj_vm_unwind_ff_eh : | ||
| 680 | lj_vm_unwind_c_eh), | ||
| 681 | rec, (void *)errcode, ctx, dispatch->HistoryTable); | ||
| 682 | /* RtlUnwindEx should never return. */ | ||
| 683 | } | ||
| 684 | } | ||
| 685 | return ExceptionContinueSearch; | ||
| 686 | } | ||
| 619 | 687 | ||
| 620 | /* Raise Windows exception. */ | 688 | /* Raise Windows exception. */ |
| 621 | static void err_raise_ext(int errcode) | 689 | static void err_raise_ext(int errcode) |
| 622 | { | 690 | { |
| 623 | RaiseException(LJ_EXCODE_MAKE(errcode), 0, 0, NULL); | 691 | RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); |
| 624 | } | 692 | } |
| 625 | 693 | ||
| 626 | #endif | 694 | #endif |
| @@ -650,10 +718,10 @@ LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode) | |||
| 650 | #else | 718 | #else |
| 651 | { | 719 | { |
| 652 | void *cf = err_unwind(L, NULL, errcode); | 720 | void *cf = err_unwind(L, NULL, errcode); |
| 653 | if (cf) | 721 | if (cframe_unwind_ff(cf)) |
| 654 | lj_vm_unwind_c(cf, errcode); | 722 | lj_vm_unwind_ff(cframe_raw(cf)); |
| 655 | else | 723 | else |
| 656 | lj_vm_unwind_ff(cframe_raw(L->cframe)); | 724 | lj_vm_unwind_c(cframe_raw(cf), errcode); |
| 657 | } | 725 | } |
| 658 | #endif | 726 | #endif |
| 659 | exit(EXIT_FAILURE); | 727 | exit(EXIT_FAILURE); |
diff --git a/src/lj_frame.h b/src/lj_frame.h index 0bfcb005..c86818e0 100644 --- a/src/lj_frame.h +++ b/src/lj_frame.h | |||
| @@ -67,13 +67,13 @@ enum { | |||
| 67 | #define CFRAME_SIZE (12*4) | 67 | #define CFRAME_SIZE (12*4) |
| 68 | #elif LJ_TARGET_X64 | 68 | #elif LJ_TARGET_X64 |
| 69 | #if _WIN64 | 69 | #if _WIN64 |
| 70 | #define CFRAME_OFS_PREV (17*8) | 70 | #define CFRAME_OFS_PREV (13*8) |
| 71 | #define CFRAME_OFS_PC (33*4) | 71 | #define CFRAME_OFS_PC (25*4) |
| 72 | #define CFRAME_OFS_L (32*4) | 72 | #define CFRAME_OFS_L (24*4) |
| 73 | #define CFRAME_OFS_ERRF (31*4) | 73 | #define CFRAME_OFS_ERRF (23*4) |
| 74 | #define CFRAME_OFS_NRES (30*4) | 74 | #define CFRAME_OFS_NRES (22*4) |
| 75 | #define CFRAME_OFS_MULTRES (29*4) | 75 | #define CFRAME_OFS_MULTRES (21*4) |
| 76 | #define CFRAME_SIZE (14*8) | 76 | #define CFRAME_SIZE (10*8) |
| 77 | #else | 77 | #else |
| 78 | #define CFRAME_OFS_PREV (4*8) | 78 | #define CFRAME_OFS_PREV (4*8) |
| 79 | #define CFRAME_OFS_PC (5*4) | 79 | #define CFRAME_OFS_PC (5*4) |
| @@ -88,8 +88,8 @@ enum { | |||
| 88 | #endif | 88 | #endif |
| 89 | 89 | ||
| 90 | #define CFRAME_RESUME 1 | 90 | #define CFRAME_RESUME 1 |
| 91 | #define CFRAME_CANYIELD ((intptr_t)(CFRAME_RESUME)) | 91 | #define CFRAME_UNWIND_FF 2 /* Only used in unwinder. */ |
| 92 | #define CFRAME_RAWMASK (~CFRAME_CANYIELD) | 92 | #define CFRAME_RAWMASK (~(intptr_t)(CFRAME_RESUME|CFRAME_UNWIND_FF)) |
| 93 | 93 | ||
| 94 | #define cframe_errfunc(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_ERRF)) | 94 | #define cframe_errfunc(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_ERRF)) |
| 95 | #define cframe_nres(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_NRES)) | 95 | #define cframe_nres(cf) (*(int32_t *)(((char *)(cf))+CFRAME_OFS_NRES)) |
| @@ -101,7 +101,8 @@ enum { | |||
| 101 | (mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns)) | 101 | (mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns)) |
| 102 | #define setcframe_pc(cf, pc) \ | 102 | #define setcframe_pc(cf, pc) \ |
| 103 | (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc))) | 103 | (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc))) |
| 104 | #define cframe_canyield(cf) ((intptr_t)(cf) & CFRAME_CANYIELD) | 104 | #define cframe_canyield(cf) ((intptr_t)(cf) & CFRAME_RESUME) |
| 105 | #define cframe_unwind_ff(cf) ((intptr_t)(cf) & CFRAME_UNWIND_FF) | ||
| 105 | #define cframe_raw(cf) ((void *)((intptr_t)(cf) & CFRAME_RAWMASK)) | 106 | #define cframe_raw(cf) ((void *)((intptr_t)(cf) & CFRAME_RAWMASK)) |
| 106 | #define cframe_Lpc(L) cframe_pc(cframe_raw(L->cframe)) | 107 | #define cframe_Lpc(L) cframe_pc(cframe_raw(L->cframe)) |
| 107 | 108 | ||
