]> granicus.if.org Git - php/commitdiff
Stabilize execution, always run destructors and extended file breakpoints
authorBob Weinand <bobwei9@hotmail.com>
Sun, 26 Oct 2014 19:43:49 +0000 (20:43 +0100)
committerBob Weinand <bobwei9@hotmail.com>
Sun, 26 Oct 2014 23:00:16 +0000 (00:00 +0100)
sapi/phpdbg/phpdbg.c
sapi/phpdbg/phpdbg.h
sapi/phpdbg/phpdbg_bp.c
sapi/phpdbg/phpdbg_bp.h
sapi/phpdbg/phpdbg_cmd.c
sapi/phpdbg/phpdbg_list.c
sapi/phpdbg/phpdbg_out.c
sapi/phpdbg/phpdbg_prompt.c

index 493d8ec20c9f492c96dd4274703ba70265279bf3..3e31f76898a0503e073f6d04aceddf75ff5d715c 100644 (file)
@@ -46,7 +46,6 @@
 
 ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
 int phpdbg_startup_run = 0;
-char *phpdbg_exec = NULL;
 
 static PHP_INI_MH(OnUpdateEol)
 {
@@ -186,7 +185,8 @@ static void php_phpdbg_destroy_registered(void *data) /* {{{ */
 
 static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
 {
-       zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],   8, NULL, php_phpdbg_destroy_bp_file, 0);
+       zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
+       zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], 8, NULL, php_phpdbg_destroy_bp_file, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
@@ -216,8 +216,8 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
        zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
        zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
        zend_hash_destroy(&PHPDBG_G(seek));
-       zend_hash_destroy(&PHPDBG_G(registered));
        zend_hash_destroy(&PHPDBG_G(file_sources));
+       zend_hash_destroy(&PHPDBG_G(registered));
        zend_hash_destroy(&PHPDBG_G(watchpoints));
        zend_llist_destroy(&PHPDBG_G(watchlist_mem));
 
@@ -363,6 +363,7 @@ static PHP_FUNCTION(phpdbg_break_function)
 static PHP_FUNCTION(phpdbg_clear)
 {
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
+       zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
@@ -543,11 +544,27 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
 
 static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */
 {
+       if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) {
+               zend_phpdbg_globals *pg = PHPDBG_G(backup) = calloc(1, sizeof(zend_phpdbg_globals));
+
+               php_phpdbg_globals_ctor(pg);
+
+               pg->exec = strndup(PHPDBG_G(exec), PHPDBG_G(exec_len));
+               pg->exec_len = PHPDBG_G(exec_len);
+               pg->oplog = PHPDBG_G(oplog);
+               pg->prompt[0] = PHPDBG_G(prompt)[0];
+               pg->prompt[1] = PHPDBG_G(prompt)[1];
+               memset(pg->colors, PHPDBG_G(colors), sizeof(pg->colors));
+               pg->eol = PHPDBG_G(eol);
+               pg->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK;
+       }
+
        fflush(stdout);
        if(SG(request_info).argv0) {
                free(SG(request_info).argv0);
                SG(request_info).argv0 = NULL;
        }
+
        return SUCCESS;
 }
 /* }}} */
@@ -1009,6 +1026,7 @@ int main(int argc, char **argv) /* {{{ */
        zend_ulong zend_extensions_len = 0L;
        zend_bool ini_ignore;
        char *ini_override;
+       char *exec = NULL;
        char *init_file;
        size_t init_file_len;
        zend_bool init_file_default;
@@ -1020,6 +1038,7 @@ int main(int argc, char **argv) /* {{{ */
        long cleaning = 0;
        zend_bool remote = 0;
        int step = 0;
+       zend_phpdbg_globals *settings = NULL;
 
 #ifdef _WIN32
        char *bp_tmp_file = NULL;
@@ -1102,6 +1121,9 @@ phpdbg_main:
        opt = 0;
        step = 0;
        sapi_name = NULL;
+       if (settings) {
+               exec = settings->exec;
+       }
 
        while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
                switch (opt) {
@@ -1243,12 +1265,12 @@ phpdbg_main:
        }
        
        /* set exec if present on command line */
