Skip to content

Commit 617276d

Browse files
committed
Use capstone disassembler, if available.
1 parent fd62917 commit 617276d

File tree

5 files changed

+214
-30
lines changed

5 files changed

+214
-30
lines changed

ext/opcache/config.m4

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ if test "$PHP_OPCACHE" != "no"; then
7070
DASM_FLAGS="$DASM_FLAGS -D ZTS=1"
7171
fi
7272

73+
PKG_CHECK_MODULES([CAPSTONE], [capstone >= 3.0.0],
74+
[have_capstone="yes"], [have_capstone="no"])
75+
if test "$have_capstone" = "yes"; then
76+
AC_DEFINE(HAVE_CAPSTONE, 1, [ ])
77+
PHP_EVAL_LIBLINE($CAPSTONE_LIBS, OPCACHE_SHARED_LIBADD)
78+
PHP_EVAL_INCLINE($CAPSTONE_CFLAGS)
79+
fi
80+
7381
PHP_SUBST(DASM_FLAGS)
7482

7583
AC_MSG_CHECKING(for opagent in default path)

ext/opcache/jit/Makefile.frag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ $(builddir)/jit/zend_jit_x86.c: $(srcdir)/jit/zend_jit_x86.dasc $(srcdir)/jit/dy
88
$(builddir)/jit/zend_jit.lo: \
99
$(builddir)/jit/zend_jit_x86.c \
1010
$(srcdir)/jit/zend_jit_helpers.c \
11-
$(srcdir)/jit/zend_jit_disasm_x86.c \
11+
$(srcdir)/jit/zend_jit_disasm.c \
1212
$(srcdir)/jit/zend_jit_gdb.c \
1313
$(srcdir)/jit/zend_jit_perf_dump.c \
1414
$(srcdir)/jit/zend_jit_oprofile.c \

