]> granicus.if.org Git - php/commitdiff
Adapted opline_num breakpoints to master branch
authorBob Weinand <bobwei9@hotmail.com>
Sat, 7 Dec 2013 14:35:35 +0000 (15:35 +0100)
committerBob Weinand <bobwei9@hotmail.com>
Sat, 7 Dec 2013 14:35:35 +0000 (15:35 +0100)
1  2 
phpdbg.c
phpdbg.h
phpdbg_bp.c
phpdbg_bp.h
phpdbg_break.c
phpdbg_cmd.c
phpdbg_cmd.h
phpdbg_help.c
phpdbg_info.c
phpdbg_prompt.c
phpdbg_utils.c

diff --cc phpdbg.c
index ce7a0b3184aba4686eb74511a3a012df4f1eb411,32cc0769f9d7cd8db9ba6878ea66fe7203a2cdbc..93c2925b07bec769db50b3800d23d2215b3f8e85
+++ b/phpdbg.c
@@@ -753,21 -960,56 +1000,57 @@@ phpdbg_main
                memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
        }
        ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
+       
+       if (zend_extensions_len) {
+               zend_ulong zend_extension = 0L;
+               
+               while (zend_extension < zend_extensions_len) {
+                       const char *ze = zend_extensions[zend_extension];
+                       size_t ze_len = strlen(ze);
+                       
+                       ini_entries = realloc(
+                               ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
+                       memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
+                       ini_entries_len += (sizeof("zend_extension=")-1);
+                       memcpy(&ini_entries[ini_entries_len], ze, ze_len);
+                       ini_entries_len += ze_len;
+                       memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
+                       
+                       free(zend_extensions[zend_extension]);
+                       zend_extension++;
+               }
+               
+               free(zend_extensions);
+       }
  
        phpdbg->ini_entries = ini_entries;
+               
        if (phpdbg->startup(phpdbg) == SUCCESS) {
 -      
 +              zend_register_extension(&zend_extension_entry, NULL);
 +
                zend_activate(TSRMLS_C);
+               
+               /* do not install sigint handlers for remote consoles */
+               /* sending SIGINT then provides a decent way of shutting down the server */
  #ifdef ZEND_SIGNALS
-               zend_try {
-                       zend_signal_activate(TSRMLS_C);
-                       zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC);
-               } zend_end_try();
+ # ifndef _WIN32
+               if (listen[0] < 0) {
+ # endif
+                       zend_try {
+                               zend_signal_activate(TSRMLS_C);
+                               zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC);
+                       } zend_end_try();
+ # ifndef _WIN32
+               }
+ # endif
  #else
-               signal(SIGINT, phpdbg_sigint_handler);
+ # ifndef _WIN32
+               if (listen[0] < 0) {
+ # endif
+                       signal(SIGINT, phpdbg_sigint_handler);
+ #ifndef _WIN32
+               }
+ #endif
  #endif
  
                PG(modules_activated) = 0;
diff --cc phpdbg.h
index 238caa8d4eb942544d209612395873a8648fa5a3,0102892f790a989dfb8ee488d694c9333e5a5ef7..233f68c035bf38f3dbe79ebe4334484a5456bd36
+++ b/phpdbg.h
  #define PHPDBG_FINISH 4
  #define PHPDBG_LEAVE  5
  
+ /*
+  BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
+ */
  /* {{{ tables */
 -#define PHPDBG_BREAK_FILE       0
 -#define PHPDBG_BREAK_SYM        1
 -#define PHPDBG_BREAK_OPLINE     2
 -#define PHPDBG_BREAK_METHOD     3
 -#define PHPDBG_BREAK_COND       4
 -#define PHPDBG_BREAK_OPCODE     5
 -#define PHPDBG_BREAK_MAP              6
 -#define PHPDBG_BREAK_TABLES     7 /* }}} */
 +#define PHPDBG_BREAK_FILE            0
 +#define PHPDBG_BREAK_SYM             1
 +#define PHPDBG_BREAK_OPLINE          2
 +#define PHPDBG_BREAK_METHOD          3
 +#define PHPDBG_BREAK_COND            4
 +#define PHPDBG_BREAK_OPCODE          5
 +#define PHPDBG_BREAK_FUNCTION_OPLINE 6
 +#define PHPDBG_BREAK_METHOD_OPLINE   7
 +#define PHPDBG_BREAK_FILE_OPLINE     8
- #define PHPDBG_BREAK_TABLES          9 /* }}} */
++#define PHPDBG_BREAK_MAP             9
++#define PHPDBG_BREAK_TABLES          10 /* }}} */
  
  /* {{{ flags */
 -#define PHPDBG_HAS_FILE_BP      (1<<1)
 -#define PHPDBG_HAS_SYM_BP       (1<<2)
 -#define PHPDBG_HAS_OPLINE_BP    (1<<3)
 -#define PHPDBG_HAS_METHOD_BP    (1<<4)
 -#define PHPDBG_HAS_COND_BP      (1<<5)
 -#define PHPDBG_HAS_OPCODE_BP    (1<<6)
 -#define PHPDBG_BP_MASK          (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP)
 +#define PHPDBG_HAS_FILE_BP            (1<<1)
 +#define PHPDBG_HAS_SYM_BP             (1<<2)
 +#define PHPDBG_HAS_OPLINE_BP          (1<<3)
 +#define PHPDBG_HAS_METHOD_BP          (1<<4)
 +#define PHPDBG_HAS_COND_BP            (1<<5)
 +#define PHPDBG_HAS_OPCODE_BP          (1<<6)
 +#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1<<7)
 +#define PHPDBG_HAS_METHOD_OPLINE_BP   (1<<8)
 +#define PHPDBG_HAS_FILE_OPLINE_BP     (1<<9)
 +#define PHPDBG_BP_MASK                (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP|PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
  
 -#define PHPDBG_IN_COND_BP       (1<<7)
 -#define PHPDBG_IN_EVAL          (1<<8)
 -
 -#define PHPDBG_IS_STEPPING      (1<<9)
 -#define PHPDBG_IS_QUIET         (1<<10)
 -#define PHPDBG_IS_QUITTING      (1<<11)
 -#define PHPDBG_IS_COLOURED      (1<<12)
 -#define PHPDBG_IS_CLEANING      (1<<13)
 -
 -#define PHPDBG_IN_UNTIL         (1<<14)
 -#define PHPDBG_IN_FINISH        (1<<15)
 -#define PHPDBG_IN_LEAVE         (1<<16)
 -#define PHPDBG_SEEK_MASK        (PHPDBG_IN_UNTIL|PHPDBG_IN_FINISH|PHPDBG_IN_LEAVE)
 -
 -#define PHPDBG_IS_REGISTERED    (1<<17)
 -#define PHPDBG_IS_STEPONEVAL    (1<<18)
 -#define PHPDBG_IS_INITIALIZING  (1<<19)
 -#define PHPDBG_IS_SIGNALED      (1<<20)
 -#define PHPDBG_IS_INTERACTIVE   (1<<21)
 -#define PHPDBG_IS_BP_ENABLED    (1<<22)
 -#define PHPDBG_IS_REMOTE              (1<<23)
 -#define PHPDBG_IS_DISCONNECTED        (1<<24)
+ /*
+  END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
+ */
 +#define PHPDBG_IN_COND_BP             (1<<8)
 +#define PHPDBG_IN_EVAL                (1<<9)
 +
 +#define PHPDBG_IS_STEPPING            (1<<10)
 +#define PHPDBG_IS_QUIET               (1<<11)
 +#define PHPDBG_IS_QUITTING            (1<<12)
 +#define PHPDBG_IS_COLOURED            (1<<13)
 +#define PHPDBG_IS_CLEANING            (1<<14)
 +
 +#define PHPDBG_IN_UNTIL               (1<<15)
 +#define PHPDBG_IN_FINISH              (1<<16)
 +#define PHPDBG_IN_LEAVE               (1<<17)
 +#define PHPDBG_SEEK_MASK              (PHPDBG_IN_UNTIL|PHPDBG_IN_FINISH|PHPDBG_IN_LEAVE)
 +
 +#define PHPDBG_IS_REGISTERED          (1<<18)
 +#define PHPDBG_IS_STEPONEVAL          (1<<19)
 +#define PHPDBG_IS_INITIALIZING        (1<<20)
 +#define PHPDBG_IS_SIGNALED            (1<<21)
 +#define PHPDBG_IS_INTERACTIVE         (1<<22)
 +#define PHPDBG_IS_BP_ENABLED          (1<<23)
