diff options
| author | Mike Pall <mike> | 2015-12-28 16:34:11 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2015-12-28 16:34:11 +0100 |
| commit | f61148c486545bf22df81f223efd3297d1c66f7b (patch) | |
| tree | a1859cf34106a3bbfdd9eb176b2626e4dbda51e9 /src | |
| parent | a687a60eaac9bd700f821415eaa50393c2fea18a (diff) | |
| download | luajit-f61148c486545bf22df81f223efd3297d1c66f7b.tar.gz luajit-f61148c486545bf22df81f223efd3297d1c66f7b.tar.bz2 luajit-f61148c486545bf22df81f223efd3297d1c66f7b.zip | |
ARM: Add external frame unwinding.
Thanks to Nick Zavaritsky.
Diffstat (limited to 'src')
| -rw-r--r-- | src/host/buildvm_asm.c | 9 | ||||
| -rw-r--r-- | src/lj_err.c | 92 | ||||
| -rw-r--r-- | src/vm_arm.dasc | 11 |
3 files changed, 84 insertions, 28 deletions
diff --git a/src/host/buildvm_asm.c b/src/host/buildvm_asm.c index 9b7ae53a..9b119425 100644 --- a/src/host/buildvm_asm.c +++ b/src/host/buildvm_asm.c | |||
| @@ -261,11 +261,20 @@ void emit_asm(BuildCtx *ctx) | |||
| 261 | 261 | ||
| 262 | #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND | 262 | #if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND |
| 263 | /* This should really be moved into buildvm_arm.dasc. */ | 263 | /* This should really be moved into buildvm_arm.dasc. */ |
| 264 | #if LJ_ARCH_HASFPU | ||
| 265 | fprintf(ctx->fp, | ||
| 266 | ".fnstart\n" | ||
| 267 | ".save {r5, r6, r7, r8, r9, r10, r11, lr}\n" | ||
| 268 | ".vsave {d8-d15}\n" | ||
| 269 | ".save {r4}\n" | ||
| 270 | ".pad #28\n"); | ||
| 271 | #else | ||
| 264 | fprintf(ctx->fp, | 272 | fprintf(ctx->fp, |
| 265 | ".fnstart\n" | 273 | ".fnstart\n" |
| 266 | ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" | 274 | ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" |
| 267 | ".pad #28\n"); | 275 | ".pad #28\n"); |
| 268 | #endif | 276 | #endif |
| 277 | #endif | ||
| 269 | #if LJ_TARGET_MIPS | 278 | #if LJ_TARGET_MIPS |
| 270 | fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n"); | 279 | fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n"); |
| 271 | #endif | 280 | #endif |
diff --git a/src/lj_err.c b/src/lj_err.c index 9ac0c988..d641735e 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
| @@ -190,13 +190,6 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
| 190 | ** since various OS, distros and compilers mess up the header installation. | 190 | ** since various OS, distros and compilers mess up the header installation. |
| 191 | */ | 191 | */ |
| 192 | 192 | ||
| 193 | typedef struct _Unwind_Exception | ||
| 194 | { | ||
| 195 | uint64_t exclass; | ||
| 196 | void (*excleanup)(int, struct _Unwind_Exception *); | ||
| 197 | uintptr_t p1, p2; | ||
| 198 | } __attribute__((__aligned__)) _Unwind_Exception; | ||
| 199 | |||
| 200 | typedef struct _Unwind_Context _Unwind_Context; | 193 | typedef struct _Unwind_Context _Unwind_Context; |
| 201 | 194 | ||
| 202 | #define _URC_OK 0 | 195 | #define _URC_OK 0 |
| @@ -206,8 +199,20 @@ typedef struct _Unwind_Context _Unwind_Context; | |||
| 206 | #define _URC_CONTINUE_UNWIND 8 | 199 | #define _URC_CONTINUE_UNWIND 8 |
| 207 | #define _URC_FAILURE 9 | 200 | #define _URC_FAILURE 9 |
| 208 | 201 | ||
| 202 | #define LJ_UEXCLASS 0x4c55414a49543200ULL /* LUAJIT2\0 */ | ||
| 203 | #define LJ_UEXCLASS_MAKE(c) (LJ_UEXCLASS | (uint64_t)(c)) | ||
| 204 | #define LJ_UEXCLASS_CHECK(cl) (((cl) ^ LJ_UEXCLASS) <= 0xff) | ||
| 205 | #define LJ_UEXCLASS_ERRCODE(cl) ((int)((cl) & 0xff)) | ||
| 206 | |||
| 209 | #if !LJ_TARGET_ARM | 207 | #if !LJ_TARGET_ARM |
| 210 | 208 | ||
| 209 | typedef struct _Unwind_Exception | ||
| 210 | { | ||
| 211 | uint64_t exclass; | ||
| 212 | void (*excleanup)(int, struct _Unwind_Exception *); | ||
| 213 | uintptr_t p1, p2; | ||
| 214 | } __attribute__((__aligned__)) _Unwind_Exception; | ||
| 215 | |||
| 211 | extern uintptr_t _Unwind_GetCFA(_Unwind_Context *); | 216 | extern uintptr_t _Unwind_GetCFA(_Unwind_Context *); |
| 212 | extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t); | 217 | extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t); |
| 213 | extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t); | 218 | extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t); |
| @@ -219,11 +224,6 @@ extern int _Unwind_RaiseException(_Unwind_Exception *); | |||
| 219 | #define _UA_HANDLER_FRAME 4 | 224 | #define _UA_HANDLER_FRAME 4 |
| 220 | #define _UA_FORCE_UNWIND 8 | 225 | #define _UA_FORCE_UNWIND 8 |
| 221 | 226 | ||
| 222 | #define LJ_UEXCLASS 0x4c55414a49543200ULL /* LUAJIT2\0 */ | ||
| 223 | #define LJ_UEXCLASS_MAKE(c) (LJ_UEXCLASS | (uint64_t)(c)) | ||
| 224 | #define LJ_UEXCLASS_CHECK(cl) (((cl) ^ LJ_UEXCLASS) <= 0xff) | ||
| 225 | #define LJ_UEXCLASS_ERRCODE(cl) ((int)((cl) & 0xff)) | ||
| 226 | |||
| 227 | /* DWARF2 personality handler referenced from interpreter .eh_frame. */ | 227 | /* DWARF2 personality handler referenced from interpreter .eh_frame. */ |
| 228 | LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | 228 | LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, |
| 229 | uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx) | 229 | uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx) |
| @@ -302,10 +302,23 @@ static void err_raise_ext(int errcode) | |||
| 302 | } | 302 | } |
| 303 | #endif | 303 | #endif |
| 304 | 304 | ||
| 305 | #else | 305 | #else /* LJ_TARGET_ARM */ |
| 306 | |||
| 307 | #define _US_VIRTUAL_UNWIND_FRAME 0 | ||
| 308 | #define _US_UNWIND_FRAME_STARTING 1 | ||
| 309 | #define _US_ACTION_MASK 3 | ||
| 310 | #define _US_FORCE_UNWIND 8 | ||
| 311 | |||
| 312 | typedef struct _Unwind_Control_Block _Unwind_Control_Block; | ||
| 313 | typedef struct _Unwind_Context _Unwind_Context; | ||
| 314 | |||
| 315 | struct _Unwind_Control_Block { | ||
| 316 | uint64_t exclass; | ||
| 317 | uint32_t misc[20]; | ||
| 318 | }; | ||
| 306 | 319 | ||
| 307 | extern void _Unwind_DeleteException(void *); | 320 | extern int _Unwind_RaiseException(_Unwind_Control_Block *); |
| 308 | extern int __gnu_unwind_frame (void *, _Unwind_Context *); | 321 | extern int __gnu_unwind_frame(_Unwind_Control_Block *, _Unwind_Context *); |
| 309 | extern int _Unwind_VRS_Set(_Unwind_Context *, int, uint32_t, int, void *); | 322 | extern int _Unwind_VRS_Set(_Unwind_Context *, int, uint32_t, int, void *); |
| 310 | extern int _Unwind_VRS_Get(_Unwind_Context *, int, uint32_t, int, void *); | 323 | extern int _Unwind_VRS_Get(_Unwind_Context *, int, uint32_t, int, void *); |
| 311 | 324 | ||
| @@ -321,34 +334,57 @@ static inline void _Unwind_SetGR(_Unwind_Context *ctx, int r, uint32_t v) | |||
| 321 | _Unwind_VRS_Set(ctx, 0, r, 0, &v); | 334 | _Unwind_VRS_Set(ctx, 0, r, 0, &v); |
| 322 | } | 335 | } |
| 323 | 336 | ||
| 324 | #define _US_VIRTUAL_UNWIND_FRAME 0 | 337 | extern void lj_vm_unwind_ext(void); |
| 325 | #define _US_UNWIND_FRAME_STARTING 1 | ||
| 326 | #define _US_ACTION_MASK 3 | ||
| 327 | #define _US_FORCE_UNWIND 8 | ||
| 328 | 338 | ||
| 329 | /* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ | 339 | /* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ |
| 330 | LJ_FUNCA int lj_err_unwind_arm(int state, void *ucb, _Unwind_Context *ctx) | 340 | LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, |
| 341 | _Unwind_Context *ctx) | ||
| 331 | { | 342 | { |
| 332 | void *cf = (void *)_Unwind_GetGR(ctx, 13); | 343 | void *cf = (void *)_Unwind_GetGR(ctx, 13); |
| 333 | lua_State *L = cframe_L(cf); | 344 | lua_State *L = cframe_L(cf); |
| 334 | if ((state & _US_ACTION_MASK) == _US_VIRTUAL_UNWIND_FRAME) { | 345 | int errcode; |
| 335 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | 346 | |
| 347 | switch ((state & _US_ACTION_MASK)) { | ||
| 348 | case _US_VIRTUAL_UNWIND_FRAME: | ||
| 349 | if ((state & _US_FORCE_UNWIND)) break; | ||
| 336 | return _URC_HANDLER_FOUND; | 350 | return _URC_HANDLER_FOUND; |
| 337 | } | 351 | case _US_UNWIND_FRAME_STARTING: |
| 338 | if ((state&(_US_ACTION_MASK|_US_FORCE_UNWIND)) == _US_UNWIND_FRAME_STARTING) { | 352 | if (LJ_UEXCLASS_CHECK(ucb->exclass)) { |
| 339 | _Unwind_DeleteException(ucb); | 353 | errcode = LJ_UEXCLASS_ERRCODE(ucb->exclass); |
| 340 | _Unwind_SetGR(ctx, 15, (uint32_t)(void *)lj_err_throw); | 354 | } else { |
| 341 | _Unwind_SetGR(ctx, 0, (uint32_t)L); | 355 | errcode = LUA_ERRRUN; |
| 342 | _Unwind_SetGR(ctx, 1, (uint32_t)LUA_ERRRUN); | 356 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); |
| 357 | } | ||
| 358 | cf = err_unwind(L, cf, errcode); | ||
| 359 | if ((state & _US_FORCE_UNWIND) || cf == NULL) break; | ||
| 360 | _Unwind_SetGR(ctx, 15, (uint32_t)lj_vm_unwind_ext); | ||
| 361 | _Unwind_SetGR(ctx, 0, (uint32_t)ucb); | ||
| 362 | _Unwind_SetGR(ctx, 1, (uint32_t)errcode); | ||
| 363 | _Unwind_SetGR(ctx, 2, cframe_unwind_ff(cf) ? | ||
| 364 | (uint32_t)lj_vm_unwind_ff_eh : | ||
| 365 | (uint32_t)lj_vm_unwind_c_eh); | ||
| 343 | return _URC_INSTALL_CONTEXT; | 366 | return _URC_INSTALL_CONTEXT; |
| 367 | default: | ||
| 368 | return _URC_FAILURE; | ||
| 344 | } | 369 | } |
| 345 | if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) | 370 | if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) |
| 346 | return _URC_FAILURE; | 371 | return _URC_FAILURE; |
| 347 | return _URC_CONTINUE_UNWIND; | 372 | return _URC_CONTINUE_UNWIND; |
| 348 | } | 373 | } |
| 349 | 374 | ||
| 375 | #if LJ_UNWIND_EXT | ||
| 376 | static __thread _Unwind_Control_Block static_uex; | ||
| 377 | |||
| 378 | static void err_raise_ext(int errcode) | ||
| 379 | { | ||
| 380 | memset(&static_uex, 0, sizeof(static_uex)); | ||
| 381 | static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); | ||
| 382 | _Unwind_RaiseException(&static_uex); | ||
| 383 | } | ||
| 350 | #endif | 384 | #endif |
| 351 | 385 | ||
| 386 | #endif /* LJ_TARGET_ARM */ | ||
| 387 | |||
| 352 | #elif LJ_TARGET_X64 && LJ_ABI_WIN | 388 | #elif LJ_TARGET_X64 && LJ_ABI_WIN |
| 353 | 389 | ||
| 354 | /* | 390 | /* |
diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc index af722f9e..acc0853b 100644 --- a/src/vm_arm.dasc +++ b/src/vm_arm.dasc | |||
| @@ -373,6 +373,17 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 373 | | st_vmstate CARG2 | 373 | | st_vmstate CARG2 |
| 374 | | b ->vm_returnc | 374 | | b ->vm_returnc |
| 375 | | | 375 | | |
| 376 | |->vm_unwind_ext: // Complete external unwind. | ||
| 377 | #if !LJ_NO_UNWIND | ||
| 378 | | push {r0, r1, r2, lr} | ||
| 379 | | bl extern _Unwind_Complete | ||
| 380 | | ldr r0, [sp] | ||
| 381 | | bl extern _Unwind_DeleteException | ||
| 382 | | pop {r0, r1, r2, lr} | ||
| 383 | | mov r0, r1 | ||
| 384 | | bx r2 | ||
| 385 | #endif | ||
| 386 | | | ||
| 376 | |//----------------------------------------------------------------------- | 387 | |//----------------------------------------------------------------------- |
| 377 | |//-- Grow stack for calls ----------------------------------------------- | 388 | |//-- Grow stack for calls ----------------------------------------------- |
| 378 | |//----------------------------------------------------------------------- | 389 | |//----------------------------------------------------------------------- |