-       if (!phpdbg_exec && (argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS)) {
+       if (!exec && (argc > php_optind) && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
                if (strlen(argv[php_optind])) {
-                       if (phpdbg_exec) {
-                               free(phpdbg_exec);
+                       if (exec) {
+                               free(exec);
                        }
-                       phpdbg_exec = strdup(argv[php_optind]);
+                       exec = strdup(argv[php_optind]);
                }
                php_optind++;
        }
@@ -1309,20 +1331,31 @@ phpdbg_main:
 #endif
                zend_mm_heap *mm_heap;
 
-       /* setup remote server if necessary */
-       if (!cleaning && listen > 0) {
-               server = phpdbg_open_socket(address, listen TSRMLS_CC);
-               if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) {
-                       exit(0);
+               /* set flags from command line */
+               PHPDBG_G(flags) = flags;
+
+               if (settings) {
+#ifdef ZTS
+                       *((zend_phpdbg_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings;
+#else
+                       phpdbg_globals = *settings;
+#endif
                }
 
+               /* setup remote server if necessary */
+               if (!cleaning && listen > 0) {
+                       server = phpdbg_open_socket(address, listen TSRMLS_CC);
+                               if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) {
+                               exit(0);
+                       }
+
 #ifndef _WIN32
-               sigaction(SIGIO, &sigio_struct, NULL);
+                       sigaction(SIGIO, &sigio_struct, NULL);
 #endif
 
-               /* set remote flag to stop service shutting down upon quit */
-               remote = 1;
-       }
+                       /* set remote flag to stop service shutting down upon quit */
+                       remote = 1;
+               }
 
                mm_heap = phpdbg_mm_get_heap();
 
@@ -1371,7 +1404,7 @@ phpdbg_main:
                        for (i = SG(request_info).argc; --i;) {
                                SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
                        }
-                       SG(request_info).argv[i] = phpdbg_exec ? estrdup(phpdbg_exec) : estrdup("");
+                       SG(request_info).argv[i] = exec ? estrdup(exec) : estrdup("");
 
                        php_hash_environment(TSRMLS_C);
                }
@@ -1392,9 +1425,6 @@ phpdbg_main:
 
                PG(modules_activated) = 0;
 
-               /* set flags from command line */
-               PHPDBG_G(flags) = flags;
-
                /* setup io here */
                if (remote) {
                        PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
@@ -1434,12 +1464,12 @@ phpdbg_main:
                php_stream_stdio_ops.write = phpdbg_stdiop_write;
 #endif
 
-               if (phpdbg_exec) { /* set execution context */
-                       PHPDBG_G(exec) = phpdbg_resolve_path(phpdbg_exec TSRMLS_CC);
+               if (exec) { /* set execution context */
+                       PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);
                        PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
 
-                       free(phpdbg_exec);
-                       phpdbg_exec = NULL;
+                       free(exec);
+                       exec = NULL;
                }
 
                if (oplog_file) { /* open oplog */
@@ -1537,7 +1567,12 @@ phpdbg_interact:
                                }
                        } zend_end_try();
                } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
-               
+
+
+               if (PHPDBG_G(exec) && (PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
+                       exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */
+               }
+
                /* this must be forced */
                CG(unclean_shutdown) = 0;
                
@@ -1590,7 +1625,24 @@ phpdbg_out:
                /* this is just helpful */
                PG(report_memleaks) = 0;
 
-               php_request_shutdown((void*)0);
+               if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) {
+                       php_free_shutdown_functions(TSRMLS_C);
+                       zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC);
+               }
+
+               /* sapi_module.deactivate is where to backup things, last chance before mm_shutdown... */
+
+               zend_try {
+                       php_request_shutdown(NULL);
+               } zend_end_try();
+
+               if ((PHPDBG_G(flags) & (PHPDBG_IS_QUITTING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_RUNNING) {
+                       phpdbg_notice("stop", "type=\"normal\"", "Script ended normally");
+               }
+
+               if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) {
+                       settings = PHPDBG_G(backup);
+               }
 
                php_output_deactivate(TSRMLS_C);
 
index 688ba7cdfcbc6ec143d1177fedbaf63df04717af..57ea7ee570f1e09d1201586e4262cae2ca1b68aa 100644 (file)
 #include "phpdbg_utils.h"
 #include "phpdbg_btree.h"
 #include "phpdbg_watch.h"
+#include "phpdbg_bp.h"
 #ifdef PHP_WIN32
 # include "phpdbg_sigio_win32.h"
 #endif
@@ -131,71 +132,62 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
  BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
 */
 
-/* {{{ tables */
-#define PHPDBG_BREAK_FILE            0
-#define PHPDBG_BREAK_SYM             1
-#define PHPDBG_BREAK_OPLINE          2
-#define PHPDBG_BREAK_METHOD          3
-#define PHPDBG_BREAK_COND            4
-#define PHPDBG_BREAK_OPCODE          5
-#define PHPDBG_BREAK_FUNCTION_OPLINE 6
-#define PHPDBG_BREAK_METHOD_OPLINE   7
-#define PHPDBG_BREAK_FILE_OPLINE     8
-#define PHPDBG_BREAK_MAP             9
-#define PHPDBG_BREAK_TABLES          10 /* }}} */
-
 /* {{{ flags */
-#define PHPDBG_HAS_FILE_BP            (1<<1)
-#define PHPDBG_HAS_SYM_BP             (1<<2)
-#define PHPDBG_HAS_OPLINE_BP          (1<<3)
-#define PHPDBG_HAS_METHOD_BP          (1<<4)
-#define PHPDBG_HAS_COND_BP            (1<<5)
-#define PHPDBG_HAS_OPCODE_BP          (1<<6)
-#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1<<7)
-#define PHPDBG_HAS_METHOD_OPLINE_BP   (1<<8)
-#define PHPDBG_HAS_FILE_OPLINE_BP     (1<<9) /* }}} */
+#define PHPDBG_HAS_FILE_BP            (1ULL<<1)
+#define PHPDBG_HAS_PENDING_FILE_BP    (1ULL<<2)
+#define PHPDBG_HAS_SYM_BP             (1ULL<<3)
+#define PHPDBG_HAS_OPLINE_BP          (1ULL<<4)
+#define PHPDBG_HAS_METHOD_BP          (1ULL<<5)
+#define PHPDBG_HAS_COND_BP            (1ULL<<6)
+#define PHPDBG_HAS_OPCODE_BP          (1ULL<<7)
+#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1ULL<<8)
+#define PHPDBG_HAS_METHOD_OPLINE_BP   (1ULL<<9)
+#define PHPDBG_HAS_FILE_OPLINE_BP     (1ULL<<10) /* }}} */
 
 /*
  END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
 */
 
-#define PHPDBG_IN_COND_BP             (1<<10)
-#define PHPDBG_IN_EVAL                (1<<11)
+#define PHPDBG_IN_COND_BP             (1ULL<<11)
+#define PHPDBG_IN_EVAL                (1ULL<<12)
 
-#define PHPDBG_IS_STEPPING            (1<<12)
-#define PHPDBG_STEP_OPCODE            (1<<13)
-#define PHPDBG_IS_QUIET               (1<<14)
-#define PHPDBG_IS_QUITTING            (1<<15)
-#define PHPDBG_IS_COLOURED            (1<<16)
-#define PHPDBG_IS_CLEANING            (1<<17)
+#define PHPDBG_IS_STEPPING            (1ULL<<13)
+#define PHPDBG_STEP_OPCODE            (1ULL<<14)
+#define PHPDBG_IS_QUIET               (1ULL<<15)
+#define PHPDBG_IS_QUITTING            (1ULL<<16)
+#define PHPDBG_IS_COLOURED            (1ULL<<17)
+#define PHPDBG_IS_CLEANING            (1ULL<<18)
+#define PHPDBG_IS_RUNNING             (1ULL<<19)
 
-#define PHPDBG_IN_UNTIL               (1<<18)
-#define PHPDBG_IN_FINISH              (1<<19)
-#define PHPDBG_IN_LEAVE               (1<<20)
+#define PHPDBG_IN_UNTIL               (1ULL<<20)
+#define PHPDBG_IN_FINISH              (1ULL<<21)
+#define PHPDBG_IN_LEAVE               (1ULL<<22)
 
-#define PHPDBG_IS_REGISTERED          (1<<21)
-#define PHPDBG_IS_STEPONEVAL          (1<<22)
-#define PHPDBG_IS_INITIALIZING        (1<<23)
-#define PHPDBG_IS_SIGNALED            (1<<24)
-#define PHPDBG_IS_INTERACTIVE         (1<<25)
-#define PHPDBG_IS_BP_ENABLED          (1<<26)
-#define PHPDBG_IS_REMOTE              (1<<27)
-#define PHPDBG_IS_DISCONNECTED        (1<<28)
-#define PHPDBG_WRITE_XML              (1<<29)
+#define PHPDBG_IS_REGISTERED          (1ULL<<23)
+#define PHPDBG_IS_STEPONEVAL          (1ULL<<24)
+#define PHPDBG_IS_INITIALIZING        (1ULL<<25)
+#define PHPDBG_IS_SIGNALED            (1ULL<<26)
+#define PHPDBG_IS_INTERACTIVE         (1ULL<<27)
+#define PHPDBG_IS_BP_ENABLED          (1ULL<<28)
+#define PHPDBG_IS_REMOTE              (1ULL<<29)
+#define PHPDBG_IS_DISCONNECTED        (1ULL<<30)
+#define PHPDBG_WRITE_XML              (1ULL<<31)
 
-#define PHPDBG_SHOW_REFCOUNTS         (1<<30)
+#define PHPDBG_SHOW_REFCOUNTS         (1ULL<<32)
 
-#define PHPDBG_IN_SIGNAL_HANDLER      (1<<30)
+#define PHPDBG_IN_SIGNAL_HANDLER      (1ULL<<33)
 
 #define PHPDBG_SEEK_MASK              (PHPDBG_IN_UNTIL | PHPDBG_IN_FINISH | PHPDBG_IN_LEAVE)
 #define PHPDBG_BP_RESOLVE_MASK       (PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
 #define PHPDBG_BP_MASK                (PHPDBG_HAS_FILE_BP | PHPDBG_HAS_SYM_BP | PHPDBG_HAS_METHOD_BP | PHPDBG_HAS_OPLINE_BP | PHPDBG_HAS_COND_BP | PHPDBG_HAS_OPCODE_BP | PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
 #define PHPDBG_IS_STOPPING            (PHPDBG_IS_QUITTING | PHPDBG_IS_CLEANING)
 
+#define PHPDBG_PRESERVE_FLAGS_MASK    (PHPDBG_SHOW_REFCOUNTS | PHPDBG_IS_STEPONEVAL | PHPDBG_IS_BP_ENABLED | PHPDBG_STEP_OPCODE)
+
 #ifndef _WIN32
-#      define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED)
+#      define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED)
 #else
-#      define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED)
+#      define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_BP_ENABLED)
 #endif /* }}} */
 
 /* {{{ output descriptors */
@@ -256,6 +248,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
                FILE *ptr;
                int fd;
        } io[PHPDBG_IO_FDS];                         /* io */
