]> granicus.if.org Git - php/commitdiff
Moved btree to separate file; minor fixes and completitions
authorBob Weinand <bobwei9@hotmail.com>
Sun, 15 Dec 2013 14:05:50 +0000 (09:05 -0500)
committerBob Weinand <bobwei9@hotmail.com>
Sun, 15 Dec 2013 14:05:50 +0000 (09:05 -0500)
config.m4
config.w32
phpdbg.h
phpdbg_btree.c [new file with mode: 0644]
phpdbg_btree.h [new file with mode: 0644]
phpdbg_watch.c

index 3016a2075df4c904ea47b508ef5d4e1deeaeae46..9e2d210580565056d492b46937c4a63f30795664 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -18,7 +18,7 @@ if test "$PHP_PHPDBG" != "no"; then
   fi
 
   PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
-  PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c"
+  PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c"
 
   PHP_SUBST(PHP_PHPDBG_CFLAGS)
   PHP_SUBST(PHP_PHPDBG_FILES)
index d97873ec85d3ddfcd5f78c094351db05cf361ac8..5813e7f15644317b65c50b056da9c3f1445fe28e 100644 (file)
@@ -1,7 +1,7 @@
 ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes');
 ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no');
 
-PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c';
+PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c';
 PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll';
 PHPDBG_EXE='phpdbg.exe';
 
index 5014976795898dc197a154ca598175a2c3523eb3..abbb5b8a7a65ab1a628242e23ad031eb01c32e3c 100644 (file)
--- a/phpdbg.h
+++ b/phpdbg.h
@@ -68,6 +68,7 @@
 
 #include "phpdbg_cmd.h"
 #include "phpdbg_utils.h"
+#include "phpdbg_btree.h"
 #include "phpdbg_watch.h"
 
 #ifdef ZTS
 #define PHPDBG_IO_FDS                  3 /* }}} */
 
 /* {{{ structs */
-typedef union _phpdbg_btree phpdbg_btree;
-union _phpdbg_btree {
-       phpdbg_btree *branches[2];
-       phpdbg_watchpoint_t *watchpoint;
-};
-
 ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
        HashTable bp[PHPDBG_BREAK_TABLES];           /* break points */
        HashTable registered;                        /* registered */
@@ -175,7 +170,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
 
        struct sigaction old_sigsegv_signal;         /* segv signal handler */
 
-       phpdbg_btree *watchpoint_tree;               /* tree with watchpoints */
+       phpdbg_btree watchpoint_tree;                /* tree with watchpoints */
        HashTable watchpoints;                       /* watchpoints */
        zend_llist watchlist_mem;                    /* triggered watchpoints */
        zend_bool watchpoint_hit;                    /* a watchpoint was hit */
