diff options
Diffstat (limited to 'sapi/phpdbg/phpdbg_bp.c')
-rw-r--r-- | sapi/phpdbg/phpdbg_bp.c | 134 |
1 files changed, 86 insertions, 48 deletions
diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index 1c06646f0e..4cb1dae42c 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2015 The PHP Group | + | Copyright (c) 1997-2016 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 | @@ -26,7 +26,7 @@ #include "phpdbg_opcode.h" #include "zend_globals.h" -ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +ZEND_EXTERN_MODULE_GLOBALS(phpdbg) /* {{{ private api functions */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array*); @@ -63,6 +63,7 @@ static void phpdbg_file_breaks_dtor(zval *data) /* {{{ */ phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) Z_PTR_P(data); efree((char*)bp->filename); + efree(bp); } /* }}} */ static void phpdbg_class_breaks_dtor(zval *data) /* {{{ */ @@ -71,11 +72,13 @@ static void phpdbg_class_breaks_dtor(zval *data) /* {{{ */ efree((char*)bp->class_name); efree((char*)bp->func_name); + efree(bp); } /* }}} */ static void phpdbg_opline_class_breaks_dtor(zval *data) /* {{{ */ { - zend_hash_destroy((HashTable *) Z_PTR_P(data)); + zend_hash_destroy(Z_ARRVAL_P(data)); + efree(Z_ARRVAL_P(data)); } /* }}} */ static void phpdbg_opline_breaks_dtor(zval *data) /* {{{ */ @@ -88,6 +91,7 @@ static void phpdbg_opline_breaks_dtor(zval *data) /* {{{ */ if (bp->func_name) { efree((char*)bp->func_name); } + efree(bp); } /* }}} */ PHPDBG_API void phpdbg_reset_breakpoints(void) /* {{{ */ @@ -208,6 +212,8 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */ phpdbg_asprintf(&new_str, "%sbreak if %s\n", str, conditional->code); } } break; + + default: continue; } if ((*str)[0]) { @@ -230,8 +236,9 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* { char realpath[MAXPATHLEN]; const char *original_path = path; zend_bool pending = 0; + zend_string *path_str; - HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE]; + HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE]; phpdbg_breakfile_t new_break; size_t path_len = 0L; @@ -261,11 +268,13 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* { } } - if (!(broken = zend_hash_str_find_ptr(file_breaks, path, path_len))) { + path_str = zend_string_init(path, path_len, 0); + + if (!(broken = zend_hash_find_ptr(file_breaks, path_str))) { HashTable breaks; zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0); - broken = zend_hash_str_add_mem(file_breaks, path, path_len, &breaks, sizeof(HashTable)); + broken = zend_hash_add_mem(file_breaks, path_str, &breaks, sizeof(HashTable)); } if (!zend_hash_index_exists(broken, line_num)) { @@ -278,18 +287,17 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* { PHPDBG_BREAK_MAPPING(new_break.id, broken); if (pending) { - zend_string *file, *path_str = zend_string_init(path, path_len, 0); + zend_string *file; ZEND_HASH_FOREACH_STR_KEY(&PHPDBG_G(file_sources), file) { HashTable *fileht; phpdbg_debug("Compare against loaded %s\n", file); if (!(pending = ((fileht = phpdbg_resolve_pending_file_break_ex(ZSTR_VAL(file), ZSTR_LEN(file), path_str, broken)) == NULL))) { - new_break = *(phpdbg_breakfile_t *) zend_hash_index_find_ptr(broken, line_num); + new_break = *(phpdbg_breakfile_t *) zend_hash_index_find_ptr(fileht, line_num); break; } } ZEND_HASH_FOREACH_END(); - zend_string_release(path_str); } if (pending) { @@ -304,13 +312,21 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* { } else { phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); } + + zend_string_release(path_str); } /* }}} */ PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, zend_string *cur, HashTable *fileht) /* {{{ */ { phpdbg_debug("file: %s, filelen: %u, cur: %s, curlen %u, pos: %c, memcmp: %d\n", file, filelen, ZSTR_VAL(cur), ZSTR_LEN(cur), filelen > ZSTR_LEN(cur) ? file[filelen - ZSTR_LEN(cur) - 1] : '?', filelen > ZSTR_LEN(cur) ? memcmp(file + filelen - ZSTR_LEN(cur), ZSTR_VAL(cur), ZSTR_LEN(cur)) : 0); - if (((ZSTR_LEN(cur) < filelen && file[filelen - ZSTR_LEN(cur) - 1] == '/') || filelen == ZSTR_LEN(cur)) && !memcmp(file + filelen - ZSTR_LEN(cur), ZSTR_VAL(cur), ZSTR_LEN(cur))) { +#ifdef _WIN32 +# define WIN32_PATH_CHECK file[filelen - ZSTR_LEN(cur) - 1] == '\\' +#else +# define WIN32_PATH_CHECK 0 +#endif + + if (((ZSTR_LEN(cur) < filelen && (file[filelen - ZSTR_LEN(cur) - 1] == '/' || WIN32_PATH_CHECK)) || filelen == ZSTR_LEN(cur)) && !memcmp(file + filelen - ZSTR_LEN(cur), ZSTR_VAL(cur), ZSTR_LEN(cur))) { phpdbg_breakfile_t *brake, new_brake; HashTable *master; @@ -327,8 +343,7 @@ PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uin new_brake.filename = estrndup(file, filelen); PHPDBG_BREAK_UNMAPPING(brake->id); - if (master) { - zend_hash_index_update_mem(master, brake->line, &new_brake, sizeof(phpdbg_breakfile_t)); + if (zend_hash_index_add_mem(master, brake->line, &new_brake, sizeof(phpdbg_breakfile_t))) { PHPDBG_BREAK_MAPPING(brake->id, master); } } ZEND_HASH_FOREACH_END(); @@ -364,6 +379,15 @@ PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file) /* {{{ */ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len) /* {{{ */ { + char *lcname; + + if (*name == '\\') { + name++; + name_len--; + } + + lcname = zend_str_tolower_dup(name, name_len); + if (!zend_hash_str_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) { phpdbg_breaksymbol_t new_break; @@ -372,7 +396,7 @@ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len) PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_SYM); new_break.symbol = estrndup(name, name_len); - zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol, name_len, &new_break, sizeof(phpdbg_breaksymbol_t)); + zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], lcname, name_len, &new_break, sizeof(phpdbg_breaksymbol_t)); phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" function=\"%s\"", "Breakpoint #%d added at %s", new_break.id, new_break.symbol); @@ -380,6 +404,8 @@ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len) } else { phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" function=\"%s\"", "Breakpoint exists at %s", name); } + + efree(lcname); } /* }}} */ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char *func_name) /* {{{ */ @@ -387,14 +413,22 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char HashTable class_breaks, *class_table; size_t class_len = strlen(class_name); size_t func_len = strlen(func_name); - char *lcname = zend_str_tolower_dup(func_name, func_len); + char *func_lcname, *class_lcname; + + if (*class_name == '\\') { + class_name++; + class_len--; + } - if (!(class_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, class_len))) { + func_lcname = zend_str_tolower_dup(func_name, func_len); + class_lcname = zend_str_tolower_dup(class_name, class_len); + + if (!(class_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_lcname, class_len))) { zend_hash_init(&class_breaks, 8, NULL, phpdbg_class_breaks_dtor, 0); - class_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, class_len, &class_breaks, sizeof(HashTable)); + class_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_lcname, class_len, &class_breaks, sizeof(HashTable)); } - if (!zend_hash_str_exists(class_table, lcname, func_len)) { + if (!zend_hash_str_exists(class_table, func_lcname, func_len)) { phpdbg_breakmethod_t new_break; PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_BP; @@ -405,7 +439,7 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char new_break.func_name = estrndup(func_name, func_len); new_break.func_len = func_len; - zend_hash_str_update_mem(class_table, lcname, func_len, &new_break, sizeof(phpdbg_breakmethod_t)); + zend_hash_str_update_mem(class_table, func_lcname, func_len, &new_break, sizeof(phpdbg_breakmethod_t)); phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" method=\"%s::%s\"", "Breakpoint #%d added at %s::%s", new_break.id, class_name, func_name); @@ -414,7 +448,8 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" method=\"%s::%s\"", "Breakpoint exists at %s::%s", class_name, func_name); } - efree(lcname); + efree(func_lcname); + efree(class_lcname); } /* }}} */ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline) /* {{{ */ @@ -500,12 +535,12 @@ PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array) /* {{{ * opline_break = zend_hash_get_current_data_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" symbol=\"%s\" num=\"%ld\" opline=\"%#lx\"", "Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)", - brake->id, + opline_break->id, brake->class_name ? brake->class_name : "", brake->class_name && brake->func_name ? "::" : "", brake->func_name ? brake->func_name : "", brake->opline_num, - brake->opline); + opline_break->opline); } } ZEND_HASH_FOREACH_END(); } /* }}} */ @@ -528,12 +563,14 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break) /* { } else { zend_execute_data *execute_data = EG(current_execute_data); do { - zend_op_array *op_array = &execute_data->func->op_array; - if (op_array->function_name == NULL && op_array->scope == NULL && new_break->class_len == ZSTR_LEN(op_array->filename) && !memcmp(ZSTR_VAL(op_array->filename), new_break->class_name, new_break->class_len)) { - if (phpdbg_resolve_op_array_break(new_break, op_array) == SUCCESS) { - return SUCCESS; - } else { - return 2; + if (ZEND_USER_CODE(execute_data->func->common.type)) { + zend_op_array *op_array = &execute_data->func->op_array; + if (op_array->function_name == NULL && op_array->scope == NULL && new_break->class_len == ZSTR_LEN(op_array->filename) && !memcmp(ZSTR_VAL(op_array->filename), new_break->class_name, new_break->class_len)) { + if (phpdbg_resolve_op_array_break(new_break, op_array) == SUCCESS) { + return SUCCESS; + } else { + return 2; + } } } } while ((execute_data = execute_data->prev_execute_data) != NULL); @@ -573,6 +610,8 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break) /* { return SUCCESS; } /* }}} */ +/* TODO ... method/function oplines need to be normalized (leading backslash, lowercase) and file oplines need to be resolved properly */ + PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline) /* {{{ */ { phpdbg_breakopline_t new_break; @@ -749,6 +788,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline) /* { PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE); new_break.opline = (zend_ulong) opline; + new_break.base = NULL; zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t)); @@ -873,8 +913,6 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *fbc) /* {{{ */ { - const char *fname; - size_t flen; zend_op_array *ops; if (fbc->type != ZEND_USER_FUNCTION) { @@ -889,30 +927,33 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *f } if (ops->function_name) { - fname = ZSTR_VAL(ops->function_name); - flen = ZSTR_LEN(ops->function_name); + phpdbg_breakbase_t *brake; + zend_string *fname = zend_string_tolower(ops->function_name); + + brake = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname); + + zend_string_release(fname); + return brake; } else { - fname = "main"; - flen = 4; + return zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], ZEND_STRL("main")); } - - return zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname, flen); } /* }}} */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array *ops) /* {{{ */ { HashTable *class_table; phpdbg_breakbase_t *brake = NULL; + zend_string *class_lcname = zend_string_tolower(ops->scope->name); - if ((class_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name))) { - size_t lcname_len = ZSTR_LEN(ops->function_name); - char *lcname = zend_str_tolower_dup(ZSTR_VAL(ops->function_name), lcname_len); + if ((class_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_lcname))) { + zend_string *lcname = zend_string_tolower(ops->function_name); - brake = zend_hash_str_find_ptr(class_table, lcname, lcname_len); + brake = zend_hash_find_ptr(class_table, lcname); - efree(lcname); + zend_string_release(lcname); } + zend_string_release(class_lcname); return brake; } /* }}} */ @@ -929,9 +970,9 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_pt static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode) /* {{{ */ { - const char *opname = phpdbg_decode_opcode(opcode); + const char *opname = zend_get_opcode_name(opcode); - if (memcmp(opname, PHPDBG_STRL("UNKNOWN")) == 0) { + if (!opname) { return NULL; } @@ -1038,11 +1079,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut zend_try { PHPDBG_G(flags) |= PHPDBG_IN_COND_BP; zend_execute(bp->ops, &retval); -#if PHP_VERSION_ID >= 50700 if (zend_is_true(&retval)) { -#else - if (zend_is_true(&retval)) { -#endif breakpoint = SUCCESS; } } zend_end_try(); @@ -1081,8 +1118,9 @@ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data *execute } if (PHPDBG_G(flags) & (PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_SYM_BP)) { - /* check we are at the beginning of the stack */ - if (execute_data->opline == execute_data->func->op_array.opcodes) { + zend_op_array *op_array = &execute_data->func->op_array; + /* check we are at the beginning of the stack, but after argument RECV */ + if (execute_data->opline == op_array->opcodes + op_array->num_args + !!(op_array->fn_flags & ZEND_ACC_VARIADIC)) { if ((base = phpdbg_find_breakpoint_symbol(execute_data->func))) { goto result; } |