+       int eol;                                     /* type of line ending to use */
        size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC);
        int in_script_xml;                           /* in <stream> output mode */
        struct {
@@ -281,17 +274,18 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
 
        JMP_BUF *sigsegv_bailout;                    /* bailout address for accesibility probing */
 
-       zend_ulong flags;                            /* phpdbg flags */
+       uint64_t flags;                              /* phpdbg flags */
 
        char *socket_path;                           /* phpdbg.path ini setting */
        char *sapi_name_ptr;                         /* store sapi name to free it if necessary to not leak memory */
        int socket_fd;                               /* file descriptor to socket (wait command) (-1 if unused) */
        int socket_server_fd;                        /* file descriptor to master socket (wait command) (-1 if unused) */
 #ifdef PHP_WIN32
-       HANDLE sigio_watcher_thread;                  /* sigio watcher thread handle */
+       HANDLE sigio_watcher_thread;                 /* sigio watcher thread handle */
        struct win32_sigio_watcher_data swd;
 #endif
-       int8_t eol;
+
+       struct _zend_phpdbg_globals *backup;         /* backup of data to store */
 ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
 
 #endif
index 81674a0daf10a94cdfab74bbb3e3a3d7279c0346..9333b353ce6ca697f89da328601a7a1ae0ccbbf5 100644 (file)
@@ -220,51 +220,119 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML
 {
        php_stream_statbuf ssb;
        char realpath[MAXPATHLEN];
+       const char *original_path = path;
+       zend_bool pending;
 
-       if (php_stream_stat_path(path, &ssb) != FAILURE) {
-               if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) {
-                       HashTable *broken;
-                       phpdbg_breakfile_t new_break;
-                       size_t path_len = 0L;
+       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 (VCWD_REALPATH(path, realpath)) {
+               path = realpath;
+       }
+       path_len = strlen(path);
+
+       if (!zend_hash_exists(&PHPDBG_G(file_sources), path, path_len)) {
+               if (php_stream_stat_path(path, &ssb) == FAILURE) {
+                       if (original_path[0] == '/') {
+                               phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", original_path);
+                               return;
                        }
+
+                       file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING];
+                       path = original_path;
                        path_len = strlen(path);
+                       pending = 1;
+               } else if (!(ssb.sb.st_mode & (S_IFREG|S_IFLNK))) {
+                       phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path);
+                       return;
+               }
+       }
 
-                       if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],
-                               path, path_len, (void**)&broken) == FAILURE) {
-                               HashTable breaks;
+       if (zend_hash_find(file_breaks, path, path_len, (void **) &broken) == FAILURE) {
+               HashTable breaks;
+               zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0);
 
-                               zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0);
+               zend_hash_add(file_breaks, path, path_len, &breaks, sizeof(HashTable), (void **) &broken);
+       }
 
