Skip to content

Commit 5fe2062

Browse files
committed
Correct DWARF frame description.
Now GDB correctly shows backtraces that involves JIT-ed code for functional/tracing JIT, HYBRID/CALL VM, x86/AArch64 CPU. (opcache.jit_debug=0x100 should be set).
1 parent 8d715b8 commit 5fe2062

File tree

8 files changed

+315
-122
lines changed

8 files changed

+315
-122
lines changed

Zend/zend_execute.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4834,10 +4834,8 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint
48344834
} \
48354835
} while (0)
48364836

4837-
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
48384837
/* This callback disables optimization of "vm_stack_data" variable in VM */
4839-
void (*zend_touch_vm_stack_data)(void *vm_stack_data) = NULL;
4840-
#endif
4838+
ZEND_API void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data) = NULL;
48414839

48424840
#include "zend_vm_execute.h"
48434841

Zend/zend_vm_execute.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50963,12 +50963,6 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5096350963
#else
5096450964
zend_execute_data *execute_data = ex;
5096550965
#endif
50966-
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
50967-
memset(vm_stack_data.hybrid_jit_red_zone, 0, ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE);
50968-
if (zend_touch_vm_stack_data) {
50969-
zend_touch_vm_stack_data(&vm_stack_data);
50970-
}
50971-
#endif
5097250966

5097350967
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
5097450968
if (UNEXPECTED(execute_data == NULL)) {
@@ -54431,6 +54425,12 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5443154425
zend_handlers_count = sizeof(labels) / sizeof(void*);
5443254426
memset(&hybrid_halt_op, 0, sizeof(hybrid_halt_op));
5443354427
hybrid_halt_op.handler = (void*)&&HYBRID_HALT_LABEL;
54428+
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
54429+
memset(vm_stack_data.hybrid_jit_red_zone, 0, ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE);
54430+
#endif
54431+
if (zend_touch_vm_stack_data) {
54432+
zend_touch_vm_stack_data(&vm_stack_data);
54433+
}
5443454434
goto HYBRID_HALT_LABEL;
5443554435
}
5443654436
#endif

Zend/zend_vm_gen.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,12 +2089,6 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
20892089
out($f,"#else\n");
20902090
out($f,$m[1]."zend_execute_data *execute_data = ex;\n");
20912091
out($f,"#endif\n");
2092-
out($f,"#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE\n");
2093-
out($f,$m[1]."memset(vm_stack_data.hybrid_jit_red_zone, 0, ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE);\n");
2094-
out($f,$m[1]."if (zend_touch_vm_stack_data) {\n");
2095-
out($f,$m[1]."\tzend_touch_vm_stack_data(&vm_stack_data);\n");
2096-
out($f,$m[1]."}\n");
2097-
out($f,"#endif\n");
20982092
}
20992093
break;
21002094
case "INTERNAL_LABELS":
@@ -2114,6 +2108,12 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
21142108
if ($kind == ZEND_VM_KIND_HYBRID) {
21152109
out($f,$prolog."\tmemset(&hybrid_halt_op, 0, sizeof(hybrid_halt_op));\n");
21162110
out($f,$prolog."\thybrid_halt_op.handler = (void*)&&HYBRID_HALT_LABEL;\n");
2111+
out($f,"#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE\n");
2112+
out($f,$prolog."\tmemset(vm_stack_data.hybrid_jit_red_zone, 0, ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE);\n");
2113+
out($f,"#endif\n");
2114+
out($f,$prolog."\tif (zend_touch_vm_stack_data) {\n");
2115+
out($f,$prolog."\t\tzend_touch_vm_stack_data(&vm_stack_data);\n");
2116+
out($f,$prolog."\t}\n");
21172117
out($f,$prolog."\tgoto HYBRID_HALT_LABEL;\n");
21182118
} else {
21192119
out($f,$prolog."\treturn;\n");

ext/opcache/jit/zend_jit.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ zend_jit_globals jit_globals;
9494
typedef struct _zend_jit_stub {
9595
const char *name;
9696
int (*stub)(dasm_State **Dst);
97+
uint32_t offset;
98+
uint32_t adjustment;
9799
} zend_jit_stub;
98100

99-
#define JIT_STUB(name) \
100-
{JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub}
101+
#define JIT_STUB(name, offset, adjustment) \
102+
{JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, offset, adjustment}
101103

102104
zend_ulong zend_jit_profile_counter = 0;
103105
int zend_jit_profile_counter_rid = -1;
@@ -348,7 +350,9 @@ static void *dasm_link_and_encode(dasm_State **dasm_state,
348350
const zend_op *rt_opline,
349351
zend_lifetime_interval **ra,
350352
const char *name,
351-
uint32_t trace_num)
353+
uint32_t trace_num,
354+
uint32_t sp_offset,
355+
uint32_t sp_adjustment)
352356
{
353357
size_t size;
354358
int ret;
@@ -507,7 +511,9 @@ static void *dasm_link_and_encode(dasm_State **dasm_state,
507511
name,
508512
op_array,
509513
entry,
510-
size);
514+
size,
515+
sp_adj[sp_offset],
516+
sp_adj[sp_adjustment]);
511517
}
512518
}
513519
#endif
@@ -3547,7 +3553,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
35473553
}
35483554
}
35493555