++#define PHPDBG_IS_REMOTE              (1<<24)
++#define PHPDBG_IS_DISCONNECTED        (1<<25)
  
  #ifndef _WIN32
  #     define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED)
  #endif /* }}} */
  
  /* {{{ strings */
 +#define PHPDBG_NAME "phpdbg"
 +#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
 +#define PHPDBG_URL "http://phpdbg.com"
  #define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
- #define PHPDBG_VERSION "0.2.0-dev"
+ #define PHPDBG_VERSION "0.3.0-dev"
  #define PHPDBG_INIT_FILENAME ".phpdbginit"
  /* }}} */
  
diff --cc phpdbg_bp.c
index 4f6b79ecf7110696c775b19f0348638bb1dc2072,bf6ef821c572eb314b173a69ae1022a80398926a..a84be3e378ac9724e573ac6d25b55bc72a48200a
@@@ -44,122 -72,107 +72,146 @@@ static void phpdbg_class_breaks_dtor(vo
        efree((char*)bp->func_name);
  } /* }}} */
  
- PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
 +static void phpdbg_opline_class_breaks_dtor(void *data) /* {{{ */
 +{
 +      zend_hash_destroy((HashTable *)data);
 +} /* }}} */
 +
 +static void phpdbg_opline_breaks_dtor(void *data) /* {{{ */
 +{
 +      phpdbg_breakopline_t *bp = (phpdbg_breakopline_t *) data;
 +
 +      if (bp->class_name) {
 +              efree((char*)bp->class_name);
 +      }
 +      if (bp->func_name) {
 +              efree((char*)bp->func_name);
 +      }
 +} /* }}} */
 +
+ PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */
  {
-       HashPosition position;
-       HashTable *table = NULL;
-       if (PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP) {
-               zend_llist *brakes;
-               table = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE];
-               for (zend_hash_internal_pointer_reset_ex(table, &position);
-                       zend_hash_get_current_data_ex(table, (void*) &brakes, &position) == SUCCESS;
-                       zend_hash_move_forward_ex(table, &position)) {
-                       zend_llist_position lposition;
-                       phpdbg_breakfile_t *brake;
-                       int count = zend_llist_count(brakes);
+       if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) {
+               HashPosition position[2];
+               HashTable **table = NULL;
  
-                       if ((brake = zend_llist_get_first_ex(brakes, &lposition))) {
-                               phpdbg_notice(
-                                       "Exporting file breakpoints in %s (%d)", brake->filename, count);
+               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]);
+                       zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS;
+                       zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) {
+                       phpdbg_breakbase_t *brake;
  
-                               do {
-                                       fprintf(handle, "break file %s:%lu\n", brake->filename, brake->line);
-                               } while ((brake = zend_llist_get_next_ex(brakes, &lposition)));
+                       for (zend_hash_internal_pointer_reset_ex((*table), &position[1]);
+                               zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS;
+                               zend_hash_move_forward_ex((*table), &position[1])) {
+                               brake->hits = 0;
                        }
                }
        }
+ } /* }}} */
  
-       if (PHPDBG_G(flags) & PHPDBG_HAS_SYM_BP) {
-               phpdbg_breaksymbol_t *brake;
-               table = &PHPDBG_G(bp)[PHPDBG_BREAK_SYM];
-               phpdbg_notice("Exporting symbol breakpoints (%d)", zend_hash_num_elements(table));
-               for (zend_hash_internal_pointer_reset_ex(table, &position);
-                       zend_hash_get_current_data_ex(table, (void*) &brake, &position) == SUCCESS;
-                       zend_hash_move_forward_ex(table, &position)) {
-                       fprintf(
-                               handle, "break %s\n", brake->symbol);
-               }
-       }
-       if (PHPDBG_G(flags) & PHPDBG_HAS_METHOD_BP) {
-               HashTable *class;
-               phpdbg_breakmethod_t *brake;
-               HashPosition mposition;
-               zend_bool noted = 0;
-               table = &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD];
-               for (zend_hash_internal_pointer_reset_ex(table, &position);
-                       zend_hash_get_current_data_ex(table, (void**) &class, &position) == SUCCESS;
-                       zend_hash_move_forward_ex(table, &position)) {
-                       noted = 0;
-                       for (zend_hash_internal_pointer_reset_ex(class, &mposition);
-                               zend_hash_get_current_data_ex(class, (void**) &brake, &mposition) == SUCCESS;
-                               zend_hash_move_forward_ex(class, &mposition)) {
-                               if (!noted) {
-                                       phpdbg_notice(
-                                               "Exporting method breakpoints in %s (%d)",
-                                               brake->class_name, zend_hash_num_elements(class));
-                                       noted = 1;
-                               }
-                               fprintf(handle, "break %s::%s\n", brake->class_name, brake->func_name);
-                       }
-               }
-       }
+ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
+ {
+       HashPosition position[2];
+       HashTable **table = NULL;
+       zend_ulong id = 0L;
  
-       if (PHPDBG_G(flags) & PHPDBG_HAS_METHOD_OPLINE_BP) {
-               HashTable *class, *method;
-               phpdbg_breakopline_t *brake;
-               HashPosition mposition[2];
-               zend_bool noted = 0;
-               table = &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE];
-               for (zend_hash_internal_pointer_reset_ex(table, &position);
-                    zend_hash_get_current_data_ex(table, (void**) &class, &position) == SUCCESS;
-                    zend_hash_move_forward_ex(table, &position)) {
-                       for (zend_hash_internal_pointer_reset_ex(class, &mposition[0]);
-                            zend_hash_get_current_data_ex(class, (void**) &method, &mposition[0]) == SUCCESS;
-                            zend_hash_move_forward_ex(class, &mposition[0])) {
-                               noted = 0;
-                               for (zend_hash_internal_pointer_reset_ex(method, &mposition[1]);
-                                    zend_hash_get_current_data_ex(method, (void**) &brake, &mposition[1]) == SUCCESS;
-                                    zend_hash_move_forward_ex(method, &mposition[1])) {
-                                       if (!noted) {
-                                               phpdbg_notice(
-                                                       "Exporting method opline breakpoints in %s::%s (%d)",
-                                                       brake->class_name, brake->func_name, zend_hash_num_elements(method));
-                                               noted = 1;
+       if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) {
+               phpdbg_notice(
+                       "Exporting %d breakpoints",
+                       zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]));
+               /* this only looks like magic, it isn't */
+               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]);
+                       zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS;
+                       zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) {
+                       phpdbg_breakbase_t *brake;
+                       zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], NULL, NULL, &id, 0, &position[0]);
+                       for (zend_hash_internal_pointer_reset_ex((*table), &position[1]);
+                               zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS;
+                               zend_hash_move_forward_ex((*table), &position[1])) {
+                               if (brake->id == id) {
+                                       switch (brake->type) {
+                                               case PHPDBG_BREAK_FILE: {
+                                                       fprintf(handle,
+                                                               "break file %s:%lu\n",
+                                                               ((phpdbg_breakfile_t*)brake)->filename,
+                                                               ((phpdbg_breakfile_t*)brake)->line);
+                                               } break;
+                                               case PHPDBG_BREAK_SYM: {
+                                                       fprintf(handle,
+                                                               "break func %s\n",
+                                                               ((phpdbg_breaksymbol_t*)brake)->symbol);
+                                               } break;
+                                               case PHPDBG_BREAK_METHOD: {
+                                                       fprintf(handle,
+                                                               "break method %s::%s\n",
+                                                               ((phpdbg_breakmethod_t*)brake)->class_name,
+                                                               ((phpdbg_breakmethod_t*)brake)->func_name);
+                                               } break;
++                                              case PHPDBG_BREAK_METHOD_OPLINE: {
++                                                      fprintf(handle,
++                                                              "break address %s::%s#%ld\n",
++                                                              ((phpdbg_breakopline_t*)brake)->class_name,
++                                                              ((phpdbg_breakopline_t*)brake)->func_name,
++                                                              ((phpdbg_breakopline_t*)brake)->opline_num);
++                                              } break;
++
++                                              case PHPDBG_BREAK_FUNCTION_OPLINE: {
++                                                      fprintf(handle,
++                                                              "break address %s#%ld\n",
++                                                              ((phpdbg_breakopline_t*)brake)->func_name,
++                                                              ((phpdbg_breakopline_t*)brake)->opline_num);
++                                              } break;
++
++                                              case PHPDBG_BREAK_FILE_OPLINE: {
++                                                      fprintf(handle,
++                                                              "break address %s:%ld\n",
++                                                              ((phpdbg_breakopline_t*)brake)->class_name,
++                                                              ((phpdbg_breakopline_t*)brake)->opline_num);
++                                              } break;
++
+                                               case PHPDBG_BREAK_OPCODE: {
+                                                       fprintf(handle,
+                                                               "break op %s\n",
+                                                               ((phpdbg_breakop_t*)brake)->name);
+                                               } break;
+                                               case PHPDBG_BREAK_COND: {
+                                                       phpdbg_breakcond_t *conditional = (phpdbg_breakcond_t*) brake;
+                                                       
+                                                       if (conditional->paramed) {
+                                                               switch (conditional->param.type) {
+                                                                       case STR_PARAM:
+                                                                               fprintf(handle, 
+                                                                                       "break at %s if %s\n", conditional->param.str, conditional->code);
+                                                                       break;
+                                                                       
+                                                                       case METHOD_PARAM:
+                                                                               fprintf(handle, 
+                                                                                       "break at %s::%s if %s\n", 
+                                                                                       conditional->param.method.class, conditional->param.method.name,
+                                                                                       conditional->code);
+                                                                       break;
+                                                                       
+                                                                       case FILE_PARAM:
+                                                                               fprintf(handle, 
+                                                                                       "break at %s:%lu if %s\n", 
+                                                                                       conditional->param.file.name, conditional->param.file.line,
+                                                                                       conditional->code);
+                                                                       break;
+                                                                       
+                                                                       default: { /* do nothing */ } break;
+                                                               }
+                                                       } else {
+                                                               fprintf(
+                                                                       handle, "break on %s\n", conditional->code);
+                                                       }
+                                               } break;
                                        }
-                                       fprintf(handle, "break %s::%s#%d\n", brake->class_name, brake->func_name, brake->opline);
                                }
                        }
                }
