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