PHPDBG_HELP(next) /* {{{ */
{
phpdbg_help_header();
- phpdbg_writeln("While stepping through execution, or after a breakpoint, use the next command to step back into the vm and execute the next opcode");
+ phpdbg_write("While stepping through execution, or after a breakpoint, ");
+ phpdbg_writeln("use the next command to step back into the vm and execute the next opcode");
phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(until) /* {{{ */
{
phpdbg_help_header();
- phpdbg_writeln("While stepping through execution, or after a breakpoint, use the until command to step back into the vm and reaches the next source line");
+ phpdbg_write("While stepping through execution, or after a breakpoint, ");
+ phpdbg_writeln("use the until command to step back into the vm and reaches the next source line");
phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(finish) /* {{{ */
{
phpdbg_help_header();
- phpdbg_writeln("While stepping through execution, or after a breakpoint, use the finish command to step back into the vm and continue until the current function has returned");
+ phpdbg_write("While stepping through execution, or after a breakpoint, ");
+ phpdbg_writeln("use the finish command to step back into the vm and continue until the current scope has returned");
+ phpdbg_writeln("Note: this allows all breakpoints that would otherwise break execution in the current scope to be skipped");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(leave) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_write("While stepping through execution, or after a breakpoint, ");
+ phpdbg_writeln("use the finish command to step back into the vm and continue until the current scope is returning");
+ phpdbg_writeln("Note: this allows inspection of the return value from any scope before it is returned");
phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(eval);
PHPDBG_HELP(until);
PHPDBG_HELP(finish);
+PHPDBG_HELP(leave);
PHPDBG_HELP(print);
PHPDBG_HELP(break);
PHPDBG_HELP(clean);
PHPDBG_HELP_D(eval, "access to eval() allows you to affect the environment during execution", 'E'),
PHPDBG_HELP_D(until, "continue until the program reaches a source line different than the current one", 'u'),
PHPDBG_HELP_D(finish, "continue until the current function has returned", 'f'),
+ PHPDBG_HELP_D(leave, "continue until the current function is returning", 'L'),
PHPDBG_HELP_D(print, "printing allows inspection of the execution environment", 'p'),
PHPDBG_HELP_D(break, "breakpoints allow execution interruption", 'b'),
PHPDBG_HELP_D(clean, "resetting the environment is useful while debugging and recompiling", 'X'),
static PHPDBG_COMMAND(eval);
static PHPDBG_COMMAND(until);
static PHPDBG_COMMAND(finish);
+static PHPDBG_COMMAND(leave);
static PHPDBG_COMMAND(print);
static PHPDBG_COMMAND(break);
static PHPDBG_COMMAND(back);
PHPDBG_COMMAND_EX_D(run, "attempt execution", 'r'),
PHPDBG_COMMAND_EX_D(eval, "evaluate some code", 'E'),
PHPDBG_COMMAND_EX_D(until, "continue until reaches next line", 'u'),
- PHPDBG_COMMAND_EX_D(finish, "continue until reaches next line", 'f'),
+ PHPDBG_COMMAND_EX_D(finish, "continue past the end of the stack", 'f'),
+ PHPDBG_COMMAND_EX_D(leave, "continue until the end of the stack", 'L'),
PHPDBG_COMMANDS_D(print, "print something", 'p', phpdbg_print_commands),
PHPDBG_COMMANDS_D(break, "set breakpoint", 'b', phpdbg_break_commands),
PHPDBG_COMMAND_EX_D(back, "show trace", 't'),
return PHPDBG_FINISH;
} /* }}} */
+static PHPDBG_COMMAND(leave) /* {{{ */
+{
+ return PHPDBG_LEAVE;
+} /* }}} */
+
static PHPDBG_COMMAND(run) /* {{{ */
{
if (EG(in_execution)) {
phpdbg_error("Failed to execute %s!", cmd);
}
break;
-
+
+ case PHPDBG_LEAVE:
case PHPDBG_FINISH:
case PHPDBG_UNTIL:
case PHPDBG_NEXT: {
\
do {\
switch (last_step = phpdbg_interactive(TSRMLS_C)) {\
+ case PHPDBG_LEAVE:\
case PHPDBG_FINISH:\
case PHPDBG_UNTIL:\
case PHPDBG_NEXT:{\
goto next;
}
+ /* run to next line */
if (last_step == PHPDBG_UNTIL
&& last_file == execute_data->op_array->filename
&& last_lineno == execute_data->opline->lineno) {
goto next;
}
+ /* run to finish */
if (last_step == PHPDBG_FINISH) {
if (execute_data->opline < last_op) {
/* skip possible breakpoints */
last_op = NULL;
}
}
+
+ /* break for leave */
+ if (last_step == PHPDBG_LEAVE) {
+ if (execute_data->opline == last_op) {
+ phpdbg_notice(
+ "Breaking for leave at %s:%u",
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C)
+ );
+ DO_INTERACTIVE();
+ } else {
+ /* skip possible breakpoints */
+ goto next;
+ }
+ }
/* not while in conditionals */
phpdbg_print_opline(
execute_data, 0 TSRMLS_CC);
-
+
/* conditions cannot be executed by eval()'d code */
if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)
&& (PHPDBG_G(flags) & PHPDBG_HAS_COND_BP)
next:
last_lineno = execute_data->opline->lineno;
last_file = execute_data->op_array->filename;
-
- if (last_step == PHPDBG_FINISH && !last_op) {
- last_op = &execute_data->op_array->opcodes[execute_data->op_array->last-1];
+
+ switch (last_step) {
+ case PHPDBG_FINISH:
+ if (!last_op) {
+ last_op = &execute_data->op_array->opcodes[execute_data->op_array->last-1];
+ }
+ break;
+
+ case PHPDBG_LEAVE:
+ if (!last_op) {
+ last_op = &execute_data->op_array->opcodes[execute_data->op_array->last-2];
+ }
+ break;
}
PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC);