diff --git a/Zend/zend.c b/Zend/zend.c index 2765f8c3ead22..7177f13c578e4 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -61,6 +61,8 @@ ZEND_TSRMLS_CACHE_DEFINE() ZEND_API zend_utility_values zend_uv; ZEND_API zend_bool zend_dtrace_enabled; +zend_llist zend_error_notify_callbacks; + /* version information */ static char *zend_version_info; static uint32_t zend_version_info_length; @@ -815,6 +817,7 @@ int zend_startup(zend_utility_functions *utility_functions) /* {{{ */ zend_startup_strtod(); zend_startup_extensions_mechanism(); + zend_startup_error_notify_callbacks(); /* Set up utility functions and values */ zend_error_cb = utility_functions->error_function; @@ -846,6 +849,8 @@ int zend_startup(zend_utility_functions *utility_functions) /* {{{ */ zend_compile_file = dtrace_compile_file; zend_execute_ex = dtrace_execute_ex; zend_execute_internal = dtrace_execute_internal; + + zend_register_error_notify_callback(dtrace_error_notify_cb); } else { zend_compile_file = compile_file; zend_execute_ex = execute_ex; @@ -1075,6 +1080,7 @@ void zend_shutdown(void) /* {{{ */ zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE); free(GLOBAL_AUTO_GLOBALS_TABLE); + zend_shutdown_error_notify_callbacks(); zend_shutdown_extensions(); free(zend_version_info); @@ -1311,11 +1317,7 @@ static ZEND_COLD void zend_error_impl( } } -#ifdef HAVE_DTRACE - if (DTRACE_ERROR_ENABLED()) { - DTRACE_ERROR(ZSTR_VAL(message), (char *)error_filename, error_lineno); - } -#endif /* HAVE_DTRACE */ + zend_error_notify_all_callbacks(type, error_filename, error_lineno, message); /* if we don't have a user defined error handler */ if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF @@ -1771,3 +1773,29 @@ ZEND_API void zend_map_ptr_extend(size_t last) CG(map_ptr_last) = last; } } + +void zend_startup_error_notify_callbacks() +{ + zend_llist_init(&zend_error_notify_callbacks, sizeof(zend_error_notify_cb), NULL, 1); +} + +void zend_shutdown_error_notify_callbacks() +{ + zend_llist_destroy(&zend_error_notify_callbacks); +} + +void zend_register_error_notify_callback(zend_error_notify_cb cb) +{ + zend_llist_add_element(&zend_error_notify_callbacks, &cb); +} + +void zend_error_notify_all_callbacks(int type, const char *error_filename, uint32_t error_lineno, zend_string *message) +{ + zend_llist_element *element; + zend_error_notify_cb callback; + + for (element = zend_error_notify_callbacks.head; element; element = element->next) { + callback = *(zend_error_notify_cb *) (element->data); + callback(type, error_filename, error_lineno, message); + } +} diff --git a/Zend/zend.h b/Zend/zend.h index 4fe89fcacc809..956d4532df795 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -351,6 +351,16 @@ ZEND_API void zend_save_error_handling(zend_error_handling *current); ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling, zend_class_entry *exception_class, zend_error_handling *current); ZEND_API void zend_restore_error_handling(zend_error_handling *saved); +typedef void (*zend_error_notify_cb)(int type, const char *error_filename, uint32_t error_lineno, zend_string *message); + +BEGIN_EXTERN_C() + +void zend_register_error_notify_callback(zend_error_notify_cb callback); +void zend_startup_error_notify_callbacks(); +void zend_shutdown_error_notify_callbacks(); +void zend_error_notify_all_callbacks(int type, const char *error_filename, uint32_t error_lineno, zend_string *message); +END_EXTERN_C() + #define DEBUG_BACKTRACE_PROVIDE_OBJECT (1<<0) #define DEBUG_BACKTRACE_IGNORE_ARGS (1<<1) diff --git a/Zend/zend_dtrace.c b/Zend/zend_dtrace.c index 750fb686c8b0e..935421121e3f5 100644 --- a/Zend/zend_dtrace.c +++ b/Zend/zend_dtrace.c @@ -109,6 +109,13 @@ ZEND_API void dtrace_execute_internal(zend_execute_data *execute_data, zval *ret } } +void dtrace_error_notify_cb(int type, const char *error_filename, uint32_t error_lineno, zend_string *message) +{ + if (DTRACE_ERROR_ENABLED()) { + DTRACE_ERROR(ZSTR_VAL(message), (char *)error_filename, error_lineno); + } +} + /* }}} */ #endif /* HAVE_DTRACE */ diff --git a/Zend/zend_dtrace.h b/Zend/zend_dtrace.h index c4fedadd40dfb..84c7379e3781d 100644 --- a/Zend/zend_dtrace.h +++ b/Zend/zend_dtrace.h @@ -37,6 +37,8 @@ ZEND_API void dtrace_execute_ex(zend_execute_data *execute_data); ZEND_API void dtrace_execute_internal(zend_execute_data *execute_data, zval *return_value); #include +void dtrace_error_notify_cb(int type, const char *error_filename, uint32_t error_lineno, zend_string *message); + #endif /* HAVE_DTRACE */ #ifdef __cplusplus diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index e46e18f1d3a9c..24bfa9e41afb4 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -893,6 +893,7 @@ static void zend_error_va(int type, const char *file, uint32_t lineno, const cha va_list args; va_start(args, format); zend_string *message = zend_vstrpprintf(0, format, args); + zend_error_notify_all_callbacks(type, file, lineno, message); zend_error_cb(type, file, lineno, message); zend_string_release(message); va_end(args); @@ -913,10 +914,10 @@ ZEND_API ZEND_COLD int zend_exception_error(zend_object *ex, int severity) /* {{ zend_string *message = zval_get_string(GET_PROPERTY(&exception, ZEND_STR_MESSAGE)); zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE)); zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE)); + int type = (ce_exception == zend_ce_parse_error ? E_PARSE : E_COMPILE_ERROR) | E_DONT_BAIL; - zend_error_cb( - (ce_exception == zend_ce_parse_error ? E_PARSE : E_COMPILE_ERROR) | E_DONT_BAIL, - ZSTR_VAL(file), line, message); + zend_error_notify_all_callbacks(type, ZSTR_VAL(file), line, message); + zend_error_cb(type, ZSTR_VAL(file), line, message); zend_string_release_ex(file, 0); zend_string_release_ex(message, 0); diff --git a/main/main.c b/main/main.c index 3b052d8b6e3be..9c0c8c11b9b26 100644 --- a/main/main.c +++ b/main/main.c @@ -1175,6 +1175,31 @@ static void clear_last_error() { } } +#if ZEND_DEBUG +/* {{{ report_zend_debug_error_notify_cb */ +static void report_zend_debug_error_notify_cb(int type, const char *error_filename, uint32_t error_lineno, zend_string *message) +{ + if (PG(report_zend_debug)) { + zend_bool trigger_break; + + switch (type) { + case E_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + trigger_break=1; + break; + default: + trigger_break=0; + break; + } + + zend_output_debug_string(trigger_break, "%s(%" PRIu32 ") : %s", error_filename, error_lineno, ZSTR_VAL(message)); + } +} +/* }}} */ +#endif + /* {{{ php_error_cb extended error handling function */ static ZEND_COLD void php_error_cb(int orig_type, const char *error_filename, const uint32_t error_lineno, zend_string *message) @@ -1330,24 +1355,6 @@ static ZEND_COLD void php_error_cb(int orig_type, const char *error_filename, co } } } -#if ZEND_DEBUG - if (PG(report_zend_debug)) { - zend_bool trigger_break; - - switch (type) { - case E_ERROR: - case E_CORE_ERROR: - case E_COMPILE_ERROR: - case E_USER_ERROR: - trigger_break=1; - break; - default: - trigger_break=0; - break; - } - zend_output_debug_string(trigger_break, "%s(%" PRIu32 ") : %s - %s", error_filename, error_lineno, error_type_str, ZSTR_VAL(message)); - } -#endif } /* Bail out if we can't recover */ @@ -2083,6 +2090,10 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod zend_startup(&zuf); zend_update_current_locale(); +#if ZEND_DEBUG + zend_register_error_notify_callback(report_zend_debug_error_notify_cb); +#endif + #if HAVE_TZSET tzset(); #endif