diff --git a/phpdbg.c b/phpdbg.c index 3b1a93b172f..1379b6b7bf2 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -26,6 +26,7 @@ void (*zend_execute_internal_old)(zend_execute_data *execute_data_ptr, zend_fcal static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) { pg->exec = NULL; pg->ops = NULL; + pg->stepping = 0; } static PHP_MINIT_FUNCTION(phpdbg) { diff --git a/phpdbg.h b/phpdbg.h index a3da778520d..0b1f2daa885 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -36,12 +36,16 @@ # define PHPDBG_G(v) (phpdbg_globals.v) #endif +#define PHPDBG_NEXT 2 + ZEND_BEGIN_MODULE_GLOBALS(phpdbg) HashTable breaks; char *exec; /* file to execute */ size_t exec_len; /* size of exec */ zend_op_array *ops; /* op_array */ zval *retval; /* return value */ + zend_bool stepping; /* stepping */ + int vmret; /* return from last opcode handler execution */ ZEND_END_MODULE_GLOBALS(phpdbg) #include "phpdbg_prompt.h" diff --git a/phpdbg_help.c b/phpdbg_help.c index d5ec6fd40c3..a72f53fd13c 100644 --- a/phpdbg_help.c +++ b/phpdbg_help.c @@ -30,6 +30,20 @@ PHPDBG_HELP(exec) /* {{{ */ return SUCCESS; } /* }}} */ +PHPDBG_HELP(step) { /* {{{ */ + printf("You can enable and disable stepping at any phpdbg prompt during execution\n"); + printf("For example:\n"); + printf("phpdbg> stepping 1\n"); + printf("Will enable stepping\n"); + printf("While stepping is enabled you are presented with a prompt after the execution of each opcode\n"); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(next) { /* {{{ */ + printf("While stepping through execution, use the next command to step back into the vm and execute the next opcode"); + return SUCCESS; +} /* }}} */ + PHPDBG_HELP(compile) /* {{{ */ { printf("Pre-compilation of the execution context provides the opportunity to inspect the opcodes before they are executed\n"); @@ -43,7 +57,7 @@ PHPDBG_HELP(print) /* {{{ */ { printf("By default, print will show information about the current execution environment\n"); printf("To show specific information pass an expression to print, for example:\n"); - printf("\tprint opcodes[0]\n"); + printf("\tphpdbg> print opcodes[0]\n"); printf("Will show the opline @ 0\n"); printf("Available print commands:\n"); printf("\tNone\n"); diff --git a/phpdbg_help.h b/phpdbg_help.h index 1ab558725ce..69b710f782d 100644 --- a/phpdbg_help.h +++ b/phpdbg_help.h @@ -33,6 +33,8 @@ */ PHPDBG_HELP(exec); PHPDBG_HELP(compile); +PHPDBG_HELP(step); +PHPDBG_HELP(next); PHPDBG_HELP(run); PHPDBG_HELP(print); PHPDBG_HELP(break); @@ -43,6 +45,8 @@ PHPDBG_HELP(break); static const phpdbg_command_t phpdbg_help_commands[] = { PHPDBG_HELP_D(exec, "the execution context should be a valid phpdbg path"), PHPDBG_HELP_D(compile, "pre-compilation allows inspection of code before execution"), + PHPDBG_HELP_D(step, "stepping through execution allows inspection of the opline after every opcode"), + PHPDBG_HELP_D(next, "execute the next opcode"), PHPDBG_HELP_D(run, "execution inside the phpdbg vm allows detailed inspection and debugging"), PHPDBG_HELP_D(print, "printing allows inspection of the execution environment"), PHPDBG_HELP_D(break, "breakpoints allow execution interruption"), diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 31722665b3e..0dfe14b1bef 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -85,6 +85,15 @@ static PHPDBG_COMMAND(compile) { /* {{{ */ } } /* }}} */ +static PHPDBG_COMMAND(step) { /* {{{ */ + PHPDBG_G(stepping) = atoi(expr); + return SUCCESS; +} /* }}} */ + +static PHPDBG_COMMAND(next) { /* {{{ */ + return PHPDBG_NEXT; +} /* }}} */ + static PHPDBG_COMMAND(run) { /* {{{ */ if (PHPDBG_G(ops) || PHPDBG_G(exec)) { if (!PHPDBG_G(ops)) { @@ -116,9 +125,12 @@ static PHPDBG_COMMAND(print) { /* {{{ */ printf("Showing Execution Context Information:\n"); printf("Exec\t\t%s\n", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); printf("Compiled\t%s\n", PHPDBG_G(ops) ? "yes" : "no"); + printf("Stepping\t%s\n", PHPDBG_G(stepping) ? "on" : "off"); if (PHPDBG_G(ops)) { - printf("Opcodes\t\t%d\n", PHPDBG_G(ops)->last-1); - printf("Variables\t%d\n", PHPDBG_G(ops)->last_var-1); + printf("Opcodes\t\t%d\n", PHPDBG_G(ops)->last); + if (PHPDBG_G(ops)->last_var) { + printf("Variables\t%d\n", PHPDBG_G(ops)->last_var-1); + } else printf("Variables\tNone\n"); } } else { printf( @@ -175,6 +187,8 @@ static PHPDBG_COMMAND(help) /* {{{ */ static const phpdbg_command_t phpdbg_prompt_commands[] = { PHPDBG_COMMAND_D(exec, "set execution context"), PHPDBG_COMMAND_D(compile, "attempt to pre-compile execution context"), + PHPDBG_COMMAND_D(step, "step through execution"), + PHPDBG_COMMAND_D(next, "next opcode"), PHPDBG_COMMAND_D(run, "attempt execution"), PHPDBG_COMMAND_D(print, "print something"), PHPDBG_COMMAND_D(break, "set breakpoint"), @@ -200,7 +214,7 @@ int phpdbg_do_cmd(const phpdbg_command_t *command, char *cmd_line, size_t cmd_le return FAILURE; } /* }}} */ -void phpdbg_interactive(int argc, char **argv TSRMLS_DC) /* {{{ */ +int phpdbg_interactive(int argc, char **argv TSRMLS_DC) /* {{{ */ { char cmd[PHPDBG_MAX_CMD]; @@ -214,13 +228,20 @@ void phpdbg_interactive(int argc, char **argv TSRMLS_DC) /* {{{ */ } if (cmd_len) { - if (phpdbg_do_cmd(phpdbg_prompt_commands, cmd, cmd_len TSRMLS_CC) == FAILURE) { - printf("error executing %s !\n", cmd); - } + switch (phpdbg_do_cmd(phpdbg_prompt_commands, cmd, cmd_len TSRMLS_CC)) { + case FAILURE: + printf("error executing %s !\n", cmd); + break; + + case PHPDBG_NEXT: + return PHPDBG_NEXT; + } } printf("phpdbg> "); } + + return SUCCESS; } /* }}} */ void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) @@ -236,7 +257,6 @@ zend_vm_enter: } while (1) { - int ret; #ifdef ZEND_WIN32 if (EG(timed_out)) { zend_timeout(0); @@ -245,8 +265,17 @@ zend_vm_enter: printf("[OPLINE: %p]\n", execute_data->opline); - if ((ret = execute_data->opline->handler(execute_data TSRMLS_CC)) > 0) { - switch (ret) { + PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC); + + if (PHPDBG_G(stepping)) { + while (phpdbg_interactive( + 0, NULL TSRMLS_CC) != PHPDBG_NEXT) { + continue; + } + } + + if (PHPDBG_G(vmret) > 0) { + switch (PHPDBG_G(vmret)) { case 1: EG(in_execution) = original_in_execution; return; diff --git a/phpdbg_prompt.h b/phpdbg_prompt.h index 028f2c080af..b6921d671e4 100644 --- a/phpdbg_prompt.h +++ b/phpdbg_prompt.h @@ -56,7 +56,7 @@ int phpdbg_do_cmd(const phpdbg_command_t *command, char *cmd_line, size_t cmd_le #define PHPDBG_COMMAND(name) \ int phpdbg_do_##name(const char *expr, size_t expr_len TSRMLS_DC) -void phpdbg_interactive(int argc, char **argv TSRMLS_DC); +int phpdbg_interactive(int argc, char **argv TSRMLS_DC); void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC); #endif /* PHPDBG_PROMPT_H */