diff --git a/phpdbg_btree.c b/phpdbg_btree.c
new file mode 100644 (file)
index 0000000..f47422f
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2013 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        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Felipe Pena <felipe@php.net>                                |
+   | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
+   | Authors: Bob Weinand <bwoebi@php.net>                                |
+   +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg_btree.h"
+#include "phpdbg.h"
+
+#define CHOOSE_BRANCH(n) \
+       branch = branch->branches[!!(n)];
+
+/* depth in bits */
+void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth) {
+       tree->depth = depth;
+       tree->branch = NULL;
+}
+
+phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx) {
+       phpdbg_btree_branch *branch = tree->branch;
+       int i = tree->depth - 1;
+
+       do {
+               if ((idx >> i) % 2 == 1) {
+                       if (branch->branches[1]) {
+                               CHOOSE_BRANCH(1);
+                       } else {
+                               return NULL;
+                       }
+               } else {
+                       if (branch->branches[0]) {
+                               CHOOSE_BRANCH(0);
+                       } else {
+                               return NULL;
+                       }
+               }
+       } while (i--);
+
+       return &branch->result;
+}
+
+phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong idx) {
+       phpdbg_btree_branch *branch = tree->branch;
+       int i = tree->depth - 1, last_superior_i = -1;
+       zend_bool had_alternative_branch = 0;
+
+       if (branch == NULL) {
+               return NULL;
+       }
+
+       /* find nearest watchpoint */
+       do {
+               /* an impossible branch was found if: */
+               if (!had_alternative_branch && (idx >> i) % 2 == 0 && !branch->branches[0]) {
+                       /* there's no lower branch than idx */
+                       if (last_superior_i == -1) {
+                               /* failure */
+                               return NULL;
+                       }
+                       /* reset state */
+                       branch = tree->branch;
+                       i = sizeof(void *) * 8 - 1;
+                       /* follow branch according to bits in idx until the last lower branch before the impossible branch */
+                       do {
+                               CHOOSE_BRANCH((idx >> i) % 2 == 1 && branch->branches[1]);
+                       } while (--i > last_superior_i);
+                       /* use now the lower branch of which we can be sure that it contains only branches lower than idx */
+                       CHOOSE_BRANCH(0);
+                       /* and choose the highest possible branch in the branch containing only branches lower than idx */
+                       while (i--) {
+                               CHOOSE_BRANCH(branch->branches[1]);
+                       }
+                       break;
+               }
+               /* follow branch according to bits in idx until having found an impossible branch */
+               if (had_alternative_branch || (idx >> i) % 2 == 1) {
+                       if (branch->branches[1]) {
+                               if (branch->branches[0]) {
+                                       last_superior_i = i;
+                               }
+                               CHOOSE_BRANCH(1);
+                       } else {
+                               CHOOSE_BRANCH(0);
+                               had_alternative_branch = 1;
+                       }
+               } else {
+                       CHOOSE_BRANCH(0);
+               }
+       } while (i--);
+
+       return &branch->result;
+}
+
+phpdbg_btree_position phpdbg_btree_find_between(phpdbg_btree *tree, zend_ulong lower_idx, zend_ulong higher_idx) {
+       phpdbg_btree_position pos;
+
+       pos.tree = tree;
+       pos.end = lower_idx;
+       pos.cur = higher_idx;
+
+       return pos;
+}
+
+phpdbg_btree_result *phpdbg_btree_next(phpdbg_btree_position *pos) {
+       phpdbg_btree_result *result = phpdbg_btree_find_closest(pos->tree, pos->cur);
+
+       if (result == NULL || result->idx < pos->end) {
+               return NULL;
+       }
+
+       pos->cur = result->idx - 1;
+
+       return result;
+}
+
+int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, int flags) {
+       int i = tree->depth - 1;
+       phpdbg_btree_branch **branch = &tree->branch;
+
+       do {
+               if (*branch == NULL) {
+                       break;
+               }
+               branch = &(*branch)->branches[(idx >> i) % 2];
+       } while (i--);
+
+       if (*branch == NULL) {
+               if (!(flags & PHPDBG_BTREE_INSERT)) {
+                       return FAILURE;
+               }
+
+               {
+                       phpdbg_btree_branch *memory = *branch = emalloc((i + 2) * sizeof(phpdbg_btree_branch));
+                       do {
+                               (*branch)->branches[!((idx >> i) % 2)] = NULL;
+                               branch = &(*branch)->branches[(idx >> i) % 2];
+                               *branch = ++memory;
+                       } while (i--);
+               }
+       } else if (!(flags & PHPDBG_BTREE_UPDATE)) {
+               return FAILURE;
+       }
+
+       (*branch)->result.idx = idx;
+       (*branch)->result.ptr = ptr;
+
+       return SUCCESS;
+}
+
+int phpdbg_btree_delete(phpdbg_btree *tree, zend_ulong idx) {
+       int i = tree->depth - 1;
+       phpdbg_btree_branch *branch = tree->branch;
+       int i_last_dual_branch = -1, last_dual_branch_branch;
+       phpdbg_btree_branch *last_dual_branch = NULL;
+
+       do {
+               if (branch == NULL) {
+                       return FAILURE;
+               }
+               if (branch->branches[0] && branch->branches[1]) {
+                       last_dual_branch = branch;
+                       i_last_dual_branch = i;
+                       last_dual_branch_branch = (idx >> i) % 2;
+               }
+               branch = branch->branches[(idx >> i) % 2];
+       } while (i--);
+
+       if (i_last_dual_branch == -1) {
+               efree(tree);
+               tree = NULL;
+       } else {
+               if (last_dual_branch->branches[last_dual_branch_branch] == last_dual_branch + 1) {
+                       memcpy(last_dual_branch + 1, last_dual_branch->branches[!last_dual_branch_branch], i_last_dual_branch * sizeof(phpdbg_btree_branch));
+                       efree(last_dual_branch->branches[last_dual_branch_branch]);
+                       last_dual_branch->branches[!last_dual_branch_branch] = last_dual_branch + 1;
+               } else {
+                       efree(last_dual_branch->branches[last_dual_branch_branch]);
+               }
+
+               last_dual_branch->branches[i_last_dual_branch] = NULL;
+       }
+
+       return SUCCESS;
+}
diff --git a/phpdbg_btree.h b/phpdbg_btree.h
new file mode 100644 (file)
index 0000000..7bb40ae
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2013 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        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Felipe Pena <felipe@php.net>                                |
+   | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
+   | Authors: Bob Weinand <bwoebi@php.net>                                |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_BTREE_H
+#define PHPDBG_BTREE_H
+
+#include "zend.h"
+
+typedef struct {
+       zend_ulong idx;
+       void *ptr;
+} phpdbg_btree_result;
+
+typedef union _phpdbg_btree_branch phpdbg_btree_branch;
+union _phpdbg_btree_branch {
+       phpdbg_btree_branch *branches[2];
+       phpdbg_btree_result result;
+};
+
+typedef struct {
+       zend_ulong depth;
+       phpdbg_btree_branch *branch;
+} phpdbg_btree;
+
+typedef struct {
+       phpdbg_btree *tree;
+       zend_ulong cur;
+       zend_ulong end;
+} phpdbg_btree_position;
+
+void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth);
+phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx);
+phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong idx);
+phpdbg_btree_position phpdbg_btree_find_between(phpdbg_btree *tree, zend_ulong lower_idx, zend_ulong higher_idx);
+phpdbg_btree_result *phpdbg_btree_next(phpdbg_btree_position *pos);
+int phpdbg_btree_delete(phpdbg_btree *tree, zend_ulong idx);
+
+#define PHPDBG_BTREE_INSERT 1
+#define PHPDBG_BTREE_UPDATE 2
+#define PHPDBG_BTREE_OVERWRITE (PHPDBG_BTREE_INSERT | PHPDBG_BTREE_UPDATE)
+
+int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, int flags);
+#define phpdbg_btree_insert(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_INSERT)
+#define phpdbg_btree_update(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_UPDATE)
+#define phpdbg_btree_overwrite(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_OWERWRITE)
+
+#endif
index 00c83b5717b3310925f34880e50918cdc5855c4a..66fcb8eab75b4679906fa17cd9544f408dac4056 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "zend.h"
 #include "phpdbg.h"
