]> granicus.if.org Git - php/commitdiff
Send a \x03 during execution to interrupt (POSIX only)
authorBob Weinand <bobwei9@hotmail.com>
Sun, 28 Sep 2014 00:57:12 +0000 (02:57 +0200)
committerBob Weinand <bobwei9@hotmail.com>
Sun, 28 Sep 2014 00:57:12 +0000 (02:57 +0200)
12 files changed:
config.m4
phpdbg.c
phpdbg.h
phpdbg_cmd.c
phpdbg_opcode.c
phpdbg_prompt.c
phpdbg_prompt.h
phpdbg_sigsafe.c [new file with mode: 0644]
phpdbg_sigsafe.h [new file with mode: 0644]
phpdbg_utils.c
phpdbg_utils.h
zend_mm_structs.h [new file with mode: 0644]

index d78a439af0248014965b26d6535968e61da5af0c..24e997616286e63265393d83f9245aeeaf412f22 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -19,7 +19,7 @@ if test "$PHP_PHPDBG" != "no"; then
   fi
 
   PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
-  PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c"
+  PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c"
 
   if test "$PHP_READLINE" != "no" -o  "$PHP_LIBEDIT" != "no"; then
        PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS"
index e30d35d71fcd7c190a892ef395653b90d78d8e28..a72ddbb1839ba6ef0434e14a17dfeb9acf748ef3 100644 (file)
--- a/phpdbg.c
+++ b/phpdbg.c
@@ -36,6 +36,7 @@
 #      include <sys/select.h>
 #      include <sys/time.h>
 #      include <sys/types.h>
+#      include <sys/poll.h>
 #      include <netinet/in.h>
 #      include <unistd.h>
 #      include <arpa/inet.h>
@@ -69,10 +70,10 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
        pg->bp_count = 0;
        pg->flags = PHPDBG_DEFAULT_FLAGS;
        pg->oplog = NULL;
-       pg->io[PHPDBG_STDIN] = NULL;
-       pg->io[PHPDBG_STDOUT] = NULL;
-       pg->io[PHPDBG_STDERR] = NULL;
+       memset(pg->io, 0, sizeof(pg->io));
        pg->frame.num = 0;
+       pg->input_buflen = 0;
+       pg->sigsafe_mem.mem = NULL;
 } /* }}} */
 
 static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
@@ -529,7 +530,9 @@ static inline void php_sapi_phpdbg_flush(void *context)  /* {{{ */
        TSRMLS_FETCH();
 #endif
 
-       fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
+       if (!phpdbg_active_sigsafe_mem(TSRMLS_C)) {
+               fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
+       }
 } /* }}} */
 
 /* copied from sapi/cli/php_cli.c cli_register_file_handles */
@@ -698,17 +701,27 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */
 {
        TSRMLS_FETCH();
 
-       if (EG(in_execution)) {
-               /* set signalled only when not interactive */
-               if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
-                       PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
-               }
-       } else {
+       if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
                /* we quit remote consoles on recv SIGINT */
                if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
                        PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
                        zend_bailout();
                }
+       } else {
+               /* set signalled only when not interactive */
+               if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
+                       if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
+                               char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
+
+                               phpdbg_set_sigsafe_mem(mem TSRMLS_CC);
+                               zend_try {
+                                       phpdbg_force_interruption(TSRMLS_C);
+                               } zend_end_try()
+                               phpdbg_clear_sigsafe_mem(TSRMLS_C);
+                               return;
+                       }
+                       PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
+               }
        }
 } /* }}} */
 
