diff options
Diffstat (limited to 'sapi/phpdbg/phpdbg_cmd.c')
| -rw-r--r-- | sapi/phpdbg/phpdbg_cmd.c | 674 | 
1 files changed, 437 insertions, 237 deletions
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c index 1d78c53321..d4ce8ebc55 100644 --- a/sapi/phpdbg/phpdbg_cmd.c +++ b/sapi/phpdbg/phpdbg_cmd.c @@ -22,12 +22,32 @@  #include "phpdbg_cmd.h"  #include "phpdbg_utils.h"  #include "phpdbg_set.h" +#include "phpdbg_prompt.h"  ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +static inline const char *phpdbg_command_name(const phpdbg_command_t *command, char *buffer) { +	size_t pos = 0; + +	if (command->parent) { +		memcpy(&buffer[pos], command->parent->name, command->parent->name_len); +		pos += command->parent->name_len; +		memcpy(&buffer[pos], " ", sizeof(" ")-1); +		pos += (sizeof(" ")-1); +	} + +	memcpy(&buffer[pos], command->name, command->name_len); +	pos += command->name_len; +	buffer[pos] = 0; +	 +	return buffer; +} +  PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */  {  	switch (param->type) { +		case STACK_PARAM: +			return "stack";  		case EMPTY_PARAM:  			return "empty";  		case ADDR_PARAM: @@ -208,10 +228,19 @@ PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **point  PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest TSRMLS_DC) /* {{{ */  {  	switch ((dest->type = src->type)) { +		case STACK_PARAM: +			/* nope */ +		break; +		  		case STR_PARAM:  			dest->str = estrndup(src->str, src->len);  			dest->len = src->len;  		break; +		 +		case OP_PARAM: +			dest->str = estrndup(src->str, src->len); +			dest->len = src->len; +		break;  		case ADDR_PARAM:  			dest->addr = src->addr; @@ -226,6 +255,7 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des  			dest->method.name = estrdup(src->method.name);  		break; +		case NUMERIC_FILE_PARAM:  		case FILE_PARAM:  			dest->file.name = estrdup(src->file.name);  			dest->file.line = src->file.line; @@ -246,6 +276,10 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des  		break;  		case EMPTY_PARAM: { /* do nothing */ } break; +		 +		default: { +			/* not yet */ +		}  	}  } /* }}} */ @@ -254,6 +288,10 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /  	zend_ulong hash = param->type;  	switch (param->type) { +		case STACK_PARAM: +			/* nope */ +		break; +		  		case STR_PARAM:  			hash += zend_inline_hash_func(param->str, param->len);  		break; @@ -291,6 +329,10 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /  		break;  		case EMPTY_PARAM: { /* do nothing */ } break; +		 +		default: { +			/* not yet */ +		}  	}  	return hash; @@ -301,7 +343,11 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa  	if (l && r) {  		if (l->type == r->type) {  			switch (l->type) { - +				case STACK_PARAM: +					/* nope, or yep */ +					return 1; +				break; +				  				case NUMERIC_FUNCTION_PARAM:  					if (l->num != r->num) {  						break; @@ -356,112 +402,400 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa  				case EMPTY_PARAM:  					return 1; +					 +				default: { +					/* not yet */ +				}  			}  		}  	}  	return 0;  } /* }}} */ -PHPDBG_API phpdbg_input_t **phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC) /* {{{ */ -{ -	char *p; -	char b[PHPDBG_MAX_CMD]; -	int l=0; -	enum states { -		IN_BETWEEN, -		IN_WORD, -		IN_STRING -	} state = IN_BETWEEN; -	phpdbg_input_t **argv = NULL; - -	argv = (phpdbg_input_t**) emalloc(sizeof(phpdbg_input_t*)); -	(*argc) = 0; - -#define RESET_STATE() do { \ -	phpdbg_input_t *arg = emalloc(sizeof(phpdbg_input_t)); \ -	if (arg) { \ -		b[l]=0; \ -		arg->length = l; \ -		arg->string = estrndup(b, arg->length); \ -		arg->argv = NULL; \ -		arg->argc = 0; \ -		argv = (phpdbg_input_t**) erealloc(argv, sizeof(phpdbg_input_t*) * ((*argc)+1)); \ -		argv[(*argc)++] = arg; \ -		l = 0; \ -	} \ -	state = IN_BETWEEN; \ -} while (0) - -	for (p = buffer; *p != '\0'; p++) { -		int c = (unsigned char) *p; -		switch (state) { -			case IN_BETWEEN: -				if (isspace(c)) { -					continue; -				} -				if (c == '"') { -					state = IN_STRING; -					continue; -				} -				state = IN_WORD; -				b[l++]=c; -				continue; - -			case IN_STRING: -				if (c == '"') { -					if (buffer[(p - buffer)-1] == '\\') { -						b[l-1]=c; -						continue; -					} -					RESET_STATE(); -				} else { -					b[l++]=c; -				} -				continue; +/* {{{ */ +PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) { +	if (param && param->type) { +		switch (param->type) { +			case STR_PARAM: +				fprintf(stderr, "%s STR_PARAM(%s=%lu)\n", msg, param->str, param->len); +			break; +			 +			case ADDR_PARAM: +				fprintf(stderr, "%s ADDR_PARAM(%lu)\n", msg, param->addr); +			break; +			 +			case NUMERIC_FILE_PARAM: +				fprintf(stderr, "%s NUMERIC_FILE_PARAM(%s:#%lu)\n", msg, param->file.name, param->file.line); +			break; +			 +			case FILE_PARAM: +				fprintf(stderr, "%s FILE_PARAM(%s:%lu)\n", msg, param->file.name, param->file.line); +			break; +			 +			case METHOD_PARAM: +				fprintf(stderr, "%s METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); +			break; +			 +			case NUMERIC_METHOD_PARAM: +				fprintf(stderr, "%s NUMERIC_METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); +			break; +			 +			case NUMERIC_FUNCTION_PARAM: +				fprintf(stderr, "%s NUMERIC_FUNCTION_PARAM(%s::%ld)\n", msg, param->str, param->num); +			break; +			 +			case NUMERIC_PARAM: +				fprintf(stderr, "%s NUMERIC_PARAM(%ld)\n", msg, param->num); +			break; +			 +			case COND_PARAM: +				fprintf(stderr, "%s COND_PARAM(%s=%lu)\n", msg, param->str, param->len); +			break; +			 +			case OP_PARAM: +				fprintf(stderr, "%s OP_PARAM(%s=%lu)\n", msg, param->str, param->len); +			break; +			 +			default: { +				/* not yet */ +			} +		} +	} +} /* }}} */ -			case IN_WORD: -				if (isspace(c)) { -					RESET_STATE(); -				} else { -					b[l++]=c; +/* {{{ */ +PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) { +	if (stack && stack->next) { +		phpdbg_param_t *remove = stack->next; +		 +		while (remove) { +			phpdbg_param_t *next = NULL; +			 +			if (remove->next) +				next = remove->next; +			 +			switch (remove->type) { +				case NUMERIC_METHOD_PARAM: +				case METHOD_PARAM: +					if (remove->method.class) +						free(remove->method.class); +					if (remove->method.name) +						free(remove->method.name); +				break; + +				case NUMERIC_FUNCTION_PARAM: +				case STR_PARAM: +				case OP_PARAM: +					if (remove->str) +						free(remove->str);	 +				break; +				 +				case NUMERIC_FILE_PARAM: +				case FILE_PARAM: +					if (remove->file.name) +						free(remove->file.name); +				break; +				 +				default: { +					/* nothing */  				} -				continue; +			} +			 +			free(remove); +			remove = NULL; +			 +			if (next) +				remove = next;  +			else break;  		}  	} +	 +	stack->next = NULL; +} /* }}} */ -	switch (state) { -		case IN_WORD: { -			RESET_STATE(); -		} break; +/* {{{ */ +PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param) { +	phpdbg_param_t *next = calloc(1, sizeof(phpdbg_param_t)); -		case IN_STRING: -			phpdbg_error( -				"Malformed command line (unclosed quote) @ %ld: %s!", -				(p - buffer)-1, &buffer[(p - buffer)-1]); -		break; +	if (!next) +		return; -		case IN_BETWEEN: -		break; +	*(next) = *(param); + +	next->next = NULL; + +	if (stack->top == NULL) { +		stack->top = next; +		next->top = NULL; +		stack->next = next; +	} else { +		stack->top->next = next; +		next->top = stack->top; +		stack->top = next;  	} -	if ((*argc) == 0) { -		/* not needed */ -		efree(argv); +	stack->len++; +} /* }}} */ -		/* to be sure */ -		return NULL; +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC) { +	if (command) { +		char buffer[128] = {0,}; +		const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL; +		const char *arg = command->args; +		size_t least = 0L, +			   received = 0L, +			   current = 0L; +		zend_bool optional = 0; +		 +		/* check for arg spec */ +		if (!(arg) || !(*arg)) { +			if (!top) { +				return SUCCESS; +			} +			 +			asprintf(why, +				"The command \"%s\" expected no arguments",  +				phpdbg_command_name(command, buffer)); +			return FAILURE; +		} +		 +		least = 0L; +		 +		/* count least amount of arguments */ +		while (arg && *arg) { +			if (arg[0] == '|') { +				break; +			} +			least++; +			arg++; +		} +		 +		arg = command->args; + +#define verify_arg(e, a, t) if (!(a)) { \ +	if (!optional) { \ +		asprintf(why, \ +			"The command \"%s\" expected %s and got nothing at parameter %lu", \ +			phpdbg_command_name(command, buffer), \ +			(e), \ +			current); \ +		return FAILURE;\ +	} \ +} else if ((a)->type != (t)) { \ +	asprintf(why, \ +		"The command \"%s\" expected %s and got %s at parameter %lu", \ +		phpdbg_command_name(command, buffer), \ +		(e),\ +		phpdbg_get_param_type((a) TSRMLS_CC), \ +		current); \ +	return FAILURE; \ +} + +		while (arg && *arg) { +			current++; +			 +			switch (*arg) { +				case '|': { +					current--; +					optional = 1; +					arg++; +				} continue; +				 +				case 'i': verify_arg("raw input", top, STR_PARAM); break; +				case 's': verify_arg("string", top, STR_PARAM); break; +				case 'n': verify_arg("number", top, NUMERIC_PARAM); break; +				case 'm': verify_arg("method", top, METHOD_PARAM); break; +				case 'a': verify_arg("address", top, ADDR_PARAM); break; +				case 'f': verify_arg("file:line", top, FILE_PARAM); break; +				case 'c': verify_arg("condition", top, COND_PARAM); break; +				case 'o': verify_arg("opcode", top, OP_PARAM); break; +				case 'b': verify_arg("boolean", top, NUMERIC_PARAM); break; +				 +				case '*': { /* do nothing */ } break; +			} +			 +			if (top ) { +				top = top->next; +			} else break; +			 +			received++; +			arg++; +		} + +#undef verify_arg + +		if ((received < least)) { +			asprintf(why, +				"The command \"%s\" expected at least %lu arguments (%s) and received %lu", +				phpdbg_command_name(command, buffer), +				least, +				command->args,  +				received); +			return FAILURE; +		}  	} +	 +	return SUCCESS; +} + +/* {{{ */ +PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why) { +	const phpdbg_command_t *command = commands; +	phpdbg_param_t *name = *top; +	const phpdbg_command_t *matched[3] = {NULL, NULL, NULL}; +	ulong matches = 0L; +	 +	while (command && command->name && command->handler) { +		if ((name->len == 1) || (command->name_len >= name->len)) { +			/* match single letter alias */ +			if (command->alias && (name->len == 1)) { +				if (command->alias == (*name->str)) { +					matched[matches] = command; +					matches++; +				} +			} else { -	return argv; +				/* match full, case insensitive, command name */ +				if (strncasecmp(command->name, name->str, name->len) == SUCCESS) { +					if (matches < 3) { +						 +						/* only allow abbreviating commands that can be aliased */ +						if (((name->len != command->name_len) && command->alias) || +							(name->len == command->name_len)) { +							matched[matches] = command; +							matches++; +						} +						 +						 +						/* exact match */ +						if (name->len == command->name_len) +							break; +					} else break; +				} +			} +		} +		 +		command++; +	} +	 +	switch (matches) { +		case 0: { +			if (parent) { +				asprintf( +				why, +				"The command \"%s %s\" could not be found",  +				parent->name, name->str); +			} else asprintf( +				why, +				"The command \"%s\" could not be found",  +				name->str); +		} return parent; +		 +		case 1: { +			(*top) = (*top)->next; + +			command = matched[0]; +		} break; +		 +		default: { +			char *list = NULL; +			zend_uint it = 0; +			size_t pos = 0; +			 +			while (it < matches) { +				if (!list) { +					list = malloc( +						matched[it]->name_len + 1 +  +						((it+1) < matches ? sizeof(", ")-1 : 0)); +				} else { +					list = realloc(list,  +						(pos + matched[it]->name_len) + 1  +  +						((it+1) < matches ? sizeof(", ")-1 : 0)); +				} +				memcpy(&list[pos], matched[it]->name, matched[it]->name_len); +				pos += matched[it]->name_len; +				if ((it+1) < matches) { +					memcpy(&list[pos], ", ", sizeof(", ")-1); +					pos += (sizeof(", ") - 1); +				} +				 +				list[pos] = 0; +				it++; +			} +			 +			asprintf( +				why, +				"The command \"%s\" is ambigious, matching %lu commands (%s)",  +				name->str, matches, list); +			free(list); +		} return NULL; +	} + +	if (command->subs && (*top) && ((*top)->type == STR_PARAM)) { +		return phpdbg_stack_resolve(command->subs, command, top, why); +	} else { +		return command; +	} + +	return NULL;  } /* }}} */ -PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ +/* {{{ */ +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) { +	phpdbg_param_t *top = NULL; +	const phpdbg_command_t *handler = NULL; +	 +	if (stack->type != STACK_PARAM) { +		asprintf( +			why, "The passed argument was not a stack !!"); +		return FAILURE; +	} +	 +	if (!stack->len) { +		asprintf( +			why, "The stack contains nothing !!"); +		return FAILURE; +	} +	 +	top = (phpdbg_param_t*) stack->next; +	 +	switch (top->type) { +		case EVAL_PARAM: +			return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC); + +		case RUN_PARAM: +			return PHPDBG_COMMAND_HANDLER(run)(top TSRMLS_CC); +		 +		case SHELL_PARAM: +			return PHPDBG_COMMAND_HANDLER(sh)(top TSRMLS_CC); +		 +		case STR_PARAM: { +			handler = phpdbg_stack_resolve( +				phpdbg_prompt_commands, NULL, &top, why); +			 +			if (handler) { +				if (phpdbg_stack_verify(handler, &top, why TSRMLS_CC) == SUCCESS) { +					return handler->handler(top TSRMLS_CC); +				} +			} +		} return FAILURE; +		 +		default: +			asprintf( +				why, "The first parameter makes no sense !!"); +			return FAILURE; +	} +	 +	return SUCCESS; +} /* }}} */ + +PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */  { -	phpdbg_input_t *buffer = NULL;  	char *cmd = NULL;  #ifndef HAVE_LIBREADLINE  	char buf[PHPDBG_MAX_CMD];  #endif +	char *buffer = NULL;  	if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {  		if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && @@ -513,32 +847,8 @@ readline:  			}  #endif  		} else cmd = buffered; - -		/* allocate and sanitize buffer */ -		buffer = (phpdbg_input_t*) ecalloc(1, sizeof(phpdbg_input_t)); -		if (!buffer) { -			return NULL; -		} - -		buffer->string = phpdbg_trim(cmd, strlen(cmd), &buffer->length); - -		/* store constant pointer to start of buffer */ -		buffer->start = (char* const*) buffer->string; - -		buffer->argv = phpdbg_read_argv( -			buffer->string, &buffer->argc TSRMLS_CC); - -#ifdef PHPDBG_DEBUG -		if (buffer->argc) { -			int arg = 0; - -			while (arg < buffer->argc) { -				phpdbg_debug( -					"argv %d=%s", arg, buffer->argv[arg]->string); -				arg++; -			} -		} -#endif +		 +		buffer = estrdup(cmd);  #ifdef HAVE_LIBREADLINE  		if (!buffered && cmd && @@ -546,144 +856,34 @@ readline:  			free(cmd);  		}  #endif - -		return buffer;  	} -	return NULL; -} /* }}} */ +	if (buffer && isspace(*buffer)) { +		char *trimmed = buffer; +		while (isspace(*trimmed)) +			trimmed++; -PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC) /* {{{ */ -{ -	if (argv) { -		if (argc) { -			int arg; -			for (arg=0; arg<argc; arg++) { -				phpdbg_destroy_input( -					&argv[arg] TSRMLS_CC); -			} -		} -		efree(argv); +		trimmed = estrdup(trimmed); +		efree(buffer); +		buffer = trimmed;  	} -} /* }}} */ - -PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t **input TSRMLS_DC) /*{{{ */ -{ -	if (*input) { -		if ((*input)->string) { -			efree((*input)->string); +	if (buffer && strlen(buffer)) { +		if (PHPDBG_G(buffer)) { +			efree(PHPDBG_G(buffer)); +		} +		PHPDBG_G(buffer) = estrdup(buffer); +	} else { +		if (PHPDBG_G(buffer)) { +			buffer = estrdup(PHPDBG_G(buffer));  		} - -		phpdbg_destroy_argv( -			(*input)->argv, (*input)->argc TSRMLS_CC); - -		efree(*input);  	} +	 +	return buffer;  } /* }}} */ -PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */  { -	int rc = FAILURE; - -	if (input->argc > 0) { -		while (command && command->name && command->handler) { -			if (((command->name_len == input->argv[0]->length) && -				(memcmp(command->name, input->argv[0]->string, command->name_len) == SUCCESS)) || -				(command->alias && -				(input->argv[0]->length == 1) && -				(command->alias == *input->argv[0]->string))) { - -				phpdbg_param_t param; -				phpdbg_command_t *initial_last_cmd; -				phpdbg_param_t initial_last_param; - -				param.type = EMPTY_PARAM; - -				if (input->argc > 1) { -					if (command->subs) { -						phpdbg_input_t sub = *input; - -						sub.string += input->argv[0]->length; -						sub.length -= input->argv[0]->length; - -						sub.string = phpdbg_trim( -							sub.string, sub.length, &sub.length); - -						sub.argc--; -						sub.argv++; - -						phpdbg_debug( -							"trying sub commands in \"%s\" for \"%s\" with %d arguments", -							command->name, sub.argv[0]->string, sub.argc-1); - -						if (phpdbg_do_cmd(command->subs, &sub TSRMLS_CC) == SUCCESS) { -							efree(sub.string); -							return SUCCESS; -						} - -						efree(sub.string); -					} - -					/* no sub command found */ -					{ -						char *store = input->string; - -						input->string += input->argv[0]->length; -						input->length -= input->argv[0]->length; - -						input->string = phpdbg_trim( -							input->string, input->length, &input->length); - -						efree(store); -					} - -					/* pass parameter on */ -					phpdbg_parse_param( -						input->string, -						input->length, -						¶m TSRMLS_CC); -				} - -				phpdbg_debug( -					"found command %s for %s with %d arguments", -					command->name, input->argv[0]->string, input->argc-1); -				{ -					int arg; -					for (arg=1; arg<input->argc; arg++) { -						phpdbg_debug( -							"\t#%d: [%s=%zu]", -							arg, -							input->argv[arg]->string, -							input->argv[arg]->length); -					} -				} - -				initial_last_param = PHPDBG_G(lparam); -				initial_last_cmd = (phpdbg_command_t *)PHPDBG_G(lcmd); -				PHPDBG_G(lparam) = param; -				PHPDBG_G(lcmd) = (phpdbg_command_t *)command; - -				rc = command->handler(¶m, input TSRMLS_CC); - -				/* only set last command when it is worth it! */ -				if (rc != FAILURE && !(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) { -					phpdbg_clear_param(&initial_last_param TSRMLS_CC); -				} else if (PHPDBG_G(lcmd) == command && !memcmp(&PHPDBG_G(lparam),& initial_last_param, sizeof(phpdbg_param_t))) { -					PHPDBG_G(lparam) = initial_last_param; -					PHPDBG_G(lcmd) = initial_last_cmd; -					phpdbg_clear_param(¶m TSRMLS_CC); -				} -				break; -			} -			command++; -		} -	} else { -		/* this should NEVER happen */ -		phpdbg_error( -			"No function executed!!"); -	} - -	return rc; +	efree(*input);  } /* }}} */  | 
