From: Bob Weinand Date: Mon, 20 Jul 2015 18:41:07 +0000 (+0200) Subject: Add show_unexecuted option to phpdbg_end_oplog() X-Git-Tag: php-7.0.0beta2~6^2~18 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6aadeba213305a0b8818c347bea956cb7e258c3a;p=php Add show_unexecuted option to phpdbg_end_oplog() --- diff --git a/sapi/phpdbg/create-test.php b/sapi/phpdbg/create-test.php index 3bda97670f..6de10bd56f 100644 --- a/sapi/phpdbg/create-test.php +++ b/sapi/phpdbg/create-test.php @@ -27,7 +27,7 @@ error_reporting(-1); $phpdbg = getenv('TEST_PHPDBG_EXECUTABLE') ?: null; -$pass_options = " -qbI"; +$pass_options = ' -qbI -n -d "error_reporting=32767" -d "display_errors=1" -d "display_startup_errors=1" -d "log_errors=0"'; $file = ""; $cmdargv = ""; diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index db830f2d28..3fdc7cbe30 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -443,16 +443,54 @@ static PHP_FUNCTION(phpdbg_start_oplog) PHPDBG_G(oplog_list)->start = PHPDBG_G(oplog_cur); } +static void phpdbg_oplog_fill_executable(zend_op_array *op_array, HashTable *insert_ht, zend_bool by_opcode) { + /* ignore RECV_* opcodes */ + zend_op *cur = op_array->opcodes + op_array->num_args + !!(op_array->fn_flags & ZEND_ACC_VARIADIC); + zend_op *end = op_array->opcodes + op_array->last; + + zend_long insert_idx; + zval zero; + ZVAL_LONG(&zero, 0); + + /* ignore autogenerated return (well, not too precise with finally branches, but that's okay) */ + if (op_array->last > 1 && (end - 1)->opcode == ZEND_RETURN && ((end - 2)->opcode == ZEND_RETURN || (end - 2)->opcode == ZEND_GENERATOR_RETURN || (end - 2)->opcode == ZEND_THROW)) { + end--; + } + + for (; cur < end; cur++) { + if (cur->opcode == ZEND_NOP || cur->opcode == ZEND_OP_DATA || cur->opcode == ZEND_FE_FREE || cur->opcode == ZEND_FREE || cur->opcode == ZEND_ASSERT_CHECK + || cur->opcode == ZEND_DECLARE_CONST || cur->opcode == ZEND_DECLARE_CLASS || cur->opcode == ZEND_DECLARE_INHERITED_CLASS || cur->opcode == ZEND_DECLARE_FUNCTION + || cur->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED || cur->opcode == ZEND_VERIFY_ABSTRACT_CLASS || cur->opcode == ZEND_ADD_TRAIT || cur->opcode == ZEND_BIND_TRAITS + || cur->opcode == ZEND_DECLARE_ANON_CLASS || cur->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS || cur->opcode == ZEND_FAST_RET || cur->opcode == ZEND_TICKS + || cur->opcode == ZEND_EXT_STMT || cur->opcode == ZEND_EXT_FCALL_BEGIN || cur->opcode == ZEND_EXT_FCALL_END || cur->opcode == ZEND_EXT_NOP || cur->opcode == ZEND_BIND_GLOBAL) { + continue; + } + + if (by_opcode) { + insert_idx = cur - op_array->opcodes; + } else { + insert_idx = cur->lineno; + } + + if (cur->opcode == ZEND_NEW && (cur + 1)->opcode == ZEND_DO_FCALL) { + cur++; + } + + zend_hash_index_update(insert_ht, insert_idx, &zero); + } +} + /* {{{ proto void phpdbg_end_oplog() */ static PHP_FUNCTION(phpdbg_end_oplog) { - phpdbg_oplog_entry *cur = PHPDBG_G(oplog_list)->start; - phpdbg_oplog_list *prev = PHPDBG_G(oplog_list)->prev; + phpdbg_oplog_entry *cur; + phpdbg_oplog_list *prev; HashTable *options = NULL; zval *option_buffer; zend_bool by_function = 0; zend_bool by_opcode = 0; + zend_bool show_unexecuted = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) { return; @@ -463,6 +501,9 @@ static PHP_FUNCTION(phpdbg_end_oplog) return; } + cur = PHPDBG_G(oplog_list)->start; + prev = PHPDBG_G(oplog_list)->prev; + efree(PHPDBG_G(oplog_list)); PHPDBG_G(oplog_list) = prev; @@ -476,6 +517,10 @@ static PHP_FUNCTION(phpdbg_end_oplog) } } + if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("show_unexecuted")))) { + show_unexecuted = zend_is_true(option_buffer); + } + array_init(return_value); { @@ -490,6 +535,9 @@ static PHP_FUNCTION(phpdbg_end_oplog) do { zend_op_array *op_array = cur->op_array; + zval zero; + ZVAL_LONG(&zero, 0); + if (op_array->filename != last_file) { last_file = op_array->filename; file_buf = zend_hash_find(Z_ARR_P(return_value), last_file); @@ -497,28 +545,41 @@ static PHP_FUNCTION(phpdbg_end_oplog) zval ht; array_init(&ht); file_buf = zend_hash_add_new(Z_ARR_P(return_value), last_file, &ht); + + if (show_unexecuted) { + phpdbg_oplog_fill_executable(op_array, Z_ARR_P(file_buf), by_opcode); + } } + insert_ht = Z_ARR_P(file_buf); } - insert_ht = Z_ARR_P(file_buf); if (by_function) { - if (op_array->function_name != last_function || op_array->scope != last_scope) { + if (op_array->function_name == NULL) { + if (last_function != NULL) { + insert_ht = Z_ARR_P(file_buf); + } + last_function = NULL; + } else if (op_array->function_name != last_function || op_array->scope != last_scope) { zend_string *fn_name; last_function = op_array->function_name; last_scope = op_array->scope; if (last_scope == NULL) { - fn_name = zend_string_copy(last_function); + fn_name = zend_string_copy(last_function ? last_function : last_file); } else { - fn_name = strpprintf(ZSTR_LEN(last_function) + ZSTR_LEN(last_scope->name) + 2, "%.*s::%.*s", ZSTR_LEN(last_function), ZSTR_VAL(last_function), ZSTR_LEN(last_scope->name), ZSTR_VAL(last_scope->name)); + fn_name = strpprintf(ZSTR_LEN(last_function) + ZSTR_LEN(last_scope->name) + 2, "%.*s::%.*s", ZSTR_LEN(last_scope->name), ZSTR_VAL(last_scope->name), ZSTR_LEN(last_function), ZSTR_VAL(last_function)); } fn_buf = zend_hash_find(Z_ARR_P(return_value), fn_name); if (!fn_buf) { zval ht; array_init(&ht); fn_buf = zend_hash_add_new(Z_ARR_P(return_value), fn_name, &ht); + + if (show_unexecuted) { + phpdbg_oplog_fill_executable(op_array, Z_ARR_P(fn_buf), by_opcode); + } } + insert_ht = Z_ARR_P(fn_buf); } - insert_ht = Z_ARR_P(fn_buf); } if (by_opcode) { @@ -530,9 +591,7 @@ static PHP_FUNCTION(phpdbg_end_oplog) { zval *num = zend_hash_index_find(insert_ht, insert_idx); if (!num) { - zval zv; - ZVAL_LONG(&zv, 0); - num = zend_hash_index_add_new(insert_ht, insert_idx, &zv); + num = zend_hash_index_add_new(insert_ht, insert_idx, &zero); } Z_LVAL_P(num)++; } @@ -1675,6 +1734,8 @@ phpdbg_main: goto phpdbg_out; } + PG(during_request_startup) = 0; + phpdbg_fully_started = 1; /* #ifndef for making compiler shutting up */ diff --git a/sapi/phpdbg/tests/phpdbg_oplog_001.phpt b/sapi/phpdbg/tests/phpdbg_oplog_001.phpt new file mode 100644 index 0000000000..4273865bd9 --- /dev/null +++ b/sapi/phpdbg/tests/phpdbg_oplog_001.phpt @@ -0,0 +1,56 @@ +--TEST-- +Test phpdbg_*_oplog() functions +--PHPDBG-- +r +q +--EXPECTF-- +[Successful compilation of %s] +prompt> halloarray(2) { + ["%s"]=> + array(6) { + [11]=> + int(0) + [13]=> + int(1) + [17]=> + int(2) + [18]=> + int(2) + [19]=> + int(3) + [21]=> + int(4) + } + ["A::b"]=> + array(2) { + [5]=> + int(5) + [4]=> + int(1) + } +} +[Script ended normally] +prompt> +--FILE-- +b(); +$a->b('ha'); + +var_dump(phpdbg_end_oplog(["functions" => true, "show_unexecuted" => true])); + diff --git a/sapi/phpdbg/tests/phpdbg_oplog_002.phpt b/sapi/phpdbg/tests/phpdbg_oplog_002.phpt new file mode 100644 index 0000000000..b9ba905caa --- /dev/null +++ b/sapi/phpdbg/tests/phpdbg_oplog_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +phpdbg_end_oplog() alone must not crash +--PHPDBG-- +r +q +--EXPECTF-- +[Successful compilation of %s] +prompt> +Warning: Can not end an oplog without starting it in %s on line 3 +NULL +[Script ended normally] +prompt> +--FILE-- +