diff options
author | Bob Weinand <bobwei9@hotmail.com> | 2015-06-22 12:56:29 +0200 |
---|---|---|
committer | Bob Weinand <bobwei9@hotmail.com> | 2015-06-22 12:58:33 +0200 |
commit | 29aad0ef45618a25d5f87031a3e4e74ba1f6ac58 (patch) | |
tree | a56120bd135219363d0de77dcb6af2c055245cec /sapi/phpdbg/phpdbg.c | |
parent | 44d545b8e1c0bb48a969e5208b6002b2423e6bde (diff) | |
download | php-git-29aad0ef45618a25d5f87031a3e4e74ba1f6ac58.tar.gz |
Add phpdbg userland API to fetch oplog
We may want to add some opcode info later, so that "opcodes" mode is more helpful
Diffstat (limited to 'sapi/phpdbg/phpdbg.c')
-rw-r--r-- | sapi/phpdbg/phpdbg.c | 149 |
1 files changed, 147 insertions, 2 deletions
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 7b7ed177df..38bd8f897a 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -245,8 +245,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ PHPDBG_G(prompt)[1] = NULL; if (PHPDBG_G(oplog)) { - fclose( - PHPDBG_G(oplog)); + fclose(PHPDBG_G(oplog)); PHPDBG_G(oplog) = NULL; } @@ -256,6 +255,18 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ PHPDBG_G(ops) = NULL; } + if (PHPDBG_G(oplog_list)) { + phpdbg_oplog_list *cur = PHPDBG_G(oplog_list); + do { + phpdbg_oplog_list *prev = cur->prev; + efree(cur); + cur = prev; + } while (cur != NULL); + + zend_arena_destroy(PHPDBG_G(oplog_arena)); + PHPDBG_G(oplog_list) = NULL; + } + return SUCCESS; } /* }}} */ @@ -403,6 +414,132 @@ static PHP_FUNCTION(phpdbg_prompt) phpdbg_set_prompt(prompt); } /* }}} */ +/* {{{ proto void phpdbg_start_oplog() */ +static PHP_FUNCTION(phpdbg_start_oplog) +{ + phpdbg_oplog_list *prev; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + prev = PHPDBG_G(oplog_list); + + if (!prev) { + PHPDBG_G(oplog_arena) = zend_arena_create(64 * 1024); + + PHPDBG_G(oplog_cur) = ((phpdbg_oplog_entry *) zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry))) + 1; + PHPDBG_G(oplog_cur)->next = NULL; + } + + PHPDBG_G(oplog_list) = emalloc(sizeof(phpdbg_oplog_list)); + PHPDBG_G(oplog_list)->prev = prev; + PHPDBG_G(oplog_list)->start = PHPDBG_G(oplog_cur); +} + +/* {{{ 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; + + HashTable *options; + zval *option_buffer; + zend_bool by_function = 0; + zend_bool by_opcode = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) { + return; + } + + if (!PHPDBG_G(oplog_list)) { + zend_error(E_WARNING, "Can not end an oplog without starting it"); + return; + } + + efree(PHPDBG_G(oplog_list)); + PHPDBG_G(oplog_list) = prev; + + if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("functions")))) { + by_function = zend_is_true(option_buffer); + } + + if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("opcodes")))) { + if (by_function) { + by_opcode = zend_is_true(option_buffer); + } + } + + array_init(return_value); + + { + zend_string *last_file = NULL; + zval *file_buf; + zend_string *last_function = (void *)~(uintptr_t)0; + zend_class_entry *last_scope = NULL; + zval *fn_buf; + + HashTable *insert_ht; + zend_long insert_idx; + + do { + zend_op_array *op_array = cur->op_array; + if (op_array->filename != last_file) { + last_file = op_array->filename; + file_buf = zend_hash_find(Z_ARR_P(return_value), last_file); + if (!file_buf) { + zval ht; + array_init(&ht); + file_buf = zend_hash_add_new(Z_ARR_P(return_value), last_file, &ht); + } + } + insert_ht = Z_ARR_P(file_buf); + + if (by_function) { + 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(last_function->len + last_scope->name->len + 2, "%.*s::%.*s", last_function->len, last_function->val, last_scope->name->len, last_scope->name->val); + } + 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); + } + } + insert_ht = Z_ARR_P(fn_buf); + } + + if (by_opcode) { + insert_idx = cur->op - op_array->opcodes; + } else { + insert_idx = cur->op->lineno; + } + + { + 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); + } + Z_LVAL_P(num)++; + } + + cur = cur->next; + } while (cur != NULL); + } + + if (!prev) { + zend_arena_destroy(PHPDBG_G(oplog_arena)); + } +} + ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0) ZEND_END_ARG_INFO() @@ -436,6 +573,12 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(phpdbg_start_oplog_arginfo, 0, 0, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_end_oplog_arginfo, 0, 0, 0) +ZEND_END_ARG_INFO() + zend_function_entry phpdbg_user_functions[] = { PHP_FE(phpdbg_clear, phpdbg_clear_arginfo) PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo) @@ -445,6 +588,8 @@ zend_function_entry phpdbg_user_functions[] = { PHP_FE(phpdbg_exec, phpdbg_exec_arginfo) PHP_FE(phpdbg_color, phpdbg_color_arginfo) PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo) + PHP_FE(phpdbg_start_oplog, phpdbg_start_oplog_arginfo) + PHP_FE(phpdbg_end_oplog, phpdbg_end_oplog_arginfo) #ifdef PHP_FE_END PHP_FE_END #else |