root/sapi/phpdbg/phpdbg_cmd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_EXTERN_MODULE_GLOBALS
  2. phpdbg_get_param_type
  3. phpdbg_clear_param
  4. phpdbg_param_tostring
  5. phpdbg_copy_param
  6. phpdbg_hash_param
  7. phpdbg_match_param
  8. phpdbg_param_debug
  9. phpdbg_stack_free
  10. phpdbg_stack_push
  11. phpdbg_stack_separate
  12. phpdbg_stack_verify
  13. phpdbg_stack_resolve
  14. phpdbg_internal_stack_execute
  15. phpdbg_stack_execute
  16. phpdbg_read_input
  17. phpdbg_destroy_input
  18. phpdbg_ask_user_permission

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Felipe Pena <felipe@php.net>                                |
  16    | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
  17    | Authors: Bob Weinand <bwoebi@php.net>                                |
  18    +----------------------------------------------------------------------+
  19 */
  20 
  21 #include "phpdbg.h"
  22 #include "phpdbg_cmd.h"
  23 #include "phpdbg_utils.h"
  24 #include "phpdbg_set.h"
  25 #include "phpdbg_prompt.h"
  26 #include "phpdbg_io.h"
  27 
  28 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
  29 
  30 static inline const char *phpdbg_command_name(const phpdbg_command_t *command, char *buffer) {
  31         size_t pos = 0;
  32 
  33         if (command->parent) {
  34                 memcpy(&buffer[pos], command->parent->name, command->parent->name_len);
  35                 pos += command->parent->name_len;
  36                 memcpy(&buffer[pos], " ", sizeof(" ")-1);
  37                 pos += (sizeof(" ")-1);
  38         }
  39 
  40         memcpy(&buffer[pos], command->name, command->name_len);
  41         pos += command->name_len;
  42         buffer[pos] = 0;
  43 
  44         return buffer;
  45 }
  46 
  47 PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param) /* {{{ */
  48 {
  49         switch (param->type) {
  50                 case STACK_PARAM:
  51                         return "stack";
  52                 case EMPTY_PARAM:
  53                         return "empty";
  54                 case ADDR_PARAM:
  55                         return "address";
  56                 case NUMERIC_PARAM:
  57                         return "numeric";
  58                 case METHOD_PARAM:
  59                         return "method";
  60                 case NUMERIC_FUNCTION_PARAM:
  61                         return "function opline";
  62                 case NUMERIC_METHOD_PARAM:
  63                         return "method opline";
  64                 case FILE_PARAM:
  65                         return "file or file opline";
  66                 case STR_PARAM:
  67                         return "string";
  68                 default: /* this is bad */
  69                         return "unknown";
  70         }
  71 }
  72 
  73 PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param) /* {{{ */
  74 {
  75         if (param) {
  76                 switch (param->type) {
  77                         case FILE_PARAM:
  78                                 efree(param->file.name);
  79                                 break;
  80                         case METHOD_PARAM:
  81                                 efree(param->method.class);
  82                                 efree(param->method.name);
  83                                 break;
  84                         case STR_PARAM:
  85                                 efree(param->str);
  86                                 break;
  87                         default:
  88                                 break;
  89                 }
  90         }
  91 
  92 } /* }}} */
  93 
  94 PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer) /* {{{ */
  95 {
  96         switch (param->type) {
  97                 case STR_PARAM:
  98                         ZEND_IGNORE_VALUE(asprintf(pointer, "%s", param->str));
  99                 break;
 100 
 101                 case ADDR_PARAM:
 102                         ZEND_IGNORE_VALUE(asprintf(pointer, ZEND_ULONG_FMT, param->addr));
 103                 break;
 104 
 105                 case NUMERIC_PARAM:
 106                         ZEND_IGNORE_VALUE(asprintf(pointer, "%li", param->num));
 107                 break;
 108 
 109                 case METHOD_PARAM:
 110                         ZEND_IGNORE_VALUE(asprintf(pointer, "%s::%s", param->method.class, param->method.name));
 111                 break;
 112 
 113                 case FILE_PARAM:
 114                         if (param->num) {
 115                                 ZEND_IGNORE_VALUE(asprintf(pointer, "%s:%lu#%lu", param->file.name, param->file.line, param->num));
 116                         } else {
 117                                 ZEND_IGNORE_VALUE(asprintf(pointer, "%s:%lu", param->file.name, param->file.line));
 118                         }
 119                 break;
 120 
 121                 case NUMERIC_FUNCTION_PARAM:
 122                         ZEND_IGNORE_VALUE(asprintf(pointer, "%s#%lu", param->str, param->num));
 123                 break;
 124 
 125                 case NUMERIC_METHOD_PARAM:
 126                         ZEND_IGNORE_VALUE(asprintf(pointer, "%s::%s#%lu", param->method.class, param->method.name, param->num));
 127                 break;
 128 
 129                 default:
 130                         *pointer = strdup("unknown");
 131         }
 132 
 133         return *pointer;
 134 } /* }}} */
 135 
 136 PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest) /* {{{ */
 137 {
 138         switch ((dest->type = src->type)) {
 139                 case STACK_PARAM:
 140                         /* nope */
 141                 break;
 142 
 143                 case STR_PARAM:
 144                         dest->str = estrndup(src->str, src->len);
 145                         dest->len = src->len;
 146                 break;
 147 
 148                 case OP_PARAM:
 149                         dest->str = estrndup(src->str, src->len);
 150                         dest->len = src->len;
 151                 break;
 152 
 153                 case ADDR_PARAM:
 154                         dest->addr = src->addr;
 155                 break;
 156 
 157                 case NUMERIC_PARAM:
 158                         dest->num = src->num;
 159                 break;
 160 
 161                 case METHOD_PARAM:
 162                         dest->method.class = estrdup(src->method.class);
 163                         dest->method.name = estrdup(src->method.name);
 164                 break;
 165 
 166                 case NUMERIC_FILE_PARAM:
 167                 case FILE_PARAM:
 168                         dest->file.name = estrdup(src->file.name);
 169                         dest->file.line = src->file.line;
 170                         if (src->num)
 171                                 dest->num   = src->num;
 172                 break;
 173 
 174                 case NUMERIC_FUNCTION_PARAM:
 175                         dest->str = estrndup(src->str, src->len);
 176                         dest->num = src->num;
 177                         dest->len = src->len;
 178                 break;
 179 
 180                 case NUMERIC_METHOD_PARAM:
 181                         dest->method.class = estrdup(src->method.class);
 182                         dest->method.name = estrdup(src->method.name);
 183                         dest->num = src->num;
 184                 break;
 185 
 186                 case EMPTY_PARAM: { /* do nothing */ } break;
 187 
 188                 default: {
 189                         /* not yet */
 190                 }
 191         }
 192 } /* }}} */
 193 
 194 PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param) /* {{{ */
 195 {
 196         zend_ulong hash = param->type;
 197 
 198         switch (param->type) {
 199                 case STACK_PARAM:
 200                         /* nope */
 201                 break;
 202 
 203                 case STR_PARAM:
 204                         hash += zend_inline_hash_func(param->str, param->len);
 205                 break;
 206 
 207                 case METHOD_PARAM:
 208                         hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
 209                         hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
 210                 break;
 211 
 212                 case FILE_PARAM:
 213                         hash += zend_inline_hash_func(param->file.name, strlen(param->file.name));
 214                         hash += param->file.line;
 215                         if (param->num)
 216                                 hash += param->num;
 217                 break;
 218 
 219                 case ADDR_PARAM:
 220                         hash += param->addr;
 221                 break;
 222 
 223                 case NUMERIC_PARAM:
 224                         hash += param->num;
 225                 break;
 226 
 227                 case NUMERIC_FUNCTION_PARAM:
 228                         hash += zend_inline_hash_func(param->str, param->len);
 229                         hash += param->num;
 230                 break;
 231 
 232                 case NUMERIC_METHOD_PARAM:
 233                         hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
 234                         hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
 235                         if (param->num)
 236                                 hash+= param->num;
 237                 break;
 238 
 239                 case EMPTY_PARAM: { /* do nothing */ } break;
 240 
 241                 default: {
 242                         /* not yet */
 243                 }
 244         }
 245 
 246         return hash;
 247 } /* }}} */
 248 
 249 PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_param_t *r) /* {{{ */
 250 {
 251         if (l && r) {
 252                 if (l->type == r->type) {
 253                         switch (l->type) {
 254                                 case STACK_PARAM:
 255                                         /* nope, or yep */
 256                                         return 1;
 257                                 break;
 258 
 259                                 case NUMERIC_FUNCTION_PARAM:
 260                                         if (l->num != r->num) {
 261                                                 break;
 262                                         }
 263                                 /* break intentionally omitted */
 264 
 265                                 case STR_PARAM:
 266                                         return (l->len == r->len) &&
 267                                                         (memcmp(l->str, r->str, l->len) == SUCCESS);
 268 
 269                                 case NUMERIC_PARAM:
 270                                         return (l->num == r->num);
 271 
 272                                 case ADDR_PARAM:
 273                                         return (l->addr == r->addr);
 274 
 275                                 case FILE_PARAM: {
 276                                         if (l->file.line == r->file.line) {
 277                                                 size_t lengths[2] = {
 278                                                         strlen(l->file.name), strlen(r->file.name)};
 279 
 280                                                 if (lengths[0] == lengths[1]) {
 281                                                         if ((!l->num && !r->num) || (l->num == r->num)) {
 282                                                                 return (memcmp(
 283                                                                         l->file.name, r->file.name, lengths[0]) == SUCCESS);
 284                                                         }
 285                                                 }
 286                                         }
 287                                 } break;
 288 
 289                                 case NUMERIC_METHOD_PARAM:
 290                                         if (l->num != r->num) {
 291                                                 break;
 292                                         }
 293                                 /* break intentionally omitted */
 294 
 295                                 case METHOD_PARAM: {
 296                                         size_t lengths[2] = {
 297                                                 strlen(l->method.class), strlen(r->method.class)};
 298                                         if (lengths[0] == lengths[1]) {
 299                                                 if (memcmp(l->method.class, r->method.class, lengths[0]) == SUCCESS) {
 300                                                         lengths[0] = strlen(l->method.name);
 301                                                         lengths[1] = strlen(r->method.name);
 302 
 303                                                         if (lengths[0] == lengths[1]) {
 304                                                                 return (memcmp(
 305                                                                         l->method.name, r->method.name, lengths[0]) == SUCCESS);
 306                                                         }
 307                                                 }
 308                                         }
 309                                 } break;
 310 
 311                                 case EMPTY_PARAM:
 312                                         return 1;
 313 
 314                                 default: {
 315                                         /* not yet */
 316                                 }
 317                         }
 318                 }
 319         }
 320         return 0;
 321 } /* }}} */
 322 
 323 /* {{{ */
 324 PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) {
 325         if (param && param->type) {
 326                 switch (param->type) {
 327                         case STR_PARAM:
 328                                 fprintf(stderr, "%s STR_PARAM(%s=%zu)\n", msg, param->str, param->len);
 329                         break;
 330 
 331                         case ADDR_PARAM:
 332                                 fprintf(stderr, "%s ADDR_PARAM(" ZEND_ULONG_FMT ")\n", msg, param->addr);
 333                         break;
 334 
 335                         case NUMERIC_FILE_PARAM:
 336                                 fprintf(stderr, "%s NUMERIC_FILE_PARAM(%s:#%lu)\n", msg, param->file.name, param->file.line);
 337                         break;
 338 
 339                         case FILE_PARAM:
 340                                 fprintf(stderr, "%s FILE_PARAM(%s:%lu)\n", msg, param->file.name, param->file.line);
 341                         break;
 342 
 343                         case METHOD_PARAM:
 344                                 fprintf(stderr, "%s METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name);
 345                         break;
 346 
 347                         case NUMERIC_METHOD_PARAM:
 348                                 fprintf(stderr, "%s NUMERIC_METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name);
 349                         break;
 350 
 351                         case NUMERIC_FUNCTION_PARAM:
 352                                 fprintf(stderr, "%s NUMERIC_FUNCTION_PARAM(%s::%ld)\n", msg, param->str, param->num);
 353                         break;
 354 
 355                         case NUMERIC_PARAM:
 356                                 fprintf(stderr, "%s NUMERIC_PARAM(%ld)\n", msg, param->num);
 357                         break;
 358 
 359                         case COND_PARAM:
 360                                 fprintf(stderr, "%s COND_PARAM(%s=%zu)\n", msg, param->str, param->len);
 361                         break;
 362 
 363                         case OP_PARAM:
 364                                 fprintf(stderr, "%s OP_PARAM(%s=%zu)\n", msg, param->str, param->len);
 365                         break;
 366 
 367                         default: {
 368                                 /* not yet */
 369                         }
 370                 }
 371         }
 372 } /* }}} */
 373 
 374 /* {{{ */
 375 PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) {
 376         if (stack && stack->next) {
 377                 phpdbg_param_t *remove = stack->next;
 378 
 379                 while (remove) {
 380                         phpdbg_param_t *next = NULL;
 381 
 382                         if (remove->next)
 383                                 next = remove->next;
 384 
 385                         switch (remove->type) {
 386                                 case NUMERIC_METHOD_PARAM:
 387                                 case METHOD_PARAM:
 388                                         if (remove->method.class) {
 389                                                 efree(remove->method.class);
 390                                         }
 391                                         if (remove->method.name) {
 392                                                 efree(remove->method.name);
 393                                         }
 394                                 break;
 395 
 396                                 case NUMERIC_FUNCTION_PARAM:
 397                                 case STR_PARAM:
 398                                 case OP_PARAM:
 399                                 case EVAL_PARAM:
 400                                 case SHELL_PARAM:
 401                                 case COND_PARAM:
 402                                 case RUN_PARAM:
 403                                         if (remove->str) {
 404                                                 efree(remove->str);
 405                                         }
 406                                 break;
 407 
 408                                 case NUMERIC_FILE_PARAM:
 409                                 case FILE_PARAM:
 410                                         if (remove->file.name) {
 411                                                 efree(remove->file.name);
 412                                         }
 413                                 break;
 414 
 415                                 default: {
 416                                         /* nothing */
 417                                 }
 418                         }
 419 
 420                         free(remove);
 421                         remove = NULL;
 422 
 423                         if (next)
 424                                 remove = next;
 425                         else break;
 426                 }
 427         }
 428 
 429 
 430         stack->next = NULL;
 431 } /* }}} */
 432 
 433 /* {{{ */
 434 PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param) {
 435         phpdbg_param_t *next = calloc(1, sizeof(phpdbg_param_t));
 436 
 437         if (!next) {
 438                 return;
 439         }
 440 
 441         *(next) = *(param);
 442 
 443         next->next = NULL;
 444 
 445         if (stack->top == NULL) {
 446                 stack->top = next;
 447                 next->top = NULL;
 448                 stack->next = next;
 449         } else {
 450                 stack->top->next = next;
 451                 next->top = stack->top;
 452                 stack->top = next;
 453         }
 454 
 455         stack->len++;
 456 } /* }}} */
 457 
 458 /* {{{ */
 459 PHPDBG_API void phpdbg_stack_separate(phpdbg_param_t *param) {
 460         phpdbg_param_t *stack = calloc(1, sizeof(phpdbg_param_t));
 461 
 462         stack->type = STACK_PARAM;
 463         stack->next = param->next;
 464         param->next = stack;
 465         stack->top = param->top;
 466 } /* }}} */
 467 
 468 PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack) {
 469         if (command) {
 470                 char buffer[128] = {0,};
 471                 const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL;
 472                 const char *arg = command->args;
 473                 size_t least = 0L,
 474                        received = 0L,
 475                        current = 0L;
 476                 zend_bool optional = 0;
 477 
 478                 /* check for arg spec */
 479                 if (!(arg) || !(*arg)) {
 480                         if (!top || top->type == STACK_PARAM) {
 481                                 return SUCCESS;
 482                         }
 483 
 484                         phpdbg_error("command", "type=\"toomanyargs\" command=\"%s\" expected=\"0\"", "The command \"%s\" expected no arguments",
 485                                 phpdbg_command_name(command, buffer));
 486                         return FAILURE;
 487                 }
 488 
 489                 least = 0L;
 490 
 491                 /* count least amount of arguments */
 492                 while (arg && *arg) {
 493                         if (arg[0] == '|') {
 494                                 break;
 495                         }
 496                         least++;
 497                         arg++;
 498                 }
 499 
 500                 arg = command->args;
 501 
 502 #define verify_arg(e, a, t) if (!(a)) { \
 503         if (!optional) { \
 504                 phpdbg_error("command", "type=\"noarg\" command=\"%s\" expected=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got nothing at parameter %lu", \
 505                         phpdbg_command_name(command, buffer), \
 506                         (e), \
 507                         current); \
 508                 return FAILURE;\
 509         } \
 510 } else if ((a)->type != (t)) { \
 511         phpdbg_error("command", "type=\"wrongarg\" command=\"%s\" expected=\"%s\" got=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got %s at parameter %lu", \
 512                 phpdbg_command_name(command, buffer), \
 513                 (e),\
 514                 phpdbg_get_param_type((a)), \
 515                 current); \
 516         return FAILURE; \
 517 }
 518 
 519                 while (arg && *arg) {
 520                         if (top && top->type == STACK_PARAM) {
 521                                 break;
 522                         }
 523 
 524                         current++;
 525 
 526                         switch (*arg) {
 527                                 case '|': {
 528                                         current--;
 529                                         optional = 1;
 530                                         arg++;
 531                                 } continue;
 532 
 533                                 case 'i': verify_arg("raw input", top, STR_PARAM); break;
 534                                 case 's': verify_arg("string", top, STR_PARAM); break;
 535                                 case 'n': verify_arg("number", top, NUMERIC_PARAM); break;
 536                                 case 'm': verify_arg("method", top, METHOD_PARAM); break;
 537                                 case 'a': verify_arg("address", top, ADDR_PARAM); break;
 538                                 case 'f': verify_arg("file:line", top, FILE_PARAM); break;
 539                                 case 'c': verify_arg("condition", top, COND_PARAM); break;
 540                                 case 'o': verify_arg("opcode", top, OP_PARAM); break;
 541                                 case 'b': verify_arg("boolean", top, NUMERIC_PARAM); break;
 542 
 543                                 case '*': { /* do nothing */ } break;
 544                         }
 545 
 546                         if (top) {
 547                                 top = top->next;
 548                         } else {
 549                                 break;
 550                         }
 551 
 552                         received++;
 553                         arg++;
 554                 }
 555 
 556 #undef verify_arg
 557 
 558                 if ((received < least)) {
 559                         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",
 560                                 phpdbg_command_name(command, buffer),
 561                                 least,
 562                                 command->args,
 563                                 received);
 564                         return FAILURE;
 565                 }
 566         }
 567 
 568         return SUCCESS;
 569 }
 570 
 571 /* {{{ */
 572 PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top) {
 573         const phpdbg_command_t *command = commands;
 574         phpdbg_param_t *name = *top;
 575         const phpdbg_command_t *matched[3] = {NULL, NULL, NULL};
 576         ulong matches = 0L;
 577 
 578         while (command && command->name && command->handler) {
 579                 if (name->len == 1 || command->name_len >= name->len) {
 580                         /* match single letter alias */
 581                         if (command->alias && (name->len == 1)) {
 582                                 if (command->alias == (*name->str)) {
 583                                         matched[matches] = command;
 584                                         matches++;
 585                                 }
 586                         } else {
 587                                 /* match full, case insensitive, command name */
 588                                 if (strncasecmp(command->name, name->str, name->len) == SUCCESS) {
 589                                         if (matches < 3) {
 590                                                 /* only allow abbreviating commands that can be aliased */
 591                                                 if ((name->len != command->name_len && command->alias) || name->len == command->name_len) {
 592                                                         matched[matches] = command;
 593                                                         matches++;
 594                                                 }
 595 
 596                                                 /* exact match */
 597                                                 if (name->len == command->name_len) {
 598                                                         break;
 599                                                 }
 600                                         } else {
 601                                                 break;
 602                                         }
 603                                 }
 604                         }
 605                 }
 606 
 607                 command++;
 608         }
 609 
 610         switch (matches) {
 611                 case 0:
 612                         if (parent) {
 613                                 phpdbg_error("command", "type=\"notfound\" command=\"%s\" subcommand=\"%s\"", "The command \"%s %s\" could not be found", parent->name, name->str);
 614                         } else {
 615                                 phpdbg_error("command", "type=\"notfound\" command=\"%s\"", "The command \"%s\" could not be found", name->str);
 616                         }
 617                         return parent;
 618 
 619                 case 1:
 620                         (*top) = (*top)->next;
 621 
 622                         command = matched[0];
 623                         break;
 624 
 625                 default: {
 626                         char *list = NULL;
 627                         uint32_t it = 0;
 628                         size_t pos = 0;
 629 
 630                         while (it < matches) {
 631                                 if (!list) {
 632                                         list = emalloc(matched[it]->name_len + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0));
 633                                 } else {
 634                                         list = erealloc(list, (pos + matched[it]->name_len) + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0));
 635                                 }
 636                                 memcpy(&list[pos], matched[it]->name, matched[it]->name_len);
 637                                 pos += matched[it]->name_len;
 638                                 if ((it + 1) < matches) {
 639                                         memcpy(&list[pos], ", ", sizeof(", ") - 1);
 640                                         pos += (sizeof(", ") - 1);
 641                                 }
 642 
 643                                 list[pos] = 0;
 644                                 it++;
 645                         }
 646 
 647                         /* ", " separated matches */
 648                         phpdbg_error("command", "type=\"ambiguous\" command=\"%s\" matches=\"%lu\" matched=\"%s\"", "The command \"%s\" is ambigious, matching %lu commands (%s)", name->str, matches, list);
 649                         efree(list);
 650 
 651                         return NULL;
 652                 }
 653         }
 654 
 655         if (command->subs && (*top) && ((*top)->type == STR_PARAM)) {
 656                 return phpdbg_stack_resolve(command->subs, command, top);
 657         } else {
 658                 return command;
 659         }
 660 
 661         return NULL;
 662 } /* }}} */
 663 
 664 static int phpdbg_internal_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe) {
 665         const phpdbg_command_t *handler = NULL;
 666         phpdbg_param_t *top = (phpdbg_param_t *) stack->next;
 667 
 668         switch (top->type) {
 669                 case EVAL_PARAM:
 670                         phpdbg_activate_err_buf(0);
 671                         phpdbg_free_err_buf();
 672                         return PHPDBG_COMMAND_HANDLER(ev)(top);
 673 
 674                 case RUN_PARAM:
 675                         if (!allow_async_unsafe) {
 676                                 phpdbg_error("signalsegv", "command=\"run\"", "run command is disallowed during hard interrupt");
 677                         }
 678                         phpdbg_activate_err_buf(0);
 679                         phpdbg_free_err_buf();
 680                         return PHPDBG_COMMAND_HANDLER(run)(top);
 681 
 682                 case SHELL_PARAM:
 683                         if (!allow_async_unsafe) {
 684                                 phpdbg_error("signalsegv", "command=\"sh\"", "sh command is disallowed during hard interrupt");
 685                                 return FAILURE;
 686                         }
 687                         phpdbg_activate_err_buf(0);
 688                         phpdbg_free_err_buf();
 689                         return PHPDBG_COMMAND_HANDLER(sh)(top);
 690 
 691                 case STR_PARAM: {
 692                         handler = phpdbg_stack_resolve(phpdbg_prompt_commands, NULL, &top);
 693 
 694                         if (handler) {
 695                                 if (!allow_async_unsafe && !(handler->flags & PHPDBG_ASYNC_SAFE)) {
 696                                         phpdbg_error("signalsegv", "command=\"%s\"", "%s command is disallowed during hard interrupt", handler->name);
 697                                         return FAILURE;
 698                                 }
 699 
 700                                 if (phpdbg_stack_verify(handler, &top) == SUCCESS) {
 701                                         phpdbg_activate_err_buf(0);
 702                                         phpdbg_free_err_buf();
 703                                         return handler->handler(top);
 704                                 }
 705                         }
 706                 } return FAILURE;
 707 
 708                 default:
 709                         phpdbg_error("command", "type=\"invalidcommand\"", "The first parameter makes no sense !");
 710                         return FAILURE;
 711         }
 712 
 713         return SUCCESS;
 714 } /* }}} */
 715 
 716 /* {{{ */
 717 PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe) {
 718         phpdbg_param_t *top = stack;
 719 
 720         if (stack->type != STACK_PARAM) {
 721                 phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !");
 722                 return FAILURE;
 723         }
 724 
 725         if (!stack->len) {
 726                 phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !");
 727                 return FAILURE;
 728         }
 729 
 730         do {
 731                 if (top->type == STACK_PARAM) {
 732                         int result;
 733                         if ((result = phpdbg_internal_stack_execute(top, allow_async_unsafe)) != SUCCESS) {
 734                                 return result;
 735                         }
 736                 }
 737         } while ((top = top->next));
 738 
 739         return SUCCESS;
 740 } /* }}} */
 741 
 742 PHPDBG_API char *phpdbg_read_input(char *buffered) /* {{{ */
 743 {
 744         char buf[PHPDBG_MAX_CMD];
 745         char *cmd = NULL;
 746         char *buffer = NULL;
 747 
 748         if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) != PHPDBG_IS_STOPPING) {
 749                 if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem()) {
 750                         fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
 751                 }
 752 
 753                 if (buffered == NULL) {
 754 #define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT))
 755                         /* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */
 756 #if USE_LIB_STAR
 757                         if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) || !isatty(PHPDBG_G(io)[PHPDBG_STDIN].fd))
 758 #endif
 759                         {
 760                                 phpdbg_write("prompt", "", "%s", phpdbg_get_prompt());
 761                                 phpdbg_consume_stdin_line(cmd = buf);
 762                         }
 763 #if USE_LIB_STAR
 764                         else {
 765                                 cmd = readline(phpdbg_get_prompt());
 766                                 PHPDBG_G(last_was_newline) = 1;
 767 
 768                                 if (!cmd) {
 769                                         PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED;
 770                                         zend_bailout();
 771                                 }
 772 
 773                                 add_history(cmd);
 774                         }
 775 #endif
 776                 } else {
 777                         cmd = buffered;
 778                 }
 779 
 780                 buffer = estrdup(cmd);
 781 
 782 #if USE_LIB_STAR
 783                 if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && isatty(PHPDBG_G(io)[PHPDBG_STDIN].fd)) {
 784                         free(cmd);
 785                 }
 786 #endif
 787         }
 788 
 789         if (buffer && isspace(*buffer)) {
 790                 char *trimmed = buffer;
 791                 while (isspace(*trimmed))
 792                         trimmed++;
 793 
 794                 trimmed = estrdup(trimmed);
 795                 efree(buffer);
 796                 buffer = trimmed;
 797         }
 798 
 799         if (buffer && strlen(buffer)) {
 800                 if (PHPDBG_G(buffer)) {
 801                         free(PHPDBG_G(buffer));
 802                 }
 803                 PHPDBG_G(buffer) = strdup(buffer);
 804         } else if (PHPDBG_G(buffer)) {
 805                 if (buffer) {
 806                         efree(buffer);
 807                 }
 808                 buffer = estrdup(PHPDBG_G(buffer));
 809         }
 810 
 811         return buffer;
 812 } /* }}} */
 813 
 814 PHPDBG_API void phpdbg_destroy_input(char **input) /*{{{ */
 815 {
 816         efree(*input);
 817 } /* }}} */
 818 
 819 PHPDBG_API int phpdbg_ask_user_permission(const char *question) {
 820         if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
 821                 char buf[PHPDBG_MAX_CMD];
 822                 phpdbg_out("%s", question);
 823                 phpdbg_out(" (type y or n): ");
 824 
 825                 while (1) {
 826                         phpdbg_consume_stdin_line(buf);
 827                         if (buf[1] == '\n' && (buf[0] == 'y' || buf[0] == 'n')) {
 828                                 if (buf[0] == 'y') {
 829                                         return SUCCESS;
 830                                 }
 831                                 return FAILURE;
 832                         }
 833                         phpdbg_out("Please enter either y (yes) or n (no): ");
 834                 }
 835         }
 836 
 837         return SUCCESS;
 838 }

/* [<][>][^][v][top][bottom][index][help] */