代码拉取完成,页面将自动刷新
/*
+----------------------------------------------------------------------+
| Xdebug |
+----------------------------------------------------------------------+
| Copyright (c) 2002-2018 Derick Rethans |
+----------------------------------------------------------------------+
| This source file is subject to version 1.01 of the Xdebug license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| https://xdebug.org/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 |
| derick@xdebug.org so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick@xdebug.org> |
+----------------------------------------------------------------------+
*/
#include "php_xdebug.h"
#include "xdebug_private.h"
#include "xdebug_code_coverage.h"
#include "xdebug_com.h"
#include "xdebug_compat.h"
#include "xdebug_filter.h"
#include "xdebug_monitor.h"
#include "xdebug_profiler.h"
#include "xdebug_stack.h"
#include "xdebug_str.h"
#include "xdebug_superglobals.h"
#include "xdebug_var.h"
#include "ext/standard/html.h"
#include "ext/standard/php_smart_string.h"
#include "main/php_ini.h"
ZEND_EXTERN_MODULE_GLOBALS(xdebug)
static const char* text_formats[11] = {
"\n",
"%s: %s in %s on line %d\n",
"\nCall Stack:\n",
"%10.4F %10ld %3d. %s(",
"'%s'",
") %s:%d\n",
"\n\nVariables in local scope (#%d):\n",
"\n",
" $%s = %s\n",
" $%s = *uninitialized*\n",
"SCREAM: Error suppression ignored for\n"
};
static const char* ansi_formats[11] = {
"\n",
"[1m[31m%s[0m: %s[22m in [31m%s[0m on line [32m%d[0m[22m\n",
"\n[1mCall Stack:[22m\n",
"%10.4F %10ld %3d. %s(",
"'%s'",
") %s:%d\n",
"\n\nVariables in local scope (#%d):\n",
"\n",
" $%s = %s\n",
" $%s = *uninitialized*\n",
"[1m[31mSCREAM[0m: Error suppression ignored for\n"
};
static const char* html_formats[13] = {
"<br />\n<font size='1'><table class='xdebug-error xe-%s%s' dir='ltr' border='1' cellspacing='0' cellpadding='1'>\n",
"<tr><th align='left' bgcolor='#f57900' colspan=\"5\"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> %s: %s in %s on line <i>%d</i></th></tr>\n",
"<tr><th align='left' bgcolor='#e9b96e' colspan='5'>Call Stack</th></tr>\n<tr><th align='center' bgcolor='#eeeeec'>#</th><th align='left' bgcolor='#eeeeec'>Time</th><th align='left' bgcolor='#eeeeec'>Memory</th><th align='left' bgcolor='#eeeeec'>Function</th><th align='left' bgcolor='#eeeeec'>Location</th></tr>\n",
"<tr><td bgcolor='#eeeeec' align='center'>%d</td><td bgcolor='#eeeeec' align='center'>%.4F</td><td bgcolor='#eeeeec' align='right'>%ld</td><td bgcolor='#eeeeec'>%s( ",
"<font color='#00bb00'>'%s'</font>",
" )</td><td title='%s' bgcolor='#eeeeec'>%s<b>:</b>%d</td></tr>\n",
"<tr><th align='left' colspan='5' bgcolor='#e9b96e'>Variables in local scope (#%d)</th></tr>\n",
"</table></font>\n",
"<tr><td colspan='2' align='right' bgcolor='#eeeeec' valign='top'><pre>$%s =</pre></td><td colspan='3' bgcolor='#eeeeec'>%s</td></tr>\n",
"<tr><td colspan='2' align='right' bgcolor='#eeeeec' valign='top'><pre>$%s =</pre></td><td colspan='3' bgcolor='#eeeeec' valign='top'><i>Undefined</i></td></tr>\n",
" )</td><td title='%s' bgcolor='#eeeeec'><a style='color: black' href='%s'>%s<b>:</b>%d</a></td></tr>\n",
"<tr><th align='left' bgcolor='#f57900' colspan=\"5\"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> %s: %s in <a style='color: black' href='%s'>%s</a> on line <i>%d</i></th></tr>\n",
"<tr><th align='left' bgcolor='#f57900' colspan=\"5\"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> SCREAM: Error suppression ignored for</th></tr>\n"
};
static const char** select_formats(int html TSRMLS_DC) {
if (html) {
return html_formats;
}
else if ((XG(cli_color) == 1 && xdebug_is_output_tty(TSRMLS_C)) || (XG(cli_color) == 2)) {
return ansi_formats;
}
else {
return text_formats;
}
}
static void dump_used_var_with_contents(void *htmlq, xdebug_hash_element* he, void *argument)
{
int html = *(int*) htmlq;
zval zvar;
xdebug_str *contents;
xdebug_str *name = (xdebug_str*) he->ptr;
HashTable *tmp_ht;
const char **formats;
xdebug_str *str = (xdebug_str *) argument;
TSRMLS_FETCH();
if (!he->ptr) {
return;
}
/* Bail out on $this and $GLOBALS */
if (strcmp(name->d, "this") == 0 || strcmp(name->d, "GLOBALS") == 0) {
return;
}
#if PHP_VERSION_ID >= 70100
if (!(ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
#else
if (!EG(current_execute_data)->symbol_table) {
#endif
zend_rebuild_symbol_table(TSRMLS_C);
}
tmp_ht = XG(active_symbol_table);
{
zend_execute_data *ex = EG(current_execute_data);
while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
ex = ex->prev_execute_data;
}
if (ex) {
XG(active_execute_data) = ex;
XG(active_symbol_table) = ex->symbol_table;
}
}
xdebug_get_php_symbol(&zvar, name);
XG(active_symbol_table) = tmp_ht;
formats = select_formats(PG(html_errors) TSRMLS_CC);
if (Z_TYPE(zvar) == IS_UNDEF) {
xdebug_str_add(str, xdebug_sprintf(formats[9], name->d), 1);
return;
}
if (html) {
contents = xdebug_get_zval_value_fancy(NULL, &zvar, 0, NULL);
} else {
contents = xdebug_get_zval_value(&zvar, 0, NULL);
}
if (contents) {
xdebug_str_add(str, xdebug_sprintf(formats[8], name->d, contents->d), 1);
} else {
xdebug_str_add(str, xdebug_sprintf(formats[9], name->d), 1);
}
if (contents) {
xdebug_str_free(contents);
}
zval_ptr_dtor_nogc(&zvar);
}
void xdebug_log_stack(const char *error_type_str, char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC)
{
xdebug_llist_element *le;
function_stack_entry *i;
char *tmp_log_message;
tmp_log_message = xdebug_sprintf( "PHP %s: %s in %s on line %d", error_type_str, buffer, error_filename, error_lineno);
php_log_err(tmp_log_message TSRMLS_CC);
xdfree(tmp_log_message);
if (XG(stack) && XG(stack)->size) {
php_log_err((char*) "PHP Stack trace:" TSRMLS_CC);
for (le = XDEBUG_LLIST_HEAD(XG(stack)); le != NULL; le = XDEBUG_LLIST_NEXT(le))
{
int c = 0; /* Comma flag */
unsigned int j = 0; /* Counter */
char *tmp_name;
xdebug_str log_buffer = XDEBUG_STR_INITIALIZER;
int variadic_opened = 0;
i = XDEBUG_LLIST_VALP(le);
tmp_name = xdebug_show_fname(i->function, 0, 0 TSRMLS_CC);
xdebug_str_add(&log_buffer, xdebug_sprintf("PHP %3d. %s(", i->level, tmp_name), 1);
xdfree(tmp_name);
/* Printing vars */
for (j = 0; j < i->varc; j++) {
char *tmp_varname;
xdebug_str *tmp_value;
if (c) {
xdebug_str_addl(&log_buffer, ", ", 2, 0);
} else {
c = 1;
}
if (
(i->var[j].is_variadic && XG(collect_params) != 5)
) {
xdebug_str_add(&log_buffer, "...", 0);
variadic_opened = 1;
}
tmp_varname = i->var[j].name ? xdebug_sprintf("$%s = ", i->var[j].name) : xdstrdup("");
xdebug_str_add(&log_buffer, tmp_varname, 0);
xdfree(tmp_varname);
if (i->var[j].is_variadic) {
xdebug_str_add(&log_buffer, "variadic(", 0);
c = 0;
continue;
}
if (!Z_ISUNDEF(i->var[j].data)) {
tmp_value = xdebug_get_zval_value(&i->var[j].data, 0, NULL);
xdebug_str_add_str(&log_buffer, tmp_value);
xdebug_str_free(tmp_value);
} else {
xdebug_str_addl(&log_buffer, "*uninitialized*", 15, 0);
}
}
if (variadic_opened) {
xdebug_str_add(&log_buffer, ")", 0);
}
xdebug_str_add(&log_buffer, xdebug_sprintf(") %s:%d", i->filename, i->lineno), 1);
php_log_err(log_buffer.d TSRMLS_CC);
xdebug_str_destroy(&log_buffer);
}
}
}
void xdebug_append_error_head(xdebug_str *str, int html, const char *error_type_str TSRMLS_DC)
{
const char **formats = select_formats(html TSRMLS_CC);
if (html) {
xdebug_str_add(str, xdebug_sprintf(formats[0], error_type_str, XG(in_at) ? " xe-scream" : ""), 1);
if (XG(in_at)) {
xdebug_str_add(str, formats[12], 0);
}
} else {
xdebug_str_add(str, formats[0], 0);
if (XG(in_at)) {
xdebug_str_add(str, formats[10], 0);
}
}
}
void xdebug_append_error_description(xdebug_str *str, int html, const char *error_type_str, const char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC)
{
const char **formats = select_formats(html TSRMLS_CC);
char *escaped;
if (html) {
zend_string *tmp;
char *first_closing = strchr(buffer, ']');
/* We do need to escape HTML entities here, as HTML chars could be in
* the error message. However, PHP in some circumstances also adds an
* HTML link to a manual page. That bit, we don't need to escape. So
* this bit of code finds the portion that doesn't need escaping, adds
* it to a tmp string, and then adds an HTML escaped string for the
* rest of the original buffer. */
if (first_closing && strstr(buffer, "() [<a href=") != NULL) {
smart_string special_escaped = { 0, 0, 0 };
*first_closing = '\0';
first_closing++;
smart_string_appends(&special_escaped, buffer);
tmp = php_escape_html_entities((unsigned char *) first_closing, strlen(first_closing), 0, 0, NULL TSRMLS_CC);
smart_string_appends(&special_escaped, tmp->val);
zend_string_free(tmp);
smart_string_0(&special_escaped);
escaped = estrdup(special_escaped.c);
smart_string_free(&special_escaped);
} else if (strncmp(buffer, "assert()", 8) == 0) {
/* Also don't escape if we're in an assert, as things are already
* escaped. It's all nice and consistent ey? */
escaped = estrdup(buffer);
} else {
tmp = php_escape_html_entities((unsigned char *) buffer, strlen(buffer), 0, 0, NULL TSRMLS_CC);
escaped = estrdup(tmp->val);
zend_string_free(tmp);
}
} else {
escaped = estrdup(buffer);
}
if (strlen(XG(file_link_format)) > 0 && html) {
char *file_link;
xdebug_format_file_link(&file_link, error_filename, error_lineno TSRMLS_CC);
xdebug_str_add(str, xdebug_sprintf(formats[11], error_type_str, escaped, file_link, error_filename, error_lineno), 1);
xdfree(file_link);
} else {
xdebug_str_add(str, xdebug_sprintf(formats[1], error_type_str, escaped, error_filename, error_lineno), 1);
}
efree(escaped);
}
static void add_single_value(xdebug_str *str, zval *zv, int html, int collecton_level TSRMLS_DC)
{
xdebug_str *tmp_value = NULL, *tmp_fancy_synop_value = NULL;
char *tmp_fancy_value = NULL;
size_t newlen;
if (html) {
switch (collecton_level) {
case 1: /* synopsis */
tmp_fancy_synop_value = xdebug_get_zval_synopsis_fancy("", zv, 0, NULL TSRMLS_CC);
xdebug_str_addl(str, "<span>", 6, 0);
xdebug_str_add_str(str, tmp_fancy_synop_value);
xdebug_str_addl(str, "</span>", 7, 0);
xdfree(tmp_fancy_synop_value);
break;
case 2: /* synopsis + full in tooltip */
tmp_value = xdebug_get_zval_value(zv, 0, NULL);
tmp_fancy_value = xdebug_xmlize(tmp_value->d, tmp_value->l, &newlen);
tmp_fancy_synop_value = xdebug_get_zval_synopsis_fancy("", zv, 0, NULL TSRMLS_CC);
xdebug_str_addl(str, "<span title='", 13, 0);
xdebug_str_add(str, tmp_fancy_value, 0);
xdebug_str_addl(str, "'>", 2, 0);
xdebug_str_add_str(str, tmp_fancy_synop_value);
xdebug_str_addl(str, "</span>", 7, 0);
xdebug_str_free(tmp_value);
efree(tmp_fancy_value);
xdebug_str_free(tmp_fancy_synop_value);
break;
case 3: /* full */
case 4: /* full (with var_name) */
default:
tmp_value = xdebug_get_zval_value(zv, 0, NULL);
tmp_fancy_value = xdebug_xmlize(tmp_value->d, tmp_value->l, &newlen);
xdebug_str_addl(str, "<span>", 6, 0);
xdebug_str_add(str, tmp_fancy_value, 0);
xdebug_str_addl(str, "</span>", 7, 0);
xdebug_str_free(tmp_value);
efree(tmp_fancy_value);
break;
case 5: { /* serialized */
tmp_value = xdebug_get_zval_value_serialized(zv, 0, NULL TSRMLS_CC);
xdebug_str_addl(str, "<span>", 6, 0);
xdebug_str_add_str(str, tmp_value);
xdebug_str_addl(str, "</span>", 7, 0);
xdebug_str_free(tmp_value);
} break;
}
} else {
switch (collecton_level) {
case 1: /* synopsis */
case 2:
tmp_value = xdebug_get_zval_synopsis(zv, 0, NULL);
break;
case 3: /* full */
case 4: /* full (with var_name) */
default:
tmp_value = xdebug_get_zval_value(zv, 0, NULL);
break;
case 5: /* serialized */
tmp_value = xdebug_get_zval_value_serialized(zv, 0, NULL TSRMLS_CC);
break;
}
if (tmp_value) {
xdebug_str_add_str(str, tmp_value);
xdebug_str_free(tmp_value);
} else {
xdebug_str_addl(str, "???", 3, 0);
}
}
}
void xdebug_append_printable_stack(xdebug_str *str, int html TSRMLS_DC)
{
xdebug_llist_element *le;
function_stack_entry *i;
int printed_frames = 0;
const char **formats = select_formats(html TSRMLS_CC);
if (XG(stack) && XG(stack)->size) {
i = XDEBUG_LLIST_VALP(XDEBUG_LLIST_HEAD(XG(stack)));
xdebug_str_add(str, formats[2], 0);
for (le = XDEBUG_LLIST_HEAD(XG(stack)); le != NULL; le = XDEBUG_LLIST_NEXT(le))
{
int c = 0; /* Comma flag */
unsigned int j = 0; /* Counter */
char *tmp_name;
int variadic_opened = 0;
i = XDEBUG_LLIST_VALP(le);
if (xdebug_is_stack_frame_filtered(XDEBUG_FILTER_TRACING, i)) {
continue;
}
tmp_name = xdebug_show_fname(i->function, html, 0 TSRMLS_CC);
if (html) {
xdebug_str_add(str, xdebug_sprintf(formats[3], i->level, i->time - XG(start_time), i->memory, tmp_name), 1);
} else {
xdebug_str_add(str, xdebug_sprintf(formats[3], i->time - XG(start_time), i->memory, i->level, tmp_name), 1);
}
xdfree(tmp_name);
/* Printing vars */
for (j = 0; j < i->varc; j++) {
if (c) {
xdebug_str_addl(str, ", ", 2, 0);
} else {
c = 1;
}
if (
(i->var[j].is_variadic && Z_ISUNDEF(i->var[j].data))
) {
xdebug_str_add(str, "...", 0);
}
if (i->var[j].name && XG(collect_params) == 4) {
if (html) {
xdebug_str_add(str, xdebug_sprintf("<span>$%s = </span>", i->var[j].name), 1);
} else {
xdebug_str_add(str, xdebug_sprintf("$%s = ", i->var[j].name), 1);
}
}
if (!variadic_opened && i->var[j].is_variadic && Z_ISUNDEF(i->var[j].data)) {
if (html) {
xdebug_str_add(str, "<i>variadic</i>(", 0);
} else {
xdebug_str_add(str, "variadic(", 0);
}
c = 0;
variadic_opened = 1;
continue;
}
if (!Z_ISUNDEF(i->var[j].data)) {
add_single_value(str, &i->var[j].data, html, XG(collect_params) TSRMLS_CC);
} else {
xdebug_str_addl(str, "???", 3, 0);
}
}
if (variadic_opened) {
xdebug_str_add(str, ")", 0);
}
if (i->include_filename) {
xdebug_str_add(str, xdebug_sprintf(formats[4], i->include_filename), 1);
}
if (html) {
char *formatted_filename;
xdebug_format_filename(&formatted_filename, XG(filename_format), "...%s%n", i->filename);
if (strlen(XG(file_link_format)) > 0) {
char *file_link;
xdebug_format_file_link(&file_link, i->filename, i->lineno TSRMLS_CC);
xdebug_str_add(str, xdebug_sprintf(formats[10], i->filename, file_link, formatted_filename, i->lineno), 1);
xdfree(file_link);
} else {
xdebug_str_add(str, xdebug_sprintf(formats[5], i->filename, formatted_filename, i->lineno), 1);
}
xdfree(formatted_filename);
} else {
xdebug_str_add(str, xdebug_sprintf(formats[5], i->filename, i->lineno), 1);
}
printed_frames++;
if (XG(max_stack_frames) > 0 && printed_frames >= XG(max_stack_frames)) {
break;
}
}
if (XG(dump_globals) && !(XG(dump_once) && XG(dumped))) {
char *tmp = xdebug_get_printable_superglobals(html TSRMLS_CC);
if (tmp) {
xdebug_str_add(str, tmp, 1);
}
XG(dumped) = 1;
}
if (XG(show_local_vars) && XG(stack) && XDEBUG_LLIST_TAIL(XG(stack))) {
int scope_nr = XG(stack)->size;
i = XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack)));
if (i->user_defined == XDEBUG_INTERNAL && XDEBUG_LLIST_PREV(XDEBUG_LLIST_TAIL(XG(stack))) && XDEBUG_LLIST_VALP(XDEBUG_LLIST_PREV(XDEBUG_LLIST_TAIL(XG(stack))))) {
i = XDEBUG_LLIST_VALP(XDEBUG_LLIST_PREV(XDEBUG_LLIST_TAIL(XG(stack))));
scope_nr--;
}
if (i->declared_vars && i->declared_vars->size) {
xdebug_hash *tmp_hash;
xdebug_str_add(str, xdebug_sprintf(formats[6], scope_nr), 1);
tmp_hash = xdebug_declared_var_hash_from_llist(i->declared_vars);
xdebug_hash_apply_with_argument(tmp_hash, (void*) &html, dump_used_var_with_contents, (void *) str);
xdebug_hash_destroy(tmp_hash);
}
}
}
}
void xdebug_append_error_footer(xdebug_str *str, int html TSRMLS_DC)
{
const char **formats = select_formats(html TSRMLS_CC);
xdebug_str_add(str, formats[7], 0);
}
static char *get_printable_stack(int html, int error_type, const char *buffer, const char *error_filename, const int error_lineno, int include_decription TSRMLS_DC)
{
char *prepend_string;
char *append_string;
char *error_type_str = xdebug_error_type(error_type);
char *error_type_str_simple = xdebug_error_type_simple(error_type);
xdebug_str str = XDEBUG_STR_INITIALIZER;
prepend_string = INI_STR((char*) "error_prepend_string");
append_string = INI_STR((char*) "error_append_string");
xdebug_str_add(&str, prepend_string ? prepend_string : "", 0);
xdebug_append_error_head(&str, html, error_type_str_simple TSRMLS_CC);
if (include_decription) {
xdebug_append_error_description(&str, html, error_type_str, buffer, error_filename, error_lineno TSRMLS_CC);
}
xdebug_append_printable_stack(&str, html TSRMLS_CC);
xdebug_append_error_footer(&str, html TSRMLS_CC);
xdebug_str_add(&str, append_string ? append_string : "", 0);
xdfree(error_type_str);
xdfree(error_type_str_simple);
return str.d;
}
static void php_output_error(const char *error TSRMLS_DC)
{
#ifdef PHP_DISPLAY_ERRORS_STDERR
if (PG(display_errors) == PHP_DISPLAY_ERRORS_STDERR) {
fputs(error, stderr);
fflush(stderr);
return;
}
#endif
php_printf("%s", error);
}
char *xdebug_strip_php_stack_trace(char *buffer)
{
char *tmp_buf, *p;
if (strncmp(buffer, "Uncaught ", 9) == 0) {
/* find first new line */
p = strchr(buffer, '\n');
if (!p) {
p = buffer + strlen(buffer);
} else {
/* find the last " in ", which isn't great and might not work... but in most cases it will */
p = xdebug_strrstr(buffer, " in ");
if (!p) {
p = buffer + strlen(buffer);
}
}
/* Create new buffer */
tmp_buf = calloc(p - buffer + 1, 1);
strncpy(tmp_buf, buffer, p - buffer);
return tmp_buf;
}
return NULL;
}
char *xdebug_handle_stack_trace(int type, char *error_type_str, const char *error_filename, const uint error_lineno, char *buffer TSRMLS_DC)
{
char *printable_stack;
char *tmp_buf;
/* We need to see if we have an uncaught exception fatal error now */
if (type == E_ERROR && ((tmp_buf = xdebug_strip_php_stack_trace(buffer)) != NULL)) {
xdebug_str str = XDEBUG_STR_INITIALIZER;
/* Append error */
xdebug_append_error_head(&str, PG(html_errors), "uncaught-exception" TSRMLS_CC);
xdebug_append_error_description(&str, PG(html_errors), error_type_str, tmp_buf, error_filename, error_lineno TSRMLS_CC);
xdebug_append_printable_stack(&str, PG(html_errors) TSRMLS_CC);
if (XG(last_exception_trace)) {
xdebug_str_add(&str, XG(last_exception_trace), 0);
}
xdebug_append_error_footer(&str, PG(html_errors) TSRMLS_CC);
free(tmp_buf);
printable_stack = str.d;
} else {
printable_stack = get_printable_stack(PG(html_errors), type, buffer, error_filename, error_lineno, 1 TSRMLS_CC);
}
return printable_stack;
}
/* Error callback for formatting stack traces */
void xdebug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args)
{
char *buffer, *error_type_str;
int buffer_len;
xdebug_brk_info *extra_brk_info = NULL;
error_handling_t error_handling;
zend_class_entry *exception_class;
TSRMLS_FETCH();
buffer_len = vspprintf(&buffer, PG(log_errors_max_len), format, args);
error_type_str = xdebug_error_type(type);
/* Store last error message for error_get_last() */
if (PG(last_error_message)) {
free(PG(last_error_message));
}
if (PG(last_error_file)) {
free(PG(last_error_file));
}
PG(last_error_type) = type;
PG(last_error_message) = strdup(buffer);
PG(last_error_file) = strdup(error_filename);
PG(last_error_lineno) = error_lineno;
error_handling = EG(error_handling);
exception_class = EG(exception_class);
/* according to error handling mode, suppress error, throw exception or show it */
if (error_handling != EH_NORMAL
) {
switch (type) {
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_PARSE:
/* fatal errors are real errors and cannot be made exceptions */
break;
case E_STRICT:
/* for the sake of BC to old damaged code */
break;
case E_NOTICE:
case E_USER_NOTICE:
/* notices are no errors and are not treated as such like E_WARNINGS */
break;
default:
/* throw an exception if we are in EH_THROW mode
* but DO NOT overwrite a pending exception
*/
if (error_handling == EH_THROW && !EG(exception)) {
zend_throw_error_exception(exception_class, buffer, 0, type TSRMLS_CC);
}
efree(buffer);
xdfree(error_type_str);
return;
}
}
if ((EG(error_reporting | XG(force_error_reporting))) & type) {
/* Log to logger */
if (PG(log_errors)) {
#ifdef PHP_WIN32
if (type==E_CORE_ERROR || type==E_CORE_WARNING) {
MessageBox(NULL, buffer, error_type_str, MB_OK);
}
#endif
xdebug_log_stack(error_type_str, buffer, error_filename, error_lineno TSRMLS_CC);
if (XG(dump_globals) && !(XG(dump_once) && XG(dumped))) {
char *printable_stack = xdebug_get_printable_superglobals(0 TSRMLS_CC);
if (printable_stack) {
int pc;
xdebug_arg *parts = (xdebug_arg*) xdmalloc(sizeof(xdebug_arg));
xdebug_arg_init(parts);
xdebug_explode("\n", printable_stack, parts, -1);
for (pc = 0; pc < parts->c; pc++) {
char *tmp_line = xdebug_sprintf("PHP %s", parts->args[pc]);
php_log_err(tmp_line);
xdfree(tmp_line);
}
xdebug_arg_dtor(parts);
xdfree(printable_stack);
php_log_err((char*) "PHP ");
}
}
}
/* Display errors */
if ((PG(display_errors) || XG(force_display_errors)) && !PG(during_request_startup)) {
char *printable_stack;
printable_stack = xdebug_handle_stack_trace(type, error_type_str, error_filename, error_lineno, buffer TSRMLS_CC);
if (XG(do_collect_errors) && (type != E_ERROR) && (type != E_COMPILE_ERROR) && (type != E_USER_ERROR)) {
xdebug_llist_insert_next(XG(collected_errors), XDEBUG_LLIST_TAIL(XG(collected_errors)), printable_stack);
} else {
php_output_error(printable_stack TSRMLS_CC);
xdfree(printable_stack);
}
} else if (XG(do_collect_errors)) {
char *printable_stack;
printable_stack = get_printable_stack(PG(html_errors), type, buffer, error_filename, error_lineno, 1 TSRMLS_CC);
xdebug_llist_insert_next(XG(collected_errors), XDEBUG_LLIST_TAIL(XG(collected_errors)), printable_stack);
}
}
/* Start JIT if requested and not yet enabled */
xdebug_do_jit(TSRMLS_C);
if (xdebug_is_debug_connection_active_for_current_pid() && XG(breakpoints_allowed)) {
/* Send notification with warning/notice/error information */
if (XG(context).send_notifications && !XG(context).inhibit_notifications) {
if (!XG(context).handler->remote_notification(&(XG(context)), error_filename, error_lineno, type, error_type_str, buffer)) {
xdebug_mark_debug_connection_not_active();
}
}
/* Check for the pseudo exceptions to allow breakpoints on PHP error statuses */
if (
xdebug_hash_find(XG(context).exception_breakpoints, error_type_str, strlen(error_type_str), (void *) &extra_brk_info) ||
xdebug_hash_find(XG(context).exception_breakpoints, "*", 1, (void *) &extra_brk_info)
) {
if (xdebug_handle_hit_value(extra_brk_info)) {
char *type_str = xdebug_sprintf("%ld", type);
if (!XG(context).handler->remote_breakpoint(&(XG(context)), XG(stack), (char *) error_filename, error_lineno, XDEBUG_BREAK, error_type_str, type_str, buffer)) {
xdebug_mark_debug_connection_not_active();
}
xdfree(type_str);
}
}
}
xdfree(error_type_str);
if (type & XG(halt_level) & XDEBUG_ALLOWED_HALT_LEVELS) {
type = E_USER_ERROR;
}
/* Bail out if we can't recover */
switch (type) {
case E_CORE_ERROR:
if (!php_get_module_initialized()) {
/* bad error in module startup - no way we can live with this */
exit(-2);
}
XDEBUG_BREAK_INTENTIONALLY_MISSING
case E_ERROR:
case E_RECOVERABLE_ERROR:
case E_PARSE:
case E_COMPILE_ERROR:
case E_USER_ERROR:
EG(exit_status) = 255;
if (php_get_module_initialized()) {
if (!PG(display_errors) &&
!SG(headers_sent) &&
SG(sapi_headers).http_response_code == 200
) {
sapi_header_line ctr = { 0, 0, 0 };
ctr.line = (char*) "HTTP/1.0 500 Internal Server Error";
ctr.line_len = sizeof("HTTP/1.0 500 Internal Server Error") - 1;
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
}
/* the parser would return 1 (failure), we can bail out nicely */
if (type != E_PARSE) {
efree(buffer);
/* restore memory limit */
zend_set_memory_limit(PG(memory_limit));
zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC);
_zend_bailout((char*) __FILE__, __LINE__);
return;
}
}
break;
}
#if PHP_VERSION_ID >= 70200
if (PG(track_errors) && EG(active)) {
#else
if (PG(track_errors) && EG(valid_symbol_table)) {
#endif
zval tmp;
ZVAL_STRINGL(&tmp, buffer, buffer_len);
if (EG(current_execute_data)) {
if (zend_set_local_var_str("php_errormsg", sizeof("php_errormsg")-1, &tmp, 0) == FAILURE) {
zval_ptr_dtor(&tmp);
}
} else {
zend_hash_str_update(&EG(symbol_table), "php_errormsg", sizeof("php_errormsg"), &tmp);
}
}
efree(buffer);
}
/* {{{ proto void xdebug_print_function_stack([string message [, int options])
Displays a stack trace */
PHP_FUNCTION(xdebug_print_function_stack)
{
char *message = NULL;
size_t message_len;
function_stack_entry *i;
char *tmp;
zend_long options = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &message, &message_len, &options) == FAILURE) {
return;
}
i = xdebug_get_stack_frame(0 TSRMLS_CC);
if (message) {
tmp = get_printable_stack(PG(html_errors), 0, message, i->filename, i->lineno, !(options & XDEBUG_STACK_NO_DESC) TSRMLS_CC);
} else {
tmp = get_printable_stack(PG(html_errors), 0, "user triggered", i->filename, i->lineno, !(options & XDEBUG_STACK_NO_DESC) TSRMLS_CC);
}
php_printf("%s", tmp);
xdfree(tmp);
}
/* }}} */
/* {{{ proto array xdebug_get_formatted_function_stack()
Displays a stack trace */
PHP_FUNCTION(xdebug_get_formatted_function_stack)
{
function_stack_entry *i;
char *tmp;
i = xdebug_get_stack_frame(0 TSRMLS_CC);
tmp = get_printable_stack(PG(html_errors), 0, "user triggered", i->filename, i->lineno, 1 TSRMLS_CC);
RETVAL_STRING(tmp);
xdfree(tmp);
}
/* }}} */
/* {{{ proto string xdebug_call_class()
Returns the name of the calling class */
PHP_FUNCTION(xdebug_call_class)
{
function_stack_entry *i;
zend_long depth = 2;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &depth) == FAILURE) {
return;
}
i = xdebug_get_stack_frame(depth TSRMLS_CC);
if (i) {
if (i->function.class) {
RETURN_STRING(i->function.class);
} else {
RETURN_FALSE;
}
} else {
return;
}
}
/* }}} */
/* {{{ proto string xdebug_call_function()
Returns the function name from which the current function was called from. */
PHP_FUNCTION(xdebug_call_function)
{
function_stack_entry *i;
zend_long depth = 2;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &depth) == FAILURE) {
return;
}
i = xdebug_get_stack_frame(depth TSRMLS_CC);
if (i) {
if (i->function.function) {
RETURN_STRING(i->function.function);
} else {
RETURN_FALSE;
}
} else {
return;
}
}
/* }}} */
/* {{{ proto int xdebug_call_line()
Returns the line number where the current function was called from. */
PHP_FUNCTION(xdebug_call_line)
{
function_stack_entry *i;
zend_long depth = 2;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &depth) == FAILURE) {
return;
}
i = xdebug_get_stack_frame(depth TSRMLS_CC);
if (i) {
RETURN_LONG(i->lineno);
} else {
return;
}
}
/* }}} */
/* {{{ proto string xdebug_call_file()
Returns the filename where the current function was called from. */
PHP_FUNCTION(xdebug_call_file)
{
function_stack_entry *i;
zend_long depth = 2;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &depth) == FAILURE) {
return;
}
i = xdebug_get_stack_frame(depth TSRMLS_CC);
if (i) {
RETURN_STRING(i->filename);
} else {
return;
}
}
/* }}} */
static int find_line_number_for_current_execute_point(zend_execute_data *edata TSRMLS_DC)
{
zend_execute_data *ptr = edata;
while (ptr && (!ptr->func || !ZEND_USER_CODE(ptr->func->type))) {
ptr = ptr->prev_execute_data;
}
if (ptr && ptr->opline) {
return ptr->opline->lineno;
}
return 0;
}
int xdebug_function_name_is_closure(char *fname)
{
int length = strlen(fname);
int closure_length = strlen("{closure}");
if (length < closure_length) {
return 0;
}
if (strcmp(fname + length - closure_length, "{closure}") == 0) {
return 1;
}
return 0;
}
char* xdebug_wrap_closure_location_around_function_name(zend_op_array *opa, char *fname)
{
xdebug_str tmp = XDEBUG_STR_INITIALIZER;
char *tmp_loc_info;
xdebug_str_addl(&tmp, fname, strlen(fname) - 1, 0);
tmp_loc_info = xdebug_sprintf(
":%s:%d-%d}",
opa->filename->val,
opa->line_start,
opa->line_end
);
xdebug_str_add(&tmp, tmp_loc_info, 1);
return tmp.d;
}
/* I don't like this API, but the function_stack_entry does not keep this as a
* pointer, and hence we need two APIs for freeing :-S */
void xdebug_func_dtor_by_ref(xdebug_func *elem)
{
if (elem->function) {
xdfree(elem->function);
}
if (elem->class) {
xdfree(elem->class);
}
}
void xdebug_func_dtor(xdebug_func *elem)
{
xdebug_func_dtor_by_ref(elem);
xdfree(elem);
}
void xdebug_build_fname(xdebug_func *tmp, zend_execute_data *edata TSRMLS_DC)
{
memset(tmp, 0, sizeof(xdebug_func));
#if PHP_VERSION_ID >= 70100
if (edata && edata->func && edata->func == (zend_function*) &zend_pass_function) {
tmp->type = XFUNC_ZEND_PASS;
tmp->function = xdstrdup("{zend_pass}");
} else
#endif
if (edata && edata->func) {
tmp->type = XFUNC_NORMAL;
#if PHP_VERSION_ID >= 70100
if ((Z_TYPE(edata->This)) == IS_OBJECT) {
#else
if (edata->This.value.obj) {
#endif
tmp->type = XFUNC_MEMBER;
if (edata->func->common.scope && strcmp(edata->func->common.scope->name->val, "class@anonymous") == 0) {
tmp->class = xdebug_sprintf(
"{anonymous-class:%s:%d-%d}",
edata->func->common.scope->info.user.filename->val,
edata->func->common.scope->info.user.line_start,
edata->func->common.scope->info.user.line_end
);
} else {
tmp->class = xdstrdup(edata->This.value.obj->ce->name->val);
}
} else {
if (edata->func->common.scope) {
tmp->type = XFUNC_STATIC_MEMBER;
tmp->class = xdstrdup(edata->func->common.scope->name->val);
}
}
if (edata->func->common.function_name) {
if (xdebug_function_name_is_closure(edata->func->common.function_name->val)) {
tmp->function = xdebug_wrap_closure_location_around_function_name(&edata->func->op_array, edata->func->common.function_name->val);
} else if (strncmp(edata->func->common.function_name->val, "call_user_func", 14) == 0) {
const char *fname = NULL;
int lineno = 0;
if (edata->prev_execute_data && edata->prev_execute_data->func && edata->prev_execute_data->func->type == ZEND_USER_FUNCTION) {
fname = edata->prev_execute_data->func->op_array.filename->val;
}
if (
!fname &&
XDEBUG_LLIST_TAIL(XG(stack)) &&
XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))) &&
((function_stack_entry*) XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))))->filename
) {
fname = ((function_stack_entry*) XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))))->filename;
}
if (!fname) {
/* It wasn't a special call_user_func after all */
goto normal_after_all;
}
lineno = find_line_number_for_current_execute_point(edata TSRMLS_CC);
tmp->function = xdebug_sprintf(
"%s:{%s:%d}",
edata->func->common.function_name->val,
fname,
lineno
);
} else {
normal_after_all:
tmp->function = xdstrdup(edata->func->common.function_name->val);
}
} else if (
edata &&
edata->func &&
edata->func->type == ZEND_EVAL_CODE &&
edata->prev_execute_data &&
edata->prev_execute_data->func &&
edata->prev_execute_data->func->common.function_name &&
(
(strncmp(edata->prev_execute_data->func->common.function_name->val, "assert", 6) == 0) ||
(strncmp(edata->prev_execute_data->func->common.function_name->val, "create_function", 15) == 0)
)
) {
tmp->type = XFUNC_NORMAL;
tmp->function = xdstrdup("{internal eval}");
} else if (
edata &&
edata->prev_execute_data &&
edata->prev_execute_data->func->type == ZEND_USER_FUNCTION &&
edata->prev_execute_data->opline &&
edata->prev_execute_data->opline->opcode == ZEND_INCLUDE_OR_EVAL
) {
switch (edata->prev_execute_data->opline->extended_value) {
case ZEND_EVAL:
tmp->type = XFUNC_EVAL;
break;
case ZEND_INCLUDE:
tmp->type = XFUNC_INCLUDE;
break;
case ZEND_REQUIRE:
tmp->type = XFUNC_REQUIRE;
break;
case ZEND_INCLUDE_ONCE:
tmp->type = XFUNC_INCLUDE_ONCE;
break;
case ZEND_REQUIRE_ONCE:
tmp->type = XFUNC_REQUIRE_ONCE;
break;
default:
tmp->type = XFUNC_UNKNOWN;
break;
}
} else if (
edata &&
edata->prev_execute_data
) {
xdebug_build_fname(tmp, edata->prev_execute_data);
} else {
tmp->type = XFUNC_UNKNOWN;
}
}
}
function_stack_entry *xdebug_add_stack_frame(zend_execute_data *zdata, zend_op_array *op_array, int type TSRMLS_DC)
{
zend_execute_data *edata;
zend_op **opline_ptr = NULL;
function_stack_entry *tmp;
zend_op *cur_opcode;
int i = 0;
char *aggr_key = NULL;
int aggr_key_len = 0;
int hit_variadic = 0;
zend_string *aggr_key_str = NULL;
if (type == XDEBUG_EXTERNAL) {
edata = EG(current_execute_data)->prev_execute_data;
if (edata) {
opline_ptr = (zend_op**) &edata->opline;
}
} else {
edata = EG(current_execute_data);
opline_ptr = (zend_op**) &EG(current_execute_data)->opline;
}
zdata = EG(current_execute_data);
tmp = xdmalloc (sizeof (function_stack_entry));
tmp->var = NULL;
tmp->varc = 0;
tmp->refcount = 1;
tmp->level = XG(level);
tmp->arg_done = 0;
tmp->declared_vars = NULL;
tmp->user_defined = type;
tmp->filename = NULL;
tmp->include_filename = NULL;
tmp->profile.call_list = NULL;
tmp->op_array = op_array;
tmp->symbol_table = NULL;
tmp->execute_data = NULL;
tmp->is_variadic = 0;
tmp->filtered_tracing = 0;
tmp->filtered_code_coverage = 0;
XG(function_count)++;
tmp->function_nr = XG(function_count);
{
zend_execute_data *ptr = edata;
while (ptr && (!ptr->func || !ZEND_USER_CODE(ptr->func->type))) {
ptr = ptr->prev_execute_data;
}
if (ptr) {
tmp->filename = xdstrdup(ptr->func->op_array.filename->val);
}
}
if (!tmp->filename) {
/* Includes/main script etc */
tmp->filename = (type == XDEBUG_EXTERNAL && op_array && op_array->filename) ? xdstrdup(op_array->filename->val): NULL;
}
/* Call user function locations */
if (
!tmp->filename &&
XG(stack) &&
XDEBUG_LLIST_TAIL(XG(stack)) &&
XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))) &&
((function_stack_entry*) XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))))->filename
) {
tmp->filename = xdstrdup(((function_stack_entry*) XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))))->filename);
}
if (!tmp->filename) {
tmp->filename = xdstrdup("UNKNOWN?");
}
tmp->prev_memory = XG(prev_memory);
tmp->memory = zend_memory_usage(0 TSRMLS_CC);
XG(prev_memory) = tmp->memory;
tmp->time = xdebug_get_utime();
tmp->lineno = 0;
tmp->prev = 0;
xdebug_build_fname(&(tmp->function), zdata TSRMLS_CC);
if (!tmp->function.type) {
tmp->function.function = xdstrdup("{main}");
tmp->function.class = NULL;
tmp->function.type = XFUNC_NORMAL;
} else if (tmp->function.type & XFUNC_INCLUDES) {
tmp->lineno = 0;
if (opline_ptr) {
cur_opcode = *opline_ptr;
if (cur_opcode) {
tmp->lineno = cur_opcode->lineno;
}
}
if (tmp->function.type == XFUNC_EVAL) {
tmp->include_filename = xdebug_sprintf("%s", XG(last_eval_statement));
} else if (XG(collect_includes)) {
tmp->include_filename = xdstrdup(zend_get_executed_filename(TSRMLS_C));
}
} else {
tmp->lineno = find_line_number_for_current_execute_point(edata TSRMLS_CC);
tmp->is_variadic = !!(zdata->func->common.fn_flags & ZEND_ACC_VARIADIC);
if (XG(collect_params) || XG(collect_vars) || xdebug_is_debug_connection_active_for_current_pid()) {
int arguments_sent = 0, arguments_wanted = 0, arguments_storage = 0;
/* This calculates how many arguments where sent to a function. It
* works for both internal and user defined functions.
* op_array->num_args works only for user defined functions so
* we're not using that here. */
arguments_sent = ZEND_CALL_NUM_ARGS(zdata);
arguments_wanted = arguments_sent;
if (ZEND_USER_CODE(zdata->func->type)) {
arguments_wanted = op_array->num_args;
}
if (ZEND_USER_CODE(zdata->func->type) && zdata->func->common.fn_flags & ZEND_ACC_VARIADIC) {
arguments_wanted++;
arguments_sent++;
}
if (arguments_wanted > arguments_sent) {
arguments_storage = arguments_wanted;
} else {
arguments_storage = arguments_sent;
}
tmp->var = xdmalloc(arguments_storage * sizeof (xdebug_var_name));
for (i = 0; i < arguments_sent; i++) {
tmp->var[tmp->varc].name = NULL;
ZVAL_UNDEF(&tmp->var[tmp->varc].data);
tmp->var[tmp->varc].length = 0;
tmp->var[tmp->varc].is_variadic = 0;
/* Because it is possible that more parameters are sent, then
* actually wanted we can only access the name in case there
* is an associated variable to receive the variable here. */
if (tmp->user_defined == XDEBUG_EXTERNAL && i < arguments_wanted) {
if (op_array->arg_info[i].name) {
tmp->var[tmp->varc].name = xdstrdup(STR_NAME_VAL(op_array->arg_info[i].name));
tmp->var[tmp->varc].length = STR_NAME_LEN(op_array->arg_info[i].name);
}
if (op_array->arg_info[i].is_variadic) {
tmp->var[tmp->varc].is_variadic = 1;
}
if (op_array->arg_info[i].is_variadic && !hit_variadic) {
tmp->var[tmp->varc].is_variadic = 1;
hit_variadic = 1;
}
}
if (XG(collect_params)) {
if ((i < arguments_wanted) || ((zdata->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && (i < arguments_sent))) {
if (ZEND_CALL_ARG(zdata, tmp->varc+1)) {
ZVAL_COPY_VALUE(&(tmp->var[tmp->varc].data), ZEND_CALL_ARG(zdata, tmp->varc+1));
}
} else {
ZVAL_COPY_VALUE(&(tmp->var[tmp->varc].data), ZEND_CALL_VAR_NUM(zdata, zdata->func->op_array.last_var + zdata->func->op_array.T + i - arguments_wanted));
}
}
tmp->varc++;
}
/* Sometimes not enough arguments are send to a user defined
* function, so we have to gather only the name for those extra. */
if (tmp->user_defined == XDEBUG_EXTERNAL && arguments_sent < arguments_wanted) {
for (i = arguments_sent; i < arguments_wanted; i++) {
if (op_array->arg_info[i].name) {
tmp->var[tmp->varc].name = xdstrdup(STR_NAME_VAL(op_array->arg_info[i].name));
tmp->var[tmp->varc].length = STR_NAME_LEN(op_array->arg_info[i].name);
}
ZVAL_UNDEF(&tmp->var[tmp->varc].data);
tmp->var[tmp->varc].is_variadic = 0;
tmp->varc++;
}
}
}
}
/* Now we have location and name, we can run the filter */
xdebug_filter_run_tracing(tmp);
/* Count code coverage line for call */
if (XG(do_code_coverage)) {
if (!op_array->reserved[XG(code_coverage_filter_offset)] && XG(code_coverage_branch_check)) {
xdebug_count_line(tmp->filename, tmp->lineno, 0, 0 TSRMLS_CC);
}
}
if (XG(do_monitor_functions)) {
char *func_name = xdebug_show_fname(tmp->function, 0, 0 TSRMLS_CC);
int func_name_len = strlen(func_name);
void *dummy;
if (xdebug_hash_find(XG(functions_to_monitor), func_name, func_name_len, (void *) &dummy)) {
xdebug_function_monitor_record(func_name, tmp->filename, tmp->lineno TSRMLS_CC);
}
xdfree(func_name);
}
if (XG(profiler_aggregate)) {
char *func_name = xdebug_show_fname(tmp->function, 0, 0 TSRMLS_CC);
aggr_key = xdebug_sprintf("%s.%s.%d", tmp->filename, func_name, tmp->lineno);
aggr_key_len = strlen(aggr_key);
aggr_key_str = zend_string_init(aggr_key, aggr_key_len, 0);
if ((tmp->aggr_entry = zend_hash_find_ptr(&XG(aggr_calls), aggr_key_str)) == NULL) {
xdebug_aggregate_entry xae;
if (tmp->user_defined == XDEBUG_EXTERNAL) {
xae.filename = xdstrdup(tmp->op_array->filename->val);
} else {
xae.filename = xdstrdup("php:internal");
}
xae.function = func_name;
xae.lineno = tmp->lineno;
xae.user_defined = tmp->user_defined;
xae.call_count = 0;
xae.time_own = 0;
xae.time_inclusive = 0;
xae.call_list = NULL;
zend_hash_add_ptr(&XG(aggr_calls), aggr_key_str, &xae);
}
}
if (XG(stack)) {
if (XDEBUG_LLIST_TAIL(XG(stack))) {
function_stack_entry *prev = XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack)));
tmp->prev = prev;
if (XG(profiler_aggregate)) {
if (prev->aggr_entry->call_list) {
if (!zend_hash_exists(prev->aggr_entry->call_list, aggr_key_str)) {
zend_hash_add_ptr(prev->aggr_entry->call_list, aggr_key_str, tmp->aggr_entry);
}
} else {
prev->aggr_entry->call_list = xdmalloc(sizeof(HashTable));
zend_hash_init_ex(prev->aggr_entry->call_list, 1, NULL, NULL, 1, 0);
zend_hash_add_ptr(prev->aggr_entry->call_list, aggr_key_str, tmp->aggr_entry);
}
}
}
xdebug_llist_insert_next(XG(stack), XDEBUG_LLIST_TAIL(XG(stack)), tmp);
}
if (XG(profiler_aggregate)) {
zend_string_release(aggr_key_str);
xdfree(aggr_key);
}
return tmp;
}
/* {{{ proto int xdebug_get_stack_depth()
Returns the stack depth */
PHP_FUNCTION(xdebug_get_stack_depth)
{
/* We substract one so that the function call to xdebug_get_stack_depth()
* is not part of the returned depth. */
RETURN_LONG(XG(stack)->size - 1);
}
/* {{{ proto array xdebug_get_function_stack()
Returns an array representing the current stack */
PHP_FUNCTION(xdebug_get_function_stack)
{
xdebug_llist_element *le;
unsigned int j;
unsigned int k;
zval *frame;
zval *params;
array_init(return_value);
le = XDEBUG_LLIST_HEAD(XG(stack));
for (k = 0; k < XG(stack)->size - 1; k++, le = XDEBUG_LLIST_NEXT(le)) {
function_stack_entry *i = XDEBUG_LLIST_VALP(le);
if (i->function.function) {
if (strcmp(i->function.function, "xdebug_get_function_stack") == 0) {
return;
}
}
/* Initialize frame array */
XDEBUG_MAKE_STD_ZVAL(frame);
array_init(frame);
/* Add data */
if (i->function.function) {
add_assoc_string_ex(frame, "function", HASH_KEY_SIZEOF("function"), i->function.function);
}
if (i->function.class) {
add_assoc_string_ex(frame, "type", HASH_KEY_SIZEOF("type"), (char*) (i->function.type == XFUNC_STATIC_MEMBER ? "static" : "dynamic"));
add_assoc_string_ex(frame, "class", HASH_KEY_SIZEOF("class"), i->function.class );
}
add_assoc_string_ex(frame, "file", HASH_KEY_SIZEOF("file"), i->filename);
add_assoc_long_ex(frame, "line", HASH_KEY_SIZEOF("line"), i->lineno);
/* Add parameters */
XDEBUG_MAKE_STD_ZVAL(params);
array_init(params);
add_assoc_zval_ex(frame, "params", HASH_KEY_SIZEOF("params"), params);
for (j = 0; j < i->varc; j++) {
int variadic_opened = 0;
xdebug_str *argument = NULL;
if (i->var[j].is_variadic) {
zval *vparams;
XDEBUG_MAKE_STD_ZVAL(vparams);
array_init(vparams);
if (i->var[j].name) {
add_assoc_zval(params, i->var[j].name, vparams);
} else {
add_index_zval(params, j, vparams);
}
efree(params);
params = vparams;
variadic_opened = 1;
continue;
}
if (!Z_ISUNDEF(i->var[j].data)) {
argument = xdebug_get_zval_value(&i->var[j].data, 0, NULL);
} else {
argument = xdebug_str_create_from_char((char*) "???");
}
if (i->var[j].name && !variadic_opened && argument) {
add_assoc_stringl_ex(params, i->var[j].name, i->var[j].length, argument->d, argument->l);
} else {
add_index_stringl(params, j - 1, argument->d, argument->l);
}
if (argument) {
xdebug_str_free(argument);
argument = NULL;
}
}
if (i->include_filename) {
add_assoc_string_ex(frame, "include_filename", HASH_KEY_SIZEOF("include_filename"), i->include_filename);
}
add_next_index_zval(return_value, frame);
efree(params);
efree(frame);
}
}
/* }}} */
void xdebug_attach_used_var_names(void *return_value, xdebug_hash_element *he)
{
xdebug_str *name = (xdebug_str*) he->ptr;
add_next_index_string(return_value, name->d);
}
/* {{{ proto array xdebug_get_declared_vars()
Returns an array representing the current stack */
PHP_FUNCTION(xdebug_get_declared_vars)
{
xdebug_llist_element *le;
function_stack_entry *i;
xdebug_hash *tmp_hash;
array_init(return_value);
le = XDEBUG_LLIST_TAIL(XG(stack));
le = XDEBUG_LLIST_PREV(le);
i = XDEBUG_LLIST_VALP(le);
/* Add declared vars */
if (i->declared_vars) {
tmp_hash = xdebug_declared_var_hash_from_llist(i->declared_vars);
xdebug_hash_apply(tmp_hash, (void *) return_value, xdebug_attach_used_var_names);
xdebug_hash_destroy(tmp_hash);
}
}
/* }}} */
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。