add opline logging and setup including command line option

This commit is contained in:
krakjoe 2013-11-14 21:10:44 +00:00
parent 365b5db1f6
commit f2212c05c7
7 changed files with 168 additions and 46 deletions

View file

@ -37,6 +37,7 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
pg->last_params = NULL;
pg->last_params_len = 0;
pg->flags = PHPDBG_DEFAULT_FLAGS;
pg->oplog = NULL;
} /* }}} */
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
@ -104,6 +105,12 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
PHPDBG_G(exec) = NULL;
}
if (PHPDBG_G(oplog)) {
fclose(
PHPDBG_G(oplog));
PHPDBG_G(oplog) = NULL;
}
if (PHPDBG_G(ops)) {
destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
efree(PHPDBG_G(ops));
@ -293,11 +300,12 @@ const opt_struct OPTIONS[] = { /* {{{ */
{'z', 1, "load zend_extension"},
/* phpdbg options */
{'e', 1, "exec"},
{'v', 0, "verbose"},
{'s', 0, "step"},
{'v', 0, "disable quietness"},
{'s', 0, "enable stepping"},
{'b', 0, "boring colours"},
{'i', 1, "init"},
{'I', 0, "ignore-init"},
{'i', 1, "specify init"},
{'I', 0, "ignore init"},
{'O', 1, "opline log"},
{'-', 0, NULL}
}; /* }}} */
@ -333,6 +341,8 @@ int main(int argc, char **argv) /* {{{ */
char *init_file;
size_t init_file_len;
zend_bool init_file_default;
char *oplog_file;
size_t oplog_file_len;
zend_ulong flags;
char *php_optarg;
int php_optind;
@ -364,6 +374,8 @@ phpdbg_main:
init_file = NULL;
init_file_len = 0;
init_file_default = 1;
oplog_file = NULL;
oplog_file_len = 0;
flags = PHPDBG_DEFAULT_FLAGS;
php_optarg = NULL;
php_optind = 1;
@ -413,23 +425,32 @@ phpdbg_main:
zend_load_extension(php_optarg);
break;
case 'e': /* set execution context */
/* begin phpdbg options */
case 'e': { /* set execution context */
exec_len = strlen(php_optarg);
if (exec_len) {
exec = strdup(php_optarg);
}
break;
} break;
case 'I': { /* ignore .phpdbginit */
init_file_default = 0;
} break;
case 'i': /* set init file */
case 'i': { /* set init file */
init_file_len = strlen(php_optarg);
if (init_file_len) {
init_file = strdup(php_optarg);
}
break;
} break;
case 'O': { /* set oplog output */
oplog_file_len = strlen(php_optarg);
if (oplog_file_len) {
oplog_file = strdup(php_optarg);
}
} break;
case 'v': /* set quietness off */
flags &= ~PHPDBG_IS_QUIET;
@ -486,6 +507,15 @@ phpdbg_main:
free(exec);
}
if (oplog_file) { /* open oplog */
PHPDBG_G(oplog) = fopen(oplog_file, "w+");
if (!PHPDBG_G(oplog)) {
phpdbg_error(
"Failed to open oplog %s", oplog_file);
}
free(oplog_file);
}
/* set flags from command line */
PHPDBG_G(flags) = flags;

View file

@ -109,6 +109,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
const char *last_params; /* last expression */
size_t last_params_len; /* last expression length */
zend_ulong flags; /* phpdbg flags */
FILE *oplog; /* opline log */
ZEND_END_MODULE_GLOBALS(phpdbg)
#endif /* PHPDBG_H */

View file