@@ -769,12 +782,12 @@ static int phpdbg_remote_init(const char* address, short port, int *server, int
        *server = phpdbg_open_socket(address, port);
 
        if (*server < 0) {
-               phpdbg_rlog(stderr, "Initializing connection on %s:%d failed", address, port);
+               phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%d failed", address, port);
 
                return FAILURE;
        }
 
-       phpdbg_rlog(stderr, "accepting connections on %s:%d", address, port);
+       phpdbg_rlog(fileno(stderr), "accepting connections on %s:%d", address, port);
        {
                struct sockaddr_in address;
                socklen_t size = sizeof(address);
@@ -784,7 +797,7 @@ static int phpdbg_remote_init(const char* address, short port, int *server, int
                *socket = accept(*server, (struct sockaddr *) &address, &size);
                inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
 
-               phpdbg_rlog(stderr, "connection established from %s", buffer);
+               phpdbg_rlog(fileno(stderr), "connection established from %s", buffer);
        }
 
        dup2(*socket, fileno(stdout));
@@ -794,9 +807,61 @@ static int phpdbg_remote_init(const char* address, short port, int *server, int
 
        *stream = fdopen(*socket, "r+");
 
+       phpdbg_set_async_io(*socket);
+
        return SUCCESS;
 }
 
+/* This function *strictly* assumes that SIGIO is *only* used on the remote connection stream */
+void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */
+{
+       int flags;
+       size_t newlen;
+       size_t i;
+       TSRMLS_FETCH();
+
+//     if (!(info->si_band & POLLIN)) {
+//             return; /* Not interested in writeablility etc., just interested in incoming data */
+//     }
+
+       /* only non-blocking reading, avoid non-blocking writing */
+       flags = fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_GETFL, 0);
+       fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags | O_NONBLOCK);
+
+       do {
+               char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
+               size_t off = 0;
+
+               if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) {
+                       break;
+               }
+               for (i = 0; i < newlen; i++) {
+                       switch (mem[off + i]) {
+                               case '\x03': /* ^C char */
+                                       if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
+                                               break; /* or quit ??? */
+                                       }
+                                       if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
+                                               phpdbg_set_sigsafe_mem(mem TSRMLS_CC);
+                                               zend_try {
+                                                       phpdbg_force_interruption(TSRMLS_C);
+                                               } zend_end_try();
+                                               phpdbg_clear_sigsafe_mem(TSRMLS_C);
+                                               break;
+                                       }
+                                       if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
+                                               PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
+                                       }
+                                       break;
+                       }
+               }
+               off += i;
+       } while (0);
+
+
+       fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags);
+} /* }}} */
+
 void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
 {
        int is_handled = FAILURE;
@@ -890,9 +955,13 @@ int main(int argc, char **argv) /* {{{ */
 #endif
 
 #ifndef _WIN32
+       struct sigaction sigio_struct;
        struct sigaction signal_struct;
        signal_struct.sa_sigaction = phpdbg_signal_handler;
        signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
+       sigio_struct.sa_sigaction = phpdbg_sigio_handler;
+       sigio_struct.sa_flags = SA_SIGINFO;
+
 
        address = strdup("127.0.0.1");
 #endif
@@ -1105,18 +1174,6 @@ phpdbg_main:
                php_optind++;
        }
 
-#ifndef _WIN32
-       /* setup remote server if necessary */
-       if (!cleaning && listen > 0) {
-               if (phpdbg_remote_init(address, listen, &server, &socket, &stream) == FAILURE) {
-                       exit(0);
-               }
-
-               /* set remote flag to stop service shutting down upon quit */
-               remote = 1;
-       }
-#endif
-
        if (sapi_name) {
                phpdbg->name = sapi_name;
        }
@@ -1171,7 +1228,23 @@ phpdbg_main:
     EXCEPTION_POINTERS *xp;
     __try {
 #endif
-               zend_mm_heap *mm_heap = phpdbg_mm_get_heap();
+               zend_mm_heap *mm_heap;
+
+#ifndef _WIN32
+       /* setup remote server if necessary */
+       if (!cleaning && listen > 0) {
+               if (phpdbg_remote_init(address, listen, &server, &socket, &stream) == FAILURE) {
+                       exit(0);
+               }
+
+               sigaction(SIGIO, &sigio_struct, NULL);
+
+               /* set remote flag to stop service shutting down upon quit */
+               remote = 1;
+       }
+#endif
+
+               mm_heap = phpdbg_mm_get_heap();
 
                if (mm_heap->use_zend_alloc) {
                        mm_heap->_malloc = phpdbg_malloc_wrapper;
@@ -1246,9 +1319,12 @@ phpdbg_main:
                }
 #endif
 
-               PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
-               PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
-               PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
+               PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
+               PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin);
+               PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
+               PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
+               PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr;
+               PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr);
 
                if (exec) { /* set execution context */
                        PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);