-                               zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],
-                                       path, path_len, &breaks, sizeof(HashTable),
-                                       (void**)&broken);
-                       }
+       if (!zend_hash_index_exists(broken, line_num)) {
+               PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE);
+               new_break.filename = estrndup(path, path_len);
+               new_break.line = line_num;
 
-                       if (!zend_hash_index_exists(broken, line_num)) {
-                               PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
+               zend_hash_index_update(broken, line_num, (void **) &new_break, sizeof(phpdbg_breakfile_t), NULL);
 
-                               PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE);
-                               new_break.filename = estrndup(path, path_len);
-                               new_break.line = line_num;
+               if (pending) {
+                       PHPDBG_G(flags) |= PHPDBG_HAS_PENDING_FILE_BP;
 
-                               zend_hash_index_update( broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL);
+                       phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\" pending=\"pending\"", "Pending breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line);
+               } else {
+                       PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
 
-                               phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld",
-                                       new_break.id, new_break.filename, new_break.line);
+                       phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line);
+               }
 
-                               PHPDBG_BREAK_MAPPING(new_break.id, broken);
-                       } else {
-                               phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num);
+               PHPDBG_BREAK_MAPPING(new_break.id, broken);
+       } else {
+               phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num);
+       }
+} /* }}} */
+
+PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* {{{ */
+{
+       HashPosition position[2];
+       HashTable *fileht;
+       uint filelen = strlen(file);
+
+       zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]);
+       while (zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (void**) &fileht, &position[0]) == SUCCESS) {
+               const char *cur;
+               uint curlen;
+
+               zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (char **) &cur, &curlen, NULL, 0, &position[0]);
+               zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]);
+
+               if (curlen < filelen && file[filelen - curlen - 1] == '/' && !memcmp(file + filelen - curlen, cur, curlen)) {
+                       phpdbg_breakfile_t *brake, new_brake;
+                       HashTable *master = NULL;
+                       dtor_func_t dtor;
+
+                       PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
+
+                       if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, (void **) &master) == FAILURE) {
+                               dtor = PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor;
+                               PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = NULL;
+                               zend_hash_add(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, fileht, sizeof(HashTable), (void **) &fileht);
                        }
 
