]> granicus.if.org Git - php/commitdiff
Add stdin command and -s command line parameter to phpdbg
authorBob Weinand <bobwei9@hotmail.com>
Wed, 12 Oct 2016 18:11:51 +0000 (20:11 +0200)
committerBob Weinand <bobwei9@hotmail.com>
Wed, 12 Oct 2016 18:15:49 +0000 (20:15 +0200)
This allows reading the initial script file from stdin instead of being forced to put the script into a file in order to run it with phpdbg.
Especially important for programmatic execution of phpdbg.

Also adding tests/include_once.phpt and tests/set_exception_handler.phpt as I seem to have forgotten to git add them sometime long ago...

run-tests.php
sapi/phpdbg/phpdbg.c
sapi/phpdbg/phpdbg_bp.c
sapi/phpdbg/phpdbg_bp.h
sapi/phpdbg/phpdbg_help.c
sapi/phpdbg/phpdbg_list.c
sapi/phpdbg/phpdbg_prompt.c
sapi/phpdbg/phpdbg_prompt.h
sapi/phpdbg/tests/include_once.phpt [new file with mode: 0644]
sapi/phpdbg/tests/set_exception_handler.phpt [new file with mode: 0644]
sapi/phpdbg/tests/stdin_001.phpt [new file with mode: 0644]

index 66fcdd7fb3143633d8581278e023dd8132ba806c..fef39c50b820b589ab0c53e82635319ed1b00525 100755 (executable)
@@ -164,7 +164,7 @@ if (getenv('TEST_PHP_EXECUTABLE')) {
                        $phpdbg = $cwd . '/sapi/phpdbg/phpdbg';
 
                        if (file_exists($phpdbg)) {
-                               putenv("TEST_PHP_CGI_EXECUTABLE=$phpdbg");
+                               putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg");
                        } else {
                                $phpdbg = null;
                        }
index 8b1dde57681b89351dd9528ce59a2b2dfdfb4b73..45eb068e32183154b014b8b57aa07f079728249c 100644 (file)
@@ -341,7 +341,7 @@ static PHP_FUNCTION(phpdbg_break_file)
                return;
        }
 
-       phpdbg_set_breakpoint_file(file, line);
+       phpdbg_set_breakpoint_file(file, 0, line);
 } /* }}} */
 
 /* {{{ proto void phpdbg_break_method(string class, string method) */
