And here is a version which flattens the calling args onto a single line (similar to sebastians usersapce script). Longer, but a bit prettier output.



Index: Zend/zend.c
===================================================================
RCS file: /repository/Zend/zend.c,v
retrieving revision 1.163
diff -u -3 -r1.163 zend.c
--- Zend/zend.c 17 Nov 2002 13:26:36 -0000      1.163
+++ Zend/zend.c 27 Nov 2002 23:07:00 -0000
@@ -138,6 +138,35 @@
 }
 
 
+static void print_flat_hash(HashTable *ht)
+{
+       zval **tmp;
+       char *string_key;
+       HashPosition iterator;
+       ulong num_key;
+       uint str_len;
+       int i = 0;
+
+       zend_hash_internal_pointer_reset_ex(ht, &iterator);
+       while (zend_hash_get_current_data_ex(ht, (void **) &tmp, &iterator) == 
+SUCCESS) {
+               if(i++ > 0) {
+                   ZEND_PUTS(",");
+               }
+               ZEND_PUTS("[");
+               switch (zend_hash_get_current_key_ex(ht, &string_key, &str_len, 
+&num_key, 0, &iterator)) {
+                       case HASH_KEY_IS_STRING:
+                               ZEND_PUTS(string_key);
+                               break;
+                       case HASH_KEY_IS_LONG:
+                               zend_printf("%ld", num_key);
+                               break;
+               }
+               ZEND_PUTS("] => ");
+               zend_print_flat_zval_r(*tmp);
+               zend_hash_move_forward_ex(ht, &iterator);
+       }
+}
+
 ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy)
 {
        if (expr->type==IS_STRING) {
@@ -215,6 +244,43 @@
 }
 
 
+ZEND_API void zend_print_flat_zval_r(zval *expr)
+{
+       zend_write_func_t write_func = zend_write;
+
+       switch(expr->type) {
+               case IS_ARRAY:
+                       ZEND_PUTS("Array (");
+                       if (++expr->value.ht->nApplyCount>1) {
+                               ZEND_PUTS(" *RECURSION*");
+                               expr->value.ht->nApplyCount--;
+                               return;
+                       }
+                       print_flat_hash(expr->value.ht);
+                       ZEND_PUTS(")");
+                       expr->value.ht->nApplyCount--;
+                       break;
+               case IS_OBJECT:
+                       {
+                               zend_object *object = Z_OBJ_P(expr);
+
+                               if (++object->properties->nApplyCount>1) {
+                                       ZEND_PUTS(" *RECURSION*");
+                                       object->properties->nApplyCount--;
+                                       return;
+                               }
+                               zend_printf("%s Object (", object->ce->name);
+                               print_flat_hash(object->properties);
+                               ZEND_PUTS(")");
+                               object->properties->nApplyCount--;
+                               break;
+                       }
+               default:
+                       zend_print_variable(expr);
+                       break;
+       }
+}
+
 ZEND_API void zend_print_zval_r(zval *expr, int indent)
 {
        zend_print_zval_r_ex(zend_write, expr, indent);
@@ -253,6 +319,7 @@
                        break;
        }
 }
+
 
 
 static FILE *zend_fopen_wrapper(const char *filename, char **opened_path)
Index: Zend/zend.h
===================================================================
RCS file: /repository/Zend/zend.h,v
retrieving revision 1.166
diff -u -3 -r1.166 zend.h
--- Zend/zend.h 17 Nov 2002 13:26:36 -0000      1.166
+++ Zend/zend.h 27 Nov 2002 23:07:00 -0000
@@ -383,6 +383,7 @@
 ZEND_API int zend_print_zval(zval *expr, int indent);
 ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent);
 ZEND_API void zend_print_zval_r(zval *expr, int indent);
+ZEND_API void zend_print_flat_zval_r(zval *expr);
 ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int 
indent);
 ZEND_API void zend_output_debug_string(zend_bool trigger_break, char *format, ...);
 
Index: Zend/zend_builtin_functions.c
===================================================================
RCS file: /repository/Zend/zend_builtin_functions.c,v
retrieving revision 1.127
diff -u -3 -r1.127 zend_builtin_functions.c
--- Zend/zend_builtin_functions.c       27 Nov 2002 20:11:39 -0000      1.127
+++ Zend/zend_builtin_functions.c       27 Nov 2002 23:07:00 -0000
@@ -68,6 +68,7 @@
 static ZEND_FUNCTION(get_extension_funcs);
 static ZEND_FUNCTION(get_defined_constants);
 static ZEND_FUNCTION(debug_backtrace);
