Chris@0: /* Chris@0: * This file is part of the Symfony package. Chris@0: * Chris@0: * (c) Fabien Potencier Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: #ifdef HAVE_CONFIG_H Chris@0: #include "config.h" Chris@0: #endif Chris@0: Chris@0: #include "php.h" Chris@0: #ifdef ZTS Chris@0: #include "TSRM.h" Chris@0: #endif Chris@0: #include "php_ini.h" Chris@0: #include "ext/standard/info.h" Chris@0: #include "php_symfony_debug.h" Chris@0: #include "ext/standard/php_rand.h" Chris@0: #include "ext/standard/php_lcg.h" Chris@0: #include "ext/spl/php_spl.h" Chris@0: #include "Zend/zend_gc.h" Chris@0: #include "Zend/zend_builtin_functions.h" Chris@0: #include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */ Chris@0: #include "ext/standard/php_array.h" Chris@0: #include "Zend/zend_interfaces.h" Chris@0: #include "SAPI.h" Chris@0: Chris@0: #define IS_PHP_53 ZEND_EXTENSION_API_NO == 220090626 Chris@0: Chris@0: ZEND_DECLARE_MODULE_GLOBALS(symfony_debug) Chris@0: Chris@0: ZEND_BEGIN_ARG_INFO_EX(symfony_zval_arginfo, 0, 0, 2) Chris@0: ZEND_ARG_INFO(0, key) Chris@0: ZEND_ARG_ARRAY_INFO(0, array, 0) Chris@0: ZEND_ARG_INFO(0, options) Chris@0: ZEND_END_ARG_INFO() Chris@0: Chris@0: const zend_function_entry symfony_debug_functions[] = { Chris@0: PHP_FE(symfony_zval_info, symfony_zval_arginfo) Chris@0: PHP_FE(symfony_debug_backtrace, NULL) Chris@0: PHP_FE_END Chris@0: }; Chris@0: Chris@0: PHP_FUNCTION(symfony_debug_backtrace) Chris@0: { Chris@0: if (zend_parse_parameters_none() == FAILURE) { Chris@0: return; Chris@0: } Chris@0: #if IS_PHP_53 Chris@0: zend_fetch_debug_backtrace(return_value, 1, 0 TSRMLS_CC); Chris@0: #else Chris@0: zend_fetch_debug_backtrace(return_value, 1, 0, 0 TSRMLS_CC); Chris@0: #endif Chris@0: Chris@0: if (!SYMFONY_DEBUG_G(debug_bt)) { Chris@0: return; Chris@0: } Chris@0: Chris@0: php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(SYMFONY_DEBUG_G(debug_bt)), 0 TSRMLS_CC); Chris@0: } Chris@0: Chris@0: PHP_FUNCTION(symfony_zval_info) Chris@0: { Chris@0: zval *key = NULL, *arg = NULL; Chris@0: zval **data = NULL; Chris@0: HashTable *array = NULL; Chris@0: long options = 0; Chris@0: Chris@0: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zh|l", &key, &array, &options) == FAILURE) { Chris@0: return; Chris@0: } Chris@0: Chris@0: switch (Z_TYPE_P(key)) { Chris@0: case IS_STRING: Chris@0: if (zend_symtable_find(array, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&data) == FAILURE) { Chris@0: return; Chris@0: } Chris@0: break; Chris@0: case IS_LONG: Chris@0: if (zend_hash_index_find(array, Z_LVAL_P(key), (void **)&data)) { Chris@0: return; Chris@0: } Chris@0: break; Chris@0: } Chris@0: Chris@0: arg = *data; Chris@0: Chris@0: array_init(return_value); Chris@0: Chris@0: add_assoc_string(return_value, "type", (char *)_symfony_debug_zval_type(arg), 1); Chris@0: add_assoc_stringl(return_value, "zval_hash", _symfony_debug_memory_address_hash((void *)arg TSRMLS_CC), 16, 0); Chris@0: add_assoc_long(return_value, "zval_refcount", Z_REFCOUNT_P(arg)); Chris@0: add_assoc_bool(return_value, "zval_isref", (zend_bool)Z_ISREF_P(arg)); Chris@0: Chris@0: if (Z_TYPE_P(arg) == IS_OBJECT) { Chris@0: char hash[33] = {0}; Chris@0: Chris@0: php_spl_object_hash(arg, (char *)hash TSRMLS_CC); Chris@0: add_assoc_stringl(return_value, "object_class", (char *)Z_OBJCE_P(arg)->name, Z_OBJCE_P(arg)->name_length, 1); Chris@0: add_assoc_long(return_value, "object_refcount", EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(arg)].bucket.obj.refcount); Chris@0: add_assoc_string(return_value, "object_hash", hash, 1); Chris@0: add_assoc_long(return_value, "object_handle", Z_OBJ_HANDLE_P(arg)); Chris@0: } else if (Z_TYPE_P(arg) == IS_ARRAY) { Chris@0: add_assoc_long(return_value, "array_count", zend_hash_num_elements(Z_ARRVAL_P(arg))); Chris@0: } else if(Z_TYPE_P(arg) == IS_RESOURCE) { Chris@0: add_assoc_long(return_value, "resource_handle", Z_LVAL_P(arg)); Chris@0: add_assoc_string(return_value, "resource_type", (char *)_symfony_debug_get_resource_type(Z_LVAL_P(arg) TSRMLS_CC), 1); Chris@0: add_assoc_long(return_value, "resource_refcount", _symfony_debug_get_resource_refcount(Z_LVAL_P(arg) TSRMLS_CC)); Chris@0: } else if (Z_TYPE_P(arg) == IS_STRING) { Chris@0: add_assoc_long(return_value, "strlen", Z_STRLEN_P(arg)); Chris@0: } Chris@0: } Chris@0: Chris@0: void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) Chris@0: { Chris@0: TSRMLS_FETCH(); Chris@0: zval *retval; Chris@0: Chris@0: switch (type) { Chris@0: case E_ERROR: Chris@0: case E_PARSE: Chris@0: case E_CORE_ERROR: Chris@0: case E_CORE_WARNING: Chris@0: case E_COMPILE_ERROR: Chris@0: case E_COMPILE_WARNING: Chris@0: ALLOC_INIT_ZVAL(retval); Chris@0: #if IS_PHP_53 Chris@0: zend_fetch_debug_backtrace(retval, 1, 0 TSRMLS_CC); Chris@0: #else Chris@0: zend_fetch_debug_backtrace(retval, 1, 0, 0 TSRMLS_CC); Chris@0: #endif Chris@0: SYMFONY_DEBUG_G(debug_bt) = retval; Chris@0: } Chris@0: Chris@0: SYMFONY_DEBUG_G(old_error_cb)(type, error_filename, error_lineno, format, args); Chris@0: } Chris@0: Chris@0: static const char* _symfony_debug_get_resource_type(long rsid TSRMLS_DC) Chris@0: { Chris@0: const char *res_type; Chris@0: res_type = zend_rsrc_list_get_rsrc_type(rsid TSRMLS_CC); Chris@0: Chris@0: if (!res_type) { Chris@0: return "Unknown"; Chris@0: } Chris@0: Chris@0: return res_type; Chris@0: } Chris@0: Chris@0: static int _symfony_debug_get_resource_refcount(long rsid TSRMLS_DC) Chris@0: { Chris@0: zend_rsrc_list_entry *le; Chris@0: Chris@0: if (zend_hash_index_find(&EG(regular_list), rsid, (void **) &le)==SUCCESS) { Chris@0: return le->refcount; Chris@0: } Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: static char *_symfony_debug_memory_address_hash(void *address TSRMLS_DC) Chris@0: { Chris@0: char *result = NULL; Chris@0: intptr_t address_rand; Chris@0: Chris@0: if (!SYMFONY_DEBUG_G(req_rand_init)) { Chris@0: if (!BG(mt_rand_is_seeded)) { Chris@0: php_mt_srand(GENERATE_SEED() TSRMLS_CC); Chris@0: } Chris@0: SYMFONY_DEBUG_G(req_rand_init) = (intptr_t)php_mt_rand(TSRMLS_C); Chris@0: } Chris@0: Chris@0: address_rand = (intptr_t)address ^ SYMFONY_DEBUG_G(req_rand_init); Chris@0: Chris@0: spprintf(&result, 17, "%016zx", address_rand); Chris@0: Chris@0: return result; Chris@0: } Chris@0: Chris@0: static const char *_symfony_debug_zval_type(zval *zv) Chris@0: { Chris@0: switch (Z_TYPE_P(zv)) { Chris@0: case IS_NULL: Chris@0: return "NULL"; Chris@0: break; Chris@0: Chris@0: case IS_BOOL: Chris@0: return "boolean"; Chris@0: break; Chris@0: Chris@0: case IS_LONG: Chris@0: return "integer"; Chris@0: break; Chris@0: Chris@0: case IS_DOUBLE: Chris@0: return "double"; Chris@0: break; Chris@0: Chris@0: case IS_STRING: Chris@0: return "string"; Chris@0: break; Chris@0: Chris@0: case IS_ARRAY: Chris@0: return "array"; Chris@0: break; Chris@0: Chris@0: case IS_OBJECT: Chris@0: return "object"; Chris@0: Chris@0: case IS_RESOURCE: Chris@0: return "resource"; Chris@0: Chris@0: default: Chris@0: return "unknown type"; Chris@0: } Chris@0: } Chris@0: Chris@0: zend_module_entry symfony_debug_module_entry = { Chris@0: STANDARD_MODULE_HEADER, Chris@0: "symfony_debug", Chris@0: symfony_debug_functions, Chris@0: PHP_MINIT(symfony_debug), Chris@0: PHP_MSHUTDOWN(symfony_debug), Chris@0: PHP_RINIT(symfony_debug), Chris@0: PHP_RSHUTDOWN(symfony_debug), Chris@0: PHP_MINFO(symfony_debug), Chris@0: PHP_SYMFONY_DEBUG_VERSION, Chris@0: PHP_MODULE_GLOBALS(symfony_debug), Chris@0: PHP_GINIT(symfony_debug), Chris@0: PHP_GSHUTDOWN(symfony_debug), Chris@0: NULL, Chris@0: STANDARD_MODULE_PROPERTIES_EX Chris@0: }; Chris@0: Chris@0: #ifdef COMPILE_DL_SYMFONY_DEBUG Chris@0: ZEND_GET_MODULE(symfony_debug) Chris@0: #endif Chris@0: Chris@0: PHP_GINIT_FUNCTION(symfony_debug) Chris@0: { Chris@0: memset(symfony_debug_globals, 0 , sizeof(*symfony_debug_globals)); Chris@0: } Chris@0: Chris@0: PHP_GSHUTDOWN_FUNCTION(symfony_debug) Chris@0: { Chris@0: Chris@0: } Chris@0: Chris@0: PHP_MINIT_FUNCTION(symfony_debug) Chris@0: { Chris@0: SYMFONY_DEBUG_G(old_error_cb) = zend_error_cb; Chris@0: zend_error_cb = symfony_debug_error_cb; Chris@0: Chris@0: return SUCCESS; Chris@0: } Chris@0: Chris@0: PHP_MSHUTDOWN_FUNCTION(symfony_debug) Chris@0: { Chris@0: zend_error_cb = SYMFONY_DEBUG_G(old_error_cb); Chris@0: Chris@0: return SUCCESS; Chris@0: } Chris@0: Chris@0: PHP_RINIT_FUNCTION(symfony_debug) Chris@0: { Chris@0: return SUCCESS; Chris@0: } Chris@0: Chris@0: PHP_RSHUTDOWN_FUNCTION(symfony_debug) Chris@0: { Chris@0: return SUCCESS; Chris@0: } Chris@0: Chris@0: PHP_MINFO_FUNCTION(symfony_debug) Chris@0: { Chris@0: php_info_print_table_start(); Chris@0: php_info_print_table_header(2, "Symfony Debug support", "enabled"); Chris@0: php_info_print_table_header(2, "Symfony Debug version", PHP_SYMFONY_DEBUG_VERSION); Chris@0: php_info_print_table_end(); Chris@0: }