summaryrefslogtreecommitdiff
path: root/Zend/zend_builtin_functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_builtin_functions.c')
-rw-r--r--Zend/zend_builtin_functions.c143
1 files changed, 125 insertions, 18 deletions
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index f58ab23876..5a49e761f4 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1247,6 +1247,26 @@ ZEND_FUNCTION(get_defined_constants)
/* }}} */
+static zval *debug_backtrace_get_args(void ***curpos TSRMLS_DC) {
+ void **p = *curpos - 2;
+ zval *arg_array, **arg;
+ int arg_count = (ulong) *p;
+
+ *curpos -= (arg_count+2);
+
+ MAKE_STD_ZVAL(arg_array);
+ array_init(arg_array);
+ p -= arg_count;
+
+ while (--arg_count >= 0) {
+ arg = (zval **) p++;
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(arg);
+ (*arg)->refcount++;
+ add_next_index_zval(arg_array, *arg);
+ }
+ return arg_array;
+}
+
/* {{{ proto void debug_backtrace(void)
Prints out a backtrace */
ZEND_FUNCTION(debug_backtrace)
@@ -1256,43 +1276,130 @@ ZEND_FUNCTION(debug_backtrace)
char *function_name;
char *filename;
char *class_name;
+ char *call_type;
+ char *include_filename = NULL;
zval *stack_frame;
+ void **cur_arg_pos = EG(argument_stack).top_element;
+ void **args = cur_arg_pos;
+ int arg_stack_consistent = 0;
+
+ if (ZEND_NUM_ARGS()) {
+ WRONG_PARAM_COUNT;
+ }
+
+ while (--args >= EG(argument_stack).elements) {
+ if (*args--) {
+ break;
+ }
+ args -= *(ulong*)args;
+
+ if (args == EG(argument_stack).elements) {
+ arg_stack_consistent = 1;
+ break;
+ }
+ }
ptr = EG(current_execute_data);
- /* Skip debug_backtrace() itself */
+ /* skip debug_backtrace() */
ptr = ptr->prev_execute_data;
-
+ cur_arg_pos -= 2;
+
array_init(return_value);
while (ptr) {
MAKE_STD_ZVAL(stack_frame);
array_init(stack_frame);
- class_name = NULL;
-
- if (ptr->object) {
- class_name = Z_OBJCE(*ptr->object)->name;
- }
- if (ptr->function_state.function->common.scope) {
- class_name = ptr->function_state.function->common.scope->name;
+ if (ptr->op_array) {
+ filename = ptr->op_array->filename;
+ lineno = ptr->opline->lineno;
+ add_assoc_string_ex(stack_frame, "file", sizeof("file"), filename, 1);
+ add_assoc_long_ex(stack_frame, "line", sizeof("line"), lineno);
+
+ /* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function
+ * and debug_baktrace() might have been called by the error_handler. in this case we don't
+ * want to pop anything of the argument-stack */
+ } else {
+ filename = NULL;
}
+
function_name = ptr->function_state.function->common.function_name;
-
- filename = ptr->op_array->filename;
- lineno = ptr->opline->lineno;
if (function_name) {
add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1);
+
+ if (ptr->object) {
+ class_name = Z_OBJCE(*ptr->object)->name;
+ call_type = "->";
+ } else if (ptr->function_state.function->common.scope) {
+ class_name = ptr->function_state.function->common.scope->name;
+ call_type = "::";
+ } else {
+ class_name = NULL;
+ call_type = NULL;
+ }
+
+ if (class_name) {
+ add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, 1);
+ add_assoc_string_ex(stack_frame, "type", sizeof("type"), call_type, 1);
+ }
+
+ if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) {
+ if (arg_stack_consistent) {
+ add_assoc_zval_ex(stack_frame, "args", sizeof("args"), debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC));
+ }
+ }
+ } else {
+ /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
+ zend_bool build_filename_arg = 1;
+
+ switch (ptr->opline->op2.u.constant.value.lval) {
+ case ZEND_EVAL:
+ function_name = "eval";
+ build_filename_arg = 0;
+ break;
+ case ZEND_INCLUDE:
+ function_name = "include";
+ break;
+ case ZEND_REQUIRE:
+ function_name = "require";
+ break;
+ case ZEND_INCLUDE_ONCE:
+ function_name = "include_once";
+ break;
+ case ZEND_REQUIRE_ONCE:
+ function_name = "require_once";
+ break;
+ default:
+ /* this can actually happen if you use debug_backtrace() in your error_handler and
+ * you're in the top-scope */
+ function_name = "unknown";
+ build_filename_arg = 0;
+ break;
+ }
+
+ if (build_filename_arg && include_filename) {
+ zval *arg_array;
+
+ MAKE_STD_ZVAL(arg_array);
+ array_init(arg_array);
+
+ /* include_filename always points to the last filename of the last last called-fuction.
+ if we have called include in the frame above - this is the file we have included.
+ */
+
+ add_next_index_string(arg_array, include_filename, 1);
+ add_assoc_zval_ex(stack_frame, "args", sizeof("args"), arg_array);
+ }
+
+ add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1);
}
- if (class_name) {
- add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, 1);
- }
- add_assoc_string_ex(stack_frame, "file", sizeof("file"), filename, 1);
- add_assoc_long_ex(stack_frame, "line", sizeof("line"), lineno);
- /* add_assoc_stringl_ex(stack_frame, "class", sizeof("class")-1, class_name, class_name_length, 1); */
+
add_next_index_zval(return_value, stack_frame);
+ include_filename = filename;
+
ptr = ptr->prev_execute_data;
}
}