+static ZEND_FUNCTION(debug_print_backtrace);
 #if ZEND_DEBUG
 static ZEND_FUNCTION(zend_test_func);
 #endif
@@ -122,6 +123,7 @@
        ZEND_FE(get_extension_funcs,            NULL)
        ZEND_FE(get_defined_constants,          NULL)
        ZEND_FE(debug_backtrace,                        NULL)
+       ZEND_FE(debug_print_backtrace,                  NULL)
 #if ZEND_DEBUG
        ZEND_FE(zend_test_func,         NULL)
 #endif
@@ -1171,6 +1173,151 @@
                add_next_index_zval(arg_array, *arg);
        }
        return arg_array;
+}
+
+
+void debug_print_backtrace_args(zval *arg_array) 
+{
+    zval **tmp;
+    HashPosition iterator;
+    int i = 0;
+    
+    zend_hash_internal_pointer_reset_ex(arg_array->value.ht, &iterator);
+    while (zend_hash_get_current_data_ex(arg_array->value.ht, (void **) &tmp, 
+&iterator) == SUCCESS) {
+       if(i++) {
+           ZEND_PUTS(", ");
+       }
+       zend_print_flat_zval_r(*tmp);
+       zend_hash_move_forward_ex(arg_array->value.ht, &iterator);
+    }
+}
+    
+/* {{{ proto void debug_backtrace(void)
+   Prints out a backtrace */
+ZEND_FUNCTION(debug_print_backtrace)
+{
+       zend_execute_data *ptr;
+       int lineno;
+       char *function_name;
+       char *filename;
+       char *class_name;
+       char *call_type;
+       char *include_filename = NULL;
+       zval *stack_frame;
+       zval *arg_array;
+       void **cur_arg_pos = EG(argument_stack).top_element;
+       void **args = cur_arg_pos;
+       int arg_stack_consistent = 0;
+       int frames_on_stack = 0;
+       int indent = 0;
+       int i;
+
+       if (ZEND_NUM_ARGS()) {
+               ZEND_WRONG_PARAM_COUNT();
+       }
+
+       while (--args >= EG(argument_stack).elements) {
+               if (*args--) {
+                       break;
+               }
+               args -= *(ulong*)args;
+               frames_on_stack++;
+
+               if (args == EG(argument_stack).elements) {
+                       arg_stack_consistent = 1;
+                       break;
+               }
+       }
+
+       ptr = EG(current_execute_data);
+
+       /* skip debug_backtrace() */
+       ptr = ptr->prev_execute_data;
+       cur_arg_pos -= 2;
+       frames_on_stack--;
+
+       array_init(return_value);
+
+       while (ptr) {
+               if (ptr->op_array) {
+                       filename = ptr->op_array->filename;
+                       lineno = ptr->opline->lineno;
+               } else {
+                       filename = NULL;
+               }
+
+               function_name = ptr->function_state.function->common.function_name;
+
+               if (function_name) {
+                       if (ptr->ce) {
+                               class_name = ptr->ce->name;
+                               call_type = "::";
+                       } else if (ptr->object.ptr) {
+                               class_name = ptr->object.ptr->value.obj.ce->name;
+                               call_type = "->";
+                       } else {
+                               class_name = NULL;
+                               call_type = NULL;
+                       }
+                       if ((! ptr->opline) || ((ptr->opline->opcode == 
+ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) {
+                               if (arg_stack_consistent && (frames_on_stack > 0)) {
+                                       arg_array = 
+debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC);
+                                       frames_on_stack--;
+                               }
+                       }       
+               } 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) {
+                               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);
+                       }
+
+               }
+               zend_printf("#%-2d ", indent);
+               if(class_name) {
+                       ZEND_PUTS(class_name);
+                       ZEND_PUTS(call_type);
+               }
+               zend_printf("%s(", function_name?function_name:"main");
+               debug_print_backtrace_args(arg_array);
+               ZVAL_DELREF(arg_array);
+               zend_printf(") called at [%s:%d]\n", filename, lineno);
+               include_filename = filename; 
+               ptr = ptr->prev_execute_data;
+               ++indent;
+       }
 }
 
 /* {{{ proto void debug_backtrace(void)

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to