index f9ca0f2a710fefa270073ab1f1219fb36cb740be..105614c8691c023755d99209a4e59d010dd52469 100644 (file)
--- a/phpdbg.h
+++ b/phpdbg.h
 #   include <editline/readline.h>
 #endif
 
+#ifdef ZTS
+# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
+#else
+# define PHPDBG_G(v) (phpdbg_globals.v)
+#endif
+
+#include "phpdbg_sigsafe.h"
 #include "phpdbg_lexer.h"
 #include "phpdbg_cmd.h"
 #include "phpdbg_utils.h"
 
 int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
 
-#ifdef ZTS
-# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
-#else
-# define PHPDBG_G(v) (phpdbg_globals.v)
-#endif
-
 #define PHPDBG_NEXT   2
 #define PHPDBG_UNTIL  3
 #define PHPDBG_FINISH 4
@@ -203,29 +204,21 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
        int vmret;                                   /* return from last opcode handler execution */
 
        FILE *oplog;                                 /* opline log */
-       FILE *io[PHPDBG_IO_FDS];                     /* io */
+       struct {
+               FILE *ptr;
+               int fd;
+       } io[PHPDBG_IO_FDS];                         /* io */
 
        char *prompt[2];                             /* prompt */
        const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */
        char *buffer;                                /* buffer */
        zend_bool last_was_newline;                  /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */
 
+       char input_buffer[PHPDBG_MAX_CMD];           /* stdin input buffer */
+       int input_buflen;                            /* length of stdin input buffer */
+       phpdbg_signal_safe_mem sigsafe_mem;          /* memory to use in async safe environment (only once!) */
+
        zend_ulong flags;                            /* phpdbg flags */
 ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
 
-/* the beginning (= the important part) of the _zend_mm_heap struct defined in Zend/zend_alloc.c
-   Needed for realizing watchpoints */
-struct _zend_mm_heap {
-       int   use_zend_alloc;
-       void *(*_malloc)(size_t);
-       void  (*_free)(void *);
-       void *(*_realloc)(void *, size_t);
-       size_t              free_bitmap;
-       size_t              large_free_bitmap;
-       size_t              block_size;
-       size_t              compact_size;
-       zend_mm_segment    *segments_list;
-       zend_mm_storage    *storage;
-};
-
 #endif /* PHPDBG_H */
index 8ca56aa25cced7aad72cf361f7a100d30f163c3c..0ea6c121271f034df5b543ed0cfaee57d2145bc0 100644 (file)
@@ -792,54 +792,71 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC)
 PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
 {
        char *cmd = NULL;
-#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT)
-       char buf[PHPDBG_MAX_CMD];
-#endif
        char *buffer = NULL;
 
        if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
-               if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) &&
-                       (buffered == NULL)) {
-                       fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
+               if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) {
+                       fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
                }
 
                if (buffered == NULL) {
-disconnect:
                        if (0) {
+disconnect:
                                PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
                                zend_bailout();
                                return NULL;
                        }
 
-#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT)
+#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) && defined(HAVE_LIBEDIT))
+#if !USE_LIB_STAR
                        if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
                                if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) {
                                        goto disconnect;
                                }
                                PHPDBG_G(last_was_newline) = 1;
                        }
-                       
-                       /* note: EOF is ignored */
-readline:      
-                       if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
-                               /* the user has gone away */
-                               if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
-                                       goto disconnect;
-                               } else goto readline;
-                       }
+#endif
 