3550-
handler = dasm_link_and_encode(&dasm_state, op_array, ssa, rt_opline, ra, NULL, 0);
3556+
handler = dasm_link_and_encode(&dasm_state, op_array, ssa, rt_opline, ra, NULL, 0,
3557+
(zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) ? SP_ADJ_VM : SP_ADJ_RET, SP_ADJ_JIT);
35513558
if (!handler) {
35523559
goto jit_failure;
35533560
}
@@ -4103,7 +4110,8 @@ static int zend_jit_make_stubs(void)
41034110
if (!zend_jit_stubs[i].stub(&dasm_state)) {
41044111
return 0;
41054112
}
4106-
if (!dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, zend_jit_stubs[i].name, 0)) {
4113+
if (!dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, zend_jit_stubs[i].name, 0,
4114+
zend_jit_stubs[i].offset, zend_jit_stubs[i].adjustment)) {
41074115
return 0;
41084116
}
41094117
}

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 129 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,22 @@
8383
|.define ZREG_TMP3, ZREG_X17
8484
|.define ZREG_FPTMP, ZREG_V16
8585

86-
|.define HYBRID_SPAD, #32 // padding for stack alignment
86+
|.define HYBRID_SPAD, 32 // padding for stack alignment
8787

8888
#define TMP_ZVAL_OFFSET 16
8989
#define DASM_ALIGNMENT 16
9090

91+
typedef enum _sp_adj_kind {
92+
SP_ADJ_NONE,
93+
SP_ADJ_RET,
94+
SP_ADJ_VM,
95+
SP_ADJ_JIT,
96+
SP_ADJ_ASSIGN,
97+
SP_ADJ_LAST
98+
} sp_adj_kind;
99+
100+
static int sp_adj[SP_ADJ_LAST];
101+
91102
/* Encoding of immediate. TODO: shift mode may be supported in the near future. */
92103
#define MAX_IMM12 0xfff // maximum value for imm12
93104
#define MAX_IMM16 0xffff // maximum value for imm16
@@ -196,13 +207,13 @@ static int logical_immediate_p (uint64_t value, uint32_t reg_size)
196207

197208
|.macro ADD_HYBRID_SPAD
198209
||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
199-
| add sp, sp, HYBRID_SPAD
210+
| add sp, sp, # HYBRID_SPAD
200211
||#endif
201212
|.endmacro
202213

203214
|.macro SUB_HYBRID_SPAD
204215
||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
205-
| sub sp, sp, HYBRID_SPAD
216+
| sub sp, sp, # HYBRID_SPAD
206217
||#endif
207218
|.endmacro
208219

@@ -2592,42 +2603,42 @@ static int zend_jit_assign_cv_stub(dasm_State **Dst)
25922603
}
25932604