+#include "phpdbg_btree.h"
 #include "phpdbg_watch.h"
 #include <unistd.h>
 #include <sys/mman.h>
@@ -37,10 +38,6 @@ typedef struct {
 
 #define MEMDUMP_SIZE(size) (sizeof(phpdbg_watch_memdump) - sizeof(void *) + (size))
 
-#define CHOOSE_BRANCH(n) \
-       addr = (addr << 1) + !!(n); \
-       branch = branch->branches[!!(n)];
-
 void phpdbg_watch_mem_dtor(void *llist_data) {
        void *page = (*(phpdbg_watch_memdump **)llist_data)->page;
        size_t size = (*(phpdbg_watch_memdump **)llist_data)->size;
@@ -63,6 +60,7 @@ void phpdbg_setup_watchpoints(TSRMLS_D) {
 #endif
 
        zend_llist_init(&PHPDBG_G(watchlist_mem), sizeof(void *), phpdbg_watch_mem_dtor, 0);
+       phpdbg_btree_init(&PHPDBG_G(watchpoint_tree), sizeof(void *) * 8);
 }
 
 void *phpdbg_get_page_boundary(void *addr) {
@@ -73,53 +71,11 @@ size_t phpdbg_get_total_page_size(void *addr, size_t size) {
        return (size_t)phpdbg_get_page_boundary(addr + size - 1) - (size_t)phpdbg_get_page_boundary(addr) + phpdbg_pagesize;
 }
 
-phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *watch_addr) {
-       phpdbg_watchpoint_t *watch;
-       phpdbg_btree *branch = PHPDBG_G(watchpoint_tree);
-       int i = sizeof(void *) * 8 - 1, last_superior_i = -1;
-       size_t addr = 0;
-       size_t opline = (size_t)phpdbg_get_page_boundary(watch_addr) + phpdbg_pagesize - 1;
-
-       /* find nearest watchpoint */
-       do {
-               /* an impossible branch was found if: */
-               if ((opline >> i) % 2 == 0 && !branch->branches[0]) {
-                       /* there's no lower branch than opline */
-                       if (last_superior_i == -1) {
-                               /* failure */
-                               return NULL;
-                       }
-                       /* reset state */
-                       branch = PHPDBG_G(watchpoint_tree);
-                       addr = 0;
-                       i = sizeof(void *) * 8 - 1;
-                       /* follow branch according to bits in opline until the last lower branch before the impossible branch */
-                       do {
-                               CHOOSE_BRANCH((opline >> i) % 2 == 1 && branch->branches[1]);
-                       } while (--i > last_superior_i);
-                       /* use now the lower branch of which we can be sure that it contains only branches lower than opline */
-                       CHOOSE_BRANCH(0);
-                       /* and choose the highest possible branch in the branch containing only branches lower than opline */
-                       while (i--) {
-                               CHOOSE_BRANCH(branch->branches[1]);
-                       }
-                       break;
-               }
-               /* follow branch according to bits in opline until having found an impossible branch */
-               if ((opline >> i) % 2 == 1 && branch->branches[1]) {
-                       if (branch->branches[0]) {
-                               last_superior_i = i;
-                       }
-                       CHOOSE_BRANCH(1);
-               } else {
-                       CHOOSE_BRANCH(0);
-               }
-       } while (i--);
-
-       watch = branch->watchpoint;
+phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr) {
+       phpdbg_watchpoint_t *watch = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong)phpdbg_get_page_boundary(addr) + phpdbg_pagesize - 1)->ptr;
 
        /* check if that addr is in a mprotect()'ed memory area */
-       if ((char *)phpdbg_get_page_boundary(watch->addr.ptr) + phpdbg_get_total_page_size(watch->addr.ptr, watch->size) < (char *)addr) {
+       if ((char *)phpdbg_get_page_boundary(watch->addr.ptr) > (char *)addr || (char *)phpdbg_get_page_boundary(watch->addr.ptr) + phpdbg_get_total_page_size(watch->addr.ptr, watch->size) < (char *)addr) {
                /* failure */
                return NULL;
        }
@@ -160,60 +116,17 @@ int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC)
 }
 
 int phpdbg_print_changed_zval(void *llist_data) {
-       phpdbg_watch_memdump *dump = *(phpdbg_watch_memdump **)llist_data;
-       void *oldPtr;
-       size_t opline;
-
        TSRMLS_FETCH();
 
+       phpdbg_watch_memdump *dump = *(phpdbg_watch_memdump **)llist_data;
        /* fetch all changes between dump->page and dump->page + dump->size */
-       opline = (size_t)dump->page + dump->size - 1;
-
-       while (1) {
-               phpdbg_btree *branch = PHPDBG_G(watchpoint_tree);
-               phpdbg_watchpoint_t *watch;
-               int i = sizeof(void *) * 8 - 1, last_superior_i = -1;
-               size_t addr = 0;
-
-               do {
-                       /* an impossible branch was found if: */
-                       if ((opline >> i) % 2 == 0 && !branch->branches[0]) {
-                               /* there's no lower branch than opline */
-                               if (last_superior_i == -1) {
-                                       return 1;
-                               }
-                               /* reset state */
-                               branch = PHPDBG_G(watchpoint_tree);
-                               addr = 0;
-                               i = sizeof(void *) * 8 - 1;
-                               /* follow branch according to bits in opline until the last lower branch before the impossible branch */
-                               do {
-                                       CHOOSE_BRANCH((opline >> i) % 2 == 1 && branch->branches[1]);
-                               } while (--i > last_superior_i);
-                               /* use now the lower branch of which we can be sure that it contains only branches lower than opline */
-                               CHOOSE_BRANCH(0);
-                               /* and choose the highest possible branch in the branch containing only branches lower than opline */
-                               while (i--) {
-                                       CHOOSE_BRANCH(branch->branches[1]);
-                               }
-                               break;
-                       }
-                       /* follow branch according to bits in opline until having found an impossible branch */
-                       if ((opline >> i) % 2 == 1 && branch->branches[1]) {
-                               if (branch->branches[0]) {
-                                       last_superior_i = i;
-                               }
-                               CHOOSE_BRANCH(1);
-                       } else {
-                               CHOOSE_BRANCH(0);
-                       }
-               } while (i--);
+       phpdbg_btree_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), (zend_ulong)dump->page, (zend_ulong)dump->page + dump->size);
+       phpdbg_btree_result *result;
 