-               } else {
-                       phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path);
+                       for (zend_hash_internal_pointer_reset_ex(fileht, &position[1]);
+                            zend_hash_get_current_data_ex(fileht, (void**)&brake, &position[1]) == SUCCESS;
+                            zend_hash_move_forward_ex(fileht, &position[1])) {
+                               new_brake = *brake;
+                               new_brake.filename = estrndup(file, filelen);
+                               PHPDBG_BREAK_UNMAPPING(brake->id);
+
+                               if (master) {
+                                       zend_hash_index_update(master, brake->line, (void **) &new_brake, sizeof(phpdbg_breakfile_t), NULL);
+                                       PHPDBG_BREAK_MAPPING(brake->id, master);
+                               } else {
+                                       efree((char *) brake->filename);
+                                       *brake = new_brake;
+                                       PHPDBG_BREAK_MAPPING(brake->id, fileht);
+                               }
+                       }
+
+                       zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur, curlen);
+
+                       if (!master) {
+                               PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = dtor;
+                       }
+
+                       if (!zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING])) {
+                               PHPDBG_G(flags) &= ~PHPDBG_HAS_PENDING_FILE_BP;
+                       }
                }
-       } else {
-               phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", path);
        }
 } /* }}} */
 
@@ -1141,6 +1209,7 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */
 PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D) /* {{{ */
 {
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
+       zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
        zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
@@ -1398,6 +1467,25 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */
                                                ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
                                }
                        }
