# 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"
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");
{
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");
*/
PHPDBG_HELP(exec);
PHPDBG_HELP(compile);
+PHPDBG_HELP(step);
+PHPDBG_HELP(next);
PHPDBG_HELP(run);
PHPDBG_HELP(print);
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"),
}
} /* }}} */
+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)) {
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(
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"),
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];
}
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)
}
while (1) {
- int ret;
#ifdef ZEND_WIN32
if (EG(timed_out)) {
zend_timeout(0);
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;