From: Bob Weinand Date: Sun, 28 Sep 2014 00:57:12 +0000 (+0200) Subject: Send a \x03 during execution to interrupt (POSIX only) X-Git-Tag: php-5.6.3RC1~51^2~70 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b183494f376adadeb332c5644e230c226b2ebb04;p=php Send a \x03 during execution to interrupt (POSIX only) --- diff --git a/config.m4 b/config.m4 index d78a439af0..24e9976162 100644 --- 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" diff --git a/phpdbg.c b/phpdbg.c index e30d35d71f..a72ddbb183 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -36,6 +36,7 @@ # include # include # include +# include # include # include # include @@ -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); diff --git a/phpdbg.h b/phpdbg.h index f9ca0f2a71..105614c869 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -72,6 +72,13 @@ # include #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" @@ -80,12 +87,6 @@ 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 */ diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index 8ca56aa25c..0ea6c12127 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -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 diff --git a/phpdbg_opcode.c b/phpdbg_opcode.c index 6b13625fc1..4edf4cfed2 100644 --- a/phpdbg_opcode.c +++ b/phpdbg_opcode.c @@ -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), diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index ed60e99c46..367926abd5 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -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"); + } +} diff --git a/phpdbg_prompt.h b/phpdbg_prompt.h index ef648aabeb..5909407e7d 100644 --- a/phpdbg_prompt.h +++ b/phpdbg_prompt.h @@ -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 index 0000000000..96ac713f23 --- /dev/null +++ b/phpdbg_sigsafe.c @@ -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 index 0000000000..810e07c789 --- /dev/null +++ b/phpdbg_sigsafe.h @@ -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 diff --git a/phpdbg_utils.c b/phpdbg_utils.c index 22a7b56282..4d3eb4cde6 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -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 +} diff --git a/phpdbg_utils.h b/phpdbg_utils.h index 56bacfc459..9686d76948 100644 --- a/phpdbg_utils.h +++ b/phpdbg_utils.h @@ -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 index 0000000000..ca64069e0f --- /dev/null +++ b/zend_mm_structs.h @@ -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