+               }  if ((PHPDBG_G(flags) & PHPDBG_HAS_PENDING_FILE_BP)) {
+                       HashPosition position[2];
+                       HashTable *points;
+
+                       phpdbg_out(SEPARATE "\n");
+                       phpdbg_out("Pending File Breakpoints:\n");
+                       for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]);
+                            zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (void**) &points, &position[0]) == SUCCESS;
+                            zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0])) {
+                               phpdbg_breakfile_t *brake;
+
+                               for (zend_hash_internal_pointer_reset_ex(points, &position[1]);
+                                    zend_hash_get_current_data_ex(points, (void**)&brake, &position[1]) == SUCCESS;
+                                    zend_hash_move_forward_ex(points, &position[1])) {
+                                       phpdbg_writeln("file", "id=\"%d\" name=\"%s\" line=\"%lu\" disabled=\"%s\" pending=\"pending\"", "#%d\t\t%s:%lu%s",
+                                               brake->id, brake->filename, brake->line,
+                                               ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+                               }
+                       }
 
                } break;
 
index a6227cba6c977ae63c1733d894158e13c4b9860b..606085ddcfcbfb6ac17915f49aaa2ca12381b1a9 100644 (file)
 
 /* {{{ defines */
 #define PHPDBG_BREAK_FILE            0
-#define PHPDBG_BREAK_SYM             1
-#define PHPDBG_BREAK_OPLINE          2
-#define PHPDBG_BREAK_METHOD          3
-#define PHPDBG_BREAK_COND            4
-#define PHPDBG_BREAK_OPCODE          5
-#define PHPDBG_BREAK_FUNCTION_OPLINE 6
-#define PHPDBG_BREAK_METHOD_OPLINE   7
-#define PHPDBG_BREAK_FILE_OPLINE     8
-#define PHPDBG_BREAK_MAP             9
-#define PHPDBG_BREAK_TABLES          10 /* }}} */
+#define PHPDBG_BREAK_FILE_PENDING    1
+#define PHPDBG_BREAK_SYM             2
+#define PHPDBG_BREAK_OPLINE          3
+#define PHPDBG_BREAK_METHOD          4
+#define PHPDBG_BREAK_COND            5
+#define PHPDBG_BREAK_OPCODE          6
+#define PHPDBG_BREAK_FUNCTION_OPLINE 7
+#define PHPDBG_BREAK_METHOD_OPLINE   8
+#define PHPDBG_BREAK_FILE_OPLINE     9
+#define PHPDBG_BREAK_MAP             10
+#define PHPDBG_BREAK_TABLES          11 /* }}} */
 
 /* {{{ */
 typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */
@@ -116,10 +117,11 @@ typedef struct _phpdbg_breakcond_t {
        zend_op_array  *ops;
 } phpdbg_breakcond_t;
 
-/* {{{ Opline breaks API */
+/* {{{ Resolving breaks API */
 PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC);
 PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC);
-PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */
+PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC);
+PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC); /* }}} */
 
 /* {{{ Breakpoint Creation API */
 PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC);
index 13d5a0d6340c348681cd27f386fd1e737ef83d2a..a170d52955586072196234b659a74ff391c79659 100644 (file)
@@ -727,7 +727,7 @@ PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
        char *cmd = NULL;
        char *buffer = NULL;
 
-       if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
+       if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) != PHPDBG_IS_STOPPING) {
                if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) {
                        fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
                }
index 7aa8c4f9e084c2ba1dfafa001879da9ae11751b9..8ab4c8922a8463474232b8ee43e20683edb76f37 100644 (file)
@@ -278,6 +278,8 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) {
        dataptr->line[line] = endptr - data.buf;
        dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
 
+       phpdbg_resolve_pending_file_break(filename TSRMLS_CC);
+
        ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC);
 
        fake.opened_path = NULL;
index a4793f144f63e3a53017a0e9a88bbc9bfad255fc..365708c71ed1aade0b6faf439d448fa4aa4c7f7d 100644 (file)
@@ -1117,6 +1117,8 @@ PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, int fd, const char *tag, const
        }
 
        if (PHPDBG_G(err_buf).active && type != P_STDOUT && type != P_STDERR) {
+               phpdbg_free_err_buf(TSRMLS_C);
+
                PHPDBG_G(err_buf).type = type;
                PHPDBG_G(err_buf).fd = fd;
                PHPDBG_G(err_buf).tag = estrdup(tag);
index eca4c6ac2ba8d8f1c3188cd1edb05ae2be7d25c7..a2e4d41042d65386decfb0ad7abb4b8b9a97b5af 100644 (file)
@@ -28,7 +28,6 @@
 #include "phpdbg_print.h"
 #include "phpdbg_info.h"
 #include "phpdbg_break.h"
-#include "phpdbg_bp.h"
 #include "phpdbg_opcode.h"
 #include "phpdbg_list.h"
 #include "phpdbg_utils.h"
@@ -44,7 +43,6 @@
 ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
 ZEND_EXTERN_MODULE_GLOBALS(output);
 extern int phpdbg_startup_run;
-extern char *phpdbg_exec;
 
 #ifdef HAVE_LIBDL
 #ifdef PHP_WIN32
@@ -641,10 +639,10 @@ PHPDBG_COMMAND(run) /* {{{ */
                }
 
                zend_try {
-                       PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
+                       PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE;
+                       PHPDBG_G(flags) |= PHPDBG_IS_RUNNING;
                        zend_execute(EG(active_op_array) TSRMLS_CC);
-                       PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
-                       phpdbg_notice("stop", "type=\"normal\"", "Script ended normally");
+                       PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
                } zend_catch {
                        EG(active_op_array) = orig_op_array;
                        EG(opline_ptr) = orig_opline;
@@ -669,7 +667,11 @@ PHPDBG_COMMAND(run) /* {{{ */
                        EG(active_op_array) = orig_op_array;
                        EG(opline_ptr) = orig_opline;
                        EG(return_value_ptr_ptr) = orig_retval_ptr;
+
+                       phpdbg_clean(1 TSRMLS_CC);
                }
+
+               PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING;
        } else {
                phpdbg_error("inactive", "type=\"nocontext\"", "Nothing to execute!");
        }
@@ -1235,8 +1237,8 @@ int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */
 
        PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
 
-       while (1) {
-               if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
+       while (ret == SUCCESS || ret == FAILURE) {
+               if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_STOPPING) {
                        zend_bailout();
                }
 
@@ -1291,6 +1293,7 @@ int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */
                phpdbg_stack_free(&stack);
                phpdbg_destroy_input(&input TSRMLS_CC);
                PHPDBG_G(req_id) = 0;
+               input = NULL;
        }
 
        if (input) {
@@ -1320,10 +1323,6 @@ void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */
        }
 
        if (full) {
-               if (PHPDBG_G(exec)) {
-                       phpdbg_exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */
-               }
-
                PHPDBG_G(flags) |= PHPDBG_IS_CLEANING;
 
                zend_bailout();