diff options
Diffstat (limited to 'sapi/phpdbg/phpdbg.c')
| -rw-r--r-- | sapi/phpdbg/phpdbg.c | 312 | 
1 files changed, 198 insertions, 114 deletions
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 51a328d0b5..064e266082 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -18,7 +18,7 @@     +----------------------------------------------------------------------+  */ -#ifndef ZEND_SIGNALS +#if !defined(ZEND_SIGNALS) || defined(_WIN32)  # include <signal.h>  #endif  #include "phpdbg.h" @@ -28,6 +28,7 @@  #include "phpdbg_list.h"  #include "phpdbg_utils.h"  #include "phpdbg_set.h" +#include "zend_alloc.h"  /* {{{ remote console headers */  #ifndef _WIN32 @@ -61,16 +62,15 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */  	pg->exec = NULL;  	pg->exec_len = 0; +	pg->buffer = NULL;  	pg->ops = NULL;  	pg->vmret = 0;  	pg->bp_count = 0; -	pg->lcmd = NULL;  	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->lparam, 0, sizeof(phpdbg_param_t));  	pg->frame.num = 0;  } /* }}} */ @@ -145,6 +145,7 @@ static void php_phpdbg_destroy_registered(void *data) /* {{{ */  		function TSRMLS_CC);  } /* }}} */ +  static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */  {  	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],   8, NULL, php_phpdbg_destroy_bp_file, 0); @@ -157,7 +158,9 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */  	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);  	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);  	zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0); -	 + +	phpdbg_setup_watchpoints(TSRMLS_C); +  	zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);  	zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0); @@ -178,7 +181,14 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */  	zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);  	zend_hash_destroy(&PHPDBG_G(seek));  	zend_hash_destroy(&PHPDBG_G(registered)); +	zend_hash_destroy(&PHPDBG_G(watchpoints)); +	zend_llist_destroy(&PHPDBG_G(watchlist_mem)); +	if (PHPDBG_G(buffer)) { +		efree(PHPDBG_G(buffer)); +		PHPDBG_G(buffer) = NULL; +	} +	  	if (PHPDBG_G(exec)) {  		efree(PHPDBG_G(exec));  		PHPDBG_G(exec) = NULL; @@ -209,24 +219,24 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */  	return SUCCESS;  } /* }}} */ -/* {{{ proto mixed phpdbg_exec(string context)  +/* {{{ proto mixed phpdbg_exec(string context)  	Attempt to set the execution context for phpdbg  	If the execution context was set previously it is returned -	If the execution context was not set previously boolean true is returned  +	If the execution context was not set previously boolean true is returned  	If the request to set the context fails, boolean false is returned, and an E_WARNING raised */ -static PHP_FUNCTION(phpdbg_exec)  +static PHP_FUNCTION(phpdbg_exec)  {  	char *exec = NULL; -	zend_ulong exec_len = 0L; +	int exec_len = 0;  	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) {  		return;  	} -	 +  	{  		struct stat sb;  		zend_bool result = 1; -		 +  		if (VCWD_STAT(exec, &sb) != FAILURE) {  			if (sb.st_mode & (S_IFREG|S_IFLNK)) {  				if (PHPDBG_G(exec)) { @@ -234,11 +244,11 @@ static PHP_FUNCTION(phpdbg_exec)  					efree(PHPDBG_G(exec));  					result = 0;  				} -			 +  				PHPDBG_G(exec) = estrndup(exec, exec_len);  				PHPDBG_G(exec_len) = exec_len; -			 -				if (result)  + +				if (result)  					ZVAL_BOOL(return_value, 1);  			} else {  				zend_error( @@ -259,9 +269,9 @@ static PHP_FUNCTION(phpdbg_exec)  static PHP_FUNCTION(phpdbg_break)  {  	if (ZEND_NUM_ARGS() > 0) { -		long type; +		long type = 0;  		char *expr = NULL; -		zend_uint expr_len = 0; +		int expr_len = 0;  		phpdbg_param_t param;  		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &type, &expr, &expr_len) == FAILURE) { @@ -269,28 +279,7 @@ static PHP_FUNCTION(phpdbg_break)  		}  		phpdbg_parse_param(expr, expr_len, ¶m TSRMLS_CC); - -		switch (type) { -			case METHOD_PARAM: -				phpdbg_do_break_method(¶m, NULL TSRMLS_CC); -				break; - -			case FILE_PARAM: -				phpdbg_do_break_file(¶m, NULL TSRMLS_CC); -				break; - -			case NUMERIC_PARAM: -				phpdbg_do_break_lineno(¶m, NULL TSRMLS_CC); -				break; - -			case STR_PARAM: -				phpdbg_do_break_func(¶m, NULL TSRMLS_CC); -				break; - -			default: zend_error( -							 E_WARNING, "unrecognized parameter type %ld", type); -		} - +		phpdbg_do_break(¶m TSRMLS_CC);  		phpdbg_clear_param(¶m TSRMLS_CC);  	} else if (EG(current_execute_data) && EG(active_op_array)) { @@ -319,9 +308,9 @@ static PHP_FUNCTION(phpdbg_clear)  /* {{{ proto void phpdbg_color(integer element, string color) */  static PHP_FUNCTION(phpdbg_color)  { -	long element; -	char *color; -	zend_uint color_len; +	long element = 0L; +	char *color = NULL; +	int color_len = 0;  	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) {  		return; @@ -341,8 +330,8 @@ static PHP_FUNCTION(phpdbg_color)  /* {{{ proto void phpdbg_prompt(string prompt) */  static PHP_FUNCTION(phpdbg_prompt)  { -	char *prompt; -	zend_uint prompt_len; +	char *prompt = NULL; +	int prompt_len = 0;  	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) {  		return; @@ -403,9 +392,9 @@ static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /*  	if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {  		return FAILURE;  	} -	 +  	phpdbg_booted=1; -	 +  	return SUCCESS;  } /* }}} */ @@ -585,7 +574,6 @@ const opt_struct OPTIONS[] = { /* {{{ */  	{'z', 1, "load zend_extension"},  	/* phpdbg options */  	{'q', 0, "no banner"}, -	{'e', 1, "exec"},  	{'v', 0, "disable quietness"},  	{'s', 0, "enable stepping"},  	{'b', 0, "boring colours"}, @@ -615,10 +603,10 @@ const char phpdbg_ini_hardcoded[] =  /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */  #define INI_DEFAULT(name, value) \ -        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); +	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);  void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */  { @@ -666,11 +654,11 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */  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; @@ -678,27 +666,27 @@ int phpdbg_open_socket(const char *interface, short port) /* {{{ */  				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);						 +						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);  						} @@ -707,28 +695,28 @@ int phpdbg_open_socket(const char *interface, short port) /* {{{ */  			}  		}  	} -	 +  	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]);  	} -	 +  	if (streams[0]) {  		fclose(streams[0]);  	} -	 +  	if ((*socket)[1] >= 0) {  		shutdown(  			(*socket)[1], SHUT_RDWR);  		close((*socket)[1]);  	} -	 +  	if (streams[1]) {  		fclose(streams[1]);  	} @@ -798,14 +786,34 @@ int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*sock  	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;  } /* }}} */ + +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 (is_handled == FAILURE) { +#ifdef ZEND_SIGNALS +				zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL TSRMLS_CC); +#else +				sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL); +#endif +			} +			break; +	} + +}  #endif  int main(int argc, char **argv) /* {{{ */ @@ -852,6 +860,10 @@ int main(int argc, char **argv) /* {{{ */  #endif  #ifndef _WIN32 +	struct sigaction signal_struct; +	signal_struct.sa_sigaction = phpdbg_signal_handler; +	signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER; +  	address = strdup("127.0.0.1");  	socket[0] = -1;  	socket[1] = -1; @@ -888,17 +900,17 @@ phpdbg_main:  				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 -		if (!bp_tmp_file) { -			phpdbg_error( -				"Unable to create temporary file"); -			return 1; -		}  	}  	ini_entries = NULL;  	ini_entries_len = 0; @@ -920,8 +932,7 @@ phpdbg_main:  	run = 0;  	step = 0;  	sapi_name = NULL; -	 -	 +  	while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {  		switch (opt) {  			case 'r': @@ -965,7 +976,7 @@ phpdbg_main:  				  ini_entries_len += len + sizeof("=1\n\0") - 2;  				}  			} break; -			 +  			case 'z':  				zend_extensions_len++;  				if (zend_extensions) { @@ -976,16 +987,6 @@ phpdbg_main:  			/* begin phpdbg options */ -			case 'e': { /* set execution context */ -				exec_len = strlen(php_optarg); -				if (exec_len) { -					if (exec) { -						free(exec); -					} -					exec = strdup(php_optarg); -				} -			} break; -			  			case 'S': { /* set SAPI name */  				if (sapi_name) {  					free(sapi_name); @@ -1001,7 +1002,7 @@ phpdbg_main:  				if (init_file) {  					free(init_file);  				} -				 +  				init_file_len = strlen(php_optarg);  				if (init_file_len) {  					init_file = strdup(php_optarg); @@ -1038,7 +1039,7 @@ phpdbg_main:  #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) { @@ -1050,7 +1051,7 @@ phpdbg_main:  					}  				}  			} break; -			 +  			case 'a': { /* set bind address */  				free(address);  				if (!php_optarg) { @@ -1076,6 +1077,19 @@ phpdbg_main:  			} 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) { +				free(exec); +			} +			exec = strdup(argv[php_optind]); +		} +		php_optind++; +	}  #ifndef _WIN32  	/* setup remote server if necessary */ @@ -1093,7 +1107,7 @@ phpdbg_main:  	if (sapi_name) {  		phpdbg->name = sapi_name;  	} -	 +  	phpdbg->ini_defaults = phpdbg_ini_defaults;  	phpdbg->phpinfo_as_text = 1;  	phpdbg->php_ini_ignore_cwd = 1; @@ -1114,14 +1128,14 @@ phpdbg_main:  		memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));  	}  	ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2; -	 +  	if (zend_extensions_len) {  		zend_ulong zend_extension = 0L; -		 +  		while (zend_extension < zend_extensions_len) {  			const char *ze = zend_extensions[zend_extension];  			size_t ze_len = strlen(ze); -			 +  			ini_entries = realloc(  				ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));  			memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1)); @@ -1133,40 +1147,81 @@ phpdbg_main:  			free(zend_extensions[zend_extension]);  			zend_extension++;  		} -		 +  		free(zend_extensions);  	}  	phpdbg->ini_entries = ini_entries; -		 +  	if (phpdbg->startup(phpdbg) == SUCCESS) { -		php_request_startup(TSRMLS_C); +#ifdef _WIN32 +    EXCEPTION_POINTERS *xp; +    __try { +#endif +		zend_mm_heap *mm_heap = zend_mm_set_heap(NULL TSRMLS_CC); +#if ZEND_DEBUG +		if (!mm_heap->use_zend_alloc) { +			mm_heap->_malloc = malloc; +			mm_heap->_realloc = realloc; +			mm_heap->_free = free; +#endif +			PHPDBG_G(original_free_function) = mm_heap->_free; +			mm_heap->_free = phpdbg_watch_efree; +			mm_heap->use_zend_alloc = 0; +#if ZEND_DEBUG +		} +#endif +		zend_mm_set_heap(mm_heap TSRMLS_CC); + +		zend_activate(TSRMLS_C); + +#if defined(ZEND_SIGNALS) && !defined(_WIN32) +		zend_try { +			zend_signal_activate(TSRMLS_C); +		} 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(); +#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) { +			int i; +		 +			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(""); + +			php_hash_environment(TSRMLS_C); +		} + +		/* 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 */ -#ifdef ZEND_SIGNALS -# ifndef _WIN32 +#if defined(ZEND_SIGNALS) && !defined(_WIN32)  		if (listen[0] < 0) { -# endif -			zend_try { -				zend_signal_activate(TSRMLS_C); -				zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); -			} zend_end_try(); -# ifndef _WIN32 +			zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try();  		} -# endif -#else -# ifndef _WIN32 +#elif !defined(_WIN32)  		if (listen[0] < 0) { -# endif +#endif  			signal(SIGINT, phpdbg_sigint_handler);  #ifndef _WIN32  		}  #endif -#endif  		PG(modules_activated) = 0; -		 +  		/* set flags from command line */  		PHPDBG_G(flags) = flags; @@ -1182,10 +1237,9 @@ phpdbg_main:  		PHPDBG_G(io)[PHPDBG_STDIN] = stdin;  		PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;  		PHPDBG_G(io)[PHPDBG_STDERR] = stderr; -		 +  		if (exec) { /* set execution context */ -			PHPDBG_G(exec) = phpdbg_resolve_path( -					exec TSRMLS_CC); +			PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);  			PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));  			free(exec); @@ -1213,6 +1267,11 @@ phpdbg_main:  			phpdbg_welcome((cleaning > 0) TSRMLS_CC);  		} +		/* auto compile */ +		if (PHPDBG_G(exec)) { +			phpdbg_compile(TSRMLS_C); +		} +  		/* initialize from file */  		PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;  		zend_try { @@ -1233,14 +1292,17 @@ phpdbg_main:  		if (run) {  			/* no need to try{}, run does it ... */ -			PHPDBG_COMMAND_HANDLER(run)(NULL, NULL TSRMLS_CC); +			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 { @@ -1282,21 +1344,42 @@ phpdbg_interact:  			} zend_end_try();  		} while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); -phpdbg_out: +		/* 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)) {  			PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;  			goto phpdbg_interact;  		}  #endif +#ifdef _WIN32 +	} __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) { +		phpdbg_error("Access violation (Segementation fault) encountered\ntrying to abort cleanly..."); +	} +phpdbg_out: +#endif +	 +		{ +			int i; +			/* free argv */ +			for (i = SG(request_info).argc; --i;) { +				efree(SG(request_info).argv[i]); +			} +			efree(SG(request_info).argv); +		} +  #ifndef ZTS  		/* force cleanup of auto and core globals */  		zend_hash_clean(CG(auto_globals));  		memset(  			&core_globals, 0, sizeof(php_core_globals));  #endif -		  		if (ini_entries) {  			free(ini_entries);  		} @@ -1318,6 +1401,7 @@ phpdbg_out:  		} zend_end_try();  		sapi_shutdown(); +  	}  	if (cleaning || remote) { @@ -1331,7 +1415,7 @@ phpdbg_out:  #ifndef _WIN32  	if (address) { -		free(address);	 +		free(address);  	}  #endif  | 