@@@ -314,12 -248,12 +287,12 @@@ PHPDBG_API void phpdbg_set_breakpoint_s
        }
  } /* }}} */
  
- PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name TSRMLS_DC) /* {{{ */
+ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char *func_name TSRMLS_DC) /* {{{ */
  {
        HashTable class_breaks, *class_table;
--    size_t class_len = strlen(class_name);
--    size_t func_len = strlen(func_name);
-     char *lcname = zend_str_tolower_dup(func_name, func_len); 
 -    char *lcname = zend_str_tolower_dup(func_name, func_len);
++      size_t class_len = strlen(class_name);
++      size_t func_len = strlen(func_name);
++      char *lcname = zend_str_tolower_dup(func_name, func_len);
  
        if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name,
                class_len, (void**)&class_table) != SUCCESS) {
@@@ -360,10 -296,9 +335,10 @@@ PHPDBG_API void phpdbg_set_breakpoint_o
  
                PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
  
+               PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE);
                new_break.name = NULL;
                new_break.opline = opline;
-               new_break.id = PHPDBG_G(bp_count)++;
-               new_break.type = 0; /* no special type */
++              new_break.base = NULL;
  
                zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline,
                        &new_break, sizeof(phpdbg_breakline_t), NULL);
        }
  } /* }}} */
  
