AC_DEFINE(HAVE_PHPDBG, 1, [ ])
PHP_PHPDBG_CFLAGS="-I$abc_srcdir"
- PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c"
+ PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c"
PHP_SUBST(PHP_PHPDBG_CFLAGS)
PHP_SUBST(PHP_PHPDBG_FILES)
zend_hash_destroy((HashTable*)brake);
} /* }}} */
+static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */
+{
+ phpdbg_breakcond_t *brake = *(phpdbg_breakcond_t**) data;
+
+ if (brake) {
+ if (brake->ops) {
+ TSRMLS_FETCH();
+
+ destroy_op_array(
+ brake->ops TSRMLS_CC);
+ efree(brake->ops);
+ }
+ zval_dtor(&brake->code);
+ }
+} /* }}} */
+
static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
{
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
-
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
+
return SUCCESS;
} /* }}} */
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
-
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
+
if (PHPDBG_G(exec)) {
efree(PHPDBG_G(exec));
}
zend_try {
phpdbg_interactive(TSRMLS_C);
} zend_catch {
-
+
} zend_end_try();
} while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
#define PHPDBG_BREAK_SYM 1
#define PHPDBG_BREAK_OPLINE 2
#define PHPDBG_BREAK_METHOD 3
-#define PHPDBG_BREAK_TABLES 4 /* }}} */
+#define PHPDBG_BREAK_COND 4
+#define PHPDBG_BREAK_TABLES 5 /* }}} */
/* {{{ flags */
-#define PHPDBG_HAS_FILE_BP 0x00000001
-#define PHPDBG_HAS_SYM_BP 0x00000010
-#define PHPDBG_HAS_OPLINE_BP 0x00000100
-#define PHPDBG_HAS_METHOD_BP 0x00001000
-#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP)
+#define PHPDBG_HAS_FILE_BP 0x000000000001
+#define PHPDBG_HAS_SYM_BP 0x000000000010
+#define PHPDBG_HAS_OPLINE_BP 0x000000000100
+#define PHPDBG_HAS_METHOD_BP 0x000000001000
+#define PHPDBG_HAS_COND_BP 0x000000010000
+#define PHPDBG_IN_COND_BP 0x000000100000
+#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP)
-#define PHPDBG_IS_STEPPING 0x00010000
-#define PHPDBG_IS_QUIET 0x00100000
-#define PHPDBG_IS_QUITTING 0x01000000
-#define PHPDBG_IS_COLOURED 0x10000000
+#define PHPDBG_IS_STEPPING 0x000001000000
+#define PHPDBG_IS_QUIET 0x000010000000
+#define PHPDBG_IS_QUITTING 0x000100000000
+#define PHPDBG_IS_COLOURED 0x001000000000
#define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED) /* }}} */
#include "phpdbg.h"
#include "phpdbg_bp.h"
#include "phpdbg_utils.h"
+#include "zend_globals.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
}
} /* }}} */
+void phpdbg_set_breakpoint_expression(const char* expr, size_t expr_len TSRMLS_DC) /* {{{ */
+{
+ zend_ulong hash = zend_inline_hash_func(expr, expr_len);
+
+ if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash)) {
+ phpdbg_breakcond_t new_break;
+
+ zend_op_array *ops = NULL;
+ zend_uint cops = CG(compiler_options);
+
+ ZVAL_STRINGL(&new_break.code, expr, expr_len, 1);
+
+ new_break.id = PHPDBG_G(bp_count)++;
+
+ cops = CG(compiler_options);
+
+ CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
+ {
+ zval pv;
+
+ Z_STRLEN(pv) = expr_len + sizeof("return ;") - 1;
+ Z_STRVAL(pv) = emalloc(Z_STRLEN(pv) + 1);
+ memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1);
+ memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, expr, expr_len);
+ Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';';
+ Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0';
+ Z_TYPE(pv) = IS_STRING;
+
+ new_break.ops = zend_compile_string(
+ &pv, "Conditional Breakpoint Code" TSRMLS_CC);
+
+ if (new_break.ops) {
+ phpdbg_breakcond_t *broken;
+
+ zend_hash_index_update(
+ &PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash, &new_break, sizeof(phpdbg_breakcond_t), (void**)&broken);
+ phpdbg_notice(
+ "Conditional breakpoint #%d added %s/%p", broken->id, Z_STRVAL(broken->code), broken->ops);
+ PHPDBG_G(flags) |= PHPDBG_HAS_COND_BP;
+
+ } else {
+ phpdbg_error(
+ "Failed to compile code for expression %s", expr);
+ zval_dtor(&new_break.code);
+ PHPDBG_G(bp_count)--;
+ }
+ }
+ CG(compiler_options) = cops;
+ } else {
+ phpdbg_notice("Conditional break %s exists", expr);
+ }
+} /* }}} */
+
int phpdbg_find_breakpoint_file(zend_op_array *op_array TSRMLS_DC) /* {{{ */
{
size_t name_len = strlen(op_array->filename);
return FAILURE;
} /* }}} */
+
+
int phpdbg_find_breakpoint_symbol(zend_function *fbc TSRMLS_DC) /* {{{ */
{
const char *fname;
return FAILURE;
} /* }}} */
+int phpdbg_find_conditional_breakpoint(TSRMLS_D) /* {{{ */
+{
+ phpdbg_breakcond_t *bp;
+ HashPosition position;
+ int breakpoint = FAILURE;
+
+ 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*)&bp, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) {
+
+ zval *retval = NULL;
+ int orig_interactive = CG(interactive);
+ zval **orig_retval = EG(return_value_ptr_ptr);
+ zend_op_array *orig_ops = EG(active_op_array);
+ zend_op **orig_opline = EG(opline_ptr);
+
+ ALLOC_INIT_ZVAL(retval);
+
+ EG(return_value_ptr_ptr) = &retval;
+ EG(active_op_array) = bp->ops;
+ EG(no_extensions) = 1;
+
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+
+ CG(interactive) = 0;
+
+ zend_try {
+ PHPDBG_G(flags) |= PHPDBG_IN_COND_BP;
+ zend_execute(
+ EG(active_op_array) TSRMLS_CC);
+ if (i_zend_is_true(retval)) {
+ breakpoint = SUCCESS;
+ }
+ } zend_catch {
+ phpdbg_error(
+ "Error detected while evaluating expression %s", Z_STRVAL(bp->code));
+ CG(interactive) = orig_interactive;
+
+ EG(no_extensions)=1;
+ EG(return_value_ptr_ptr) = orig_retval;
+ EG(active_op_array) = orig_ops;
+ EG(opline_ptr) = orig_opline;
+ PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP;
+ } zend_end_try();
+
+ CG(interactive) = orig_interactive;
+
+ EG(no_extensions)=1;
+ EG(return_value_ptr_ptr) = orig_retval;
+ EG(active_op_array) = orig_ops;
+ EG(opline_ptr) = orig_opline;
+ PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP;
+
+ if (breakpoint == SUCCESS) {
+ break;
+ }
+ }
+
+ if (breakpoint == SUCCESS) {
+ phpdbg_notice("Conditional breakpoint #%d: (%s) %s:%u",
+ bp->id, Z_STRVAL(bp->code),
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C));
+ }
+
+ return breakpoint;
+} /* }}} */
+
void phpdbg_clear_breakpoints(TSRMLS_D) /* {{{ */
{
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]);
-
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
+
PHPDBG_G(flags) &= ~PHPDBG_BP_MASK;
PHPDBG_G(bp_count) = 0;
int id;
} phpdbg_breakline_t;
+/**
+ * Breakpoint opline based representation
+ */
+typedef struct _phpdbg_breakcond_t {
+ zval code;
+ zend_op_array *ops;
+ int id;
+} phpdbg_breakcond_t;
+
void phpdbg_set_breakpoint_file(const char*, long TSRMLS_DC);
void phpdbg_set_breakpoint_symbol(const char* TSRMLS_DC);
void phpdbg_set_breakpoint_method(const char*, const char* TSRMLS_DC);
void phpdbg_set_breakpoint_opline(zend_ulong TSRMLS_DC);
void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t TSRMLS_DC);
+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_conditional_breakpoint(TSRMLS_D);
void phpdbg_clear_breakpoints(TSRMLS_D);
void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC);
#include "phpdbg.h"
#include "phpdbg_help.h"
#include "phpdbg_print.h"
+#include "phpdbg_break.h"
#include "phpdbg_bp.h"
#include "phpdbg_opcode.h"
#include "phpdbg_list.h"
}
if (PHPDBG_G(ops) || PHPDBG_G(exec)) {
+ zend_op **orig_opline = EG(opline_ptr);
+ zend_op_array *orig_op_array = EG(active_op_array);
+ zval **orig_retval_ptr = EG(return_value_ptr_ptr);
+
if (!PHPDBG_G(ops)) {
if (phpdbg_compile(TSRMLS_C) == FAILURE) {
phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec));
EG(active_op_array) = PHPDBG_G(ops);
EG(return_value_ptr_ptr) = &PHPDBG_G(retval);
-
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+
zend_try {
- zend_execute(EG(active_op_array) TSRMLS_CC);
+ zend_execute(
+ EG(active_op_array) TSRMLS_CC);
} zend_catch {
+ EG(active_op_array) = orig_op_array;
+ EG(opline_ptr) = orig_opline;
+ EG(return_value_ptr_ptr) = orig_retval_ptr;
+
if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
phpdbg_error("Caught excetion in VM");
return FAILURE;
} else return SUCCESS;
} zend_end_try();
+ EG(active_op_array) = orig_op_array;
+ EG(opline_ptr) = orig_opline;
+ EG(return_value_ptr_ptr) = orig_retval_ptr;
+
return SUCCESS;
} else {
phpdbg_error("Nothing to execute!");
static PHPDBG_COMMAND(break) /* {{{ */
{
char *line_pos;
+
+ if (expr_len > 0L) {
+ /* allow advanced breakers to run */
+ if (phpdbg_do_cmd(phpdbg_break_commands, (char*)expr, expr_len TSRMLS_CC) == SUCCESS) {
+ return SUCCESS;
+ }
+ }
if (expr_len <= 0L) {
phpdbg_error("No expression found");
phpdbg_print_opline(
execute_data, 0 TSRMLS_CC);
- if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP)
- && phpdbg_find_breakpoint_file(execute_data->op_array TSRMLS_CC) == SUCCESS) {
- while (phpdbg_interactive(TSRMLS_C) != PHPDBG_NEXT) {
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
- continue;
- }
+ /* allow conditional breakpoints to access the vm uninterrupted */
+ if (!(PHPDBG_G(flags) & PHPDBG_IN_COND_BP)) {
+
+ if ((PHPDBG_G(flags) & PHPDBG_HAS_COND_BP)
+ && phpdbg_find_conditional_breakpoint(TSRMLS_C) == SUCCESS) {
+ do {
+ switch (phpdbg_interactive(TSRMLS_C)) {
+ case PHPDBG_NEXT:
+ goto next;
+ }
+ } while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
+ }
+
+ if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP)
+ && phpdbg_find_breakpoint_file(execute_data->op_array TSRMLS_CC) == SUCCESS) {
+ do {
+ switch (phpdbg_interactive(TSRMLS_C)) {
+ case PHPDBG_NEXT:
+ goto next;
+ }
+ } while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
}
- }
- if ((PHPDBG_G(flags) & (PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_SYM_BP))) {
- zend_execute_data *previous = execute_data->prev_execute_data;
- if (previous && previous != execute_data && previous->opline) {
- /* check we are the beginning of a function entry */
- if (execute_data->opline == EG(active_op_array)->opcodes) {
- switch (previous->opline->opcode) {
- case ZEND_DO_FCALL:
- case ZEND_DO_FCALL_BY_NAME:
- case ZEND_INIT_STATIC_METHOD_CALL: {
- if (phpdbg_find_breakpoint_symbol(previous->function_state.function TSRMLS_CC) == SUCCESS) {
- while (phpdbg_interactive(TSRMLS_C) != PHPDBG_NEXT) {
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
- continue;
- }
+ if ((PHPDBG_G(flags) & (PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_SYM_BP))) {
+ zend_execute_data *previous = execute_data->prev_execute_data;
+ if (previous && previous != execute_data && previous->opline) {
+ /* check we are the beginning of a function entry */
+ if (execute_data->opline == EG(active_op_array)->opcodes) {
+ switch (previous->opline->opcode) {
+ case ZEND_DO_FCALL:
+ case ZEND_DO_FCALL_BY_NAME:
+ case ZEND_INIT_STATIC_METHOD_CALL: {
+ if (phpdbg_find_breakpoint_symbol(previous->function_state.function TSRMLS_CC) == SUCCESS) {
+ do {
+ switch (phpdbg_interactive(TSRMLS_C)) {
+ case PHPDBG_NEXT:
+ goto next;
+ }
+ } while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
}
- }
- } break;
+ } break;
+ }
}
}
}
- }
- if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)
- && phpdbg_find_breakpoint_opline(execute_data->opline TSRMLS_CC) == SUCCESS) {
- while (phpdbg_interactive(TSRMLS_C) != PHPDBG_NEXT) {
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
- continue;
- }
+ if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)
+ && phpdbg_find_breakpoint_opline(execute_data->opline TSRMLS_CC) == SUCCESS) {
+ do {
+ switch (phpdbg_interactive(TSRMLS_C)) {
+ case PHPDBG_NEXT:
+ goto next;
+ }
+ } while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
}
}
+next:
PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC);
- if ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)) {
- while (phpdbg_interactive(TSRMLS_C) != PHPDBG_NEXT) {
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
- continue;
+ if (!(PHPDBG_G(flags) & PHPDBG_IN_COND_BP)) {
+ if ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)) {
+ while (phpdbg_interactive(TSRMLS_C) != PHPDBG_NEXT) {
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ continue;
+ }
}
}
}
$dbg = new phpdbg();
+$test = 1;
+
var_dump(
$dbg->isGreat("PHP Rocks !!"));
?>