From: Bob Weinand Date: Sun, 15 Dec 2013 14:10:28 +0000 (-0500) Subject: Merge branch 'watchpoints' of ssh://github.com/krakjoe/phpdbg into watchpoints X-Git-Tag: php-5.6.0beta2~1^2~37^2~49 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d3c8d76e5b7cfec8f5b1727b17928518969c9da3;p=php Merge branch 'watchpoints' of ssh://github.com/krakjoe/phpdbg into watchpoints Conflicts: phpdbg_watch.c --- d3c8d76e5b7cfec8f5b1727b17928518969c9da3 diff --cc phpdbg_watch.c index 66fcb8eab7,dd4384f315..0f3e1322cf --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@@ -38,7 -37,11 +38,7 @@@ typedef struct #define MEMDUMP_SIZE(size) (sizeof(phpdbg_watch_memdump) - sizeof(void *) + (size)) - void phpdbg_watch_mem_dtor(void *llist_data) { -#define CHOOSE_BRANCH(n) \ - addr = (addr << 1) + !!(n); \ - branch = branch->branches[!!(n)]; - + static 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; @@@ -60,10 -63,9 +60,10 @@@ 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) { + static inline void *phpdbg_get_page_boundary(void *addr) { return (void *)((size_t)addr & ~(phpdbg_pagesize - 1)); } @@@ -71,11 -73,53 +71,11 @@@ static inline size_t phpdbg_get_total_p 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 *addr) { -static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *watch_addr TSRMLS_DC) { - 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; ++static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr TSRMLS_DC) { + 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; } @@@ -115,18 -159,61 +115,18 @@@ int phpdbg_watchpoint_segfault_handler( return SUCCESS; } - int phpdbg_print_changed_zval(void *llist_data) { + static 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; @@@ -158,15 -249,38 +158,15 @@@ int phpdbg_print_changed_zvals(TSRMLS_D return PHPDBG_G(watchpoint_hit)?SUCCESS:FAILURE; } - void phpdbg_store_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + static 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_activate_watchpoint (phpdbg_watchpoint_t *watch) { -static void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch TSRMLS_DC) { ++static 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)"); @@@ -207,11 -315,9 +207,11 @@@ int phpdbg_create_var_watchpoint(char * /* 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); ++ 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_create_zval_watchpoint(*zv, watch TSRMLS_CC); + + phpdbg_activate_watchpoint(watch); return SUCCESS; } diff --cc phpdbg_watch.h index 81a2f741ea,81a2f741ea..272e613ad2 --- a/phpdbg_watch.h +++ b/phpdbg_watch.h @@@ -58,6 -58,6 +58,8 @@@ void phpdbg_setup_watchpoints(TSRMLS_D) int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC); ++void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch); ++void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch); int phpdbg_create_var_watchpoint(char *name, size_t len TSRMLS_DC); int phpdbg_print_changed_zvals(TSRMLS_D);