pg->last_params = NULL;
pg->last_params_len = 0;
pg->flags = PHPDBG_DEFAULT_FLAGS;
+ pg->oplog = NULL;
} /* }}} */
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
efree(PHPDBG_G(exec));
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);
{'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}
}; /* }}} */
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;
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;
case 'z':
zend_load_extension(php_optarg);
break;
+
+ /* begin phpdbg options */
- case 'e': /* set execution context */
+ 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;
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;
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 */
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;
} /* }}} */
{
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;
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);
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;
} /* }}} */
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");
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);
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;
+} /* }}} */
PHPDBG_HELP(back);
PHPDBG_HELP(quiet);
PHPDBG_HELP(list);
+PHPDBG_HELP(oplog);
/**
* 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}
};
static PHPDBG_COMMAND(help);
static PHPDBG_COMMAND(quiet);
static PHPDBG_COMMAND(aliases);
+static PHPDBG_COMMAND(oplog);
static PHPDBG_COMMAND(quit); /* }}} */
/* {{{ command declarations */
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}
}; /* }}} */
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",
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);
/* 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;
- /* 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(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");
+ }
}
} /* }}} */
}
} /* }}} */
-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;
switch (type) {
case P_ERROR:
- rc = printf("%s%s%s\n",
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[1;31m[" : "["),
- buffer,
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]"));
+ 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",
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[1;64m[" : "["),
- buffer,
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "]\033[0m" : "]"));
+ 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" : "]"));
break;
case P_WRITELN: {
if (buffer) {
- rc = printf("%s%s%s\n",
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""),
- buffer,
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : ""));
+ 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",
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[37m" : ""),
- buffer,
- ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED) ? "\033[0m" : ""));
+ 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) {
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 "" /* }}} */