summaryrefslogtreecommitdiff
path: root/sapi/phpdbg/phpdbg_cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sapi/phpdbg/phpdbg_cmd.c')
-rw-r--r--sapi/phpdbg/phpdbg_cmd.c369
1 files changed, 177 insertions, 192 deletions
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c
index 5290639dcb..5c74adfdcd 100644
--- a/sapi/phpdbg/phpdbg_cmd.c
+++ b/sapi/phpdbg/phpdbg_cmd.c
@@ -23,6 +23,7 @@
#include "phpdbg_utils.h"
#include "phpdbg_set.h"
#include "phpdbg_prompt.h"
+#include "phpdbg_io.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
@@ -39,7 +40,7 @@ static inline const char *phpdbg_command_name(const phpdbg_command_t *command, c
memcpy(&buffer[pos], command->name, command->name_len);
pos += command->name_len;
buffer[pos] = 0;
-
+
return buffer;
}
@@ -94,59 +95,39 @@ PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **point
{
switch (param->type) {
case STR_PARAM:
- asprintf(pointer,
- "%s", param->str);
+ asprintf(pointer, "%s", param->str);
break;
case ADDR_PARAM:
- asprintf(pointer,
- "%#lx", param->addr);
+ asprintf(pointer, "%#llx", param->addr);
break;
case NUMERIC_PARAM:
- asprintf(pointer,
- "%li",
- param->num);
+ asprintf(pointer, "%li", param->num);
break;
case METHOD_PARAM:
- asprintf(pointer,
- "%s::%s",
- param->method.class,
- param->method.name);
+ asprintf(pointer, "%s::%s", param->method.class, param->method.name);
break;
case FILE_PARAM:
if (param->num) {
- asprintf(pointer,
- "%s:%lu#%lu",
- param->file.name,
- param->file.line,
- param->num);
+ asprintf(pointer, "%s:%lu#%lu", param->file.name, param->file.line, param->num);
} else {
- asprintf(pointer,
- "%s:%lu",
- param->file.name,
- param->file.line);
+ asprintf(pointer, "%s:%lu", param->file.name, param->file.line);
}
break;
case NUMERIC_FUNCTION_PARAM:
- asprintf(pointer,
- "%s#%lu", param->str, param->num);
+ asprintf(pointer, "%s#%lu", param->str, param->num);
break;
case NUMERIC_METHOD_PARAM:
- asprintf(pointer,
- "%s::%s#%lu",
- param->method.class,
- param->method.name,
- param->num);
+ asprintf(pointer, "%s::%s#%lu", param->method.class, param->method.name, param->num);
break;
default:
- asprintf(pointer,
- "%s", "unknown");
+ *pointer = strdup("unknown");
}
return *pointer;
@@ -158,12 +139,12 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des
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;
@@ -203,7 +184,7 @@ 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 */
}
@@ -218,7 +199,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /
case STACK_PARAM:
/* nope */
break;
-
+
case STR_PARAM:
hash += zend_inline_hash_func(param->str, param->len);
break;
@@ -256,7 +237,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /
break;
case EMPTY_PARAM: { /* do nothing */ } break;
-
+
default: {
/* not yet */
}
@@ -274,7 +255,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa
/* nope, or yep */
return 1;
break;
-
+
case NUMERIC_FUNCTION_PARAM:
if (l->num != r->num) {
break;
@@ -329,7 +310,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa
case EMPTY_PARAM:
return 1;
-
+
default: {
/* not yet */
}
@@ -346,43 +327,43 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)
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);
+ fprintf(stderr, "%s ADDR_PARAM(%llu)\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 */
}
@@ -394,13 +375,13 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)
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:
@@ -414,29 +395,30 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) {
case STR_PARAM:
case OP_PARAM:
if (remove->str)
- free(remove->str);
+ free(remove->str);
break;
-
+
case NUMERIC_FILE_PARAM:
case FILE_PARAM:
if (remove->file.name)
free(remove->file.name);
break;
-
+
default: {
/* nothing */
}
}
-
+
free(remove);
remove = NULL;
-
+
if (next)
- remove = next;
+ remove = next;
else break;
}
}
-
+
+
stack->next = NULL;
} /* }}} */
@@ -464,30 +446,29 @@ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param)
stack->len++;
} /* }}} */
-PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC) {
+PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack 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;
+ 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_error("command", "type=\"toomanyargs\" command=\"%s\" expected=\"0\"", "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] == '|') {
@@ -496,21 +477,19 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
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_error("command", "type=\"noarg\" command=\"%s\" expected=\"%s\" num=\"%lu\"", "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_error("command", "type=\"wrongarg\" command=\"%s\" expected=\"%s\" got=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got %s at parameter %lu", \
phpdbg_command_name(command, buffer), \
(e),\
phpdbg_get_param_type((a) TSRMLS_CC), \
@@ -520,14 +499,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
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;
@@ -537,14 +516,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
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++;
}
@@ -552,28 +531,27 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
#undef verify_arg
if ((received < least)) {
- asprintf(why,
- "The command \"%s\" expected at least %lu arguments (%s) and received %lu",
+ phpdbg_error("command", "type=\"toofewargs\" command=\"%s\" expected=\"%d\" argtypes=\"%s\" got=\"%d\"", "The command \"%s\" expected at least %lu arguments (%s) and received %lu",
phpdbg_command_name(command, buffer),
least,
- command->args,
+ 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) {
+PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC) {
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)) {
+ if (name->len == 1 || command->name_len >= name->len) {
/* match single letter alias */
if (command->alias && (name->len == 1)) {
if (command->alias == (*name->str)) {
@@ -581,85 +559,76 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
matches++;
}
} else {
-
/* 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)) {
+ 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)
+ if (name->len == command->name_len) {
break;
- } else break;
+ }
+ } else {
+ break;
+ }
}
}
}
-
+
command++;
}
-
+
switch (matches) {
- case 0: {
+ 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: {
+ phpdbg_error("command", "type=\"notfound\" command=\"%s\" subcommand=\"%s\"", "The command \"%s %s\" could not be found", parent->name, name->str);
+ } else {
+ phpdbg_error("command", "type=\"notfound\" command=\"%s\"", "The command \"%s\" could not be found", name->str);
+ }
+ return parent;
+
+ case 1:
(*top) = (*top)->next;
command = matched[0];
- } break;
-
+ break;
+
default: {
char *list = NULL;
- zend_uint it = 0;
+ uint32_t it = 0;
size_t pos = 0;
-
+
while (it < matches) {
if (!list) {
- list = malloc(
- matched[it]->name_len + 1 +
- ((it+1) < matches ? sizeof(", ")-1 : 0));
+ list = emalloc(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));
+ list = erealloc(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);
+ 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;
+
+ /* ", " separated matches */
+ phpdbg_error("command", "type=\"ambiguous\" command=\"%s\" matches=\"%lu\" matched=\"%s\"", "The command \"%s\" is ambigious, matching %lu commands (%s)", name->str, matches, list);
+ efree(list);
+
+ return NULL;
+ }
}
if (command->subs && (*top) && ((*top)->type == STR_PARAM)) {
- return phpdbg_stack_resolve(command->subs, command, top, why);
+ return phpdbg_stack_resolve(command->subs, command, top TSRMLS_CC);
} else {
return command;
}
@@ -668,103 +637,98 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
} /* }}} */
/* {{{ */
-PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) {
+PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe 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 !!");
+ phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !");
return FAILURE;
}
-
+
if (!stack->len) {
- asprintf(
- why, "The stack contains nothing !!");
+ phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !");
return FAILURE;
}
-
- top = (phpdbg_param_t*) stack->next;
-
+
+ top = (phpdbg_param_t *) stack->next;
+
switch (top->type) {
case EVAL_PARAM:
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ phpdbg_free_err_buf(TSRMLS_C);
return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC);
case RUN_PARAM:
+ if (!allow_async_unsafe) {
+ phpdbg_error("signalsegv", "command=\"run\"", "run command is disallowed during hard interrupt");
+ }
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ phpdbg_free_err_buf(TSRMLS_C);
return PHPDBG_COMMAND_HANDLER(run)(top TSRMLS_CC);
-
+
case SHELL_PARAM:
+ if (!allow_async_unsafe) {
+ phpdbg_error("signalsegv", "command=\"sh\"", "sh command is disallowed during hard interrupt");
+ return FAILURE;
+ }
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ phpdbg_free_err_buf(TSRMLS_C);
return PHPDBG_COMMAND_HANDLER(sh)(top TSRMLS_CC);
-
+
case STR_PARAM: {
- handler = phpdbg_stack_resolve(
- phpdbg_prompt_commands, NULL, &top, why);
-
+ handler = phpdbg_stack_resolve(phpdbg_prompt_commands, NULL, &top TSRMLS_CC);
+
if (handler) {
- if (phpdbg_stack_verify(handler, &top, why TSRMLS_CC) == SUCCESS) {
+ if (!allow_async_unsafe && !(handler->flags & PHPDBG_ASYNC_SAFE)) {
+ phpdbg_error("signalsegv", "command=\"%s\"", "%s command is disallowed during hard interrupt", handler->name);
+ return FAILURE;
+ }
+
+ if (phpdbg_stack_verify(handler, &top TSRMLS_CC) == SUCCESS) {
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ phpdbg_free_err_buf(TSRMLS_C);
return handler->handler(top TSRMLS_CC);
}
}
} return FAILURE;
-
+
default:
- asprintf(
- why, "The first parameter makes no sense !!");
+ phpdbg_error("command", "type=\"invalidcommand\"", "The first parameter makes no sense !");
return FAILURE;
}
-
+
return SUCCESS;
} /* }}} */
-PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
+PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
{
- char *cmd = NULL;
-#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT)
char buf[PHPDBG_MAX_CMD];
-#endif
+ char *cmd = NULL;
char *buffer = NULL;
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
- if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) &&
- (buffered == NULL)) {
- fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
+ if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) != PHPDBG_IS_STOPPING) {
+ if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) {
+ fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
}
if (buffered == NULL) {
-disconnect:
- if (0) {
- PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
- zend_bailout();
- return NULL;
- }
-
-#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT)
- if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
- if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) {
- goto disconnect;
- }
+#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT))
+ /* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */
+#if USE_LIB_STAR
+readline:
+ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE)
+#endif
+ {
+ phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_consume_stdin_line(cmd = buf TSRMLS_CC);
}
-
- /* note: EOF is ignored */
-readline:
- if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
- /* the user has gone away */
- if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
- goto disconnect;
- } else goto readline;
+#if USE_LIB_STAR
+ else {
+ cmd = readline(phpdbg_get_prompt(TSRMLS_C));
+ PHPDBG_G(last_was_newline) = 1;
}
- cmd = buf;
-#else
- /* note: EOF makes readline write prompt again in local console mode */
-readline:
- if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
- char buf[PHPDBG_MAX_CMD];
- if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
- cmd = buf;
- } else goto disconnect;
- } else cmd = readline(phpdbg_get_prompt(TSRMLS_C));
-
if (!cmd) {
goto readline;
}
@@ -773,13 +737,14 @@ readline:
add_history(cmd);
}
#endif
- } else cmd = buffered;
-
+ } else {
+ cmd = buffered;
+ }
+
buffer = estrdup(cmd);
-#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
- if (!buffered && cmd &&
- !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+#if USE_LIB_STAR
+ if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
free(cmd);
}
#endif
@@ -805,7 +770,7 @@ readline:
buffer = estrdup(PHPDBG_G(buffer));
}
}
-
+
return buffer;
} /* }}} */
@@ -814,3 +779,23 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */
efree(*input);
} /* }}} */
+PHPDBG_API int phpdbg_ask_user_permission(const char *question TSRMLS_DC) {
+ if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
+ char buf[PHPDBG_MAX_CMD];
+ phpdbg_out("%s", question);
+ phpdbg_out(" (type y or n): ");
+
+ while (1) {
+ phpdbg_consume_stdin_line(buf TSRMLS_CC);
+ if (buf[1] == '\n' && (buf[0] == 'y' || buf[0] == 'n')) {
+ if (buf[0] == 'y') {
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ phpdbg_out("Please enter either y (yes) or n (no): ");
+ }
+ }
+
+ return SUCCESS;
+}