ext/opcache/jit/Makefile.frag.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ext\opcache\jit\zend_jit_x86.c: ext\opcache\jit\zend_jit_x86.dasc $(BUILD_DIR)\\
99
$(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \
1010
ext/opcache/jit/zend_jit_x86.c \
1111
ext/opcache/jit/zend_jit_helpers.c \
12-
ext/opcache/jit/zend_jit_disasm_x86.c \
12+
ext/opcache/jit/zend_jit_disasm.c \
1313
ext/opcache/jit/zend_jit_gdb.c \
1414
ext/opcache/jit/zend_jit_perf_dump.c \
1515
ext/opcache/jit/zend_jit_oprofile.c \

ext/opcache/jit/zend_jit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ static bool zend_long_is_power_of_two(zend_long x)
206206

207207
#include "dynasm/dasm_x86.h"
208208
#include "jit/zend_jit_helpers.c"
209-
#include "jit/zend_jit_disasm_x86.c"
209+
#include "jit/zend_jit_disasm.c"
210210
#ifndef _WIN32
211211
#include "jit/zend_jit_gdb.c"
212212
#include "jit/zend_jit_perf_dump.c"

ext/opcache/jit/zend_jit_disasm_x86.c renamed to ext/opcache/jit/zend_jit_disasm.c

Lines changed: 203 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,29 @@
1414
+----------------------------------------------------------------------+
1515
| Authors: Dmitry Stogov <[email protected]> |
1616
| Xinchen Hui <[email protected]> |
17+
| Hao Sun <[email protected]> |
1718
+----------------------------------------------------------------------+
1819
*/
1920

20-
#define HAVE_DISASM 1
21-
#define DISASM_INTEL_SYNTAX 0
2221

23-
#include "jit/libudis86/itab.c"
24-
#include "jit/libudis86/decode.c"
25-
#include "jit/libudis86/syn.c"
26-
#if DISASM_INTEL_SYNTAX
27-
# include "jit/libudis86/syn-intel.c"
22+
#ifdef HAVE_CAPSTONE
23+
# define HAVE_DISASM 1
24+
# include <capstone/capstone.h>
25+
# define HAVE_CAPSTONE_ITER 1
2826
#else
29-
# include "jit/libudis86/syn-att.c"
30-
#endif
31-
#include "jit/libudis86/udis86.c"
27+
# define HAVE_DISASM 1
28+
# define DISASM_INTEL_SYNTAX 0
29+
30+
# include "jit/libudis86/itab.c"
31+
# include "jit/libudis86/decode.c"
32+
# include "jit/libudis86/syn.c"
33+
# if DISASM_INTEL_SYNTAX
34+
# include "jit/libudis86/syn-intel.c"
35+
# else
36+
# include "jit/libudis86/syn-att.c"
37+
# endif
38+
# include "jit/libudis86/udis86.c"
39+
#endif /* HAVE_CAPSTONE */
3240

3341
static void zend_jit_disasm_add_symbol(const char *name,
3442
uint64_t addr,
@@ -48,8 +56,6 @@ static void zend_jit_disasm_add_symbol(const char *name,
4856
#include <dlfcn.h>
4957
#endif
5058

51-
static struct ud ud;
52-
5359
struct _sym_node {
5460
uint64_t addr;
5561
uint64_t end;
@@ -214,12 +220,34 @@ static const char* zend_jit_disasm_find_symbol(uint64_t addr,
214220
return NULL;
215221
}
216222

217-
static const char* zend_jit_disasm_resolver(struct ud *ud,
223+
#ifdef HAVE_CAPSTONE
224+
static uint64_t zend_jit_disasm_branch_target(csh cs, const cs_insn *insn)
225+
{
226+
unsigned int i;
227+
228+
if (cs_insn_group(cs, insn, X86_GRP_JUMP)) {
229+
for (i = 0; i < insn->detail->x86.op_count; i++) {
230+
if (insn->detail->x86.operands[i].type == X86_OP_IMM) {
231+
return insn->detail->x86.operands[i].imm;
232+
}
233+
}
234+
}
235+
236+
return 0;
237+
}
238+
#endif
239+
240+
static const char* zend_jit_disasm_resolver(
241+
#ifndef HAVE_CAPSTONE
242+
struct ud *ud,
243+
#endif
218244
uint64_t addr,
219245
int64_t *offset)
220246
{
221247
#ifndef _WIN32
248+
# ifndef HAVE_CAPSTONE
222249
((void)ud);
250+
# endif
223251
const char *name;
224252
void *a = (void*)(zend_uintptr_t)(addr);
225253
Dl_info info;
@@ -261,16 +289,69 @@ static int zend_jit_disasm(const char *name,
261289
zval zv, *z;
262290
zend_long n, m;
263291
HashTable labels;
264-
const struct ud_operand *op;
265292
uint64_t addr;
266293
int b;
294+
#ifdef HAVE_CAPSTONE
295+
csh cs;
296+
cs_insn *insn;
297+
# ifdef HAVE_CAPSTONE_ITER
298+
const uint8_t *cs_code;
299+
size_t cs_size;
300+
uint64_t cs_addr;
301+
# else
302+
size_t count, i;
303+
# endif
304+
const char *sym;
305+
int64_t offset = 0;
306+
char *p, *q, *r;
307+
#else
308+
struct ud ud;
309+
const struct ud_operand *op;
310+
#endif
311+
312+
#ifdef HAVE_CAPSTONE
313+
# if defined(__x86_64__) || defined(_WIN64)
314+
if (cs_open(CS_ARCH_X86, CS_MODE_64, &cs) != CS_ERR_OK)
315+
return 0;
316+
cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON);
317+
# if DISASM_INTEL_SYNTAX
318+
cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
319+
# else
320+
cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
321+
# endif
322+
# else
323+
if (cs_open(CS_ARCH_X86, CS_MODE_32, &cs) != CS_ERR_OK)
324+
return 0;
325+
cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON);
326+
# if DISASM_INTEL_SYNTAX
327+
cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
328+
# else
329+
cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
330+
# endif
331+
# endif
332+
#else
333+
ud_init(&ud);
334+
# if defined(__x86_64__) || defined(_WIN64)
335+
ud_set_mode(&ud, 64);
336+
# else
337+
ud_set_mode(&ud, 32);
338+
# endif
339+
# if DISASM_INTEL_SYNTAX
340+
ud_set_syntax(&ud, UD_SYN_INTEL);
341+
# else
342+
ud_set_syntax(&ud, UD_SYN_ATT);
343+
# endif
344+
ud_set_sym_resolver(&ud, zend_jit_disasm_resolver);
345+
#endif /* HAVE_CAPSTONE */
267346

268347
if (name) {
269348
fprintf(stderr, "%s: ; (%s)\n", name, filename ? filename : "unknown");
270349
}
271350

351+
#ifndef HAVE_CAPSTONE
272352
ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
273353
ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
354+
#endif
274355

275356
zend_hash_init(&labels, 8, NULL, NULL, 0);
276357
if (op_array && cfg) {
@@ -284,6 +365,26 @@ static int zend_jit_disasm(const char *name,
284365
}
285366
}
286367
}
368+
#ifdef HAVE_CAPSTONE
369+
ZVAL_TRUE(&zv);
370+
# ifdef HAVE_CAPSTONE_ITER
371+
cs_code = start;
372+
cs_size = (uint8_t*)end - (uint8_t*)start;
373+
cs_addr = (uint64_t)(uintptr_t)cs_code;
374+
insn = cs_malloc(cs);
375+
while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) {
376+
if ((addr = zend_jit_disasm_branch_target(cs, insn))) {
377+
# else
378+
count = cs_disasm(cs, start, (uint8_t*)end - (uint8_t*)start, (uintptr_t)start, 0, &insn);
379+
for (i = 0; i < count; i++) {
380+
if ((addr = zend_jit_disasm_branch_target(cs, &(insn[i])))) {
381+
# endif
382+
if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
383+
zend_hash_index_add(&labels, addr, &zv);
384+
}
385+
}
386+
}
387+
#else
287388
ZVAL_TRUE(&zv);
288389
while (ud_disassemble(&ud)) {
289390
op = ud_insn_opr(&ud, 0);
@@ -294,6 +395,7 @@ static int zend_jit_disasm(const char *name,
294395
}
295396
}
296397
}
398+
#endif
297399

298400
zend_hash_sort(&labels, zend_jit_cmp_labels, 0);
299401

@@ -309,6 +411,88 @@ static int zend_jit_disasm(const char *name,
309411
}
310412
} ZEND_HASH_FOREACH_END();
311413

414+
#ifdef HAVE_CAPSTONE
415+
# ifdef HAVE_CAPSTONE_ITER
416+
cs_code = start;
417+
cs_size = (uint8_t*)end - (uint8_t*)start;
418+
cs_addr = (uint64_t)(uintptr_t)cs_code;
419+
while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) {
420+
z = zend_hash_index_find(&labels, insn->address);
421+
# else
422+
for (i = 0; i < count; i++) {
423+
z = zend_hash_index_find(&labels, insn[i].address);
424+
# endif
425+
if (z) {
426+
if (Z_LVAL_P(z) < 0) {
427+
fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
428+
} else {
429+
fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
430+
}
431+
}
432+
433+
# ifdef HAVE_CAPSTONE_ITER
434+
fprintf(stderr, "\t%s ", insn->mnemonic);
435+
p = insn->op_str;
436+
# else
437+
fprintf(stderr, "\t%s ", insn[i].mnemonic);
438+
p = insn[i].op_str;
439+
# endif
440+
/* Try to replace the target addresses with a symbols */
441+
while ((q = strchr(p, 'x')) != NULL) {
442+
if (p != q && *(q-1) == '0') {
443+
r = q + 1;
444+
addr = 0;
445+
while (1) {
446+
if (*r >= '0' && *r <= '9') {
447+
addr = addr * 16 + (*r - '0');
448+
} else if (*r >= 'A' && *r <= 'F') {
449+
addr = addr * 16 + (*r - 'A' + 10);
450+
} else if (*r >= 'a' && *r <= 'f') {
451+
addr = addr * 16 + (*r - 'a' + 10);
452+
} else {
453+
break;
454+
}
455+
r++;
456+
}
457+
if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
458+
if ((z = zend_hash_index_find(&labels, addr))) {
459+
if (Z_LVAL_P(z) < 0) {
460+
fwrite(p, 1, q - p - 1, stderr);
461+
fprintf(stderr, ".ENTRY" ZEND_LONG_FMT, -Z_LVAL_P(z));
462+
} else {
463+
fwrite(p, 1, q - p - 1, stderr);
464+
fprintf(stderr, ".L" ZEND_LONG_FMT, Z_LVAL_P(z));
465+
}
466+
} else {
467+
fwrite(p, 1, r - p, stderr);
468+
}
469+
} else if ((sym = zend_jit_disasm_resolver(addr, &offset))) {
470+
fwrite(p, 1, q - p - 1, stderr);
471+
fputs(sym, stderr);
472+
if (offset != 0) {
473+
if (offset > 0) {
474+
fprintf(stderr, "+%" PRIx64, offset);
475+
} else {
476+
fprintf(stderr, "-%" PRIx64, offset);
477+
}
478+
}
479+
} else {
480+
fwrite(p, 1, r - p, stderr);
481+
}
482+
p = r;
483+
} else {
484+
fwrite(p, 1, q - p + 1, stderr);
485+
p = q + 1;
486+
}
487+
}
488+
fprintf(stderr, "%s\n", p);
489+
}
490+
# ifdef HAVE_CAPSTONE_ITER
491+
cs_free(insn, 1);
492+
# else
493+
cs_free(insn, count);
494+
# endif
495+
#else
312496
ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
313497
ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
314498

@@ -351,28 +535,20 @@ static int zend_jit_disasm(const char *name,
351535
}
352536
fprintf(stderr, "\t%s\n", ud_insn_asm(&ud));
353537
}
538+
#endif
354539
fprintf(stderr, "\n");
355540

356541
zend_hash_destroy(&labels);
357542

543+
#ifdef HAVE_CAPSTONE
544+
cs_close(&cs);
545+
#endif
546+
358547
return 1;
359548
}
360549

361550
static int zend_jit_disasm_init(void)
362551
{
363-
ud_init(&ud);
364-
#if defined(__x86_64__) || defined(_WIN64)
365-
ud_set_mode(&ud, 64);
366-
#else
367-
ud_set_mode(&ud, 32);
368-
#endif
369-
#if DISASM_INTEL_SYNTAX
370-
ud_set_syntax(&ud, UD_SYN_INTEL);
371-
#else
372-
ud_set_syntax(&ud, UD_SYN_ATT);
373-
#endif
374-
ud_set_sym_resolver(&ud, zend_jit_disasm_resolver);
375-
376552
#ifndef ZTS
377553
#define REGISTER_EG(n) \
378554
zend_jit_disasm_add_symbol("EG("#n")", \

0 commit comments

Comments
 (0)