-       if (op_array->last < brake->opline) {
 +PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC) {
 +      phpdbg_breakline_t opline_break;
-                       phpdbg_error("There are only %d oplines in function %s (breaking at opline %d impossible)", op_array->last, brake->func_name, brake->opline);
++      if (op_array->last < brake->opline_num) {
 +              if (brake->class_name == NULL) {
-                       phpdbg_error("There are only %d oplines in file %s (breaking at opline %d impossible)", op_array->last, brake->class_name, brake->opline);
++                      phpdbg_error("There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num);
 +              } else if (brake->func_name == NULL) {
-                       phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %d impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline);
++                      phpdbg_error("There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num);
 +              } else {
-       opline_break.opline = (zend_ulong)(op_array->opcodes + brake->opline);
++                      phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num);
 +              }
 +
 +              return FAILURE;
 +      }
 +
++      opline_break.disabled = 0;
++      opline_break.hits = 0;
 +      opline_break.id = brake->id;
-                       phpdbg_notice("Breakpoint #%d resolved at %s%s%s#%d (opline %#lx)", brake->id, brake->class_name?brake->class_name:"", brake->class_name&&brake->func_name?"::":"", brake->func_name?brake->func_name:"", brake->opline, opline_break->opline);
++      opline_break.opline = brake->opline = (zend_ulong)(op_array->opcodes + brake->opline_num);
 +      opline_break.name = NULL;
++      opline_break.base = brake;
 +      if (op_array->scope) {
 +              opline_break.type = PHPDBG_BREAK_METHOD_OPLINE;
 +      } else if (op_array->function_name) {
 +              opline_break.type = PHPDBG_BREAK_FUNCTION_OPLINE;
 +      } else {
 +              opline_break.type = PHPDBG_BREAK_FILE_OPLINE;
 +      }
 +
 +      PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
 +
 +      zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline_break.opline, &opline_break, sizeof(phpdbg_breakline_t), NULL);
 +
 +      return SUCCESS;
 +}
 +
 +PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC) {
 +      HashTable *func_table = &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE];
 +      HashTable *oplines_table;
 +      HashPosition position;
 +      phpdbg_breakopline_t *brake;
 +
 +      if (op_array->scope != NULL &&
 +          zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], op_array->scope->name, op_array->scope->name_length, (void **)&func_table) == FAILURE) {
 +              return;
 +      }
 +
 +      if (op_array->function_name == NULL) {
 +              if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], op_array->filename, strlen(op_array->filename), (void **)&oplines_table) == FAILURE) {
 +                      return;
 +              }
 +      } else if (zend_hash_find(func_table, op_array->function_name?op_array->function_name:"", op_array->function_name?strlen(op_array->function_name):0, (void **)&oplines_table) == FAILURE) {
 +              return;
 +      }
 +
 +      for (zend_hash_internal_pointer_reset_ex(oplines_table, &position);
 +           zend_hash_get_current_data_ex(oplines_table, (void**) &brake, &position) == SUCCESS;
 +           zend_hash_move_forward_ex(oplines_table, &position)) {
 +              if (phpdbg_resolve_op_array_break(brake, op_array TSRMLS_CC) == SUCCESS) {
 +                      phpdbg_breakline_t *opline_break;
 +
 +                      zend_hash_internal_pointer_end(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 +                      zend_hash_get_current_data(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void **)&opline_break);
 +
-               if (zend_hash_find(EG(class_table), new_break->class_name, new_break->class_len + 1, (void **)&ce) == FAILURE) {
++                      phpdbg_notice("Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)",
++                              brake->id,
++                              brake->class_name?brake->class_name:"",
++                              brake->class_name&&brake->func_name?"::":"",
++                              brake->func_name?brake->func_name:"",
++                              brake->opline_num,
++                              brake->opline);
 +              }
 +      }
 +}
 +
 +PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC) {
 +      HashTable *func_table = EG(function_table);
 +      zend_function *func;
 +
 +      if (new_break->func_name == NULL) {
 +              if (EG(current_execute_data) == NULL) {
 +                      if (PHPDBG_G(ops) != NULL && !memcmp(PHPDBG_G(ops)->filename, new_break->class_name, new_break->class_len)) {
 +                              if (phpdbg_resolve_op_array_break(new_break, PHPDBG_G(ops) TSRMLS_CC) == SUCCESS) {
 +                                      return SUCCESS;
 +                              } else {
 +                                      return 2;
 +                              }
 +                      }
 +                      return FAILURE;
 +              } else {
 +                      zend_execute_data *execute_data = EG(current_execute_data);
 +                      do {
 +                              if (execute_data->op_array->function_name == NULL && execute_data->op_array->scope == NULL && !memcmp(execute_data->op_array->filename, new_break->class_name, new_break->class_len)) {
 +                                      if (phpdbg_resolve_op_array_break(new_break, execute_data->op_array TSRMLS_CC) == SUCCESS) {
 +                                              return SUCCESS;
 +                                      } else {
 +                                              return 2;
 +                                      }
 +                              }
 +                      } while ((execute_data = execute_data->prev_execute_data) != NULL);
 +                      return FAILURE;
 +              }
 +      }
 +
 +      if (new_break->class_name != NULL) {
 +              zend_class_entry **ce;
-       if (zend_hash_find(func_table, new_break->func_name, new_break->func_len + 1, (void **)&func) == FAILURE) {
++              if (zend_hash_find(EG(class_table), zend_str_tolower_dup(new_break->class_name, new_break->class_len), new_break->class_len + 1, (void **)&ce) == FAILURE) {
 +                      return FAILURE;
 +              }
 +              func_table = &(*ce)->function_table;
 +      }
 +
- PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, int opline TSRMLS_DC) /* {{{ */
++      if (zend_hash_find(func_table, zend_str_tolower_dup(new_break->func_name, new_break->func_len), new_break->func_len + 1, (void **)&func) == FAILURE) {
 +              if (new_break->class_name != NULL && new_break->func_name != NULL) {
 +                      phpdbg_error("Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name);
++                      return 2;
 +              }
 +              return FAILURE;
 +      }
 +
 +      if (func->type != ZEND_USER_FUNCTION) {
 +              if (new_break->class_name == NULL) {
 +                      phpdbg_error("%s is not an user defined function, no oplines exist", new_break->func_name);
 +              } else {
 +                      phpdbg_error("%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name);
 +              }
 +              return 2;
 +      }
 +
 +      if (phpdbg_resolve_op_array_break(new_break, &func->op_array TSRMLS_CC) == FAILURE) {
 +              return 2;
 +      }
 +
 +      return SUCCESS;
 +}
 +
-       new_break.opline = opline;
-       new_break.id = PHPDBG_G(bp_count)++;
++PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC) /* {{{ */
 +{
 +      phpdbg_breakopline_t new_break;
 +      HashTable class_breaks, *class_table;
 +      HashTable method_breaks, *method_table;
 +
++      PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_METHOD_OPLINE);
 +      new_break.func_len = strlen(method);
 +      new_break.func_name = estrndup(method, new_break.func_len);
 +      new_break.class_len = strlen(class);
 +      new_break.class_name = estrndup(class, new_break.class_len);
-                       phpdbg_notice("Pending breakpoint #%d at %s::%s#%d", new_break.id, new_break.class_name, new_break.func_name, opline);
++      new_break.opline_num = opline;
++      new_break.opline = 0;
 +
 +      switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
 +              case FAILURE:
-                       phpdbg_notice("Breakpoint #%d added at %s::%s#%d", new_break.id, new_break.class_name, new_break.func_name, opline);
++                      phpdbg_notice("Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline);
 +                      break;
 +
 +              case SUCCESS:
-               phpdbg_notice("Breakpoint already exists for %s::%s#%d", new_break.class_name, new_break.func_name, opline);
++                      phpdbg_notice("Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline);
 +                      break;
 +
 +              case 2:
 +                      return;
 +      }
 +
 +      if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len, (void **)&class_table) == FAILURE) {
 +              zend_hash_init(&class_breaks, 8, NULL, phpdbg_opline_class_breaks_dtor, 0);
 +              zend_hash_update(
 +                      &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
 +                      new_break.class_name,
 +                      new_break.class_len,
 +                      (void **)&class_breaks, sizeof(HashTable), (void **)&class_table);
 +      }
 +
 +      if (zend_hash_find(class_table, new_break.func_name, new_break.func_len, (void **)&method_table) == FAILURE) {
 +              zend_hash_init(&method_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
 +              zend_hash_update(
 +                      class_table,
 +                      new_break.func_name,
 +                      new_break.func_len,
 +                      (void **)&method_breaks, sizeof(HashTable), (void **)&method_table);
 +      }
 +
 +      if (zend_hash_index_exists(method_table, opline)) {
-       zend_hash_index_update(method_table, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
++              phpdbg_notice("Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline);
 +              efree(new_break.func_name);
 +              efree(new_break.class_name);
 +              PHPDBG_G(bp_count)--;
 +              return;
 +      }
 +
 +      PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_OPLINE_BP;
 +
- PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, int opline TSRMLS_DC) /* {{{ */
++      zend_hash_index_update(method_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
 +}
 +
-       new_break.opline = opline;
-       new_break.id = PHPDBG_G(bp_count)++;
++PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC) /* {{{ */
 +{
 +      phpdbg_breakopline_t new_break;
 +      HashTable func_breaks, *func_table;
 +
++      PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FUNCTION_OPLINE);
 +      new_break.func_len = strlen(function);
 +      new_break.func_name = estrndup(function, new_break.func_len);
 +      new_break.class_len = 0;
 +      new_break.class_name = NULL;
-                       phpdbg_notice("Pending breakpoint #%d at %s#%d", new_break.id, new_break.func_name, new_break.opline);
++      new_break.opline_num = opline;
++      new_break.opline = 0;
 +
 +      switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
 +              case FAILURE:
-                       phpdbg_notice("Breakpoint #%d added at %s#%d", new_break.id, new_break.func_name, new_break.opline);
++                      phpdbg_notice("Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline);
 +                      break;
 +
 +              case SUCCESS:
-               phpdbg_notice("Breakpoint already exists for %s#%d", new_break.func_name, opline);
++                      phpdbg_notice("Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline);
 +                      break;
 +
 +              case 2:
 +                      return;
 +      }
 +
 +      if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len, (void **)&func_table) == FAILURE) {
 +              zend_hash_init(&func_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
 +              zend_hash_update(
 +                      &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE],
 +                      new_break.func_name,
 +                      new_break.func_len,
 +                      (void **)&func_breaks, sizeof(HashTable), (void **)&func_table);
 +      }
 +
 +      if (zend_hash_index_exists(func_table, opline)) {
-       zend_hash_index_update(func_table, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
++              phpdbg_notice("Breakpoint already exists for %s#%ld", new_break.func_name, opline);
 +              efree(new_break.func_name);
 +              PHPDBG_G(bp_count)--;
 +              return;
 +      }
 +
 +      PHPDBG_G(flags) |= PHPDBG_HAS_FUNCTION_OPLINE_BP;
 +
- PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, int opline TSRMLS_DC) /* {{{ */
++      zend_hash_index_update(func_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
 +}
 +
-       new_break.opline = opline;
-       new_break.id = PHPDBG_G(bp_count)++;
++PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC) /* {{{ */
 +{
 +      phpdbg_breakopline_t new_break;
 +      HashTable file_breaks, *file_table;
 +
++      PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE_OPLINE);
 +      new_break.func_len = 0;
 +      new_break.func_name = NULL;
 +      new_break.class_len = strlen(file);
 +      new_break.class_name = estrndup(file, new_break.class_len);
-                       phpdbg_notice("Pending breakpoint #%d at %s:%d", new_break.id, new_break.class_name, new_break.opline);
++      new_break.opline_num = opline;
++      new_break.opline = 0;
 +
 +      switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
 +              case FAILURE:
-                       phpdbg_notice("Breakpoint #%d added at %s:%d", new_break.id, new_break.class_name, new_break.opline);
++                      phpdbg_notice("Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline);
 +                      break;
 +
 +              case SUCCESS:
-               phpdbg_notice("Breakpoint already exists for %s:%d", new_break.class_name, opline);
++                      phpdbg_notice("Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline);
 +                      break;
 +
 +              case 2:
 +                      return;
 +      }
 +
 +      if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], new_break.class_name, new_break.class_len, (void **)&file_table) == FAILURE) {
 +              zend_hash_init(&file_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
 +              zend_hash_update(
 +                      &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE],
 +                      new_break.class_name,
 +                      new_break.class_len,
 +                      (void **)&file_breaks, sizeof(HashTable), (void **)&file_table);
 +      }
 +
 +      if (zend_hash_index_exists(file_table, opline)) {
-       zend_hash_index_update(file_table, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
++              phpdbg_notice("Breakpoint already exists for %s:%ld", new_break.class_name, opline);
 +              efree(new_break.class_name);
 +              PHPDBG_G(bp_count)--;
 +              return;
 +      }
 +
 +      PHPDBG_G(flags) |= PHPDBG_HAS_FILE_OPLINE_BP;
 +
++      zend_hash_index_update(file_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
 +}
 +
  PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len TSRMLS_DC) /* {{{ */
  {
        phpdbg_breakop_t new_break;
@@@ -825,29 -544,24 +871,24 @@@ static inline phpdbg_breakbase_t *phpdb
                efree(lcname);
        }
  