-                       cmd = buf;
-#else
-                       /* note: EOF makes readline write prompt again in local console mode */
+                       /* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */
+                       /* strongly assuming to be in blocking mode... */
+#if USE_LIB_STAR
 readline:
-                       if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+                       if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE)
+#endif
+                       {
                                char buf[PHPDBG_MAX_CMD];
-                               if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
-                                       cmd = buf;
-                               } else goto disconnect;
-                       } else {
+                               int bytes = 0, len = PHPDBG_G(input_buflen);
+                               if (PHPDBG_G(input_buflen)) {
+                                       memcpy(buf, PHPDBG_G(input_buffer), len);
+                               }
+
+                               while ((bytes = read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len)) > 0) {
+                                       int i;
+                                       for (i = len; i < len + bytes; i++) {
+                                               if (buf[i] == '\n') {
+                                                       PHPDBG_G(input_buflen) = len + bytes - 1 - i;
+                                                       if (PHPDBG_G(input_buflen)) {
+                                                               memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen));
+                                                       }
+                                                       if (i != PHPDBG_MAX_CMD - 1) {
+                                                               buf[i + 1] = 0;
+                                                       }
+                                                       cmd = buf;
+                                                       goto end;
+                                               }
+                                       }
+                                       len += bytes;
+                               }
+
+                               if (bytes <= 0) {
+                                       goto disconnect;
+                               }
+
+                               cmd = buf;
+                       }
+#if USE_LIB_STAR
+                       else {
                                cmd = readline(phpdbg_get_prompt(TSRMLS_C));
-                               PHPDBG_G(last_was_newline) = 1;
                        }
 
                        if (!cmd) {
@@ -850,13 +867,15 @@ readline:
                                add_history(cmd);
                        }
 #endif
-               } else cmd = buffered;
-               
+               } else {
+                       cmd = buffered;
+               }
+end:
+               PHPDBG_G(last_was_newline) = 1;
                buffer = estrdup(cmd);
 
-#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
-               if (!buffered && cmd &&
-                       !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+#if USE_LIB_STAR
+               if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
                        free(cmd);
                }
 #endif
index 6b13625fc1417a4e0d8639c6edcdccb736d709ed..4edf4cfed25d41df1b7da0e25adca9f2d8d9c8b6 100644 (file)
@@ -162,7 +162,7 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, ze
                }
 
                if (!ignore_flags && PHPDBG_G(oplog)) {
-                       phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s",
+                       phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %-30s %s %s",
                                opline->lineno,
                                opline,
                                phpdbg_decode_opcode(opline->opcode),
index ed60e99c46869ab91794eb040059b2da7e65faa4..367926abd5f844c0b6966dda804e4c54f9848dd2 100644 (file)
@@ -1334,3 +1334,17 @@ next:
        }
        zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
 } /* }}} */
+
+void phpdbg_force_interruption(TSRMLS_D) {
+       zend_execute_data *data = EG(current_execute_data); /* should be always readable if not NULL */
+
+       if (data) {
+               if (data->op_array) {
+                       phpdbg_notice("Current opline: %p (op #%lu) in %s:%u", data->opline, (data->opline - data->op_array->opcodes) / sizeof(data->opline), data->op_array->filename, data->opline->lineno);
+               } else {
+                       phpdbg_notice("Current opline: %p (op_array information unavailable)", data->opline);
+               }
+       } else {
+               phpdbg_notice("No information available about executing context");
+       }
+}
index ef648aabeb08ad011979fb7673571eb35d567dd7..5909407e7dfa3547c5e6addcdea6b0e01a20d756 100644 (file)
@@ -64,4 +64,6 @@ void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC);
 void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC);
 #endif /* }}} */
 
+void phpdbg_force_interruption(TSRMLS_D);
+
 #endif /* PHPDBG_PROMPT_H */
