]> granicus.if.org Git - php/commitdiff
Finished working for today, continuing tomorrow (not working)
authorBob Weinand <bobwei9@hotmail.com>
Fri, 13 Dec 2013 22:57:36 +0000 (17:57 -0500)
committerBob Weinand <bobwei9@hotmail.com>
Fri, 13 Dec 2013 22:57:36 +0000 (17:57 -0500)
phpdbg.c
phpdbg.h
phpdbg_prompt.c
phpdbg_watch.c
phpdbg_watch.h

index d72133b2186421f30afeffa979dfef01ad58f4ba..147a66e55a34087f833b6589f9c6fb4f121aa0f9 100644 (file)
--- a/phpdbg.c
+++ b/phpdbg.c
@@ -153,7 +153,7 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
-       
+
        zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
        zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
 
index 906b894f263a42b7d1d1abefba3ad5f51cbb5400..f11176325b22b8d59e6bec3165c17969e5168234 100644 (file)
--- a/phpdbg.h
+++ b/phpdbg.h
@@ -177,6 +177,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
 
        phpdbg_btree *watchpoint_tree;               /* tree with watchpoints */
        HashTable watchpoints;                       /* watchpoints */
+       zend_llist watchlist_mem;                    /* triggered watchpoints */
 
        char *exec;                                  /* file to execute */
        size_t exec_len;                             /* size of exec */
index 07b9f1400eebb77c50d8f7a5cc24e299a88648f6..626177fa4ea5690669fa41968f308f59adf26560 100644 (file)
@@ -1291,6 +1291,13 @@ zend_vm_enter:
                phpdbg_print_opline_ex(
                        execute_data, &vars, 0 TSRMLS_CC);
 
+               /* check if some watchpoint was hit */
+               {
+                       if (phpdbg_print_changed_zvals(TSRMLS_C) == SUCCESS) {
+                               DO_INTERACTIVE();
+                       }
+               }
+
                /* search for breakpoints */
                {
                        phpdbg_breakbase_t *brake;
index e54431f3e018944c922c1b7d8eb65fb9c4a0bee3..66721ee8e65317f5d1307190939ef0f994565e44 100644 (file)
@@ -1,3 +1,23 @@
+/*
+   +----------------------------------------------------------------------+
+   | 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 "zend.h"
 #include "phpdbg.h"
 #include "phpdbg_watch.h"
@@ -8,7 +28,20 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
 
 long phpdbg_pagesize;
 
-void phpdbg_setup_watchpoints() {
+typedef struct {
+       void *page;
+       size_t size;
+       /* data must be last element */
+       void *data;
+} phpdbg_watch_memdump;
+
+#define MEMDUMP_SIZE(size) (sizeof(phpdbg_watch_memdump) - sizeof(void *) + (size))
+
+void phpdbg_watch_mem_dtor(void *llist_data) {
+       efree(llist_data);
+}
+
+void phpdbg_setup_watchpoints(TSRMLS_D) {
 #ifdef _SC_PAGE_SIZE
        phpdbg_pagesize = sysconf(_SC_PAGE_SIZE);
 #endif
@@ -18,32 +51,124 @@ void phpdbg_setup_watchpoints() {
 #ifdef _SC_NUTC_OS_PAGESIZE
        phpdbg_pagesize = sysconf(_SC_NUTC_OS_PAGESIZE);
 #endif
+
+       zend_llist_init(&PHPDBG_G(watchlist_mem), 0, phpdbg_watch_mem_dtor, 0);
 }
 
-int phpdbg_check_for_watchpoint(void *addr) {
-       return FAILURE;
+void *phpdbg_get_page_boundary(void *addr) {
+       return (void *)((unsigned long)addr & ~(phpdbg_pagesize - 1));
+}
+
+size_t phpdbg_get_total_page_size(size_t size) {
+       return ((size - 1)  & ~(phpdbg_pagesize - 1)) | phpdbg_pagesize;
+}
+
+phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr) {
+       phpdbg_watchpoint_t *watch;
+
+       /* find nearest watchpoint */
+
+       /* check if that watchpoint includes addr */
+       if (((char *)watch->addr.ptr) + watch->size > (char *)addr) {
+               /* failure */
+               return NULL;
+       }
+
+       return watch;
 }
 
 int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC) {
-       printf("Text");
-       return FAILURE;
+       void *addr;
+       void *page;
+       phpdbg_watch_memdump *dump;
+       phpdbg_watchpoint_t *watch;
+       size_t size;
+
+       addr = info->si_addr;
+
+       watch = phpdbg_check_for_watchpoint(addr);
+
+       if (watch == NULL) {
+               return FAILURE;
+       }
+
+       page = phpdbg_get_page_boundary(addr);
+       size = phpdbg_get_total_page_size(watch->size);
+
+       /* re-enable writing */
+       mprotect(page, size, PROT_NONE | PROT_READ | PROT_WRITE);
+
+       dump = emalloc(MEMDUMP_SIZE(size));
+
+       memcpy(&dump->data, page, size);
+
+       zend_llist_add_element(&PHPDBG_G(watchlist_mem), dump);
+
+       return SUCCESS;
+}
+
+int phpdbg_print_changed_zval(void *llist_data) {
+       phpdbg_watch_memdump *dump = llist_data;
+       phpdbg_watchpoint_t *watch;
+       phpdbg_btree *tree = PHPDBG_G(watchpoint_tree);
+       void *oldPtr;
+
+       TSRMLS_FETCH();
+
+       /* fetch all changes between dump->page and dump->page + dump->size */
+       watch = tree->watchpoint;
+       oldPtr = (char *)dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page);
+       if (memcmp(oldPtr, watch->addr.ptr, watch->size) == SUCCESS) {
+               phpdbg_notice("Breaking on watchpoint %s", watch->str);
+               switch (watch->type) {
+                       case WATCH_ON_ZVAL:
+                               phpdbg_write("Old value: ");
+                               zend_print_flat_zval_r((zval *)oldPtr TSRMLS_CC);
+                               phpdbg_write("New value: ");
+                               zend_print_flat_zval_r(watch->addr.zv TSRMLS_CC);
+                               break;
+               }
+       }
+       
+
+       return 1;
+}
+
+int phpdbg_print_changed_zvals(TSRMLS_D) {
+       if (zend_llist_count(&PHPDBG_G(watchlist_mem)) == 0) {
+               return FAILURE;
+       }
+
+       zend_llist_apply_with_del(&PHPDBG_G(watchlist_mem), phpdbg_print_changed_zval);
+
+       return SUCCESS;
 }
 