-       return FAILURE;
+       return NULL;
  } /* }}} */
  
int phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */
static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */
  {
-       phpdbg_breakline_t *bp;
 -      phpdbg_breakbase_t *brake;
++      phpdbg_breakline_t *brake;
  
        if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE],
-               (zend_ulong) opline, (void**)&bp) == SUCCESS) {
-               phpdbg_notice("Breakpoint #%d in %#lx at %s:%u",
-                       bp->id, bp->opline,
-                       zend_get_executed_filename(TSRMLS_C),
-                       zend_get_executed_lineno(TSRMLS_C));
-               return SUCCESS;
+               (zend_ulong) opline, (void**)&brake) == SUCCESS) {
 -              return brake;
++              return (brake->base?(phpdbg_breakbase_t *)brake->base:(phpdbg_breakbase_t *)brake);
        }
  
-       return FAILURE;
+       return NULL;
  } /* }}} */
  
int phpdbg_find_breakpoint_opcode(zend_uchar opcode TSRMLS_DC) /* {{{ */
static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode TSRMLS_DC) /* {{{ */
  {
-       phpdbg_breakop_t *bp;
+       phpdbg_breakbase_t *brake;
        const char *opname = phpdbg_decode_opcode(opcode);
  
        if (memcmp(opname, PHPDBG_STRL("UNKNOWN")) == 0) {
        }
  
        if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE],
-               zend_hash_func(opname, strlen(opname)), (void**)&bp) == SUCCESS) {
-               phpdbg_notice("Breakpoint #%d in %s at %s:%u",
-                       bp->id,
-                       opname,
-                       zend_get_executed_filename(TSRMLS_C),
-                       zend_get_executed_lineno(TSRMLS_C));
-               return SUCCESS;
+               zend_hash_func(opname, strlen(opname)), (void**)&brake) == SUCCESS) {
+               return brake;
+       }
+       return NULL;
+ } /* }}} */
+ static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
+ {
+       zend_function *function = (zend_function*) execute_data->function_state.function;
+        
+       switch (param->type) {
+               case STR_PARAM: {
+                       /* function breakpoint */
+                       
+                       if (function->type != ZEND_USER_FUNCTION) {
+                               return 0;
+                       }
+                       
+                       {
+                               const char *str = NULL;
+                               size_t len = 0L;
+                               zend_op_array *ops  = (zend_op_array*)function;
+                               str = ops->function_name ? ops->function_name : "main";
+                               len = strlen(str);
+                               
+                               if (len == param->len) {
+                                       return (memcmp(param->str, str, len) == SUCCESS);
+                               }
+                       }
+               } break;
+               
+               case FILE_PARAM: {
 -                      if ((param->file.line == zend_get_executed_lineno(TSRMLS_C))) {
++                      if (param->file.line == zend_get_executed_lineno(TSRMLS_C)) {
+                               const char *str = zend_get_executed_filename(TSRMLS_C);
+                               size_t lengths[2] = {strlen(param->file.name), strlen(str)};
+                               
+                               if (lengths[0] == lengths[1]) {
+                                       return (memcmp(
+                                               param->file.name, str, lengths[0]) == SUCCESS);
+                               }
+                       }
+               } break;
+               
+               case METHOD_PARAM: {
+                       if (function->type != ZEND_USER_FUNCTION) {
+                               return 0;
+                       }
+                       
+                       {
+                               zend_op_array *ops = (zend_op_array*) function;
+                               
+                               if (ops->scope) {
+                                       size_t lengths[2] = {
+                                               strlen(param->method.class), ops->scope->name_length};
+                                       if (lengths[0] == lengths[1]) {
+                                               if (memcmp(param->method.class, 
+                                                       ops->scope->name, lengths[0]) == SUCCESS) {
+                                                       lengths[0] = strlen(param->method.name);
+                                                       lengths[1] = strlen(ops->function_name);
+                                                       
+                                                       if (lengths[0] == lengths[1]) {
+                                                               return (memcmp(param->method.name, 
+                                                                       ops->function_name, lengths[0]) == SUCCESS);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               } break;
+               
+               case ADDR_PARAM: {
 -                      return ((phpdbg_opline_ptr_t)execute_data->opline == param->addr);
++                      return ((zend_ulong)(phpdbg_opline_ptr_t)execute_data->opline == param->addr);
+               } break;
+               
 -              case NUMERIC_PARAM:
 -              case EMPTY_PARAM: { 
 -                      /* do nothing */ } break;
++              default: {
++                      /* do nothing */
++              } break;
        }
-       return FAILURE;
+       return 0;
  } /* }}} */
  
int phpdbg_find_conditional_breakpoint(TSRMLS_D) /* {{{ */
static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
  {
        phpdbg_breakcond_t *bp;
        HashPosition position;
@@@ -982,153 -772,62 +1099,72 @@@ result
  
  PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */
  {
-       if (PHPDBG_G(flags) & PHPDBG_HAS_METHOD_OPLINE_BP) {
-               HashPosition position[3];
-               phpdbg_breakopline_t *brake;
-               HashTable *class_table, *method_table;
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0]);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], (void**) &class_table, &position[0]) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0])) {
-                       for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]);
-                            zend_hash_get_current_data_ex(class_table, (void**) &method_table, &position[1]) == SUCCESS;
-                            zend_hash_move_forward_ex(class_table, &position[1])) {
-                               for (zend_hash_internal_pointer_reset_ex(method_table, &position[2]);
-                                    zend_hash_get_current_data_ex(method_table, (void**) &brake, &position[2]) == SUCCESS;
-                                    zend_hash_move_forward_ex(method_table, &position[2])) {
-                                       if (brake->id == num) {
-                                               zend_hash_index_del(method_table, brake->opline);
+       HashTable **table;
+       HashPosition position;
+       phpdbg_breakbase_t *brake;
+       
 -      if ((brake  = phpdbg_find_breakbase_ex(num, &table, &position TSRMLS_CC))) {
++      if ((brake = phpdbg_find_breakbase_ex(num, &table, &position TSRMLS_CC))) {
+               char *key;
+               zend_uint klen;
+               zend_ulong idx;
+               int type = brake->type;
+               char *name = NULL;
+               size_t name_len = 0L;
+               switch (type) {
+                       case PHPDBG_BREAK_FILE:
+                       case PHPDBG_BREAK_METHOD:
+                               if (zend_hash_num_elements((*table)) == 1) {
+                                       name = estrdup(brake->name);
+                                       name_len = strlen(name);
+                                       if (zend_hash_num_elements(&PHPDBG_G(bp)[type]) == 1) {
+                                               PHPDBG_G(flags) &= ~(1<<(brake->type+1));
                                        }
                                }
-                       }
-               }
-       }
+                       break;
  
-       if (PHPDBG_G(flags) & PHPDBG_HAS_FUNCTION_OPLINE_BP) {
-               HashPosition position[2];
-               phpdbg_breakopline_t *brake;
-               HashTable *function_table;
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0]);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], (void**) &function_table, &position[0]) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0])) {
-                       for (zend_hash_internal_pointer_reset_ex(function_table, &position[1]);
-                            zend_hash_get_current_data_ex(function_table, (void**) &brake, &position[1]) == SUCCESS;
-                            zend_hash_move_forward_ex(function_table, &position[1])) {
-                               if (brake->id == num) {
-                                       zend_hash_index_del(function_table, brake->opline);
+                       default: {
+                               if (zend_hash_num_elements((*table)) == 1) {
+                                       PHPDBG_G(flags) &= ~(1<<(brake->type+1));
                                }
                        }
                }
-       }
  
-       if (PHPDBG_G(flags) & PHPDBG_HAS_FILE_OPLINE_BP) {
-               HashPosition position[2];
-               phpdbg_breakopline_t *brake;
-               HashTable *file_table;
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0]);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], (void**) &file_table, &position[0]) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0])) {
-                       for (zend_hash_internal_pointer_reset_ex(file_table, &position[1]);
-                            zend_hash_get_current_data_ex(file_table, (void**) &brake, &position[1]) == SUCCESS;
-                            zend_hash_move_forward_ex(file_table, &position[1])) {
-                               if (brake->id == num) {
-                                       zend_hash_index_del(file_table, brake->opline);
++              switch (type) {
++                      case PHPDBG_BREAK_FILE_OPLINE:
++                      case PHPDBG_BREAK_FUNCTION_OPLINE:
++                      case PHPDBG_BREAK_METHOD_OPLINE:
++                              if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]) == 1) {
++                                      PHPDBG_G(flags) &= PHPDBG_HAS_OPLINE_BP;
 +                              }
-                       }
++                              zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], ((phpdbg_breakopline_t*)brake)->opline);
 +              }
