diff options
Diffstat (limited to 'sapi/phpdbg/phpdbg.c')
-rw-r--r-- | sapi/phpdbg/phpdbg.c | 125 |
1 files changed, 96 insertions, 29 deletions
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 31dab3f274..d594601f29 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -111,6 +111,8 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */ pg->sigsafe_mem.mem = NULL; pg->sigsegv_bailout = NULL; + pg->oplog_list = NULL; + #ifdef PHP_WIN32 pg->sigio_watcher_thread = INVALID_HANDLE_VALUE; memset(&pg->swd, 0, sizeof(struct win32_sigio_watcher_data)); @@ -441,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; + 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; @@ -461,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; @@ -474,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); { @@ -488,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); @@ -495,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); } 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) { @@ -528,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)++; } @@ -709,6 +770,8 @@ static int php_sapi_phpdbg_deactivate(void) /* {{{ */ pg->prompt[1] = PHPDBG_G(prompt)[1]; memcpy(pg->colors, PHPDBG_G(colors), sizeof(pg->colors)); pg->eol = PHPDBG_G(eol); + pg->input_buflen = PHPDBG_G(input_buflen); + memcpy(pg->input_buffer, PHPDBG_G(input_buffer), pg->input_buflen); pg->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK; } @@ -1169,7 +1232,7 @@ int main(int argc, char **argv) /* {{{ */ char *php_optarg; int php_optind, opt, show_banner = 1; long cleaning = -1; - zend_bool quit_immediately = 0; + volatile zend_bool quit_immediately = 0; /* somehow some gcc release builds will play a bit around with order in combination with setjmp..., hence volatile */ zend_bool remote = 0; zend_phpdbg_globals *settings = NULL; char *bp_tmp = NULL; @@ -1390,11 +1453,8 @@ phpdbg_main: } /* set exec if present on command line */ - if (!exec && (argc > php_optind) && (strcmp(argv[php_optind-1], "--") != SUCCESS)) { - if (strlen(argv[php_optind])) { - if (exec) { - free(exec); - } + if (argc > php_optind && (strcmp(argv[php_optind-1], "--") != SUCCESS)) { + if (!exec && strlen(argv[php_optind])) { exec = strdup(argv[php_optind]); } php_optind++; @@ -1473,7 +1533,7 @@ phpdbg_main: /* setup remote server if necessary */ if (cleaning <= 0 && listen > 0) { server = phpdbg_open_socket(address, listen); - if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream) == FAILURE) { + if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream) == FAILURE) { exit(0); } @@ -1525,6 +1585,14 @@ phpdbg_main: PHPDBG_G(sapi_name_ptr) = sapi_name; + if (exec) { /* set execution context */ + PHPDBG_G(exec) = phpdbg_resolve_path(exec); + PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0; + + free(exec); + exec = NULL; + } + php_output_activate(); php_output_deactivate(); @@ -1538,7 +1606,7 @@ phpdbg_main: for (i = SG(request_info).argc; --i;) { SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]); } - SG(request_info).argv[i] = exec ? estrdup(exec) : estrdup(""); + SG(request_info).argv[0] = PHPDBG_G(exec) ? estrdup(PHPDBG_G(exec)) : estrdup(""); php_hash_environment(); } @@ -1599,14 +1667,6 @@ phpdbg_main: php_stream_stdio_ops.write = phpdbg_stdiop_write; #endif - if (exec) { /* set execution context */ - PHPDBG_G(exec) = phpdbg_resolve_path(exec); - PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0; - - free(exec); - exec = NULL; - } - if (oplog_file) { /* open oplog */ PHPDBG_G(oplog) = fopen(oplog_file, "w+"); if (!PHPDBG_G(oplog)) { @@ -1654,7 +1714,7 @@ phpdbg_main: /* auto compile */ if (PHPDBG_G(exec)) { - if (settings) { + if (settings || phpdbg_startup_run > 0) { PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; } @@ -1674,6 +1734,8 @@ phpdbg_main: goto phpdbg_out; } + PG(during_request_startup) = 0; + phpdbg_fully_started = 1; /* #ifndef for making compiler shutting up */ @@ -1771,7 +1833,7 @@ phpdbg_out: { int i; /* free argv */ - for (i = SG(request_info).argc; --i;) { + for (i = SG(request_info).argc; i--;) { efree(SG(request_info).argv[i]); } efree(SG(request_info).argv); @@ -1813,7 +1875,9 @@ phpdbg_out: } zend_end_try(); if ((PHPDBG_G(flags) & (PHPDBG_IS_QUITTING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_RUNNING) { - phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); + if (!quit_immediately && !phpdbg_startup_run) { + phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); + } cleaning++; } @@ -1832,6 +1896,9 @@ phpdbg_out: } if ((cleaning > 0 || remote) && !quit_immediately) { + /* reset internal php_getopt state */ + php_getopt(-1, argv, OPTIONS, NULL, &php_optind, 0, 0); + goto phpdbg_main; } |