- More work on file:line breakpoint

This commit is contained in:
Felipe Pena 2013-11-10 13:11:56 -02:00
commit 23cfc8ed35
6 changed files with 115 additions and 27 deletions

View file

@ -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) { static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) {
pg->exec = NULL; pg->exec = NULL;
pg->ops = NULL; pg->ops = NULL;
pg->stepping = 0;
} }
static PHP_MINIT_FUNCTION(phpdbg) { static PHP_MINIT_FUNCTION(phpdbg) {

View file

@ -36,14 +36,18 @@
# define PHPDBG_G(v) (phpdbg_globals.v) # define PHPDBG_G(v) (phpdbg_globals.v)
#endif #endif
#define PHPDBG_NEXT 2
ZEND_BEGIN_MODULE_GLOBALS(phpdbg) ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
HashTable break_files; HashTable break_files;
HashTable break_symbols; HashTable break_symbols;
char *exec; /* file to execute */ char *exec; /* file to execute */
size_t exec_len; /* size of exec */ size_t exec_len; /* size of exec */
zend_op_array *ops; /* op_array */ zend_op_array *ops; /* op_array */
zval *retval; /* return value */ zval *retval; /* return value */
zend_bool has_breakpoint; /* breakpoint has been set */ zend_bool stepping; /* stepping */
int vmret; /* return from last opcode handler execution */
zend_bool has_file_bp; /* file-based breakpoint has been set */
ZEND_END_MODULE_GLOBALS(phpdbg) ZEND_END_MODULE_GLOBALS(phpdbg)
#include "phpdbg_prompt.h" #include "phpdbg_prompt.h"

View file

@ -30,6 +30,20 @@ PHPDBG_HELP(exec) /* {{{ */
return SUCCESS; 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) /* {{{ */ PHPDBG_HELP(compile) /* {{{ */
{ {
printf("Pre-compilation of the execution context provides the opportunity to inspect the opcodes before they are executed\n"); 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("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("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("Will show the opline @ 0\n");
printf("Available print commands:\n"); printf("Available print commands:\n");
printf("\tNone\n"); printf("\tNone\n");
@ -51,6 +65,13 @@ PHPDBG_HELP(print) /* {{{ */
return SUCCESS; return SUCCESS;
} /* }}} */ } /* }}} */
PHPDBG_HELP(run) /* {{{ */
{
printf("Run the code inside the debug vm, you should have break points and variables set before running\n");
printf("The execution context must not be set, but not necessarily compiled before execution occurs\n");
return SUCCESS;
} /* }}} */
PHPDBG_HELP(break) /* {{{ */ PHPDBG_HELP(break) /* {{{ */
{ {
printf("doing break help: %s\n", expr); printf("doing break help: %s\n", expr);

View file

@ -33,6 +33,9 @@
*/ */
PHPDBG_HELP(exec); PHPDBG_HELP(exec);
PHPDBG_HELP(compile); PHPDBG_HELP(compile);
PHPDBG_HELP(step);
PHPDBG_HELP(next);
PHPDBG_HELP(run);
PHPDBG_HELP(print); PHPDBG_HELP(print);
PHPDBG_HELP(break); PHPDBG_HELP(break);
@ -42,6 +45,9 @@ PHPDBG_HELP(break);
static const phpdbg_command_t phpdbg_help_commands[] = { static const phpdbg_command_t phpdbg_help_commands[] = {
PHPDBG_HELP_D(exec, "the execution context should be a valid phpdbg path"), 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(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(print, "printing allows inspection of the execution environment"),
PHPDBG_HELP_D(break, "breakpoints allow execution interruption"), PHPDBG_HELP_D(break, "breakpoints allow execution interruption"),
{NULL, 0, 0} {NULL, 0, 0}

View file

@ -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) { /* {{{ */ static PHPDBG_COMMAND(run) { /* {{{ */
if (PHPDBG_G(ops) || PHPDBG_G(exec)) { if (PHPDBG_G(ops) || PHPDBG_G(exec)) {
if (!PHPDBG_G(ops)) { if (!PHPDBG_G(ops)) {
@ -116,9 +125,12 @@ static PHPDBG_COMMAND(print) { /* {{{ */
printf("Showing Execution Context Information:\n"); printf("Showing Execution Context Information:\n");
printf("Exec\t\t%s\n", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); printf("Exec\t\t%s\n", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none");
printf("Compiled\t%s\n", PHPDBG_G(ops) ? "yes" : "no"); printf("Compiled\t%s\n", PHPDBG_G(ops) ? "yes" : "no");
printf("Stepping\t%s\n", PHPDBG_G(stepping) ? "on" : "off");
if (PHPDBG_G(ops)) { if (PHPDBG_G(ops)) {
printf("Opcodes\t\t%d\n", PHPDBG_G(ops)->last-1); printf("Opcodes\t\t%d\n", PHPDBG_G(ops)->last);
printf("Variables\t%d\n", PHPDBG_G(ops)->last_var-1); if (PHPDBG_G(ops)->last_var) {
printf("Variables\t%d\n", PHPDBG_G(ops)->last_var-1);
} else printf("Variables\tNone\n");
} }
} else { } else {
printf( printf(
@ -135,17 +147,24 @@ static PHPDBG_COMMAND(break) /* {{{ */
if (line_pos) { if (line_pos) {
long line_num = strtol(line_pos+1, NULL, 0); long line_num = strtol(line_pos+1, NULL, 0);
phpdbg_breakfile_t new_break; phpdbg_breakfile_t new_break;
zend_llist break_files; zend_llist *break_files_ptr;
new_break.filename = estrndup(expr, line_pos - expr); size_t name_len = line_pos - expr;
new_break.filename = estrndup(expr, name_len);
new_break.line = line_num; new_break.line = line_num;
PHPDBG_G(has_breakpoint) = 1; PHPDBG_G(has_file_bp) = 1;
if (zend_hash_find(&PHPDBG_G(break_files), new_break.filename, line_pos - expr, &break_files) == FAILURE) { if (zend_hash_find(&PHPDBG_G(break_files),
new_break.filename, name_len, (void**)&break_files_ptr) == FAILURE) {
zend_llist break_files;
zend_llist_init(&break_files, sizeof(phpdbg_breakfile_t), NULL, 0); zend_llist_init(&break_files, sizeof(phpdbg_breakfile_t), NULL, 0);
zend_hash_update(&PHPDBG_G(break_files),
new_break.filename, name_len, &break_files, sizeof(zend_llist), (void**)&break_files_ptr);
} }
zend_llist_add_element(&break_files, &new_break); zend_llist_add_element(break_files_ptr, &new_break);
} }
return SUCCESS; return SUCCESS;
@ -194,6 +213,8 @@ static PHPDBG_COMMAND(help) /* {{{ */
static const phpdbg_command_t phpdbg_prompt_commands[] = { static const phpdbg_command_t phpdbg_prompt_commands[] = {
PHPDBG_COMMAND_D(exec, "set execution context"), PHPDBG_COMMAND_D(exec, "set execution context"),
PHPDBG_COMMAND_D(compile, "attempt to pre-compile 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(run, "attempt execution"),
PHPDBG_COMMAND_D(print, "print something"), PHPDBG_COMMAND_D(print, "print something"),
PHPDBG_COMMAND_D(break, "set breakpoint"), PHPDBG_COMMAND_D(break, "set breakpoint"),
@ -219,12 +240,29 @@ int phpdbg_do_cmd(const phpdbg_command_t *command, char *cmd_line, size_t cmd_le
return FAILURE; return FAILURE;
} /* }}} */ } /* }}} */
void phpdbg_breakpoint(zend_op_array *op_array) /* {{{ */ int phpdbg_breakpoint(zend_op_array *op_array TSRMLS_DC) /* {{{ */
{ {
printf(">> %s\n", op_array->filename); size_t name_len = strlen(op_array->filename);
zend_llist *break_list;
if (zend_hash_find(&PHPDBG_G(break_files), op_array->filename, name_len,
(void**)&break_list) == SUCCESS) {
zend_llist_element *le;
for (le = break_list->head; le; le = le->next) {
phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) le->data;
if (bp->line == (*EG(opline_ptr))->lineno) {
printf("breakpoint reached!\n");
return SUCCESS;
}
}
}
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]; char cmd[PHPDBG_MAX_CMD];
@ -238,13 +276,20 @@ void phpdbg_interactive(int argc, char **argv TSRMLS_DC) /* {{{ */
} }
if (cmd_len) { if (cmd_len) {
if (phpdbg_do_cmd(phpdbg_prompt_commands, cmd, cmd_len TSRMLS_CC) == FAILURE) { switch (phpdbg_do_cmd(phpdbg_prompt_commands, cmd, cmd_len TSRMLS_CC)) {
printf("error executing %s !\n", cmd); case FAILURE:
} printf("error executing %s !\n", cmd);
break;
case PHPDBG_NEXT:
return PHPDBG_NEXT;
}
} }
printf("phpdbg> "); printf("phpdbg> ");
} }
return SUCCESS;
} /* }}} */ } /* }}} */
void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC)
@ -260,7 +305,6 @@ zend_vm_enter:
} }
while (1) { while (1) {
int ret;
#ifdef ZEND_WIN32 #ifdef ZEND_WIN32
if (EG(timed_out)) { if (EG(timed_out)) {
zend_timeout(0); zend_timeout(0);
@ -269,12 +313,24 @@ zend_vm_enter:
printf("[OPLINE: %p]\n", execute_data->opline); printf("[OPLINE: %p]\n", execute_data->opline);
if (PHPDBG_G(has_breakpoint)) { if (PHPDBG_G(has_file_bp)
phpdbg_breakpoint(execute_data->op_array); && phpdbg_breakpoint(execute_data->op_array TSRMLS_CC) == SUCCESS) {
while (phpdbg_interactive(0, NULL TSRMLS_CC) != PHPDBG_NEXT) {
continue;
}
} }
if ((ret = execute_data->opline->handler(execute_data TSRMLS_CC)) > 0) { PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC);
switch (ret) {
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: case 1:
EG(in_execution) = original_in_execution; EG(in_execution) = original_in_execution;
return; return;

View file

@ -72,7 +72,7 @@ int phpdbg_do_cmd(const phpdbg_command_t *command, char *cmd_line, size_t cmd_le
#define PHPDBG_COMMAND(name) \ #define PHPDBG_COMMAND(name) \
int phpdbg_do_##name(const char *expr, size_t expr_len TSRMLS_DC) 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); void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC);
#endif /* PHPDBG_PROMPT_H */ #endif /* PHPDBG_PROMPT_H */