diff options
author | Ondřej Surý <ondrej@sury.org> | 2014-05-05 11:21:23 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2014-05-05 11:21:23 +0200 |
commit | 4bbffbee21093458feadd96f93b96d4627461cff (patch) | |
tree | d316b17d64aede352ae0a336c23238b8756004e6 /sapi/phpdbg/phpdbg_prompt.c | |
parent | 9566c3fcaf4cfaa866ea395ee5d1a480785fef0d (diff) | |
download | php-4bbffbee21093458feadd96f93b96d4627461cff.tar.gz |
New upstream version 5.6.0~beta2+dfsgupstream/5.6.0_beta2+dfsg
Diffstat (limited to 'sapi/phpdbg/phpdbg_prompt.c')
-rw-r--r-- | sapi/phpdbg/phpdbg_prompt.c | 883 |
1 files changed, 453 insertions, 430 deletions
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index f586bb5a8..7a28a7512 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -35,99 +35,154 @@ #include "phpdbg_cmd.h" #include "phpdbg_set.h" #include "phpdbg_frame.h" +#include "phpdbg_lexer.h" +#include "phpdbg_parser.h" + +int yyparse(phpdbg_param_t *stack, yyscan_t scanner); /* {{{ command declarations */ const phpdbg_command_t phpdbg_prompt_commands[] = { - PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, 1), - PHPDBG_COMMAND_D(compile, "attempt compilation", 'c', NULL, 0), - PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 1), - PHPDBG_COMMAND_D(next, "continue execution", 'n', NULL, 0), - PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0), - PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, 1), + PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s"), + PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0), + PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0), + PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s"), + PHPDBG_COMMAND_D(ev, "evaluate some code", 0, NULL, "i"), PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0), PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0), PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0), - PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 2), - PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1), - PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0), - PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, 1), - PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, 2), - PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, 1), + PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 0), + PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c"), + PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n"), + PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n"), + PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*"), + PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s"), PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0), PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0), - PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, 2), - PHPDBG_COMMAND_D(quiet, "silence some output", 'Q', NULL, 1), - PHPDBG_COMMAND_D(aliases, "show alias list", 'a', NULL, 0), - PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, 1), - PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, 1), - PHPDBG_COMMAND_D(source, "execute a phpdbginit", '.', NULL, 1), - PHPDBG_COMMAND_D(shell, "shell a command", '-', NULL, 1), + PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s"), + PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s"), + PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s"), + PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s"), + PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s"), + PHPDBG_COMMAND_D(sh, "shell a command", 0, NULL, "i"), PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0), + PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss"), PHPDBG_END_COMMAND }; /* }}} */ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -static inline int phpdbg_call_register(phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ */ { - phpdbg_input_t *function = input->argv[0]; - - if (zend_hash_exists( - &PHPDBG_G(registered), function->string, function->length+1)) { - - zval fname, *fretval; - zend_fcall_info fci; - - ZVAL_STRINGL(&fname, function->string, function->length, 1); - - memset(&fci, 0, sizeof(zend_fcall_info)); - - fci.size = sizeof(zend_fcall_info); - fci.function_table = &PHPDBG_G(registered); - fci.function_name = &fname; - fci.symbol_table = EG(active_symbol_table); - fci.object_ptr = NULL; - fci.retval_ptr_ptr = &fretval; - fci.no_separation = 1; - - if (input->argc > 1) { - int param; - zval params; - - array_init(¶ms); + phpdbg_param_t *name = NULL; - for (param = 0; param < (input->argc-1); param++) { - add_next_index_stringl( - ¶ms, - input->argv[param+1]->string, - input->argv[param+1]->length, 1); + if (stack->type == STACK_PARAM) { + name = stack->next; + + if (!name || name->type != STR_PARAM) { + return FAILURE; + } + + if (zend_hash_exists( + &PHPDBG_G(registered), name->str, name->len+1)) { + + zval fname, *fretval; + zend_fcall_info fci; + + ZVAL_STRINGL(&fname, name->str, name->len, 1); + + memset(&fci, 0, sizeof(zend_fcall_info)); + + fci.size = sizeof(zend_fcall_info); + fci.function_table = &PHPDBG_G(registered); + fci.function_name = &fname; + fci.symbol_table = EG(active_symbol_table); + fci.object_ptr = NULL; + fci.retval_ptr_ptr = &fretval; + fci.no_separation = 1; + + if (name->next) { + zval params; + phpdbg_param_t *next = name->next; + + array_init(¶ms); + + while (next) { + char *buffered = NULL; + + switch (next->type) { + case OP_PARAM: + case COND_PARAM: + case STR_PARAM: + add_next_index_stringl( + ¶ms, + next->str, + next->len, 1); + break; + + case NUMERIC_PARAM: + add_next_index_long(¶ms, next->num); + break; + + case METHOD_PARAM: + spprintf(&buffered, 0, "%s::%s", + next->method.class, next->method.name); + add_next_index_string(¶ms, buffered, 0); + break; + + case NUMERIC_METHOD_PARAM: + spprintf(&buffered, 0, "%s::%s#%ld", + next->method.class, next->method.name, next->num); + add_next_index_string(¶ms, buffered, 0); + break; + + case NUMERIC_FUNCTION_PARAM: + spprintf(&buffered, 0, "%s#%ld", + next->str, next->num); + add_next_index_string(¶ms, buffered, 0); + break; + + case FILE_PARAM: + spprintf(&buffered, 0, "%s:%ld", + next->file.name, next->file.line); + add_next_index_string(¶ms, buffered, 0); + break; + + case NUMERIC_FILE_PARAM: + spprintf(&buffered, 0, "%s:#%ld", + next->file.name, next->file.line); + add_next_index_string(¶ms, buffered, 0); + break; + + default: { + /* not yet */ + } + } + + next = next->next; + } - phpdbg_debug( - "created param[%d] from argv[%d]: %s", - param, param+1, input->argv[param+1]->string); + zend_fcall_info_args(&fci, ¶ms TSRMLS_CC); + } else { + fci.params = NULL; + fci.param_count = 0; } - zend_fcall_info_args(&fci, ¶ms TSRMLS_CC); - } else { - fci.params = NULL; - fci.param_count = 0; - } - - phpdbg_debug( - "created %d params from %d arguments", - fci.param_count, input->argc); + phpdbg_debug( + "created %d params from arguments", + fci.param_count); - zend_call_function(&fci, NULL TSRMLS_CC); + zend_call_function(&fci, NULL TSRMLS_CC); - if (fretval) { - zend_print_zval_r( - fretval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); - } + if (fretval) { + zend_print_zval_r( + fretval, 0 TSRMLS_CC); + phpdbg_writeln(EMPTY); + } - zval_dtor(&fname); + zval_dtor(&fname); - return SUCCESS; + return SUCCESS; + } } return FAILURE; @@ -136,7 +191,7 @@ static inline int phpdbg_call_register(phpdbg_input_t *input TSRMLS_DC) /* {{{ * void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */ { struct stat sb; - + if (init_file && VCWD_STAT(init_file, &sb) != -1) { FILE *fp = fopen(init_file, "r"); if (fp) { @@ -190,19 +245,47 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ } { - phpdbg_input_t *input = phpdbg_read_input(cmd TSRMLS_CC); - switch (phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) { - case FAILURE: - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) { - phpdbg_error("Unrecognized command in %s:%d: %s!", init_file, line, input->string); - } - } + char *why = NULL; + char *input = phpdbg_read_input(cmd TSRMLS_CC); + phpdbg_param_t stack; + yyscan_t scanner; + YY_BUFFER_STATE state; + + phpdbg_init_param(&stack, STACK_PARAM); + + if (yylex_init(&scanner)) { + phpdbg_error( + "could not initialize scanner"); break; } + + state = yy_scan_string(input, scanner); + + if (yyparse(&stack, scanner) <= 0) { + switch (phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + case FAILURE: +// if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + phpdbg_error( + "Unrecognized command in %s:%d: %s, %s!", + init_file, line, input, why); + } +// } + break; + } + } + + if (why) { + free(why); + why = NULL; + } + + yy_delete_buffer(state, scanner); + yylex_destroy(scanner); + + phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); } - } next_line: line++; @@ -264,47 +347,47 @@ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TS PHPDBG_COMMAND(exec) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - struct stat sb; - - if (VCWD_STAT(param->str, &sb) != FAILURE) { - if (sb.st_mode & (S_IFREG|S_IFLNK)) { - char *res = phpdbg_resolve_path(param->str TSRMLS_CC); - size_t res_len = strlen(res); - - if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { - - if (PHPDBG_G(exec)) { - phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec)); - efree(PHPDBG_G(exec)); - PHPDBG_G(exec) = NULL; - PHPDBG_G(exec_len) = 0L; - } + struct stat sb; - if (PHPDBG_G(ops)) { - phpdbg_notice("Destroying compiled opcodes"); - phpdbg_clean(0 TSRMLS_CC); - } + if (VCWD_STAT(param->str, &sb) != FAILURE) { + if (sb.st_mode & (S_IFREG|S_IFLNK)) { + char *res = phpdbg_resolve_path(param->str TSRMLS_CC); + size_t res_len = strlen(res); - PHPDBG_G(exec) = res; - PHPDBG_G(exec_len) = res_len; + if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { - phpdbg_notice("Set execution context: %s", PHPDBG_G(exec)); - } else { - phpdbg_notice("Execution context not changed"); - } - } else { - phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str); + if (PHPDBG_G(exec)) { + phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec)); + efree(PHPDBG_G(exec)); + PHPDBG_G(exec) = NULL; + PHPDBG_G(exec_len) = 0L; + } + + if (PHPDBG_G(ops)) { + phpdbg_notice("Destroying compiled opcodes"); + phpdbg_clean(0 TSRMLS_CC); + } + + PHPDBG_G(exec) = res; + PHPDBG_G(exec_len) = res_len; + + *SG(request_info).argv = PHPDBG_G(exec); + php_hash_environment(TSRMLS_C); + + phpdbg_notice("Set execution context: %s", PHPDBG_G(exec)); + + if (phpdbg_compile(TSRMLS_C) == FAILURE) { + phpdbg_error("Failed to compile %s", PHPDBG_G(exec)); } } else { - phpdbg_error("Cannot stat %s, ensure the file exists", param->str); + phpdbg_notice("Execution context not changed"); } - } break; - - phpdbg_default_switch_case(); + } else { + phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str); + } + } else { + phpdbg_error("Cannot stat %s, ensure the file exists", param->str); } - return SUCCESS; } /* }}} */ @@ -312,6 +395,11 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ { zend_file_handle fh; + if (!PHPDBG_G(exec)) { + phpdbg_error("No execution context"); + return SUCCESS; + } + if (EG(in_execution)) { phpdbg_error("Cannot compile while in execution"); return FAILURE; @@ -334,47 +422,16 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ return FAILURE; } /* }}} */ -PHPDBG_COMMAND(compile) /* {{{ */ -{ - if (!PHPDBG_G(exec)) { - phpdbg_error("No execution context"); - return SUCCESS; - } - - if (!EG(in_execution)) { - if (PHPDBG_G(ops)) { - phpdbg_error("Destroying previously compiled opcodes"); - phpdbg_clean(0 TSRMLS_CC); - } - } - - phpdbg_compile(TSRMLS_C); - - return SUCCESS; -} /* }}} */ - PHPDBG_COMMAND(step) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: - case NUMERIC_PARAM: { - if (param->type == NUMERIC_PARAM && param->num) { - PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; - } else { - PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; - } - - phpdbg_notice("Stepping %s", - (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); - } break; - - phpdbg_default_switch_case(); + if (EG(in_execution)) { + PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } - return SUCCESS; + return PHPDBG_NEXT; } /* }}} */ -PHPDBG_COMMAND(next) /* {{{ */ +PHPDBG_COMMAND(continue) /* {{{ */ { return PHPDBG_NEXT; } /* }}} */ @@ -475,17 +532,9 @@ PHPDBG_COMMAND(leave) /* {{{ */ PHPDBG_COMMAND(frame) /* {{{ */ { - switch (param->type) { - case NUMERIC_PARAM: - phpdbg_switch_frame(param->num TSRMLS_CC); - break; - - case EMPTY_PARAM: - phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num); - break; - - phpdbg_default_switch_case(); - } + if (!param) { + phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num); + } else phpdbg_switch_frame(param->num TSRMLS_CC); return SUCCESS; } /* }}} */ @@ -580,6 +629,31 @@ PHPDBG_COMMAND(run) /* {{{ */ /* reset hit counters */ phpdbg_reset_breakpoints(TSRMLS_C); + if (param && param->type != EMPTY_PARAM && param->len != 0) { + char **argv = emalloc(5 * sizeof(char *)); + int argc = 0; + int i; + char *argv_str = strtok(param->str, " "); + + while (argv_str) { + if (argc >= 4 && argc == (argc & -argc)) { + argv = erealloc(argv, (argc * 2 + 1) * sizeof(char *)); + } + argv[++argc] = argv_str; + argv_str = strtok(0, " "); + argv[argc] = estrdup(argv[argc]); + } + argv[0] = SG(request_info).argv[0]; + for (i = SG(request_info).argc; --i;) { + efree(SG(request_info).argv[i]); + } + efree(SG(request_info).argv); + SG(request_info).argv = erealloc(argv, ++argc * sizeof(char *)); + SG(request_info).argc = argc; + + php_hash_environment(TSRMLS_C); + } + zend_try { php_output_activate(TSRMLS_C); PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; @@ -615,42 +689,36 @@ out: return SUCCESS; } /* }}} */ -PHPDBG_COMMAND(eval) /* {{{ */ +PHPDBG_COMMAND(ev) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING); - zval retval; - - if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { - PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING; - } - - /* disable stepping while eval() in progress */ - PHPDBG_G(flags) |= PHPDBG_IN_EVAL; - zend_try { - if (zend_eval_stringl(param->str, param->len, - &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { - zend_print_zval_r( - &retval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); - zval_dtor(&retval); - } - } zend_end_try(); - PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; + zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING); + zval retval; - /* switch stepping back on */ - if (stepping && - !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { - PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; - } + if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING; + } - CG(unclean_shutdown) = 0; - } break; + /* disable stepping while eval() in progress */ + PHPDBG_G(flags) |= PHPDBG_IN_EVAL; + zend_try { + if (zend_eval_stringl(param->str, param->len, + &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { + zend_print_zval_r( + &retval, 0 TSRMLS_CC); + phpdbg_writeln(EMPTY); + zval_dtor(&retval); + } + } zend_end_try(); + PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; - phpdbg_default_switch_case(); + /* switch stepping back on */ + if (stepping && + !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } + CG(unclean_shutdown) = 0; + return SUCCESS; } /* }}} */ @@ -661,14 +729,10 @@ PHPDBG_COMMAND(back) /* {{{ */ return SUCCESS; } - switch (param->type) { - case EMPTY_PARAM: - case NUMERIC_PARAM: - phpdbg_dump_backtrace( - (param->type == NUMERIC_PARAM) ? param->num : 0 TSRMLS_CC); - break; - - phpdbg_default_switch_case(); + if (!param) { + phpdbg_dump_backtrace(0 TSRMLS_CC); + } else { + phpdbg_dump_backtrace(param->num TSRMLS_CC); } return SUCCESS; @@ -676,47 +740,41 @@ PHPDBG_COMMAND(back) /* {{{ */ PHPDBG_COMMAND(print) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: { - phpdbg_writeln(SEPARATE); - phpdbg_notice("Execution Context Information"); + phpdbg_writeln(SEPARATE); + phpdbg_notice("Execution Context Information"); #ifdef HAVE_LIBREADLINE - phpdbg_writeln("Readline\tyes"); + phpdbg_writeln("Readline\tyes"); #else - phpdbg_writeln("Readline\tno"); + phpdbg_writeln("Readline\tno"); #endif - phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); - phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); - phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); - phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); - phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off"); + phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); + phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); + phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); + phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); + phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off"); - if (PHPDBG_G(ops)) { - phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last); - - if (PHPDBG_G(ops)->last_var) { - phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1); - } else { - phpdbg_writeln("Variables\tNone"); - } - } + if (PHPDBG_G(ops)) { + phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last); - phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no"); - if (EG(in_execution)) { - phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret)); - } + if (PHPDBG_G(ops)->last_var) { + phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1); + } else { + phpdbg_writeln("Variables\tNone"); + } + } - phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files))); + phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no"); + if (EG(in_execution)) { + phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret)); + } - phpdbg_writeln(SEPARATE); - } break; + phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files))); - phpdbg_default_switch_case(); - } + phpdbg_writeln(SEPARATE); return SUCCESS; } /* }}} */ @@ -732,19 +790,18 @@ PHPDBG_COMMAND(info) /* {{{ */ PHPDBG_COMMAND(set) /* {{{ */ { phpdbg_error( - "No information command selected!"); + "No set command selected!"); return SUCCESS; } /* }}} */ PHPDBG_COMMAND(break) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: - phpdbg_set_breakpoint_file( + if (!param) { + phpdbg_set_breakpoint_file( zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); - break; + } else switch (param->type) { case ADDR_PARAM: phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC); break; @@ -767,9 +824,18 @@ PHPDBG_COMMAND(break) /* {{{ */ case FILE_PARAM: phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC); break; + case NUMERIC_FILE_PARAM: + phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line TSRMLS_CC); + break; + case COND_PARAM: + phpdbg_set_breakpoint_expression(param->str, param->len TSRMLS_CC); + break; case STR_PARAM: phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC); break; + case OP_PARAM: + phpdbg_set_breakpoint_opcode(param->str, param->len TSRMLS_CC); + break; phpdbg_default_switch_case(); } @@ -777,83 +843,72 @@ PHPDBG_COMMAND(break) /* {{{ */ return SUCCESS; } /* }}} */ -PHPDBG_COMMAND(shell) /* {{{ */ +PHPDBG_COMMAND(sh) /* {{{ */ { - /* don't allow this to loop, ever ... */ - switch (param->type) { - case STR_PARAM: { - FILE *fd = NULL; - if ((fd=VCWD_POPEN((char*)param->str, "w"))) { - /* do something perhaps ?? do we want input ?? */ - fclose(fd); - } else { - phpdbg_error( - "Failed to execute %s", param->str); - } - } break; - - phpdbg_default_switch_case(); + FILE *fd = NULL; + if ((fd=VCWD_POPEN((char*)param->str, "w"))) { + /* do something perhaps ?? do we want input ?? */ + fclose(fd); + } else { + phpdbg_error( + "Failed to execute %s", param->str); } + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(source) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - if (input->argc > 2) { - if (phpdbg_argv_is(1, "export")) { - FILE *h = VCWD_FOPEN(input->argv[2]->string, "w+"); - if (h) { - phpdbg_export_breakpoints(h TSRMLS_CC); - fclose(h); - } else phpdbg_error("Failed to open %s", input->argv[1]->string); - } else { - phpdbg_error( - "Incorrect usage of source command, see help"); - } - } else { - struct stat sb; - if (VCWD_STAT(param->str, &sb) != -1) { - phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC); - } else phpdbg_error("Cannot stat %s", param->str); - } - } break; + struct stat sb; + + if (VCWD_STAT(param->str, &sb) != -1) { + phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC); + } else { + phpdbg_error( + "Failed to stat %s, file does not exist", param->str); + } + + return SUCCESS; +} /* }}} */ - phpdbg_default_switch_case(); +PHPDBG_COMMAND(export) /* {{{ */ +{ + FILE *handle = VCWD_FOPEN(param->str, "w+"); + + if (handle) { + phpdbg_export_breakpoints(handle TSRMLS_CC); + fclose(handle); + } else { + phpdbg_error( + "Failed to open or create %s, check path and permissions", param->str); } + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(register) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - zend_function *function; - char *lcname = zend_str_tolower_dup(param->str, param->len); - size_t lcname_len = strlen(lcname); - - if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) { - if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) { - zend_hash_update( - &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); - function_add_ref(function); - - phpdbg_notice( - "Registered %s", lcname); - } else { - phpdbg_error("The requested function (%s) could not be found", param->str); - } - } else { - phpdbg_error( - "The requested name (%s) is already in use", lcname); - } - - efree(lcname); - } break; - - phpdbg_default_switch_case(); + zend_function *function; + char *lcname = zend_str_tolower_dup(param->str, param->len); + size_t lcname_len = strlen(lcname); + + if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) { + if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) { + zend_hash_update( + &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); + function_add_ref(function); + + phpdbg_notice( + "Registered %s", lcname); + } else { + phpdbg_error("The requested function (%s) could not be found", param->str); + } + } else { + phpdbg_error( + "The requested name (%s) is already in use", lcname); } + + efree(lcname); return SUCCESS; } /* }}} */ @@ -861,14 +916,11 @@ PHPDBG_COMMAND(quit) /* {{{ */ { /* don't allow this to loop, ever ... */ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - - phpdbg_destroy_input((phpdbg_input_t**)&input TSRMLS_CC); - PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; zend_bailout(); } - return SUCCESS; + return PHPDBG_NEXT; } /* }}} */ PHPDBG_COMMAND(clean) /* {{{ */ @@ -908,100 +960,12 @@ PHPDBG_COMMAND(clear) /* {{{ */ return SUCCESS; } /* }}} */ -PHPDBG_COMMAND(aliases) /* {{{ */ -{ - const phpdbg_command_t *prompt_command = phpdbg_prompt_commands; - - phpdbg_help_header(); - phpdbg_writeln("Below are the aliased, short versions of all supported commands"); - while (prompt_command && prompt_command->name) { - if (prompt_command->alias) { - if (prompt_command->subs) { - const phpdbg_command_t *sub_command = prompt_command->subs; - phpdbg_writeln(EMPTY); - phpdbg_writeln(" %c -> %9s", prompt_command->alias, prompt_command->name); - while (sub_command && sub_command->name) { - if (sub_command->alias) { - phpdbg_writeln(" |-------- %c -> %15s\t%s", sub_command->alias, - sub_command->name, sub_command->tip); - } - ++sub_command; - } - phpdbg_writeln(EMPTY); - } else { - phpdbg_writeln(" %c -> %9s\t\t\t%s", prompt_command->alias, - prompt_command->name, prompt_command->tip); - } - } - - ++prompt_command; - } - phpdbg_help_footer(); - - return SUCCESS; -} /* }}} */ - -PHPDBG_COMMAND(help) /* {{{ */ -{ - switch (param->type) { - case EMPTY_PARAM: { - const phpdbg_command_t *prompt_command = phpdbg_prompt_commands; - const phpdbg_command_t *help_command = phpdbg_help_commands; - - phpdbg_help_header(); - phpdbg_writeln("To get help regarding a specific command type \"help command\""); - - phpdbg_notice("Commands"); - - while (prompt_command && prompt_command->name) { - phpdbg_writeln( - " %10s\t%s", prompt_command->name, prompt_command->tip); - ++prompt_command; - } - - phpdbg_notice("Help Commands"); - - while (help_command && help_command->name) { - phpdbg_writeln(" %10s\t%s", help_command->name, help_command->tip); - ++help_command; - } - - phpdbg_help_footer(); - } break; - - default: { - phpdbg_error( - "No help can be found for the subject \"%s\"", param->str); - } - } - - return SUCCESS; -} /* }}} */ - -PHPDBG_COMMAND(quiet) /* {{{ */ -{ - switch (param->type) { - case NUMERIC_PARAM: { - if (param->num) { - PHPDBG_G(flags) |= PHPDBG_IS_QUIET; - } else { - PHPDBG_G(flags) &= ~PHPDBG_IS_QUIET; - } - phpdbg_notice("Quietness %s", - (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "enabled" : "disabled"); - } break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - PHPDBG_COMMAND(list) /* {{{ */ { - switch (param->type) { + if (!param) { + return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS); + } else switch (param->type) { case NUMERIC_PARAM: - case EMPTY_PARAM: return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS); case FILE_PARAM: @@ -1020,54 +984,101 @@ PHPDBG_COMMAND(list) /* {{{ */ return SUCCESS; } /* }}} */ +PHPDBG_COMMAND(watch) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_list_watchpoints(TSRMLS_C); + } else switch (param->type) { + case STR_PARAM: + if (phpdbg_create_var_watchpoint(param->str, param->len TSRMLS_CC) != FAILURE) { + phpdbg_notice("Set watchpoint on %.*s", (int)param->len, param->str); + } + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + int phpdbg_interactive(TSRMLS_D) /* {{{ */ { int ret = SUCCESS; - phpdbg_input_t *input; + char *why = NULL; + char *input = NULL; + phpdbg_param_t stack; PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE; input = phpdbg_read_input(NULL TSRMLS_CC); - if (input && input->length > 0L) { + if (input) { do { - switch (ret = phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) { - case FAILURE: - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) { - phpdbg_error("Failed to execute %s!", input->string); + yyscan_t scanner; + YY_BUFFER_STATE state; + + phpdbg_init_param(&stack, STACK_PARAM); + + if (yylex_init(&scanner)) { + phpdbg_error( + "could not initialize scanner"); + return FAILURE; + } + + state = yy_scan_string(input, scanner); + + if (yyparse(&stack, scanner) <= 0) { + switch (ret = phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + case FAILURE: + if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + if (why) { + phpdbg_error("%s", why); + } + } } - } - break; - case PHPDBG_LEAVE: - case PHPDBG_FINISH: - case PHPDBG_UNTIL: - case PHPDBG_NEXT: { - if (!EG(in_execution)) { - phpdbg_error("Not running"); + if (why) { + free(why); + why = NULL; + } + break; + + case PHPDBG_LEAVE: + case PHPDBG_FINISH: + case PHPDBG_UNTIL: + case PHPDBG_NEXT: { + if (!EG(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + phpdbg_error("Not running"); + } + goto out; } - goto out; } } - phpdbg_destroy_input(&input TSRMLS_CC); - } while ((input = phpdbg_read_input(NULL TSRMLS_CC)) && (input->length > 0L)); + if (why) { + free(why); + why = NULL; + } - if (input && !input->length) - goto last; + yy_delete_buffer(state, scanner); + yylex_destroy(scanner); - } else { -last: - if (PHPDBG_G(lcmd)) { - ret = PHPDBG_G(lcmd)->handler( - &PHPDBG_G(lparam), input TSRMLS_CC); - goto out; - } + phpdbg_stack_free(&stack); + phpdbg_destroy_input(&input TSRMLS_CC); + + } while ((input = phpdbg_read_input(NULL TSRMLS_CC))); } out: - phpdbg_destroy_input(&input TSRMLS_CC); + if (input) { + phpdbg_stack_free(&stack); + phpdbg_destroy_input(&input TSRMLS_CC); + } + + if (why) { + free(why); + } if (EG(in_execution)) { phpdbg_restore_frame(TSRMLS_C); @@ -1075,6 +1086,8 @@ out: PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE; + phpdbg_print_changed_zvals(TSRMLS_C); + return ret; } /* }}} */ @@ -1214,7 +1227,7 @@ zend_vm_enter: ); \ } \ \ - do { \ +/* do { */\ switch (phpdbg_interactive(TSRMLS_C)) { \ case PHPDBG_LEAVE: \ case PHPDBG_FINISH: \ @@ -1223,7 +1236,7 @@ zend_vm_enter: goto next; \ } \ } \ - } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); \ +/* } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); */\ } while (0) /* allow conditional breakpoints and @@ -1285,22 +1298,30 @@ zend_vm_enter: phpdbg_print_opline_ex( execute_data, &vars, 0 TSRMLS_CC); + if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING && (PHPDBG_G(flags) & PHPDBG_STEP_OPCODE || execute_data->opline->lineno != PHPDBG_G(last_line))) { + PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; + DO_INTERACTIVE(); + } + + /* check if some watchpoint was hit */ + { + if (phpdbg_print_changed_zvals(TSRMLS_C) == SUCCESS) { + DO_INTERACTIVE(); + } + } + /* search for breakpoints */ { phpdbg_breakbase_t *brake; - if ((PHPDBG_G(flags) & PHPDBG_BP_MASK) && - (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC))) { - phpdbg_hit_breakpoint( - brake, 1 TSRMLS_CC); + if ((PHPDBG_G(flags) & PHPDBG_BP_MASK) + && (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC)) + && (brake->type != PHPDBG_BREAK_FILE || execute_data->opline->lineno != PHPDBG_G(last_line))) { + phpdbg_hit_breakpoint(brake, 1 TSRMLS_CC); DO_INTERACTIVE(); } } - if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) { - DO_INTERACTIVE(); - } - next: if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { phpdbg_writeln(EMPTY); @@ -1309,6 +1330,8 @@ next: DO_INTERACTIVE(); } + PHPDBG_G(last_line) = execute_data->opline->lineno; + PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC); if (PHPDBG_G(vmret) > 0) { |