Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tag: XDEBUG_2_1_1RC1
Fetching contributors…

Cannot retrieve contributors at this time

461 lines (394 sloc) 12.83 kb
/*
+----------------------------------------------------------------------+
| Xdebug |
+----------------------------------------------------------------------+
| Copyright (c) 2002-2010 Derick Rethans |
+----------------------------------------------------------------------+
| This source file is subject to version 1.0 of the Xdebug license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://xdebug.derickrethans.nl/license.php |
| If you did not receive a copy of the Xdebug license and are unable |
| to obtain it through the world-wide-web, please send a note to |
| xdebug@derickrethans.nl so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick@xdebug.org> |
+----------------------------------------------------------------------+
*/
#include "php_xdebug.h"
#include "xdebug_private.h"
#include "xdebug_str.h"
#include "xdebug_tracing.h"
#include "xdebug_var.h"
ZEND_EXTERN_MODULE_GLOBALS(xdebug)
static char* return_trace_stack_frame_begin(function_stack_entry* i, int fnr TSRMLS_DC);
static char* return_trace_stack_frame_end(function_stack_entry* i, int fnr TSRMLS_DC);
void xdebug_trace_function_begin(function_stack_entry *fse, int function_nr TSRMLS_DC)
{
if (XG(do_trace) && XG(trace_file)) {
char *t = return_trace_stack_frame_begin(fse, function_nr TSRMLS_CC);
if (fprintf(XG(trace_file), "%s", t) < 0) {
fclose(XG(trace_file));
XG(trace_file) = NULL;
} else {
fflush(XG(trace_file));
}
xdfree(t);
}
}
void xdebug_trace_function_end(function_stack_entry *fse, int function_nr TSRMLS_DC)
{
if (XG(do_trace) && XG(trace_file)) {
char *t = return_trace_stack_frame_end(fse, function_nr TSRMLS_CC);
if (fprintf(XG(trace_file), "%s", t) < 0) {
fclose(XG(trace_file));
XG(trace_file) = NULL;
} else {
fflush(XG(trace_file));
}
xdfree(t);
}
}
char* xdebug_return_trace_assignment(function_stack_entry *i, char *varname, zval *retval, char *op, char *filename, int lineno TSRMLS_DC)
{
int j = 0;
xdebug_str str = {0, 0, NULL};
char *tmp_value;
if (XG(trace_format) != 0) {
return xdstrdup("");
}
xdebug_str_addl(&str, " ", 20, 0);
if (XG(show_mem_delta)) {
xdebug_str_addl(&str, " ", 8, 0);
}
for (j = 0; j < i->level; j++) {
xdebug_str_addl(&str, " ", 2, 0);
}
xdebug_str_addl(&str, " => ", 6, 0);
xdebug_str_add(&str, varname, 0);
if (op[0] != '\0' ) { // pre/post inc/dec ops are special
xdebug_str_add(&str, xdebug_sprintf(" %s ", op), 1);
tmp_value = xdebug_get_zval_value(retval, 0, NULL);
if (tmp_value) {
xdebug_str_add(&str, tmp_value, 1);
} else {
xdebug_str_addl(&str, "NULL", 4, 0);
}
}
xdebug_str_add(&str, xdebug_sprintf(" %s:%d\n", filename, lineno), 1);
return str.d;
}
char* xdebug_return_trace_stack_retval(function_stack_entry* i, zval* retval TSRMLS_DC)
{
int j = 0; /* Counter */
xdebug_str str = {0, 0, NULL};
char *tmp_value;
if (XG(trace_format) != 0) {
return xdstrdup("");
}
xdebug_str_addl(&str, " ", 20, 0);
if (XG(show_mem_delta)) {
xdebug_str_addl(&str, " ", 8, 0);
}
for (j = 0; j < i->level; j++) {
xdebug_str_addl(&str, " ", 2, 0);
}
xdebug_str_addl(&str, " >=> ", 7, 0);
tmp_value = xdebug_get_zval_value(retval, 0, NULL);
if (tmp_value) {
xdebug_str_add(&str, tmp_value, 1);
}
xdebug_str_addl(&str, "\n", 2, 0);
return str.d;
}
static char* return_trace_stack_frame_begin_normal(function_stack_entry* i TSRMLS_DC)
{
int c = 0; /* Comma flag */
int j = 0; /* Counter */
char *tmp_name;
xdebug_str str = {0, 0, NULL};
tmp_name = xdebug_show_fname(i->function, 0, 0 TSRMLS_CC);
xdebug_str_add(&str, xdebug_sprintf("%10.4f ", i->time - XG(start_time)), 1);
xdebug_str_add(&str, xdebug_sprintf("%10lu ", i->memory), 1);
if (XG(show_mem_delta)) {
xdebug_str_add(&str, xdebug_sprintf("%+8ld ", i->memory - i->prev_memory), 1);
}
for (j = 0; j < i->level; j++) {
xdebug_str_addl(&str, " ", 2, 0);
}
xdebug_str_add(&str, xdebug_sprintf("-> %s(", tmp_name), 1);
xdfree(tmp_name);
/* Printing vars */
if (XG(collect_params) > 0) {
for (j = 0; j < i->varc; j++) {
char *tmp_value;
if (c) {
xdebug_str_addl(&str, ", ", 2, 0);
} else {
c = 1;
}
if (i->var[j].name && XG(collect_params) >= 4) {
xdebug_str_add(&str, xdebug_sprintf("$%s = ", i->var[j].name), 1);
}
switch (XG(collect_params)) {
case 1: // synopsis
case 2:
tmp_value = xdebug_get_zval_synopsis(i->var[j].addr, 0, NULL);
break;
case 3:
default:
tmp_value = xdebug_get_zval_value(i->var[j].addr, 0, NULL);
break;
}
if (tmp_value) {
xdebug_str_add(&str, tmp_value, 1);
} else {
xdebug_str_add(&str, "???", 0);
}
}
}
if (i->include_filename) {
xdebug_str_add(&str, i->include_filename, 0);
}
xdebug_str_add(&str, xdebug_sprintf(") %s:%d\n", i->filename, i->lineno), 1);
return str.d;
}
#define return_trace_stack_frame_begin_computerized(i,f) return_trace_stack_frame_computerized((i), (f), 0 TSRMLS_CC)
#define return_trace_stack_frame_end_computerized(i,f) return_trace_stack_frame_computerized((i), (f), 1 TSRMLS_CC)
static char* return_trace_stack_frame_computerized(function_stack_entry* i, int fnr, int whence TSRMLS_DC)
{
char *tmp_name;
xdebug_str str = {0, 0, NULL};
xdebug_str_add(&str, xdebug_sprintf("%d\t", i->level), 1);
xdebug_str_add(&str, xdebug_sprintf("%d\t", fnr), 1);
if (whence == 0) { /* start */
tmp_name = xdebug_show_fname(i->function, 0, 0 TSRMLS_CC);
xdebug_str_add(&str, "0\t", 0);
xdebug_str_add(&str, xdebug_sprintf("%f\t", i->time - XG(start_time)), 1);
#if HAVE_PHP_MEMORY_USAGE
xdebug_str_add(&str, xdebug_sprintf("%lu\t", i->memory), 1);
#else
xdebug_str_add(&str, "\t", 0);
#endif
xdebug_str_add(&str, xdebug_sprintf("%s\t", tmp_name), 1);
xdebug_str_add(&str, xdebug_sprintf("%d\t", i->user_defined == XDEBUG_EXTERNAL ? 1 : 0), 1);
xdfree(tmp_name);
if (i->include_filename) {
xdebug_str_add(&str, i->include_filename, 0);
}
/* Filename and Lineno (9, 10) */
xdebug_str_add(&str, xdebug_sprintf("\t%s\t%d", i->filename, i->lineno), 1);
if (XG(collect_params) > 0) {
int j = 0; /* Counter */
/* Nr of arguments (11) */
xdebug_str_add(&str, xdebug_sprintf("\t%d", i->varc), 1);
/* Arguments (12-...) */
for (j = 0; j < i->varc; j++) {
char *tmp_value;
xdebug_str_addl(&str, "\t", 1, 0);
if (i->var[j].name && XG(collect_params) >= 4) {
xdebug_str_add(&str, xdebug_sprintf("$%s = ", i->var[j].name), 1);
}
switch (XG(collect_params)) {
case 1: // synopsis
case 2:
tmp_value = xdebug_get_zval_synopsis(i->var[j].addr, 0, NULL);
break;
case 3:
default:
tmp_value = xdebug_get_zval_value(i->var[j].addr, 0, NULL);
break;
}
if (tmp_value) {
xdebug_str_add(&str, tmp_value, 1);
} else {
xdebug_str_add(&str, "???", 0);
}
}
}
/* Trailing \n */
xdebug_str_add(&str, "\n", 0);
} else if (whence == 1) { /* end */
xdebug_str_add(&str, "1\t", 0);
xdebug_str_add(&str, xdebug_sprintf("%f\t", xdebug_get_utime() - XG(start_time)), 1);
#if HAVE_PHP_MEMORY_USAGE
xdebug_str_add(&str, xdebug_sprintf("%lu\n", XG_MEMORY_USAGE()), 1);
#else
xdebug_str_add(&str, "\n", 0);
#endif
}
return str.d;
}
static char* return_trace_stack_frame_begin_html(function_stack_entry* i, int fnr TSRMLS_DC)
{
char *tmp_name;
int j;
xdebug_str str = {0, 0, NULL};
xdebug_str_add(&str, "\t<tr>", 0);
xdebug_str_add(&str, xdebug_sprintf("<td>%d</td>", fnr), 1);
xdebug_str_add(&str, xdebug_sprintf("<td>%0.6f</td>", i->time - XG(start_time)), 1);
#if MEMORY_LIMIT
xdebug_str_add(&str, xdebug_sprintf("<td align='right'>%lu</td>", i->memory), 1);
#endif
xdebug_str_add(&str, "<td align='left'>", 0);
for (j = 0; j < i->level - 1; j++) {
xdebug_str_add(&str, "&nbsp; &nbsp;", 0);
}
xdebug_str_add(&str, "-&gt;</td>", 0);
tmp_name = xdebug_show_fname(i->function, 0, 0 TSRMLS_CC);
xdebug_str_add(&str, xdebug_sprintf("<td>%s(", tmp_name), 1);
xdfree(tmp_name);
if (i->include_filename) {
xdebug_str_add(&str, i->include_filename, 0);
}
xdebug_str_add(&str, xdebug_sprintf(")</td><td>%s:%d</td>", i->filename, i->lineno), 1);
xdebug_str_add(&str, "</tr>\n", 0);
return str.d;
}
static char* return_trace_stack_frame_begin(function_stack_entry* i, int fnr TSRMLS_DC)
{
switch (XG(trace_format)) {
case 0:
return return_trace_stack_frame_begin_normal(i TSRMLS_CC);
case 1:
return return_trace_stack_frame_begin_computerized(i, fnr);
case 2:
return return_trace_stack_frame_begin_html(i, fnr TSRMLS_CC);
default:
return xdstrdup("");
}
}
static char* return_trace_stack_frame_end(function_stack_entry* i, int fnr TSRMLS_DC)
{
switch (XG(trace_format)) {
case 1:
return return_trace_stack_frame_end_computerized(i, fnr);
default:
return xdstrdup("");
}
}
PHP_FUNCTION(xdebug_start_trace)
{
char *fname = NULL;
int fname_len = 0;
char *trace_fname;
long options = 0;
if (XG(do_trace) == 0) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &fname, &fname_len, &options) == FAILURE) {
return;
}
if ((trace_fname = xdebug_start_trace(fname, options TSRMLS_CC)) != NULL) {
XG(do_trace) = 1;
RETVAL_STRING(trace_fname, 1);
xdfree(trace_fname);
return;
} else {
php_error(E_NOTICE, "Trace could not be started");
}
XG(do_trace) = 0;
RETURN_FALSE;
} else {
php_error(E_NOTICE, "Function trace already started");
RETURN_FALSE;
}
}
char* xdebug_start_trace(char* fname, long options TSRMLS_DC)
{
char *str_time;
char *filename;
char *tmp_fname = NULL;
if (fname && strlen(fname)) {
filename = xdstrdup(fname);
} else {
if (!strlen(XG(trace_output_name)) ||
xdebug_format_output_filename(&fname, XG(trace_output_name), NULL) <= 0
) {
/* Invalid or empty xdebug.trace_output_name */
return NULL;
}
filename = xdebug_sprintf("%s/%s", XG(trace_output_dir), fname);
}
if (options & XDEBUG_TRACE_OPTION_APPEND) {
XG(trace_file) = xdebug_fopen(filename, "a", "xt", (char**) &tmp_fname);
} else {
XG(trace_file) = xdebug_fopen(filename, "w", "xt", (char**) &tmp_fname);
}
xdfree(filename);
if (options & XDEBUG_TRACE_OPTION_COMPUTERIZED) {
XG(trace_format) = 1;
}
if (options & XDEBUG_TRACE_OPTION_HTML) {
XG(trace_format) = 2;
}
if (XG(trace_file)) {
if (XG(trace_format) == 1) {
fprintf(XG(trace_file), "Version: %s\n", XDEBUG_VERSION);
fprintf(XG(trace_file), "File format: 2\n");
}
if (XG(trace_format) == 0 || XG(trace_format) == 1) {
str_time = xdebug_get_time();
fprintf(XG(trace_file), "TRACE START [%s]\n", str_time);
xdfree(str_time);
}
if (XG(trace_format) == 2) {
fprintf(XG(trace_file), "<table class='xdebug-trace' dir='ltr' border='1' cellspacing='0'>\n");
fprintf(XG(trace_file), "\t<tr><th>#</th><th>Time</th>");
#if MEMORY_LIMIT
fprintf(XG(trace_file), "<th>Mem</th>");
#endif
fprintf(XG(trace_file), "<th colspan='2'>Function</th><th>Location</th></tr>\n");
}
XG(do_trace) = 1;
XG(tracefile_name) = tmp_fname;
return xdstrdup(XG(tracefile_name));
}
return NULL;
}
void xdebug_stop_trace(TSRMLS_D)
{
char *str_time;
double u_time;
XG(do_trace) = 0;
if (XG(trace_file)) {
if (XG(trace_format) == 0 || XG(trace_format) == 1) {
u_time = xdebug_get_utime();
fprintf(XG(trace_file), XG(trace_format) == 0 ? "%10.4f " : "\t\t\t%f\t", u_time - XG(start_time));
#if HAVE_PHP_MEMORY_USAGE
fprintf(XG(trace_file), XG(trace_format) == 0 ? "%10zu" : "%lu", XG_MEMORY_USAGE());
#else
fprintf(XG(trace_file), XG(trace_format) == 0 ? "%10u" : "", 0);
#endif
fprintf(XG(trace_file), "\n");
str_time = xdebug_get_time();
fprintf(XG(trace_file), "TRACE END [%s]\n\n", str_time);
xdfree(str_time);
}
if (XG(trace_format) == 2) {
fprintf(XG(trace_file), "</table>\n");
}
fclose(XG(trace_file));
XG(trace_file) = NULL;
}
if (XG(tracefile_name)) {
xdfree(XG(tracefile_name));
XG(tracefile_name) = NULL;
}
}
PHP_FUNCTION(xdebug_stop_trace)
{
if (XG(do_trace) == 1) {
RETVAL_STRING(XG(tracefile_name), 1);
xdebug_stop_trace(TSRMLS_C);
} else {
RETVAL_FALSE;
php_error(E_NOTICE, "Function trace was not started");
}
}
PHP_FUNCTION(xdebug_get_tracefile_name)
{
if (XG(tracefile_name)) {
RETURN_STRING(XG(tracefile_name), 1);
} else {
RETURN_FALSE;
}
}
Jump to Line
Something went wrong with that request. Please try again.