summaryrefslogtreecommitdiff
path: root/sapi/phpdbg/phpdbg_cmd.c
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2014-05-05 11:21:23 +0200
committerOndřej Surý <ondrej@sury.org>2014-05-05 11:21:23 +0200
commit4bbffbee21093458feadd96f93b96d4627461cff (patch)
treed316b17d64aede352ae0a336c23238b8756004e6 /sapi/phpdbg/phpdbg_cmd.c
parent9566c3fcaf4cfaa866ea395ee5d1a480785fef0d (diff)
downloadphp-4bbffbee21093458feadd96f93b96d4627461cff.tar.gz
New upstream version 5.6.0~beta2+dfsgupstream/5.6.0_beta2+dfsg
Diffstat (limited to 'sapi/phpdbg/phpdbg_cmd.c')
-rw-r--r--sapi/phpdbg/phpdbg_cmd.c674
1 files changed, 437 insertions, 237 deletions
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c
index 1d78c5332..d4ce8ebc5 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,
- &param 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(&param, 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(&param TSRMLS_CC);
- }
- break;
- }
- command++;
- }
- } else {
- /* this should NEVER happen */
- phpdbg_error(
- "No function executed!!");
- }
-
- return rc;
+ efree(*input);
} /* }}} */