diff options
Diffstat (limited to 'sapi/phpdbg/phpdbg.c')
| -rw-r--r-- | sapi/phpdbg/phpdbg.c | 1064 | 
1 files changed, 577 insertions, 487 deletions
| diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 6fce7f4a42..f2f18b944e 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -28,7 +28,9 @@  #include "phpdbg_list.h"  #include "phpdbg_utils.h"  #include "phpdbg_set.h" +#include "phpdbg_io.h"  #include "zend_alloc.h" +#include "phpdbg_eol.h"  /* {{{ remote console headers */  #ifndef _WIN32 @@ -36,19 +38,35 @@  #	include <sys/select.h>  #	include <sys/time.h>  #	include <sys/types.h> +#	include <sys/poll.h>  #	include <netinet/in.h>  #	include <unistd.h>  #	include <arpa/inet.h>  #endif /* }}} */  ZEND_DECLARE_MODULE_GLOBALS(phpdbg); +int phpdbg_startup_run = 0; + +static PHP_INI_MH(OnUpdateEol) +{ +	if (!new_value) { +		return FAILURE; +	} + +	return phpdbg_eol_global_update(new_value->val); +} + +PHP_INI_BEGIN() +	STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, socket_path, zend_phpdbg_globals, phpdbg_globals) +	STD_PHP_INI_ENTRY("phpdbg.eol", "2", PHP_INI_ALL, OnUpdateEol, socket_path, zend_phpdbg_globals, phpdbg_globals) +PHP_INI_END()  static zend_bool phpdbg_booted = 0;  #if PHP_VERSION_ID >= 50500 -void (*zend_execute_old)(zend_execute_data *execute_data TSRMLS_DC); +void (*zend_execute_old)(zend_execute_data *execute_data);  #else -void (*zend_execute_old)(zend_op_array *op_array TSRMLS_DC); +void (*zend_execute_old)(zend_op_array *op_array);  #endif  static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */ @@ -63,20 +81,40 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */  	pg->exec = NULL;  	pg->exec_len = 0;  	pg->buffer = NULL; +	pg->last_was_newline = 1;  	pg->ops = NULL;  	pg->vmret = 0; +	pg->in_execution = 0;  	pg->bp_count = 0;  	pg->flags = PHPDBG_DEFAULT_FLAGS;  	pg->oplog = NULL; -	pg->io[PHPDBG_STDIN] = NULL; -	pg->io[PHPDBG_STDOUT] = NULL; -	pg->io[PHPDBG_STDERR] = NULL; +	memset(pg->io, 0, sizeof(pg->io));  	pg->frame.num = 0; +	pg->sapi_name_ptr = NULL; +	pg->socket_fd = -1; +	pg->socket_server_fd = -1; + +	pg->req_id = 0; +	pg->err_buf.active = 0; +	pg->err_buf.type = 0; + +	pg->input_buflen = 0; +	pg->sigsafe_mem.mem = NULL; +	pg->sigsegv_bailout = NULL; + +#ifdef PHP_WIN32 +	pg->sigio_watcher_thread = INVALID_HANDLE_VALUE; +	memset(&pg->swd, 0, sizeof(struct win32_sigio_watcher_data)); +#endif + +	pg->eol = PHPDBG_EOL_LF;  } /* }}} */  static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */  {  	ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL); +	REGISTER_INI_ENTRIES(); +  #if PHP_VERSION_ID >= 50500  	zend_execute_old = zend_execute_ex;  	zend_execute_ex = phpdbg_execute_ex; @@ -86,7 +124,7 @@ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */  #endif  	REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT); -	 +  	REGISTER_LONG_CONSTANT("PHPDBG_FILE",   FILE_PARAM, CONST_CS|CONST_PERSISTENT);  	REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);  	REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT); @@ -99,56 +137,54 @@ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */  	return SUCCESS;  } /* }}} */ -static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_file(zval *brake) /* {{{ */  { -	zend_hash_destroy((HashTable*)brake); +	zend_hash_destroy(Z_ARRVAL_P(brake));  } /* }}} */ -static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_symbol(zval *brake) /* {{{ */  { -	efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol); +	efree((char *) ((phpdbg_breaksymbol_t *) Z_PTR_P(brake))->symbol);  } /* }}} */ -static void php_phpdbg_destroy_bp_opcode(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_opcode(zval *brake) /* {{{ */  { -	efree((char*)((phpdbg_breakop_t*)brake)->name); +	efree((char *) ((phpdbg_breakop_t *) Z_PTR_P(brake))->name);  } /* }}} */ -static void php_phpdbg_destroy_bp_methods(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_methods(zval *brake) /* {{{ */  { -	zend_hash_destroy((HashTable*)brake); +	zend_hash_destroy(Z_ARRVAL_P(brake));  } /* }}} */ -static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */ +static void php_phpdbg_destroy_bp_condition(zval *data) /* {{{ */  { -	phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data; +	phpdbg_breakcond_t *brake = (phpdbg_breakcond_t *) Z_PTR_P(data);  	if (brake) {  		if (brake->ops) { -			TSRMLS_FETCH(); -			destroy_op_array( -					brake->ops TSRMLS_CC); +			destroy_op_array(brake->ops);  			efree(brake->ops);  		} -		efree((char*)brake->code); +		efree((char*) brake->code);  	}  } /* }}} */ -static void php_phpdbg_destroy_registered(void *data) /* {{{ */ +static void php_phpdbg_destroy_registered(zval *data) /* {{{ */  { -	zend_function *function = (zend_function*) data; -	TSRMLS_FETCH(); +	zend_function *function = (zend_function *) Z_PTR_P(data); + -	destroy_zend_function( -		function TSRMLS_CC); +	destroy_zend_function(function);  } /* }}} */  static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */  { -	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],   8, NULL, php_phpdbg_destroy_bp_file, 0); +	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0); +	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], 8, NULL, php_phpdbg_destroy_bp_file, 0);  	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);  	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);  	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0); @@ -178,6 +214,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */  	zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);  	zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);  	zend_hash_destroy(&PHPDBG_G(seek)); +	zend_hash_destroy(&PHPDBG_G(file_sources));  	zend_hash_destroy(&PHPDBG_G(registered));  	zend_hash_destroy(&PHPDBG_G(watchpoints));  	zend_llist_destroy(&PHPDBG_G(watchlist_mem)); @@ -186,7 +223,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */  		efree(PHPDBG_G(buffer));  		PHPDBG_G(buffer) = NULL;  	} -	 +  	if (PHPDBG_G(exec)) {  		efree(PHPDBG_G(exec));  		PHPDBG_G(exec) = NULL; @@ -209,7 +246,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */  	}  	if (PHPDBG_G(ops)) { -		destroy_op_array(PHPDBG_G(ops) TSRMLS_CC); +		destroy_op_array(PHPDBG_G(ops));  		efree(PHPDBG_G(ops));  		PHPDBG_G(ops) = NULL;  	} @@ -224,10 +261,9 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */  	If the request to set the context fails, boolean false is returned, and an E_WARNING raised */  static PHP_FUNCTION(phpdbg_exec)  { -	char *exec = NULL; -	int exec_len = 0; -	 -	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) { +	zend_string *exec; + +	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &exec) == FAILURE) {  		return;  	} @@ -235,88 +271,81 @@ static PHP_FUNCTION(phpdbg_exec)  		struct stat sb;  		zend_bool result = 1; -		if (VCWD_STAT(exec, &sb) != FAILURE) { +		if (VCWD_STAT(exec->val, &sb) != FAILURE) {  			if (sb.st_mode & (S_IFREG|S_IFLNK)) {  				if (PHPDBG_G(exec)) { -					ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1); +					ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len));  					efree(PHPDBG_G(exec));  					result = 0;  				} -				PHPDBG_G(exec) = estrndup(exec, exec_len); -				PHPDBG_G(exec_len) = exec_len; +				PHPDBG_G(exec) = estrndup(exec->val, exec->len); +				PHPDBG_G(exec_len) = exec->len; -				if (result) -					ZVAL_BOOL(return_value, 1); +				if (result) { +					ZVAL_TRUE(return_value); +				}  			} else { -				zend_error( -					E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec); -				ZVAL_BOOL(return_value, 0); +				zend_error(E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec); +				ZVAL_FALSE(return_value);  			}  		} else { -			zend_error( -				E_WARNING, "Failed to set execution context (%s) the file does not exist", exec); +			zend_error(E_WARNING, "Failed to set execution context (%s) the file does not exist", exec); -			ZVAL_BOOL(return_value, 0); +			ZVAL_FALSE(return_value);  		}  	}  } /* }}} */ -/* {{{ proto void phpdbg_break_next() +/* {{{ proto void phpdbg_break()      instructs phpdbg to insert a breakpoint at the next opcode */  static PHP_FUNCTION(phpdbg_break_next)  { -	if (zend_parse_parameters_none() != SUCCESS) { +	if (zend_parse_parameters_none() == FAILURE && EG(current_execute_data)) {  		return; -	} else if (EG(current_execute_data) && EG(active_op_array)) { -		zend_ulong opline_num = (EG(current_execute_data)->opline - -				EG(active_op_array)->opcodes); - -		phpdbg_set_breakpoint_opline_ex( -				&EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC);  	} + +	phpdbg_set_breakpoint_opline_ex((phpdbg_opline_ptr_t) EG(current_execute_data)->opline + 1);  } /* }}} */  /* {{{ proto void phpdbg_break_file(string file, integer line) */  static PHP_FUNCTION(phpdbg_break_file)  { -    char    *file = NULL; -    int      flen = 0; -    long     line; -     -    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &file, &flen, &line) == FAILURE) { -        return; -    } - -    phpdbg_set_breakpoint_file(file, line TSRMLS_CC); +	char    *file = NULL; +	size_t   flen = 0; +	long     line; + +	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &file, &flen, &line) == FAILURE) { +		return; +	} + +	phpdbg_set_breakpoint_file(file, line);  } /* }}} */  /* {{{ proto void phpdbg_break_method(string class, string method) */  static PHP_FUNCTION(phpdbg_break_method)  { -    char *class = NULL, -         *method = NULL; -    int clen = 0,  -        mlen = 0; +	char *class = NULL, *method = NULL; +	size_t clen = 0, mlen = 0; -    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &class, &clen, &method, &mlen) == FAILURE) { -    return; -    } +	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &class, &clen, &method, &mlen) == FAILURE) { +		return; +	} -    phpdbg_set_breakpoint_method(class, method TSRMLS_CC); +	phpdbg_set_breakpoint_method(class, method);  } /* }}} */  /* {{{ proto void phpdbg_break_function(string function) */  static PHP_FUNCTION(phpdbg_break_function)  { -    char *function = NULL; -    int   function_len; +	char    *function = NULL; +	size_t   function_len; -    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &function, &function_len) == FAILURE) { -           return; -    } +	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &function, &function_len) == FAILURE) { +		return; +	} -    phpdbg_set_breakpoint_symbol(function, function_len TSRMLS_CC); +	phpdbg_set_breakpoint_symbol(function, function_len);  } /* }}} */  /* {{{ proto void phpdbg_clear(void) @@ -324,6 +353,7 @@ static PHP_FUNCTION(phpdbg_break_function)  static PHP_FUNCTION(phpdbg_clear)  {  	zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]); +	zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]);  	zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);  	zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);  	zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]); @@ -338,9 +368,9 @@ static PHP_FUNCTION(phpdbg_color)  {  	long element = 0L;  	char *color = NULL; -	int color_len = 0; +	size_t color_len = 0; -	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) { +	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &element, &color, &color_len) == FAILURE) {  		return;  	} @@ -348,7 +378,7 @@ static PHP_FUNCTION(phpdbg_color)  		case PHPDBG_COLOR_NOTICE:  		case PHPDBG_COLOR_ERROR:  		case PHPDBG_COLOR_PROMPT: -			phpdbg_set_color_ex(element, color, color_len TSRMLS_CC); +			phpdbg_set_color_ex(element, color, color_len);  		break;  		default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant"); @@ -359,30 +389,30 @@ static PHP_FUNCTION(phpdbg_color)  static PHP_FUNCTION(phpdbg_prompt)  {  	char *prompt = NULL; -	int prompt_len = 0; +	size_t prompt_len = 0; -	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) { +	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &prompt, &prompt_len) == FAILURE) {  		return;  	} -	phpdbg_set_prompt(prompt TSRMLS_CC); +	phpdbg_set_prompt(prompt);  } /* }}} */  ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0)  ZEND_END_ARG_INFO()  ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_file_arginfo, 0, 0, 2) -    ZEND_ARG_INFO(0, file) -    ZEND_ARG_INFO(0, line) +	ZEND_ARG_INFO(0, file) +	ZEND_ARG_INFO(0, line)  ZEND_END_ARG_INFO()  ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_method_arginfo, 0, 0, 2) -    ZEND_ARG_INFO(0, class) -    ZEND_ARG_INFO(0, method) +	ZEND_ARG_INFO(0, class) +	ZEND_ARG_INFO(0, method)  ZEND_END_ARG_INFO()  ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_function_arginfo, 0, 0, 1) -    ZEND_ARG_INFO(0, function) +	ZEND_ARG_INFO(0, function)  ZEND_END_ARG_INFO()  ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0) @@ -441,18 +471,18 @@ static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /*  	return SUCCESS;  } /* }}} */ -static char* php_sapi_phpdbg_read_cookies(TSRMLS_D) /* {{{ */ +static char* php_sapi_phpdbg_read_cookies(void) /* {{{ */  {  	return NULL;  } /* }}} */ -static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */ +static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s) /* {{{ */  {  	return 0;  }  /* }}} */ -static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */ +static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers) /* {{{ */  {  	/* We do nothing here, this function is needed to prevent that the fallback  	 * header handling is called. */ @@ -460,18 +490,23 @@ static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS  }  /* }}} */ -static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /* {{{ */ +static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context) /* {{{ */  {  }  /* }}} */ -static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ +static void php_sapi_phpdbg_log_message(char *message) /* {{{ */  {  	/*  	* We must not request TSRM before being boot  	*/  	if (phpdbg_booted) { -		phpdbg_error("%s", message); +		if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) { +			phpdbg_error("eval", "msg=\"%s\"", "%s", message); +			return; +		} + +		phpdbg_error("php", "msg=\"%s\"", "%s", message);  		switch (PG(last_error_type)) {  			case E_ERROR: @@ -479,123 +514,154 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */  			case E_COMPILE_ERROR:  			case E_USER_ERROR:  			case E_PARSE: -			case E_RECOVERABLE_ERROR: -				if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { -					phpdbg_list_file( -						zend_get_executed_filename(TSRMLS_C), -						3, -						zend_get_executed_lineno(TSRMLS_C)-1, -						zend_get_executed_lineno(TSRMLS_C) -						TSRMLS_CC -					); -				} +			case E_RECOVERABLE_ERROR: { +				const char *file_char = zend_get_executed_filename(); +				zend_string *file = zend_string_init(file_char, strlen(file_char), 0); +				phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno()); +				efree(file);  				do { -					switch (phpdbg_interactive(TSRMLS_C)) { +					switch (phpdbg_interactive(1)) {  						case PHPDBG_LEAVE:  						case PHPDBG_FINISH:  						case PHPDBG_UNTIL:  						case PHPDBG_NEXT:  							return;  					} -				} while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); - +				} while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)); +			}  		} -	} else fprintf(stdout, "%s\n", message); +	} else { +		fprintf(stdout, "%s\n", message); +	}  }  /* }}} */ -static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */ +static int php_sapi_phpdbg_deactivate(void) /* {{{ */  { +	if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) == PHPDBG_IS_CLEANING) { +		zend_phpdbg_globals *pg = PHPDBG_G(backup) = calloc(1, sizeof(zend_phpdbg_globals)); + +		php_phpdbg_globals_ctor(pg); + +		pg->exec = zend_strndup(PHPDBG_G(exec), PHPDBG_G(exec_len)); +		pg->exec_len = PHPDBG_G(exec_len); +		pg->oplog = PHPDBG_G(oplog); +		pg->prompt[0] = PHPDBG_G(prompt)[0]; +		pg->prompt[1] = PHPDBG_G(prompt)[1]; +		memcpy(pg->colors, PHPDBG_G(colors), sizeof(pg->colors)); +		pg->eol = PHPDBG_G(eol); +		pg->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK; +	} +  	fflush(stdout);  	if(SG(request_info).argv0) {  		free(SG(request_info).argv0);  		SG(request_info).argv0 = NULL;  	} +  	return SUCCESS;  }  /* }}} */ -static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {{{ */ +static void php_sapi_phpdbg_register_vars(zval *track_vars_array) /* {{{ */  { -	unsigned int len; -	char   *docroot = ""; +	size_t len; +	char  *docroot = "";  	/* In phpdbg mode, we consider the environment to be a part of the server variables  	*/ -	php_import_environment_variables(track_vars_array TSRMLS_CC); +	php_import_environment_variables(track_vars_array);  	if (PHPDBG_G(exec)) {  		len = PHPDBG_G(exec_len); -		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", -					&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { -			php_register_variable("PHP_SELF", PHPDBG_G(exec), -					track_vars_array TSRMLS_CC); +		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) { +			php_register_variable("PHP_SELF", PHPDBG_G(exec), track_vars_array);  		} -		if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", -					&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { -			php_register_variable("SCRIPT_NAME", PHPDBG_G(exec), -					track_vars_array TSRMLS_CC); +		if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) { +			php_register_variable("SCRIPT_NAME", PHPDBG_G(exec), track_vars_array);  		} -		if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", -					&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { -			php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec), -					track_vars_array TSRMLS_CC); +		if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) { +			php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec), track_vars_array);  		} -		if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", -					&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { -			php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec), -					track_vars_array TSRMLS_CC); +		if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) { +			php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec), track_vars_array);  		}  	} -	/* any old docroot will doo */ -	len = 0U; -	if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", -				&docroot, len, &len TSRMLS_CC)) { -		php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC); +	/* any old docroot will do */ +	len = 0; +	if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len)) { +		php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array);  	}  }  /* }}} */ -static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */ +static inline size_t php_sapi_phpdbg_ub_write(const char *message, size_t length) /* {{{ */  { -	return phpdbg_write("%s", message); +	if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { +		send(PHPDBG_G(socket_fd), message, length, 0); +	} +	return phpdbg_script(P_STDOUT, "%.*s", length, message);  } /* }}} */ +/* beginning of struct, see main/streams/plain_wrapper.c line 111 */ +typedef struct { +	FILE *file; +	int fd; +} php_stdio_stream_data; + +static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t count) { +	php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; + +	while (data->fd >= 0) { +		struct stat stat[3]; +		memset(stat, 0, sizeof(stat)); +		if (((fstat(fileno(stderr), &stat[2]) < 0) & (fstat(fileno(stdout), &stat[0]) < 0)) | (fstat(data->fd, &stat[1]) < 0)) { +			break; +		} + +		if (stat[0].st_dev == stat[1].st_dev && stat[0].st_ino == stat[1].st_ino) { +			phpdbg_script(P_STDOUT, "%.*s", (int) count, buf); +			return count; +		} +		if (stat[2].st_dev == stat[1].st_dev && stat[2].st_ino == stat[1].st_ino) { +			phpdbg_script(P_STDERR, "%.*s", (int) count, buf); +			return count; +		} +		break; +	} + +	return PHPDBG_G(php_stdiop_write)(stream, buf, count); +} +  #if PHP_VERSION_ID >= 50700 -static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC)  /* {{{ */ +static inline void php_sapi_phpdbg_flush(void *context)  /* {{{ */  {  #else  static inline void php_sapi_phpdbg_flush(void *context)  /* {{{ */  { -	TSRMLS_FETCH();  #endif -	fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); +	if (!phpdbg_active_sigsafe_mem()) { +		fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); +	}  } /* }}} */  /* copied from sapi/cli/php_cli.c cli_register_file_handles */ -static void phpdbg_register_file_handles(TSRMLS_D) /* {{{ */ +static void phpdbg_register_file_handles(void) /* {{{ */  { -	zval *zin, *zout, *zerr; +	zval zin, zout, zerr;  	php_stream *s_in, *s_out, *s_err;  	php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;  	zend_constant ic, oc, ec; -	MAKE_STD_ZVAL(zin); -	MAKE_STD_ZVAL(zout); -	MAKE_STD_ZVAL(zerr); -  	s_in  = php_stream_open_wrapper_ex("php://stdin",  "rb", 0, NULL, sc_in);  	s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);  	s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);  	if (s_in==NULL || s_out==NULL || s_err==NULL) { -		FREE_ZVAL(zin); -		FREE_ZVAL(zout); -		FREE_ZVAL(zerr);  		if (s_in) php_stream_close(s_in);  		if (s_out) php_stream_close(s_out);  		if (s_err) php_stream_close(s_err); @@ -608,34 +674,27 @@ static void phpdbg_register_file_handles(TSRMLS_D) /* {{{ */  	s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;  #endif -	php_stream_to_zval(s_in,  zin); -	php_stream_to_zval(s_out, zout); -	php_stream_to_zval(s_err, zerr); +	php_stream_to_zval(s_in,  &zin); +	php_stream_to_zval(s_out, &zout); +	php_stream_to_zval(s_err, &zerr); -	ic.value = *zin; +	ic.value = zin;  	ic.flags = CONST_CS; -	ic.name = zend_strndup(ZEND_STRL("STDIN")); -	ic.name_len = sizeof("STDIN"); +	ic.name = zend_string_init(ZEND_STRL("STDIN"), 0);  	ic.module_number = 0; -	zend_register_constant(&ic TSRMLS_CC); +	zend_register_constant(&ic); -	oc.value = *zout; +	oc.value = zout;  	oc.flags = CONST_CS; -	oc.name = zend_strndup(ZEND_STRL("STDOUT")); -	oc.name_len = sizeof("STDOUT"); +	oc.name = zend_string_init(ZEND_STRL("STDOUT"), 0);  	oc.module_number = 0; -	zend_register_constant(&oc TSRMLS_CC); +	zend_register_constant(&oc); -	ec.value = *zerr; +	ec.value = zerr;  	ec.flags = CONST_CS; -	ec.name = zend_strndup(ZEND_STRL("STDERR")); -	ec.name_len = sizeof("STDERR"); +	ec.name = zend_string_init(ZEND_STRL("STDERR"), 0);  	ec.module_number = 0; -	zend_register_constant(&ec TSRMLS_CC); - -	FREE_ZVAL(zin); -	FREE_ZVAL(zout); -	FREE_ZVAL(zerr); +	zend_register_constant(&ec);  }  /* }}} */ @@ -693,6 +752,7 @@ const opt_struct OPTIONS[] = { /* {{{ */  	{'l', 1, "listen"},  	{'a', 1, "address-or-any"},  #endif +	{'x', 0, "xml output"},  	{'V', 0, "version"},  	{'-', 0, NULL}  }; /* }}} */ @@ -706,14 +766,13 @@ const char phpdbg_ini_hardcoded[] =  "max_execution_time=0\n"  "max_input_time=-1\n"  "error_log=\n" -"output_buffering=off\0"; +"output_buffering=off\n\0";  /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */  #define INI_DEFAULT(name, value) \ +	ZVAL_STRINGL(&tmp, value, sizeof(value) - 1); \  	Z_SET_REFCOUNT(tmp, 0); \ -	Z_UNSET_ISREF(tmp); \ -	ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \ -	zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL); +	zend_hash_str_update(configuration_hash, name, sizeof(name) - 1, &tmp);  void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */  { @@ -721,199 +780,173 @@ void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */  	INI_DEFAULT("report_zend_debug", "0");  } /* }}} */ -static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */ +static void phpdbg_welcome(zend_bool cleaning) /* {{{ */  {  	/* print blurb */  	if (!cleaning) { -		phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", -				PHPDBG_VERSION); -		phpdbg_writeln("To get help using phpdbg type \"help\" and press enter"); -		phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); -	} else { -		phpdbg_notice("Clean Execution Environment"); +		phpdbg_xml("<intros>"); +		phpdbg_notice("intro", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); +		phpdbg_writeln("intro", "help=\"help\"", "To get help using phpdbg type \"help\" and press enter"); +		phpdbg_notice("intro", "report=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES); +		phpdbg_xml("</intros>"); +	} else if (phpdbg_startup_run == 0) { +		if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) { +			phpdbg_notice(NULL, NULL, "Clean Execution Environment"); +		} -		phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table))); -		phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table))); -		phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants))); -		phpdbg_writeln("Includes\t\t%d",  zend_hash_num_elements(&EG(included_files))); +		phpdbg_write("cleaninfo", "classes=\"%d\" functions=\"%d\" constants=\"%d\" includes=\"%d\"", +			"Classes              %d\n" +			"Functions            %d\n" +			"Constants            %d\n" +			"Includes             %d\n", +			zend_hash_num_elements(EG(class_table)), +			zend_hash_num_elements(EG(function_table)), +			zend_hash_num_elements(EG(zend_constants)), +			zend_hash_num_elements(&EG(included_files)));  	}  } /* }}} */  static inline void phpdbg_sigint_handler(int signo) /* {{{ */  { -	TSRMLS_FETCH(); -	if (EG(in_execution)) { -		/* set signalled only when not interactive */ -		if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { -			PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; -		} -	} else { +	if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {  		/* we quit remote consoles on recv SIGINT */  		if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { -			PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; +			PHPDBG_G(flags) |= PHPDBG_IS_STOPPING;  			zend_bailout();  		} -	} -} /* }}} */ - -#ifndef _WIN32 -int phpdbg_open_socket(const char *interface, short port) /* {{{ */ -{ -	int fd = socket(AF_INET, SOCK_STREAM, 0); - -	switch (fd) { -		case -1: -			return -1; - -		default: { -			int reuse = 1; - -			switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) { -				case -1: -					close(fd); -					return -2; - -				default: { -					struct sockaddr_in address; - -					memset(&address, 0, sizeof(address)); - -					address.sin_port = htons(port); -					address.sin_family = AF_INET; - -					if ((*interface == '*')) { -						address.sin_addr.s_addr = htonl(INADDR_ANY); -					} else if (!inet_pton(AF_INET, interface, &address.sin_addr)) { -						close(fd); -						return -3; -					} - -					switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) { -						case -1: -							close(fd); -							return -4; - -						default: { -							listen(fd, 5); -						} -					} -				} +	} else { +		/* set signalled only when not interactive */ +		if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { +			if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { +				char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1]; + +				phpdbg_set_sigsafe_mem(mem); +				zend_try { +					phpdbg_force_interruption(); +				} zend_end_try() +				phpdbg_clear_sigsafe_mem(); +				return;  			} +			PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;  		}  	} - -	return fd;  } /* }}} */ -static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */ -{ -	if ((*socket)[0] >= 0) { -		shutdown( -			(*socket)[0], SHUT_RDWR); -		close((*socket)[0]); +static void phpdbg_remote_close(int socket, FILE *stream) { +	if (socket >= 0) { +		phpdbg_close_socket(socket);  	} -	if (streams[0]) { -		fclose(streams[0]); +	if (stream) { +		fclose(stream);  	} +} -	if ((*socket)[1] >= 0) { -		shutdown( -			(*socket)[1], SHUT_RDWR); -		close((*socket)[1]); -	} +/* don't inline this, want to debug it easily, will inline when done */ +static int phpdbg_remote_init(const char* address, unsigned short port, int server, int *socket, FILE **stream) { +	phpdbg_remote_close(*socket, *stream); -	if (streams[1]) { -		fclose(streams[1]); +	if (server < 0) { +		phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%u failed", address, port); + +		return FAILURE;  	} -} /* }}} */ -/* don't inline this, want to debug it easily, will inline when done */ +	phpdbg_rlog(fileno(stderr), "accepting connections on %s:%u", address, port); +	{ +		struct sockaddr_storage address; +		socklen_t size = sizeof(address); +		char buffer[20] = {0}; +		/* XXX error checks */ +		memset(&address, 0, size); +		*socket = accept(server, (struct sockaddr *) &address, &size); +		inet_ntop(AF_INET, &(((struct sockaddr_in *)&address)->sin_addr), buffer, sizeof(buffer)); -int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */ -{ -	if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) { -		((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]); -		((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]); +		phpdbg_rlog(fileno(stderr), "connection established from %s", buffer);  	} -	streams[0] = NULL; -	streams[1] = NULL; - -	if ((*listen)[0] < 0 || (*listen)[1] < 0) { -		if ((*listen)[0] < 0) { -			phpdbg_rlog(stderr, -				"console failed to initialize (stdin) on %s:%d", address, port[0]); -		} +#ifndef _WIN32 +	dup2(*socket, fileno(stdout)); +	dup2(*socket, fileno(stdin)); -		if ((*listen)[1] < 0) { -			phpdbg_rlog(stderr, -				"console failed to initialize (stdout) on %s:%d", address, port[1]); -		} +	setbuf(stdout, NULL); -		if ((*listen)[0] >= 0) { -			close((*listen)[0]); -		} +	*stream = fdopen(*socket, "r+"); -		if ((*listen)[1] >= 0) { -			close((*listen)[1]); -		} +	phpdbg_set_async_io(*socket); +#endif +	return SUCCESS; +} -		return FAILURE; -	} +#ifndef _WIN32 +/* This function *strictly* assumes that SIGIO is *only* used on the remote connection stream */ +void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */ +{ +	int flags; +	size_t newlen; +	size_t i/*, last_nl*/; -	phpdbg_close_sockets(socket, streams); +//	if (!(info->si_band & POLLIN)) { +//		return; /* Not interested in writeablility etc., just interested in incoming data */ +//	} -	phpdbg_rlog(stderr, -		"accepting connections on %s:%d/%d", address, port[0], port[1]); -	{ -		struct sockaddr_in address; -		socklen_t size = sizeof(address); -		char buffer[20] = {0}; +	/* only non-blocking reading, avoid non-blocking writing */ +	flags = fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_GETFL, 0); +	fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags | O_NONBLOCK); -		{ -			memset(&address, 0, size); -			(*socket)[0] = accept( -				(*listen)[0], (struct sockaddr *) &address, &size); -			inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); +	do { +		char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1]; +		size_t off = 0; -			phpdbg_rlog(stderr, "connection (stdin) from %s", buffer); +		if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) { +			break;  		} - -		{ -			memset(&address, 0, size); -			(*socket)[1] = accept( -				(*listen)[1], (struct sockaddr *) &address, &size); -		    inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); - -			phpdbg_rlog(stderr, "connection (stdout) from %s", buffer); +		for (i = 0; i < newlen; i++) { +			switch (mem[off + i]) { +				case '\x03': /* ^C char */ +					if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { +						break; /* or quit ??? */ +					} +					if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { +						phpdbg_set_sigsafe_mem(mem); +						zend_try { +							phpdbg_force_interruption(); +						} zend_end_try(); +						phpdbg_clear_sigsafe_mem(); +						break; +					} +					if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { +						PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; +					} +					break; +/*				case '\n': +					zend_llist_add_element(PHPDBG_G(stdin), strndup() +					last_nl = PHPDBG_G(stdin_buf).len + i; +					break; +*/			}  		} -	} +		off += i; +	} while (0); -	dup2((*socket)[0], fileno(stdin)); -	dup2((*socket)[1], fileno(stdout)); -	setbuf(stdout, NULL); - -	streams[0] = fdopen((*socket)[0], "r"); -	streams[1] = fdopen((*socket)[1], "w"); - -	return SUCCESS; +	fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags);  } /* }}} */  void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */  {  	int is_handled = FAILURE; -	TSRMLS_FETCH();  	switch (sig) {  		case SIGBUS:  		case SIGSEGV: -			is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC); +			if (PHPDBG_G(sigsegv_bailout)) { +				LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE); +			} +			is_handled = phpdbg_watchpoint_segfault_handler(info, context);  			if (is_handled == FAILURE) {  #ifdef ZEND_SIGNALS -				zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL TSRMLS_CC); +				zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);  #else  				sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);  #endif @@ -928,10 +961,9 @@ static inline zend_mm_heap *phpdbg_mm_get_heap() /* {{{ */  {  	zend_mm_heap *mm_heap; -	TSRMLS_FETCH(); -	mm_heap = zend_mm_set_heap(NULL TSRMLS_CC); -	zend_mm_set_heap(mm_heap TSRMLS_CC); +	mm_heap = zend_mm_set_heap(NULL); +	zend_mm_set_heap(mm_heap);  	return mm_heap;  } /* }}} */ @@ -961,8 +993,7 @@ int main(int argc, char **argv) /* {{{ */  	zend_ulong zend_extensions_len = 0L;  	zend_bool ini_ignore;  	char *ini_override; -	char *exec; -	size_t exec_len; +	char *exec = NULL;  	char *init_file;  	size_t init_file_len;  	zend_bool init_file_default; @@ -971,43 +1002,31 @@ int main(int argc, char **argv) /* {{{ */  	zend_ulong flags;  	char *php_optarg;  	int php_optind, opt, show_banner = 1; -	long cleaning = 0; +	long cleaning = -1;  	zend_bool remote = 0; -	int run = 0;  	int step = 0; - -#ifdef _WIN32 -	char *bp_tmp_file = NULL; -#else -	char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX"; -#endif - -#ifndef _WIN32 +	zend_phpdbg_globals *settings = NULL; +	char *bp_tmp = NULL;  	char *address; -	int listen[2]; -	int server[2]; -	int socket[2]; -	FILE* streams[2] = {NULL, NULL}; -#endif +	int listen = -1; +	int server = -1; +	int socket = -1; +	FILE* stream = NULL;  #ifdef ZTS  	void ***tsrm_ls;  #endif  #ifndef _WIN32 +	struct sigaction sigio_struct;  	struct sigaction signal_struct;  	signal_struct.sa_sigaction = phpdbg_signal_handler;  	signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER; +	sigio_struct.sa_sigaction = phpdbg_sigio_handler; +	sigio_struct.sa_flags = SA_SIGINFO; +  	address = strdup("127.0.0.1"); -	socket[0] = -1; -	socket[1] = -1; -	listen[0] = -1; -	listen[1] = -1; -	server[0] = -1; -	server[1] = -1; -	streams[0] = NULL; -	streams[1] = NULL;  #endif  #ifdef PHP_WIN32 @@ -1024,37 +1043,12 @@ int main(int argc, char **argv) /* {{{ */  #endif  phpdbg_main: -	if (!cleaning) { -	 -#ifdef _WIN32 -		bp_tmp_file = malloc(L_tmpnam); - -		if (bp_tmp_file) { -			if (!tmpnam(bp_tmp_file)) { -				free(bp_tmp_file); -				bp_tmp_file = NULL; -			} -		} - -		if (!bp_tmp_file) { -			phpdbg_error("Unable to create temporary file"); -			return 1; -		} -#else -		if (!mkstemp(bp_tmp_file)) { -			memset(bp_tmp_file, 0, sizeof(bp_tmp_file)); -		} -#endif - -	}  	ini_entries = NULL;  	ini_entries_len = 0;  	ini_ignore = 0;  	ini_override = NULL;  	zend_extensions = NULL;  	zend_extensions_len = 0L; -	exec = NULL; -	exec_len = 0;  	init_file = NULL;  	init_file_len = 0;  	init_file_default = 1; @@ -1064,14 +1058,16 @@ phpdbg_main:  	php_optarg = NULL;  	php_optind = 1;  	opt = 0; -	run = 0;  	step = 0;  	sapi_name = NULL; +	if (settings) { +		exec = settings->exec; +	}  	while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {  		switch (opt) {  			case 'r': -				run++; +				phpdbg_startup_run++;  				break;  			case 'n':  				ini_ignore = 1; @@ -1172,20 +1168,12 @@ phpdbg_main:  			break;  #ifndef _WIN32 -			/* if you pass a listen port, we will accept input on listen port */ -			/* and write output to listen port * 2 */ - -			case 'l': { /* set listen ports */ -				if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) { -					if (sscanf(php_optarg, "%d", &listen[0]) != 1) { -						/* default to hardcoded ports */ -						listen[0] = 4000; -						listen[1] = 8000; -					} else { -						listen[1] = (listen[0] * 2); -					} +			/* if you pass a listen port, we will read and write on listen port */ +			case 'l': /* set listen ports */ +				if (sscanf(php_optarg, "%d", &listen) != 1) { +					listen = 8000;  				} -			} break; +				break;  			case 'a': { /* set bind address */  				free(address); @@ -1195,6 +1183,10 @@ phpdbg_main:  			} break;  #endif +			case 'x': +				flags |= PHPDBG_WRITE_XML; +			break; +  			case 'V': {  				sapi_startup(phpdbg);  				phpdbg->startup(phpdbg); @@ -1206,18 +1198,16 @@ phpdbg_main:  					PHP_VERSION,  					get_zend_version()  				); -				sapi_deactivate(TSRMLS_C); +				sapi_deactivate();  				sapi_shutdown();  				return 0;  			} break;  		}  	} -	 +  	/* set exec if present on command line */ -	if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS)) -	{ -		exec_len = strlen(argv[php_optind]); -		if (exec_len) { +	if (!exec && (argc > php_optind) && (strcmp(argv[php_optind-1], "--") != SUCCESS)) { +		if (strlen(argv[php_optind])) {  			if (exec) {  				free(exec);  			} @@ -1226,19 +1216,6 @@ phpdbg_main:  		php_optind++;  	} -#ifndef _WIN32 -	/* setup remote server if necessary */ -	if (!cleaning && -		(listen[0] > 0 && listen[1] > 0)) { -		if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) { -			remote = 0; -			exit(0); -		} -		/* set remote flag to stop service shutting down upon quit */ -		remote = 1; -	} -#endif -  	if (sapi_name) {  		phpdbg->name = sapi_name;  	} @@ -1293,60 +1270,102 @@ phpdbg_main:      EXCEPTION_POINTERS *xp;      __try {  #endif -		zend_mm_heap *mm_heap = phpdbg_mm_get_heap(); +		zend_mm_heap *mm_heap; +		void* (*_malloc)(size_t); +		void (*_free)(void*); +		void* (*_realloc)(void*, size_t); -		if (mm_heap->use_zend_alloc) { -			mm_heap->_malloc = phpdbg_malloc_wrapper; -			mm_heap->_realloc = phpdbg_realloc_wrapper; -			mm_heap->_free = phpdbg_free_wrapper; -			mm_heap->use_zend_alloc = 0; +		/* set flags from command line */ +		PHPDBG_G(flags) = flags; + +		if (settings) { +#ifdef ZTS +			*((zend_phpdbg_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings; +#else +			phpdbg_globals = *settings; +#endif  		} -		zend_activate(TSRMLS_C); +		/* setup remote server if necessary */ +		if (cleaning <= 0 && listen > 0) { +			server = phpdbg_open_socket(address, listen); +				if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream) == FAILURE) { +				exit(0); +			} -		PHPDBG_G(original_free_function) = mm_heap->_free; -		mm_heap->_free = phpdbg_watch_efree; +#ifndef _WIN32 +			sigaction(SIGIO, &sigio_struct, NULL); +#endif + +			/* set remote flag to stop service shutting down upon quit */ +			remote = 1; +		} + +		mm_heap = phpdbg_mm_get_heap(); +		zend_mm_get_custom_handlers(mm_heap, &_malloc, &_free, &_realloc); + +		if (!_malloc) { +			_malloc = phpdbg_malloc_wrapper; +		} +		if (!_realloc) { +			_realloc = phpdbg_realloc_wrapper; +		} +		if (!_free) { +			_free = phpdbg_free_wrapper; +		} -		phpdbg_setup_watchpoints(TSRMLS_C); +		zend_activate(); + +		phpdbg_init_list(); + +		PHPDBG_G(original_free_function) = _free; +		_free = phpdbg_watch_efree; + +		zend_mm_set_custom_handlers(mm_heap, _malloc, _free, _realloc); + +		phpdbg_setup_watchpoints();  #if defined(ZEND_SIGNALS) && !defined(_WIN32)  		zend_try { -			zend_signal_activate(TSRMLS_C); +			zend_signal_activate();  		} zend_end_try();  #endif  #if defined(ZEND_SIGNALS) && !defined(_WIN32) -		zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try(); -		zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try(); +		zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try(); +		zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();  #elif !defined(_WIN32)  		sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal));  		sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));  #endif -		if (php_request_startup(TSRMLS_C) == SUCCESS) { +		PHPDBG_G(sapi_name_ptr) = sapi_name; + +		php_output_activate(); +		php_output_deactivate(); + +		php_output_activate(); + +		if (php_request_startup() == SUCCESS) {  			int i; -		 -			SG(request_info).argc = argc - php_optind + 1;		 + +			SG(request_info).argc = argc - php_optind + 1;  			SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *));  			for (i = SG(request_info).argc; --i;) {  				SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);  			} -			SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup(""); +			SG(request_info).argv[i] = exec ? estrdup(exec) : estrdup(""); -			php_hash_environment(TSRMLS_C); +			php_hash_environment();  		} -		/* make sure to turn off buffer for ev command */ -		php_output_activate(TSRMLS_C); -		php_output_deactivate(TSRMLS_C); -		  		/* do not install sigint handlers for remote consoles */  		/* sending SIGINT then provides a decent way of shutting down the server */  #ifndef _WIN32 -		if (listen[0] < 0) { +		if (listen < 0) {  #endif  #if defined(ZEND_SIGNALS) && !defined(_WIN32) -			zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try(); +			zend_try { zend_signal(SIGINT, phpdbg_sigint_handler); } zend_end_try();  #else  			signal(SIGINT, phpdbg_sigint_handler);  #endif @@ -1356,99 +1375,143 @@ phpdbg_main:  		PG(modules_activated) = 0; -		/* set flags from command line */ -		PHPDBG_G(flags) = flags; -  #ifndef _WIN32  		/* setup io here */ -		if (streams[0] && streams[1]) { +		if (remote) {  			PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;  			signal(SIGPIPE, SIG_IGN);  		}  #endif -		PHPDBG_G(io)[PHPDBG_STDIN] = stdin; -		PHPDBG_G(io)[PHPDBG_STDOUT] = stdout; -		PHPDBG_G(io)[PHPDBG_STDERR] = stderr; +#ifndef _WIN32 +		PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; +		PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin); +		PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; +		PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout); +#else +		/* XXX this is a complete mess here with FILE/fd/SOCKET, +			we should let only one to survive probably. Need +			a clean separation whether it's a remote or local +			prompt. And what is supposed to go as user interaction, +			error log, etc. */ +		if (remote) { +			PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; +			PHPDBG_G(io)[PHPDBG_STDIN].fd = socket; +			PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; +			PHPDBG_G(io)[PHPDBG_STDOUT].fd = socket; +		} else { +			PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; +			PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin); +			PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; +			PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout); +		} +#endif +		PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr; +		PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr); + +#ifndef _WIN32 +		PHPDBG_G(php_stdiop_write) = php_stream_stdio_ops.write; +		php_stream_stdio_ops.write = phpdbg_stdiop_write; +#endif  		if (exec) { /* set execution context */ -			PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); -			PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec)); +			PHPDBG_G(exec) = phpdbg_resolve_path(exec); +			PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0;  			free(exec); +			exec = NULL;  		}  		if (oplog_file) { /* open oplog */  			PHPDBG_G(oplog) = fopen(oplog_file, "w+");  			if (!PHPDBG_G(oplog)) { -				phpdbg_error( -						"Failed to open oplog %s", oplog_file); +				phpdbg_error("oplog", "path=\"%s\"", "Failed to open oplog %s", oplog_file);  			}  			free(oplog_file);  		}  		/* set default colors */ -		phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT,  PHPDBG_STRL("white-bold") TSRMLS_CC); -		phpdbg_set_color_ex(PHPDBG_COLOR_ERROR,   PHPDBG_STRL("red-bold") TSRMLS_CC); -		phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE,  PHPDBG_STRL("green") TSRMLS_CC); +		phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT,  PHPDBG_STRL("white-bold")); +		phpdbg_set_color_ex(PHPDBG_COLOR_ERROR,   PHPDBG_STRL("red-bold")); +		phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE,  PHPDBG_STRL("green"));  		/* set default prompt */ -		phpdbg_set_prompt(PROMPT TSRMLS_CC); +		phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT);  		/* Make stdin, stdout and stderr accessible from PHP scripts */ -		phpdbg_register_file_handles(TSRMLS_C); +		phpdbg_register_file_handles(); -		if (show_banner) { +		if (show_banner && cleaning < 2) {  			/* print blurb */ -			phpdbg_welcome((cleaning > 0) TSRMLS_CC); +			phpdbg_welcome(cleaning == 1);  		} -		/* auto compile */ -		if (PHPDBG_G(exec)) { -			phpdbg_compile(TSRMLS_C); -		} +		cleaning = -1;  		/* initialize from file */  		PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;  		zend_try { -			phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC); -			phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC); +			phpdbg_init(init_file, init_file_len, init_file_default); +			if (bp_tmp) { +				PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; +				phpdbg_string_init(bp_tmp); +				free(bp_tmp); +				bp_tmp = NULL; +				PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; +			}  		} zend_end_try();  		PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; -		 +  		/* quit if init says so */  		if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {  			goto phpdbg_out;  		} +		/* auto compile */ +		if (PHPDBG_G(exec)) { +			if (settings) { +				PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; +			} +			phpdbg_compile(); +			PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; +		} +  		/* step from here, not through init */  		if (step) {  			PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;  		} -		if (run) { -			/* no need to try{}, run does it ... */ -			PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); -			if (run > 1) { -				/* if -r is on the command line more than once just quit */ -				goto phpdbg_out; -			} -		} -  /* #ifndef for making compiler shutting up */  #ifndef _WIN32  phpdbg_interact:  #endif +  		/* phpdbg main() */  		do {  			zend_try { -				phpdbg_interactive(TSRMLS_C); +				if (phpdbg_startup_run) { +					zend_bool quit_immediately = phpdbg_startup_run > 1; +					phpdbg_startup_run = 0; +					PHPDBG_COMMAND_HANDLER(run)(NULL); +					if (quit_immediately) { +						/* if -r is on the command line more than once just quit */ +						EG(bailout) = __orig_bailout; /* reset zend_try */ +						break; +					} +				} + +				phpdbg_interactive(1);  			} zend_catch {  				if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { -					FILE *bp_tmp_fp = fopen(bp_tmp_file, "w"); -					phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC); -					fclose(bp_tmp_fp); +					char *bp_tmp_str; +					PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; +					phpdbg_export_breakpoints_to_string(&bp_tmp_str); +					PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; +					if (bp_tmp_str) { +						bp_tmp = strdup(bp_tmp_str); +						efree(bp_tmp_str); +					}  					cleaning = 1;  				} else {  					cleaning = 0; @@ -1458,17 +1521,16 @@ phpdbg_interact:  				if (!cleaning) {  					/* remote client disconnected */  					if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { -					 +  						if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {  							/* renegociate connections */ -							phpdbg_open_sockets( -								address, listen, &server, &socket, streams); -				 +							phpdbg_remote_init(address, listen, server, &socket, &stream); +  							/* set streams */ -							if (streams[0] && streams[1]) { +							if (stream) {  								PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;  							} -				 +  							/* this must be forced */  							CG(unclean_shutdown) = 0;  						} else { @@ -1479,14 +1541,19 @@ phpdbg_interact:  				}  #endif  			} zend_end_try(); -		} while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); -		 +		} while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)); + + +		if (PHPDBG_G(exec) && (PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { +			exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */ +		} +  		/* this must be forced */  		CG(unclean_shutdown) = 0; -		 +  		/* this is just helpful */  		PG(report_memleaks) = 0; -		 +  #ifndef _WIN32  phpdbg_out:  		if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { @@ -1497,11 +1564,16 @@ phpdbg_out:  #ifdef _WIN32  	} __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) { -		phpdbg_error("Access violation (Segmentation fault) encountered\ntrying to abort cleanly..."); +		phpdbg_error("segfault", "", "Access violation (Segmentation fault) encountered\ntrying to abort cleanly...");  	}  phpdbg_out:  #endif -	 + +		if (cleaning <= 0) { +			PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING; +			cleaning = -1; +		} +  		{  			int i;  			/* free argv */ @@ -1511,11 +1583,15 @@ phpdbg_out:  			efree(SG(request_info).argv);  		} +#ifndef _WIN32 +		/* reset it... else we risk a stack overflow upon next run (when clean'ing) */ +		php_stream_stdio_ops.write = PHPDBG_G(php_stdiop_write); +#endif +  #ifndef ZTS  		/* force cleanup of auto and core globals */  		zend_hash_clean(CG(auto_globals)); -		memset( -			&core_globals, 0, sizeof(php_core_globals)); +		memset(	&core_globals, 0, sizeof(php_core_globals));  #endif  		if (ini_entries) {  			free(ini_entries); @@ -1524,27 +1600,47 @@ phpdbg_out:  		if (ini_override) {  			free(ini_override);  		} -		 +  		/* this must be forced */  		CG(unclean_shutdown) = 0; -		 +  		/* this is just helpful */  		PG(report_memleaks) = 0; -		php_request_shutdown((void*)0); +		if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) { +			php_free_shutdown_functions(); +			zend_objects_store_mark_destructed(&EG(objects_store)); +		} + +		/* sapi_module.deactivate is where to backup things, last chance before mm_shutdown... */  		zend_try { -			php_module_shutdown(TSRMLS_C); +			php_request_shutdown(NULL); +		} zend_end_try(); + +		if ((PHPDBG_G(flags) & (PHPDBG_IS_QUITTING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_RUNNING) { +			phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); +			cleaning++; +		} + +		if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) == PHPDBG_IS_CLEANING) { +			settings = PHPDBG_G(backup); +		} + +		php_output_deactivate(); + +		zend_try { +			php_module_shutdown();  		} zend_end_try();  		sapi_shutdown();  	} -	if (cleaning || remote) { +	if (cleaning > 0 || remote) {  		goto phpdbg_main;  	} -	 +  #ifdef ZTS  	/* bugggy */  	/* tsrm_shutdown(); */ @@ -1556,15 +1652,9 @@ phpdbg_out:  	}  #endif -	if (sapi_name) { -		free(sapi_name); +	if (PHPDBG_G(sapi_name_ptr)) { +		free(PHPDBG_G(sapi_name_ptr));  	} -	 -#ifdef _WIN32 -	free(bp_tmp_file); -#else -	unlink(bp_tmp_file); -#endif  	return 0;  } /* }}} */ | 
