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 | ||