123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816 |
- /*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2016 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Felipe Pena <felipe@php.net> |
- | Authors: Joe Watkins <joe.watkins@live.co.uk> |
- | Authors: Bob Weinand <bwoebi@php.net> |
- +----------------------------------------------------------------------+
- */
- #include "phpdbg.h"
- #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:
- return "address";
- case NUMERIC_PARAM:
- return "numeric";
- case METHOD_PARAM:
- return "method";
- case NUMERIC_FUNCTION_PARAM:
- return "function opline";
- case NUMERIC_METHOD_PARAM:
- return "method opline";
- case FILE_PARAM:
- return "file or file opline";
- case STR_PARAM:
- return "string";
- default: /* this is bad */
- return "unknown";
- }
- }
- PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param TSRMLS_DC) /* {{{ */
- {
- if (param) {
- switch (param->type) {
- case FILE_PARAM:
- efree(param->file.name);
- break;
- case METHOD_PARAM:
- efree(param->method.class);
- efree(param->method.name);
- break;
- case STR_PARAM:
- efree(param->str);
- break;
- default:
- break;
- }
- }
- } /* }}} */
- PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC) /* {{{ */
- {
- switch (param->type) {
- case STR_PARAM:
- asprintf(pointer,
- "%s", param->str);
- break;
- case ADDR_PARAM:
- asprintf(pointer,
- "%#lx", param->addr);
- break;
- case NUMERIC_PARAM:
- asprintf(pointer,
- "%li",
- param->num);
- break;
- case METHOD_PARAM:
- 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);
- } else {
- asprintf(pointer,
- "%s:%lu",
- param->file.name,
- param->file.line);
- }
- break;
- case NUMERIC_FUNCTION_PARAM:
- 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);
- break;
- default:
- asprintf(pointer,
- "%s", "unknown");
- }
- return *pointer;
- } /* }}} */
- 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;
- break;
- case NUMERIC_PARAM:
- dest->num = src->num;
- break;
- case METHOD_PARAM:
- dest->method.class = estrdup(src->method.class);
- 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;
- if (src->num)
- dest->num = src->num;
- break;
- case NUMERIC_FUNCTION_PARAM:
- dest->str = estrndup(src->str, src->len);
- dest->num = src->num;
- dest->len = src->len;
- break;
- case NUMERIC_METHOD_PARAM:
- dest->method.class = estrdup(src->method.class);
- dest->method.name = estrdup(src->method.name);
- dest->num = src->num;
- break;
- case EMPTY_PARAM: { /* do nothing */ } break;
-
- default: {
- /* not yet */
- }
- }
- } /* }}} */
- 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;
- case METHOD_PARAM:
- hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
- hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
- break;
- case FILE_PARAM:
- hash += zend_inline_hash_func(param->file.name, strlen(param->file.name));
- hash += param->file.line;
- if (param->num)
- hash += param->num;
- break;
- case ADDR_PARAM:
- hash += param->addr;
- break;
- case NUMERIC_PARAM:
- hash += param->num;
- break;
- case NUMERIC_FUNCTION_PARAM:
- hash += zend_inline_hash_func(param->str, param->len);
- hash += param->num;
- break;
- case NUMERIC_METHOD_PARAM:
- hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
- hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
- if (param->num)
- hash+= param->num;
- break;
- case EMPTY_PARAM: { /* do nothing */ } break;
-
- default: {
- /* not yet */
- }
- }
- return hash;
- } /* }}} */
- PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_param_t *r TSRMLS_DC) /* {{{ */
- {
- 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;
- }
- /* break intentionally omitted */
- case STR_PARAM:
- return (l->len == r->len) &&
- (memcmp(l->str, r->str, l->len) == SUCCESS);
- case NUMERIC_PARAM:
- return (l->num == r->num);
- case ADDR_PARAM:
- return (l->addr == r->addr);
- case FILE_PARAM: {
- if (l->file.line == r->file.line) {
- size_t lengths[2] = {
- strlen(l->file.name), strlen(r->file.name)};
- if (lengths[0] == lengths[1]) {
- if ((!l->num && !r->num) || (l->num == r->num)) {
- return (memcmp(
- l->file.name, r->file.name, lengths[0]) == SUCCESS);
- }
- }
- }
- } break;
- case NUMERIC_METHOD_PARAM:
- if (l->num != r->num) {
- break;
- }
- /* break intentionally omitted */
- case METHOD_PARAM: {
- size_t lengths[2] = {
- strlen(l->method.class), strlen(r->method.class)};
- if (lengths[0] == lengths[1]) {
- if (memcmp(l->method.class, r->method.class, lengths[0]) == SUCCESS) {
- lengths[0] = strlen(l->method.name);
- lengths[1] = strlen(r->method.name);
- if (lengths[0] == lengths[1]) {
- return (memcmp(
- l->method.name, r->method.name, lengths[0]) == SUCCESS);
- }
- }
- }
- } break;
- case EMPTY_PARAM:
- return 1;
-
- default: {
- /* not yet */
- }
- }
- }
- }
- return 0;
- } /* }}} */
- /* {{{ */
- 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 */
- }
- }
- }
- } /* }}} */
- /* {{{ */
- 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 */
- }
- }
-
- free(remove);
- remove = NULL;
-
- if (next)
- remove = next;
- else break;
- }
- }
-
- stack->next = NULL;
- } /* }}} */
- /* {{{ */
- PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param) {
- phpdbg_param_t *next = calloc(1, sizeof(phpdbg_param_t));
- if (!next)
- return;
- *(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;
- }
- stack->len++;
- } /* }}} */
- 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 {
- /* 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 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) /* {{{ */
- {
- 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 (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;
- }
- }
-
- /* 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;
- }
- 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;
- }
- if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
- add_history(cmd);
- }
- #endif
- } else cmd = buffered;
-
- buffer = estrdup(cmd);
- #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
- if (!buffered && cmd &&
- !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
- free(cmd);
- }
- #endif
- }
- if (buffer && isspace(*buffer)) {
- char *trimmed = buffer;
- while (isspace(*trimmed))
- trimmed++;
- trimmed = estrdup(trimmed);
- efree(buffer);
- buffer = trimmed;
- }
- 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));
- }
- }
-
- return buffer;
- } /* }}} */
- PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */
- {
- efree(*input);
- } /* }}} */
|