Skip to content
Browse files

Initial support for built-in backtracing.

There are still a few problems such as includes and calling other functions
from internal functions which aren't seen (will have to think if and how to
fix this).
Also the main scripts filename isn't available. Need to think about that.
  • Loading branch information...
1 parent 7a64b2b commit 7e5ec2d7616ec1a2573b76d3222333cc36e4dd3c @andigutmans andigutmans committed May 2, 2002
Showing with 85 additions and 52 deletions.
  1. +0 −1 Zend/zend.h
  2. +29 −0 Zend/zend_builtin_functions.c
  3. +13 −0 Zend/zend_compile.h
  4. +39 −51 Zend/zend_execute.c
  5. +2 −0 Zend/zend_execute_API.c
  6. +2 −0 Zend/zend_globals.h
View
1 Zend/zend.h
@@ -297,7 +297,6 @@ struct _zend_class_entry {
};
-
typedef struct _zend_utility_functions {
void (*error_function)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);
int (*printf_function)(const char *format, ...);
View
29 Zend/zend_builtin_functions.c
@@ -65,6 +65,7 @@ static ZEND_FUNCTION(get_loaded_extensions);
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 @@ static zend_function_entry builtin_functions[] = {
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
@@ -1180,6 +1182,33 @@ ZEND_FUNCTION(get_defined_constants)
}
+/* {{{ proto void debug_backtrace(void)
+ Prints out a backtrace */
+ZEND_FUNCTION(debug_backtrace)
+{
+ zend_execute_data *ptr;
+ int lineno;
+
+
+ ptr = EG(current_execute_data);
+ lineno = ptr->opline->lineno;
+
+ ptr = ptr->prev_execute_data;
+
+ while (ptr) {
+ if (ptr->object) {
+ printf("%s::", Z_OBJCE(*ptr->object)->name);
+ }
+ printf("%s() [%s:%d]\n", ptr->function_state.function->common.function_name, ptr->function_state.function->op_array.filename, lineno);
+ lineno = ptr->opline->lineno;
+ ptr = ptr->prev_execute_data;
+ }
+
+ printf("main() [...:%d]\n", lineno);
+ RETURN_TRUE;
+}
+
+
/* {{{ proto bool extension_loaded(string extension_name)
Returns true if the named extension is loaded */
ZEND_FUNCTION(extension_loaded)
View
13 Zend/zend_compile.h
@@ -181,6 +181,19 @@ typedef struct _zend_file_handle {
zend_bool free_filename;
} zend_file_handle;
+union _temp_variable;
+
+typedef struct _zend_execute_data {
+ struct _zend_op *opline;
+ zend_function_state function_state;
+ zend_function *fbc; /* Function Being Called */
+ zend_function *fbc_constructor;
+ zval *object;
+ union _temp_variable *Ts;
+ zend_bool original_in_execution;
+ zend_class_entry *calling_scope;
+ struct _zend_execute_data *prev_execute_data;
+} zend_execute_data;
#define IS_CONST (1<<0)
View
90 Zend/zend_execute.c
@@ -1127,23 +1127,9 @@ static int zend_check_symbol(zval **pz TSRMLS_DC)
#define RETURN_FROM_EXECUTE_LOOP(execute_data) \
free_alloca(EX(Ts)); \
EG(in_execution) = EX(original_in_execution); \
+ EG(current_execute_data) = EX(prev_execute_data); \
return;
-typedef struct _object_info {
- zval *ptr;
-} object_info;
-
-typedef struct _zend_execute_data {
- zend_op *opline;
- zend_function_state function_state;
- zend_function *fbc; /* Function Being Called */
- zend_function *fbc_constructor;
- object_info object;
- temp_variable *Ts;
- zend_bool original_in_execution;
- zend_class_entry *calling_scope;
-} zend_execute_data;
-
#define EX(element) execute_data.element
ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
@@ -1152,9 +1138,11 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
/* Initialize execute_data */
EX(fbc) = NULL;
- EX(object).ptr = NULL;
+ EX(object) = NULL;
EX(Ts) = (temp_variable *) do_alloca(sizeof(temp_variable)*op_array->T);
- EX(original_in_execution)=EG(in_execution);
+ EX(original_in_execution) = EG(in_execution);
+ EX(prev_execute_data) = EG(current_execute_data);
+ EG(current_execute_data) = &execute_data;
EG(in_execution) = 1;
if (op_array->start_op) {
@@ -1873,29 +1861,29 @@ binary_assign_op_addr: {
}
case ZEND_INIT_CTOR_CALL:
{
- zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr);
+ zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object));
if (EX(opline)->op1.op_type == IS_VAR) {
SELECTIVE_PZVAL_LOCK(*EX(Ts)[EX(opline)->op1.u.var].var.ptr_ptr, &EX(opline)->op1);
}
/* We are not handling overloaded classes right now */
- EX(object).ptr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
- if (!PZVAL_IS_REF(EX(object).ptr)) {
- EX(object).ptr->refcount++; /* For $this pointer */
+ EX(object) = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
+ if (!PZVAL_IS_REF(EX(object))) {
+ EX(object)->refcount++; /* For $this pointer */
} else {
zval *this_ptr;
ALLOC_ZVAL(this_ptr);
- *this_ptr = *EX(object).ptr;
+ *this_ptr = *EX(object);
INIT_PZVAL(this_ptr);
zval_copy_ctor(this_ptr);
- EX(object).ptr = this_ptr;
+ EX(object) = this_ptr;
}
EX(fbc) = EX(fbc_constructor);
if(EX(fbc)->type == ZEND_USER_FUNCTION) { /* HACK!! */
- EX(calling_scope) = Z_OBJCE_P(EX(object).ptr);
+ EX(calling_scope) = Z_OBJCE_P(EX(object));
} else {
EX(calling_scope) = NULL;
}
@@ -1910,7 +1898,7 @@ binary_assign_op_addr: {
char *function_name_strval;
int function_name_strlen;
- zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr);
+ zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object));
is_const = (EX(opline)->op2.op_type == IS_CONST);
@@ -1936,33 +1924,33 @@ binary_assign_op_addr: {
if (!EG(This)) {
zend_error(E_ERROR, "Can't fetch $this as not in object context");
}
- EX(object).ptr = EG(This);
+ EX(object) = EG(This);
} else {
- EX(object).ptr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
+ EX(object) = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
}
- if (EX(object).ptr && EX(object).ptr->type == IS_OBJECT) {
- EX(fbc) = Z_OBJ_HT_P(EX(object).ptr)->get_method(EX(object).ptr, function_name_strval, function_name_strlen TSRMLS_CC);
+ if (EX(object) && EX(object)->type == IS_OBJECT) {
+ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
} else {
zend_error(E_ERROR, "Call to a member function on a non-object");
}
if (!EX(fbc)) {
zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval);
}
- if (!PZVAL_IS_REF(EX(object).ptr)) {
- EX(object).ptr->refcount++; /* For $this pointer */
+ if (!PZVAL_IS_REF(EX(object))) {
+ EX(object)->refcount++; /* For $this pointer */
} else {
zval *this_ptr;
ALLOC_ZVAL(this_ptr);
- *this_ptr = *EX(object).ptr;
+ *this_ptr = *EX(object);
INIT_PZVAL(this_ptr);
zval_copy_ctor(this_ptr);
- EX(object).ptr = this_ptr;
+ EX(object) = this_ptr;
}
if(EX(fbc)->type == ZEND_USER_FUNCTION) {
- EX(calling_scope) = Z_OBJCE_P(EX(object).ptr);
+ EX(calling_scope) = Z_OBJCE_P(EX(object));
} else {
EX(calling_scope) = NULL;
}
@@ -1984,7 +1972,7 @@ binary_assign_op_addr: {
char *function_name_strval;
int function_name_strlen;
- zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr);
+ zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object));
is_const = (EX(opline)->op2.op_type == IS_CONST);
@@ -2003,8 +1991,8 @@ binary_assign_op_addr: {
function_name_strlen = tmp.value.str.len;
}
- if ((EX(object).ptr = EG(This))) {
- EX(object).ptr->refcount++;
+ if ((EX(object) = EG(This))) {
+ EX(object)->refcount++;
}
ce = EX(Ts)[EX(opline)->op1.u.var].EA.class_entry;
@@ -2033,7 +2021,7 @@ binary_assign_op_addr: {
char *function_name_strval;
int function_name_strlen;
- zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr);
+ zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object));
is_const = (EX(opline)->op2.op_type == IS_CONST);
@@ -2056,8 +2044,8 @@ binary_assign_op_addr: {
do {
if (EG(scope)) {
if (zend_hash_find(&EG(scope)->function_table, function_name_strval, function_name_strlen+1, (void **) &function) == SUCCESS) {
- if ((EX(object).ptr = EG(This))) {
- EX(object).ptr->refcount++;
+ if ((EX(object) = EG(This))) {
+ EX(object)->refcount++;
}
EX(calling_scope) = EG(scope);
break;
@@ -2067,7 +2055,7 @@ binary_assign_op_addr: {
zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval);
}
EX(calling_scope) = function->common.scope;
- EX(object).ptr = NULL;
+ EX(object) = NULL;
} while (0);
if (!is_const) {
@@ -2084,13 +2072,13 @@ binary_assign_op_addr: {
case ZEND_DO_FCALL: {
zval *fname = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
- zend_ptr_stack_push(&EG(arg_types_stack), EX(object).ptr);
+ zend_ptr_stack_push(&EG(arg_types_stack), EX(object));
do {
if (EG(scope)) {
if (zend_hash_find(&EG(scope)->function_table, fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function) == SUCCESS) {
- if ((EX(object).ptr = EG(This))) {
- EX(object).ptr->refcount++;
+ if ((EX(object) = EG(This))) {
+ EX(object)->refcount++;
}
EX(calling_scope) = EG(scope);
break;
@@ -2099,7 +2087,7 @@ binary_assign_op_addr: {
if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
zend_error(E_ERROR, "Unknown function: %s()\n", fname->value.str.val);
}
- EX(object).ptr = NULL;
+ EX(object) = NULL;
EX(calling_scope) = EX(function_state).function->common.scope;
} while (0);
@@ -2119,14 +2107,14 @@ binary_assign_op_addr: {
EG(scope) = EX(calling_scope);
current_this = EG(This);
- EG(This) = EX(object).ptr;
+ EG(This) = EX(object);
EX(Ts)[EX(opline)->result.u.var].var.ptr_ptr = &EX(Ts)[EX(opline)->result.u.var].var.ptr;
if (EX(function_state).function->type==ZEND_INTERNAL_FUNCTION) {
ALLOC_ZVAL(EX(Ts)[EX(opline)->result.u.var].var.ptr);
INIT_ZVAL(*(EX(Ts)[EX(opline)->result.u.var].var.ptr));
- ((zend_internal_function *) EX(function_state).function)->handler(EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object).ptr, return_value_used TSRMLS_CC);
+ ((zend_internal_function *) EX(function_state).function)->handler(EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object), return_value_used TSRMLS_CC);
EX(Ts)[EX(opline)->result.u.var].var.ptr->is_ref = 0;
EX(Ts)[EX(opline)->result.u.var].var.ptr->refcount = 1;
if (!return_value_used) {
@@ -2176,8 +2164,8 @@ binary_assign_op_addr: {
ALLOC_ZVAL(EX(Ts)[EX(opline)->result.u.var].var.ptr);
INIT_ZVAL(*(EX(Ts)[EX(opline)->result.u.var].var.ptr));
- if(EX(object).ptr) {
- Z_OBJ_HT_P(EX(object).ptr)->call_method(EX(fbc)->common.function_name, EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object).ptr, return_value_used TSRMLS_CC);
+ if(EX(object)) {
+ Z_OBJ_HT_P(EX(object))->call_method(EX(fbc)->common.function_name, EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object), return_value_used TSRMLS_CC);
} else {
zend_error(E_ERROR, "Cannot call overloaded function for non-object");
}
@@ -2188,9 +2176,9 @@ binary_assign_op_addr: {
}
}
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), 2, &EX(object), &EX(fbc));
} else {
- EX(object).ptr = zend_ptr_stack_pop(&EG(arg_types_stack));
+ EX(object) = zend_ptr_stack_pop(&EG(arg_types_stack));
}
EX(function_state).function = (zend_function *) op_array;
EG(function_state_ptr) = &EX(function_state);
View
2 Zend/zend_execute_API.c
@@ -174,6 +174,8 @@ void init_executor(TSRMLS_D)
EG(main_class_ptr) = &CG(main_class);
CG(main_class).static_members = &EG(symbol_table);
+ EG(current_execute_data) = NULL;
+
EG(This) = NULL;
}
View
2 Zend/zend_globals.h
@@ -203,6 +203,8 @@ struct _zend_executor_globals {
zend_objects objects;
zval *exception;
+ struct _zend_execute_data *current_execute_data;
+
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

0 comments on commit 7e5ec2d

Please sign in to comment.
Something went wrong with that request. Please try again.