-void phpdbg_create_addr_watchpoint(void *addr, size_t size) {
+void phpdbg_create_addr_watchpoint(void *addr, size_t size, 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((void *)((unsigned long)addr & ~(phpdbg_pagesize - 1)), ((size - 1)  & ~(phpdbg_pagesize - 1)) | phpdbg_pagesize, PROT_NONE | PROT_READ);
+       m = mprotect(phpdbg_get_page_boundary(addr), phpdbg_get_total_page_size(size), PROT_NONE | PROT_READ);
 
-       printf("\n!!!!!\n%d\n!!!!!\n", m);
+       if (m == FAILURE) {
+               phpdbg_error("Unable to set watchpoint (mprotect() failed)");
+               zend_bailout();
+       }
 }
 
-void phpdbg_create_zval_watchpoint(zval *zv) {
-       phpdbg_create_addr_watchpoint(zv, sizeof(zval));
+void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch) {
+       phpdbg_create_addr_watchpoint(zv, sizeof(zval), watch);
+       watch->type = WATCH_ON_ZVAL;
 }
 
 int phpdbg_create_var_watchpoint(char *name, size_t len TSRMLS_DC) {
        zval *zv;
+       phpdbg_watchpoint_t watch;
+
 
        if (!EG(active_op_array)) {
                phpdbg_error("No active op array!");
@@ -61,7 +186,8 @@ 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);
+               phpdbg_create_zval_watchpoint(zv, &watch);
+               zend_hash_add(&PHPDBG_G(watchpoints), name, len, &watch, sizeof(phpdbg_watchpoint_t), NULL);
                return SUCCESS;
        }
 
index 3d142070b3524505b90098191a64cfc3442dc9fa..81a2f741ea68a86e5cd13536ede9893660e68430 100644 (file)
@@ -1,3 +1,23 @@
+/*
+   +----------------------------------------------------------------------+
+   | 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_WATCH_H
 #define PHPDBG_WATCH_H
 
@@ -30,14 +50,16 @@ struct _phpdbg_watchpoint_t {
                HashTable *ht;
                void *ptr;
        } addr;
-       int size;
+       size_t size;
        phpdbg_watchtype type;
 };
 
-void phpdbg_setup_watchpoints();
+void phpdbg_setup_watchpoints(TSRMLS_D);
 
 int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC);
 
 int phpdbg_create_var_watchpoint(char *name, size_t len TSRMLS_DC);
 
+int phpdbg_print_changed_zvals(TSRMLS_D);
+
 #endif