-       }
 +
-       if (PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP) {
-               HashPosition position;
-               phpdbg_breakline_t *brake;
+               switch (zend_hash_get_current_key_ex(
+                       (*table), &key, &klen, &idx, 0, &position)) {
  
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void**) &brake, &position) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position)) {
-                       if (brake->id == num) {
-                               zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], brake->opline);
-                               return;
-                       }
-               }
-       }
-       if (PHPDBG_G(flags) & PHPDBG_HAS_SYM_BP) {
-               HashPosition position;
-               phpdbg_breaksymbol_t *brake;
+                       case HASH_KEY_IS_STRING:
+                               zend_hash_del((*table), key, klen);
+                       break;
  
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], (void**) &brake, &position) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position)) {
-                       if (brake->id == num) {
-                               zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], brake->symbol, strlen(brake->symbol));
-                               return;
-                       }
+                       default:
+                               zend_hash_index_del((*table), idx);
                }
-       }
  
-       if (PHPDBG_G(flags) & PHPDBG_HAS_METHOD_BP) {
-               HashPosition position[2];
-               phpdbg_breakmethod_t *brake;
-               HashTable *class_table;
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0]);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], (void**) &class_table, &position[0]) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0])) {
-                       for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]);
-                            zend_hash_get_current_data_ex(class_table, (void**) &brake, &position[1]) == SUCCESS;
-                            zend_hash_move_forward_ex(class_table, &position[1])) {
-                               if (brake->id == num) {
-                                       zend_hash_del(class_table, brake->func_name, brake->func_len);
-                                       return;
+               switch (type) {
+                       case PHPDBG_BREAK_FILE:
+                       case PHPDBG_BREAK_METHOD:
+                               if (name) {
+                                       zend_hash_del(&PHPDBG_G(bp)[type], name, name_len);
+                                       efree(name);
                                }
-                       }
-               }
-       }
-       if (PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP) {
-               HashPosition position;
-               zend_llist *points;
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], (void**) &points, &position) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position)) {
-                       size_t size = points->size;
-                       PHPDBG_G(del_bp_num) = num;
-                       zend_llist_apply_with_del(points, phpdbg_delete_breakpoint_from_file_llist);
-                       if (size != points->size) {
-                               return;
-                       }
-               }
-       }
-       if (PHPDBG_G(flags) & PHPDBG_HAS_COND_BP) {
-               HashPosition position;
-               phpdbg_breakcond_t *brake;
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void**) &brake, &position) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) {
-                       if (brake->id == num) {
-                               zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], brake->hash);
-                               return;
-                       }
+                       break;
                }
-       }
  
-       if (PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) {
-               HashPosition position;
-               phpdbg_breakop_t *brake;
-               for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position);
-                    zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], (void**) &brake, &position) == SUCCESS;
-                    zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position)) {
-                       if (brake->id == num) {
-                               zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], brake->hash);
-                               return;
-                       }
-               }
+               phpdbg_notice("Deleted breakpoint #%ld", num);
+               PHPDBG_BREAK_UNMAPPING(num);    
+       } else {
+               phpdbg_error("Failed to find breakpoint #%ld", num);
        }
  } /* }}} */
  
@@@ -1137,6 -836,6 +1173,9 @@@ PHPDBG_API void phpdbg_clear_breakpoint
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
++      zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
++      zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
++      zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
        PHPDBG_G(bp_count) = 0;
  } /* }}} */
  
 -                ((phpdbg_breaksymbol_t*)brake)->id,
 -                ((phpdbg_breaksymbol_t*)brake)->symbol,
 -                zend_get_executed_filename(TSRMLS_C),
 -                zend_get_executed_lineno(TSRMLS_C),
 -                ((phpdbg_breakfile_t*)brake)->hits);
+ PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t *brake, zend_bool output TSRMLS_DC) /* {{{ */
+ {
+       brake->hits++;
+       if (output) {
+               phpdbg_print_breakpoint(brake TSRMLS_CC);
+       }
+ } /* }}} */
+ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* {{{ */
+ {
+       if (!brake)
+               goto unknown;
+       switch (brake->type) {
+               case PHPDBG_BREAK_FILE: {
+                       phpdbg_notice("Breakpoint #%d at %s:%ld, hits: %lu",
+                               ((phpdbg_breakfile_t*)brake)->id,
+                               ((phpdbg_breakfile_t*)brake)->filename,
+                               ((phpdbg_breakfile_t*)brake)->line,
+                               ((phpdbg_breakfile_t*)brake)->hits);
+               } break;
+               case PHPDBG_BREAK_SYM: {
+                       phpdbg_notice("Breakpoint #%d in %s() at %s:%u, hits: %lu",
 -                      
++                              ((phpdbg_breaksymbol_t*)brake)->id,
++                              ((phpdbg_breaksymbol_t*)brake)->symbol,
++                              zend_get_executed_filename(TSRMLS_C),
++                              zend_get_executed_lineno(TSRMLS_C),
++                              ((phpdbg_breakfile_t*)brake)->hits);
+               } break;
+               case PHPDBG_BREAK_OPLINE: {
+                       phpdbg_notice("Breakpoint #%d in %#lx at %s:%u, hits: %lu",
+                               ((phpdbg_breakline_t*)brake)->id,
+                               ((phpdbg_breakline_t*)brake)->opline,
+                               zend_get_executed_filename(TSRMLS_C),
+                               zend_get_executed_lineno(TSRMLS_C),
+                               ((phpdbg_breakline_t*)brake)->hits);
+               } break;
++              case PHPDBG_BREAK_METHOD_OPLINE: {
++                       phpdbg_notice("Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu",
++                              ((phpdbg_breakopline_t*)brake)->id,
++                              ((phpdbg_breakopline_t*)brake)->class_name,
++                              ((phpdbg_breakopline_t*)brake)->func_name,
++                              ((phpdbg_breakopline_t*)brake)->opline_num,
++                              zend_get_executed_filename(TSRMLS_C),
++                              zend_get_executed_lineno(TSRMLS_C),
++                              ((phpdbg_breakopline_t*)brake)->hits);
++              } break;
++
++              case PHPDBG_BREAK_FUNCTION_OPLINE: {
++                       phpdbg_notice("Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu",
++                              ((phpdbg_breakopline_t*)brake)->id,
++                              ((phpdbg_breakopline_t*)brake)->func_name,
++                              ((phpdbg_breakopline_t*)brake)->opline_num,
++                              zend_get_executed_filename(TSRMLS_C),
++                              zend_get_executed_lineno(TSRMLS_C),
++                              ((phpdbg_breakopline_t*)brake)->hits);
++              } break;
++
++              case PHPDBG_BREAK_FILE_OPLINE: {
++                       phpdbg_notice("Breakpoint #%d in %s:%lu at %s:%u, hits: %lu",
++                              ((phpdbg_breakopline_t*)brake)->id,
++                              ((phpdbg_breakopline_t*)brake)->class_name,
++                              ((phpdbg_breakopline_t*)brake)->opline_num,
++                              zend_get_executed_filename(TSRMLS_C),
++                              zend_get_executed_lineno(TSRMLS_C),
++                              ((phpdbg_breakopline_t*)brake)->hits);
++              } break;
++
+               case PHPDBG_BREAK_OPCODE: {
+                        phpdbg_notice("Breakpoint #%d in %s at %s:%u, hits: %lu",
+                               ((phpdbg_breakop_t*)brake)->id,
+                               ((phpdbg_breakop_t*)brake)->name,
+                               zend_get_executed_filename(TSRMLS_C),
+                               zend_get_executed_lineno(TSRMLS_C),
+                               ((phpdbg_breakop_t*)brake)->hits);
+               } break;
+               case PHPDBG_BREAK_METHOD: {
+                        phpdbg_notice("Breakpoint #%d in %s::%s() at %s:%u, hits: %lu",
+                               ((phpdbg_breakmethod_t*)brake)->id,
+                               ((phpdbg_breakmethod_t*)brake)->class_name,
+                               ((phpdbg_breakmethod_t*)brake)->func_name,
+                               zend_get_executed_filename(TSRMLS_C),
+                               zend_get_executed_lineno(TSRMLS_C),
+                               ((phpdbg_breakmethod_t*)brake)->hits);
+               } break;
+               case PHPDBG_BREAK_COND: {
+                       phpdbg_notice("Conditional breakpoint #%d: (%s) %s:%u, hits: %lu",
+                               ((phpdbg_breakcond_t*)brake)->id,
+                               ((phpdbg_breakcond_t*)brake)->code,
+                               zend_get_executed_filename(TSRMLS_C),
+                               zend_get_executed_lineno(TSRMLS_C),
+                               ((phpdbg_breakcond_t*)brake)->hits);
+               } break;
+               default: {
+ unknown:
+                       phpdbg_notice("Unknown breakpoint at %s:%u",
+                               zend_get_executed_filename(TSRMLS_C),
+                               zend_get_executed_lineno(TSRMLS_C));
+               }
+       }
+ } /* }}} */
+ PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */
+ {
+       phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC);
+       
+       if (brake) {
+               brake->disabled = 0;
+       }
+ } /* }}} */
+ PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */
+ {
+       phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC);
+       
+       if (brake) {
+               brake->disabled = 1;
+       }
+ } /* }}} */
+ PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D) /* {{{ */
+ {
+       PHPDBG_G(flags) |= PHPDBG_IS_BP_ENABLED;
+ } /* }}} */
+ PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D) { /* {{{ */
+       PHPDBG_G(flags) &= ~PHPDBG_IS_BP_ENABLED;       
+ } /* }}} */
+ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC) /* {{{ */
+ {
+       HashTable **table;
+       HashPosition position;
+       return phpdbg_find_breakbase_ex(id, &table, &position TSRMLS_CC);
+ } /* }}} */
+ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC) /* {{{ */
+ {
+       if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id, (void**)table) == SUCCESS) {
+               phpdbg_breakbase_t *brake;
+               for (zend_hash_internal_pointer_reset_ex((**table), position);
+                       zend_hash_get_current_data_ex((**table), (void**)&brake, position) == SUCCESS;
+                       zend_hash_move_forward_ex((**table), position)) {
++
+                       if (brake->id == id) {
+                               return brake;
+                       }
+               }
+       }
+       return NULL;
+ } /* }}} */
  PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */
  {
        switch (type) {
                        for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position);
                             zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void**) &brake, &position) == SUCCESS;
                             zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position)) {
 -                              phpdbg_writeln("#%d\t\t%#lx%s", 
 -                                      brake->id, brake->opline, 
 -                                      ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
 +                              switch (brake->type) {
 +                                      case PHPDBG_BREAK_METHOD_OPLINE:
 +                                      case PHPDBG_BREAK_FUNCTION_OPLINE:
 +                                      case PHPDBG_BREAK_FILE_OPLINE:
-                                               phpdbg_writeln("#%d\t\t%#lx\t\t(%s breakpoint)", brake->id, brake->opline,
++                                              phpdbg_writeln("#%d\t\t%#lx\t\t(%s breakpoint)%s", brake->id, brake->opline,
 +                                                      brake->type == PHPDBG_BREAK_METHOD_OPLINE?"method":
 +                                                              brake->type == PHPDBG_BREAK_FUNCTION_OPLINE?"function":
 +                                                                      brake->type == PHPDBG_BREAK_FILE_OPLINE?"file":
-                                                                               "--- error ---"
-                                               );
++                                                                              "--- error ---",
++                                                      ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
 +                                              break;
 +
 +                                      default:
 +                                              phpdbg_writeln("#%d\t\t%#lx", brake->id, brake->opline);
 +                                              break;
 +                              }
 +                      }
 +              } break;
 +
 +              case PHPDBG_BREAK_METHOD_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_OPLINE_BP)) {
 +                      HashPosition position[3];
 +                      HashTable *class_table, *method_table;
 +                      char *class_name = NULL, *method_name = NULL;
 +                      zend_uint class_len = 0, method_len = 0;
 +                      zend_ulong class_idx = 0L, method_idx = 0L;
 +
 +                      phpdbg_writeln(SEPARATE);
 +                      phpdbg_writeln("Method opline Breakpoints:");
 +                      for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0]);
 +                           zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], (void**) &class_table, &position[0]) == SUCCESS;
 +                           zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0])) {
 +
 +                              if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
 +                                      &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
 +
 +                                      for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]);
 +                                           zend_hash_get_current_data_ex(class_table, (void**) &method_table, &position[1]) == SUCCESS;
 +                                           zend_hash_move_forward_ex(class_table, &position[1])) {
 +
 +                                              if (zend_hash_get_current_key_ex(class_table,
 +                                                      &method_name, &method_len, &method_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
 +
 +                                                      phpdbg_breakopline_t *brake;
 +
 +                                                      for (zend_hash_internal_pointer_reset_ex(method_table, &position[2]);
 +                                                           zend_hash_get_current_data_ex(method_table, (void**)&brake, &position[2]) == SUCCESS;
 +                                                           zend_hash_move_forward_ex(method_table, &position[2])) {
-                                                               phpdbg_writeln("#%d\t\t%s::%s opline %d", brake->id, brake->class_name, brake->func_name, brake->opline);
++                                                              phpdbg_writeln("#%d\t\t%s::%s opline %ld%s",
++                                                                      brake->id, brake->class_name, brake->func_name, brake->opline_num,
++                                                                      ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +
 +                      }
 +              } break;
 +
 +              case PHPDBG_BREAK_FUNCTION_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FUNCTION_OPLINE_BP)) {
 +                      HashPosition position[2];
 +                      HashTable *function_table;
 +                      char *function_name = NULL;
 +                      zend_uint function_len = 0;
 +                      zend_ulong function_idx = 0L;
 +
 +                      phpdbg_writeln(SEPARATE);
 +                      phpdbg_writeln("Function opline Breakpoints:");
 +                      for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0]);
 +                           zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], (void**) &function_table, &position[0]) == SUCCESS;
 +                           zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0])) {
 +
 +                              if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE],
 +                                      &function_name, &function_len, &function_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
 +
 +                                      phpdbg_breakopline_t *brake;
 +
 +                                      for (zend_hash_internal_pointer_reset_ex(function_table, &position[1]);
 +                                           zend_hash_get_current_data_ex(function_table, (void**)&brake, &position[1]) == SUCCESS;
 +                                           zend_hash_move_forward_ex(function_table, &position[1])) {
-                                               phpdbg_writeln("#%d\t\t%s opline %d", brake->id, brake->func_name, brake->opline);
++                                              phpdbg_writeln("#%d\t\t%s opline %ld%s",
++                                                      brake->id, brake->func_name, brake->opline_num,
++                                                      ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
 +                                      }
 +                              }
 +
 +                      }
 +              } break;
 +
 +              case PHPDBG_BREAK_FILE_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_OPLINE_BP)) {
 +                      HashPosition position[2];
 +                      HashTable *file_table;
 +                      char *file_name = NULL;
 +                      zend_uint file_len = 0;
 +                      zend_ulong file_idx = 0L;
 +
 +                      phpdbg_writeln(SEPARATE);
 +                      phpdbg_writeln("File opline Breakpoints:");
 +                      for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0]);
 +                           zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], (void**) &file_table, &position[0]) == SUCCESS;
 +                           zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0])) {
 +
 +                              if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE],
 +                                      &file_name, &file_len, &file_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
 +
 +                                      phpdbg_breakopline_t *brake;
 +
 +                                      for (zend_hash_internal_pointer_reset_ex(file_table, &position[1]);
 +                                           zend_hash_get_current_data_ex(file_table, (void**)&brake, &position[1]) == SUCCESS;
 +                                           zend_hash_move_forward_ex(file_table, &position[1])) {
-                                               phpdbg_writeln("#%d\t\t%s opline %d", brake->id, brake->class_name, brake->opline);
++                                              phpdbg_writeln("#%d\t\t%s opline %ld%s",
++                                                      brake->id, brake->class_name, brake->opline_num,
++                                                      ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
 +                                      }
 +                              }
                        }
                } break;
  
                        for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position);
                             zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void**) &brake, &position) == SUCCESS;
                             zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) {
-                               phpdbg_writeln("#%d\t\t%s", brake->id, Z_STRVAL(brake->code));
+                               if (brake->paramed) {
+                                       switch (brake->param.type) {
+                                               case STR_PARAM:
+                                                       phpdbg_writeln("#%d\t\tat %s if %s%s",  
+                                                               brake->id, 
+                                                               brake->param.str,
+                                                               brake->code, 
+                                                               ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+                                               break;
+                                               
+                                               case METHOD_PARAM:
+                                                       phpdbg_writeln("#%d\t\tat %s::%s if %s%s",      
+                                                               brake->id, 
+                                                               brake->param.method.class,
+                                                               brake->param.method.name,
+                                                               brake->code, 
+                                                               ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+                                               break;
+                                               
+                                               case FILE_PARAM:
+                                                       phpdbg_writeln("#%d\t\tat %s:%lu if %s%s",      
+                                                               brake->id, 
+                                                               brake->param.file.name,
+                                                               brake->param.file.line,
+                                                               brake->code,
+                                                               ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+                                               break;
+                                               
+                                               case ADDR_PARAM:
+                                                       phpdbg_writeln("#%d\t\tat #%lx if %s%s",        
+                                                               brake->id, 
+                                                               brake->param.addr,
+                                                               brake->code, 
+                                                               ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+                                               break;
++
++                                              default:
++                                                      phpdbg_error("Invalid parameter type for conditional breakpoint");
++                                              return;
+                                       }
+                               } else {
+                                       phpdbg_writeln("#%d\t\tif %s%s",        
+                                               brake->id, brake->code, 
+                                               ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+                               }
                        }
                } break;
  
diff --cc phpdbg_bp.h
index 31f739338c1e613cfc3ecf97773394071829f493,3838a68d18b38e44383dd914c09c410f0d507726..fe328bfbf586b7b93f2f41ffc77b8a449b660bed
  /* {{{ */
  typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */
  
 -      int                     id; \
+ /* {{{ breakpoint base structure */
+ #define phpdbg_breakbase(name) \
 -      const char  *name /* }}} */
++      int         id; \
+       zend_uchar  type; \
+       zend_ulong  hits; \
+       zend_bool   disabled; \
++      const char *name /* }}} */
+ /* {{{ breakpoint base */
+ typedef struct _phpdbg_breakbase_t {
+       phpdbg_breakbase(name);
+ } phpdbg_breakbase_t; /* }}} */
  /**
   * Breakpoint file-based representation
   */
@@@ -48,77 -59,66 +59,87 @@@ typedef struct _phpdbg_breakmethod_t 
        size_t      class_len;
        const char *func_name;
        size_t      func_len;
-       int         id;
  } phpdbg_breakmethod_t;
  
-       const char *func_name;
-       size_t      func_len;
-       int         opline;
-       int         id;
 +/**
 + * Breakpoint opline num based representation
 + */
 +typedef struct _phpdbg_breakopline_t {
++      phpdbg_breakbase(func_name);
++      size_t      func_len;
 +      const char *class_name;
 +      size_t      class_len;
++      zend_ulong  opline_num;
++      zend_ulong  opline;
 +} phpdbg_breakopline_t;
 +
  /**
   * Breakpoint opline based representation
   */
  typedef struct _phpdbg_breakline_t {
-       const char *name;
-       zend_ulong  opline;
-       zend_uchar  type;
-       int         id;
+       phpdbg_breakbase(name);
 -      zend_ulong  opline;
++      zend_ulong opline;
++      phpdbg_breakopline_t *base;
  } phpdbg_breakline_t;
  
  /**
   * Breakpoint opcode based representation
   */
  typedef struct _phpdbg_breakop_t {
-       zend_ulong  hash;
-       const char *name;
-       int         id;
+       phpdbg_breakbase(name);
 -      zend_ulong  hash;
++      zend_ulong hash;
  } phpdbg_breakop_t;
  
  /**
   * Breakpoint condition based representation
   */
  typedef struct _phpdbg_breakcond_t {
 -      size_t                  code_len;
+       phpdbg_breakbase(code);
++      size_t          code_len;
+       zend_bool       paramed;
+       phpdbg_param_t  param;
        zend_ulong      hash;
-       zval            code;
        zend_op_array  *ops;
-       int             id;
  } phpdbg_breakcond_t;
  
- PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_file(const char*, long TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_symbol(const char*, size_t TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_method(const char*, const char* TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_opcode(const char*, size_t TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, int opline TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, int opline TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, int opline TSRMLS_DC);
- PHPDBG_API void phpdbg_set_breakpoint_expression(const char*, size_t TSRMLS_DC);
- int phpdbg_find_breakpoint_file(zend_op_array* TSRMLS_DC);
- int phpdbg_find_breakpoint_symbol(zend_function* TSRMLS_DC);
- int phpdbg_find_breakpoint_method(zend_op_array* TSRMLS_DC);
- int phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t TSRMLS_DC);
- int phpdbg_find_breakpoint_opcode(zend_uchar TSRMLS_DC);
- int phpdbg_find_conditional_breakpoint(TSRMLS_D);
- int phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC);
++/* {{{ Opline breaks API */
 +PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC);
 +PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC);
- PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC);
- PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D);
++PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */
 +
