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"
# 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>
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) /* {{{ */
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 */
{
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;
+ }
}
} /* }}} */
*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);
*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));
*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;
#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
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;
}
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;
}
#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);
# 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
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 */
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) {
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
}
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),
}
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");
+ }
+}
void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC);
#endif /* }}} */
+void phpdbg_force_interruption(TSRMLS_D);
+
#endif /* PHPDBG_PROMPT_H */
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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
} /* }}} */
-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) {
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;
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;
}
break;
}
+ if (outbuf) {
+ rc = write(fd, outbuf, rc);
+ efree(outbuf);
+ }
+
if (buffer) {
efree(buffer);
}
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;
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);
#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
+}
};
#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__)
#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
/* {{{ 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
--- /dev/null
+#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