@ -26,7 +26,7 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
PHPDBG_HELP(exec) /* {{{ */
{
phpdbg_writeln("Will attempt execution, if compilation has not yet taken place, it occurs now.");
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");
return SUCCESS;
} /* }}} */
@ -53,7 +53,7 @@ PHPDBG_HELP(compile) /* {{{ */
{
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("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");
return SUCCESS;
@ -99,13 +99,13 @@ PHPDBG_HELP(run) /* {{{ */
PHPDBG_HELP(eval) /* {{{ */
{
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_writeln("Note: When using eval in phpdbg do not prefix the code with return");
return SUCCESS;
} /* }}} */
PHPDBG_HELP(break) /* {{{ */
{
phpdbg_writeln("Setting a breakpoint stops execution at a specific stage.");
phpdbg_writeln("Setting a breakpoint stops execution at a specific stage");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Examples:");
phpdbg_writeln("\t%sbreak test.php:1", PROMPT);
@ -131,8 +131,8 @@ PHPDBG_HELP(break) /* {{{ */
PHPDBG_HELP(clean) /* {{{ */
{
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_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");
return SUCCESS;
} /* }}} */
@ -159,7 +159,7 @@ PHPDBG_HELP(quiet) /* {{{ */
PHPDBG_HELP(back) /* {{{ */
{
phpdbg_writeln("The backtrace is gathered with the default debug_backtrace functionality.");
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");
@ -170,7 +170,7 @@ PHPDBG_HELP(back) /* {{{ */
PHPDBG_HELP(list) /* {{{ */
{
phpdbg_writeln("The list command displays N line from current context file.");
phpdbg_writeln("The list command displays N line from current context file");
phpdbg_writeln(EMPTY);
phpdbg_writeln("Examples:");
phpdbg_writeln("\t%slist 2", PROMPT);
@ -183,3 +183,20 @@ PHPDBG_HELP(list) /* {{{ */
phpdbg_writeln("Note: before listing functions you must have a populated function table, try compile !!");
return SUCCESS;
} /* }}} */
PHPDBG_HELP(oplog) /* {{{ */
{
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(EMPTY);
phpdbg_writeln("Example:");
phpdbg_writeln("\t%soplog /path/to/my.oplog", PROMPT);
phpdbg_writeln("Will open the file /path/to/my.oplog for writing, creating it if it does not exist");
phpdbg_writeln("Example:");
phpdbg_writeln("\t%soplog 0", PROMPT);
phpdbg_writeln("Will open 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");
return SUCCESS;
} /* }}} */

View file

@ -47,6 +47,7 @@ PHPDBG_HELP(clear);
PHPDBG_HELP(back);
PHPDBG_HELP(quiet);
PHPDBG_HELP(list);
PHPDBG_HELP(oplog);
/**
* Commands
@ -65,6 +66,7 @@ static const phpdbg_command_t phpdbg_help_commands[] = {
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, "sets a file for, or disables oplog"),
{NULL, 0, 0}
};

View file

@ -46,6 +46,7 @@ static PHPDBG_COMMAND(clear);
static PHPDBG_COMMAND(help);
static PHPDBG_COMMAND(quiet);
static PHPDBG_COMMAND(aliases);
static PHPDBG_COMMAND(oplog);
static PHPDBG_COMMAND(quit); /* }}} */
/* {{{ command declarations */
@ -65,6 +66,7 @@ static const phpdbg_command_t phpdbg_prompt_commands[] = {
PHPDBG_COMMAND_EX_D(help, "show help menu", 'h'),
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'),
PHPDBG_COMMAND_EX_D(quit, "exit phpdbg", 'q'),
{NULL, 0, 0}
}; /* }}} */
@ -496,6 +498,45 @@ static PHPDBG_COMMAND(aliases) /* {{{ */
return SUCCESS;
} /* }}} */
static PHPDBG_COMMAND(oplog) /* {{{ */
{
if (expr && expr_len > 0L) {
/* disable oplog */
if (expr[0] == '0' && expr_len == 1) {
if (PHPDBG_G(oplog)) {
phpdbg_notice("Disabling oplog");
fclose(
PHPDBG_G(oplog));
return SUCCESS;
} else {
phpdbg_error("No oplog currently open");
return FAILURE;
}
} else {
/* open oplog */
FILE *old = PHPDBG_G(oplog);
PHPDBG_G(oplog) = fopen(expr, "w+");
if (!PHPDBG_G(oplog)) {
phpdbg_error("Failed to open %s for oplog", expr);
PHPDBG_G(oplog) = old;
return FAILURE;
} else {
if (old) {
phpdbg_notice("Closing previously open oplog");
fclose(old);
}
phpdbg_notice("Successfully opened oplog");
return SUCCESS;
}
}
} else {
phpdbg_error("No expression provided");
return FAILURE;
}
} /* }}} */
static PHPDBG_COMMAND(help) /* {{{ */
{
phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
@ -538,6 +579,7 @@ static PHPDBG_COMMAND(help) /* {{{ */
phpdbg_writeln("\t-b\tN/A\t\t\tDisable the use of colours");
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_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
@ -687,15 +729,28 @@ void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags
/* force out a line while stepping so the user knows what is happening */
if (ignore_flags ||
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ||
(PHPDBG_G(oplog)))) {
zend_op *opline = execute_data->opline;
if (ignore_flags ||
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
/* output line info */
phpdbg_notice("#%lu %p %s %s",
opline->lineno,
opline, phpdbg_decode_opcode(opline->opcode),
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
}
if (!ignore_flags && PHPDBG_G(oplog)) {
phpdbg_log_ex(PHPDBG_G(oplog), "#%lu %p %s %s",
opline->lineno,
opline, phpdbg_decode_opcode(opline->opcode),
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
}
}
} /* }}} */
void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */

View file

@ -159,7 +159,7 @@ void phpdbg_clear_param(int type, phpdbg_param_t *param TSRMLS_DC) /* {{{ */
}
} /* }}} */
int phpdbg_print(int type TSRMLS_DC, const char *format, ...) /* {{{ */
int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */
{
int rc = 0;
char *buffer = NULL;
@ -175,14 +175,14 @@ int phpdbg_print(int type TSRMLS_DC, const char *format, ...) /* {{{ */
switch (type) {
case P_ERROR:
rc = printf("%s%s%s\n",
rc = fprintf(fp, "%s%s%s\n",
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[1;31m[" : "["),
buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]"));
break;
case P_NOTICE:
rc = printf("%s%s%s\n",
rc = fprintf(fp, "%s%s%s\n",
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[1;64m[" : "["),
buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]"));
@ -190,21 +190,30 @@ int phpdbg_print(int type TSRMLS_DC, const char *format, ...) /* {{{ */
case P_WRITELN: {
if (buffer) {
rc = printf("%s%s%s\n",
rc = fprintf(fp, "%s%s%s\n",
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""),
buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : ""));
} else {
rc = printf("\n");
rc = fprintf(fp, "\n");
}
} break;
case P_WRITE: if (buffer) {
rc = printf("%s%s%s",
rc = fprintf(fp, "%s%s%s",
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""),
buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : ""));
} break;
/* no formatting on logging output */
case P_LOG: if (buffer) {
struct timeval tp;
if (gettimeofday(&tp, NULL) == SUCCESS) {
rc = fprintf(
fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer);
} else rc = FAILURE;
} break;
}
if (buffer) {

View file

@ -66,15 +66,23 @@ enum {
P_ERROR = 1,
P_NOTICE,
P_WRITELN,
P_WRITE
P_WRITE,
P_LOG
};
int phpdbg_print(int TSRMLS_DC, const char*, ...);
int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...);
#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, fmt, ##__VA_ARGS__)
#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, fmt, ##__VA_ARGS__)
#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, fmt, ##__VA_ARGS__)
#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, fmt, ##__VA_ARGS__)
#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, stderr, fmt, ##__VA_ARGS__)
#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, stderr, fmt, ##__VA_ARGS__)
#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, stderr, fmt, ##__VA_ARGS__)
#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, stderr, fmt, ##__VA_ARGS__)
#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, stderr, fmt, ##__VA_ARGS__)
#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__)
#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
#define phpdbg_writeln_ex(out, fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, fmt, ##__VA_ARGS__)
#define phpdbg_write_ex(out, fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__)
/* {{{ For writing blank lines */
#define EMPTY "" /* }}} */