hi,
this patch adds the extremely useful debug_backtrace() function to ZE1. as it's more-or-less the same implementation as in ZE2 so it should be "fast and efficient" enough for inclusion in 4.3 IMHO. it has one extra feature over the ZE2 implementation by giving some extra information if a method was called using :: or -> (see the 'type' attribute in the array returned by debug_backtrace). zeev, andi one question: i had to comment line 1628 (just apply the patch and see for yourself) to make the following code work correctly (= show the class in the backtrace): <?php class a { function dump() { var_dump(debug_backtrace()); } } $a = new a; $a->dump(); ?> (just uncomment line 1628 in the patched sources and see how the output of debug_backtrace doesn't show the class-name for this script any more) i don't think that commenting this line will have any side-effect as EG(object).ptr will be re-initialized in 1665 and i don't see any references to it in between. i'd love to have this included in 4.3.0 and i think a lot of people would be happy as well. implementation: to make this whole thing work i simply added the class_entry to the execute_data and am pushing and popping it together with (object).ptr. if this patch gets accepted i'll add an php.ini seting so that errors and warnings will optionally have the full call-stack. comments are welcome - especially from andi & zeev. tc PS: patch is against -HEAD -- Thies C. Arnzten - Looking for all sorts of freelance work - just ask.. Whishlist: http://www.amazon.de/exec/obidos/wishlist/AB9DY62QWDSZ/ref=wl_em_to
? ext/tca_prof Index: Zend/zend_builtin_functions.c =================================================================== RCS file: /repository/Zend/zend_builtin_functions.c,v retrieving revision 1.118 diff -u -r1.118 zend_builtin_functions.c --- Zend/zend_builtin_functions.c 12 Jun 2002 17:02:22 -0000 1.118 +++ Zend/zend_builtin_functions.c 16 Aug 2002 17:22:01 -0000 @@ -65,6 +65,7 @@ static ZEND_FUNCTION(extension_loaded); static ZEND_FUNCTION(get_extension_funcs); static ZEND_FUNCTION(get_defined_constants); +static ZEND_FUNCTION(debug_backtrace); #if ZEND_DEBUG static ZEND_FUNCTION(zend_test_func); #endif @@ -116,6 +117,7 @@ ZEND_FE(extension_loaded, NULL) ZEND_FE(get_extension_funcs, NULL) ZEND_FE(get_defined_constants, NULL) + ZEND_FE(debug_backtrace, NULL) #if ZEND_DEBUG ZEND_FE(zend_test_func, NULL) #endif @@ -1133,6 +1135,69 @@ array_init(return_value); zend_hash_apply_with_argument(EG(zend_constants), (apply_func_arg_t) add_constant_info, return_value TSRMLS_CC); } + +/* {{{ proto void debug_backtrace(void) + Prints out a backtrace */ +ZEND_FUNCTION(debug_backtrace) +{ + zend_execute_data *ptr; + int lineno; + char *function_name; + char *filename; + char *class_name; + zend_uint class_name_length; + zval *stack_frame; + + ptr = EG(execute_data_ptr); + + /* Skip debug_backtrace() itself */ + ptr = ptr->prev_execute_data; + + array_init(return_value); + + while (ptr) { + MAKE_STD_ZVAL(stack_frame); + array_init(stack_frame); + + +/* if (ptr->object) { + class_name = Z_OBJCE(*ptr->object)->name; + class_name_length = Z_OBJCE(*ptr->object)->name_length; + } + if (ptr->function_state.function->common.scope) { + class_name = ptr->function_state.function->common.scope->name; + } +*/ + if (ptr->ce) { + add_assoc_string_ex(stack_frame, "type", sizeof("type"), "::", +1); + class_name = ptr->ce->name; + } else if (ptr->object.ptr) { + add_assoc_string_ex(stack_frame, "type", sizeof("type"), "->", +1); + class_name = ptr->object.ptr->value.obj.ce->name; + + } else { + class_name = 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 (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_next_index_zval(return_value, stack_frame); + + ptr = ptr->prev_execute_data; + } +} +/* }}} */ /* {{{ proto bool extension_loaded(string extension_name) Index: Zend/zend_execute.c =================================================================== RCS file: /repository/Zend/zend_execute.c,v retrieving revision 1.300 diff -u -r1.300 zend_execute.c --- Zend/zend_execute.c 2 Aug 2002 20:21:38 -0000 1.300 +++ Zend/zend_execute.c 16 Aug 2002 17:22:02 -0000 @@ -1000,14 +1000,17 @@ { zend_execute_data execute_data; - EG(execute_data_ptr) = &execute_data; - /* Initialize execute_data */ EX(fbc) = NULL; + EX(ce) = NULL; EX(object).ptr = NULL; + EX(op_array) = op_array; EX(Ts) = (temp_variable *) do_alloca(sizeof(temp_variable)*op_array->T); + EX(prev_execute_data) = EG(execute_data_ptr); EX(original_in_execution)=EG(in_execution); + EG(execute_data_ptr) = &execute_data; + EG(in_execution) = 1; if (op_array->start_op) { EX(opline) = op_array->start_op; @@ -1479,7 +1482,7 @@ HashTable *active_function_table; zval tmp; - zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr); + zend_ptr_stack_n_push(&EG(arg_types_stack), 3, +EX(fbc), EX(object).ptr, EX(ce)); if (EX(opline)->extended_value & ZEND_CTOR_CALL) { /* constructor call */ @@ -1497,10 +1500,9 @@ convert_to_string(&tmp); function_name = &tmp; zend_str_tolower(tmp.value.str.val, tmp.value.str.len); - + EX(ce) = NULL; + if (EX(opline)->op1.op_type != IS_UNUSED) { if (EX(opline)->op1.op_type==IS_CONST) { /* used for class_name::function() */ - zend_class_entry *ce; zval **object_ptr_ptr; if (zend_hash_find(EG(active_symbol_table), "this", sizeof("this"), (void **) &object_ptr_ptr)==FAILURE) { @@ -1511,10 +1513,10 @@ EX(object).ptr = *object_ptr_ptr; EX(object).ptr->refcount++; /* For this pointer */ } - if (zend_hash_find(EG(class_table), EX(opline)->op1.u.constant.value.str.val, EX(opline)->op1.u.constant.value.str.len+1, (void **) &ce)==FAILURE) { /* class doesn't exist */ + if +(zend_hash_find(EG(class_table), EX(opline)->op1.u.constant.value.str.val, +EX(opline)->op1.u.constant.value.str.len+1, (void **) &EX(ce))==FAILURE) { /* class +doesn't exist */ zend_error(E_ERROR, "Undefined class name '%s'", EX(opline)->op1.u.constant.value.str.val); } - active_function_table = &ce->function_table; + active_function_table = +&EX(ce)->function_table; } else { /* used for member function calls */ EX(object).ptr = _get_object_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1) TSRMLS_CC); @@ -1572,8 +1574,9 @@ zend_error(E_ERROR, "Unknown function: %s()\n", fname->value.str.val); } FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1)); - zend_ptr_stack_push(&EG(arg_types_stack), EX(object).ptr); + zend_ptr_stack_n_push(&EG(arg_types_stack), 2, +EX(object).ptr, EX(ce)); EX(object).ptr = NULL; + EX(ce) = NULL; goto do_fcall_common; } do_fcall_common: @@ -1623,7 +1626,7 @@ zend_error(E_WARNING, "Problem with method call - please report this bug"); } *this_ptr = EX(object).ptr; - EX(object).ptr = NULL; + /* EX(object).ptr = NULL; */ } original_return_value = EG(return_value_ptr_ptr); EG(return_value_ptr_ptr) = EX(Ts)[EX(opline)->result.u.var].var.ptr_ptr; @@ -1659,9 +1662,9 @@ } } if (EX(opline)->opcode == ZEND_DO_FCALL_BY_NAME) { - zend_ptr_stack_n_pop(&EG(arg_types_stack), 2, &EX(object).ptr, &EX(fbc)); + +zend_ptr_stack_n_pop(&EG(arg_types_stack), 3, &EX(ce), &EX(object).ptr, &EX(fbc)); } else { - EX(object).ptr = zend_ptr_stack_pop(&EG(arg_types_stack)); + +zend_ptr_stack_n_pop(&EG(arg_types_stack), 2, &EX(ce), &EX(object).ptr); } EX(function_state).function = (zend_function *) op_array; EG(function_state_ptr) = &EX(function_state); @@ -1709,6 +1712,7 @@ } free_alloca(EX(Ts)); EG(in_execution) = EX(original_in_execution); + EG(execute_data_ptr) = EX(prev_execute_data); return; } break; Index: Zend/zend_execute_globals.h =================================================================== RCS file: /repository/Zend/zend_execute_globals.h,v retrieving revision 1.1 diff -u -r1.1 zend_execute_globals.h --- Zend/zend_execute_globals.h 16 May 2002 04:28:18 -0000 1.1 +++ Zend/zend_execute_globals.h 16 Aug 2002 17:22:02 -0000 @@ -55,9 +55,12 @@ zend_op *opline; zend_function_state function_state; zend_function *fbc; /* Function Being Called */ + zend_class_entry *ce; object_info object; temp_variable *Ts; zend_bool original_in_execution; + zend_op_array *op_array; + struct _zend_execute_data *prev_execute_data; } zend_execute_data; #endif
-- PHP Development Mailing List <http://www.php.net/> To unsubscribe, visit: http://www.php.net/unsub.php