------------------------
1. Added until/u command
+2. Added printers for class and method
+3. Make uniform commands and aliases where possible
+4. Include all alias information and sub-command information in help
Version 0.0.1 2013-11-15
size_t tip_len; /* Menu tip length */
char alias; /* Alias */
phpdbg_command_handler_t handler; /* Command handler */
+ const phpdbg_command_t *subs; /* Sub Commands */
};
ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
* Command Declarators
*/
#define PHPDBG_BREAK_D(name, tip) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, 0, phpdbg_do_break_##name}
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, 0, phpdbg_do_break_##name, NULL}
#define PHPDBG_BREAK_EX_D(name, tip, alias) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_break_##name}
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_break_##name, NULL}
#define PHPDBG_BREAK(name) \
int phpdbg_do_break_##name(phpdbg_param_t *param TSRMLS_DC)
PHPDBG_HELP(exec) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Will attempt execution, if compilation has not yet taken place, it occurs now");
phpdbg_writeln("The execution context must be set before execution can take place");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(step) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("You can enable and disable stepping at any phpdbg prompt during execution");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Examples:");
phpdbg_writeln("Will enable stepping");
phpdbg_writeln(EMPTY);
phpdbg_writeln("While stepping is enabled you are presented with a prompt after the execution of each opcode");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
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_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_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(compile) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Pre-compilation of the execution context provides the opportunity to inspect the opcodes before they are executed");
phpdbg_writeln("The execution context must be set for compilation to succeed");
phpdbg_writeln("If errors occur during compilation they must be resolved before execution can take place");
phpdbg_writeln("It is a good idea to clean the environment between each compilation with the clean command");
phpdbg_writeln("You do not need to exit phpdbg to retry compilation");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(print) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("By default, print will show information about the current execution environment");
phpdbg_writeln("Other printing commands give access to address, file and line information");
phpdbg_writeln(EMPTY);
++print_command;
}
}
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(run) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Run the code inside the debug vm, you should have break points and variables set before running");
phpdbg_writeln("The execution context must not be set, but not necessarily compiled before execution occurs");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(eval) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Access to eval() allows you to change the environment during execution, careful though !!");
phpdbg_writeln("Note: When using eval in phpdbg do not prefix the code with return");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(break) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Setting a breakpoint stops execution at a specific stage");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Examples:");
}
}
phpdbg_writeln("Conditional breaks are costly, use them sparingly !!");
-
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(clean) /* {{{ */
-{
+{
+ phpdbg_help_header();
phpdbg_writeln("While debugging you may experience errors because of attempts to redeclare classes, constants or functions");
phpdbg_writeln("Cleaning the environment cleans these tables, so that files can be recompiled without exiting phpdbg");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(clear) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Clearing breakpoints means you can once again run code without interruption");
phpdbg_writeln("Careful though, all breakpoints are lost; be sure debugging is complete before clearing");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(quiet) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Setting quietness on will stop the OPLINE output during execution");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Examples:");
phpdbg_writeln("Will enable OPLINE output again");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Quietness is disabled while stepping through execution automatically");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(back) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("The backtrace is gathered with the default debug_backtrace functionality");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Examples:");
phpdbg_writeln("You can set the limit on the trace");
phpdbg_writeln("\t%sback 5", PROMPT);
phpdbg_writeln("Will limit the number of frames to 5, the default is no limit");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(list) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("The list command displays source code for the given argument");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Examples:");
++list_command;
}
}
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
PHPDBG_HELP(oplog) /* {{{ */
{
+ phpdbg_help_header();
phpdbg_writeln("Even when quietness is enabled you may wish to save opline logs to a file");
phpdbg_writeln("Setting a new oplog closes the previously open log");
phpdbg_writeln("The log includes a high resolution timestamp on each entry");
phpdbg_writeln("Will close the currently open log file, disabling oplog");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Note: upon failure to open a new oplog, the last oplog is held open");
+ phpdbg_help_footer();
return SUCCESS;
} /* }}} */
/**
* Command Declarators
*/
-#define PHPDBG_HELP_D(name, tip) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, 0, phpdbg_do_help_##name}
+#define PHPDBG_HELP_D(name, tip, alias) \
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_help_##name, NULL}
#define PHPDBG_HELP(name) \
int phpdbg_do_help_##name(phpdbg_param_t *param TSRMLS_DC)
* Commands
*/
static const phpdbg_command_t phpdbg_help_commands[] = {
- PHPDBG_HELP_D(exec, "the execution context should be a valid 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 as it is executed"),
- PHPDBG_HELP_D(next, "continue executing while stepping or after breaking"),
- PHPDBG_HELP_D(run, "execution inside the phpdbg vm allows detailed inspection and debugging"),
- PHPDBG_HELP_D(eval, "access to eval() allows you to affect the environment during execution"),
- PHPDBG_HELP_D(until, "continue until the program reaches a source line different than the current one"),
- PHPDBG_HELP_D(print, "printing allows inspection of the execution environment"),
- PHPDBG_HELP_D(break, "breakpoints allow execution interruption"),
- PHPDBG_HELP_D(clean, "resetting the environment is useful while debugging and recompiling"),
- PHPDBG_HELP_D(clear, "clearing breakpoints allows you to run code without interruption"),
- PHPDBG_HELP_D(back, "show debug backtrace information during execution"),
- PHPDBG_HELP_D(quiet, "be quiet during execution"),
- PHPDBG_HELP_D(list, "listing code gives you quick access to code while executing"),
- PHPDBG_HELP_D(oplog, "keep clutter off the screen by sending oplogs to a file"),
+ PHPDBG_HELP_D(exec, "the execution context should be a valid path", 'e'),
+ PHPDBG_HELP_D(compile, "pre-compilation allows inspection of code before execution", 'c'),
+ PHPDBG_HELP_D(step, "stepping through execution allows inspection of the opline as it is executed", 's'),
+ PHPDBG_HELP_D(next, "continue executing while stepping or after breaking", 'n'),
+ PHPDBG_HELP_D(run, "execution inside the phpdbg vm allows detailed inspection and debugging", 'r'),
+ 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(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'),
+ PHPDBG_HELP_D(clear, "clearing breakpoints allows you to run code without interruption", 'c'),
+ PHPDBG_HELP_D(back, "show debug backtrace information during execution", 't'),
+ PHPDBG_HELP_D(quiet, "be quiet during execution", 's'),
+ PHPDBG_HELP_D(list, "listing code gives you quick access to code while executing", 'l'),
+ PHPDBG_HELP_D(oplog, "keep clutter off the screen by sending oplogs to a file", 'O'),
{NULL, 0, 0}
};
+#define phpdbg_help_header() \
+ phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
+#define phpdbg_help_footer() \
+ phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
+
#endif /* PHPDBG_HELP_H */
* Command Declarators
*/
#define PHPDBG_LIST_D(name, tip) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, 0, phpdbg_do_list_##name}
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, 0, phpdbg_do_list_##name, NULL}
#define PHPDBG_LIST_EX_D(name, tip, alias) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_list_##name}
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_list_##name, NULL}
#define PHPDBG_LIST(name) \
int phpdbg_do_list_##name(phpdbg_param_t *param TSRMLS_DC)
* Command Declarators
*/
#define PHPDBG_PRINT_D(name, tip, alias) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_print_##name}
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_print_##name, NULL}
#define PHPDBG_PRINT(name) \
int phpdbg_do_print_##name(phpdbg_param_t *param TSRMLS_DC)
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(print, "print something", 'p'),
- PHPDBG_COMMAND_EX_D(break, "set breakpoint", 'b'),
+ 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'),
- PHPDBG_COMMAND_EX_D(list, "list specified line or function", 'l'),
+ PHPDBG_COMMANDS_D(list, "lists some code", 'l', phpdbg_list_commands),
PHPDBG_COMMAND_EX_D(clean, "clean the execution environment", 'X'),
PHPDBG_COMMAND_EX_D(clear, "clear breakpoints", 'C'),
- PHPDBG_COMMAND_EX_D(help, "show help menu", 'h'),
+ PHPDBG_COMMANDS_D(help, "show help menu", 'h', phpdbg_help_commands),
PHPDBG_COMMAND_EX_D(quiet, "silence some output", 'Q'),
PHPDBG_COMMAND_EX_D(aliases, "show alias list", 'a'),
PHPDBG_COMMAND_EX_D(oplog, "sets oplog output", 'O'),
static PHPDBG_COMMAND(back) /* {{{ */
{
- zval zbacktrace;
- zval **tmp;
- HashPosition position;
- int i = 0, limit = 0;
-
- if (!EG(in_execution)) {
- phpdbg_error("Not executing!");
- return FAILURE;
- }
-
- limit = (param->type == NUMERIC_PARAM) ? param->num : 0;
-
- zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit TSRMLS_CC);
-
- for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
- zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position) == SUCCESS;
- zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position)) {
- if (i++) {
- phpdbg_writeln(",");
- }
- zend_print_flat_zval_r(*tmp TSRMLS_CC);
- }
+ if (!EG(in_execution)) {
+ phpdbg_error("Not executing!");
+ return FAILURE;
+ }
- phpdbg_writeln(EMPTY);
- zval_dtor(&zbacktrace);
+ switch (param->type) {
+ case EMPTY_PARAM:
+ case NUMERIC_PARAM: {
+ zval zbacktrace;
+ zval **tmp;
+ HashPosition position;
+ int i = 0,
+ limit = (param->type == NUMERIC_PARAM) ? param->num : 0;
+
+ zend_fetch_debug_backtrace(
+ &zbacktrace, 0, 0, limit TSRMLS_CC);
+
+ for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
+ zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position) == SUCCESS;
+ zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position)) {
+ if (i++) {
+ phpdbg_writeln(",");
+ }
+ zend_print_flat_zval_r(*tmp TSRMLS_CC);
+ }
- return SUCCESS;
+ phpdbg_writeln(EMPTY);
+ zval_dtor(&zbacktrace);
+
+ return SUCCESS;
+ } break;
+
+ default: {
+ phpdbg_error(
+ "Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC));
+ return FAILURE;
+ }
+ }
} /* }}} */
static PHPDBG_COMMAND(print) /* {{{ */
phpdbg_writeln(SEPARATE);
} else {
- if (param->type == STR_PARAM) {
- if (phpdbg_do_cmd(phpdbg_print_commands, param->str, param->len TSRMLS_CC) == FAILURE) {
- phpdbg_error("Failed to find print command %s", param->str);
- return FAILURE;
- }
- } else {
- phpdbg_error("You must use a specific printer");
- }
+ phpdbg_error("You must use a specific printer");
}
return SUCCESS;
static PHPDBG_COMMAND(break) /* {{{ */
{
- if (param->type == EMPTY_PARAM) {
- phpdbg_error("No expression found");
- return FAILURE;
- }
-
- /* allow advanced breakers to run */
- if (param->type == STR_PARAM &&
- phpdbg_do_cmd(phpdbg_break_commands, param->str, param->len TSRMLS_CC) == SUCCESS) {
- return SUCCESS;
- }
-
switch (param->type) {
case ADDR_PARAM:
phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC);
{
const phpdbg_command_t *prompt_command = phpdbg_prompt_commands;
- phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
- PHPDBG_VERSION);
-
- phpdbg_notice("Aliases");
-
+ phpdbg_help_header();
+ phpdbg_writeln("Below are the aliased, short versions of all supported commands");
while (prompt_command && prompt_command->name) {
if (prompt_command->alias) {
- phpdbg_writeln("\t%c -> %s\t%s", prompt_command->alias,
- prompt_command->name, prompt_command->tip);
+ if (prompt_command->subs) {
+ const phpdbg_command_t *sub_command = prompt_command->subs;
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%c -> %s", prompt_command->alias, prompt_command->name);
+ while (sub_command && sub_command->name) {
+ if (sub_command->alias) {
+ phpdbg_writeln("\t|------- %c -> %s\t%s", sub_command->alias,
+ sub_command->name, sub_command->tip);
+ }
+ ++sub_command;
+ }
+ phpdbg_writeln(EMPTY);
+ } else {
+ phpdbg_writeln("\t%c -> %s\t%s", prompt_command->alias,
+ prompt_command->name, prompt_command->tip);
+ }
}
+
++prompt_command;
}
-
- phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
+ phpdbg_help_footer();
+
return SUCCESS;
} /* }}} */
static PHPDBG_COMMAND(help) /* {{{ */
{
- phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
- PHPDBG_VERSION);
-
- if (param->type == STR_PARAM) {
- if (phpdbg_do_cmd(phpdbg_help_commands, param->str, param->len TSRMLS_CC) == FAILURE) {
- phpdbg_error("Failed to find help command: %s", param->str);
- }
- } else {
+ if (param->type == EMPTY_PARAM) {
const phpdbg_command_t *prompt_command = phpdbg_prompt_commands;
const phpdbg_command_t *help_command = phpdbg_help_commands;
-
+
+ phpdbg_help_header();
phpdbg_writeln("To get help regarding a specific command type \"help command\"");
phpdbg_notice("Commands");
phpdbg_writeln("\t-i\t-imy.init\t\tSet the phpdbginit file");
phpdbg_writeln("\t-I\tN/A\t\t\tDisable loading .phpdbginit");
phpdbg_writeln("\t-O\t-Omy.oplog\t\tSets oplog output file");
+ phpdbg_help_footer();
+ } else {
+ phpdbg_error(
+ "Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC));
+ return FAILURE;
}
- phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
-
return SUCCESS;
} /* }}} */
static PHPDBG_COMMAND(list) /* {{{ */
{
- /* allow advanced listers to run */
- if (param->type == STR_PARAM &&
- phpdbg_do_cmd(phpdbg_list_commands, param->str, param->len TSRMLS_CC) == SUCCESS) {
- return SUCCESS;
- }
-
phpdbg_list_dispatch(param TSRMLS_CC);
return SUCCESS;
if ((command->name_len == expr_len
&& memcmp(cmd, command->name, expr_len) == 0)
|| ((expr_len == 1) && (command->alias && command->alias == cmd_line[0]))) {
-
+
phpdbg_param_t *param = emalloc(sizeof(phpdbg_param_t));
-
+
PHPDBG_G(last) = (phpdbg_command_t*) command;
-
+
/* urm ... */
if (PHPDBG_G(lparam)) {
//phpdbg_clear_param(
}
phpdbg_parse_param(
- expr,
+ expr,
(cmd_len - expr_len) ? (((cmd_len - expr_len) - sizeof(" "))+1) : 0,
param TSRMLS_CC);
PHPDBG_G(lparam) = param;
-
+
+ if (command->subs && (param->type == STR_PARAM)) {
+ if (phpdbg_do_cmd(command->subs, param->str, param->len TSRMLS_CC) == SUCCESS) {
+ rc = SUCCESS;
+ break;
+ }
+ }
+
phpdbg_debug("phpdbg_do_cmd(%s, \"%s\")",
command->name, phpdbg_get_param_type(param TSRMLS_CC));
* Command Declarators
*/
#define PHPDBG_COMMAND_D(name, tip) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, 0, phpdbg_do_##name}
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, 0, phpdbg_do_##name, NULL}
#define PHPDBG_COMMAND_EX_D(name, tip, alias) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name}
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, NULL}
+#define PHPDBG_COMMANDS_D(name, tip, alias, children) \
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children}
#define PHPDBG_COMMAND(name) \
int phpdbg_do_##name(phpdbg_param_t *param TSRMLS_DC)