]> granicus.if.org Git - php/commitdiff
Merge branch 'watchpoints' of ssh://github.com/krakjoe/phpdbg into watchpoints
authorBob Weinand <bobwei9@hotmail.com>
Sun, 15 Dec 2013 14:10:28 +0000 (09:10 -0500)
committerBob Weinand <bobwei9@hotmail.com>
Sun, 15 Dec 2013 14:10:28 +0000 (09:10 -0500)
Conflicts:
phpdbg_watch.c

1  2 
phpdbg_watch.c
phpdbg_watch.h

diff --cc phpdbg_watch.c
index 66fcb8eab75b4679906fa17cd9544f408dac4056,dd4384f315e2dc7d0c7e8d9917be4933b4701d9b..0f3e1322cfffe74d65558bcb4f7ca7c1ab6ad43c
@@@ -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 81a2f741ea68a86e5cd13536ede9893660e68430,81a2f741ea68a86e5cd13536ede9893660e68430..272e613ad256df1135f85b8a88a39886e4a7cb2e
@@@ -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);