-               if (watch == branch->watchpoint)
-                       return 1; /* TODO: there's sometime wrong with the breaking condition ... */
 
-               watch = branch->watchpoint;
-               oldPtr = (char *)&dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page);
+       while ((result = phpdbg_btree_next(&pos))) {
+               phpdbg_watchpoint_t *watch = result->ptr;
+               void *oldPtr = (char *)&dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page);
                if (memcmp(oldPtr, watch->addr.ptr, watch->size) != SUCCESS) {
                        PHPDBG_G(watchpoint_hit) = 1;
 
@@ -222,17 +135,13 @@ int phpdbg_print_changed_zval(void *llist_data) {
                                case WATCH_ON_ZVAL:
                                        phpdbg_write("Old value: ");
                                        zend_print_flat_zval_r((zval *)oldPtr TSRMLS_CC);
-                                       phpdbg_writeln("");
+                                       phpdbg_writeln("\nOld refcount: %d; Old is_ref: %d", ((zval *)oldPtr)->refcount__gc, ((zval *)oldPtr)->is_ref__gc);
                                        phpdbg_write("New value: ");
                                        zend_print_flat_zval_r(watch->addr.zv TSRMLS_CC);
-                                       phpdbg_writeln("");
+                                       phpdbg_writeln("\nNew refcount: %d; Old is_ref: %d", watch->addr.zv->refcount__gc, watch->addr.zv->is_ref__gc);
                                        break;
                        }
-               } else {
-                       break;
                }
