com php-src: first working version of wildcard watchpoints: phpdbg.c phpdbg_prompt.c phpdbg_watch.c phpdbg_watch.h test.php
| From: | Bob Weinand | Date: | Wed, 18 Dec 2013 07:56:20 +0000 |
| Subject: | com php-src: first working version of wildcard watchpoints: phpdbg.c phpdbg_prompt.c phpdbg_watch.c phpdbg_watch.h test.php | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-77106@lists.php.net to get a copy of this message | ||
Commit: 0dbc5c2087622f203143bbf4347aff0eeb0e4e0b
Author: Bob Weinand <bobwei9@hotmail.com> Wed, 18 Dec 2013 02:56:20 -0500
Parents: 0a8c20e740d6680ecfe566e5e681a3da4c67970e
Branches: PHP-5.6
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=0dbc5c2087622f203143bbf4347aff0eeb0e4e0b
Log:
first working version of wildcard watchpoints
Changed paths:
M phpdbg.c
M phpdbg_prompt.c
M phpdbg_watch.c
M phpdbg_watch.h
M test.php
Diff:
diff --git a/phpdbg.c b/phpdbg.c
index e3c998d..891875e 100644
--- a/phpdbg.c
+++ b/phpdbg.c
@@ -177,6 +177,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
zend_hash_destroy(&PHPDBG_G(seek));
zend_hash_destroy(&PHPDBG_G(registered));
zend_hash_destroy(&PHPDBG_G(watchpoints));
+ zend_llist_destroy(&PHPDBG_G(watchlist_mem));
if (PHPDBG_G(exec)) {
efree(PHPDBG_G(exec));
diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c
index 626177f..1caa219 100644
--- a/phpdbg_prompt.c
+++ b/phpdbg_prompt.c
@@ -1020,6 +1020,10 @@ PHPDBG_COMMAND(watch) /* {{{ */
phpdbg_create_var_watchpoint(param->str, param->len TSRMLS_CC);
break;
+ case EMPTY_PARAM:
+ phpdbg_list_watchpoints(TSRMLS_C);
+ break;
+
phpdbg_default_switch_case();
}
diff --git a/phpdbg_watch.c b/phpdbg_watch.c
index a87da5f..b3438c6 100644
--- a/phpdbg_watch.c
+++ b/phpdbg_watch.c
@@ -93,10 +93,113 @@ void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch) {
watch->type = WATCH_ON_ZVAL;
}
-int phpdbg_create_var_watchpoint(char *name, size_t len TSRMLS_DC) {
+static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, int i
TSRMLS_DC) {
+ zend_bool new_index = 1;
+ char *last_index;
+ int index_len = 0;
zval **zv;
- phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
+ if (len < 2 || *input != '$') {
+ goto error;
+ }
+
+ while (i++ < len) {
+ if (i == len) {
+ new_index = 1;
+ } else {
+ switch (input[i]) {
+ case '[':
+ new_index = 1;
+ break;
+ case ']':
+ break;
+ case '>':
+ if (last_index[index_len - 1] == '-') {
+ new_index = 1;
+ index_len--;
+ }
+ break;
+
+ default:
+ if (new_index) {
+ last_index = input + i;
+ new_index = 0;
+ }
+ if (input[i - 1] == ']') {
+ goto error;
+ }
+ index_len++;
+ }
+ }
+
+ if (new_index && index_len == 0) {
+ HashPosition position;
+ for (zend_hash_internal_pointer_reset_ex(parent, &position);
+ zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS;
+ zend_hash_move_forward_ex(parent, &position)) {
+ if (i == len || (i == len - 1 && input[len - 1] == ']')) {
+ zval *key = emalloc(sizeof(zval));
+ phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
+ zend_hash_get_current_key_zval_ex(parent, key, &position);
+ convert_to_string(key);
+ watch->str_len = asprintf(&watch->str, "%.*s%.*s%s", i, input,
Z_STRLEN_P(key), Z_STRVAL_P(key), input[len - 1] == ']'?"]":"");
+ efree(key);
+ watch->name_in_parent = estrndup(last_index, index_len);
+ watch->name_in_parent_len = index_len;
+ watch->parent_container = parent;
+ phpdbg_create_zval_watchpoint(*zv, watch TSRMLS_CC);
+ phpdbg_store_watchpoint(watch TSRMLS_CC);
+ zend_hash_add(&PHPDBG_G(watchpoints), watch->str, watch->str_len, &watch,
sizeof(phpdbg_watchpoint_t *), NULL);
+
+ phpdbg_activate_watchpoint(watch);
+ } else if (Z_TYPE_PP(zv) == IS_OBJECT) {
+ phpdbg_watchpoint_parse_input(input, len, Z_OBJPROP_PP(zv), i TSRMLS_CC);
+ } else if (Z_TYPE_PP(zv) == IS_ARRAY) {
+ phpdbg_watchpoint_parse_input(input, len, Z_ARRVAL_PP(zv), i TSRMLS_CC);
+ } else {
+ /* Ignore silently */
+ }
+ }
+ return SUCCESS;
+ } else if (new_index) {
+ char last_chr = last_index[index_len];
+ last_index[index_len] = 0;
+ if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) {
+ phpdbg_error("%.*s is undefined", i, input);
+ return FAILURE;
+ }
+ last_index[index_len] = last_chr;
+ if (i == len) {
+ phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
+ watch->str = estrndup(input, len);
+ watch->str_len = len;
+ watch->name_in_parent = estrndup(last_index, index_len);
+ watch->name_in_parent_len = index_len;
+ watch->parent_container = parent;
+ phpdbg_create_zval_watchpoint(*zv, watch TSRMLS_CC);
+ phpdbg_store_watchpoint(watch TSRMLS_CC);
+ zend_hash_add(&PHPDBG_G(watchpoints), input, len, &watch, sizeof(phpdbg_watchpoint_t
*), NULL);
+
+ phpdbg_activate_watchpoint(watch);
+ } else if (Z_TYPE_PP(zv) == IS_OBJECT) {
+ parent = Z_OBJPROP_PP(zv);
+ } else if (Z_TYPE_PP(zv) == IS_ARRAY) {
+ parent = Z_ARRVAL_PP(zv);
+ } else {
+ phpdbg_error("%.*s is nor an array nor an object", i, input);
+ return FAILURE;
+ }
+ index_len = 0;
+ }
+ }
+
+ return SUCCESS;
+ error:
+ phpdbg_error("Malformed input");
+ return FAILURE;
+}
+
+int phpdbg_create_var_watchpoint(char *input, size_t len TSRMLS_DC) {
if (!EG(active_op_array)) {
phpdbg_error("No active op array!");
return SUCCESS;
@@ -111,22 +214,7 @@ int phpdbg_create_var_watchpoint(char *name, size_t len TSRMLS_DC) {
}
}
- watch->str = estrndup(name, len);
- watch->parent_container = EG(current_execute_data)->symbol_table;
- watch->name_in_parent = estrndup(name, len);
- watch->name_in_parent_len = len + 1;
-
- /* Lookup current symbol table */
- if (zend_hash_find(EG(current_execute_data)->symbol_table, name, len + 1, (void **)&zv) ==
SUCCESS) {
- phpdbg_create_zval_watchpoint(*zv, watch TSRMLS_CC);
- zend_hash_add(&PHPDBG_G(watchpoints), name, len, &watch, sizeof(phpdbg_watchpoint_t *),
NULL);
- phpdbg_store_watchpoint(watch TSRMLS_CC);
-
- phpdbg_activate_watchpoint(watch);
- return SUCCESS;
- }
-
- return FAILURE;
+ return phpdbg_watchpoint_parse_input(input, len, EG(active_symbol_table), 0 TSRMLS_CC);
}
int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC) {
@@ -229,9 +317,9 @@ static int phpdbg_print_changed_zval(void *llist_data) {
phpdbg_writeln("\nOld refcount: %d; Old is_ref: %d", ((zval
*)oldPtr)->refcount__gc, ((zval *)oldPtr)->is_ref__gc);
/* check if zval was removed */
- if (((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc &&
!zend_hash_exists(watch->parent_container, watch->name_in_parent,
watch->name_in_parent_len)) {
- phpdbg_notice("Watchpoint %s was unset, removing watchpoint");
- phpdbg_deactivate_watchpoint(watch);
+ if (((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc &&
!zend_symtable_exists(watch->parent_container, watch->name_in_parent,
watch->name_in_parent_len + 1)) {
+ phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str);
+ zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
break;
}
@@ -256,3 +344,14 @@ int phpdbg_print_changed_zvals(TSRMLS_D) {
return PHPDBG_G(watchpoint_hit)?SUCCESS:FAILURE;
}
+
+void phpdbg_list_watchpoints(TSRMLS_D) {
+ HashPosition position;
+ phpdbg_watchpoint_t **watch;
+
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(watchpoints), &position);
+ zend_hash_get_current_data_ex(&PHPDBG_G(watchpoints), (void**) &watch, &position)
== SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(watchpoints), &position)) {
+ phpdbg_writeln("%.*s", (int)(*watch)->str_len, (*watch)->str);
+ }
+}
diff --git a/phpdbg_watch.h b/phpdbg_watch.h
index 8c83363..ce76321 100644
--- a/phpdbg_watch.h
+++ b/phpdbg_watch.h
@@ -48,10 +48,10 @@ struct _phpdbg_watchpoint_t {
char *name_in_parent;
size_t name_in_parent_len;
char *str;
+ size_t str_len;
union {
zval *zv;
HashTable *ht;
- zend_llist *llist;
void *ptr;
} addr;
size_t size;
@@ -68,4 +68,6 @@ int phpdbg_create_var_watchpoint(char *name, size_t len TSRMLS_DC);
int phpdbg_print_changed_zvals(TSRMLS_D);
+void phpdbg_list_watchpoints(TSRMLS_D);
+
#endif
diff --git a/test.php b/test.php
index 744ed79..669eb34 100644
--- a/test.php
+++ b/test.php
@@ -50,5 +50,18 @@ function phpdbg_test_ob()
echo $b;
}
+$array = [
+ 1,
+ 2,
+ [3, 4],
+ [5, 6],
+];
+
+array_walk($array, function (&$item) {
+ if (is_array($item))
+ $item[0] += 2;
+ else
+ $item -= 1;
+});
?>