From 85b97c0f7053df210bfb358fdd3643cf5ebf453c Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Fri, 13 Dec 2013 17:57:36 -0500 Subject: [PATCH] Finished working for today, continuing tomorrow (not working) --- phpdbg.c | 2 +- phpdbg.h | 1 + phpdbg_prompt.c | 7 +++ phpdbg_watch.c | 148 ++++++++++++++++++++++++++++++++++++++++++++---- phpdbg_watch.h | 26 ++++++++- 5 files changed, 170 insertions(+), 14 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index d72133b218..147a66e55a 100644 --- 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); diff --git a/phpdbg.h b/phpdbg.h index 906b894f26..f11176325b 100644 --- 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 */ diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 07b9f1400e..626177fa4e 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -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; diff --git a/phpdbg_watch.c b/phpdbg_watch.c index e54431f3e0..66721ee8e6 100644 --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@ -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 | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + #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; } diff --git a/phpdbg_watch.h b/phpdbg_watch.h index 3d142070b3..81a2f741ea 100644 --- a/phpdbg_watch.h +++ b/phpdbg_watch.h @@ -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 | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + #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 -- 2.50.1