From 60fbd6df951e2181e0a2f5c4d81f6bde0feae3ee Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 13 Jul 2021 15:32:14 +0200 Subject: [PATCH] replace phpdbg custom opcode dumper with O+ dump (#7227) --- Zend/Optimizer/zend_dump.c | 6 +- Zend/Optimizer/zend_dump.h | 2 + sapi/phpdbg/config.m4 | 2 +- sapi/phpdbg/config.w32 | 2 +- sapi/phpdbg/phpdbg.1.in | 4 - sapi/phpdbg/phpdbg.c | 30 ---- sapi/phpdbg/phpdbg.h | 30 ++-- sapi/phpdbg/phpdbg_bp.c | 1 - sapi/phpdbg/phpdbg_break.c | 1 - sapi/phpdbg/phpdbg_help.c | 2 - sapi/phpdbg/phpdbg_opcode.c | 192 -------------------------- sapi/phpdbg/phpdbg_opcode.h | 44 ------ sapi/phpdbg/phpdbg_print.c | 103 +++++--------- sapi/phpdbg/phpdbg_print.h | 5 +- sapi/phpdbg/phpdbg_prompt.c | 6 +- sapi/phpdbg/phpdbg_set.c | 30 ---- sapi/phpdbg/phpdbg_set.h | 1 - sapi/phpdbg/phpdbg_utils.c | 1 - sapi/phpdbg/tests/exceptions_003.phpt | 14 +- sapi/phpdbg/tests/next_001.phpt | 14 +- sapi/phpdbg/tests/print_001.phpt | 66 +++++---- sapi/phpdbg/tests/print_002.phpt | 23 +-- sapi/phpdbg/tests/stepping_001.phpt | 33 ++--- 23 files changed, 137 insertions(+), 475 deletions(-) delete mode 100644 sapi/phpdbg/phpdbg_opcode.c delete mode 100644 sapi/phpdbg/phpdbg_opcode.h diff --git a/Zend/Optimizer/zend_dump.c b/Zend/Optimizer/zend_dump.c index ab1744f9872..49e14e9d36a 100644 --- a/Zend/Optimizer/zend_dump.c +++ b/Zend/Optimizer/zend_dump.c @@ -716,11 +716,15 @@ ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block } } -static void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data) +ZEND_API void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data) { int len = 0; const zend_ssa *ssa = NULL; zend_ssa_op *ssa_op = NULL; + + if (dump_flags & ZEND_DUMP_LINE_NUMBERS) { + fprintf(stderr, "L%04u ", opline->lineno); + } len = fprintf(stderr, "%04u", (uint32_t)(opline - op_array->opcodes)); fprintf(stderr, "%*c", 5-len, ' '); diff --git a/Zend/Optimizer/zend_dump.h b/Zend/Optimizer/zend_dump.h index 1bc71f9748d..57f0be0f97f 100644 --- a/Zend/Optimizer/zend_dump.h +++ b/Zend/Optimizer/zend_dump.h @@ -27,11 +27,13 @@ #define ZEND_DUMP_CFG (1<<2) #define ZEND_DUMP_SSA (1<<3) #define ZEND_DUMP_LIVE_RANGES (1<<4) +#define ZEND_DUMP_LINE_NUMBERS (1<<5) BEGIN_EXTERN_C() ZEND_API void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data); ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const zend_ssa *ssa, const zend_ssa_op *ssa_op); +ZEND_API void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data); void zend_dump_dominators(const zend_op_array *op_array, const zend_cfg *cfg); void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg); void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa); diff --git a/sapi/phpdbg/config.m4 b/sapi/phpdbg/config.m4 index 545517f9124..2f9a5e4a0f8 100644 --- a/sapi/phpdbg/config.m4 +++ b/sapi/phpdbg/config.m4 @@ -30,7 +30,7 @@ if test "$BUILD_PHPDBG" = "" && test "$PHP_PHPDBG" != "no"; then fi PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" - PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_io.c phpdbg_out.c" + PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_io.c phpdbg_out.c" AC_MSG_CHECKING([for phpdbg and readline integration]) if test "$PHP_PHPDBG_READLINE" = "yes"; then diff --git a/sapi/phpdbg/config.w32 b/sapi/phpdbg/config.w32 index 96eb71fdc78..90db273143c 100644 --- a/sapi/phpdbg/config.w32 +++ b/sapi/phpdbg/config.w32 @@ -2,7 +2,7 @@ ARG_ENABLE('phpdbg', 'Build phpdbg', 'no'); ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c ' + - 'phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c ' + + 'phpdbg_print.c phpdbg_bp.c phpdbg_list.c phpdbg_utils.c ' + 'phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c '+ 'phpdbg_parser.c phpdbg_lexer.c phpdbg_sigsafe.c phpdbg_io.c phpdbg_out.c'; PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; diff --git a/sapi/phpdbg/phpdbg.1.in b/sapi/phpdbg/phpdbg.1.in index 258d12f3979..29f832407db 100644 --- a/sapi/phpdbg/phpdbg.1.in +++ b/sapi/phpdbg/phpdbg.1.in @@ -49,10 +49,6 @@ Override .phpgdbinit location (implies -I) .B \-I Ignore .phpdbginit (default init file) .TP -.B \-O \fIfile\fR -Set oplog output to -.IR file -.TP .B \-r Jump straight to run .TP diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 4503e85d928..193a89bfa68 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -122,7 +122,6 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */ pg->in_execution = 0; pg->bp_count = 0; pg->flags = PHPDBG_DEFAULT_FLAGS; - pg->oplog = NULL; memset(pg->io, 0, sizeof(pg->io)); pg->frame.num = 0; pg->sapi_name_ptr = NULL; @@ -199,11 +198,6 @@ static PHP_MSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ PHPDBG_G(exec) = NULL; } - if (PHPDBG_G(oplog)) { - fclose(PHPDBG_G(oplog)); - PHPDBG_G(oplog) = NULL; - } - if (PHPDBG_G(oplog_list)) { phpdbg_oplog_list *cur = PHPDBG_G(oplog_list); do { @@ -1134,8 +1128,6 @@ int main(int argc, char **argv) /* {{{ */ char *init_file; size_t init_file_len; bool init_file_default; - char *oplog_file; - size_t oplog_file_len; uint64_t flags; char *php_optarg; int php_optind, opt, show_banner = 1; @@ -1186,8 +1178,6 @@ phpdbg_main: init_file = NULL; init_file_len = 0; init_file_default = 1; - oplog_file = NULL; - oplog_file_len = 0; flags = PHPDBG_DEFAULT_FLAGS; is_exit = 0; php_optarg = NULL; @@ -1281,13 +1271,6 @@ phpdbg_main: } } break; - case 'O': { /* set oplog output */ - oplog_file_len = strlen(php_optarg); - if (oplog_file_len) { - oplog_file = strdup(php_optarg); - } - } break; - case 'v': /* set quietness off */ flags &= ~PHPDBG_IS_QUIET; break; @@ -1442,9 +1425,6 @@ phpdbg_main: if (exec) { free(exec); } - if (oplog_file) { - free(oplog_file); - } if (init_file) { free(init_file); } @@ -1534,15 +1514,6 @@ phpdbg_main: php_stream_stdio_ops.write = phpdbg_stdiop_write; #endif - if (oplog_file) { /* open oplog */ - PHPDBG_G(oplog) = fopen(oplog_file, "w+"); - if (!PHPDBG_G(oplog)) { - phpdbg_error("Failed to open oplog %s", oplog_file); - } - free(oplog_file); - oplog_file = NULL; - } - { zval *zv = zend_hash_str_find(php_stream_get_url_stream_wrappers_hash(), ZEND_STRL("php")); php_stream_wrapper *tmp_wrapper = Z_PTR_P(zv); @@ -1757,7 +1728,6 @@ phpdbg_out: settings->exec = zend_strndup(PHPDBG_G(exec), PHPDBG_G(exec_len)); settings->exec_len = PHPDBG_G(exec_len); } - settings->oplog = PHPDBG_G(oplog); settings->prompt[0] = PHPDBG_G(prompt)[0]; settings->prompt[1] = PHPDBG_G(prompt)[1]; memcpy(ZEND_VOIDP(settings->colors), PHPDBG_G(colors), sizeof(settings->colors)); diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h index 46b1eced118..789abecc9e7 100644 --- a/sapi/phpdbg/phpdbg.h +++ b/sapi/phpdbg/phpdbg.h @@ -100,15 +100,6 @@ #define PHPDBG_DEFAULT_PROMPT "prompt>" /* }}} */ -/* Hey, apple. One shouldn't define *functions* from the standard C library as macros. */ -#ifdef memcpy -#define memcpy_tmp(...) memcpy(__VA_ARGS__) -#undef memcpy -#define memcpy(...) memcpy_tmp(__VA_ARGS__) -#endif - -#if !defined(PHPDBG_WEBDATA_TRANSFER_H) && !defined(PHPDBG_WEBHELPER_H) - #ifdef ZTS # define PHPDBG_G(v) ZEND_TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) #else @@ -123,7 +114,6 @@ #include "phpdbg_btree.h" #include "phpdbg_watch.h" #include "phpdbg_bp.h" -#include "phpdbg_opcode.h" int phpdbg_do_parse(phpdbg_param_t *stack, char *input); @@ -223,6 +213,23 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input); void phpdbg_register_file_handles(void); +typedef struct _phpdbg_oplog_entry phpdbg_oplog_entry; +struct _phpdbg_oplog_entry { + phpdbg_oplog_entry *next; + zend_string *function_name; + zend_class_entry *scope; + zend_string *filename; + zend_op *opcodes; + zend_op *op; +}; + +typedef struct _phpdbg_oplog_list phpdbg_oplog_list; +struct _phpdbg_oplog_list { + phpdbg_oplog_list *prev; + phpdbg_oplog_entry start; /* Only "next" member used. */ +}; + + /* {{{ structs */ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */ @@ -266,7 +273,6 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) zend_op_array *(*compile_string)(zend_string *source_string, const char *filename); HashTable file_sources; - FILE *oplog; /* opline log */ zend_arena *oplog_arena; /* arena for storing oplog */ phpdbg_oplog_list *oplog_list; /* list of oplog starts */ phpdbg_oplog_entry *oplog_cur; /* current oplog entry */ @@ -304,6 +310,4 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) zend_ulong lines; /* max number of lines to display */ ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ -#endif - #endif /* PHPDBG_H */ diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index ae35c740a59..e48ed5ceba2 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -21,7 +21,6 @@ #include "phpdbg.h" #include "phpdbg_bp.h" #include "phpdbg_utils.h" -#include "phpdbg_opcode.h" #include "zend_globals.h" #include "ext/standard/php_string.h" diff --git a/sapi/phpdbg/phpdbg_break.c b/sapi/phpdbg/phpdbg_break.c index ce4e1e1351e..481e4b8693b 100644 --- a/sapi/phpdbg/phpdbg_break.c +++ b/sapi/phpdbg/phpdbg_break.c @@ -19,7 +19,6 @@ #include "phpdbg.h" #include "phpdbg_print.h" #include "phpdbg_utils.h" -#include "phpdbg_opcode.h" #include "phpdbg_break.h" #include "phpdbg_bp.h" #include "phpdbg_prompt.h" diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c index 36eb8600bd0..b162c4b39fe 100644 --- a/sapi/phpdbg/phpdbg_help.c +++ b/sapi/phpdbg/phpdbg_help.c @@ -391,7 +391,6 @@ phpdbg_help_text_t phpdbg_help_text[] = { " **-b** Disable colour" CR " **-i** **-i**my.init Set .phpdbginit file" CR " **-I** Ignore default .phpdbginit" CR -" **-O** **-O**my.oplog Sets oplog output file" CR " **-r** Run execution context" CR " **-rr** Run execution context and quit after execution (not respecting breakpoints)" CR " **-e** Generate extended information for debugger/profiler" CR @@ -872,7 +871,6 @@ phpdbg_help_text_t phpdbg_help_text[] = { " **prompt** **p** set the prompt" CR " **color** **c** set color " CR " **colors** **C** set colors []" CR -" **oplog** **O** set oplog [output]" CR " **break** **b** set break **id** " CR " **breaks** **B** set breaks []" CR " **quiet** **q** set quiet []" CR diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c deleted file mode 100644 index e57e1bfb9c9..00000000000 --- a/sapi/phpdbg/phpdbg_opcode.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Felipe Pena | - | Authors: Joe Watkins | - | Authors: Bob Weinand | - +----------------------------------------------------------------------+ -*/ - -#include "phpdbg.h" -#include "zend_vm_opcodes.h" -#include "zend_compile.h" -#include "phpdbg_opcode.h" -#include "phpdbg_utils.h" -#include "ext/standard/php_string.h" - -ZEND_EXTERN_MODULE_GLOBALS(phpdbg) - -static inline const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */ -{ - const char *ret = zend_get_opcode_name(opcode); - if (ret) { - return ret + 5; /* Skip ZEND_ prefix */ - } - return "UNKNOWN"; -} /* }}} */ - -static inline char *phpdbg_decode_op( - zend_op_array *ops, const zend_op *opline, const znode_op *op, uint32_t type) /* {{{ */ -{ - char *decode = NULL; - - switch (type) { - case IS_CV: { - zend_string *var = ops->vars[EX_VAR_TO_NUM(op->var)]; - spprintf(&decode, 0, "$%.*s%c", - ZSTR_LEN(var) <= 19 ? (int) ZSTR_LEN(var) : 18, - ZSTR_VAL(var), ZSTR_LEN(var) <= 19 ? 0 : '+'); - } break; - - case IS_VAR: - spprintf(&decode, 0, "@%u", EX_VAR_TO_NUM(op->var) - ops->last_var); - break; - case IS_TMP_VAR: - spprintf(&decode, 0, "~%u", EX_VAR_TO_NUM(op->var) - ops->last_var); - break; - case IS_CONST: { - zval *literal = RT_CONSTANT(opline, *op); - decode = phpdbg_short_zval_print(literal, 20); - } break; - } - return decode; -} /* }}} */ - -char *phpdbg_decode_input_op( - zend_op_array *ops, const zend_op *opline, znode_op op, zend_uchar op_type, - uint32_t flags) { - char *result = NULL; - if (op_type != IS_UNUSED) { - result = phpdbg_decode_op(ops, opline, &op, op_type); - } else if (ZEND_VM_OP_JMP_ADDR == (flags & ZEND_VM_OP_MASK)) { - spprintf(&result, 0, "J%td", OP_JMP_ADDR(opline, op) - ops->opcodes); - } else if (ZEND_VM_OP_NUM == (flags & ZEND_VM_OP_MASK)) { - spprintf(&result, 0, "%" PRIu32, op.num); - } else if (ZEND_VM_OP_TRY_CATCH == (flags & ZEND_VM_OP_MASK)) { - if (op.num != (uint32_t)-1) { - spprintf(&result, 0, "try-catch(%" PRIu32 ")", op.num); - } - } else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) { - result = estrdup("THIS"); - } else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) { - result = estrdup("NEXT"); - } else if (ZEND_VM_OP_CLASS_FETCH == (flags & ZEND_VM_OP_MASK)) { - //zend_dump_class_fetch_type(op.num); - } else if (ZEND_VM_OP_CONSTRUCTOR == (flags & ZEND_VM_OP_MASK)) { - result = estrdup("CONSTRUCTOR"); - } - return result; -} - -char *phpdbg_decode_opline(zend_op_array *ops, zend_op *opline) /*{{{ */ -{ - const char *opcode_name = phpdbg_decode_opcode(opline->opcode); - uint32_t flags = zend_get_opcode_flags(opline->opcode); - char *result, *decode[4] = {NULL, NULL, NULL, NULL}; - - /* OpcodeName */ - if (opline->extended_value) { - spprintf(&decode[0], 0, "%s<%" PRIi32 ">", opcode_name, opline->extended_value); - } - - /* OP1 */ - decode[1] = phpdbg_decode_input_op( - ops, opline, opline->op1, opline->op1_type, ZEND_VM_OP1_FLAGS(flags)); - - /* OP2 */ - decode[2] = phpdbg_decode_input_op( - ops, opline, opline->op2, opline->op2_type, ZEND_VM_OP2_FLAGS(flags)); - - /* RESULT */ - switch (opline->opcode) { - case ZEND_CATCH: - if (opline->extended_value & ZEND_LAST_CATCH) { - if (decode[2]) { - efree(decode[2]); - decode[2] = NULL; - } - } - decode[3] = phpdbg_decode_op(ops, opline, &opline->result, opline->result_type); - break; - default: - decode[3] = phpdbg_decode_op(ops, opline, &opline->result, opline->result_type); - break; - } - - spprintf(&result, 0, - "%-23s %-20s %-20s %-20s", - decode[0] ? decode[0] : opcode_name, - decode[1] ? decode[1] : "", - decode[2] ? decode[2] : "", - decode[3] ? decode[3] : ""); - - if (decode[0]) - efree(decode[0]); - if (decode[1]) - efree(decode[1]); - if (decode[2]) - efree(decode[2]); - if (decode[3]) - efree(decode[3]); - - return result; -} /* }}} */ - -void phpdbg_print_opline_ex(zend_execute_data *execute_data, bool ignore_flags) /* {{{ */ -{ - /* force out a line while stepping so the user knows what is happening */ - if (ignore_flags || - (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || - (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) || - (PHPDBG_G(oplog)))) { - - zend_op *opline = (zend_op *) execute_data->opline; - char *decode = phpdbg_decode_opline(&execute_data->func->op_array, opline); - - if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) { - /* output line info */ - phpdbg_notice("L%-5u %16p %s %s", - opline->lineno, - opline, - decode, - execute_data->func->op_array.filename ? ZSTR_VAL(execute_data->func->op_array.filename) : "unknown"); - } - - if (!ignore_flags && PHPDBG_G(oplog)) { - phpdbg_log_internal(fileno(PHPDBG_G(oplog)), "L%-5u %16p %s %s\n", - opline->lineno, - opline, - decode, - execute_data->func->op_array.filename ? ZSTR_VAL(execute_data->func->op_array.filename) : "unknown"); - } - - efree(decode); - } - - if (PHPDBG_G(oplog_list)) { - phpdbg_oplog_entry *cur = zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry)); - zend_op_array *op_array = &execute_data->func->op_array; - cur->op = (zend_op *) execute_data->opline; - cur->opcodes = op_array->opcodes; - cur->filename = op_array->filename; - cur->scope = op_array->scope; - cur->function_name = op_array->function_name; - cur->next = NULL; - PHPDBG_G(oplog_cur)->next = cur; - PHPDBG_G(oplog_cur) = cur; - } -} /* }}} */ - -void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags) /* {{{ */ -{ - phpdbg_print_opline_ex(execute_data, ignore_flags); -} /* }}} */ diff --git a/sapi/phpdbg/phpdbg_opcode.h b/sapi/phpdbg/phpdbg_opcode.h deleted file mode 100644 index 8cc47030e52..00000000000 --- a/sapi/phpdbg/phpdbg_opcode.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Felipe Pena | - | Authors: Joe Watkins | - | Authors: Bob Weinand | - +----------------------------------------------------------------------+ -*/ - -#ifndef PHPDBG_OPCODE_H -#define PHPDBG_OPCODE_H - -#include "zend_types.h" - -char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op); -void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags); -void phpdbg_print_opline_ex(zend_execute_data *execute_data, bool ignore_flags); - -typedef struct _phpdbg_oplog_entry phpdbg_oplog_entry; -struct _phpdbg_oplog_entry { - phpdbg_oplog_entry *next; - zend_string *function_name; - zend_class_entry *scope; - zend_string *filename; - zend_op *opcodes; - zend_op *op; -}; - -typedef struct _phpdbg_oplog_list phpdbg_oplog_list; -struct _phpdbg_oplog_list { - phpdbg_oplog_list *prev; - phpdbg_oplog_entry start; /* Only "next" member used. */ -}; - -#endif /* PHPDBG_OPCODE_H */ diff --git a/sapi/phpdbg/phpdbg_print.c b/sapi/phpdbg/phpdbg_print.c index e91e36227aa..67d68b9da35 100644 --- a/sapi/phpdbg/phpdbg_print.c +++ b/sapi/phpdbg/phpdbg_print.c @@ -19,9 +19,10 @@ #include "phpdbg.h" #include "phpdbg_print.h" #include "phpdbg_utils.h" -#include "phpdbg_opcode.h" #include "phpdbg_prompt.h" +#include "Optimizer/zend_dump.h" + ZEND_EXTERN_MODULE_GLOBALS(phpdbg) #define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s, flags) \ @@ -55,44 +56,13 @@ static inline void phpdbg_print_function_helper(zend_function *method) /* {{{ */ zend_op_array* op_array = &(method->op_array); if (op_array) { - zend_op *opline = &(op_array->opcodes[0]); - uint32_t opcode = 0, - end = op_array->last-1; - - if (method->common.scope) { - phpdbg_writeln("L%d-%d %s::%s() %s - %p + %d ops", - op_array->line_start, - op_array->line_end, - ZSTR_VAL(method->common.scope->name), - ZSTR_VAL(method->common.function_name), - op_array->filename ? ZSTR_VAL(op_array->filename) : "unknown", - opline, - op_array->last); - } else { - phpdbg_writeln("L%d-%d %s() %s - %p + %d ops", - op_array->line_start, - op_array->line_end, - method->common.function_name ? ZSTR_VAL(method->common.function_name) : "{main}", - op_array->filename ? ZSTR_VAL(op_array->filename) : "unknown", - opline, - op_array->last); - } - - do { - char *decode = phpdbg_decode_opline(op_array, opline); - phpdbg_writeln(" L%-4u #%-5u %s", - opline->lineno, - opcode, - decode); - efree(decode); - opline++; - } while (opcode++ < end); + zend_dump_op_array(op_array, ZEND_DUMP_LINE_NUMBERS, NULL, NULL); for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) { zend_op_array *def = op_array->dynamic_func_defs[i]; phpdbg_out("\ndynamic def: %i, function name: %.*s\n", i, (int) ZSTR_LEN(def->function_name), ZSTR_VAL(def->function_name)); - phpdbg_print_function_helper((zend_function *) def); + zend_dump_op_array(def, ZEND_DUMP_LINE_NUMBERS, NULL, NULL); } } } break; @@ -123,7 +93,7 @@ PHPDBG_PRINT(exec) /* {{{ */ phpdbg_error("No execution context set"); } -return SUCCESS; + return SUCCESS; } /* }}} */ PHPDBG_PRINT(stack) /* {{{ */ @@ -261,7 +231,6 @@ PHPDBG_PRINT(func) /* {{{ */ } /* }}} */ void phpdbg_print_opcodes_main(void) { - phpdbg_out("function name: (null)\n"); phpdbg_print_function_helper((zend_function *) PHPDBG_G(ops)); } @@ -269,19 +238,10 @@ void phpdbg_print_opcodes_function(const char *function, size_t len) { zend_function *func = zend_hash_str_find_ptr(EG(function_table), function, len); if (!func) { - zend_string *rt_name; - ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), rt_name, func) { - if (func->type == ZEND_USER_FUNCTION && *rt_name->val == '\0') { - if (func->op_array.function_name->len == len && !zend_binary_strcasecmp(function, len, func->op_array.function_name->val, func->op_array.function_name->len)) { - phpdbg_print_opcodes_function(rt_name->val, rt_name->len); - } - } - } ZEND_HASH_FOREACH_END(); - + phpdbg_error("The function %s could not be found", function); return; } - phpdbg_out("function name: %.*s\n", (int) ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name)); phpdbg_print_function_helper(func); } @@ -294,10 +254,10 @@ static void phpdbg_print_opcodes_method_ce(zend_class_entry *ce, const char *fun } if (!(func = zend_hash_str_find_ptr(&ce->function_table, function, strlen(function)))) { + phpdbg_error("The method %s::%s could not be found", ZSTR_VAL(ce->name), function); return; } - phpdbg_out("function name: %s::%s\n", ce->name->val, function); phpdbg_print_function_helper(func); } @@ -305,15 +265,7 @@ void phpdbg_print_opcodes_method(const char *class, const char *function) { zend_class_entry *ce; if (phpdbg_safe_class_lookup(class, strlen(class), &ce) != SUCCESS) { - zend_string *rt_name; - ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), rt_name, ce) { - if (ce->type == ZEND_USER_CLASS && *rt_name->val == '\0') { - if (ce->name->len == strlen(class) && !zend_binary_strcasecmp(class, strlen(class), ce->name->val, ce->name->len)) { - phpdbg_print_opcodes_method_ce(ce, function); - } - } - } ZEND_HASH_FOREACH_END(); - + phpdbg_error("The class %s could not be found", class); return; } @@ -322,7 +274,6 @@ void phpdbg_print_opcodes_method(const char *class, const char *function) { static void phpdbg_print_opcodes_ce(zend_class_entry *ce) { zend_function *method; - zend_string *method_name; bool first = 1; phpdbg_out("%s %s: %s\n", @@ -353,8 +304,7 @@ static void phpdbg_print_opcodes_ce(zend_class_entry *ce) { } phpdbg_out("\n"); - ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, method_name, method) { - phpdbg_out("\nfunction name: %s\n", ZSTR_VAL(method_name)); + ZEND_HASH_FOREACH_PTR(&ce->function_table, method) { phpdbg_print_function_helper(method); } ZEND_HASH_FOREACH_END(); } @@ -363,22 +313,14 @@ void phpdbg_print_opcodes_class(const char *class) { zend_class_entry *ce; if (phpdbg_safe_class_lookup(class, strlen(class), &ce) != SUCCESS) { - zend_string *rt_name; - ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), rt_name, ce) { - if (ce->type == ZEND_USER_CLASS && *rt_name->val == '\0') { - if (ce->name->len == strlen(class) && !zend_binary_strcasecmp(class, strlen(class), ce->name->val, ce->name->len)) { - phpdbg_print_opcodes_ce(ce); - } - } - } ZEND_HASH_FOREACH_END(); - + phpdbg_error("The class %s could not be found", class); return; } phpdbg_print_opcodes_ce(ce); } -PHPDBG_API void phpdbg_print_opcodes(const char *function) +void phpdbg_print_opcodes(const char *function) { if (function == NULL) { phpdbg_print_opcodes_main(); @@ -392,14 +334,13 @@ PHPDBG_API void phpdbg_print_opcodes(const char *function) ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), name, func) { if (func->type == ZEND_USER_FUNCTION) { - phpdbg_out("\n"); phpdbg_print_opcodes_function(ZSTR_VAL(name), ZSTR_LEN(name)); } } ZEND_HASH_FOREACH_END(); ZEND_HASH_FOREACH_PTR(EG(class_table), ce) { if (ce->type == ZEND_USER_CLASS) { - phpdbg_out("\n\n"); + phpdbg_out("\n"); phpdbg_print_opcodes_ce(ce); } } ZEND_HASH_FOREACH_END(); @@ -420,3 +361,23 @@ PHPDBG_API void phpdbg_print_opcodes(const char *function) efree(function_lowercase); } } + +void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags) /* {{{ */ +{ + if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) && (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) { + zend_dump_op_line(&EX(func)->op_array, NULL, EX(opline), ZEND_DUMP_LINE_NUMBERS, NULL); + } + + if (PHPDBG_G(oplog_list)) { + phpdbg_oplog_entry *cur = zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry)); + zend_op_array *op_array = &EX(func)->op_array; + cur->op = (zend_op *) EX(opline); + cur->opcodes = op_array->opcodes; + cur->filename = op_array->filename; + cur->scope = op_array->scope; + cur->function_name = op_array->function_name; + cur->next = NULL; + PHPDBG_G(oplog_cur)->next = cur; + PHPDBG_G(oplog_cur) = cur; + } +} /* }}} */ diff --git a/sapi/phpdbg/phpdbg_print.h b/sapi/phpdbg/phpdbg_print.h index 72f538cddfa..7529bbc9943 100644 --- a/sapi/phpdbg/phpdbg_print.h +++ b/sapi/phpdbg/phpdbg_print.h @@ -33,8 +33,9 @@ PHPDBG_PRINT(method); PHPDBG_PRINT(func); PHPDBG_PRINT(stack); -PHPDBG_API void phpdbg_print_opcodes(const char *function); - extern const phpdbg_command_t phpdbg_print_commands[]; +void phpdbg_print_opcodes(const char *function); + +void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags); #endif /* PHPDBG_PRINT_H */ diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 5edca645150..6597f5fe42c 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -32,7 +32,6 @@ #include "phpdbg_print.h" #include "phpdbg_info.h" #include "phpdbg_break.h" -#include "phpdbg_opcode.h" #include "phpdbg_list.h" #include "phpdbg_utils.h" #include "phpdbg_prompt.h" @@ -1107,7 +1106,6 @@ PHPDBG_COMMAND(info) /* {{{ */ phpdbg_writeln("Compiled %s", PHPDBG_G(ops) ? "yes" : "no"); phpdbg_writeln("Stepping %s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); phpdbg_writeln("Quietness %s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); - phpdbg_writeln("Oplog %s", PHPDBG_G(oplog) ? "on" : "off"); if (PHPDBG_G(ops)) { phpdbg_writeln("Opcodes %d", PHPDBG_G(ops)->last); @@ -1676,7 +1674,7 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */ } if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) { - phpdbg_print_opline_ex(execute_data, 0); + phpdbg_print_opline(execute_data, 0); goto next; } @@ -1720,7 +1718,7 @@ ex_is_caught: } /* not while in conditionals */ - phpdbg_print_opline_ex(execute_data, 0); + phpdbg_print_opline(execute_data, 0); /* perform seek operation */ if ((PHPDBG_G(flags) & PHPDBG_SEEK_MASK) && !(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { diff --git a/sapi/phpdbg/phpdbg_set.c b/sapi/phpdbg/phpdbg_set.c index ff0828a6f86..d6b19a7e551 100644 --- a/sapi/phpdbg/phpdbg_set.c +++ b/sapi/phpdbg/phpdbg_set.c @@ -35,7 +35,6 @@ const phpdbg_command_t phpdbg_set_commands[] = { PHPDBG_SET_COMMAND_D(color, "usage: set color ", 'c', set_color, NULL, "ss", PHPDBG_ASYNC_SAFE), PHPDBG_SET_COMMAND_D(colors, "usage: set colors []", 'C', set_colors, NULL, "|b", PHPDBG_ASYNC_SAFE), #endif - PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog []", 'O', set_oplog, NULL, "|s", 0), PHPDBG_SET_COMMAND_D(break, "usage: set break id []", 'b', set_break, NULL, "l|b", PHPDBG_ASYNC_SAFE), PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks []", 'B', set_breaks, NULL, "|b", PHPDBG_ASYNC_SAFE), PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet []", 'q', set_quiet, NULL, "|b", PHPDBG_ASYNC_SAFE), @@ -197,35 +196,6 @@ PHPDBG_SET(colors) /* {{{ */ } /* }}} */ #endif -PHPDBG_SET(oplog) /* {{{ */ -{ - if (!param || param->type == EMPTY_PARAM) { - phpdbg_notice("Oplog %s", PHPDBG_G(oplog) ? "on" : "off"); - } else switch (param->type) { - case STR_PARAM: { - /* open oplog */ - FILE *old = PHPDBG_G(oplog); - - PHPDBG_G(oplog) = fopen(param->str, "w+"); - if (!PHPDBG_G(oplog)) { - phpdbg_error("Failed to open %s for oplog", param->str); - PHPDBG_G(oplog) = old; - } else { - if (old) { - phpdbg_notice("Closing previously open oplog"); - fclose(old); - } - - phpdbg_notice("Successfully opened oplog %s", param->str); - } - } break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - PHPDBG_SET(quiet) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { diff --git a/sapi/phpdbg/phpdbg_set.h b/sapi/phpdbg/phpdbg_set.h index f545c0ec112..2caeccdffc7 100644 --- a/sapi/phpdbg/phpdbg_set.h +++ b/sapi/phpdbg/phpdbg_set.h @@ -28,7 +28,6 @@ PHPDBG_SET(prompt); PHPDBG_SET(color); PHPDBG_SET(colors); #endif -PHPDBG_SET(oplog); PHPDBG_SET(break); PHPDBG_SET(breaks); PHPDBG_SET(quiet); diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c index 6963183ec12..272715654eb 100644 --- a/sapi/phpdbg/phpdbg_utils.c +++ b/sapi/phpdbg/phpdbg_utils.c @@ -20,7 +20,6 @@ #include "php.h" #include "phpdbg.h" -#include "phpdbg_opcode.h" #include "phpdbg_utils.h" #include "ext/standard/php_string.h" diff --git a/sapi/phpdbg/tests/exceptions_003.phpt b/sapi/phpdbg/tests/exceptions_003.phpt index ee68490df1a..d2692d7ee5e 100644 --- a/sapi/phpdbg/tests/exceptions_003.phpt +++ b/sapi/phpdbg/tests/exceptions_003.phpt @@ -16,28 +16,22 @@ prompt> [Breakpoint #0 at %s:5, hits: 1] >00005: x(); 00006: } finally { 00007: print "ok\n"; -prompt> [L0 %s HANDLE_EXCEPTION %s] ->00005: x(); +prompt> >00005: x(); 00006: } finally { 00007: print "ok\n"; -prompt> [L7 %s ECHO<1> "ok\n" %s] ->00007: print "ok\n"; +prompt> >00007: print "ok\n"; 00008: } 00009: } catch (Error $e) { prompt> ok -[L7 %s FAST_RET ~%d try-catch(0) %s] -[L9 %s CATCH<%d> %s "Error" $e %s] >00005: x(); 00006: } finally { 00007: print "ok\n"; -prompt> [L10 %s ECHO<1> "caught\n" %s] ->00010: print "caught\n"; +prompt> >00010: print "caught\n"; 00011: } 00012: prompt> caught -[L14 %s RETURN<-1> 1 %s] >00014: -prompt> +prompt> --FILE-- [Breakpoint #0 added at %s:4] prompt> [Breakpoint #0 at %s:4, hits: 1] ->00004: echo 0; +>00004: echo 0 . PHP_EOL; 00005: } 00006: prompt> 0 -[L5 %s RETURN<-1> null %s] >00005: } 00006: 00007: foo(); -prompt> [L8 %s ECHO 1 %s] ->00008: echo 1; +prompt> >00008: echo 1 . PHP_EOL; 00009: prompt> 1 -[L9 %s RETURN<-1> 1 %s] >00009: -prompt> +prompt> + --FILE-- [User Function foo (8 ops)] -L14-16 foo() %s - %s + 8 ops - L14 #0 RECV 1 $baz - L15 #1 INIT_FCALL%s %d %s "var_dump" - L15 #2 INIT_FCALL%s %d %s "strrev" - L15 #3 SEND_VAR $baz 1 - L15 #4 DO_%cCALL @0 - L15 #5 SEND_VAR @0 1 - L15 #6 DO_%cCALL - L16 #7 RETURN<-1> null + +foo: + ; (lines=8, args=1, vars=1, tmps=2) + ; %s:14-16 +L0014 0000 CV0($baz) = RECV 1 +L0015 0001 INIT_FCALL %d %d string("var_dump") +L0015 0002 INIT_FCALL %d %d string("strrev") +L0015 0003 SEND_VAR CV0($baz) 1 +L0015 0004 V1 = DO_ICALL +L0015 0005 SEND_VAR V1 1 +L0015 0006 DO_ICALL +L0016 0007 RETURN null prompt> [User Class: Foo\Bar (2 methods)] -L5-7 Foo\Bar::Foo() %s - %s + 5 ops - L5 #0 RECV 1 $bar - L6 #1 INIT_NS_FCALL_BY_NAME<1> "Foo\\var_dump" - L6 #2 SEND_VAR_EX $bar 1 - L6 #3 DO_FCALL - L7 #4 RETURN<-1> null -L9-9 Foo\Bar::baz() %s - %s + 1 ops - L9 #0 RETURN<-1> null + +Foo\Bar::Foo: + ; (lines=5, args=1, vars=1, tmps=1) + ; %s:5-7 +L0005 0000 CV0($bar) = RECV 1 +L0006 0001 INIT_NS_FCALL_BY_NAME 1 string("Foo\var_dump") +L0006 0002 SEND_VAR_EX CV0($bar) 1 +L0006 0003 DO_FCALL +L0007 0004 RETURN null + +Foo\Bar::baz: + ; (lines=1, args=0, vars=0, tmps=0) + ; %s:9-9 +L0009 0000 RETURN null prompt> [Not Executing!] prompt> [Context %s (9 ops)] -L1-21 {main}() %s - %s + 9 ops - L18 #0 NEW "Foo\\Bar" @0 - L18 #1 DO_FCALL - L18 #2 INIT_METHOD_CALL<1> @0 "Foo" - L18 #3 SEND_VAL_EX "test" 1 - L18 #4 DO_FCALL - L19 #5 INIT_FCALL%s %d %s "foo" - L19 #6 SEND_VAL "test" 1 - L19 #7 DO_FCALL - L21 #8 RETURN<-1> 1 + +$_main: + ; (lines=9, args=0, vars=0, tmps=4) + ; %s:1-21 +L0018 0000 V0 = NEW 0 string("Foo\Bar") +L0018 0001 DO_FCALL +L0018 0002 INIT_METHOD_CALL 1 V0 string("Foo") +L0018 0003 SEND_VAL_EX string("test") 1 +L0018 0004 DO_FCALL +L0019 0005 INIT_FCALL %d %d string("foo") +L0019 0006 SEND_VAL string("test") 1 +L0019 0007 DO_FCALL +L0021 0008 RETURN int(1) prompt> --FILE-- string(4) "test" 00016: } 00017: prompt> [Stack in foo() (8 ops)] -L14-16 foo() %s - %s + 8 ops - L14 #0 RECV 1 $baz - L15 #1 INIT_FCALL%s %d %s "var_dump" - L15 #2 INIT_FCALL%s %d %s "strrev" - L15 #3 SEND_VAR $baz 1 - L15 #4 DO_%cCALL @0 - L15 #5 SEND_VAR @0 1 - L15 #6 DO_%cCALL - L16 #7 RETURN<-1> null -prompt> [L15 %s INIT_FCALL%s %d %s "var_dump" %s] + +foo: + ; (lines=8, args=1, vars=1, tmps=2) + ; %s:14-16 +L0014 0000 CV0($baz) = RECV 1 +L0015 0001 INIT_FCALL %d %d string("var_dump") +L0015 0002 INIT_FCALL %d %d string("strrev") +L0015 0003 SEND_VAR CV0($baz) 1 +L0015 0004 V1 = DO_ICALL +L0015 0005 SEND_VAR V1 1 +L0015 0006 DO_ICALL +L0016 0007 RETURN null +prompt> L0015 0001 INIT_FCALL %d %d string("var_dump") prompt> --FILE-- [Breakpoint #0 in ZEND_THROW at %s:4, hits: 1] >00004: throw new Exception; 00005: } 00006: -prompt> [L0 %s HANDLE_EXCEPTION %s] ->00004: throw new Exception; +prompt> >00004: throw new Exception; 00005: } 00006: -prompt> [L0 %s HANDLE_EXCEPTION %s] -[L9 %s CATCH<%d> "Exception" $e %s] ->00008: foo(); +prompt> >00008: foo(); 00009: } catch (Exception $e) { - 00010: echo "ok"; -prompt> [L10 %s ECHO "ok" %s] ->00010: echo "ok"; + 00010: echo "ok\n"; +prompt> >00010: echo "ok\n"; 00011: } finally { - 00012: echo " ... ok"; + 00012: echo " ... ok\n"; prompt> ok -[L11 %s FAST_CALL J7 ~%d %s] >00011: } finally { - 00012: echo " ... ok"; + 00012: echo " ... ok\n"; 00013: } -prompt> [L12 %s ECHO " ... ok" %s] ->00012: echo " ... ok"; +prompt> >00012: echo " ... ok\n"; 00013: } 00014: prompt> ... ok -[L12 %s FAST_RET ~%d %s] -[L11 %s JMP J9 %s] >00011: } finally { - 00012: echo " ... ok"; + 00012: echo " ... ok\n"; 00013: } -prompt> [L14 %s RETURN<-1> 1 %s] ->00014: -prompt> +prompt> >00014: +prompt> --FILE--