summaryrefslogtreecommitdiff
path: root/sapi/phpdbg/phpdbg.c
diff options
context:
space:
mode:
Diffstat (limited to 'sapi/phpdbg/phpdbg.c')
-rw-r--r--sapi/phpdbg/phpdbg.c737
1 files changed, 316 insertions, 421 deletions
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c
index 2f0ed2eab6..fa6f843432 100644
--- a/sapi/phpdbg/phpdbg.c
+++ b/sapi/phpdbg/phpdbg.c
@@ -28,9 +28,7 @@
#include "phpdbg_list.h"
#include "phpdbg_utils.h"
#include "phpdbg_set.h"
-#include "phpdbg_io.h"
#include "zend_alloc.h"
-#include "phpdbg_eol.h"
/* {{{ remote console headers */
#ifndef _WIN32
@@ -38,28 +36,12 @@
# 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>
#endif /* }}} */
ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
-int phpdbg_startup_run = 0;
-
-static PHP_INI_MH(OnUpdateEol)
-{
- if (!new_value) {
- return FAILURE;
- }
-
- return phpdbg_eol_global_update(new_value TSRMLS_CC);
-}
-
-PHP_INI_BEGIN()
- STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, socket_path, zend_phpdbg_globals, phpdbg_globals)
- STD_PHP_INI_ENTRY("phpdbg.eol", "2", PHP_INI_ALL, OnUpdateEol, socket_path, zend_phpdbg_globals, phpdbg_globals)
-PHP_INI_END()
static zend_bool phpdbg_booted = 0;
@@ -81,39 +63,20 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
pg->exec = NULL;
pg->exec_len = 0;
pg->buffer = NULL;
- pg->last_was_newline = 1;
pg->ops = NULL;
pg->vmret = 0;
pg->bp_count = 0;
pg->flags = PHPDBG_DEFAULT_FLAGS;
pg->oplog = NULL;
- memset(pg->io, 0, sizeof(pg->io));
+ pg->io[PHPDBG_STDIN] = NULL;
+ pg->io[PHPDBG_STDOUT] = NULL;
+ pg->io[PHPDBG_STDERR] = NULL;
pg->frame.num = 0;
- pg->sapi_name_ptr = NULL;
- pg->socket_fd = -1;
- pg->socket_server_fd = -1;
-
- pg->req_id = 0;
- pg->err_buf.active = 0;
- pg->err_buf.type = 0;
-
- pg->input_buflen = 0;
- pg->sigsafe_mem.mem = NULL;
- pg->sigsegv_bailout = NULL;
-
-#ifdef PHP_WIN32
- pg->sigio_watcher_thread = INVALID_HANDLE_VALUE;
- memset(&pg->swd, 0, sizeof(struct win32_sigio_watcher_data));
-#endif
-
- pg->eol = PHPDBG_EOL_LF;
} /* }}} */
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
{
ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
- REGISTER_INI_ENTRIES();
-
#if PHP_VERSION_ID >= 50500
zend_execute_old = zend_execute_ex;
zend_execute_ex = phpdbg_execute_ex;
@@ -123,7 +86,7 @@ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
#endif
REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT);
-
+
REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT);
@@ -185,8 +148,7 @@ 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_PENDING], 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_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,7 +178,6 @@ 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(file_sources));
zend_hash_destroy(&PHPDBG_G(registered));
zend_hash_destroy(&PHPDBG_G(watchpoints));
zend_llist_destroy(&PHPDBG_G(watchlist_mem));
@@ -225,7 +186,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
efree(PHPDBG_G(buffer));
PHPDBG_G(buffer) = NULL;
}
-
+
if (PHPDBG_G(exec)) {
efree(PHPDBG_G(exec));
PHPDBG_G(exec) = NULL;
@@ -265,7 +226,7 @@ static PHP_FUNCTION(phpdbg_exec)
{
char *exec = NULL;
int exec_len = 0;
-
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) {
return;
}
@@ -363,7 +324,6 @@ 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]);
@@ -378,7 +338,7 @@ static PHP_FUNCTION(phpdbg_color)
{
long element = 0L;
char *color = NULL;
- size_t color_len = 0;
+ int color_len = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) {
return;
@@ -399,7 +359,7 @@ static PHP_FUNCTION(phpdbg_color)
static PHP_FUNCTION(phpdbg_prompt)
{
char *prompt = NULL;
- size_t prompt_len = 0;
+ int prompt_len = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) {
return;
@@ -511,12 +471,7 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
* We must not request TSRM before being boot
*/
if (phpdbg_booted) {
- if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) {
- phpdbg_error("eval", "msg=\"%s\"", "%s", message);
- return;
- }
-
- phpdbg_error("php", "msg=\"%s\"", "%s", message);
+ phpdbg_error("%s", message);
switch (PG(last_error_type)) {
case E_ERROR:
@@ -525,17 +480,25 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
case E_USER_ERROR:
case E_PARSE:
case E_RECOVERABLE_ERROR:
- phpdbg_list_file(zend_get_executed_filename(TSRMLS_C), 3, zend_get_executed_lineno(TSRMLS_C)-1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
+ if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
+ phpdbg_list_file(
+ zend_get_executed_filename(TSRMLS_C),
+ 3,
+ zend_get_executed_lineno(TSRMLS_C)-1,
+ zend_get_executed_lineno(TSRMLS_C)
+ TSRMLS_CC
+ );
+ }
do {
- switch (phpdbg_interactive(1 TSRMLS_CC)) {
+ switch (phpdbg_interactive(TSRMLS_C)) {
case PHPDBG_LEAVE:
case PHPDBG_FINISH:
case PHPDBG_UNTIL:
case PHPDBG_NEXT:
return;
}
- } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
+ } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
}
} else fprintf(stdout, "%s\n", message);
@@ -544,27 +507,11 @@ 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_STOPPING) == PHPDBG_IS_CLEANING) {
- zend_phpdbg_globals *pg = PHPDBG_G(backup) = calloc(1, sizeof(zend_phpdbg_globals));
-
- php_phpdbg_globals_ctor(pg);
-
- pg->exec = zend_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];
- memcpy(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;
}
/* }}} */
@@ -614,42 +561,9 @@ static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {
static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */
{
- if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
- send(PHPDBG_G(socket_fd), message, length, 0);
- }
- return phpdbg_script(P_STDOUT, "%.*s", length, message);
+ return phpdbg_write("%s", message);
} /* }}} */
-/* beginning of struct, see main/streams/plain_wrapper.c line 111 */
-typedef struct {
- FILE *file;
- int fd;
-} php_stdio_stream_data;
-
-static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) {
- php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
-
- while (data->fd >= 0) {
- struct stat stat[3];
- memset(stat, 0, sizeof(stat));
- if (((fstat(fileno(stderr), &stat[2]) < 0) & (fstat(fileno(stdout), &stat[0]) < 0)) | (fstat(data->fd, &stat[1]) < 0)) {
- break;
- }
-
- if (stat[0].st_dev == stat[1].st_dev && stat[0].st_ino == stat[1].st_ino) {
- phpdbg_script(P_STDOUT, "%.*s", (int) count, buf);
- return count;
- }
- if (stat[2].st_dev == stat[1].st_dev && stat[2].st_ino == stat[1].st_ino) {
- phpdbg_script(P_STDERR, "%.*s", (int) count, buf);
- return count;
- }
- break;
- }
-
- return PHPDBG_G(php_stdiop_write)(stream, buf, count TSRMLS_CC);
-}
-
#if PHP_VERSION_ID >= 50700
static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC) /* {{{ */
{
@@ -659,9 +573,7 @@ static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
TSRMLS_FETCH();
#endif
- if (!phpdbg_active_sigsafe_mem(TSRMLS_C)) {
- fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
- }
+ fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
} /* }}} */
/* copied from sapi/cli/php_cli.c cli_register_file_handles */
@@ -777,10 +689,9 @@ const opt_struct OPTIONS[] = { /* {{{ */
{'r', 0, "run"},
{'E', 0, "step-through-eval"},
{'S', 1, "sapi-name"},
+#ifndef _WIN32
{'l', 1, "listen"},
{'a', 1, "address-or-any"},
-#if PHPDBG_IN_DEV
- {'x', 0, "xml output"},
#endif
{'V', 0, "version"},
{'-', 0, NULL}
@@ -814,25 +725,17 @@ static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */
{
/* print blurb */
if (!cleaning) {
- phpdbg_xml("<intros>");
- phpdbg_notice("intro", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
- phpdbg_writeln("intro", "help=\"help\"", "To get help using phpdbg type \"help\" and press enter");
- phpdbg_notice("intro", "report=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES);
- phpdbg_xml("</intros>");
- } else if (phpdbg_startup_run == 0) {
- if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
- phpdbg_notice(NULL, NULL, "Clean Execution Environment");
- }
+ phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
+ PHPDBG_VERSION);
+ phpdbg_writeln("To get help using phpdbg type \"help\" and press enter");
+ phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
+ } else {
+ phpdbg_notice("Clean Execution Environment");
- phpdbg_write("cleaninfo", "classes=\"%d\" functions=\"%d\" constants=\"%d\" includes=\"%d\"",
- "Classes %d\n"
- "Functions %d\n"
- "Constants %d\n"
- "Includes %d\n",
- zend_hash_num_elements(EG(class_table)),
- zend_hash_num_elements(EG(function_table)),
- zend_hash_num_elements(EG(zend_constants)),
- zend_hash_num_elements(&EG(included_files)));
+ phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table)));
+ phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table)));
+ phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants)));
+ phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files)));
}
} /* }}} */
@@ -840,130 +743,163 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */
{
TSRMLS_FETCH();
- 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_STOPPING;
- zend_bailout();
- }
- } else {
+ if (EG(in_execution)) {
/* 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;
}
+ } else {
+ /* we quit remote consoles on recv SIGINT */
+ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+ zend_bailout();
+ }
}
} /* }}} */
+#ifndef _WIN32
+int phpdbg_open_socket(const char *interface, short port) /* {{{ */
+{
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ switch (fd) {
+ case -1:
+ return -1;
+
+ default: {
+ int reuse = 1;
+
+ switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) {
+ case -1:
+ close(fd);
+ return -2;
+
+ default: {
+ struct sockaddr_in address;
+
+ memset(&address, 0, sizeof(address));
+
+ address.sin_port = htons(port);
+ address.sin_family = AF_INET;
+
+ if ((*interface == '*')) {
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+ } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) {
+ close(fd);
+ return -3;
+ }
-static void phpdbg_remote_close(int socket, FILE *stream) {
- if (socket >= 0) {
- phpdbg_close_socket(socket);
+ switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) {
+ case -1:
+ close(fd);
+ return -4;
+
+ default: {
+ listen(fd, 5);
+ }
+ }
+ }
+ }
+ }
}
- if (stream) {
- fclose(stream);
+ return fd;
+} /* }}} */
+
+static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */
+{
+ if ((*socket)[0] >= 0) {
+ shutdown(
+ (*socket)[0], SHUT_RDWR);
+ close((*socket)[0]);
}
-}
-/* don't inline this, want to debug it easily, will inline when done */
-static int phpdbg_remote_init(const char* address, unsigned short port, int server, int *socket, FILE **stream TSRMLS_DC) {
- phpdbg_remote_close(*socket, *stream);
+ if (streams[0]) {
+ fclose(streams[0]);
+ }
- if (server < 0) {
- phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%u failed", address, port);
+ if ((*socket)[1] >= 0) {
+ shutdown(
+ (*socket)[1], SHUT_RDWR);
+ close((*socket)[1]);
+ }
- return FAILURE;
+ if (streams[1]) {
+ fclose(streams[1]);
}
+} /* }}} */
- phpdbg_rlog(fileno(stderr), "accepting connections on %s:%u", address, port);
- {
- struct sockaddr_storage address;
- socklen_t size = sizeof(address);
- char buffer[20] = {0};
- /* XXX error checks */
- memset(&address, 0, size);
- *socket = accept(server, (struct sockaddr *) &address, &size);
- inet_ntop(AF_INET, &(((struct sockaddr_in *)&address)->sin_addr), buffer, sizeof(buffer));
+/* don't inline this, want to debug it easily, will inline when done */
- phpdbg_rlog(fileno(stderr), "connection established from %s", buffer);
+int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */
+{
+ if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) {
+ ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]);
+ ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]);
}
-#ifndef _WIN32
- dup2(*socket, fileno(stdout));
- dup2(*socket, fileno(stdin));
+ streams[0] = NULL;
+ streams[1] = NULL;
- setbuf(stdout, NULL);
+ if ((*listen)[0] < 0 || (*listen)[1] < 0) {
+ if ((*listen)[0] < 0) {
+ phpdbg_rlog(stderr,
+ "console failed to initialize (stdin) on %s:%d", address, port[0]);
+ }
- *stream = fdopen(*socket, "r+");
+ if ((*listen)[1] < 0) {
+ phpdbg_rlog(stderr,
+ "console failed to initialize (stdout) on %s:%d", address, port[1]);
+ }
- phpdbg_set_async_io(*socket);
-#endif
- return SUCCESS;
-}
+ if ((*listen)[0] >= 0) {
+ close((*listen)[0]);
+ }
-#ifndef _WIN32
-/* 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/*, last_nl*/;
- TSRMLS_FETCH();
+ if ((*listen)[1] >= 0) {
+ close((*listen)[1]);
+ }
-// if (!(info->si_band & POLLIN)) {
-// return; /* Not interested in writeablility etc., just interested in incoming data */
-// }
+ return FAILURE;
+ }
- /* 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);
+ phpdbg_close_sockets(socket, streams);
+
+ phpdbg_rlog(stderr,
+ "accepting connections on %s:%d/%d", address, port[0], port[1]);
+ {
+ struct sockaddr_in address;
+ socklen_t size = sizeof(address);
+ char buffer[20] = {0};
- do {
- char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
- size_t off = 0;
+ {
+ memset(&address, 0, size);
+ (*socket)[0] = accept(
+ (*listen)[0], (struct sockaddr *) &address, &size);
+ inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
- if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) {
- break;
+ phpdbg_rlog(stderr, "connection (stdin) from %s", buffer);
}
- 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;
-/* case '\n':
- zend_llist_add_element(PHPDBG_G(stdin), strndup()
- last_nl = PHPDBG_G(stdin_buf).len + i;
- break;
-*/ }
+
+ {
+ memset(&address, 0, size);
+ (*socket)[1] = accept(
+ (*listen)[1], (struct sockaddr *) &address, &size);
+ inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
+
+ phpdbg_rlog(stderr, "connection (stdout) from %s", buffer);
}
- off += i;
- } while (0);
+ }
+ dup2((*socket)[0], fileno(stdin));
+ dup2((*socket)[1], fileno(stdout));
- fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags);
+ setbuf(stdout, NULL);
+
+ streams[0] = fdopen((*socket)[0], "r");
+ streams[1] = fdopen((*socket)[1], "w");
+
+ return SUCCESS;
} /* }}} */
void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
@@ -974,9 +910,6 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
switch (sig) {
case SIGBUS:
case SIGSEGV:
- if (PHPDBG_G(sigsegv_bailout)) {
- LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE);
- }
is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC);
if (is_handled == FAILURE) {
#ifdef ZEND_SIGNALS
@@ -1028,7 +961,8 @@ int main(int argc, char **argv) /* {{{ */
zend_ulong zend_extensions_len = 0L;
zend_bool ini_ignore;
char *ini_override;
- char *exec = NULL;
+ char *exec;
+ size_t exec_len;
char *init_file;
size_t init_file_len;
zend_bool init_file_default;
@@ -1037,31 +971,44 @@ int main(int argc, char **argv) /* {{{ */
zend_ulong flags;
char *php_optarg;
int php_optind, opt, show_banner = 1;
- long cleaning = -1;
+ long cleaning = 0;
zend_bool remote = 0;
+ int run = 0;
int step = 0;
- zend_phpdbg_globals *settings = NULL;
- char *bp_tmp = NULL;
+
+#ifdef _WIN32
+ char *bp_tmp_file = NULL;
+#else
+ char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX";
+#endif
+
+#ifndef _WIN32
char *address;
- int listen = -1;
- int server = -1;
- int socket = -1;
- FILE* stream = NULL;
+ int listen[2];
+ int server[2];
+ int socket[2];
+ FILE* streams[2] = {NULL, NULL};
+#endif
#ifdef ZTS
void ***tsrm_ls;
#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;
-#endif
address = strdup("127.0.0.1");
+ socket[0] = -1;
+ socket[1] = -1;
+ listen[0] = -1;
+ listen[1] = -1;
+ server[0] = -1;
+ server[1] = -1;
+ streams[0] = NULL;
+ streams[1] = NULL;
+#endif
#ifdef PHP_WIN32
_fmode = _O_BINARY; /* sets default for file streams to binary */
@@ -1077,12 +1024,37 @@ int main(int argc, char **argv) /* {{{ */
#endif
phpdbg_main:
+ if (!cleaning) {
+
+#ifdef _WIN32
+ bp_tmp_file = malloc(L_tmpnam);
+
+ if (bp_tmp_file) {
+ if (!tmpnam(bp_tmp_file)) {
+ free(bp_tmp_file);
+ bp_tmp_file = NULL;
+ }
+ }
+
+ if (!bp_tmp_file) {
+ phpdbg_error("Unable to create temporary file");
+ return 1;
+ }
+#else
+ if (!mkstemp(bp_tmp_file)) {
+ memset(bp_tmp_file, 0, sizeof(bp_tmp_file));
+ }
+#endif
+
+ }
ini_entries = NULL;
ini_entries_len = 0;
ini_ignore = 0;
ini_override = NULL;
zend_extensions = NULL;
zend_extensions_len = 0L;
+ exec = NULL;
+ exec_len = 0;
init_file = NULL;
init_file_len = 0;
init_file_default = 1;
@@ -1092,16 +1064,14 @@ phpdbg_main:
php_optarg = NULL;
php_optind = 1;
opt = 0;
+ run = 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) {
case 'r':
- phpdbg_startup_run++;
+ run++;
break;
case 'n':
ini_ignore = 1;
@@ -1201,12 +1171,21 @@ phpdbg_main:
show_banner = 0;
break;
- /* if you pass a listen port, we will read and write on listen port */
- case 'l': /* set listen ports */
- if (sscanf(php_optarg, "%d", &listen) != 1) {
- listen = 8000;
+#ifndef _WIN32
+ /* if you pass a listen port, we will accept input on listen port */
+ /* and write output to listen port * 2 */
+
+ case 'l': { /* set listen ports */
+ if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) {
+ if (sscanf(php_optarg, "%d", &listen[0]) != 1) {
+ /* default to hardcoded ports */
+ listen[0] = 4000;
+ listen[1] = 8000;
+ } else {
+ listen[1] = (listen[0] * 2);
+ }
}
- break;
+ } break;
case 'a': { /* set bind address */
free(address);
@@ -1214,12 +1193,7 @@ phpdbg_main:
address = strdup("*");
} else address = strdup(php_optarg);
} break;
-
-#if PHPDBG_IN_DEV
- case 'x':
- flags |= PHPDBG_WRITE_XML;
#endif
- break;
case 'V': {
sapi_startup(phpdbg);
@@ -1240,8 +1214,10 @@ phpdbg_main:
}
/* set exec if present on command line */
- if (!exec && (argc > php_optind) && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
- if (strlen(argv[php_optind])) {
+ if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS))
+ {
+ exec_len = strlen(argv[php_optind]);
+ if (exec_len) {
if (exec) {
free(exec);
}
@@ -1250,6 +1226,19 @@ phpdbg_main:
php_optind++;
}
+#ifndef _WIN32
+ /* setup remote server if necessary */
+ if (!cleaning &&
+ (listen[0] > 0 && listen[1] > 0)) {
+ if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) {
+ remote = 0;
+ exit(0);
+ }
+ /* set remote flag to stop service shutting down upon quit */
+ remote = 1;
+ }
+#endif
+
if (sapi_name) {
phpdbg->name = sapi_name;
}
@@ -1304,35 +1293,7 @@ phpdbg_main:
EXCEPTION_POINTERS *xp;
__try {
#endif
- zend_mm_heap *mm_heap;
-
- /* 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 <= 0 && 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);
-#endif
-
- /* set remote flag to stop service shutting down upon quit */
- remote = 1;
- }
-
- mm_heap = phpdbg_mm_get_heap();
+ zend_mm_heap *mm_heap = phpdbg_mm_get_heap();
if (mm_heap->use_zend_alloc) {
mm_heap->_malloc = phpdbg_malloc_wrapper;
@@ -1343,8 +1304,6 @@ phpdbg_main:
zend_activate(TSRMLS_C);
- phpdbg_init_list(TSRMLS_C);
-
PHPDBG_G(original_free_function) = mm_heap->_free;
mm_heap->_free = phpdbg_watch_efree;
@@ -1364,30 +1323,27 @@ phpdbg_main:
sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
#endif
- PHPDBG_G(sapi_name_ptr) = sapi_name;
-
- php_output_activate(TSRMLS_C);
- php_output_deactivate(TSRMLS_C);
-
- php_output_activate(TSRMLS_C);
-
if (php_request_startup(TSRMLS_C) == SUCCESS) {
int i;
-
- SG(request_info).argc = argc - php_optind + 1;
+
+ SG(request_info).argc = argc - php_optind + 1;
SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *));
for (i = SG(request_info).argc; --i;) {
SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
}
- SG(request_info).argv[i] = exec ? estrdup(exec) : estrdup("");
+ SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup("");
php_hash_environment(TSRMLS_C);
}
+ /* make sure to turn off buffer for ev command */
+ php_output_activate(TSRMLS_C);
+ php_output_deactivate(TSRMLS_C);
+
/* do not install sigint handlers for remote consoles */
/* sending SIGINT then provides a decent way of shutting down the server */
#ifndef _WIN32
- if (listen < 0) {
+ if (listen[0] < 0) {
#endif
#if defined(ZEND_SIGNALS) && !defined(_WIN32)
zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try();
@@ -1400,57 +1356,34 @@ phpdbg_main:
PG(modules_activated) = 0;
+ /* set flags from command line */
+ PHPDBG_G(flags) = flags;
+
+#ifndef _WIN32
/* setup io here */
- if (remote) {
+ if (streams[0] && streams[1]) {
PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
-#ifndef _WIN32
- signal(SIGPIPE, SIG_IGN);
-#endif
- }
-#ifndef _WIN32
- 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);
-#else
- /* XXX this is a complete mess here with FILE/fd/SOCKET,
- we should let only one to survive probably. Need
- a clean separation whether it's a remote or local
- prompt. And what is supposed to go as user interaction,
- error log, etc. */
- if (remote) {
- PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
- PHPDBG_G(io)[PHPDBG_STDIN].fd = socket;
- PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
- PHPDBG_G(io)[PHPDBG_STDOUT].fd = socket;
- } else {
- 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);
+ signal(SIGPIPE, SIG_IGN);
}
#endif
- PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr;
- PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr);
-#ifndef _WIN32
- PHPDBG_G(php_stdiop_write) = php_stream_stdio_ops.write;
- php_stream_stdio_ops.write = phpdbg_stdiop_write;
-#endif
+ PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
+ PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
+ PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
if (exec) { /* set execution context */
PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);
- PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0;
+ PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
free(exec);
- exec = NULL;
}
if (oplog_file) { /* open oplog */
PHPDBG_G(oplog) = fopen(oplog_file, "w+");
if (!PHPDBG_G(oplog)) {
- phpdbg_error("oplog", "path=\"%s\"", "Failed to open oplog %s", oplog_file);
+ phpdbg_error(
+ "Failed to open oplog %s", oplog_file);
}
free(oplog_file);
}
@@ -1461,29 +1394,26 @@ phpdbg_main:
phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC);
/* set default prompt */
- phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT TSRMLS_CC);
+ phpdbg_set_prompt(PROMPT TSRMLS_CC);
/* Make stdin, stdout and stderr accessible from PHP scripts */
phpdbg_register_file_handles(TSRMLS_C);
- if (show_banner && cleaning < 2) {
+ if (show_banner) {
/* print blurb */
- phpdbg_welcome(cleaning == 1 TSRMLS_CC);
+ phpdbg_welcome((cleaning > 0) TSRMLS_CC);
}
- cleaning = -1;
+ /* auto compile */
+ if (PHPDBG_G(exec)) {
+ phpdbg_compile(TSRMLS_C);
+ }
/* initialize from file */
PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
zend_try {
phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC);
- if (bp_tmp) {
- PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
- phpdbg_string_init(bp_tmp TSRMLS_CC);
- free(bp_tmp);
- bp_tmp = NULL;
- PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
- }
+ phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC);
} zend_end_try();
PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
@@ -1492,61 +1422,50 @@ phpdbg_main:
goto phpdbg_out;
}
- /* auto compile */
- if (PHPDBG_G(exec)) {
- if (settings) {
- PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
- }
- phpdbg_compile(TSRMLS_C);
- PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
- }
-
/* step from here, not through init */
if (step) {
PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
}
+ if (run) {
+ /* no need to try{}, run does it ... */
+ PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC);
+ if (run > 1) {
+ /* if -r is on the command line more than once just quit */
+ goto phpdbg_out;
+ }
+ }
+
+/* #ifndef for making compiler shutting up */
+#ifndef _WIN32
phpdbg_interact:
+#endif
/* phpdbg main() */
do {
zend_try {
- if (phpdbg_startup_run) {
- zend_bool quit_immediately = phpdbg_startup_run > 1;
- phpdbg_startup_run = 0;
- PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC);
- if (quit_immediately) {
- /* if -r is on the command line more than once just quit */
- EG(bailout) = __orig_bailout; /* reset zend_try */
- break;
- }
- }
-
- phpdbg_interactive(1 TSRMLS_CC);
+ phpdbg_interactive(TSRMLS_C);
} zend_catch {
if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
- char *bp_tmp_str;
- PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
- phpdbg_export_breakpoints_to_string(&bp_tmp_str TSRMLS_CC);
- PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
- if (bp_tmp_str) {
- bp_tmp = strdup(bp_tmp_str);
- efree(bp_tmp_str);
- }
+ FILE *bp_tmp_fp = fopen(bp_tmp_file, "w");
+ phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC);
+ fclose(bp_tmp_fp);
cleaning = 1;
} else {
cleaning = 0;
}
+#ifndef _WIN32
if (!cleaning) {
/* remote client disconnected */
if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
/* renegociate connections */
- phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC);
+ phpdbg_open_sockets(
+ address, listen, &server, &socket, streams);
/* set streams */
- if (stream) {
+ if (streams[0] && streams[1]) {
PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
}
@@ -1558,37 +1477,31 @@ phpdbg_interact:
}
}
}
+#endif
} 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 */
- }
-
+ } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
+
/* this must be forced */
CG(unclean_shutdown) = 0;
/* this is just helpful */
PG(report_memleaks) = 0;
+#ifndef _WIN32
phpdbg_out:
if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
goto phpdbg_interact;
}
+#endif
#ifdef _WIN32
} __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) {
- phpdbg_error("segfault", "", "Access violation (Segmentation fault) encountered\ntrying to abort cleanly...");
+ phpdbg_error("Access violation (Segementation fault) encountered\ntrying to abort cleanly...");
}
+phpdbg_out:
#endif
-
- if (cleaning <= 0) {
- PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING;
- cleaning = -1;
- }
-
+
{
int i;
/* free argv */
@@ -1598,15 +1511,11 @@ phpdbg_out:
efree(SG(request_info).argv);
}
-#ifndef _WIN32
- /* reset it... else we risk a stack overflow upon next run (when clean'ing) */
- php_stream_stdio_ops.write = PHPDBG_G(php_stdiop_write);
-#endif
-
#ifndef ZTS
/* force cleanup of auto and core globals */
zend_hash_clean(CG(auto_globals));
- memset( &core_globals, 0, sizeof(php_core_globals));
+ memset(
+ &core_globals, 0, sizeof(php_core_globals));
#endif
if (ini_entries) {
free(ini_entries);
@@ -1615,34 +1524,14 @@ phpdbg_out:
if (ini_override) {
free(ini_override);
}
-
+
/* this must be forced */
CG(unclean_shutdown) = 0;
-
+
/* this is just helpful */
PG(report_memleaks) = 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");
- cleaning++;
- }
-
- if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) == PHPDBG_IS_CLEANING) {
- settings = PHPDBG_G(backup);
- }
-
- php_output_deactivate(TSRMLS_C);
+ php_request_shutdown((void*)0);
zend_try {
php_module_shutdown(TSRMLS_C);
@@ -1652,10 +1541,10 @@ phpdbg_out:
}
- if (cleaning > 0 || remote) {
+ if (cleaning || remote) {
goto phpdbg_main;
}
-
+
#ifdef ZTS
/* bugggy */
/* tsrm_shutdown(); */
@@ -1667,9 +1556,15 @@ phpdbg_out:
}
#endif
- if (PHPDBG_G(sapi_name_ptr)) {
- free(PHPDBG_G(sapi_name_ptr));
+ if (sapi_name) {
+ free(sapi_name);
}
+
+#ifdef _WIN32
+ free(bp_tmp_file);
+#else
+ unlink(bp_tmp_file);
+#endif
return 0;
} /* }}} */