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 = NULL;
pg->last_params_len = 0; pg->last_params_len = 0;
pg->flags = PHPDBG_DEFAULT_FLAGS; pg->flags = PHPDBG_DEFAULT_FLAGS;
pg->oplog = NULL;
} /* }}} */ } /* }}} */
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
@ -103,6 +104,12 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
efree(PHPDBG_G(exec)); efree(PHPDBG_G(exec));
PHPDBG_G(exec) = NULL; PHPDBG_G(exec) = NULL;
} }
if (PHPDBG_G(oplog)) {
fclose(
PHPDBG_G(oplog));
PHPDBG_G(oplog) = NULL;
}
if (PHPDBG_G(ops)) { if (PHPDBG_G(ops)) {
destroy_op_array(PHPDBG_G(ops) TSRMLS_CC); destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
@ -293,11 +300,12 @@ const opt_struct OPTIONS[] = { /* {{{ */
{'z', 1, "load zend_extension"}, {'z', 1, "load zend_extension"},
/* phpdbg options */ /* phpdbg options */
{'e', 1, "exec"}, {'e', 1, "exec"},
{'v', 0, "verbose"}, {'v', 0, "disable quietness"},
{'s', 0, "step"}, {'s', 0, "enable stepping"},
{'b', 0, "boring colours"}, {'b', 0, "boring colours"},
{'i', 1, "init"}, {'i', 1, "specify init"},
{'I', 0, "ignore-init"}, {'I', 0, "ignore init"},
{'O', 1, "opline log"},
{'-', 0, NULL} {'-', 0, NULL}
}; /* }}} */ }; /* }}} */
@ -333,6 +341,8 @@ int main(int argc, char **argv) /* {{{ */
char *init_file; char *init_file;
size_t init_file_len; size_t init_file_len;
zend_bool init_file_default; zend_bool init_file_default;
char *oplog_file;
size_t oplog_file_len;
zend_ulong flags; zend_ulong flags;
char *php_optarg; char *php_optarg;
int php_optind; int php_optind;
@ -364,6 +374,8 @@ phpdbg_main:
init_file = NULL; init_file = NULL;
init_file_len = 0; init_file_len = 0;
init_file_default = 1; init_file_default = 1;
oplog_file = NULL;
oplog_file_len = 0;
flags = PHPDBG_DEFAULT_FLAGS; flags = PHPDBG_DEFAULT_FLAGS;
php_optarg = NULL; php_optarg = NULL;
php_optind = 1; php_optind = 1;
@ -412,24 +424,33 @@ phpdbg_main:
case 'z': case 'z':
zend_load_extension(php_optarg); zend_load_extension(php_optarg);
break; break;
/* begin phpdbg options */
case 'e': /* set execution context */ case 'e': { /* set execution context */
exec_len = strlen(php_optarg); exec_len = strlen(php_optarg);
if (exec_len) { if (exec_len) {
exec = strdup(php_optarg); exec = strdup(php_optarg);
} }
break; } break;
case 'I': { /* ignore .phpdbginit */ case 'I': { /* ignore .phpdbginit */
init_file_default = 0; init_file_default = 0;
} break; } break;
case 'i': /* set init file */ case 'i': { /* set init file */
init_file_len = strlen(php_optarg); init_file_len = strlen(php_optarg);
if (init_file_len) { if (init_file_len) {
init_file = strdup(php_optarg); 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 */ case 'v': /* set quietness off */
flags &= ~PHPDBG_IS_QUIET; flags &= ~PHPDBG_IS_QUIET;
@ -485,6 +506,15 @@ phpdbg_main:
free(exec); 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 */ /* set flags from command line */
PHPDBG_G(flags) = flags; PHPDBG_G(flags) = flags;

View file

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

View file

@ -26,7 +26,7 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
PHPDBG_HELP(exec) /* {{{ */ 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"); phpdbg_writeln("The execution context must be set before execution can take place");
return SUCCESS; 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("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("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("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_writeln("You do not need to exit phpdbg to retry compilation");
return SUCCESS; return SUCCESS;
@ -99,13 +99,13 @@ PHPDBG_HELP(run) /* {{{ */
PHPDBG_HELP(eval) /* {{{ */ PHPDBG_HELP(eval) /* {{{ */
{ {
phpdbg_writeln("Access to eval() allows you to change the environment during execution, careful though !!"); 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; return SUCCESS;
} /* }}} */ } /* }}} */
PHPDBG_HELP(break) /* {{{ */ 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(EMPTY);
phpdbg_writeln("Examples:"); phpdbg_writeln("Examples:");
phpdbg_writeln("\t%sbreak test.php:1", PROMPT); phpdbg_writeln("\t%sbreak test.php:1", PROMPT);
@ -131,8 +131,8 @@ PHPDBG_HELP(break) /* {{{ */
PHPDBG_HELP(clean) /* {{{ */ PHPDBG_HELP(clean) /* {{{ */
{ {
phpdbg_writeln("While debugging you may experience errors because of attempts to redeclare classes, constants or functions."); 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("Cleaning the environment cleans these tables, so that files can be recompiled without exiting phpdbg");
return SUCCESS; return SUCCESS;
} /* }}} */ } /* }}} */
@ -159,7 +159,7 @@ PHPDBG_HELP(quiet) /* {{{ */
PHPDBG_HELP(back) /* {{{ */ 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(EMPTY);
phpdbg_writeln("Examples:"); phpdbg_writeln("Examples:");
phpdbg_writeln("You can set the limit on the trace"); phpdbg_writeln("You can set the limit on the trace");
@ -170,7 +170,7 @@ PHPDBG_HELP(back) /* {{{ */
PHPDBG_HELP(list) /* {{{ */ 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(EMPTY);
phpdbg_writeln("Examples:"); phpdbg_writeln("Examples:");
phpdbg_writeln("\t%slist 2", PROMPT); 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 !!"); phpdbg_writeln("Note: before listing functions you must have a populated function table, try compile !!");
return SUCCESS; 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(back);
PHPDBG_HELP(quiet); PHPDBG_HELP(quiet);
PHPDBG_HELP(list); PHPDBG_HELP(list);
PHPDBG_HELP(oplog);
/** /**
* Commands * 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(back, "show debug backtrace information during execution"),
PHPDBG_HELP_D(quiet, "be quiet 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(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} {NULL, 0, 0}
}; };

View file

@ -46,6 +46,7 @@ static PHPDBG_COMMAND(clear);
static PHPDBG_COMMAND(help); static PHPDBG_COMMAND(help);
static PHPDBG_COMMAND(quiet); static PHPDBG_COMMAND(quiet);
static PHPDBG_COMMAND(aliases); static PHPDBG_COMMAND(aliases);
static PHPDBG_COMMAND(oplog);
static PHPDBG_COMMAND(quit); /* }}} */ static PHPDBG_COMMAND(quit); /* }}} */
/* {{{ command declarations */ /* {{{ 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(help, "show help menu", 'h'),
PHPDBG_COMMAND_EX_D(quiet, "silence some output", 'Q'), PHPDBG_COMMAND_EX_D(quiet, "silence some output", 'Q'),
PHPDBG_COMMAND_EX_D(aliases, "show alias list", 'a'), 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'), PHPDBG_COMMAND_EX_D(quit, "exit phpdbg", 'q'),
{NULL, 0, 0} {NULL, 0, 0}
}; /* }}} */ }; /* }}} */
@ -496,6 +498,45 @@ static PHPDBG_COMMAND(aliases) /* {{{ */
return SUCCESS; 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) /* {{{ */ static PHPDBG_COMMAND(help) /* {{{ */
{ {
phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", 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-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\t-imy.init\t\tSet the phpdbginit file");
phpdbg_writeln("\t-I\tN/A\t\t\tDisable loading .phpdbginit"); 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); phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
@ -687,14 +729,27 @@ 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 */ /* force out a line while stepping so the user knows what is happening */
if (ignore_flags || if (ignore_flags ||
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (!(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; zend_op *opline = execute_data->opline;
/* output line info */
phpdbg_notice("#%lu %p %s %s", if (ignore_flags ||
opline->lineno, (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
opline, phpdbg_decode_opcode(opline->opcode), (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown"); /* 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");
}
} }
} /* }}} */ } /* }}} */

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; int rc = 0;
char *buffer = NULL; char *buffer = NULL;
@ -175,36 +175,45 @@ int phpdbg_print(int type TSRMLS_DC, const char *format, ...) /* {{{ */
switch (type) { switch (type) {
case P_ERROR: 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[" : "["), ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[1;31m[" : "["),
buffer, buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]")); ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]"));
break; break;
case P_NOTICE: 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[" : "["), ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[1;64m[" : "["),
buffer, buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]")); ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]"));
break; break;
case P_WRITELN: { case P_WRITELN: {
if (buffer) { if (buffer) {
rc = printf("%s%s%s\n", rc = fprintf(fp, "%s%s%s\n",
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""), ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""),
buffer, buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : "")); ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : ""));
} else { } else {
rc = printf("\n"); rc = fprintf(fp, "\n");
} }
} break; } break;
case P_WRITE: if (buffer) { case P_WRITE: if (buffer) {
rc = printf("%s%s%s", rc = fprintf(fp, "%s%s%s",
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""), ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""),
buffer, buffer,
((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : "")); ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : ""));
} break; } 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) { if (buffer) {

View file

@ -66,15 +66,23 @@ enum {
P_ERROR = 1, P_ERROR = 1,
P_NOTICE, P_NOTICE,
P_WRITELN, 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_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, stderr, fmt, ##__VA_ARGS__)
#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, 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, 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, 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 */ /* {{{ For writing blank lines */
#define EMPTY "" /* }}} */ #define EMPTY "" /* }}} */