@@ -1042,6 +1042,7 @@ const opt_struct OPTIONS[] = { /* {{{ */
        {'r', 0, "run"},
        {'e', 0, "generate ext_stmt opcodes"},
        {'E', 0, "step-through-eval"},
+       {'s', 1, "script from stdin"},
        {'S', 1, "sapi-name"},
 #ifndef _WIN32
        {'l', 1, "listen"},
@@ -1345,6 +1346,8 @@ int main(int argc, char **argv) /* {{{ */
        zend_bool use_mm_wrappers = 0;
        zend_bool is_exit;
        int exit_status;
+       char *read_from_stdin = NULL;
+       zend_string *backup_phpdbg_compile = NULL;
 
 #ifndef _WIN32
        struct sigaction sigio_struct;
@@ -1455,6 +1458,12 @@ phpdbg_main:
 
                        /* begin phpdbg options */
 
+                       case 's': { /* read script from stdin */
+                               if (settings == NULL) {
+                                       read_from_stdin = strdup(php_optarg);
+                               }
+                       } break;
+
                        case 'S': { /* set SAPI name */
                                if (sapi_name) {
                                        free(sapi_name);
@@ -1567,8 +1576,10 @@ phpdbg_main:
                php_optarg = NULL;
        }
 
+       quit_immediately = phpdbg_startup_run > 1;
+
        /* set exec if present on command line */
-       if (argc > php_optind && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
+       if (!read_from_stdin && argc > php_optind && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
                if (!exec && strlen(argv[php_optind])) {
                        exec = strdup(argv[php_optind]);
                }
@@ -1832,13 +1843,6 @@ phpdbg_main:
                        if (init_file) {
                                phpdbg_init(init_file, init_file_len, init_file_default);
                        }
-                       if (bp_tmp) {
-                               PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
-                               phpdbg_string_init(bp_tmp);
-                               free(bp_tmp);
-                               bp_tmp = NULL;
-                               PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
-                       }
                } zend_end_try();
                PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
 
@@ -1848,18 +1852,55 @@ phpdbg_main:
                }
 
                /* auto compile */
-               if (PHPDBG_G(exec)) {
+               if (read_from_stdin) {
+                       if (!read_from_stdin[0]) {
+                               if (!quit_immediately) {
+                                       phpdbg_error("error", "", "Impossible to not specify a stdin delimiter without -rr");
+                                       PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+                                       goto phpdbg_out;
+                               }
+                       }
+                       if (show_banner || read_from_stdin[0]) {
+                               phpdbg_notice("stdin", "delimiter=\"%s\"", "Reading input from stdin; put '%s' followed by a newline on an own line after code to end input", read_from_stdin);
+                       }
+
+                       if (phpdbg_startup_run > 0) {
+                               PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
+                       }
+
+                       zend_try {
+                               phpdbg_param_t cmd;
+                               cmd.str = read_from_stdin;
+                               cmd.len = strlen(read_from_stdin);
+                               PHPDBG_COMMAND_HANDLER(stdin)(&cmd);
+                       } zend_end_try();
+
+                       PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
+               } else if (PHPDBG_G(exec)) {
                        if (settings || phpdbg_startup_run > 0) {
                                PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
                        }
 
                        zend_try {
-                               phpdbg_compile();
+                               if (backup_phpdbg_compile) {
+                                       phpdbg_compile_stdin(backup_phpdbg_compile);
+                               } else {
+                                       phpdbg_compile();
+                               }
                        } zend_end_try();
+                       backup_phpdbg_compile = NULL;
 
                        PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
                }
 
+               if (bp_tmp) {
+                       PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT | PHPDBG_IS_INITIALIZING;
+                       phpdbg_string_init(bp_tmp);
+                       free(bp_tmp);
+                       bp_tmp = NULL;
+                       PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT & ~PHPDBG_IS_INITIALIZING;
+               }
+
                if (settings == (void *) 0x1) {
                        if (PHPDBG_G(ops)) {
                                phpdbg_print_opcodes(print_opline_func);
@@ -1881,7 +1922,6 @@ phpdbg_interact:
                do {
                        zend_try {
                                if (phpdbg_startup_run) {
-                                       quit_immediately = phpdbg_startup_run > 1;
                                        phpdbg_startup_run = 0;
                                        if (quit_immediately) {
                                                PHPDBG_G(flags) = (PHPDBG_G(flags) & ~PHPDBG_HAS_PAGINATION) | PHPDBG_IS_INTERACTIVE | PHPDBG_PREVENT_INTERACTIVE;
@@ -2059,6 +2099,12 @@ phpdbg_out:
                        wrapper->wops->stream_opener = PHPDBG_G(orig_url_wrap_php);
                }
 
+               if (PHPDBG_G(exec) && !memcmp("-", PHPDBG_G(exec), 2)) { /* i.e. execution context has been read from stdin - back it up */
+                       phpdbg_file_source *data = zend_hash_str_find_ptr(&PHPDBG_G(file_sources), PHPDBG_G(exec), PHPDBG_G(exec_len));
+                       backup_phpdbg_compile = zend_string_alloc(data->len + 2, 1);
+                       sprintf(ZSTR_VAL(backup_phpdbg_compile), "?>%.*s", (int) data->len, data->buf);
+               }
+
                zend_try {
                        php_module_shutdown();
                } zend_end_try();
@@ -2071,6 +2117,11 @@ phpdbg_out:
                sapi_shutdown();
        }
 
+       if (read_from_stdin) {
+               free(read_from_stdin);
+               read_from_stdin = NULL;
+       }
+
        if ((cleaning > 0 || remote) && !quit_immediately) {
                /* reset internal php_getopt state */
                php_getopt(-1, argv, OPTIONS, NULL, &php_optind, 0, 0);
@@ -2083,6 +2134,10 @@ phpdbg_out:
        /* tsrm_shutdown(); */
 #endif
 
+       if (backup_phpdbg_compile) {
+               zend_string_free(backup_phpdbg_compile);
+       }
+
 #ifndef _WIN32
        if (address) {
                free(address);
index 4cb1dae42c6b12e6c225669f56ac27bc7d4d9ed1..da4c8f71bf38d5379aec26c5d0ae7897ec358d2d 100644 (file)
@@ -230,7 +230,7 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */
        }
 } /* }}} */
 
-PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* {{{ */
+PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, size_t path_len, long line_num) /* {{{ */
 {
        php_stream_statbuf ssb;
        char realpath[MAXPATHLEN];
@@ -240,10 +240,11 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* {
 
        HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE];
        phpdbg_breakfile_t new_break;
-       size_t path_len = 0L;
 
-       if (VCWD_REALPATH(path, realpath)) {
-               path = realpath;
+       if (!path_len) {
+               if (VCWD_REALPATH(path, realpath)) {
+                       path = realpath;
+               }
        }
        path_len = strlen(path);
 
@@ -886,21 +887,13 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_
 {
        HashTable *breaks;
        phpdbg_breakbase_t *brake;
-       size_t path_len;
-       char realpath[MAXPATHLEN];
-       const char *path = ZSTR_VAL(op_array->filename);
-
-       if (VCWD_REALPATH(path, realpath)) {
-               path = realpath;
-       }
-
-       path_len = strlen(path);
 
 #if 0
-       phpdbg_debug("Op at: %.*s %d\n", path_len, path, (*EG(opline_ptr))->lineno);
+       phpdbg_debug("Op at: %.*s %d\n", ZSTR_LEN(op_array->filename), ZSTR_VAL(op_array->filename), (*EG(opline_ptr))->lineno);
 #endif
 
-       if (!(breaks = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len))) {
+       /* NOTE: realpath resolution should have happened at compile time - no reason to do it here again */
+       if (!(breaks = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename))) {
                return NULL;
        }
 
index abbcc4d5df97077a3ab4e4cd7da32ff1327188ac..7daafe48c1a197ecb5b2bbe528394e161a305d2b 100644 (file)
@@ -125,7 +125,7 @@ PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uin
 PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file); /* }}} */
 
 /* {{{ Breakpoint Creation API */
-PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno);
+PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, size_t path_len, long lineno);
 PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len);
 PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name);
 PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len);
index a7385df21e79bec7537a0f6c644457e6ab8c84e0..ce1d8d9e90acf47dd714e6633b80c7b91e286134 100644 (file)
@@ -338,6 +338,7 @@ phpdbg_help_text_t phpdbg_help_text[] = {
 
 "**Starting and Stopping Execution**" CR
 "  **exec**     set execution context" CR
+"  **stdin**    set executing script from stdin" CR
 "  **run**      attempt execution" CR
 "  **step**     continue execution until other line is reached" CR
 "  **continue** continue execution" CR
@@ -386,6 +387,7 @@ phpdbg_help_text_t phpdbg_help_text[] = {
 "  **-rr**                         Run execution context and quit after execution (not respecting breakpoints)" CR
 "  **-e**                          Generate extended information for debugger/profiler" CR
 "  **-E**                          Enable step through eval, careful!" CR
+"  **-s**      **-s=**, **-s**=foo         Read code to execute from stdin with an optional delimiter" CR
 "  **-S**      **-S**cli               Override SAPI name, careful!" CR
 "  **-l**      **-l**4000              Setup remote console ports" CR
 "  **-a**      **-a**192.168.0.3       Setup remote console bind address" CR
@@ -396,6 +398,13 @@ phpdbg_help_text_t phpdbg_help_text[] = {
 "  **--**      **--** arg1 arg2        Use to delimit phpdbg arguments and php $argv; append any $argv "
 "argument after it" CR CR
 
+"**Reading from stdin**" CR CR
+
+"The **-s** option allows inputting a script to execute directly from stdin. The given delimiter "
+"(\"foo\" in the example) needs to be specified at the end of the input on its own line, followed by "
+"a line break. If **-rr** has been specified, it is allowed to omit the delimiter (**-s=**) and "
+"it will read until EOF. See also the help entry for the **stdin** command." CR CR
+
 "**Remote Console Mode**" CR CR
 
 "This mode is enabled by specifying the **-a** option. Phpdbg will bind only to the loopback "
@@ -634,6 +643,21 @@ phpdbg_help_text_t phpdbg_help_text[] = {
 "    Set the execution context to **/tmp/script.php**"
 },
 
+{"stdin",
+"The **stdin** command takes a string serving as delimiter. It will then read all the input from "
+"stdin until encountering the given delimiter on a standalone line. It can also be passed at "
+"startup using the **-s=** command line option (the delimiter then is optional if **-rr** is "
+"also passed - in that case it will just read until EOF)." CR
+"This input will be then compiled as PHP code and set as execution context." CR CR
+
+"**Example**" CR CR
+
+"    $P stdin foo" CR
+"    <?php" CR
+"    echo \"Hello, world!\\n\";" CR
+"    foo"
+},
+
 //*********** Does F skip any breakpoints lower stack frames or only the current??
 {"finish",
 "The **finish** command causes control to be passed back to the vm, continuing execution.  Any "
index 6895bea43ef371ba48344a0e9913dcdfe043ad99..87594614e1a386c8238f50db116eb76878874e5e 100644 (file)
@@ -62,9 +62,15 @@ PHPDBG_LIST(lines) /* {{{ */
                } break;
 
                case FILE_PARAM: {
-                       zend_string *file = zend_string_init(param->file.name, strlen(param->file.name), 0);
+                       zend_string *file;
+                       char resolved_path_buf[MAXPATHLEN];
+                       const char *abspath = param->file.name;
+                       if (VCWD_REALPATH(abspath, resolved_path_buf)) {
+                               abspath = resolved_path_buf;
+                       }
+                       file = zend_string_init(abspath, strlen(abspath), 0);
                        phpdbg_list_file(file, param->file.line, 0, 0);
-                       efree(file);
+                       zend_string_release(file);
                } break;
 
                phpdbg_default_switch_case();
@@ -127,16 +133,8 @@ void phpdbg_list_file(zend_string *filename, uint count, int offset, uint highli
 {
        uint line, lastline;
        phpdbg_file_source *data;
-       char resolved_path_buf[MAXPATHLEN];
-       const char *abspath;
-
-       if (VCWD_REALPATH(ZSTR_VAL(filename), resolved_path_buf)) {
-               abspath = resolved_path_buf;
-       } else {
-               abspath = ZSTR_VAL(filename);
-       }
 
-       if (!(data = zend_hash_str_find_ptr(&PHPDBG_G(file_sources), abspath, strlen(abspath)))) {
+       if (!(data = zend_hash_find_ptr(&PHPDBG_G(file_sources), filename))) {
                phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file...");
                return;
        }
@@ -287,6 +285,7 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type) {
                return NULL;
        }
 
+       dataptr->filename = estrdup(dataptr->filename);
        dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
        zend_hash_str_add_ptr(&PHPDBG_G(file_sources), filename, strlen(filename), dataptr);
        phpdbg_resolve_pending_file_break(filename);
@@ -305,6 +304,17 @@ zend_op_array *phpdbg_init_compile_file(zend_file_handle *file, int type) {
 
        if (VCWD_REALPATH(filename, resolved_path_buf)) {
                filename = resolved_path_buf;
+
+               if (file->opened_path) {
+                       zend_string_release(file->opened_path);
+                       file->opened_path = zend_string_init(filename, strlen(filename), 0);
+               } else {
+                       if (file->free_filename) {
+                               efree((char *) file->filename);
+                       }
+                       file->free_filename = 1;
+                       file->filename = estrdup(filename);
+               }
        }
 
        op_array = PHPDBG_G(init_compile_file)(file, type);
@@ -355,7 +365,7 @@ zend_op_array *phpdbg_compile_string(zval *source_string, char *filename) {
                return NULL;
        }
 
-       fake_name = strpprintf(0, "%s\0%p", filename, op_array->opcodes);
+       fake_name = strpprintf(0, "%s%c%p", filename, 0, op_array->opcodes);
 
        dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
        zend_hash_add_ptr(&PHPDBG_G(file_sources), fake_name, dataptr);
@@ -377,6 +387,7 @@ void phpdbg_free_file_source(zval *zv) {
        if (data->buf) {
                efree(data->buf);
        }
+       efree(data->filename);
 
        destroy_op_array(&data->op_array);
 
index 97f9a711f74cec162498948369b8f5811defdd8e..85b37b1686307265765972717e71fcc549b9f46b 100644 (file)
@@ -26,7 +26,9 @@
 #include "zend_vm.h"
 #include "zend_generators.h"
 #include "zend_interfaces.h"
+#include "zend_smart_str.h"
 #include "phpdbg.h"
+#include "phpdbg_io.h"
 
 #include "phpdbg_help.h"
 #include "phpdbg_print.h"
@@ -68,6 +70,7 @@ extern int phpdbg_startup_run;
 /* {{{ command declarations */
 const phpdbg_command_t phpdbg_prompt_commands[] = {
        PHPDBG_COMMAND_D(exec,    "set execution context",                    'e', NULL, "s", 0),
+       PHPDBG_COMMAND_D(stdin,   "read script from stdin",                    0 , NULL, "s", 0),
        PHPDBG_COMMAND_D(step,    "step through execution",                   's', NULL, 0, PHPDBG_ASYNC_SAFE),
        PHPDBG_COMMAND_D(continue,"continue execution",                       'c', NULL, 0, PHPDBG_ASYNC_SAFE),
        PHPDBG_COMMAND_D(run,     "attempt execution",                        'r', NULL, "|s", 0),
@@ -460,6 +463,111 @@ PHPDBG_COMMAND(exec) /* {{{ */
        return SUCCESS;
 } /* }}} */
 
+PHPDBG_COMMAND(stdin)
+{
+       smart_str code = {0};
+       char *buf;
+       char *sep = param->str;
+       int seplen = param->len;
+       int bytes = 0;
+
+       smart_str_appends(&code, "?>");
+
+       do {
+               PHPDBG_G(input_buflen) += bytes;
+               if (PHPDBG_G(input_buflen) <= 0) {
+                       continue;
+               }
+
+               if (sep && seplen) {
+                       char *nl = buf = PHPDBG_G(input_buffer);
+                       do {
+                               if (buf == nl + seplen) {
+                                       if (!memcmp(sep, nl, seplen) && (*buf == '\n' || (*buf == '\r' && buf[1] == '\n'))) {
+                                               smart_str_appendl(&code, PHPDBG_G(input_buffer), nl - PHPDBG_G(input_buffer));
+                                               memmove(PHPDBG_G(input_buffer), ++buf, --PHPDBG_G(input_buflen));
+                                               goto exec_code;
+                                       }
+                               }
+                               if (*buf == '\n') {
+                                       nl = buf + 1;
+                               }
+                               buf++;
+                       } while (--PHPDBG_G(input_buflen));
+                       if (buf != nl && buf <= nl + seplen) {
+                               smart_str_appendl(&code, PHPDBG_G(input_buffer), nl - PHPDBG_G(input_buffer));
+                               PHPDBG_G(input_buflen) = buf - nl;
+                               memmove(PHPDBG_G(input_buffer), nl, PHPDBG_G(input_buflen));
+                       } else {
+                               PHPDBG_G(input_buflen) = 0;
+                               smart_str_appendl(&code, PHPDBG_G(input_buffer), buf - PHPDBG_G(input_buffer));
+                       }
+               } else {
+                       smart_str_appendl(&code, PHPDBG_G(input_buffer), PHPDBG_G(input_buflen));
+                       PHPDBG_G(input_buflen) = 0;
+               }
+       } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, PHPDBG_G(input_buffer) + PHPDBG_G(input_buflen), PHPDBG_MAX_CMD - PHPDBG_G(input_buflen), -1)) > 0);
+
+       if (bytes < 0) {
+               PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED;
+               zend_bailout();
+       }
+
+exec_code:
+       smart_str_0(&code);
+
+       if (phpdbg_compile_stdin(code.s) == FAILURE) {
+               zend_exception_error(EG(exception), E_ERROR);
+               zend_bailout();
+       }
+
+       return SUCCESS;
+} /* }}} */
+
+int phpdbg_compile_stdin(zend_string *code) {
+       zval zv;
+
+       ZVAL_STR(&zv, code);
+
+       PHPDBG_G(ops) = zend_compile_string(&zv, "-");
+
+       zend_string_release(code);
+
+       if (EG(exception)) {
+               return FAILURE;
+       }
+
+       if (PHPDBG_G(exec)) {
+               efree(PHPDBG_G(exec));
+       }
+       PHPDBG_G(exec) = estrdup("-");
+       PHPDBG_G(exec_len) = 1;
+       { /* remove leading ?> from source */
+               int i;
+               zend_string *source_path = zend_strpprintf(0, "-%c%p", 0, PHPDBG_G(ops)->opcodes);
+               phpdbg_file_source *data = zend_hash_find_ptr(&PHPDBG_G(file_sources), source_path);
+               dtor_func_t dtor = PHPDBG_G(file_sources).pDestructor;
+               PHPDBG_G(file_sources).pDestructor = NULL;
+               zend_hash_del(&PHPDBG_G(file_sources), source_path);
+               PHPDBG_G(file_sources).pDestructor = dtor;
+               zend_hash_str_update_ptr(&PHPDBG_G(file_sources), "-", 1, data);
+               zend_string_release(source_path);
+
+               efree(data->filename);
+               data->filename = estrdup("-");
+
+               for (i = 1; i <= data->lines; i++) {
+                       data->line[i] -= 2;
+               }
+               data->len -= 2;
+               memmove(data->buf, data->buf + 2, data->len);
+       }
+
+       phpdbg_notice("compile", "context=\"-\"", "Successful compilation of stdin input");
+
+       return SUCCESS;
+}
+
 int phpdbg_compile(void) /* {{{ */
 {
        zend_file_handle fh;
@@ -1019,16 +1127,21 @@ PHPDBG_COMMAND(set) /* {{{ */
 PHPDBG_COMMAND(break) /* {{{ */
 {
        if (!param) {
-               phpdbg_set_breakpoint_file(
-                       zend_get_executed_filename(),
-                       zend_get_executed_lineno());
+               if (PHPDBG_G(exec)) {
+                       phpdbg_set_breakpoint_file(
+                               zend_get_executed_filename(),
+                               strlen(zend_get_executed_filename()),
+                               zend_get_executed_lineno());
+               } else {
+                       phpdbg_error("inactive", "type=\"noexec\"", "Execution context not set!");
+               }
        } else switch (param->type) {
                case ADDR_PARAM:
                        phpdbg_set_breakpoint_opline(param->addr);
                        break;
                case NUMERIC_PARAM:
                        if (PHPDBG_G(exec)) {
-                               phpdbg_set_breakpoint_file(phpdbg_current_file(), param->num);
+                               phpdbg_set_breakpoint_file(phpdbg_current_file(), strlen(phpdbg_current_file()), param->num);
                        } else {
                                phpdbg_error("inactive", "type=\"noexec\"", "Execution context not set!");
                        }
@@ -1043,7 +1156,7 @@ PHPDBG_COMMAND(break) /* {{{ */
                        phpdbg_set_breakpoint_function_opline(param->str, param->num);
                        break;
                case FILE_PARAM:
-                       phpdbg_set_breakpoint_file(param->file.name, param->file.line);
+                       phpdbg_set_breakpoint_file(param->file.name, 0, param->file.line);
                        break;
                case NUMERIC_FILE_PARAM:
                        phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line);
index c93beeba03e5d493235c221e93c0394333641d41..2966104e58f41da6b2a192d70cc1c101184ad24e 100644 (file)
@@ -27,11 +27,13 @@ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default);
 void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init);
 int phpdbg_interactive(zend_bool allow_async_unsafe, char *input);
 int phpdbg_compile(void);
+int phpdbg_compile_stdin(zend_string *code);
 void phpdbg_force_interruption(void);
 /* }}} */
 
 /* {{{ phpdbg command handlers */
 PHPDBG_COMMAND(exec);
+PHPDBG_COMMAND(stdin);
 PHPDBG_COMMAND(step);
 PHPDBG_COMMAND(continue);
 PHPDBG_COMMAND(run);
diff --git a/sapi/phpdbg/tests/include_once.phpt b/sapi/phpdbg/tests/include_once.phpt
new file mode 100644 (file)
index 0000000..0a00e04
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+include_once must include only once
+--PHPDBG--
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> 1
+[Script ended normally]
+prompt> 
+--FILE--
+<?php
+
+include_once __DIR__.'/include.inc';
+include_once __DIR__.'/include.inc';
+
diff --git a/sapi/phpdbg/tests/set_exception_handler.phpt b/sapi/phpdbg/tests/set_exception_handler.phpt
new file mode 100644 (file)
index 0000000..7d4d4fa
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+set_exception_handler() in phpdbg
+--PHPDBG--
+r
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Uncaught Exception in %s on line 4: test]
+>00004: throw new Exception("test");
+ 00005: 
+prompt> EX
+[Script ended normally]
+prompt> 
+--FILE--
+<?php
+
+set_exception_handler(function () { print "EX\n"; });
+throw new Exception("test");
diff --git a/sapi/phpdbg/tests/stdin_001.phpt b/sapi/phpdbg/tests/stdin_001.phpt
new file mode 100644 (file)
index 0000000..0bc940c
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Test stdin input with breakpoints
+--PHPDBG--
+stdin foo
+<?php
+
+echo "Hello, world!\n";
+foo
+b 3
+r
+c
+r
+q
+--EXPECTF--
+prompt> [Successful compilation of stdin input]
+prompt> [Breakpoint #0 added at -:3]
+prompt> [Breakpoint #0 at -:3, hits: 1]
+>00003: echo "Hello, world!\n";
+ 00004: 
+prompt> Hello, world!
+[Script ended normally]
+prompt> [Breakpoint #0 at -:3, hits: 1]
+>00003: echo "Hello, world!\n";
+ 00004: 
+prompt> 
\ No newline at end of file