diff options
| -rw-r--r-- | Zend/zend_compile.h | 2 | ||||
| -rw-r--r-- | Zend/zend_opcode.c | 12 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 12 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 26 | ||||
| -rw-r--r-- | sapi/phpdbg/phpdbg.c | 149 | ||||
| -rw-r--r-- | sapi/phpdbg/phpdbg_list.c | 12 | ||||
| -rw-r--r-- | sapi/phpdbg/phpdbg_list.h | 1 | ||||
| -rw-r--r-- | sapi/phpdbg/tests/phpdbg_oplog_001.phpt | 10 |
8 files changed, 168 insertions, 56 deletions
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 06796aab83..96a1f95078 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -726,7 +726,7 @@ ZEND_API zend_op_array *compile_filename(int type, zval *filename); ZEND_API int zend_execute_scripts(int type, zval *retval, int file_count, ...); ZEND_API int open_file_for_scanning(zend_file_handle *file_handle); ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size); -ZEND_API void destroy_op_array(zend_op_array *op_array); +ZEND_API zend_bool destroy_op_array(zend_op_array *op_array); ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle); ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce); ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 62869373dd..90afc6a985 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -335,7 +335,7 @@ void zend_class_add_ref(zval *zv) ce->refcount++; } -ZEND_API void destroy_op_array(zend_op_array *op_array) +ZEND_API zend_bool destroy_op_array(zend_op_array *op_array) { zval *literal = op_array->literals; zval *end; @@ -352,8 +352,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) efree(op_array->run_time_cache); } - if (!op_array->refcount || --(*op_array->refcount)>0) { - return; + if (!op_array->refcount) { + return 1; + } + + if (--(*op_array->refcount) > 0) { + return 0; } efree_size(op_array->refcount, sizeof(*(op_array->refcount))); @@ -414,6 +418,8 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) } efree(arg_info); } + + return 1; } void init_op(zend_op *op) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index db9f4eb4d4..ce5d520aa2 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2364,8 +2364,9 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) ZEND_VM_LEAVE(); } else if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_CODE) { zend_detach_symbol_table(execute_data); - destroy_op_array(&EX(func)->op_array); - efree_size(EX(func), sizeof(zend_op_array)); + if (EXPECTED(destroy_op_array(&EX(func)->op_array) != 0)) { + efree_size(EX(func), sizeof(zend_op_array)); + } old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); @@ -5439,7 +5440,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY) } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value); + i_init_code_execute_data(call, new_op_array, return_value); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { @@ -5448,8 +5449,9 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY) zend_vm_stack_free_call_frame(call); } - destroy_op_array(new_op_array); - efree_size(new_op_array, sizeof(zend_op_array)); + if (EXPECTED(destroy_op_array(new_op_array) != 0)) { + efree_size(new_op_array, sizeof(zend_op_array)); + } if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL); HANDLE_EXCEPTION(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3257fd5fdf..da2eeada13 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -503,8 +503,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ ZEND_VM_LEAVE(); } else if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_CODE) { zend_detach_symbol_table(execute_data); - destroy_op_array(&EX(func)->op_array); - efree_size(EX(func), sizeof(zend_op_array)); + if (EXPECTED(destroy_op_array(&EX(func)->op_array) != 0)) { + efree_size(EX(func), sizeof(zend_op_array)); + } old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); @@ -3642,7 +3643,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HAN } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value); + i_init_code_execute_data(call, new_op_array, return_value); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { @@ -3651,8 +3652,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HAN zend_vm_stack_free_call_frame(call); } - destroy_op_array(new_op_array); - efree_size(new_op_array, sizeof(zend_op_array)); + if (EXPECTED(destroy_op_array(new_op_array) != 0)) { + efree_size(new_op_array, sizeof(zend_op_array)); + } if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL); HANDLE_EXCEPTION(); @@ -29006,7 +29008,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLE } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value); + i_init_code_execute_data(call, new_op_array, return_value); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { @@ -29015,8 +29017,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLE zend_vm_stack_free_call_frame(call); } - destroy_op_array(new_op_array); - efree_size(new_op_array, sizeof(zend_op_array)); + if (EXPECTED(destroy_op_array(new_op_array) != 0)) { + efree_size(new_op_array, sizeof(zend_op_array)); + } if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL); HANDLE_EXCEPTION(); @@ -40417,7 +40420,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HA } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value); + i_init_code_execute_data(call, new_op_array, return_value); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { @@ -40426,8 +40429,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HA zend_vm_stack_free_call_frame(call); } - destroy_op_array(new_op_array); - efree_size(new_op_array, sizeof(zend_op_array)); + if (EXPECTED(destroy_op_array(new_op_array) != 0)) { + efree_size(new_op_array, sizeof(zend_op_array)); + } if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL); HANDLE_EXCEPTION(); diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 83425fe531..a4f36eeced 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -480,6 +480,114 @@ static void phpdbg_oplog_fill_executable(zend_op_array *op_array, HashTable *ins } } +static inline HashTable* phpdbg_add_empty_array(HashTable *ht, zend_string *name) { + zval *ht_zv = zend_hash_find(ht, name); + if (!ht_zv) { + zval zv; + array_init(&zv); + ht_zv = zend_hash_add_new(ht, name, &zv); + } + return Z_ARR_P(ht_zv); +} + +/* {{{ proto void phpdbg_end_oplog() */ +static PHP_FUNCTION(phpdbg_get_executable) +{ + HashTable *options = NULL; + zval *option_buffer; + zend_bool by_function = 0; + zend_bool by_opcode = 0; + HashTable *insert_ht; + + zend_function *func; + zend_class_entry *ce; + zend_string *name; + HashTable *files = &PHPDBG_G(file_sources); + HashTable files_tmp; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) { + return; + } + + 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); + } + } + + if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("files")))) { + ZVAL_DEREF(option_buffer); + if (Z_TYPE_P(option_buffer) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(option_buffer)) > 0) { + zval *filename; + + files = &files_tmp; + zend_hash_init(files, 0, NULL, NULL, 0); + + ZEND_HASH_FOREACH_VAL(Z_ARR_P(option_buffer), filename) { + zend_hash_add_empty_element(files, zval_get_string(filename)); + } ZEND_HASH_FOREACH_END(); + } else { + GC_REFCOUNT(files)++; + } + } else { + GC_REFCOUNT(files)++; + } + + array_init(return_value); + + ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), name, func) { + if (func->type == ZEND_USER_FUNCTION) { + if (zend_hash_exists(files, func->op_array.filename)) { + insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), func->op_array.filename); + + if (by_function) { + insert_ht = phpdbg_add_empty_array(insert_ht, name); + } + + phpdbg_oplog_fill_executable(&func->op_array, insert_ht, by_opcode); + } + } + } ZEND_HASH_FOREACH_END(); + + ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), name, ce) { + if (ce->type == ZEND_USER_CLASS) { + if (zend_hash_exists(files, ce->info.user.filename)) { + ZEND_HASH_FOREACH_PTR(&ce->function_table, func) { + if (func->type == ZEND_USER_FUNCTION) { + insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), func->op_array.filename); + + if (by_function) { + zend_string *fn_name = strpprintf(ZSTR_LEN(name) + ZSTR_LEN(func->op_array.function_name) + 2, "%.*s::%.*s", ZSTR_LEN(name), ZSTR_VAL(name), ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name)); + insert_ht = phpdbg_add_empty_array(insert_ht, fn_name); + zend_string_release(fn_name); + } + + phpdbg_oplog_fill_executable(&func->op_array, insert_ht, by_opcode); + } + } ZEND_HASH_FOREACH_END(); + } + } + } ZEND_HASH_FOREACH_END(); + + ZEND_HASH_FOREACH_STR_KEY(files, name) { + phpdbg_file_source *source = zend_hash_find_ptr(&PHPDBG_G(file_sources), name); + if (source) { + phpdbg_oplog_fill_executable( + source->op_array, + phpdbg_add_empty_array(Z_ARR_P(return_value), source->op_array->filename), + by_opcode); + } + } ZEND_HASH_FOREACH_END(); + + if (!--GC_REFCOUNT(files)) { + zend_hash_destroy(files); + } +} + /* {{{ proto void phpdbg_end_oplog() */ static PHP_FUNCTION(phpdbg_end_oplog) { @@ -490,7 +598,6 @@ static PHP_FUNCTION(phpdbg_end_oplog) 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; @@ -517,18 +624,13 @@ 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); { zend_string *last_file = NULL; - zval *file_buf; + HashTable *file_ht; zend_string *last_function = (void *)~(uintptr_t)0; zend_class_entry *last_scope = NULL; - zval *fn_buf; HashTable *insert_ht; zend_long insert_idx; @@ -540,23 +642,13 @@ static PHP_FUNCTION(phpdbg_end_oplog) 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); - - if (show_unexecuted) { - phpdbg_oplog_fill_executable(op_array, Z_ARR_P(file_buf), by_opcode); - } - } - insert_ht = Z_ARR_P(file_buf); + file_ht = insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), last_file); } if (by_function) { if (op_array->function_name == NULL) { if (last_function != NULL) { - insert_ht = Z_ARR_P(file_buf); + insert_ht = file_ht; } last_function = NULL; } else if (op_array->function_name != last_function || op_array->scope != last_scope) { @@ -568,17 +660,8 @@ static PHP_FUNCTION(phpdbg_end_oplog) } else { 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 = phpdbg_add_empty_array(Z_ARR_P(return_value), fn_name); + zend_string_release(fn_name); } } @@ -642,6 +725,11 @@ 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_ARG_INFO(0, options) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_get_executable_arginfo, 0, 0, 0) + ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO() zend_function_entry phpdbg_user_functions[] = { @@ -655,6 +743,7 @@ zend_function_entry phpdbg_user_functions[] = { 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) + PHP_FE(phpdbg_get_executable, phpdbg_get_executable_arginfo) #ifdef PHP_FE_END PHP_FE_END #else diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c index 7b1bc8783b..3a7761cc64 100644 --- a/sapi/phpdbg/phpdbg_list.c +++ b/sapi/phpdbg/phpdbg_list.c @@ -288,6 +288,14 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type) { fake.opened_path = NULL; zend_file_handle_dtor(&fake); + dataptr->op_array = ret; + if (dataptr->op_array->refcount) { + ++*dataptr->op_array->refcount; + } else { + dataptr->op_array->refcount = emalloc(sizeof(uint32_t)); + *dataptr->op_array->refcount = 2; + } + return ret; } @@ -301,6 +309,10 @@ void phpdbg_free_file_source(phpdbg_file_source *data) { efree(data->buf); } + if (destroy_op_array(data->op_array)) { + efree(data->op_array); + } + efree(data); } diff --git a/sapi/phpdbg/phpdbg_list.h b/sapi/phpdbg/phpdbg_list.h index 3436ddd8fb..bfaef06248 100644 --- a/sapi/phpdbg/phpdbg_list.h +++ b/sapi/phpdbg/phpdbg_list.h @@ -47,6 +47,7 @@ typedef struct { #if HAVE_MMAP void *map; #endif + zend_op_array *op_array; uint lines; uint line[1]; } phpdbg_file_source; diff --git a/sapi/phpdbg/tests/phpdbg_oplog_001.phpt b/sapi/phpdbg/tests/phpdbg_oplog_001.phpt index 868493b4ba..15eeea5ebe 100644 --- a/sapi/phpdbg/tests/phpdbg_oplog_001.phpt +++ b/sapi/phpdbg/tests/phpdbg_oplog_001.phpt @@ -9,9 +9,7 @@ q [Successful compilation of %s] prompt> halloarray(2) { ["%s"]=> - array(6) { - [11]=> - int(0) + array(5) { [13]=> int(1) [17]=> @@ -25,10 +23,10 @@ prompt> halloarray(2) { } ["A::b"]=> array(2) { - [5]=> - int(5) [4]=> int(1) + [5]=> + int(5) } } [Script ended normally] @@ -54,5 +52,5 @@ $a = new A(); $a->b(); $a->b('ha'); -var_dump(phpdbg_end_oplog(["functions" => true, "show_unexecuted" => true])); +var_dump(phpdbg_end_oplog(["functions" => true])); |
