diff options
Diffstat (limited to 'sapi/phpdbg/phpdbg_cmd.c')
-rw-r--r-- | sapi/phpdbg/phpdbg_cmd.c | 383 |
1 files changed, 199 insertions, 184 deletions
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c index 0437455054..729babefca 100644 --- a/sapi/phpdbg/phpdbg_cmd.c +++ b/sapi/phpdbg/phpdbg_cmd.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -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; } @@ -167,59 +168,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; @@ -231,12 +212,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; @@ -276,7 +257,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 */ } @@ -291,7 +272,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; @@ -329,7 +310,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 */ } @@ -347,7 +328,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; @@ -402,7 +383,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa case EMPTY_PARAM: return 1; - + default: { /* not yet */ } @@ -419,43 +400,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 */ } @@ -467,13 +448,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: @@ -487,29 +468,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; } /* }}} */ @@ -537,30 +519,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] == '|') { @@ -569,21 +550,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), \ @@ -593,14 +572,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; @@ -610,14 +589,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++; } @@ -625,28 +604,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)) { @@ -654,85 +632,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; 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; } @@ -741,103 +710,148 @@ 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 *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_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) { + fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); } if (buffered == NULL) { -disconnect: if (0) { +disconnect: 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))) { +#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 */ + /* strongly assuming to be in blocking mode... */ +#if USE_LIB_STAR +readline: + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) +#endif + { + char buf[PHPDBG_MAX_CMD]; + int bytes = PHPDBG_G(input_buflen), len = 0; + if (PHPDBG_G(input_buflen)) { + memcpy(buf, PHPDBG_G(input_buffer), bytes); + } + + phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C)); + PHPDBG_G(last_was_newline) = 1; + + do { + int i; + if (bytes <= 0) { + continue; + } + + for (i = len; i < len + bytes; i++) { + if (buf[i] == '\x03') { + if (i != len + bytes - 1) { + memmove(buf + i, buf + i + 1, len + bytes - i - 1); + } + len--; + i--; + continue; + } + if (buf[i] == '\n') { + PHPDBG_G(input_buflen) = len + bytes - 1 - i; + if (PHPDBG_G(input_buflen)) { + memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen)); + } + if (i != PHPDBG_MAX_CMD - 1) { + buf[i + 1] = 0; + } + cmd = buf; + goto end; + } + } + len += bytes; + /* XXX export the timeout through INI??*/ + } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0); + + if (bytes <= 0) { goto disconnect; } + + cmd = buf; } - - /* 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)); } - 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; } @@ -846,13 +860,15 @@ readline: add_history(cmd); } #endif - } else cmd = buffered; - + } else { + cmd = buffered; + } +end: + PHPDBG_G(last_was_newline) = 1; 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 @@ -878,7 +894,7 @@ readline: buffer = estrdup(PHPDBG_G(buffer)); } } - + return buffer; } /* }}} */ @@ -886,4 +902,3 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */ { efree(*input); } /* }}} */ - |