+ /* {{{ Breakpoint Creation API */
+ PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC);
+ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len TSRMLS_DC);
+ PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name TSRMLS_DC);
+ PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len TSRMLS_DC);
+ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC);
+ PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC);
++PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC);
++PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC);
++PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC);
+ PHPDBG_API void phpdbg_set_breakpoint_expression(const char* expression, size_t expression_len TSRMLS_DC);
+ PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC); /* }}} */
+ /* {{{ Breakpoint Detection API */
+ PHPDBG_API phpdbg_breakbase_t* phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC); /* }}} */
+ /* {{{ Misc Breakpoint API */
+ PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t* brake, zend_bool output TSRMLS_DC);
  PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC);
+ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t* brake TSRMLS_DC);
+ PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D);
+ PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D);
+ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC);
+ PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D);
+ PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC);
+ PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC);
+ PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D); /* }}} */
+ /* {{{ Breakbase API */
+ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC);
+ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC); /* }}} */
  
- PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC);
+ /* {{{ Breakpoint Exportation API */
+ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */
  
  #endif /* PHPDBG_BP_H */
diff --cc phpdbg_break.c
Simple merge
diff --cc phpdbg_cmd.c
Simple merge
diff --cc phpdbg_cmd.h
Simple merge
diff --cc phpdbg_help.c
Simple merge
diff --cc phpdbg_info.c
Simple merge
diff --cc phpdbg_prompt.c
index 390aaa556bba80abb3ea0cde7fe4e418fac3ee1e,2589a247322a47a48aee6e8c5d556ac65fdbcb63..7d2ad6ca34ea3090181d10ae5e1d8af1f4ce0b73
@@@ -957,6 -950,6 +956,9 @@@ PHPDBG_COMMAND(clear) /* {{{ *
        phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]));
        phpdbg_writeln("Methods\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]));
        phpdbg_writeln("Oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]));
++      phpdbg_writeln("File oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]));
++      phpdbg_writeln("Function oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]));
++      phpdbg_writeln("Method oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]));
        phpdbg_writeln("Conditionals\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]));
  
        phpdbg_clear_breakpoints(TSRMLS_C);
diff --cc phpdbg_utils.c
index f18bbb55fa8a1b0216e1d46bf380f3f984fcbf1a,67e1cbc4643da8f2fa3a9c84d995e1b9e06fc761..bd3c530bbc68e7b08298fda141508c6902a95c67
@@@ -100,6 -101,6 +101,9 @@@ PHPDBG_API int phpdbg_is_class_method(c
  {
        char *sep = NULL;
  
++      if (strstr(str, "#") != NULL)
++              return 0;
++
        if (strstr(str, " ") != NULL)
                return 0;