-
-               opline = (size_t)watch->addr.ptr - 1;
        }
 
        return 1;
@@ -250,37 +159,14 @@ int phpdbg_print_changed_zvals(TSRMLS_D) {
 }
 
 void phpdbg_store_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
-       phpdbg_btree **branch = &PHPDBG_G(watchpoint_tree);
-       int i = sizeof(void *) * 8 - 1;
-
-       do {
-               if (*branch == NULL) {
-                       break;
-               }
-               branch = &(*branch)->branches[((size_t)watch->addr.ptr >> i) % 2];
-       } while (i--);
-
-       if (*branch == NULL) {
-               phpdbg_btree *memory = *branch = emalloc((i + 2) * sizeof(phpdbg_btree));
-               do {
-                       (*branch)->branches[!(((size_t)watch->addr.ptr >> i) % 2)] = NULL;
-                       branch = &(*branch)->branches[((size_t)watch->addr.ptr >> i) % 2];
-                       *branch = ++memory;
-               } while (i--);
-       }
-
-       (*branch)->watchpoint = watch;
+       phpdbg_btree_insert(&PHPDBG_G(watchpoint_tree), (zend_ulong)watch->addr.ptr, watch);
 }
 
-void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch) {
+void phpdbg_activate_watchpoint (phpdbg_watchpoint_t *watch) {
        int m;
 
-       watch->addr.ptr = addr;
-       watch->size = size;
-       watch->type = WATCH_ON_PTR;
-
        /* pagesize is assumed to be in the range of 2^x */
-       m = mprotect(phpdbg_get_page_boundary(addr), phpdbg_get_total_page_size(addr, size), PROT_NONE | PROT_READ);
+       m = mprotect(phpdbg_get_page_boundary(watch->addr.ptr), phpdbg_get_total_page_size(watch->addr.ptr, watch->size), PROT_NONE | PROT_READ);
 
        if (m == FAILURE) {
                phpdbg_error("Unable to set watchpoint (mprotect() failed)");
@@ -288,6 +174,12 @@ void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t
        }
 }
 
+void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch) {
+       watch->addr.ptr = addr;
+       watch->size = size;
+       watch->type = WATCH_ON_PTR;
+}
+
 void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch) {
        phpdbg_create_addr_watchpoint(zv, sizeof(zval), watch);
        watch->type = WATCH_ON_ZVAL;
@@ -315,9 +207,11 @@ int phpdbg_create_var_watchpoint(char *name, size_t len TSRMLS_DC) {
 
        /* 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);
                zend_hash_add(&PHPDBG_G(watchpoints), name, len, &watch, sizeof(phpdbg_watchpoint_t *), NULL);
                phpdbg_store_watchpoint(watch TSRMLS_CC);
-               phpdbg_create_zval_watchpoint(*zv, watch);
+
+               phpdbg_activate_watchpoint(watch);
                return SUCCESS;
        }