summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Weinand <bobwei9@hotmail.com>2014-10-26 20:43:49 +0100
committerBob Weinand <bobwei9@hotmail.com>2014-10-27 00:00:16 +0100
commit510676fbbf6391b3f1931e99c2c043db79d3326d (patch)
treeaa35c78ef3dd1506d2d039d9900f0e291ee76cb8
parentaf9c6afa6f3465ae5b287af298fb148792f83d06 (diff)
downloadphp-git-510676fbbf6391b3f1931e99c2c043db79d3326d.tar.gz
Stabilize execution, always run destructors and extended file breakpoints
-rw-r--r--phpdbg.c104
-rw-r--r--phpdbg.h92
-rw-r--r--phpdbg_bp.c148
-rw-r--r--phpdbg_bp.h26
-rw-r--r--phpdbg_cmd.c2
-rw-r--r--phpdbg_list.c2
-rw-r--r--phpdbg_out.c2
-rw-r--r--phpdbg_prompt.c21
8 files changed, 268 insertions, 129 deletions
diff --git a/phpdbg.c b/phpdbg.c
index 493d8ec20c..3e31f76898 100644
--- a/phpdbg.c
+++ b/phpdbg.c
@@ -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);
diff --git a/phpdbg.h b/phpdbg.h
index 688ba7cdfc..57ea7ee570 100644
--- a/phpdbg.h
+++ b/phpdbg.h
@@ -116,6 +116,7 @@
#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
diff --git a/phpdbg_bp.c b/phpdbg_bp.c
index 81674a0daf..9333b353ce 100644
--- a/phpdbg_bp.c
+++ b/phpdbg_bp.c
@@ -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;
diff --git a/phpdbg_bp.h b/phpdbg_bp.h
index a6227cba6c..606085ddcf 100644
--- a/phpdbg_bp.h
+++ b/phpdbg_bp.h
@@ -23,16 +23,17 @@
/* {{{ 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);
diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c
index 13d5a0d634..a170d52955 100644
--- a/phpdbg_cmd.c
+++ b/phpdbg_cmd.c
@@ -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);
}
diff --git a/phpdbg_list.c b/phpdbg_list.c
index 7aa8c4f9e0..8ab4c8922a 100644
--- a/phpdbg_list.c
+++ b/phpdbg_list.c
@@ -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;
diff --git a/phpdbg_out.c b/phpdbg_out.c
index a4793f144f..365708c71e 100644
--- a/phpdbg_out.c
+++ b/phpdbg_out.c
@@ -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);
diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c
index eca4c6ac2b..a2e4d41042 100644
--- a/phpdbg_prompt.c
+++ b/phpdbg_prompt.c
@@ -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();