25942605
static const zend_jit_stub zend_jit_stubs[] = {
2595-
JIT_STUB(interrupt_handler),
2596-
JIT_STUB(exception_handler),
2597-
JIT_STUB(exception_handler_undef),
2598-
JIT_STUB(leave_function),
2599-
JIT_STUB(leave_throw),
2600-
JIT_STUB(icall_throw),
2601-
JIT_STUB(throw_cannot_pass_by_ref),
2602-
JIT_STUB(undefined_offset),
2603-
JIT_STUB(undefined_index),
2604-
JIT_STUB(cannot_add_element),
2605-
JIT_STUB(undefined_offset_ex),
2606-
JIT_STUB(undefined_index_ex),
2607-
JIT_STUB(cannot_add_element_ex),
2608-
JIT_STUB(undefined_function),
2609-
JIT_STUB(negative_shift),
2610-
JIT_STUB(mod_by_zero),
2611-
JIT_STUB(invalid_this),
2612-
JIT_STUB(trace_halt),
2613-
JIT_STUB(trace_exit),
2614-
JIT_STUB(trace_escape),
2615-
JIT_STUB(hybrid_runtime_jit),
2616-
JIT_STUB(hybrid_profile_jit),
2617-
JIT_STUB(hybrid_hot_code),
2618-
JIT_STUB(hybrid_func_hot_counter),
2619-
JIT_STUB(hybrid_loop_hot_counter),
2620-
JIT_STUB(hybrid_hot_trace),
2621-
JIT_STUB(hybrid_func_trace_counter),
2622-
JIT_STUB(hybrid_ret_trace_counter),
2623-
JIT_STUB(hybrid_loop_trace_counter),
2624-
JIT_STUB(assign_const),
2625-
JIT_STUB(assign_tmp),
2626-
JIT_STUB(assign_var),
2627-
JIT_STUB(assign_cv_noref),
2628-
JIT_STUB(assign_cv),
2606+
JIT_STUB(interrupt_handler, SP_ADJ_JIT, SP_ADJ_NONE),
2607+
JIT_STUB(exception_handler, SP_ADJ_JIT, SP_ADJ_NONE),
2608+
JIT_STUB(exception_handler_undef, SP_ADJ_JIT, SP_ADJ_NONE),
2609+
JIT_STUB(leave_function, SP_ADJ_JIT, SP_ADJ_NONE),
2610+
JIT_STUB(leave_throw, SP_ADJ_JIT, SP_ADJ_NONE),
2611+
JIT_STUB(icall_throw, SP_ADJ_JIT, SP_ADJ_NONE),
2612+
JIT_STUB(throw_cannot_pass_by_ref, SP_ADJ_JIT, SP_ADJ_NONE),
2613+
JIT_STUB(undefined_offset, SP_ADJ_JIT, SP_ADJ_NONE),
2614+
JIT_STUB(undefined_index, SP_ADJ_JIT, SP_ADJ_NONE),
2615+
JIT_STUB(cannot_add_element, SP_ADJ_JIT, SP_ADJ_NONE),
2616+
JIT_STUB(undefined_offset_ex, SP_ADJ_JIT, SP_ADJ_NONE),
2617+
JIT_STUB(undefined_index_ex, SP_ADJ_JIT, SP_ADJ_NONE),
2618+
JIT_STUB(cannot_add_element_ex, SP_ADJ_JIT, SP_ADJ_NONE),
2619+
JIT_STUB(undefined_function, SP_ADJ_JIT, SP_ADJ_NONE),
2620+
JIT_STUB(negative_shift, SP_ADJ_JIT, SP_ADJ_NONE),
2621+
JIT_STUB(mod_by_zero, SP_ADJ_JIT, SP_ADJ_NONE),
2622+
JIT_STUB(invalid_this, SP_ADJ_JIT, SP_ADJ_NONE),
2623+
JIT_STUB(trace_halt, SP_ADJ_JIT, SP_ADJ_NONE),
2624+
JIT_STUB(trace_exit, SP_ADJ_JIT, SP_ADJ_NONE),
2625+
JIT_STUB(trace_escape, SP_ADJ_JIT, SP_ADJ_NONE),
2626+
JIT_STUB(hybrid_runtime_jit, SP_ADJ_VM, SP_ADJ_NONE),
2627+
JIT_STUB(hybrid_profile_jit, SP_ADJ_VM, SP_ADJ_NONE),
2628+
JIT_STUB(hybrid_hot_code, SP_ADJ_VM, SP_ADJ_NONE),
2629+
JIT_STUB(hybrid_func_hot_counter, SP_ADJ_VM, SP_ADJ_NONE),
2630+
JIT_STUB(hybrid_loop_hot_counter, SP_ADJ_VM, SP_ADJ_NONE),
2631+
JIT_STUB(hybrid_hot_trace, SP_ADJ_VM, SP_ADJ_NONE),
2632+
JIT_STUB(hybrid_func_trace_counter, SP_ADJ_VM, SP_ADJ_NONE),
2633+
JIT_STUB(hybrid_ret_trace_counter, SP_ADJ_VM, SP_ADJ_NONE),
2634+
JIT_STUB(hybrid_loop_trace_counter, SP_ADJ_VM, SP_ADJ_NONE),
2635+
JIT_STUB(assign_const, SP_ADJ_RET, SP_ADJ_ASSIGN),
2636+
JIT_STUB(assign_tmp, SP_ADJ_RET, SP_ADJ_ASSIGN),
2637+
JIT_STUB(assign_var, SP_ADJ_RET, SP_ADJ_ASSIGN),
2638+
JIT_STUB(assign_cv_noref, SP_ADJ_RET, SP_ADJ_ASSIGN),
2639+
JIT_STUB(assign_cv, SP_ADJ_RET, SP_ADJ_ASSIGN),
26292640
#ifdef CONTEXT_THREADED_JIT
2630-
JIT_STUB(context_threaded_call),
2641+
JIT_STUB(context_threaded_call, SP_ADJ_NONE, SP_ADJ_NONE),
26312642
#endif
26322643
};
26332644