diff --git a/phpdbg_sigsafe.c b/phpdbg_sigsafe.c
new file mode 100644 (file)
index 0000000..96ac713
--- /dev/null
@@ -0,0 +1,107 @@
+#include "phpdbg_sigsafe.h"
+#include "phpdbg.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+static inline void zend_mm_init(zend_mm_heap *heap) {
+       zend_mm_free_block *p;
+       int i;
+
+       heap->free_bitmap = 0;
+       heap->large_free_bitmap = 0;
+#if ZEND_MM_CACHE
+       heap->cached = 0;
+       memset(heap->cache, 0, sizeof(heap->cache));
+#endif
+#if ZEND_MM_CACHE_STAT
+       for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
+               heap->cache_stat[i].count = 0;
+       }
+#endif
+       p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
+       for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
+               p->next_free_block = p;
+               p->prev_free_block = p;
+               p = (zend_mm_free_block *)((char *)p + sizeof(zend_mm_free_block *) * 2);
+               heap->large_free_buckets[i] = NULL;
+       }
+       heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap);
+       heap->rest_count = 0;
+}
+
+static zend_mm_storage* zend_mm_mem_init(void *params) {
+       TSRMLS_FETCH();
+
+       return &PHPDBG_G(sigsafe_mem).storage;
+}
+
+static void zend_mm_mem_dummy(zend_mm_storage *storage) {
+}
+
+#define STR(x) #x
+#define EXP_STR(x) STR(x)
+
+static zend_mm_segment* zend_mm_mem_alloc(zend_mm_storage *storage, size_t size) {
+       TSRMLS_FETCH();
+
+       if (EXPECTED(size == PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) {
+               PHPDBG_G(sigsafe_mem).allocated = 1;
+               return (zend_mm_segment *) PHPDBG_G(sigsafe_mem).mem;
+       }
+
+       write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Tried to allocate more than " EXP_STR(PHPDBG_SIGSAFE_MEM_SIZE) " bytes from stack memory in signal handler ... bailing out of signal handler\n"));
+
+       if (*EG(bailout)) {
+               LONGJMP(*EG(bailout), FAILURE);
+       }
+
+       write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n"));
+
+       return NULL;
+}
+
+static zend_mm_segment* zend_mm_mem_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size) {
+       return zend_mm_mem_alloc(storage, size);
+}
+
+static void zend_mm_mem_free(zend_mm_storage *storage, zend_mm_segment *ptr) {
+}
+
+static const zend_mm_mem_handlers phpdbg_handlers_sigsafe_mem = { "stack", zend_mm_mem_init, zend_mm_mem_dummy, zend_mm_mem_dummy, zend_mm_mem_alloc, zend_mm_mem_realloc, zend_mm_mem_free };
+
+void phpdbg_set_sigsafe_mem(char *buffer TSRMLS_DC) {
+       phpdbg_signal_safe_mem *mem = &PHPDBG_G(sigsafe_mem);
+       mem->old_heap = zend_mm_set_heap(&mem->heap TSRMLS_CC);
+       mem->mem = buffer;
+       mem->allocated = 0;
+
+       mem->storage.handlers = &phpdbg_handlers_sigsafe_mem;
+       mem->heap.storage = &mem->storage;
+       mem->heap.block_size = PHPDBG_SIGSAFE_MEM_SIZE;
+       mem->heap.compact_size = 0;
+       mem->heap.segments_list = NULL;
+       zend_mm_init(&mem->heap);
+#if ZEND_MM_CACHE_STAT
+       memset(mem->heap.cache_stat, 0, sizeof(mem->heap.cache_stat));
+#endif
+       mem->heap.use_zend_alloc = 1;
+       mem->heap.real_size = 0;
+       mem->heap.overflow = 0;
+       mem->heap.real_peak = 0;
+       mem->heap.limit = PHPDBG_SIGSAFE_MEM_SIZE;
+       mem->heap.size = 0;
+       mem->heap.peak = 0;
+       mem->heap.internal = 0;
+       mem->heap.reserve = NULL;
+       mem->heap.reserve_size = 0;
+}
+
+void phpdbg_clear_sigsafe_mem(TSRMLS_D) {
+       PHPDBG_G(sigsafe_mem).mem = NULL;
+       zend_mm_set_heap(PHPDBG_G(sigsafe_mem).old_heap TSRMLS_CC);
+}
+
+zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D) {
+       return !!PHPDBG_G(sigsafe_mem).mem;
+}
+
diff --git a/phpdbg_sigsafe.h b/phpdbg_sigsafe.h
new file mode 100644 (file)
index 0000000..810e07c
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef PHPDBG_SIGSAFE_H
+#define PHPDBG_SIGSAFE_H
+
+#include "zend_mm_structs.h"
+
+#define PHPDBG_SIGSAFE_MEM_SIZE (1 << 20)
+
+typedef struct {
+       char *mem;
+       zend_bool allocated;;
+       zend_mm_heap heap;
+       zend_mm_heap *old_heap;
+       zend_mm_storage storage;
+} phpdbg_signal_safe_mem;
+
+#include "phpdbg.h"
+
+zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D);
+
+void phpdbg_set_sigsafe_mem(char *mem TSRMLS_DC);
+void phpdbg_clear_sigsafe_mem(TSRMLS_D);
+
+#endif
index 22a7b56282507a71aea596069f1a5007f924dac2..4d3eb4cde68d2ff03bfcfc7668329b3dd9f28ea6 100644 (file)
@@ -224,10 +224,9 @@ PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{
 
 } /* }}} */
 
-PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */
-{
+PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *format, ...) { /* {{{ */
        int rc = 0;
-       char *buffer = NULL;
+       char *buffer = NULL, *outbuf = NULL;
        va_list args;
 
        if (format != NULL && strlen(format) > 0L) {
@@ -241,44 +240,41 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ..
        switch (type) {
                case P_ERROR:
                        if (!PHPDBG_G(last_was_newline)) {
-                               fprintf(fp, "\n");
+                               write(fd, "\n", 1);
                                PHPDBG_G(last_was_newline) = 1;
                        }
                        if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
-                               rc = fprintf(fp,
-                                               "\033[%sm[%s]\033[0m\n",
-                                               PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer);
+                               rc = spprintf(&outbuf, 0, "\033[%sm[%s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer);
                        } else {
-                               rc = fprintf(fp, "[%s]\n", buffer);
+                               rc = spprintf(&outbuf, 0, "[%s]\n", buffer);
                        }
                break;
 
                case P_NOTICE:
                        if (!PHPDBG_G(last_was_newline)) {
-                               fprintf(fp, "\n");
+                               write(fd, "\n", 1);
                                PHPDBG_G(last_was_newline) = 1;
                        }
                        if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
-                               rc = fprintf(fp,
-                                               "\033[%sm[%s]\033[0m\n",
-                                               PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer);
+                               rc = spprintf(&outbuf, 0, "\033[%sm[%s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer);
                        } else {
-                               rc = fprintf(fp, "[%s]\n", buffer);
+                               rc = spprintf(&outbuf, 0, "[%s]\n", buffer);
                        }
                break;
 
                case P_WRITELN: {
                        if (buffer) {
-                               rc = fprintf(fp, "%s\n", buffer);
+                               rc = spprintf(&outbuf, 0, "%s\n", buffer);
                        } else {
-                               rc = fprintf(fp, "\n");
+                               rc = 1;
+                               outbuf = estrdup("\n");
                        }
                        PHPDBG_G(last_was_newline) = 1;
                } break;
 
                case P_WRITE:
                        if (buffer) {
-                               rc = fprintf(fp, "%s", buffer);
+                               rc = spprintf(&outbuf, 0, "%s", buffer);
                                PHPDBG_G(last_was_newline) = buffer[strlen(buffer) - 1] == '\n';
                        }
                break;
@@ -288,7 +284,7 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ..
                        if (buffer) {
                                struct timeval tp;
                                if (gettimeofday(&tp, NULL) == SUCCESS) {
-                                       rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer);
+                                       rc = spprintf(&outbuf, 0, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer);
                                } else {
                                        rc = FAILURE;
                                }
@@ -296,6 +292,11 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ..
                        break;
        }
 
+       if (outbuf) {
+               rc = write(fd, outbuf, rc);
+               efree(outbuf);
+       }
+
        if (buffer) {
                efree(buffer);
        }
@@ -303,7 +304,7 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ..
        return rc;
 } /* }}} */
 
-PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
+PHPDBG_API int phpdbg_rlog(int fd, const char *fmt, ...) { /* {{{ */
        int rc = 0;
 
        va_list args;
@@ -312,19 +313,21 @@ PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
        va_start(args, fmt);
        if (gettimeofday(&tp, NULL) == SUCCESS) {
                char friendly[100];
-               char *format = NULL, *buffer = NULL;
+               char *format = NULL, *buffer = NULL, *outbuf = NULL;
                const time_t tt = tp.tv_sec;
 
                strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt));
-               asprintf(
-                       &buffer, friendly, tp.tv_usec/1000);
-               asprintf(
-                       &format, "[%s]: %s\n", buffer, fmt);
-               rc = vfprintf(
-                       fp, format, args);
+               spprintf(&buffer, 0,  friendly, tp.tv_usec/1000);
+               spprintf(&format, 0, "[%s]: %s\n", buffer, fmt);
+               rc = vspprintf(&outbuf, 0, format, args);
 
-               free(format);
-               free(buffer);
+               if (outbuf) {
+                       rc = write(fd, outbuf, rc);
+                       efree(outbuf);
+               }
+
+               efree(format);
+               efree(buffer);
        }
        va_end(args);
 
