#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;
#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));
}
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;
}
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;
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)");
/* 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;
}