@@ -2637,6 +2648,66 @@ extern char *_tls_start;
26372648
extern char *_tls_end;
26382649
#endif
26392650

2651+
#ifdef HAVE_GDB
2652+
# if 0
2653+
typedef struct _Unwind_Context _Unwind_Context;
2654+
typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
2655+
extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
2656+
extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
2657+
2658+
typedef struct _zend_jit_unwind_arg {
2659+
int cnt;
2660+
uintptr_t cfa[3];
2661+
} zend_jit_unwind_arg;
2662+
2663+
static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
2664+
{
2665+
zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
2666+
arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
2667+
arg->cnt++;
2668+
if (arg->cnt == 3) {
2669+
return 5; // _URC_END_OF_STACK
2670+
}
2671+
return 0; // _URC_NO_REASON;
2672+
}
2673+
2674+
static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
2675+
{
2676+
zend_jit_unwind_arg arg;
2677+
2678+
memset(&arg, 0, sizeof(arg));
2679+
_Unwind_Backtrace(zend_jit_unwind_cb, &arg);
2680+
if (arg.cnt == 3) {
2681+
sp_adj[SP_ADJ_VM] = arg.cfa[2] - arg.cfa[1];
2682+
}
2683+
}
2684+
# else
2685+
static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
2686+
{
2687+
uintptr_t ret;
2688+
2689+
__asm__ (
2690+
"ldr %0, [x29]\n\t"
2691+
"sub %0 ,%0, x29"
2692+
: "=r"(ret));
2693+
2694+
sp_adj[SP_ADJ_VM] = ret;
2695+
}
2696+
# endif
2697+
2698+
extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
2699+
2700+
static zend_never_inline void zend_jit_set_sp_adj_vm(void)
2701+
{
2702+
void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
2703+
2704+
orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
2705+
zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
2706+
execute_ex(NULL); // set sp_adj[SP_ADJ_VM]
2707+
zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
2708+
}
2709+
#endif
2710+
26402711
static int zend_jit_setup(void)
26412712
{
26422713
allowed_opt_flags = 0;
@@ -2753,6 +2824,24 @@ static int zend_jit_setup(void)
27532824
# endif
27542825
#endif
27552826

2827+
memset(sp_adj, 0, sizeof(sp_adj));
2828+
#ifdef HAVE_GDB
2829+
sp_adj[SP_ADJ_RET] = 0;
2830+
sp_adj[SP_ADJ_ASSIGN] = 32;
2831+
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2832+
zend_jit_set_sp_adj_vm(); // set sp_adj[SP_ADJ_VM]
2833+
#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
2834+
|| sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_VM] + HYBRID_SPAD; // sub r4, HYBRID_SPAD
2835+
#else
2836+
|| sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_VM];
2837+
#endif
2838+
} else if (GCC_GLOBAL_REGS) {
2839+
|| sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_RET] + SPAD; // sub r4, SPAD
2840+
} else {
2841+
|| sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_RET] + NR_SPAD; // sub r4, NR_SPAD
2842+
}
2843+
#endif
2844+
27562845
return SUCCESS;
27572846
}
27582847

@@ -2780,8 +2869,10 @@ static int zend_jit_prologue(dasm_State **Dst)
27802869
| SUB_HYBRID_SPAD
27812870
} else if (GCC_GLOBAL_REGS) {
27822871
| stp x29, x30, [sp, # -SPAD]! // stack alignment
2872+
|// mov x29, sp
27832873
} else {
27842874
| stp x29, x30, [sp, # -NR_SPAD]! // stack alignment
2875+
|// mov x29, sp
27852876
| stp FP, RX, T2 // save FP and IP
27862877
| mov FP, FCARG1x
27872878
}

0 commit comments

Comments
 (0)