@@ -463,3 +466,12 @@ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */
 #endif
        return columns;
 } /* }}} */
+
+PHPDBG_API void phpdbg_set_async_io(int fd) {
+#ifndef _WIN32
+       int flags;
+       fcntl(STDIN_FILENO, F_SETOWN, getpid());
+       flags = fcntl(STDIN_FILENO, F_GETFL);
+       fcntl(STDIN_FILENO, F_SETFL, flags | FASYNC);
+#endif
+}
index 56bacfc45961c5491498f085e011b41bbf882fef..9686d769480a7457fb2538e0b3a08e198b1f9fec 100644 (file)
@@ -45,18 +45,18 @@ enum {
 };
 
 #ifdef ZTS
-PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5);
+PHPDBG_API int phpdbg_print(int severity TSRMLS_DC, int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5);
 #else
-PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
+PHPDBG_API int phpdbg_print(int severity TSRMLS_DC, int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
 #endif
 
-PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...);
+PHPDBG_API int phpdbg_rlog(int fd, const char *fmt, ...);
 
-#define phpdbg_error(fmt, ...)              phpdbg_print(P_ERROR   TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
-#define phpdbg_notice(fmt, ...)             phpdbg_print(P_NOTICE  TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
-#define phpdbg_writeln(fmt, ...)            phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
-#define phpdbg_write(fmt, ...)              phpdbg_print(P_WRITE   TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
-#define phpdbg_log(fmt, ...)                phpdbg_print(P_LOG     TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
+#define phpdbg_error(fmt, ...)              phpdbg_print(P_ERROR   TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
+#define phpdbg_notice(fmt, ...)             phpdbg_print(P_NOTICE  TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
+#define phpdbg_writeln(fmt, ...)            phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
+#define phpdbg_write(fmt, ...)              phpdbg_print(P_WRITE   TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
+#define phpdbg_log(fmt, ...)                phpdbg_print(P_LOG     TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
 
 #define phpdbg_error_ex(out, fmt, ...)      phpdbg_print(P_ERROR   TSRMLS_CC, out, fmt, ##__VA_ARGS__)
 #define phpdbg_notice_ex(out, fmt, ...)     phpdbg_print(P_NOTICE  TSRMLS_CC, out, fmt, ##__VA_ARGS__)
@@ -65,7 +65,7 @@ PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...);
 #define phpdbg_log_ex(out, fmt, ...)        phpdbg_print(P_LOG     TSRMLS_CC, out, fmt, ##__VA_ARGS__)
 
 #if PHPDBG_DEBUG
