From: Bob Weinand Date: Sat, 7 Dec 2013 14:35:35 +0000 (+0100) Subject: Adapted opline_num breakpoints to master branch X-Git-Tag: php-5.6.0alpha1~110^2~30 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=50db4919ce324cdd63aa79b89c9db52908aedafc;p=php Adapted opline_num breakpoints to master branch --- 50db4919ce324cdd63aa79b89c9db52908aedafc diff --cc phpdbg.c index ce7a0b3184,32cc0769f9..93c2925b07 --- a/phpdbg.c +++ 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 238caa8d4e,0102892f79..233f68c035 --- a/phpdbg.h +++ b/phpdbg.h @@@ -79,50 -79,55 +79,61 @@@ #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) + /* + END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE + */ + -#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) +#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) @@@ -131,11 -136,8 +142,11 @@@ #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 4f6b79ecf7,bf6ef821c5..a84be3e378 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@@ -44,122 -72,107 +72,146 @@@ static void phpdbg_class_breaks_dtor(vo efree((char*)bp->func_name); } /* }}} */ +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_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ + 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); @@@ -375,280 -311,6 +351,293 @@@ } } /* }}} */ +PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC) { + phpdbg_breakline_t opline_break; - if (op_array->last < brake->opline) { ++ if (op_array->last < brake->opline_num) { + if (brake->class_name == NULL) { - phpdbg_error("There are only %d oplines in function %s (breaking at opline %d impossible)", op_array->last, brake->func_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 file %s (breaking at opline %d impossible)", op_array->last, brake->class_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 { - 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 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; - opline_break.opline = (zend_ulong)(op_array->opcodes + brake->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); + - 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); ++ 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(EG(class_table), new_break->class_name, new_break->class_len + 1, (void **)&ce) == 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; + } + - if (zend_hash_find(func_table, new_break->func_name, new_break->func_len + 1, (void **)&func) == FAILURE) { ++ 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; +} + - PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, int opline TSRMLS_DC) /* {{{ */ ++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); - new_break.opline = opline; - new_break.id = PHPDBG_G(bp_count)++; ++ new_break.opline_num = opline; ++ new_break.opline = 0; + + switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { + case FAILURE: - phpdbg_notice("Pending breakpoint #%d 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 #%d added at %s::%s#%d", new_break.id, 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)) { - phpdbg_notice("Breakpoint already exists for %s::%s#%d", new_break.class_name, new_break.func_name, opline); ++ 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; + - zend_hash_index_update(method_table, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); ++ zend_hash_index_update(method_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); +} + - PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, int opline TSRMLS_DC) /* {{{ */ ++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; - new_break.opline = opline; - new_break.id = PHPDBG_G(bp_count)++; ++ new_break.opline_num = opline; ++ new_break.opline = 0; + + switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { + case FAILURE: - phpdbg_notice("Pending breakpoint #%d 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 #%d added at %s#%d", new_break.id, new_break.func_name, new_break.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)) { - phpdbg_notice("Breakpoint already exists for %s#%d", new_break.func_name, opline); ++ 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; + - zend_hash_index_update(func_table, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); ++ zend_hash_index_update(func_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); +} + - PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, int opline TSRMLS_DC) /* {{{ */ ++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); - new_break.opline = opline; - new_break.id = PHPDBG_G(bp_count)++; ++ new_break.opline_num = opline; ++ new_break.opline = 0; + + switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { + case FAILURE: - phpdbg_notice("Pending breakpoint #%d 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 #%d added at %s:%d", new_break.id, new_break.class_name, new_break.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)) { - phpdbg_notice("Breakpoint already exists for %s:%d", new_break.class_name, opline); ++ 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, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); ++ 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) { @@@ -855,19 -569,88 +896,88 @@@ } 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]); @@@ -1146,6 -846,136 +1186,167 @@@ PHPDBG_G(bp_count) = 0; } /* }}} */ + 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); ++ ((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) { @@@ -1219,115 -1054,9 +1425,120 @@@ 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; @@@ -1340,7 -1069,47 +1551,51 @@@ 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 31f739338c,3838a68d18..fe328bfbf5 --- a/phpdbg_bp.h +++ b/phpdbg_bp.h @@@ -23,6 -23,19 +23,19 @@@ /* {{{ */ typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */ + /* {{{ breakpoint base structure */ + #define phpdbg_breakbase(name) \ - int id; \ ++ int id; \ + zend_uchar type; \ + zend_ulong hits; \ + zend_bool disabled; \ - const char *name /* }}} */ ++ 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; +/** + * 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; - const char *func_name; - size_t func_len; - int opline; - int id; ++ 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 { + phpdbg_breakbase(code); - size_t code_len; ++ 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; ++/* {{{ 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 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); ++PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */ + - PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC); - PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D); + /* {{{ 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_prompt.c index 390aaa556b,2589a24732..7d2ad6ca34 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@@ -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 f18bbb55fa,67e1cbc464..bd3c530bbc --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@@ -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;