-#      define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG   TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__)
+#      define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG   TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR].fd, fmt, ##__VA_ARGS__)
 #else
 #      define phpdbg_debug(fmt, ...)
 #endif
@@ -122,6 +122,8 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */
 /* {{{ Console Width */
 PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */
 
+PHPDBG_API void phpdbg_set_async_io(int fd);
+
 int phpdbg_rebuild_symtable(TSRMLS_D);
 
 #if PHP_VERSION_ID < 50500
diff --git a/zend_mm_structs.h b/zend_mm_structs.h
new file mode 100644 (file)
index 0000000..ca64069
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef ZEND_MM_STRUCTS_H
+#define ZEND_MM_STRUCTS_H
+
+/* structs and macros defined in Zend/zend_alloc.c
+   Needed for realizing watchpoints and sigsafe memory */
+
+#include "zend.h"
+
+#ifndef ZEND_MM_COOKIES
+#      define ZEND_MM_COOKIES ZEND_DEBUG
+#endif
+
+#define ZEND_MM_CACHE 1
+#ifndef ZEND_MM_CACHE_STAT
+#      define ZEND_MM_CACHE_STAT 0
+#endif
+
+typedef struct _zend_mm_block_info {
+#if ZEND_MM_COOKIES
+       size_t _cookie;
+#endif
+       size_t _size;
+       size_t _prev;
+} zend_mm_block_info;
+
+typedef struct _zend_mm_small_free_block {
+       zend_mm_block_info info;
+#if ZEND_DEBUG
+       unsigned int magic;
+#ifdef ZTS
+       THREAD_T thread_id;
+#endif
+#endif
+       struct _zend_mm_free_block *prev_free_block;
+       struct _zend_mm_free_block *next_free_block;
+} zend_mm_small_free_block;
+
+typedef struct _zend_mm_free_block {
+       zend_mm_block_info info;
+#if ZEND_DEBUG
+       unsigned int magic;
+#ifdef ZTS
+       THREAD_T thread_id;
+#endif
+#endif
+       struct _zend_mm_free_block *prev_free_block;
+       struct _zend_mm_free_block *next_free_block;
+
+       struct _zend_mm_free_block **parent;
+       struct _zend_mm_free_block *child[2];
+} zend_mm_free_block;
+
+#define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
+       (zend_mm_free_block *) ((char *)&heap->free_buckets[index * 2] + \
+               sizeof(zend_mm_free_block *) * 2 - \
+               sizeof(zend_mm_small_free_block))
+
+#define ZEND_MM_REST_BUCKET(heap) \
+       (zend_mm_free_block *)((char *)&heap->rest_buckets[0] + \
+               sizeof(zend_mm_free_block *) * 2 - \
+               sizeof(zend_mm_small_free_block))
+
+#define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
+struct _zend_mm_heap {
+       int   use_zend_alloc;
+       void *(*_malloc)(size_t);
+       void  (*_free)(void *);
+       void *(*_realloc)(void *, size_t);
+       size_t              free_bitmap;
+       size_t              large_free_bitmap;
+       size_t              block_size;
+       size_t              compact_size;
+       zend_mm_segment    *segments_list;
+       zend_mm_storage    *storage;
+       size_t              real_size;
+       size_t              real_peak;
+       size_t              limit;
+       size_t              size;
+       size_t              peak;
+       size_t              reserve_size;
+       void               *reserve;
+       int                 overflow;
+       int                 internal;
+#if ZEND_MM_CACHE
+       unsigned int        cached;
+       zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
+#endif
+       zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
+       zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
+       zend_mm_free_block *rest_buckets[2];
+       int                 rest_count;
+#if ZEND_MM_CACHE_STAT
+       struct {
+               int count;
+               int max_count;
+               int hit;
+               int miss;
+       } cache_stat[ZEND_MM_NUM_BUCKETS+1];
+#endif
+};
+
+#endif