summaryrefslogtreecommitdiff
path: root/sapi
diff options
context:
space:
mode:
Diffstat (limited to 'sapi')
-rw-r--r--sapi/apache2handler/php_functions.c8
-rw-r--r--sapi/cgi/fastcgi.c10
-rw-r--r--sapi/cli/php_cli_server.c11
-rw-r--r--sapi/cli/ps_title.c4
-rw-r--r--sapi/embed/php_embed.c2
-rw-r--r--sapi/fpm/fpm/fastcgi.c96
-rw-r--r--sapi/fpm/fpm/fastcgi.h2
-rw-r--r--sapi/fpm/fpm/fpm_log.c2
-rw-r--r--sapi/fpm/fpm/fpm_sockets.c41
-rw-r--r--sapi/fpm/fpm/fpm_unix.c3
-rw-r--r--sapi/fpm/php-fpm.conf.in8
-rw-r--r--sapi/fpm/tests/002.phpt14
-rw-r--r--sapi/fpm/tests/003.phpt14
-rw-r--r--sapi/fpm/tests/004.phpt59
-rw-r--r--sapi/fpm/tests/005.phpt57
-rw-r--r--sapi/fpm/tests/006.phpt57
-rw-r--r--sapi/fpm/tests/007.phpt68
-rw-r--r--sapi/fpm/tests/008.phpt84
-rw-r--r--sapi/fpm/tests/009.phpt53
-rw-r--r--sapi/fpm/tests/010.phpt84
-rw-r--r--sapi/fpm/tests/011.phpt53
-rw-r--r--sapi/fpm/tests/012.phpt79
-rw-r--r--sapi/fpm/tests/013.phpt54
-rw-r--r--sapi/fpm/tests/fcgi.inc592
-rw-r--r--sapi/fpm/tests/include.inc34
-rw-r--r--sapi/litespeed/lsapi_main.c4
-rw-r--r--sapi/phpdbg/config.m410
-rw-r--r--sapi/phpdbg/config.w325
-rw-r--r--sapi/phpdbg/phpdbg.c330
-rw-r--r--sapi/phpdbg/phpdbg.h128
-rw-r--r--sapi/phpdbg/phpdbg_bp.c232
-rw-r--r--sapi/phpdbg/phpdbg_bp.h30
-rw-r--r--sapi/phpdbg/phpdbg_cmd.c155
-rw-r--r--sapi/phpdbg/phpdbg_cmd.h2
-rw-r--r--sapi/phpdbg/phpdbg_frame.c6
-rw-r--r--sapi/phpdbg/phpdbg_io.c49
-rw-r--r--sapi/phpdbg/phpdbg_io.h2
-rw-r--r--sapi/phpdbg/phpdbg_list.c15
-rw-r--r--sapi/phpdbg/phpdbg_out.c18
-rw-r--r--sapi/phpdbg/phpdbg_parser.c250
-rw-r--r--sapi/phpdbg/phpdbg_parser.h18
-rw-r--r--sapi/phpdbg/phpdbg_prompt.c338
-rw-r--r--sapi/phpdbg/phpdbg_prompt.h1
-rw-r--r--sapi/phpdbg/phpdbg_rinit_hook.c4
-rw-r--r--sapi/phpdbg/phpdbg_sigio_win32.c25
-rw-r--r--sapi/phpdbg/phpdbg_sigio_win32.h2
-rw-r--r--sapi/phpdbg/phpdbg_utils.h25
-rw-r--r--sapi/phpdbg/phpdbg_wait.c18
-rw-r--r--sapi/phpdbg/phpdbg_webdata_transfer.c19
-rw-r--r--sapi/phpdbg/tests/commands/0104_clean.test1
50 files changed, 2393 insertions, 783 deletions
diff --git a/sapi/apache2handler/php_functions.c b/sapi/apache2handler/php_functions.c
index d9ae4d97ea..f32c881e05 100644
--- a/sapi/apache2handler/php_functions.c
+++ b/sapi/apache2handler/php_functions.c
@@ -388,8 +388,12 @@ PHP_MINFO_FUNCTION(apache)
}
smart_str_appendc(&tmp1, ' ');
}
- if (tmp1.s && (tmp1.s->len - 1) >= 0) {
- tmp1.s->val[tmp1.s->len - 1] = '\0';
+ if (tmp1.s) {
+ if (tmp1.s->len > 0) {
+ tmp1.s->val[tmp1.s->len - 1] = '\0';
+ } else {
+ tmp1.s->val[0] = '\0';
+ }
}
php_info_print_table_start();
diff --git a/sapi/cgi/fastcgi.c b/sapi/cgi/fastcgi.c
index 0cd3096e4d..7925f87562 100644
--- a/sapi/cgi/fastcgi.c
+++ b/sapi/cgi/fastcgi.c
@@ -435,7 +435,11 @@ int fcgi_init(void)
str = getenv("_FCGI_SHUTDOWN_EVENT_");
if (str != NULL) {
- HANDLE shutdown_event = (HANDLE) atoi(str);
+ zend_long ev;
+ HANDLE shutdown_event;
+
+ ZEND_ATOL(ev, str);
+ shutdown_event = (HANDLE) ev;
if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
shutdown_event, 0, NULL)) {
return -1;
@@ -443,7 +447,9 @@ int fcgi_init(void)
}
str = getenv("_FCGI_MUTEX_");
if (str != NULL) {
- fcgi_accept_mutex = (HANDLE) atoi(str);
+ zend_long mt;
+ ZEND_ATOL(mt, str);
+ fcgi_accept_mutex = (HANDLE) mt;
}
return is_fastcgi = 1;
} else {
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
index 7d930d99f8..367800635f 100644
--- a/sapi/cli/php_cli_server.c
+++ b/sapi/cli/php_cli_server.c
@@ -259,7 +259,9 @@ static php_cli_server_http_response_status_code_pair template_map[] = {
{ 501, "<h1>%s</h1><p>Request method not supported.</p>" }
};
+#if HAVE_UNISTD_H
static int php_cli_output_is_tty = OUTPUT_NOT_CHECKED;
+#endif
static size_t php_cli_server_client_send_through(php_cli_server_client *client, const char *str, size_t str_len);
static php_cli_server_chunk *php_cli_server_chunk_heap_new_self_contained(size_t len);
@@ -556,7 +558,7 @@ static void sapi_cli_server_flush(void *server_context TSRMLS_DC) /* {{{ */
return;
}
- if (client->sock < 0) {
+ if (!ZEND_VALID_SOCKET(client->sock)) {
php_handle_aborted_connection();
return;
}
@@ -838,7 +840,6 @@ static int php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, v
SOCKET fd;
int events;
} entries[FD_SETSIZE * 2];
- php_socket_t fd = 0;
size_t i;
struct socket_entry *n = entries, *m;
@@ -1335,7 +1336,7 @@ out:
php_network_freeaddresses(sal);
}
if (err) {
- if (retval >= 0) {
+ if (ZEND_VALID_SOCKET(retval)) {
closesocket(retval);
}
if (errstr) {
@@ -2186,7 +2187,7 @@ static void php_cli_server_dtor(php_cli_server *server TSRMLS_DC) /* {{{ */
{
zend_hash_destroy(&server->clients);
zend_hash_destroy(&server->extension_mime_types);
- if (server->server_sock >= 0) {
+ if (ZEND_VALID_SOCKET(server->server_sock)) {
closesocket(server->server_sock);
}
if (server->host) {
@@ -2401,7 +2402,7 @@ static int php_cli_server_do_event_for_each_fd_callback(void *_params, php_socke
return FAILURE;
}
client_sock = accept(server->server_sock, sa, &socklen);
- if (client_sock < 0) {
+ if (!ZEND_VALID_SOCKET(client_sock)) {
char *errstr;
errstr = php_socket_strerror(php_socket_errno(), NULL, 0);
php_cli_server_logf("Failed to accept a client (reason: %s)" TSRMLS_CC, errstr);
diff --git a/sapi/cli/ps_title.c b/sapi/cli/ps_title.c
index 97eec86e5b..6cef483983 100644
--- a/sapi/cli/ps_title.c
+++ b/sapi/cli/ps_title.c
@@ -129,7 +129,9 @@ static char** save_argv;
* This holds the 'locally' allocated environ from the save_ps_args method.
* This is subsequently free'd at exit.
*/
+#if defined(PS_USE_CLOBBER_ARGV)
static char** frozen_environ, **new_environ;
+#endif
/*
* Call this method early, before any code has used the original argv passed in
@@ -311,7 +313,7 @@ const char* ps_title_errno(int rc)
#ifdef PS_USE_WIN32
case PS_TITLE_WINDOWS_ERROR:
- sprintf(windows_error_details, "Windows error code: %u", GetLastError());
+ sprintf(windows_error_details, "Windows error code: %lu", GetLastError());
return windows_error_details;
#endif
}
diff --git a/sapi/embed/php_embed.c b/sapi/embed/php_embed.c
index e0df666108..8bfaf9f52d 100644
--- a/sapi/embed/php_embed.c
+++ b/sapi/embed/php_embed.c
@@ -108,7 +108,7 @@ static int php_embed_startup(sapi_module_struct *sapi_module)
return SUCCESS;
}
-extern EMBED_SAPI_API sapi_module_struct php_embed_module = {
+EMBED_SAPI_API sapi_module_struct php_embed_module = {
"embed", /* name */
"PHP Embedded Library", /* pretty name */
diff --git a/sapi/fpm/fpm/fastcgi.c b/sapi/fpm/fpm/fastcgi.c
index 4f7f5eab9c..432182ec2b 100644
--- a/sapi/fpm/fpm/fastcgi.c
+++ b/sapi/fpm/fpm/fastcgi.c
@@ -137,13 +137,14 @@ typedef union _sa_t {
struct sockaddr sa;
struct sockaddr_un sa_unix;
struct sockaddr_in sa_inet;
+ struct sockaddr_in6 sa_inet6;
} sa_t;
static HashTable fcgi_mgmt_vars;
static int is_initialized = 0;
static int in_shutdown = 0;
-static in_addr_t *allowed_clients = NULL;
+static sa_t *allowed_clients = NULL;
static sa_t client_sa;
@@ -266,14 +267,18 @@ void fcgi_set_allowed_clients(char *ip)
*end = 0;
end++;
}
- allowed_clients[n] = inet_addr(cur);
- if (allowed_clients[n] == INADDR_NONE) {
+ if (inet_pton(AF_INET, cur, &allowed_clients[n].sa_inet.sin_addr)>0) {
+ allowed_clients[n].sa.sa_family = AF_INET;
+ n++;
+ } else if (inet_pton(AF_INET6, cur, &allowed_clients[n].sa_inet6.sin6_addr)>0) {
+ allowed_clients[n].sa.sa_family = AF_INET6;
+ n++;
+ } else {
zlog(ZLOG_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
}
- n++;
cur = end;
}
- allowed_clients[n] = INADDR_NONE;
+ allowed_clients[n].sa.sa_family = 0;
free(ip);
}
}
@@ -749,6 +754,43 @@ void fcgi_close(fcgi_request *req, int force, int destroy)
}
}
+static int fcgi_is_allowed() {
+ int i;
+
+ if (client_sa.sa.sa_family == AF_UNIX) {
+ return 1;
+ }
+ if (!allowed_clients) {
+ return 1;
+ }
+ if (client_sa.sa.sa_family == AF_INET) {
+ for (i=0 ; allowed_clients[i].sa.sa_family ; i++) {
+ if (allowed_clients[i].sa.sa_family == AF_INET
+ && !memcmp(&client_sa.sa_inet.sin_addr, &allowed_clients[i].sa_inet.sin_addr, 4)) {
+ return 1;
+ }
+ }
+ }
+ if (client_sa.sa.sa_family == AF_INET6) {
+ for (i=0 ; allowed_clients[i].sa.sa_family ; i++) {
+ if (allowed_clients[i].sa.sa_family == AF_INET6
+ && !memcmp(&client_sa.sa_inet6.sin6_addr, &allowed_clients[i].sa_inet6.sin6_addr, 12)) {
+ return 1;
+ }
+#ifdef IN6_IS_ADDR_V4MAPPED
+ if (allowed_clients[i].sa.sa_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)
+ && !memcmp(((char *)&client_sa.sa_inet6.sin6_addr)+12, &allowed_clients[i].sa_inet.sin_addr, 4)) {
+ return 1;
+ }
+#endif
+ }
+ }
+
+ zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", fcgi_get_last_client_ip());
+ return 0;
+}
+
int fcgi_accept_request(fcgi_request *req)
{
#ifdef _WIN32
@@ -799,23 +841,10 @@ int fcgi_accept_request(fcgi_request *req)
FCGI_UNLOCK(req->listen_socket);
client_sa = sa;
- if (sa.sa.sa_family == AF_INET && req->fd >= 0 && allowed_clients) {
- int n = 0;
- int allowed = 0;
-
- while (allowed_clients[n] != INADDR_NONE) {
- if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
- allowed = 1;
- break;
- }
- n++;
- }
- if (!allowed) {
- zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", inet_ntoa(sa.sa_inet.sin_addr));
- closesocket(req->fd);
- req->fd = -1;
- continue;
- }
+ if (req->fd >= 0 && !fcgi_is_allowed()) {
+ closesocket(req->fd);
+ req->fd = -1;
+ continue;
}
}
@@ -1073,12 +1102,27 @@ void fcgi_free_mgmt_var_cb(zval *zv)
zend_string_free(Z_STR_P(zv));
}
-char *fcgi_get_last_client_ip() /* {{{ */
+const char *fcgi_get_last_client_ip() /* {{{ */
{
- if (client_sa.sa.sa_family == AF_UNIX) {
- return NULL;
+ static char str[INET6_ADDRSTRLEN];
+
+ /* Ipv4 */
+ if (client_sa.sa.sa_family == AF_INET) {
+ return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet.sin_addr, str, INET6_ADDRSTRLEN);
+ }
+#ifdef IN6_IS_ADDR_V4MAPPED
+ /* Ipv4-Mapped-Ipv6 */
+ if (client_sa.sa.sa_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)) {
+ return inet_ntop(AF_INET, ((char *)&client_sa.sa_inet6.sin6_addr)+12, str, INET6_ADDRSTRLEN);
}
- return inet_ntoa(client_sa.sa_inet.sin_addr);
+#endif
+ /* Ipv6 */
+ if (client_sa.sa.sa_family == AF_INET6) {
+ return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet6.sin6_addr, str, INET6_ADDRSTRLEN);
+ }
+ /* Unix socket */
+ return NULL;
}
/* }}} */
/*
diff --git a/sapi/fpm/fpm/fastcgi.h b/sapi/fpm/fpm/fastcgi.h
index 6d1bb38dba..9c96f763a9 100644
--- a/sapi/fpm/fpm/fastcgi.h
+++ b/sapi/fpm/fpm/fastcgi.h
@@ -133,7 +133,7 @@ int fcgi_flush(fcgi_request *req, int close);
void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len);
void fcgi_free_mgmt_var_cb(zval *ptr);
-char *fcgi_get_last_client_ip();
+const char *fcgi_get_last_client_ip();
/*
* Local variables:
diff --git a/sapi/fpm/fpm/fpm_log.c b/sapi/fpm/fpm/fpm_log.c
index 4e1a057db1..c71281b0b9 100644
--- a/sapi/fpm/fpm/fpm_log.c
+++ b/sapi/fpm/fpm/fpm_log.c
@@ -367,7 +367,7 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */
case 'R': /* remote IP address */
if (!test) {
- char *tmp = fcgi_get_last_client_ip();
+ const char *tmp = fcgi_get_last_client_ip();
len2 = snprintf(b, FPM_LOG_BUFFER - len, "%s", tmp ? tmp : "-");
}
break;
diff --git a/sapi/fpm/fpm/fpm_sockets.c b/sapi/fpm/fpm/fpm_sockets.c
index da14d63d8c..9d9def35c7 100644
--- a/sapi/fpm/fpm/fpm_sockets.c
+++ b/sapi/fpm/fpm/fpm_sockets.c
@@ -85,13 +85,24 @@ static void *fpm_get_in_addr(struct sockaddr *sa) /* {{{ */
}
/* }}} */
+static int fpm_get_in_port(struct sockaddr *sa) /* {{{ */
+{
+ if (sa->sa_family == AF_INET) {
+ return ntohs(((struct sockaddr_in*)sa)->sin_port);
+ }
+
+ return ntohs(((struct sockaddr_in6*)sa)->sin6_port);
+}
+/* }}} */
+
static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op) /* {{{ */
{
if (key == NULL) {
switch (type) {
case FPM_AF_INET : {
- key = alloca(INET6_ADDRSTRLEN);
- inet_ntop(sa->sa_family, fpm_get_in_addr(sa), key, sizeof key);
+ key = alloca(INET6_ADDRSTRLEN+10);
+ inet_ntop(sa->sa_family, fpm_get_in_addr(sa), key, INET6_ADDRSTRLEN);
+ sprintf(key+strlen(key), ":%d", fpm_get_in_port(sa));
break;
}
@@ -246,7 +257,7 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /*
char *addr = NULL;
int addr_len;
int port = 0;
- int sock;
+ int sock = -1;
int status;
if (port_str) { /* this is host:port pair */
@@ -263,13 +274,23 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /*
return -1;
}
- // strip brackets from address for getaddrinfo
- if (addr != NULL) {
- addr_len = strlen(addr);
- if (addr[0] == '[' && addr[addr_len - 1] == ']') {
- addr[addr_len - 1] = '\0';
- addr++;
- }
+ if (!addr) {
+ /* no address: default documented behavior, all IPv4 addresses */
+ struct sockaddr_in sa_in;
+
+ memset(&sa_in, 0, sizeof(sa_in));
+ sa_in.sin_family = AF_INET;
+ sa_in.sin_port = htons(port);
+ sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
+ free(dup_address);
+ return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in));
+ }
+
+ /* strip brackets from address for getaddrinfo */
+ addr_len = strlen(addr);
+ if (addr[0] == '[' && addr[addr_len - 1] == ']') {
+ addr[addr_len - 1] = '\0';
+ addr++;
}
memset(&hints, 0, sizeof hints);
diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c
index 68978ee75d..c29e28f886 100644
--- a/sapi/fpm/fpm/fpm_unix.c
+++ b/sapi/fpm/fpm/fpm_unix.c
@@ -266,6 +266,8 @@ int fpm_unix_init_main() /* {{{ */
struct fpm_worker_pool_s *wp;
int is_root = !geteuid();
+ zlog_set_level(fpm_globals.log_level);
+
if (fpm_global_config.rlimit_files) {
struct rlimit r;
@@ -396,7 +398,6 @@ int fpm_unix_init_main() /* {{{ */
}
}
- zlog_set_level(fpm_globals.log_level);
return 0;
}
/* }}} */
diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in
index 106689f0a7..bcdfe56a10 100644
--- a/sapi/fpm/php-fpm.conf.in
+++ b/sapi/fpm/php-fpm.conf.in
@@ -150,12 +150,14 @@ group = @php_fpm_group@
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
-; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
+; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
; a specific port;
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
; a specific port;
-; 'port' - to listen on a TCP socket to all addresses on a
+; 'port' - to listen on a TCP socket to all IPv4 addresses on a
; specific port;
+; '[::]:port' - to listen on a TCP socket to all addresses
+; (IPv6 and IPv4-mapped) on a specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = 127.0.0.1:9000
@@ -173,7 +175,7 @@ listen = 127.0.0.1:9000
;listen.group = @php_fpm_group@
;listen.mode = 0660
-; List of ipv4 addresses of FastCGI clients which are allowed to connect.
+; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.
; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
; must be separated by a comma. If this value is left blank, connections will be
diff --git a/sapi/fpm/tests/002.phpt b/sapi/fpm/tests/002.phpt
index 2ef6cedc38..89e431849a 100644
--- a/sapi/fpm/tests/002.phpt
+++ b/sapi/fpm/tests/002.phpt
@@ -8,12 +8,13 @@ FPM: Startup and connect
include "include.inc";
$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
$cfg = <<<EOT
[global]
error_log = $logfile
[unconfined]
-listen = 127.0.0.1:9000
+listen = 127.0.0.1:$port
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
@@ -23,10 +24,9 @@ EOT;
$fpm = run_fpm($cfg, $tail);
if (is_resource($fpm)) {
- var_dump(fgets($tail));
- var_dump(fgets($tail));
+ fpm_display_log($tail, 2);
$i = 0;
- while (($i++ < 30) && !($fp = @fsockopen('127.0.0.1', 9000))) {
+ while (($i++ < 30) && !($fp = @fsockopen('127.0.0.1', $port))) {
usleep(10000);
}
if ($fp) {
@@ -41,10 +41,8 @@ if (is_resource($fpm)) {
?>
--EXPECTF--
-string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
-"
-string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
-"
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
Done
--CLEAN--
<?php
diff --git a/sapi/fpm/tests/003.phpt b/sapi/fpm/tests/003.phpt
index 389cb2401e..f928626ecc 100644
--- a/sapi/fpm/tests/003.phpt
+++ b/sapi/fpm/tests/003.phpt
@@ -8,12 +8,13 @@ FPM: Test IPv6 support
include "include.inc";
$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
$cfg = <<<EOT
[global]
error_log = $logfile
[unconfined]
-listen = [::1]:9000
+listen = [::1]:$port
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
@@ -23,10 +24,9 @@ EOT;
$fpm = run_fpm($cfg, $tail);
if (is_resource($fpm)) {
- var_dump(fgets($tail));
- var_dump(fgets($tail));
+ fpm_display_log($tail, 2);
$i = 0;
- while (($i++ < 30) && !($fp = fsockopen('[::1]', 9000))) {
+ while (($i++ < 30) && !($fp = fsockopen('[::1]', $port))) {
usleep(10000);
}
if ($fp) {
@@ -41,10 +41,8 @@ if (is_resource($fpm)) {
?>
--EXPECTF--
-string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
-"
-string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
-"
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
Done
--CLEAN--
<?php
diff --git a/sapi/fpm/tests/004.phpt b/sapi/fpm/tests/004.phpt
new file mode 100644
index 0000000000..2a4d666c64
--- /dev/null
+++ b/sapi/fpm/tests/004.phpt
@@ -0,0 +1,59 @@
+--TEST--
+FPM: Test IPv4/IPv6 support
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = [::]:$port
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ $i = 0;
+ while (($i++ < 30) && !($fp = @fsockopen('127.0.0.1', $port))) {
+ usleep(10000);
+ }
+ if ($fp) {
+ echo "Done IPv4\n";
+ fclose($fp);
+ }
+ while (($i++ < 30) && !($fp = @fsockopen('[::1]', $port))) {
+ usleep(10000);
+ }
+ if ($fp) {
+ echo "Done IPv6\n";
+ fclose($fp);
+ }
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+Done IPv4
+Done IPv6
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/005.phpt b/sapi/fpm/tests/005.phpt
new file mode 100644
index 0000000000..c565c2a9eb
--- /dev/null
+++ b/sapi/fpm/tests/005.phpt
@@ -0,0 +1,57 @@
+--TEST--
+FPM: Test IPv4 allowed clients
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = [::]:$port
+listen.allowed_clients = 127.0.0.1
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ run_request('127.0.0.1', $port);
+ echo "IPv4 ok\n";
+ } catch (Exception $e) {
+ echo "IPv4 error\n";
+ }
+ try {
+ run_request('[::1]', $port);
+ echo "IPv6 ok\n";
+ } catch (Exception $e) {
+ echo "IPv6 error\n";
+ }
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+IPv4 ok
+IPv6 error
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/006.phpt b/sapi/fpm/tests/006.phpt
new file mode 100644
index 0000000000..a12ca253d2
--- /dev/null
+++ b/sapi/fpm/tests/006.phpt
@@ -0,0 +1,57 @@
+--TEST--
+FPM: Test IPv6 allowed clients (bug #68428)
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = [::]:$port
+listen.allowed_clients = ::1
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ run_request('127.0.0.1', $port);
+ echo "IPv4 ok\n";
+ } catch (Exception $e) {
+ echo "IPv4 error\n";
+ }
+ try {
+ run_request('[::1]', $port);
+ echo "IPv6 ok\n";
+ } catch (Exception $e) {
+ echo "IPv6 error\n";
+ }
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+IPv4 error
+IPv6 ok
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/007.phpt b/sapi/fpm/tests/007.phpt
new file mode 100644
index 0000000000..0d817907cf
--- /dev/null
+++ b/sapi/fpm/tests/007.phpt
@@ -0,0 +1,68 @@
+--TEST--
+FPM: Test IPv6 all addresses and access_log (bug #68421)
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$accfile = dirname(__FILE__).'/php-fpm.acc.tmp';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = [::]:$port
+access.log = $accfile
+ping.path = /ping
+ping.response = pong
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ var_dump(strpos(run_request('127.0.0.1', $port), 'pong'));
+ echo "IPv4 ok\n";
+ } catch (Exception $e) {
+ echo "IPv4 error\n";
+ }
+ try {
+ var_dump(strpos(run_request('[::1]', $port), 'pong'));
+ echo "IPv6 ok\n";
+ } catch (Exception $e) {
+ echo "IPv6 error\n";
+ }
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+
+ echo file_get_contents($accfile);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+int(%d)
+IPv4 ok
+int(%d)
+IPv6 ok
+127.0.0.1 %s "GET /ping" 200
+::1 %s "GET /ping" 200
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+ $accfile = dirname(__FILE__).'/php-fpm.acc.tmp';
+ @unlink($accfile);
+?>
diff --git a/sapi/fpm/tests/008.phpt b/sapi/fpm/tests/008.phpt
new file mode 100644
index 0000000000..60f1ea6ebd
--- /dev/null
+++ b/sapi/fpm/tests/008.phpt
@@ -0,0 +1,84 @@
+--TEST--
+FPM: Test multi pool (dynamic + ondemand + static) (bug #68423)
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port1 = 9000+PHP_INT_SIZE;
+$port2 = 9001+PHP_INT_SIZE;
+$port3 = 9002+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[pool_dynamic]
+listen = 127.0.0.1:$port1
+ping.path = /ping
+ping.response = pong-dynamic
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+[poold_ondemand]
+listen = 127.0.0.1:$port2
+ping.path = /ping
+ping.response = pong-on-demand
+pm = ondemand
+pm.max_children = 2
+pm.process_idle_timeout = 10
+[pool_static]
+listen = 127.0.0.1:$port3
+ping.path = /ping
+ping.response = pong-static
+pm = static
+pm.max_children = 2
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ var_dump(strpos(run_request('127.0.0.1', $port1), 'pong-dynamic'));
+ echo "Dynamic ok\n";
+ } catch (Exception $e) {
+ echo "Dynamic error\n";
+ }
+ try {
+ var_dump(strpos(run_request('127.0.0.1', $port2), 'pong-on-demand'));
+ echo "OnDemand ok\n";
+ } catch (Exception $e) {
+ echo "OnDemand error\n";
+ }
+ try {
+ var_dump(strpos(run_request('127.0.0.1', $port3), 'pong-static'));
+ echo "Static ok\n";
+ } catch (Exception $e) {
+ echo "Static error\n";
+ }
+
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+int(%d)
+Dynamic ok
+int(%d)
+OnDemand ok
+int(%d)
+Static ok
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/009.phpt b/sapi/fpm/tests/009.phpt
new file mode 100644
index 0000000000..34cdffcf83
--- /dev/null
+++ b/sapi/fpm/tests/009.phpt
@@ -0,0 +1,53 @@
+--TEST--
+FPM: Test Unix Domain Socket
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$socket = dirname(__FILE__).'/php-fpm.sock';
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = $socket
+ping.path = /ping
+ping.response = pong
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ var_dump(strpos(run_request('unix://'.$socket, -1), 'pong'));
+ echo "UDS ok\n";
+ } catch (Exception $e) {
+ echo "UDS error\n";
+ }
+
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+int(%d)
+UDS ok
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/010.phpt b/sapi/fpm/tests/010.phpt
new file mode 100644
index 0000000000..37c778db5b
--- /dev/null
+++ b/sapi/fpm/tests/010.phpt
@@ -0,0 +1,84 @@
+--TEST--
+FPM: Test status page
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = 127.0.0.1:$port
+pm.status_path = /status
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ echo run_request('127.0.0.1', $port, '/status');
+
+ $html = run_request('127.0.0.1', $port, '/status', 'html');
+ var_dump(strpos($html, 'text/html') && strpos($html, 'DOCTYPE') && strpos($html, 'PHP-FPM Status Page'));
+
+ $json = run_request('127.0.0.1', $port, '/status', 'json');
+ var_dump(strpos($json, 'application/json') && strpos($json, '"pool":"unconfined"'));
+
+ $xml = run_request('127.0.0.1', $port, '/status', 'xml');
+ var_dump(strpos($xml, 'text/xml') && strpos($xml, '<?xml'));
+
+ echo "IPv4 ok\n";
+ } catch (Exception $e) {
+ echo "IPv4 error\n";
+ }
+
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+X-Powered-By: PHP/%s
+Expires: %s
+Cache-Control: %s
+Content-type: text/plain%s
+
+pool: unconfined
+process manager: dynamic
+start time: %s
+start since: %d
+accepted conn: 1
+listen queue: 0
+max listen queue: 0
+listen queue len: %d
+idle processes: 1
+active processes: 1
+total processes: 2
+max active processes: 1
+max children reached: 0
+slow requests: 0
+
+bool(true)
+bool(true)
+bool(true)
+IPv4 ok
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/011.phpt b/sapi/fpm/tests/011.phpt
new file mode 100644
index 0000000000..0b849f873b
--- /dev/null
+++ b/sapi/fpm/tests/011.phpt
@@ -0,0 +1,53 @@
+--TEST--
+FPM: Test IPv4 all addresses (bug #68420)
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = $port
+ping.path = /ping
+ping.response = pong
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ var_dump(strpos(run_request('127.0.0.1', $port), 'pong'));
+ echo "IPv4 ok\n";
+ } catch (Exception $e) {
+ echo "IPv4 error\n";
+ }
+
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+int(%d)
+IPv4 ok
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/012.phpt b/sapi/fpm/tests/012.phpt
new file mode 100644
index 0000000000..d96c53081c
--- /dev/null
+++ b/sapi/fpm/tests/012.phpt
@@ -0,0 +1,79 @@
+--TEST--
+FPM: Test reload configuration (bug #68442)
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$pidfile = dirname(__FILE__).'/php-fpm.pid';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+pid = $pidfile
+[unconfined]
+listen = 127.0.0.1:$port
+ping.path = /ping
+ping.response = pong
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ fpm_display_log($tail, 2);
+ try {
+ var_dump(strpos(run_request('127.0.0.1', $port), 'pong'));
+ echo "IPv4 ok\n";
+ } catch (Exception $e) {
+ echo "IPv4 error\n";
+ }
+
+ $pid=file_get_contents($pidfile);
+ if ($pid) {
+ exec("kill -USR2 $pid");
+ } else {
+ die("PID not found\n");
+ }
+ fpm_display_log($tail, 5);
+
+ try {
+ var_dump(strpos(run_request('127.0.0.1', $port), 'pong'));
+ echo "IPv4 ok\n";
+ } catch (Exception $e) {
+ echo "IPv4 error\n";
+ }
+
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+--EXPECTF--
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+int(%d)
+IPv4 ok
+[%d-%s-%d %d:%d:%d] NOTICE: Reloading in progress ...
+[%d-%s-%d %d:%d:%d] NOTICE: reloading: %s
+[%d-%s-%d %d:%d:%d] NOTICE: using inherited socket fd=%d, "127.0.0.1:%d"
+[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
+[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
+int(%d)
+IPv4 ok
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+ $pidfile = dirname(__FILE__).'/php-fpm.pid';
+ @unlink($pidfile);
+?>
diff --git a/sapi/fpm/tests/013.phpt b/sapi/fpm/tests/013.phpt
new file mode 100644
index 0000000000..8d6a9d1d85
--- /dev/null
+++ b/sapi/fpm/tests/013.phpt
@@ -0,0 +1,54 @@
+--TEST--
+FPM: Test for log_level in fpm_unix_init_main #68381
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$port = 9000+PHP_INT_SIZE;
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+log_level = warning
+[unconfined]
+listen = 127.0.0.1:$port
+user = foo
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+EOT;
+
+$fpm = run_fpm($cfg, $tail);
+if (is_resource($fpm)) {
+ $i = 0;
+ while (($i++ < 30) && !($fp = @fsockopen('127.0.0.1', $port))) {
+ usleep(10000);
+ }
+ if ($fp) {
+ echo "Started\n";
+ fclose($fp);
+ }
+ proc_terminate($fpm);
+ if (!feof($tail)) {
+ echo stream_get_contents($tail);
+ }
+ fclose($tail);
+ proc_close($fpm);
+}
+
+?>
+Done
+--EXPECTF--
+Started
+Done
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?> \ No newline at end of file
diff --git a/sapi/fpm/tests/fcgi.inc b/sapi/fpm/tests/fcgi.inc
new file mode 100644
index 0000000000..b31676260d
--- /dev/null
+++ b/sapi/fpm/tests/fcgi.inc
@@ -0,0 +1,592 @@
+<?php
+/*
+ * This file is part of PHP-FastCGI-Client.
+ *
+ * (c) Pierrick Charron <pierrick@adoy.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+namespace Adoy\FastCGI;
+
+class TimedOutException extends \Exception {}
+class ForbiddenException extends \Exception {}
+
+/**
+ * Handles communication with a FastCGI application
+ *
+ * @author Pierrick Charron <pierrick@adoy.net>
+ * @version 1.0
+ */
+class Client
+{
+ const VERSION_1 = 1;
+
+ const BEGIN_REQUEST = 1;
+ const ABORT_REQUEST = 2;
+ const END_REQUEST = 3;
+ const PARAMS = 4;
+ const STDIN = 5;
+ const STDOUT = 6;
+ const STDERR = 7;
+ const DATA = 8;
+ const GET_VALUES = 9;
+ const GET_VALUES_RESULT = 10;
+ const UNKNOWN_TYPE = 11;
+ const MAXTYPE = self::UNKNOWN_TYPE;
+
+ const RESPONDER = 1;
+ const AUTHORIZER = 2;
+ const FILTER = 3;
+
+ const REQUEST_COMPLETE = 0;
+ const CANT_MPX_CONN = 1;
+ const OVERLOADED = 2;
+ const UNKNOWN_ROLE = 3;
+
+ const MAX_CONNS = 'MAX_CONNS';
+ const MAX_REQS = 'MAX_REQS';
+ const MPXS_CONNS = 'MPXS_CONNS';
+
+ const HEADER_LEN = 8;
+
+ const REQ_STATE_WRITTEN = 1;
+ const REQ_STATE_OK = 2;
+ const REQ_STATE_ERR = 3;
+ const REQ_STATE_TIMED_OUT = 4;
+
+ /**
+ * Socket
+ * @var Resource
+ */
+ private $_sock = null;
+
+ /**
+ * Host
+ * @var String
+ */
+ private $_host = null;
+
+ /**
+ * Port
+ * @var Integer
+ */
+ private $_port = null;
+
+ /**
+ * Keep Alive
+ * @var Boolean
+ */
+ private $_keepAlive = false;
+
+ /**
+ * Outstanding request statuses keyed by request id
+ *
+ * Each request is an array with following form:
+ *
+ * array(
+ * 'state' => REQ_STATE_*
+ * 'response' => null | string
+ * )
+ *
+ * @var array
+ */
+ private $_requests = array();
+
+ /**
+ * Use persistent sockets to connect to backend
+ * @var Boolean
+ */
+ private $_persistentSocket = false;
+
+ /**
+ * Connect timeout in milliseconds
+ * @var Integer
+ */
+ private $_connectTimeout = 5000;
+
+ /**
+ * Read/Write timeout in milliseconds
+ * @var Integer
+ */
+ private $_readWriteTimeout = 5000;
+
+ /**
+ * Constructor
+ *
+ * @param String $host Host of the FastCGI application
+ * @param Integer $port Port of the FastCGI application
+ */
+ public function __construct($host, $port)
+ {
+ $this->_host = $host;
+ $this->_port = $port;
+ }
+
+ /**
+ * Define whether or not the FastCGI application should keep the connection
+ * alive at the end of a request
+ *
+ * @param Boolean $b true if the connection should stay alive, false otherwise
+ */
+ public function setKeepAlive($b)
+ {
+ $this->_keepAlive = (boolean)$b;
+ if (!$this->_keepAlive && $this->_sock) {
+ fclose($this->_sock);
+ }
+ }
+
+ /**
+ * Get the keep alive status
+ *
+ * @return Boolean true if the connection should stay alive, false otherwise
+ */
+ public function getKeepAlive()
+ {
+ return $this->_keepAlive;
+ }
+
+ /**
+ * Define whether or not PHP should attempt to re-use sockets opened by previous
+ * request for efficiency
+ *
+ * @param Boolean $b true if persistent socket should be used, false otherwise
+ */
+ public function setPersistentSocket($b)
+ {
+ $was_persistent = ($this->_sock && $this->_persistentSocket);
+ $this->_persistentSocket = (boolean)$b;
+ if (!$this->_persistentSocket && $was_persistent) {
+ fclose($this->_sock);
+ }
+ }
+
+ /**
+ * Get the pesistent socket status
+ *
+ * @return Boolean true if the socket should be persistent, false otherwise
+ */
+ public function getPersistentSocket()
+ {
+ return $this->_persistentSocket;
+ }
+
+
+ /**
+ * Set the connect timeout
+ *
+ * @param Integer number of milliseconds before connect will timeout
+ */
+ public function setConnectTimeout($timeoutMs)
+ {
+ $this->_connectTimeout = $timeoutMs;
+ }
+
+ /**
+ * Get the connect timeout
+ *
+ * @return Integer number of milliseconds before connect will timeout
+ */
+ public function getConnectTimeout()
+ {
+ return $this->_connectTimeout;
+ }
+
+ /**
+ * Set the read/write timeout
+ *
+ * @param Integer number of milliseconds before read or write call will timeout
+ */
+ public function setReadWriteTimeout($timeoutMs)
+ {
+ $this->_readWriteTimeout = $timeoutMs;
+ $this->set_ms_timeout($this->_readWriteTimeout);
+ }
+
+ /**
+ * Get the read timeout
+ *
+ * @return Integer number of milliseconds before read will timeout
+ */
+ public function getReadWriteTimeout()
+ {
+ return $this->_readWriteTimeout;
+ }
+
+ /**
+ * Helper to avoid duplicating milliseconds to secs/usecs in a few places
+ *
+ * @param Integer millisecond timeout
+ * @return Boolean
+ */
+ private function set_ms_timeout($timeoutMs) {
+ if (!$this->_sock) {
+ return false;
+ }
+ return stream_set_timeout($this->_sock, floor($timeoutMs / 1000), ($timeoutMs % 1000) * 1000);
+ }
+
+
+ /**
+ * Create a connection to the FastCGI application
+ */
+ private function connect()
+ {
+ if (!$this->_sock) {
+ if ($this->_persistentSocket) {
+ $this->_sock = pfsockopen($this->_host, $this->_port, $errno, $errstr, $this->_connectTimeout/1000);
+ } else {
+ $this->_sock = fsockopen($this->_host, $this->_port, $errno, $errstr, $this->_connectTimeout/1000);
+ }
+
+ if (!$this->_sock) {
+ throw new \Exception('Unable to connect to FastCGI application: ' . $errstr);
+ }
+
+ if (!$this->set_ms_timeout($this->_readWriteTimeout)) {
+ throw new \Exception('Unable to set timeout on socket');
+ }
+ }
+ }
+
+ /**
+ * Build a FastCGI packet
+ *
+ * @param Integer $type Type of the packet
+ * @param String $content Content of the packet
+ * @param Integer $requestId RequestId
+ */
+ private function buildPacket($type, $content, $requestId = 1)
+ {
+ $clen = strlen($content);
+ return chr(self::VERSION_1) /* version */
+ . chr($type) /* type */
+ . chr(($requestId >> 8) & 0xFF) /* requestIdB1 */
+ . chr($requestId & 0xFF) /* requestIdB0 */
+ . chr(($clen >> 8 ) & 0xFF) /* contentLengthB1 */
+ . chr($clen & 0xFF) /* contentLengthB0 */
+ . chr(0) /* paddingLength */
+ . chr(0) /* reserved */
+ . $content; /* content */
+ }
+
+ /**
+ * Build an FastCGI Name value pair
+ *
+ * @param String $name Name
+ * @param String $value Value
+ * @return String FastCGI Name value pair
+ */
+ private function buildNvpair($name, $value)
+ {
+ $nlen = strlen($name);
+ $vlen = strlen($value);
+ if ($nlen < 128) {
+ /* nameLengthB0 */
+ $nvpair = chr($nlen);
+ } else {
+ /* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */
+ $nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF);
+ }
+ if ($vlen < 128) {
+ /* valueLengthB0 */
+ $nvpair .= chr($vlen);
+ } else {
+ /* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */
+ $nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF);
+ }
+ /* nameData & valueData */
+ return $nvpair . $name . $value;
+ }
+
+ /**
+ * Read a set of FastCGI Name value pairs
+ *
+ * @param String $data Data containing the set of FastCGI NVPair
+ * @return array of NVPair
+ */
+ private function readNvpair($data, $length = null)
+ {
+ $array = array();
+
+ if ($length === null) {
+ $length = strlen($data);
+ }
+
+ $p = 0;
+
+ while ($p != $length) {
+
+ $nlen = ord($data{$p++});
+ if ($nlen >= 128) {
+ $nlen = ($nlen & 0x7F << 24);
+ $nlen |= (ord($data{$p++}) << 16);
+ $nlen |= (ord($data{$p++}) << 8);
+ $nlen |= (ord($data{$p++}));
+ }
+ $vlen = ord($data{$p++});
+ if ($vlen >= 128) {
+ $vlen = ($nlen & 0x7F << 24);
+ $vlen |= (ord($data{$p++}) << 16);
+ $vlen |= (ord($data{$p++}) << 8);
+ $vlen |= (ord($data{$p++}));
+ }
+ $array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen);
+ $p += ($nlen + $vlen);
+ }
+
+ return $array;
+ }
+
+ /**
+ * Decode a FastCGI Packet
+ *
+ * @param String $data String containing all the packet
+ * @return array
+ */
+ private function decodePacketHeader($data)
+ {
+ $ret = array();
+ $ret['version'] = ord($data{0});
+ $ret['type'] = ord($data{1});
+ $ret['requestId'] = (ord($data{2}) << 8) + ord($data{3});
+ $ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5});
+ $ret['paddingLength'] = ord($data{6});
+ $ret['reserved'] = ord($data{7});
+ return $ret;
+ }
+
+ /**
+ * Read a FastCGI Packet
+ *
+ * @return array
+ */
+ private function readPacket()
+ {
+ if ($packet = fread($this->_sock, self::HEADER_LEN)) {
+ $resp = $this->decodePacketHeader($packet);
+ $resp['content'] = '';
+ if ($resp['contentLength']) {
+ $len = $resp['contentLength'];
+ while ($len && $buf=fread($this->_sock, $len)) {
+ $len -= strlen($buf);
+ $resp['content'] .= $buf;
+ }
+ }
+ if ($resp['paddingLength']) {
+ $buf = fread($this->_sock, $resp['paddingLength']);
+ }
+ return $resp;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get Informations on the FastCGI application
+ *
+ * @param array $requestedInfo information to retrieve
+ * @return array
+ */
+ public function getValues(array $requestedInfo)
+ {
+ $this->connect();
+
+ $request = '';
+ foreach ($requestedInfo as $info) {
+ $request .= $this->buildNvpair($info, '');
+ }
+ fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0));
+
+ $resp = $this->readPacket();
+ if ($resp['type'] == self::GET_VALUES_RESULT) {
+ return $this->readNvpair($resp['content'], $resp['length']);
+ } else {
+ throw new \Exception('Unexpected response type, expecting GET_VALUES_RESULT');
+ }
+ }
+
+ /**
+ * Execute a request to the FastCGI application
+ *
+ * @param array $params Array of parameters
+ * @param String $stdin Content
+ * @return String
+ */
+ public function request(array $params, $stdin)
+ {
+ $id = $this->async_request($params, $stdin);
+ return $this->wait_for_response($id);
+ }
+
+ /**
+ * Execute a request to the FastCGI application asyncronously
+ *
+ * This sends request to application and returns the assigned ID for that request.
+ *
+ * You should keep this id for later use with wait_for_response(). Ids are chosen randomly
+ * rather than seqentially to guard against false-positives when using persistent sockets.
+ * In that case it is possible that a delayed response to a request made by a previous script
+ * invocation comes back on this socket and is mistaken for response to request made with same ID
+ * during this request.
+ *
+ * @param array $params Array of parameters
+ * @param String $stdin Content
+ * @return Integer
+ */
+ public function async_request(array $params, $stdin)
+ {
+ $this->connect();
+
+ // Pick random number between 1 and max 16 bit unsigned int 65535
+ $id = mt_rand(1, (1 << 16) - 1);
+
+ // Using persistent sockets implies you want them keept alive by server!
+ $keepAlive = intval($this->_keepAlive || $this->_persistentSocket);
+
+ $request = $this->buildPacket(self::BEGIN_REQUEST
+ ,chr(0) . chr(self::RESPONDER) . chr($keepAlive) . str_repeat(chr(0), 5)
+ ,$id
+ );
+
+ $paramsRequest = '';
+ foreach ($params as $key => $value) {
+ $paramsRequest .= $this->buildNvpair($key, $value, $id);
+ }
+ if ($paramsRequest) {
+ $request .= $this->buildPacket(self::PARAMS, $paramsRequest, $id);
+ }
+ $request .= $this->buildPacket(self::PARAMS, '', $id);
+
+ if ($stdin) {
+ $request .= $this->buildPacket(self::STDIN, $stdin, $id);
+ }
+ $request .= $this->buildPacket(self::STDIN, '', $id);
+
+ if (fwrite($this->_sock, $request) === false || fflush($this->_sock) === false) {
+
+ $info = stream_get_meta_data($this->_sock);
+
+ if ($info['timed_out']) {
+ throw new TimedOutException('Write timed out');
+ }
+
+ // Broken pipe, tear down so future requests might succeed
+ fclose($this->_sock);
+ throw new \Exception('Failed to write request to socket');
+ }
+
+ $this->_requests[$id] = array(
+ 'state' => self::REQ_STATE_WRITTEN,
+ 'response' => null
+ );
+
+ return $id;
+ }
+
+ /**
+ * Blocking call that waits for response to specific request
+ *
+ * @param Integer $requestId
+ * @param Integer $timeoutMs [optional] the number of milliseconds to wait. Defaults to the ReadWriteTimeout value set.
+ * @return string response body
+ */
+ public function wait_for_response($requestId, $timeoutMs = 0) {
+
+ if (!isset($this->_requests[$requestId])) {
+ throw new \Exception('Invalid request id given');
+ }
+
+ // If we already read the response during an earlier call for different id, just return it
+ if ($this->_requests[$requestId]['state'] == self::REQ_STATE_OK
+ || $this->_requests[$requestId]['state'] == self::REQ_STATE_ERR
+ ) {
+ return $this->_requests[$requestId]['response'];
+ }
+
+ if ($timeoutMs > 0) {
+ // Reset timeout on socket for now
+ $this->set_ms_timeout($timeoutMs);
+ } else {
+ $timeoutMs = $this->_readWriteTimeout;
+ }
+
+ // Need to manually check since we might do several reads none of which timeout themselves
+ // but still not get the response requested
+ $startTime = microtime(true);
+
+ do {
+ $resp = $this->readPacket();
+
+ if ($resp['type'] == self::STDOUT || $resp['type'] == self::STDERR) {
+ if ($resp['type'] == self::STDERR) {
+ $this->_requests[$resp['requestId']]['state'] = self::REQ_STATE_ERR;
+ }
+ $this->_requests[$resp['requestId']]['response'] .= $resp['content'];
+ }
+ if ($resp['type'] == self::END_REQUEST) {
+ $this->_requests[$resp['requestId']]['state'] = self::REQ_STATE_OK;
+ if ($resp['requestId'] == $requestId) {
+ break;
+ }
+ }
+ if (microtime(true) - $startTime >= ($timeoutMs * 1000)) {
+ // Reset
+ $this->set_ms_timeout($this->_readWriteTimeout);
+ throw new \Exception('Timed out');
+ }
+ } while ($resp);
+
+ if (!is_array($resp)) {
+ $info = stream_get_meta_data($this->_sock);
+
+ // We must reset timeout but it must be AFTER we get info
+ $this->set_ms_timeout($this->_readWriteTimeout);
+
+ if ($info['timed_out']) {
+ throw new TimedOutException('Read timed out');
+ }
+
+ if ($info['unread_bytes'] == 0
+ && $info['blocked']
+ && $info['eof']) {
+ throw new ForbiddenException('Not in white list. Check listen.allowed_clients.');
+ }
+
+ throw new \Exception('Read failed');
+ }
+
+ // Reset timeout
+ $this->set_ms_timeout($this->_readWriteTimeout);
+
+ switch (ord($resp['content']{4})) {
+ case self::CANT_MPX_CONN:
+ throw new \Exception('This app can\'t multiplex [CANT_MPX_CONN]');
+ break;
+ case self::OVERLOADED:
+ throw new \Exception('New request rejected; too busy [OVERLOADED]');
+ break;
+ case self::UNKNOWN_ROLE:
+ throw new \Exception('Role value not known [UNKNOWN_ROLE]');
+ break;
+ case self::REQUEST_COMPLETE:
+ return $this->_requests[$requestId]['response'];
+ }
+ }
+}
diff --git a/sapi/fpm/tests/include.inc b/sapi/fpm/tests/include.inc
index 983cbd3454..b195fad507 100644
--- a/sapi/fpm/tests/include.inc
+++ b/sapi/fpm/tests/include.inc
@@ -76,4 +76,36 @@ function run_fpm_till($needle, $config, $max = 10) /* {{{ */
}
/* }}} */
-?>
+function fpm_display_log($tail, $n=1, $ignore='systemd') {
+ while ($n) {
+ $a = fgets($tail);
+ if (empty($ignore) || !strpos($a, $ignore)) {
+ echo $a;
+ $n--;
+ }
+ }
+}
+
+function run_request($host, $port, $uri='/ping', $query='') {
+ require_once 'fcgi.inc';
+ $client = new Adoy\FastCGI\Client($host, $port);
+ $params = array(
+ 'GATEWAY_INTERFACE' => 'FastCGI/1.0',
+ 'REQUEST_METHOD' => 'GET',
+ 'SCRIPT_FILENAME' => $uri,
+ 'SCRIPT_NAME' => $uri,
+ 'QUERY_STRING' => $query,
+ 'REQUEST_URI' => $uri . ($query ? '?'.$query : ""),
+ 'DOCUMENT_URI' => $uri,
+ 'SERVER_SOFTWARE' => 'php/fcgiclient',
+ 'REMOTE_ADDR' => '127.0.0.1',
+ 'REMOTE_PORT' => '9985',
+ 'SERVER_ADDR' => '127.0.0.1',
+ 'SERVER_PORT' => '80',
+ 'SERVER_NAME' => php_uname('n'),
+ 'SERVER_PROTOCOL' => 'HTTP/1.1',
+ 'CONTENT_TYPE' => '',
+ 'CONTENT_LENGTH' => 0
+ );
+ return $client->request($params, false)."\n";
+}
diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c
index 13439460ae..a9f27fcea1 100644
--- a/sapi/litespeed/lsapi_main.c
+++ b/sapi/litespeed/lsapi_main.c
@@ -478,8 +478,8 @@ static int init_request_info( TSRMLS_D )
SG(request_info).content_length = LSAPI_GetReqBodyLen();
SG(request_info).path_translated = estrdup( LSAPI_GetScriptFileName());
- /* It is not reset by zend engine, set it to 0. */
- SG(sapi_headers).http_response_code = 0;
+ /* It is not reset by zend engine, set it to 200. */
+ SG(sapi_headers).http_response_code = 200;
pAuth = LSAPI_GetHeader( H_AUTHORIZATION );
php_handle_auth_data(pAuth TSRMLS_CC);
diff --git a/sapi/phpdbg/config.m4 b/sapi/phpdbg/config.m4
index 528abb5822..87d38ea8c5 100644
--- a/sapi/phpdbg/config.m4
+++ b/sapi/phpdbg/config.m4
@@ -22,14 +22,10 @@ if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then
fi
if test "$PHP_PHPDBG_WEBHELPER" != "no"; then
- if ! test -d ext/phpdbg_webhelper; then
- ln -s ../sapi/phpdbg ext/phpdbg_webhelper
- fi
- if test "$PHP_JSON" != "no"; then
- PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared)
- else
- AC_MSG_ERROR(Webhelper extension of phpdbg needs json enabled)
+ if ! test -d $abs_srcdir/ext/phpdbg_webhelper; then
+ ln -s ../sapi/phpdbg $abs_srcdir/ext/phpdbg_webhelper
fi
+ PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared)
fi
PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
diff --git a/sapi/phpdbg/config.w32 b/sapi/phpdbg/config.w32
index 6f0bd8f811..8a685d3347 100644
--- a/sapi/phpdbg/config.w32
+++ b/sapi/phpdbg/config.w32
@@ -1,5 +1,6 @@
ARG_ENABLE('phpdbg', 'Build phpdbg', 'no');
ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no');
+ARG_ENABLE('phpdbg-webhelper', 'Build phpdbg webhelper', 'yes');
PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c ' +
'phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c ' +
@@ -14,6 +15,10 @@ if (PHP_PHPDBG == "yes") {
ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib");
ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H");
ADD_FLAG("LDFLAGS_PHPDBG", "/stack:8388608");
+
+ if (PHP_PHPDBG_WEBHELPER == "yes") {
+ EXTENSION('phpdbg_webhelper', 'phpdbg_rinit_hook.c phpdbg_webdata_transfer.c');
+ }
}
if (PHP_PHPDBGS == "yes") {
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c
index d70e512751..ec65a22f12 100644
--- a/sapi/phpdbg/phpdbg.c
+++ b/sapi/phpdbg/phpdbg.c
@@ -45,6 +45,7 @@
#endif /* }}} */
ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
+int phpdbg_startup_run = 0;
static PHP_INI_MH(OnUpdateEol)
{
@@ -184,7 +185,8 @@ static void php_phpdbg_destroy_registered(zval *data) /* {{{ */
static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
{
- zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], 8, NULL, php_phpdbg_destroy_bp_file, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
@@ -214,8 +216,8 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
zend_hash_destroy(&PHPDBG_G(seek));
- zend_hash_destroy(&PHPDBG_G(registered));
zend_hash_destroy(&PHPDBG_G(file_sources));
+ zend_hash_destroy(&PHPDBG_G(registered));
zend_hash_destroy(&PHPDBG_G(watchpoints));
zend_llist_destroy(&PHPDBG_G(watchlist_mem));
@@ -297,26 +299,55 @@ static PHP_FUNCTION(phpdbg_exec)
}
} /* }}} */
-/* {{{ proto void phpdbg_break([integer type, string expression])
+/* {{{ proto void phpdbg_break()
instructs phpdbg to insert a breakpoint at the next opcode */
-static PHP_FUNCTION(phpdbg_break)
+static PHP_FUNCTION(phpdbg_break_next)
{
- if (ZEND_NUM_ARGS() > 0) {
- long type = 0;
- char *expr = NULL;
- int expr_len = 0;
- phpdbg_param_t param;
+ if (zend_parse_parameters_none() == FAILURE && EG(current_execute_data)) {
+ return;
+ }
+
+ phpdbg_set_breakpoint_opline_ex((phpdbg_opline_ptr_t) EG(current_execute_data)->opline + 1 TSRMLS_CC);
+} /* }}} */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &type, &expr, &expr_len) == FAILURE) {
- return;
- }
+/* {{{ proto void phpdbg_break_file(string file, integer line) */
+static PHP_FUNCTION(phpdbg_break_file)
+{
+ char *file = NULL;
+ size_t flen = 0;
+ long line;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &file, &flen, &line) == FAILURE) {
+ return;
+ }
+
+ phpdbg_set_breakpoint_file(file, line TSRMLS_CC);
+} /* }}} */
- phpdbg_parse_param(expr, expr_len, &param TSRMLS_CC);
- phpdbg_do_break(&param TSRMLS_CC);
- phpdbg_clear_param(&param TSRMLS_CC);
- } else if (EG(current_execute_data) && EG(current_execute_data)->func->type != ZEND_INTERNAL_FUNCTION) {
- phpdbg_set_breakpoint_opline_ex((phpdbg_opline_ptr_t) EG(current_execute_data)->opline + 1 TSRMLS_CC);
+/* {{{ proto void phpdbg_break_method(string class, string method) */
+static PHP_FUNCTION(phpdbg_break_method)
+{
+ char *class = NULL, *method = NULL;
+ size_t clen = 0, mlen = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &class, &clen, &method, &mlen) == FAILURE) {
+ return;
}
+
+ phpdbg_set_breakpoint_method(class, method TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto void phpdbg_break_function(string function) */
+static PHP_FUNCTION(phpdbg_break_function)
+{
+ char *function = NULL;
+ size_t function_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &function, &function_len) == FAILURE) {
+ return;
+ }
+
+ phpdbg_set_breakpoint_symbol(function, function_len TSRMLS_CC);
} /* }}} */
/* {{{ proto void phpdbg_clear(void)
@@ -324,6 +355,7 @@ static PHP_FUNCTION(phpdbg_break)
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]);
@@ -368,9 +400,21 @@ static PHP_FUNCTION(phpdbg_prompt)
phpdbg_set_prompt(prompt TSRMLS_CC);
} /* }}} */
-ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_arginfo, 0, 0, 0)
- ZEND_ARG_INFO(0, type)
- ZEND_ARG_INFO(0, expression)
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_file_arginfo, 0, 0, 2)
+ ZEND_ARG_INFO(0, file)
+ ZEND_ARG_INFO(0, line)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_method_arginfo, 0, 0, 2)
+ ZEND_ARG_INFO(0, class)
+ ZEND_ARG_INFO(0, method)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_function_arginfo, 0, 0, 1)
+ ZEND_ARG_INFO(0, function)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0)
@@ -391,7 +435,10 @@ ZEND_END_ARG_INFO()
zend_function_entry phpdbg_user_functions[] = {
PHP_FE(phpdbg_clear, phpdbg_clear_arginfo)
- PHP_FE(phpdbg_break, phpdbg_break_arginfo)
+ PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo)
+ PHP_FE(phpdbg_break_file, phpdbg_break_file_arginfo)
+ PHP_FE(phpdbg_break_method, phpdbg_break_method_arginfo)
+ PHP_FE(phpdbg_break_function, phpdbg_break_function_arginfo)
PHP_FE(phpdbg_exec, phpdbg_exec_arginfo)
PHP_FE(phpdbg_color, phpdbg_color_arginfo)
PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
@@ -469,13 +516,11 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
case E_COMPILE_ERROR:
case E_USER_ERROR:
case E_PARSE:
- case E_RECOVERABLE_ERROR:
- if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
- const char *file_char = zend_get_executed_filename(TSRMLS_C);
- zend_string *file = zend_string_init(file_char, strlen(file_char), 0);
- phpdbg_list_file(file, 3, zend_get_executed_lineno(TSRMLS_C) - 1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
- efree(file);
- }
+ case E_RECOVERABLE_ERROR: {
+ const char *file_char = zend_get_executed_filename(TSRMLS_C);
+ zend_string *file = zend_string_init(file_char, strlen(file_char), 0);
+ phpdbg_list_file(file, 3, zend_get_executed_lineno(TSRMLS_C) - 1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
+ efree(file);
do {
switch (phpdbg_interactive(1 TSRMLS_CC)) {
@@ -485,20 +530,38 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
case PHPDBG_NEXT:
return;
}
- } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
-
+ } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
+ }
}
- } else fprintf(stdout, "%s\n", message);
+ } else {
+ fprintf(stdout, "%s\n", message);
+ }
}
/* }}} */
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;
}
/* }}} */
@@ -705,7 +768,8 @@ const char phpdbg_ini_hardcoded[] =
"log_errors=On\n"
"max_execution_time=0\n"
"max_input_time=-1\n"
-"error_log=\n\0";
+"error_log=\n"
+"output_buffering=off\n\0";
/* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
#define INI_DEFAULT(name, value) \
@@ -728,7 +792,7 @@ static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */
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 {
+ } else if (phpdbg_startup_run == 0) {
if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
phpdbg_notice(NULL, NULL, "Clean Execution Environment");
}
@@ -752,7 +816,7 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */
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;
+ PHPDBG_G(flags) |= PHPDBG_IS_STOPPING;
zend_bailout();
}
} else {
@@ -936,8 +1000,7 @@ int main(int argc, char **argv) /* {{{ */
zend_ulong zend_extensions_len = 0L;
zend_bool ini_ignore;
char *ini_override;
- char *exec;
- size_t exec_len;
+ char *exec = NULL;
char *init_file;
size_t init_file_len;
zend_bool init_file_default;
@@ -946,24 +1009,16 @@ int main(int argc, char **argv) /* {{{ */
zend_ulong flags;
char *php_optarg;
int php_optind, opt, show_banner = 1;
- long cleaning = 0;
+ long cleaning = -1;
zend_bool remote = 0;
- int run = 0;
int step = 0;
-
-#ifdef _WIN32
- char *bp_tmp_file = NULL;
-#else
- char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX";
-#endif
-
-#ifndef _WIN32
+ zend_phpdbg_globals *settings = NULL;
+ char *bp_tmp = NULL;
char *address;
int listen = -1;
int server = -1;
int socket = -1;
FILE* stream = NULL;
-#endif
#ifdef ZTS
void ***tsrm_ls;
@@ -995,37 +1050,12 @@ 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("tmpfile", "", "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;
@@ -1035,14 +1065,16 @@ 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':
- run++;
+ phpdbg_startup_run++;
break;
case 'n':
ini_ignore = 1;
@@ -1181,10 +1213,8 @@ phpdbg_main:
}
/* set exec if present on command line */
- if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS))
- {
- exec_len = strlen(argv[php_optind]);
- if (exec_len) {
+ if (!exec && (argc > php_optind) && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
+ if (strlen(argv[php_optind])) {
if (exec) {
free(exec);
}
@@ -1252,21 +1282,32 @@ phpdbg_main:
void (*_free)(void*);
void* (*_realloc)(void*, size_t);
-#ifndef _WIN32
- /* setup remote server if necessary */
- if (!cleaning && listen > 0) {
- server = phpdbg_open_socket(address, listen TSRMLS_CC);
- if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) {
- exit(0);
+ /* set flags from command line */
+ PHPDBG_G(flags) = flags;
+
+ if (settings) {
+#ifdef ZTS
+ *((zend_phpdbg_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings;
+#else
+ phpdbg_globals = *settings;
+#endif
}
- sigaction(SIGIO, &sigio_struct, NULL);
+ /* 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);
+ }
- /* set remote flag to stop service shutting down upon quit */
- remote = 1;
- }
+#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_get_custom_handlers(mm_heap, &_malloc, &_free, &_realloc);
@@ -1320,7 +1361,7 @@ phpdbg_main:
for (i = SG(request_info).argc; --i;) {
SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
}
- SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup("");
+ SG(request_info).argv[i] = exec ? estrdup(exec) : estrdup("");
php_hash_environment(TSRMLS_C);
}
@@ -1341,9 +1382,6 @@ phpdbg_main:
PG(modules_activated) = 0;
- /* set flags from command line */
- PHPDBG_G(flags) = flags;
-
#ifndef _WIN32
/* setup io here */
if (remote) {
@@ -1386,9 +1424,10 @@ phpdbg_main:
if (exec) { /* set execution context */
PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);
- PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
+ PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0;
free(exec);
+ exec = NULL;
}
if (oplog_file) { /* open oplog */
@@ -1410,21 +1449,24 @@ phpdbg_main:
/* Make stdin, stdout and stderr accessible from PHP scripts */
phpdbg_register_file_handles(TSRMLS_C);
- if (show_banner) {
+ if (show_banner && cleaning < 2) {
/* print blurb */
- phpdbg_welcome((cleaning > 0) TSRMLS_CC);
+ phpdbg_welcome(cleaning == 1 TSRMLS_CC);
}
- /* auto compile */
- if (PHPDBG_G(exec)) {
- phpdbg_compile(TSRMLS_C);
- }
+ cleaning = -1;
/* initialize from file */
PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
zend_try {
phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC);
- phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 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;
+ }
} zend_end_try();
PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
@@ -1433,33 +1475,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);
} zend_catch {
if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
- FILE *bp_tmp_fp = fopen(bp_tmp_file, "w");
- phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC);
- fclose(bp_tmp_fp);
+ 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);
+ }
cleaning = 1;
} else {
cleaning = 0;
@@ -1489,8 +1548,13 @@ phpdbg_interact:
}
#endif
} zend_end_try();
- } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
-
+ } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
+
+
+ if (PHPDBG_G(exec) && (PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
+ exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */
+ }
+
/* this must be forced */
CG(unclean_shutdown) = 0;
@@ -1512,6 +1576,11 @@ phpdbg_out:
phpdbg_out:
#endif
+ if (cleaning <= 0) {
+ PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING;
+ cleaning = -1;
+ }
+
{
int i;
/* free argv */
@@ -1521,6 +1590,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));
@@ -1540,7 +1614,25 @@ phpdbg_out:
/* this is just helpful */
PG(report_memleaks) = 0;
- php_request_shutdown((void*)0);
+ if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) {
+ php_free_shutdown_functions(TSRMLS_C);
+ zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC);
+ }
+
+ /* sapi_module.deactivate is where to backup things, last chance before mm_shutdown... */
+
+ zend_try {
+ php_request_shutdown(NULL);
+ } zend_end_try();
+
+ if ((PHPDBG_G(flags) & (PHPDBG_IS_QUITTING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_RUNNING) {
+ phpdbg_notice("stop", "type=\"normal\"", "Script ended normally");
+ cleaning++;
+ }
+
+ if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) == PHPDBG_IS_CLEANING) {
+ settings = PHPDBG_G(backup);
+ }
php_output_deactivate(TSRMLS_C);
@@ -1552,7 +1644,7 @@ phpdbg_out:
}
- if (cleaning || remote) {
+ if (cleaning > 0 || remote) {
goto phpdbg_main;
}
@@ -1571,11 +1663,5 @@ phpdbg_out:
free(PHPDBG_G(sapi_name_ptr));
}
-#ifdef _WIN32
- free(bp_tmp_file);
-#else
- unlink(bp_tmp_file);
-#endif
-
return 0;
} /* }}} */
diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h
index f3e8ba3107..60d1239a27 100644
--- a/sapi/phpdbg/phpdbg.h
+++ b/sapi/phpdbg/phpdbg.h
@@ -29,8 +29,12 @@
# define PHPDBG_API
#endif
-#include <stdint.h>
-#include <stddef.h>
+#ifndef PHP_WIN32
+# include <stdint.h>
+# include <stddef.h>
+#else
+# include "win32/php_stdint.h"
+#endif
#include "php.h"
#include "php_globals.h"
#include "php_variables.h"
@@ -50,7 +54,6 @@
#if defined(_WIN32) && !defined(__MINGW32__)
# include <windows.h>
# include "config.w32.h"
-# include "win32/php_stdint.h"
# undef strcasecmp
# undef strncasecmp
# define strcasecmp _stricmp
@@ -67,29 +70,11 @@
# include "TSRM.h"
#endif
-#define ZEND_HASH_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
- ZEND_HASH_FOREACH(ht, 0); \
- _h = _p->h; \
- _ptr = Z_PTR_P(_z);
-
#undef zend_hash_str_add
#define zend_hash_str_add_tmp(ht, key, len, pData) \
_zend_hash_str_add(ht, key, len, pData ZEND_FILE_LINE_CC)
#define zend_hash_str_add(...) zend_hash_str_add_tmp(__VA_ARGS__)
-static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
-{
- zval tmp, *zv;
-
- ZVAL_PTR(&tmp, NULL);
- if ((zv = zend_hash_index_add(ht, h, &tmp))) {
- Z_PTR_P(zv) = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
- memcpy(Z_PTR_P(zv), pData, size);
- return Z_PTR_P(zv);
- }
- return NULL;
-}
-
#ifdef HAVE_LIBREADLINE
# include <readline/readline.h>
# include <readline/history.h>
@@ -139,6 +124,7 @@ static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulon
#include "phpdbg_utils.h"
#include "phpdbg_btree.h"
#include "phpdbg_watch.h"
+#include "phpdbg_bp.h"
#ifdef PHP_WIN32
# include "phpdbg_sigio_win32.h"
#endif
@@ -154,70 +140,64 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
*/
-/* {{{ tables */
-#define PHPDBG_BREAK_FILE 0
-#define PHPDBG_BREAK_SYM 1
-#define PHPDBG_BREAK_OPLINE 2
-#define PHPDBG_BREAK_METHOD 3
-#define PHPDBG_BREAK_COND 4
-#define PHPDBG_BREAK_OPCODE 5
-#define PHPDBG_BREAK_FUNCTION_OPLINE 6
-#define PHPDBG_BREAK_METHOD_OPLINE 7
-#define PHPDBG_BREAK_FILE_OPLINE 8
-#define PHPDBG_BREAK_MAP 9
-#define PHPDBG_BREAK_TABLES 10 /* }}} */
-
/* {{{ flags */
-#define PHPDBG_HAS_FILE_BP (1<<1)
-#define PHPDBG_HAS_SYM_BP (1<<2)
-#define PHPDBG_HAS_OPLINE_BP (1<<3)
-#define PHPDBG_HAS_METHOD_BP (1<<4)
-#define PHPDBG_HAS_COND_BP (1<<5)
-#define PHPDBG_HAS_OPCODE_BP (1<<6)
-#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1<<7)
-#define PHPDBG_HAS_METHOD_OPLINE_BP (1<<8)
-#define PHPDBG_HAS_FILE_OPLINE_BP (1<<9) /* }}} */
+#define PHPDBG_HAS_FILE_BP (1ULL<<1)
+#define PHPDBG_HAS_PENDING_FILE_BP (1ULL<<2)
+#define PHPDBG_HAS_SYM_BP (1ULL<<3)
+#define PHPDBG_HAS_OPLINE_BP (1ULL<<4)
+#define PHPDBG_HAS_METHOD_BP (1ULL<<5)
+#define PHPDBG_HAS_COND_BP (1ULL<<6)
+#define PHPDBG_HAS_OPCODE_BP (1ULL<<7)
+#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1ULL<<8)
+#define PHPDBG_HAS_METHOD_OPLINE_BP (1ULL<<9)
+#define PHPDBG_HAS_FILE_OPLINE_BP (1ULL<<10) /* }}} */
/*
END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
*/
-#define PHPDBG_IN_COND_BP (1<<10)
-#define PHPDBG_IN_EVAL (1<<11)
+#define PHPDBG_IN_COND_BP (1ULL<<11)
+#define PHPDBG_IN_EVAL (1ULL<<12)
-#define PHPDBG_IS_STEPPING (1<<12)
-#define PHPDBG_STEP_OPCODE (1<<13)
-#define PHPDBG_IS_QUIET (1<<14)
-#define PHPDBG_IS_QUITTING (1<<15)
-#define PHPDBG_IS_COLOURED (1<<16)
-#define PHPDBG_IS_CLEANING (1<<17)
+#define PHPDBG_IS_STEPPING (1ULL<<13)
+#define PHPDBG_STEP_OPCODE (1ULL<<14)
+#define PHPDBG_IS_QUIET (1ULL<<15)
+#define PHPDBG_IS_QUITTING (1ULL<<16)
+#define PHPDBG_IS_COLOURED (1ULL<<17)
+#define PHPDBG_IS_CLEANING (1ULL<<18)
+#define PHPDBG_IS_RUNNING (1ULL<<19)
-#define PHPDBG_IN_UNTIL (1<<18)
-#define PHPDBG_IN_FINISH (1<<19)
-#define PHPDBG_IN_LEAVE (1<<20)
+#define PHPDBG_IN_UNTIL (1ULL<<20)
+#define PHPDBG_IN_FINISH (1ULL<<21)
+#define PHPDBG_IN_LEAVE (1ULL<<22)
-#define PHPDBG_IS_REGISTERED (1<<21)
-#define PHPDBG_IS_STEPONEVAL (1<<22)
-#define PHPDBG_IS_INITIALIZING (1<<23)
-#define PHPDBG_IS_SIGNALED (1<<24)
-#define PHPDBG_IS_INTERACTIVE (1<<25)
-#define PHPDBG_IS_BP_ENABLED (1<<26)
-#define PHPDBG_IS_REMOTE (1<<27)
-#define PHPDBG_IS_DISCONNECTED (1<<28)
-#define PHPDBG_WRITE_XML (1<<29)
+#define PHPDBG_IS_REGISTERED (1ULL<<23)
+#define PHPDBG_IS_STEPONEVAL (1ULL<<24)
+#define PHPDBG_IS_INITIALIZING (1ULL<<25)
+#define PHPDBG_IS_SIGNALED (1ULL<<26)
+#define PHPDBG_IS_INTERACTIVE (1ULL<<27)
+#define PHPDBG_IS_BP_ENABLED (1ULL<<28)
+#define PHPDBG_IS_REMOTE (1ULL<<29)
+#define PHPDBG_IS_DISCONNECTED (1ULL<<30)
+#define PHPDBG_WRITE_XML (1ULL<<31)
-#define PHPDBG_SHOW_REFCOUNTS (1<<30)
+#define PHPDBG_SHOW_REFCOUNTS (1ULL<<32)
-#define PHPDBG_IN_SIGNAL_HANDLER (1<<30)
+#define PHPDBG_IN_SIGNAL_HANDLER (1ULL<<33)
-#define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL|PHPDBG_IN_FINISH|PHPDBG_IN_LEAVE)
-#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
-#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP|PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
+#define PHPDBG_DISCARD_OUTPUT (1ULL<<34)
+
+#define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL | PHPDBG_IN_FINISH | PHPDBG_IN_LEAVE)
+#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
+#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP | PHPDBG_HAS_SYM_BP | PHPDBG_HAS_METHOD_BP | PHPDBG_HAS_OPLINE_BP | PHPDBG_HAS_COND_BP | PHPDBG_HAS_OPCODE_BP | PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
+#define PHPDBG_IS_STOPPING (PHPDBG_IS_QUITTING | PHPDBG_IS_CLEANING)
+
+#define PHPDBG_PRESERVE_FLAGS_MASK (PHPDBG_SHOW_REFCOUNTS | PHPDBG_IS_STEPONEVAL | PHPDBG_IS_BP_ENABLED | PHPDBG_STEP_OPCODE | PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_REMOTE | PHPDBG_WRITE_XML | PHPDBG_IS_DISCONNECTED)
#ifndef _WIN32
-# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED)
+# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED)
#else
-# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED)
+# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_BP_ENABLED)
#endif /* }}} */
/* {{{ output descriptors */
@@ -280,6 +260,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
FILE *ptr;
int fd;
} io[PHPDBG_IO_FDS]; /* io */
+ int eol; /* type of line ending to use */
size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC);
int in_script_xml; /* in <stream> output mode */
struct {
@@ -305,17 +286,18 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
JMP_BUF *sigsegv_bailout; /* bailout address for accesibility probing */
- zend_ulong flags; /* phpdbg flags */
+ uint64_t flags; /* phpdbg flags */
char *socket_path; /* phpdbg.path ini setting */
char *sapi_name_ptr; /* store sapi name to free it if necessary to not leak memory */
int socket_fd; /* file descriptor to socket (wait command) (-1 if unused) */
int socket_server_fd; /* file descriptor to master socket (wait command) (-1 if unused) */
#ifdef PHP_WIN32
- HANDLE sigio_watcher_thread; /* sigio watcher thread handle */
+ HANDLE sigio_watcher_thread; /* sigio watcher thread handle */
struct win32_sigio_watcher_data swd;
#endif
- int8_t eol;
+
+ struct _zend_phpdbg_globals *backup; /* backup of data to store */
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
#endif
diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c
index aaeaee13fd..cd40510c79 100644
--- a/sapi/phpdbg/phpdbg_bp.c
+++ b/sapi/phpdbg/phpdbg_bp.c
@@ -104,9 +104,18 @@ PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */
PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
{
+ char *string;
+ phpdbg_export_breakpoints_to_string(&string TSRMLS_CC);
+ fputs(string, handle);
+}
+
+PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str TSRMLS_DC) /* {{{ */
+{
HashTable *table;
zend_ulong id = 0L;
+ *str = "";
+
if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) {
phpdbg_notice("exportbreakpoint", "count=\"%d\"", "Exporting %d breakpoints", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]));
@@ -116,52 +125,54 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
ZEND_HASH_FOREACH_PTR(table, brake) {
if (brake->id == id) {
+ char *new_str = NULL;
+
switch (brake->type) {
case PHPDBG_BREAK_FILE: {
- fprintf(handle,
- "break %s:%lu\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak %s:%lu\n", *str,
((phpdbg_breakfile_t*)brake)->filename,
((phpdbg_breakfile_t*)brake)->line);
} break;
case PHPDBG_BREAK_SYM: {
- fprintf(handle,
- "break %s\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak %s\n", *str,
((phpdbg_breaksymbol_t*)brake)->symbol);
} break;
case PHPDBG_BREAK_METHOD: {
- fprintf(handle,
- "break %s::%s\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak %s::%s\n", *str,
((phpdbg_breakmethod_t*)brake)->class_name,
((phpdbg_breakmethod_t*)brake)->func_name);
} break;
case PHPDBG_BREAK_METHOD_OPLINE: {
- fprintf(handle,
- "break %s::%s#%llu\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak %s::%s#%llu\n", *str,
((phpdbg_breakopline_t*)brake)->class_name,
((phpdbg_breakopline_t*)brake)->func_name,
((phpdbg_breakopline_t*)brake)->opline_num);
} break;
case PHPDBG_BREAK_FUNCTION_OPLINE: {
- fprintf(handle,
- "break %s#%llu\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak %s#%llu\n", *str,
((phpdbg_breakopline_t*)brake)->func_name,
((phpdbg_breakopline_t*)brake)->opline_num);
} break;
case PHPDBG_BREAK_FILE_OPLINE: {
- fprintf(handle,
- "break %s:#%llu\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak %s:#%llu\n", *str,
((phpdbg_breakopline_t*)brake)->class_name,
((phpdbg_breakopline_t*)brake)->opline_num);
} break;
case PHPDBG_BREAK_OPCODE: {
- fprintf(handle,
- "break %s\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak %s\n", *str,
((phpdbg_breakop_t*)brake)->name);
} break;
@@ -171,20 +182,20 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
if (conditional->paramed) {
switch (conditional->param.type) {
case STR_PARAM:
- fprintf(handle,
- "break at %s if %s\n", conditional->param.str, conditional->code);
+ phpdbg_asprintf(&new_str,
+ "%sbreak at %s if %s\n", *str, conditional->param.str, conditional->code);
break;
case METHOD_PARAM:
- fprintf(handle,
- "break at %s::%s if %s\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak at %s::%s if %s\n", *str,
conditional->param.method.class, conditional->param.method.name,
conditional->code);
break;
case FILE_PARAM:
- fprintf(handle,
- "break at %s:%lu if %s\n",
+ phpdbg_asprintf(&new_str,
+ "%sbreak at %s:%lu if %s\n", *str,
conditional->param.file.name, conditional->param.file.line,
conditional->code);
break;
@@ -192,65 +203,163 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
default: { /* do nothing */ } break;
}
} else {
- fprintf(
- handle, "break if %s\n", conditional->code);
+ phpdbg_asprintf(&new_str, "%sbreak if %s\n", str, conditional->code);
}
} break;
}
+
+ if ((*str)[0]) {
+ efree(*str);
+ }
+ *str = new_str;
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}
+
+ if (!(*str)[0]) {
+ *str = NULL;
+ }
} /* }}} */
PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRMLS_DC) /* {{{ */
{
php_stream_statbuf ssb;
char realpath[MAXPATHLEN];
+ const char *original_path = path;
+ zend_bool pending = 0;
- if (php_stream_stat_path(path, &ssb) != FAILURE) {
- if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) {
- HashTable *broken;
- phpdbg_breakfile_t new_break;
- size_t path_len = 0L;
+ HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE];
+ phpdbg_breakfile_t new_break;
+ size_t path_len = 0L;
- if (VCWD_REALPATH(path, realpath)) {
- path = realpath;
+ if (VCWD_REALPATH(path, realpath)) {
+ path = realpath;
+ }
+ path_len = strlen(path);
+
+ phpdbg_debug("file path: %s, resolved path: %s, was compiled: %d\n", original_path, path, zend_hash_exists(&PHPDBG_G(file_sources), path, path_len));
+
+ if (!zend_hash_str_exists(&PHPDBG_G(file_sources), path, path_len)) {
+ if (php_stream_stat_path(path, &ssb) == FAILURE) {
+ if (original_path[0] == '/') {
+ phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", original_path);
+ return;
}
+
+ file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING];
+ path = original_path;
path_len = strlen(path);
+ pending = 1;
+ } else if (!(ssb.sb.st_mode & (S_IFREG|S_IFLNK))) {
+ phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path);
+ return;
+ } else {
+ phpdbg_debug("File exists, but not compiled\n");
+ }
+ }
- if (!(broken = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len))) {
- HashTable breaks;
+ if (!(broken = zend_hash_str_find_ptr(file_breaks, path, path_len))) {
+ HashTable breaks;
+ zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0);
- zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0);
+ broken = zend_hash_str_add_mem(file_breaks, path, path_len, &breaks, sizeof(HashTable));
+ }
- broken = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len, &breaks, sizeof(HashTable));
- }
+ if (!zend_hash_index_exists(broken, line_num)) {
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE);
+ new_break.filename = estrndup(path, path_len);
+ new_break.line = line_num;
- if (!zend_hash_index_exists(broken, line_num)) {
- PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
+ zend_hash_index_update_mem(broken, line_num, &new_break, sizeof(phpdbg_breakfile_t));
- PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE);
- new_break.filename = estrndup(path, path_len);
- new_break.line = line_num;
+ PHPDBG_BREAK_MAPPING(new_break.id, broken);
- zend_hash_index_update_mem(broken, line_num, &new_break, sizeof(phpdbg_breakfile_t));
+ if (pending) {
+ zend_string *file, *path_str = zend_string_init(path, path_len, 0);
+ ZEND_HASH_FOREACH_STR_KEY(&PHPDBG_G(file_sources), file) {
+ HashTable *fileht;
- phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line);
+ phpdbg_debug("Compare against loaded %s\n", file);
- PHPDBG_BREAK_MAPPING(new_break.id, broken);
- } else {
- phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num);
- }
+ if (!(pending = ((fileht = phpdbg_resolve_pending_file_break_ex(file->val, file->len, path_str, broken TSRMLS_CC)) == NULL))) {
+ new_break = *(phpdbg_breakfile_t *) zend_hash_index_find_ptr(broken, line_num);
+ break;
+ }
+ } ZEND_HASH_FOREACH_END();
+ zend_string_release(path_str);
+ }
+ if (pending) {
+ PHPDBG_G(flags) |= PHPDBG_HAS_PENDING_FILE_BP;
+
+ phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\" pending=\"pending\"", "Pending breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line);
} else {
- phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path);
+ PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
+
+ phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line);
}
} else {
- phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", path);
+ phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num);
}
} /* }}} */
+PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, zend_string *cur, HashTable *fileht TSRMLS_DC) /* {{{ */
+{
+ phpdbg_debug("file: %s, filelen: %u, cur: %s, curlen %u, pos: %c, memcmp: %d\n", file, filelen, cur, curlen, filelen > curlen ? file[filelen - curlen - 1] : '?', filelen > curlen ? memcmp(file + filelen - curlen, cur, curlen) : 0);
+
+ if (((cur->len < filelen && file[filelen - cur->len - 1] == '/') || filelen == cur->len) && !memcmp(file + filelen - cur->len, cur->val, cur->len)) {
+ phpdbg_breakfile_t *brake, new_brake;
+ HashTable *master;
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
+
+ if (!(master = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen))) {
+ HashTable new_ht;
+ zend_hash_init(&new_ht, 8, NULL, phpdbg_file_breaks_dtor, 0);
+ master = zend_hash_str_add_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, &new_ht, sizeof(HashTable));
+ }
+
+ ZEND_HASH_FOREACH_PTR(fileht, brake) {
+ new_brake = *brake;
+ new_brake.filename = estrndup(file, filelen);
+ PHPDBG_BREAK_UNMAPPING(brake->id);
+
+ if (master) {
+ zend_hash_index_update_mem(master, brake->line, &new_brake, sizeof(phpdbg_breakfile_t));
+ PHPDBG_BREAK_MAPPING(brake->id, master);
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur);
+
+ if (!zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING])) {
+ PHPDBG_G(flags) &= ~PHPDBG_HAS_PENDING_FILE_BP;
+ }
+
+ phpdbg_debug("compiled file: %s, cur bp file: %s\n", file, cur);
+
+ return master;
+ }
+
+ return NULL;
+} /* }}} */
+
+PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* {{{ */
+{
+ HashTable *fileht;
+ uint filelen = strlen(file);
+ zend_string *cur;
+
+ phpdbg_debug("was compiled: %s\n", file);
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur, fileht) {
+ phpdbg_debug("check bp: %s\n", cur);
+
+ phpdbg_resolve_pending_file_break_ex(file, filelen, cur, fileht TSRMLS_CC);
+ } ZEND_HASH_FOREACH_END();
+} /* }}} */
+
PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len TSRMLS_DC) /* {{{ */
{
if (!zend_hash_str_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) {
@@ -732,8 +841,21 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_
{
HashTable *breaks;
phpdbg_breakbase_t *brake;
+ size_t path_len;
+ char realpath[MAXPATHLEN];
+ const char *path = op_array->filename->val;
+
+ if (VCWD_REALPATH(path, realpath)) {
+ path = realpath;
+ }
- if (!(breaks = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename))) {
+ path_len = strlen(path);
+
+#if 0
+ phpdbg_debug("Op at: %.*s %d\n", path_len, path, (*EG(opline_ptr))->lineno);
+#endif
+
+ if (!(breaks = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len))) {
return NULL;
}
@@ -1048,6 +1170,7 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */
PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D) /* {{{ */
{
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
@@ -1283,7 +1406,20 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */
((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : "");
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
+ } if ((PHPDBG_G(flags) & PHPDBG_HAS_PENDING_FILE_BP)) {
+ HashTable *points;
+ phpdbg_out(SEPARATE "\n");
+ phpdbg_out("Pending File Breakpoints:\n");
+ ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], points) {
+ phpdbg_breakfile_t *brake;
+
+ ZEND_HASH_FOREACH_PTR(points, brake) {
+ phpdbg_writeln("file", "id=\"%d\" name=\"%s\" line=\"%lu\" disabled=\"%s\" pending=\"pending\"", "#%d\t\t%s:%lu%s",
+ brake->id, brake->filename, brake->line,
+ ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : "");
+ } ZEND_HASH_FOREACH_END();
+ } ZEND_HASH_FOREACH_END();
} break;
case PHPDBG_BREAK_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)) {
diff --git a/sapi/phpdbg/phpdbg_bp.h b/sapi/phpdbg/phpdbg_bp.h
index 4090d90f91..99c4eb6011 100644
--- a/sapi/phpdbg/phpdbg_bp.h
+++ b/sapi/phpdbg/phpdbg_bp.h
@@ -23,16 +23,17 @@
/* {{{ defines */
#define PHPDBG_BREAK_FILE 0
-#define PHPDBG_BREAK_SYM 1
-#define PHPDBG_BREAK_OPLINE 2
-#define PHPDBG_BREAK_METHOD 3
-#define PHPDBG_BREAK_COND 4
-#define PHPDBG_BREAK_OPCODE 5
-#define PHPDBG_BREAK_FUNCTION_OPLINE 6
-#define PHPDBG_BREAK_METHOD_OPLINE 7
-#define PHPDBG_BREAK_FILE_OPLINE 8
-#define PHPDBG_BREAK_MAP 9
-#define PHPDBG_BREAK_TABLES 10 /* }}} */
+#define PHPDBG_BREAK_FILE_PENDING 1
+#define PHPDBG_BREAK_SYM 2
+#define PHPDBG_BREAK_OPLINE 3
+#define PHPDBG_BREAK_METHOD 4
+#define PHPDBG_BREAK_COND 5
+#define PHPDBG_BREAK_OPCODE 6
+#define PHPDBG_BREAK_FUNCTION_OPLINE 7
+#define PHPDBG_BREAK_METHOD_OPLINE 8
+#define PHPDBG_BREAK_FILE_OPLINE 9
+#define PHPDBG_BREAK_MAP 10
+#define PHPDBG_BREAK_TABLES 11 /* }}} */
/* {{{ */
typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */
@@ -116,10 +117,12 @@ typedef struct _phpdbg_breakcond_t {
zend_op_array *ops;
} phpdbg_breakcond_t;
-/* {{{ Opline breaks API */
+/* {{{ Resolving breaks API */
PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC);
PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC);
-PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */
+PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC);
+PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, zend_string *cur, HashTable *fileht TSRMLS_DC);
+PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC); /* }}} */
/* {{{ Breakpoint Creation API */
PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC);
@@ -154,6 +157,7 @@ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC);
PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable **table, zend_ulong *numkey, zend_string **strkey TSRMLS_DC); /* }}} */
/* {{{ Breakpoint Exportation API */
-PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */
+PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC);
+PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str TSRMLS_DC); /* }}} */
#endif /* PHPDBG_BP_H */
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c
index 729babefca..5c74adfdcd 100644
--- a/sapi/phpdbg/phpdbg_cmd.c
+++ b/sapi/phpdbg/phpdbg_cmd.c
@@ -70,79 +70,6 @@ PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_
}
}
-PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char *str, size_t len, phpdbg_param_t *param TSRMLS_DC) /* {{{ */
-{
- char *class_name, *func_name;
-
- if (len == 0) {
- param->type = EMPTY_PARAM;
- goto parsed;
- }
-
- if (phpdbg_is_addr(str)) {
- param->addr = strtoul(str, 0, 16);
- param->type = ADDR_PARAM;
- goto parsed;
-
- } else if (phpdbg_is_numeric(str)) {
- param->num = strtol(str, NULL, 0);
- param->type = NUMERIC_PARAM;
- goto parsed;
-
- } else if (phpdbg_is_class_method(str, len+1, &class_name, &func_name)) {
- param->method.class = class_name;
- param->method.name = func_name;
- param->type = METHOD_PARAM;
- goto parsed;
- } else {
- char *line_pos = strrchr(str, ':');
-
- if (line_pos && phpdbg_is_numeric(line_pos+1)) {
- if (strchr(str, ':') == line_pos) {
- char path[MAXPATHLEN];
-
- memcpy(path, str, line_pos - str);
- path[line_pos - str] = 0;
- *line_pos = 0;
- param->file.name = phpdbg_resolve_path(path TSRMLS_CC);
- param->file.line = strtol(line_pos+1, NULL, 0);
- param->type = FILE_PARAM;
-
- goto parsed;
- }
- }
-
- line_pos = strrchr(str, '#');
-
- if (line_pos && phpdbg_is_numeric(line_pos+1)) {
- if (strchr(str, '#') == line_pos) {
- param->num = strtol(line_pos + 1, NULL, 0);
-
- if (phpdbg_is_class_method(str, line_pos - str, &class_name, &func_name)) {
- param->method.class = class_name;
- param->method.name = func_name;
- param->type = NUMERIC_METHOD_PARAM;
- } else {
- param->len = line_pos - str;
- param->str = estrndup(str, param->len);
- param->type = NUMERIC_FUNCTION_PARAM;
- }
-
- goto parsed;
- }
- }
- }
-
- param->str = estrndup(str, len);
- param->len = len;
- param->type = STR_PARAM;
-
-parsed:
- phpdbg_debug("phpdbg_parse_param(\"%s\", %lu): %s",
- str, len, phpdbg_get_param_type(param TSRMLS_CC));
- return param->type;
-} /* }}} */
-
PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param TSRMLS_DC) /* {{{ */
{
if (param) {
@@ -776,80 +703,30 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async
PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
{
+ char buf[PHPDBG_MAX_CMD];
char *cmd = NULL;
char *buffer = NULL;
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) != PHPDBG_IS_STOPPING) {
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) {
fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
}
if (buffered == NULL) {
- if (0) {
-disconnect:
- PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
- zend_bailout();
- return NULL;
- }
-
#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT))
-
/* 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)
#endif
{
- char buf[PHPDBG_MAX_CMD];
- int bytes = PHPDBG_G(input_buflen), len = 0;
- if (PHPDBG_G(input_buflen)) {
- memcpy(buf, PHPDBG_G(input_buffer), bytes);
- }
-
phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C));
- PHPDBG_G(last_was_newline) = 1;
-
- do {
- int i;
- if (bytes <= 0) {
- continue;
- }
-
- for (i = len; i < len + bytes; i++) {
- if (buf[i] == '\x03') {
- if (i != len + bytes - 1) {
- memmove(buf + i, buf + i + 1, len + bytes - i - 1);
- }
- len--;
- i--;
- continue;
- }
- 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;
- /* XXX export the timeout through INI??*/
- } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0);
-
- if (bytes <= 0) {
- goto disconnect;
- }
-
- cmd = buf;
+ phpdbg_consume_stdin_line(cmd = buf TSRMLS_CC);
}
#if USE_LIB_STAR
else {
cmd = readline(phpdbg_get_prompt(TSRMLS_C));
+ PHPDBG_G(last_was_newline) = 1;
}
if (!cmd) {
@@ -863,8 +740,7 @@ readline:
} else {
cmd = buffered;
}
-end:
- PHPDBG_G(last_was_newline) = 1;
+
buffer = estrdup(cmd);
#if USE_LIB_STAR
@@ -902,3 +778,24 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */
{
efree(*input);
} /* }}} */
+
+PHPDBG_API int phpdbg_ask_user_permission(const char *question TSRMLS_DC) {
+ if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
+ char buf[PHPDBG_MAX_CMD];
+ phpdbg_out("%s", question);
+ phpdbg_out(" (type y or n): ");
+
+ while (1) {
+ phpdbg_consume_stdin_line(buf TSRMLS_CC);
+ if (buf[1] == '\n' && (buf[0] == 'y' || buf[0] == 'n')) {
+ if (buf[0] == 'y') {
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ phpdbg_out("Please enter either y (yes) or n (no): ");
+ }
+ }
+
+ return SUCCESS;
+}
diff --git a/sapi/phpdbg/phpdbg_cmd.h b/sapi/phpdbg/phpdbg_cmd.h
index 3896551c9a..a79641c080 100644
--- a/sapi/phpdbg/phpdbg_cmd.h
+++ b/sapi/phpdbg/phpdbg_cmd.h
@@ -131,6 +131,7 @@ typedef struct {
*/
PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC);
PHPDBG_API void phpdbg_destroy_input(char** TSRMLS_DC);
+PHPDBG_API int phpdbg_ask_user_permission(const char *question TSRMLS_DC);
/**
* Stack Management
@@ -144,7 +145,6 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack);
/*
* Parameter Management
*/
-PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char*, size_t, phpdbg_param_t* TSRMLS_DC);
PHPDBG_API void phpdbg_clear_param(phpdbg_param_t* TSRMLS_DC);
PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t*, phpdbg_param_t* TSRMLS_DC);
PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *, const phpdbg_param_t * TSRMLS_DC);
diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c
index 4429a7fb73..f42fc659f1 100644
--- a/sapi/phpdbg/phpdbg_frame.c
+++ b/sapi/phpdbg/phpdbg_frame.c
@@ -174,8 +174,12 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
zval *file, *line;
int i = 0, limit = num;
+ PHPDBG_OUTPUT_BACKUP();
+
if (limit < 0) {
phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit);
+
+ PHPDBG_OUTPUT_BACKUP_RESTORE();
return;
}
@@ -218,4 +222,6 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
phpdbg_xml("</backtrace>");
zval_dtor(&zbacktrace);
+
+ PHPDBG_OUTPUT_BACKUP_RESTORE();
} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_io.c b/sapi/phpdbg/phpdbg_io.c
index 97f0356285..a2a5c5969f 100644
--- a/sapi/phpdbg/phpdbg_io.c
+++ b/sapi/phpdbg/phpdbg_io.c
@@ -47,6 +47,55 @@
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+/* is easy to generalize ... but not needed for now */
+PHPDBG_API int phpdbg_consume_stdin_line(char *buf TSRMLS_DC) {
+ int bytes = PHPDBG_G(input_buflen), len = 0;
+
+ if (PHPDBG_G(input_buflen)) {
+ memcpy(buf, PHPDBG_G(input_buffer), bytes);
+ }
+
+ PHPDBG_G(last_was_newline) = 1;
+
+ do {
+ int i;
+ if (bytes <= 0) {
+ continue;
+ }
+
+ for (i = len; i < len + bytes; i++) {
+ if (buf[i] == '\x03') {
+ if (i != len + bytes - 1) {
+ memmove(buf + i, buf + i + 1, len + bytes - i - 1);
+ }
+ len--;
+ i--;
+ continue;
+ }
+ 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;
+ }
+ return i;
+ }
+ }
+
+ len += bytes;
+ } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0);
+
+ if (bytes <= 0) {
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED;
+ zend_bailout();
+ return 0;
+ }
+
+ return bytes;
+}
+
PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC) {
int got_now, i = len, j;
char *p = ptr;
diff --git a/sapi/phpdbg/phpdbg_io.h b/sapi/phpdbg/phpdbg_io.h
index 3ac8f4112d..a5659e88c6 100644
--- a/sapi/phpdbg/phpdbg_io.h
+++ b/sapi/phpdbg/phpdbg_io.h
@@ -21,6 +21,8 @@
#include "phpdbg.h"
+PHPDBG_API int phpdbg_consume_stdin_line(char *buf TSRMLS_DC);
+
PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC);
PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len);
PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC);
diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c
index de03a3651e..f201be9850 100644
--- a/sapi/phpdbg/phpdbg_list.c
+++ b/sapi/phpdbg/phpdbg_list.c
@@ -126,8 +126,16 @@ void phpdbg_list_file(zend_string *filename, uint count, int offset, uint highli
{
uint line, lastline;
phpdbg_file_source *data;
+ char resolved_path_buf[MAXPATHLEN];
+ const char *abspath;
- if (!(data = zend_hash_find_ptr(&PHPDBG_G(file_sources), filename))) {
+ if (VCWD_REALPATH(filename->val, resolved_path_buf)) {
+ abspath = resolved_path_buf;
+ } else {
+ abspath = filename->val;
+ }
+
+ if (!(data = zend_hash_str_find_ptr(&PHPDBG_G(file_sources), abspath, strlen(abspath)))) {
phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file...");
return;
}
@@ -230,6 +238,7 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) {
char *filename = (char *)(file->opened_path ? file->opened_path : file->filename);
uint line;
char *bufptr, *endptr;
+ char resolved_path_buf[MAXPATHLEN];
zend_stream_fixup(file, &data.buf, &data.len TSRMLS_CC);
@@ -256,6 +265,9 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) {
fake.opened_path = file->opened_path;
*(dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * data.len)) = data;
+ if (VCWD_REALPATH(filename, resolved_path_buf)) {
+ filename = resolved_path_buf;
+ }
for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) {
if (*bufptr == '\n') {
@@ -267,6 +279,7 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) {
dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
zend_hash_str_add_ptr(&PHPDBG_G(file_sources), filename, strlen(filename), dataptr);
+ phpdbg_resolve_pending_file_break(filename TSRMLS_CC);
ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC);
diff --git a/sapi/phpdbg/phpdbg_out.c b/sapi/phpdbg/phpdbg_out.c
index 4d70381533..a9edd19ad9 100644
--- a/sapi/phpdbg/phpdbg_out.c
+++ b/sapi/phpdbg/phpdbg_out.c
@@ -1118,6 +1118,8 @@ PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, int fd, const char *tag, const
}
if (PHPDBG_G(err_buf).active && type != P_STDOUT && type != P_STDERR) {
+ phpdbg_free_err_buf(TSRMLS_C);
+
PHPDBG_G(err_buf).type = type;
PHPDBG_G(err_buf).fd = fd;
PHPDBG_G(err_buf).tag = estrdup(tag);
@@ -1167,6 +1169,10 @@ PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const
va_list args;
int errbuf_active = PHPDBG_G(err_buf).active;
+ if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) {
+ return 0;
+ }
+
PHPDBG_G(err_buf).active = 0;
#ifdef ZTS
@@ -1187,6 +1193,10 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *tag, const c
va_list args;
int len;
+ if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) {
+ return 0;
+ }
+
va_start(args, strfmt);
len = phpdbg_vprint(type TSRMLS_CC, fd, tag, xmlfmt, strfmt, args);
va_end(args);
@@ -1197,6 +1207,10 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *tag, const c
PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) {
int len = 0;
+ if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) {
+ return 0;
+ }
+
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
va_list args;
char *buffer;
@@ -1242,6 +1256,10 @@ PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) {
int buflen;
int len = 0;
+ if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) {
+ return 0;
+ }
+
va_start(args, fmt);
buflen = phpdbg_xml_vasprintf(&buffer, fmt, 0, args TSRMLS_CC);
va_end(args);
diff --git a/sapi/phpdbg/phpdbg_parser.c b/sapi/phpdbg/phpdbg_parser.c
index 8bb9103a98..b4da3ed593 100644
--- a/sapi/phpdbg/phpdbg_parser.c
+++ b/sapi/phpdbg/phpdbg_parser.c
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.6. */
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison implementation for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.6"
+#define YYBISON_VERSION "2.7.12-4996"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -69,8 +69,7 @@
#define yynerrs phpdbg_nerrs
/* Copy the first part of user declarations. */
-
-/* Line 336 of yacc.c */
+/* Line 371 of yacc.c */
#line 1 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
@@ -98,9 +97,8 @@ static int yyerror(void ***tsrm_ls, const char *msg);
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
-
-/* Line 336 of yacc.c */
-#line 104 "sapi/phpdbg/phpdbg_parser.c"
+/* Line 371 of yacc.c */
+#line 102 "sapi/phpdbg/phpdbg_parser.c"
# ifndef YY_NULL
# if defined __cplusplus && 201103L <= __cplusplus
@@ -120,8 +118,8 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
/* In a future release of Bison, this section will be replaced
by #include "phpdbg_parser.h". */
-#ifndef PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H
-# define PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H
+#ifndef YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
+# define YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
@@ -130,8 +128,7 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
extern int phpdbg_debug;
#endif
/* "%code requires" blocks. */
-
-/* Line 350 of yacc.c */
+/* Line 387 of yacc.c */
#line 31 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
#include "phpdbg.h"
@@ -141,9 +138,8 @@ typedef void* yyscan_t;
#endif
-
-/* Line 350 of yacc.c */
-#line 147 "sapi/phpdbg/phpdbg_parser.c"
+/* Line 387 of yacc.c */
+#line 143 "sapi/phpdbg/phpdbg_parser.c"
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -217,13 +213,12 @@ int phpdbg_parse ();
#endif
#endif /* ! YYPARSE_PARAM */
-#endif /* !PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H */
+#endif /* !YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */
/* Copy the second part of user declarations. */
-
-/* Line 353 of yacc.c */
-#line 227 "sapi/phpdbg/phpdbg_parser.c"
+/* Line 390 of yacc.c */
+#line 222 "sapi/phpdbg/phpdbg_parser.c"
#ifdef short
# undef short
@@ -276,24 +271,33 @@ typedef short int yytype_int16;
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
# endif
# endif
# ifndef YY_
-# define YY_(msgid) msgid
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+# define __attribute__(Spec) /* empty */
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
#else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
#endif
+
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
@@ -621,10 +625,10 @@ static const yytype_uint8 yytable[] =
32, 36, 39, 40, 0, 0, 41, 42, 27
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-16))
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-16)))
-#define yytable_value_is_error(yytable_value) \
+#define yytable_value_is_error(Yytable_value) \
YYID (0)
static const yytype_int8 yycheck[] =
@@ -691,47 +695,18 @@ do \
} \
while (YYID (0))
-
+/* Error token number */
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-
-
/* This macro is provided for backward compatibility. */
-
#ifndef YY_LOCATION_PRINT
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
-
#ifdef YYLEX_PARAM
# define YYLEX yylex (&yylval, YYLEX_PARAM)
#else
@@ -793,11 +768,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, tsrm_ls)
# else
YYUSE (yyoutput);
# endif
- switch (yytype)
- {
- default:
- break;
- }
+ YYUSE (yytype);
}
@@ -1040,7 +1011,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
{
YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
/* Internationalized format string. */
const char *yyformat = YY_NULL;
@@ -1103,11 +1073,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
break;
}
yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
}
}
}
@@ -1127,10 +1099,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
# undef YYCASE_
}
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
if (*yymsg_alloc < yysize)
{
@@ -1188,12 +1162,7 @@ yydestruct (yymsg, yytype, yyvaluep, tsrm_ls)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
- switch (yytype)
- {
-
- default:
- break;
- }
+ YYUSE (yytype);
}
@@ -1228,8 +1197,31 @@ yyparse (tsrm_ls)
/* The lookahead symbol. */
int yychar;
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+static YYSTYPE yyval_default;
+# define YY_INITIAL_VALUE(Value) = Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
/* Number of syntax errors so far. */
int yynerrs;
@@ -1260,7 +1252,7 @@ YYSTYPE yylval;
int yyn;
int yyresult;
/* Lookahead token as an internal (translated) token number. */
- int yytoken;
+ int yytoken = 0;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
@@ -1278,9 +1270,8 @@ YYSTYPE yylval;
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1289,14 +1280,6 @@ YYSTYPE yylval;
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
-
goto yysetstate;
/*------------------------------------------------------------.
@@ -1437,7 +1420,9 @@ yybackup:
yychar = YYEMPTY;
yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1474,36 +1459,31 @@ yyreduce:
switch (yyn)
{
case 3:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 68 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); }
break;
case 5:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 73 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); }
break;
case 6:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 74 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); }
break;
case 7:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 75 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 8:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 79 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = FILE_PARAM;
@@ -1513,8 +1493,7 @@ yyreduce:
break;
case 9:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 84 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_FILE_PARAM;
@@ -1524,8 +1503,7 @@ yyreduce:
break;
case 10:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 89 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = FILE_PARAM;
@@ -1540,8 +1518,7 @@ yyreduce:
break;
case 11:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 99 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_FILE_PARAM;
@@ -1556,8 +1533,7 @@ yyreduce:
break;
case 12:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 109 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = METHOD_PARAM;
@@ -1567,8 +1543,7 @@ yyreduce:
break;
case 13:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 114 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_METHOD_PARAM;
@@ -1579,8 +1554,7 @@ yyreduce:
break;
case 14:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 120 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_FUNCTION_PARAM;
@@ -1591,8 +1565,7 @@ yyreduce:
break;
case 15:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 126 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = COND_PARAM;
@@ -1602,64 +1575,55 @@ yyreduce:
break;
case 16:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 131 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 17:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 132 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 18:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 133 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 19:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 134 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 20:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 135 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 21:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 136 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 22:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 137 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 23:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 141 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{ PHPDBG_G(req_id) = (yyvsp[(1) - (1)]).num; }
break;
case 25:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 146 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = EVAL_PARAM;
@@ -1669,8 +1633,7 @@ yyreduce:
break;
case 26:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 151 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = SHELL_PARAM;
@@ -1680,8 +1643,7 @@ yyreduce:
break;
case 27:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 156 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = RUN_PARAM;
@@ -1690,8 +1652,7 @@ yyreduce:
break;
case 28:
-
-/* Line 1803 of yacc.c */
+/* Line 1802 of yacc.c */
#line 160 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = RUN_PARAM;
@@ -1701,9 +1662,8 @@ yyreduce:
break;
-
-/* Line 1803 of yacc.c */
-#line 1707 "sapi/phpdbg/phpdbg_parser.c"
+/* Line 1802 of yacc.c */
+#line 1667 "sapi/phpdbg/phpdbg_parser.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -1866,7 +1826,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -1932,8 +1894,7 @@ yyreturn:
}
-
-/* Line 2049 of yacc.c */
+/* Line 2050 of yacc.c */
#line 167 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
@@ -1960,4 +1921,3 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) {
return yyparse(NULL);
#endif
}
-
diff --git a/sapi/phpdbg/phpdbg_parser.h b/sapi/phpdbg/phpdbg_parser.h
index e8ab7a6503..8d4aeacc31 100644
--- a/sapi/phpdbg/phpdbg_parser.h
+++ b/sapi/phpdbg/phpdbg_parser.h
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.6. */
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison interface for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,8 +30,8 @@
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
-#ifndef PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H
-# define PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H
+#ifndef YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
+# define YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
@@ -40,8 +40,7 @@
extern int phpdbg_debug;
#endif
/* "%code requires" blocks. */
-
-/* Line 2056 of yacc.c */
+/* Line 2060 of yacc.c */
#line 31 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
#include "phpdbg.h"
@@ -51,9 +50,8 @@ typedef void* yyscan_t;
#endif
-
-/* Line 2056 of yacc.c */
-#line 57 "sapi/phpdbg/phpdbg_parser.h"
+/* Line 2060 of yacc.c */
+#line 55 "sapi/phpdbg/phpdbg_parser.h"
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -127,4 +125,4 @@ int phpdbg_parse ();
#endif
#endif /* ! YYPARSE_PARAM */
-#endif /* !PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H */
+#endif /* !YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
index 190907e687..aa431a8ae0 100644
--- a/sapi/phpdbg/phpdbg_prompt.c
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -29,7 +29,6 @@
#include "phpdbg_print.h"
#include "phpdbg_info.h"
#include "phpdbg_break.h"
-#include "phpdbg_bp.h"
#include "phpdbg_opcode.h"
#include "phpdbg_list.h"
#include "phpdbg_utils.h"
@@ -43,6 +42,7 @@
#include "phpdbg_eol.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+extern int phpdbg_startup_run;
#ifdef HAVE_LIBDL
#ifdef PHP_WIN32
@@ -200,93 +200,128 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ *
return FAILURE;
} /* }}} */
-void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */
-{
- struct stat sb;
+struct phpdbg_init_state {
+ int line;
+ zend_bool in_code;
+ char *code;
+ size_t code_len;
+ const char *init_file;
+};
- if (init_file && VCWD_STAT(init_file, &sb) != -1) {
- FILE *fp = fopen(init_file, "r");
- if (fp) {
- int line = 1;
+static void phpdbg_line_init(char *cmd, struct phpdbg_init_state *state TSRMLS_DC) {
+ size_t cmd_len = strlen(cmd);
- char cmd[PHPDBG_MAX_CMD];
- size_t cmd_len = 0L;
- char *code = NULL;
- size_t code_len = 0L;
- zend_bool in_code = 0;
+ state->line++;
- while (fgets(cmd, PHPDBG_MAX_CMD, fp) != NULL) {
- cmd_len = strlen(cmd)-1;
-
- while (cmd_len > 0L && isspace(cmd[cmd_len-1]))
- cmd_len--;
-
- cmd[cmd_len] = '\0';
-
- if (*cmd && cmd_len > 0L && cmd[0] != '#') {
- if (cmd_len == 2) {
- if (memcmp(cmd, "<:", sizeof("<:")-1) == SUCCESS) {
- in_code = 1;
- goto next_line;
- } else {
- if (memcmp(cmd, ":>", sizeof(":>")-1) == SUCCESS) {
- in_code = 0;
- code[code_len] = '\0';
- {
- zend_eval_stringl(code, code_len, NULL, "phpdbginit code" TSRMLS_CC);
- }
- free(code);
- code = NULL;
- goto next_line;
- }
- }
- }
+ while (cmd_len > 0L && isspace(cmd[cmd_len-1])) {
+ cmd_len--;
+ }
- if (in_code) {
- if (code == NULL) {
- code = malloc(cmd_len + 1);
- } else code = realloc(code, code_len + cmd_len + 1);
+ cmd[cmd_len] = '\0';
- if (code) {
- memcpy(
- &code[code_len], cmd, cmd_len);
- code_len += cmd_len;
- }
- goto next_line;
- }
+ if (*cmd && cmd_len > 0L && cmd[0] != '#') {
+ if (cmd_len == 2) {
+ if (memcmp(cmd, "<:", sizeof("<:")-1) == SUCCESS) {
+ state->in_code = 1;
+ return;
+ } else {
+ if (memcmp(cmd, ":>", sizeof(":>")-1) == SUCCESS) {
+ state->in_code = 0;
+ state->code[state->code_len] = '\0';
+ zend_eval_stringl(state->code, state->code_len, NULL, "phpdbginit code" TSRMLS_CC);
+ free(state->code);
+ state->code = NULL;
+ return;
+ }
+ }
+ }
+
+ if (state->in_code) {
+ if (state->code == NULL) {
+ state->code = malloc(cmd_len + 1);
+ } else {
+ state->code = realloc(state->code, state->code_len + cmd_len + 1);
+ }
+
+ if (state->code) {
+ memcpy(&state->code[state->code_len], cmd, cmd_len);
+ state->code_len += cmd_len;
+ }
+
+ return;
+ }
- {
- char *input = phpdbg_read_input(cmd TSRMLS_CC);
- phpdbg_param_t stack;
+ zend_try {
+ char *input = phpdbg_read_input(cmd TSRMLS_CC);
+ phpdbg_param_t stack;
- phpdbg_init_param(&stack, STACK_PARAM);
+ phpdbg_init_param(&stack, STACK_PARAM);
- phpdbg_activate_err_buf(1 TSRMLS_CC);
+ phpdbg_activate_err_buf(1 TSRMLS_CC);
- if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) {
- switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */ TSRMLS_CC)) {
- case FAILURE:
- phpdbg_activate_err_buf(0 TSRMLS_CC);
- if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) {
- phpdbg_output_err_buf("initfailure", "%b file=\"%s\" line=\"%d\" input=\"%s\"", "Unrecognized command in %s:%d: %s, %b!" TSRMLS_CC, init_file, line, input);
- }
- break;
+ if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) {
+ switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */ TSRMLS_CC)) {
+ case FAILURE:
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) {
+ if (state->init_file) {
+ phpdbg_output_err_buf("initfailure", "%b file=\"%s\" line=\"%d\" input=\"%s\"", "Unrecognized command in %s:%d: %s, %b!" TSRMLS_CC, state->init_file, state->line, input);
+ } else {
+ phpdbg_output_err_buf("initfailure", "%b line=\"%d\" input=\"%s\"", "Unrecognized command on line %d: %s, %b!" TSRMLS_CC, state->line, input);
}
}
+ break;
+ }
+ }
- phpdbg_activate_err_buf(0 TSRMLS_CC);
- phpdbg_free_err_buf(TSRMLS_C);
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ phpdbg_free_err_buf(TSRMLS_C);
- phpdbg_stack_free(&stack);
- phpdbg_destroy_input(&input TSRMLS_CC);
- }
- }
-next_line:
- line++;
+ phpdbg_stack_free(&stack);
+ phpdbg_destroy_input(&input TSRMLS_CC);
+ } zend_catch {
+ PHPDBG_G(flags) &= ~(PHPDBG_IS_RUNNING | PHPDBG_IS_CLEANING);
+ if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
+ zend_bailout();
+ }
+ } zend_end_try();
+ }
+
+}
+
+void phpdbg_string_init(char *buffer TSRMLS_DC) {
+ struct phpdbg_init_state state = {0};
+ char *str = strtok(buffer, "\n");
+
+ while (str) {
+ phpdbg_line_init(str, &state TSRMLS_CC);
+
+ str = strtok(NULL, "\n");
+ }
+
+ if (state.code) {
+ free(state.code);
+ }
+}
+
+void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */
+{
+ struct stat sb;
+
+ if (init_file && VCWD_STAT(init_file, &sb) != -1) {
+ FILE *fp = fopen(init_file, "r");
+ if (fp) {
+ char cmd[PHPDBG_MAX_CMD];
+ struct phpdbg_init_state state = {0};
+
+ state.init_file = init_file;
+
+ while (fgets(cmd, PHPDBG_MAX_CMD, fp) != NULL) {
+ phpdbg_line_init(cmd, &state TSRMLS_CC);
}
- if (code) {
- free(code);
+ if (state.code) {
+ free(state.code);
}
fclose(fp);
@@ -347,6 +382,11 @@ PHPDBG_COMMAND(exec) /* {{{ */
size_t res_len = strlen(res);
if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) {
+ if (PHPDBG_G(in_execution)) {
+ if (phpdbg_ask_user_permission("Do you really want to stop execution to set a new execution context?" TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+ }
if (PHPDBG_G(exec)) {
phpdbg_notice("exec", "type=\"unset\" context=\"%s\"", "Unsetting old execution context: %s", PHPDBG_G(exec));
@@ -370,9 +410,11 @@ PHPDBG_COMMAND(exec) /* {{{ */
phpdbg_notice("exec", "type=\"set\" context=\"%s\"", "Set execution context: %s", PHPDBG_G(exec));
- if (phpdbg_compile(TSRMLS_C) == FAILURE) {
- phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s", PHPDBG_G(exec));
+ if (PHPDBG_G(in_execution)) {
+ phpdbg_clean(1 TSRMLS_CC);
}
+
+ phpdbg_compile(TSRMLS_C);
} else {
phpdbg_notice("exec", "type=\"unchanged\"", "Execution context not changed");
}
@@ -391,11 +433,6 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */
if (!PHPDBG_G(exec)) {
phpdbg_error("inactive", "type=\"nocontext\"", "No execution context");
- return SUCCESS;
- }
-
- if (PHPDBG_G(in_execution)) {
- phpdbg_error("inactive", "type=\"isrunning\"", "Cannot compile while in execution");
return FAILURE;
}
@@ -404,6 +441,7 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */
zend_destroy_file_handle(&fh TSRMLS_CC);
phpdbg_notice("compile", "context=\"%s\"", "Successful compilation of %s", PHPDBG_G(exec));
+
return SUCCESS;
} else {
phpdbg_error("compile", "type=\"openfailure\" context=\"%s\"", "Could not open file %s", PHPDBG_G(exec));
@@ -540,15 +578,18 @@ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */
PHPDBG_COMMAND(run) /* {{{ */
{
- if (PHPDBG_G(in_execution)) {
- phpdbg_error("inactive", "type=\"isrunning\"", "Cannot start another execution while one is in progress");
- return SUCCESS;
- }
-
if (PHPDBG_G(ops) || PHPDBG_G(exec)) {
zend_execute_data *ex = EG(current_execute_data);
zend_bool restore = 1;
+ if (PHPDBG_G(in_execution)) {
+ if (phpdbg_ask_user_permission("Do you really want to restart execution?" TSRMLS_CC) == SUCCESS) {
+ phpdbg_startup_run++;
+ phpdbg_clean(1 TSRMLS_CC);
+ }
+ return SUCCESS;
+ }
+
if (!PHPDBG_G(ops)) {
if (phpdbg_compile(TSRMLS_C) == FAILURE) {
phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s, cannot run", PHPDBG_G(exec));
@@ -597,12 +638,17 @@ PHPDBG_COMMAND(run) /* {{{ */
zend_try {
PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
+ PHPDBG_G(flags) |= PHPDBG_IS_RUNNING;
zend_execute(PHPDBG_G(ops), &PHPDBG_G(retval) TSRMLS_CC);
PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
- phpdbg_notice("stop", "type=\"normal\"", "Script ended normally");
} zend_catch {
PHPDBG_G(in_execution) = 0;
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+
+ if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
+ zend_bailout();
+ }
+
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
phpdbg_error("stop", "type=\"bailout\"", "Caught exit/error from VM");
restore = 0;
}
@@ -618,6 +664,10 @@ PHPDBG_COMMAND(run) /* {{{ */
phpdbg_handle_exception(TSRMLS_C);
}
}
+
+ phpdbg_clean(1 TSRMLS_CC);
+
+ PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING;
} else {
phpdbg_error("inactive", "type=\"nocontext\"", "Nothing to execute!");
}
@@ -645,12 +695,21 @@ PHPDBG_COMMAND(ev) /* {{{ */
zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING) == PHPDBG_IS_STEPPING);
zval retval;
+ zend_execute_data *original_execute_data = EG(current_execute_data);
+ zend_class_entry *original_scope = EG(scope);
+ zend_vm_stack original_stack = EG(vm_stack);
+ original_stack->top = EG(vm_stack_top);
+
+ PHPDBG_OUTPUT_BACKUP();
+
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
phpdbg_try_access {
phpdbg_parse_variable(param->str, param->len, &EG(symbol_table).ht, 0, phpdbg_output_ev_variable, 0 TSRMLS_CC);
} phpdbg_catch_access {
phpdbg_error("signalsegv", "", "Could not fetch data, invalid data source");
} phpdbg_end_try_access();
+
+ PHPDBG_OUTPUT_BACKUP_RESTORE();
return SUCCESS;
}
@@ -672,6 +731,12 @@ PHPDBG_COMMAND(ev) /* {{{ */
phpdbg_out("\n");
zval_ptr_dtor(&retval);
}
+ } zend_catch {
+ EG(current_execute_data) = original_execute_data;
+ EG(scope) = original_scope;
+ EG(vm_stack_top) = original_stack->top;
+ EG(vm_stack_end) = original_stack->end;
+ EG(vm_stack) = original_stack;
} zend_end_try();
PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL;
@@ -682,6 +747,8 @@ PHPDBG_COMMAND(ev) /* {{{ */
CG(unclean_shutdown) = 0;
+ PHPDBG_OUTPUT_BACKUP_RESTORE();
+
return SUCCESS;
} /* }}} */
@@ -1043,7 +1110,7 @@ PHPDBG_COMMAND(register) /* {{{ */
phpdbg_notice("register", "function=\"%s\"", "Registered %s", lcname);
} else {
- phpdbg_error("register", "type=\"notfoundc\" function=\"%s\"", "The requested function (%s) could not be found", param->str);
+ phpdbg_error("register", "type=\"notfound\" function=\"%s\"", "The requested function (%s) could not be found", param->str);
}
} else {
phpdbg_error("register", "type=\"inuse\" function=\"%s\"", "The requested name (%s) is already in use", lcname);
@@ -1056,8 +1123,9 @@ PHPDBG_COMMAND(register) /* {{{ */
PHPDBG_COMMAND(quit) /* {{{ */
{
/* don't allow this to loop, ever ... */
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+ PHPDBG_G(flags) &= ~(PHPDBG_IS_RUNNING | PHPDBG_IS_CLEANING);
zend_bailout();
}
@@ -1067,8 +1135,9 @@ PHPDBG_COMMAND(quit) /* {{{ */
PHPDBG_COMMAND(clean) /* {{{ */
{
if (PHPDBG_G(in_execution)) {
- phpdbg_error("inactive", "type=\"isrunning\"", "Cannot clean environment while executing");
- return SUCCESS;
+ if (phpdbg_ask_user_permission("Do you really want to clean your current environment?" TSRMLS_CC) == FAILURE) {
+ return SUCCESS;
+ }
}
phpdbg_out("Cleaning Execution Environment\n");
@@ -1079,6 +1148,8 @@ PHPDBG_COMMAND(clean) /* {{{ */
phpdbg_writeln("clean", "constants=\"%d\"", "Constants %d", zend_hash_num_elements(EG(zend_constants)));
phpdbg_writeln("clean", "includes=\"%d\"", "Includes %d", zend_hash_num_elements(&EG(included_files)));
+ PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING;
+
phpdbg_clean(1 TSRMLS_CC);
phpdbg_xml("</cleaninfo>");
@@ -1156,60 +1227,65 @@ int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */
PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
- input = phpdbg_read_input(NULL TSRMLS_CC);
+ while (ret == SUCCESS || ret == FAILURE) {
+ if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_STOPPING) {
+ zend_bailout();
+ }
- if (input) {
- do {
- phpdbg_init_param(&stack, STACK_PARAM);
+ if (!(input = phpdbg_read_input(NULL TSRMLS_CC))) {
+ break;
+ }
- if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) {
- phpdbg_activate_err_buf(1 TSRMLS_CC);
+
+ phpdbg_init_param(&stack, STACK_PARAM);
+
+ if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) {
+ phpdbg_activate_err_buf(1 TSRMLS_CC);
#ifdef PHP_WIN32
#define PARA ((phpdbg_param_t *)stack.next)->type
- if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) {
- sigio_watcher_start();
- }
+ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) {
+ sigio_watcher_start();
+ }
#endif
- switch (ret = phpdbg_stack_execute(&stack, allow_async_unsafe TSRMLS_CC)) {
- case FAILURE:
- if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
- if (!allow_async_unsafe || phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) {
- phpdbg_output_err_buf(NULL, "%b", "%b" TSRMLS_CC);
- }
+ switch (ret = phpdbg_stack_execute(&stack, allow_async_unsafe TSRMLS_CC)) {
+ case FAILURE:
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
+ if (!allow_async_unsafe || phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) {
+ phpdbg_output_err_buf(NULL, "%b", "%b" TSRMLS_CC);
}
- break;
+ }
+ break;
- case PHPDBG_LEAVE:
- case PHPDBG_FINISH:
- case PHPDBG_UNTIL:
- case PHPDBG_NEXT: {
- phpdbg_activate_err_buf(0 TSRMLS_CC);
- phpdbg_free_err_buf(TSRMLS_C);
- if (!PHPDBG_G(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
- phpdbg_error("command", "type=\"noexec\"", "Not running");
- }
- goto out;
+ case PHPDBG_LEAVE:
+ case PHPDBG_FINISH:
+ case PHPDBG_UNTIL:
+ case PHPDBG_NEXT: {
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ phpdbg_free_err_buf(TSRMLS_C);
+ if (!PHPDBG_G(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
+ phpdbg_error("command", "type=\"noexec\"", "Not running");
}
+ break;
}
+ }
- phpdbg_activate_err_buf(0 TSRMLS_CC);
- phpdbg_free_err_buf(TSRMLS_C);
+ phpdbg_activate_err_buf(0 TSRMLS_CC);
+ phpdbg_free_err_buf(TSRMLS_C);
#ifdef PHP_WIN32
- if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) {
- sigio_watcher_stop();
- }
+ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) {
+ sigio_watcher_stop();
+ }
#undef PARA
#endif
- }
+ }
- phpdbg_stack_free(&stack);
- phpdbg_destroy_input(&input TSRMLS_CC);
- PHPDBG_G(req_id) = 0;
- } while ((input = phpdbg_read_input(NULL TSRMLS_CC)));
+ phpdbg_stack_free(&stack);
+ phpdbg_destroy_input(&input TSRMLS_CC);
+ PHPDBG_G(req_id) = 0;
+ input = NULL;
}
-out:
if (input) {
phpdbg_stack_free(&stack);
phpdbg_destroy_input(&input TSRMLS_CC);
@@ -1268,6 +1344,10 @@ void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
zend_hash_init(&vars, execute_data->func->op_array.last, NULL, NULL, 0);
+ if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) && !(PHPDBG_G(flags) & PHPDBG_IS_RUNNING)) {
+ zend_bailout();
+ }
+
PHPDBG_G(in_execution) = 1;
while (1) {
@@ -1413,7 +1493,7 @@ void phpdbg_force_interruption(TSRMLS_D) {
next:
PHPDBG_G(flags) &= ~PHPDBG_IN_SIGNAL_HANDLER;
- if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
+ if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
zend_bailout();
}
}
diff --git a/sapi/phpdbg/phpdbg_prompt.h b/sapi/phpdbg/phpdbg_prompt.h
index 94e24df833..f583f2cdcd 100644
--- a/sapi/phpdbg/phpdbg_prompt.h
+++ b/sapi/phpdbg/phpdbg_prompt.h
@@ -22,6 +22,7 @@
#define PHPDBG_PROMPT_H
/* {{{ */
+void phpdbg_string_init(char *buffer TSRMLS_DC);
void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC);
void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC);
int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC);
diff --git a/sapi/phpdbg/phpdbg_rinit_hook.c b/sapi/phpdbg/phpdbg_rinit_hook.c
index 1bf891654d..ab976c4ddb 100644
--- a/sapi/phpdbg/phpdbg_rinit_hook.c
+++ b/sapi/phpdbg/phpdbg_rinit_hook.c
@@ -99,3 +99,7 @@ zend_module_entry phpdbg_webhelper_module_entry = {
PHPDBG_VERSION,
STANDARD_MODULE_PROPERTIES
};
+
+#ifdef COMPILE_DL_PHPDBG_WEBHELPER
+ZEND_GET_MODULE(phpdbg_webhelper)
+#endif
diff --git a/sapi/phpdbg/phpdbg_sigio_win32.c b/sapi/phpdbg/phpdbg_sigio_win32.c
index 24e9ac0e0a..158e034872 100644
--- a/sapi/phpdbg/phpdbg_sigio_win32.c
+++ b/sapi/phpdbg/phpdbg_sigio_win32.c
@@ -33,30 +33,31 @@ SigIoWatcherThread(VOID *p)
struct win32_sigio_watcher_data *swd = (struct win32_sigio_watcher_data *)p;
#ifdef ZTS
void ***tsrm_ls = swd->tsrm_ls;
-top:
- (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1, tsrm_ls);
-#else
-top:
- (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1);
#endif
+top:
+ (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1 TSRMLS_CC);
+
if (3 == sig) {
- printf("signaled, got %d", sig);
/* XXX completely not sure it is done right here */
- if (swd->flags & PHPDBG_IS_INTERACTIVE) {
+ if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
if (raise(sig)) {
- /* just out*/
- exit(0);
+ goto top;
}
}
- if (swd->flags & PHPDBG_IS_SIGNALED) {
+ if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
phpdbg_set_sigsafe_mem(&sig TSRMLS_CC);
zend_try {
phpdbg_force_interruption(TSRMLS_C);
} zend_end_try();
phpdbg_clear_sigsafe_mem(TSRMLS_C);
+ goto end;
+ }
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
+ PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
}
+end:
/* XXX set signaled flag to the caller thread, question is - whether it's needed */
ExitThread(sig);
} else {
@@ -74,8 +75,6 @@ sigio_watcher_start(void)
TSRMLS_FETCH();
PHPDBG_G(swd).fd = PHPDBG_G(io)[PHPDBG_STDIN].fd;
- PHPDBG_G(swd).running = 1;
- PHPDBG_G(swd).flags = PHPDBG_G(flags);
#ifdef ZTS
PHPDBG_G(swd).tsrm_ls = tsrm_ls;
#endif
@@ -113,8 +112,6 @@ sigio_watcher_stop(void)
}
PHPDBG_G(swd).fd = -1;
- PHPDBG_G(swd).running = 0;
- PHPDBG_G(swd).flags = 0;
PHPDBG_G(sigio_watcher_thread) = INVALID_HANDLE_VALUE;
}
diff --git a/sapi/phpdbg/phpdbg_sigio_win32.h b/sapi/phpdbg/phpdbg_sigio_win32.h
index 796b477f93..8c8a381d64 100644
--- a/sapi/phpdbg/phpdbg_sigio_win32.h
+++ b/sapi/phpdbg/phpdbg_sigio_win32.h
@@ -25,12 +25,10 @@
#include "phpdbg_io.h"
struct win32_sigio_watcher_data {
- zend_ulong flags;
#ifdef ZTS
void ***tsrm_ls;
#endif
int fd;
- zend_uchar running;
};
void
diff --git a/sapi/phpdbg/phpdbg_utils.h b/sapi/phpdbg/phpdbg_utils.h
index 83dc8e9694..feb5470b69 100644
--- a/sapi/phpdbg/phpdbg_utils.h
+++ b/sapi/phpdbg/phpdbg_utils.h
@@ -94,4 +94,29 @@ int phpdbg_is_auto_global(char *name, int len TSRMLS_DC);
PHPDBG_API void phpdbg_xml_var_dump(zval *zv TSRMLS_DC);
+#ifdef ZTS
+#define PHPDBG_OUTPUT_BACKUP_DEFINES() \
+ zend_output_globals *output_globals_ptr; \
+ zend_output_globals original_output_globals; \
+ output_globals_ptr = (zend_output_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)];
+#else
+#define PHPDBG_OUTPUT_BACKUP_DEFINES() \
+ zend_output_globals *output_globals_ptr; \
+ zend_output_globals original_output_globals; \
+ output_globals_ptr = &output_globals;
+#endif
+
+#define PHPDBG_OUTPUT_BACKUP_SWAP() \
+ original_output_globals = *output_globals_ptr; \
+ memset(output_globals_ptr, 0, sizeof(zend_output_globals)); \
+ php_output_activate(TSRMLS_C);
+
+#define PHPDBG_OUTPUT_BACKUP() \
+ PHPDBG_OUTPUT_BACKUP_DEFINES() \
+ PHPDBG_OUTPUT_BACKUP_SWAP()
+
+#define PHPDBG_OUTPUT_BACKUP_RESTORE() \
+ php_output_deactivate(TSRMLS_C); \
+ *output_globals_ptr = original_output_globals;
+
#endif /* PHPDBG_UTILS_H */
diff --git a/sapi/phpdbg/phpdbg_wait.c b/sapi/phpdbg/phpdbg_wait.c
index 9051ca379f..a76dda88e4 100644
--- a/sapi/phpdbg/phpdbg_wait.c
+++ b/sapi/phpdbg/phpdbg_wait.c
@@ -18,11 +18,10 @@
#include "phpdbg_wait.h"
#include "phpdbg_prompt.h"
-#include "ext/json/JSON_parser.h"
+#include "ext/standard/php_var.h"
#include "ext/standard/basic_functions.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
-ZEND_EXTERN_MODULE_GLOBALS(json);
static void phpdbg_rebuild_http_globals_array(int type, const char *name TSRMLS_DC) {
zval *zvp;
@@ -126,16 +125,18 @@ static int phpdbg_array_intersect(phpdbg_intersect_ptr *info, zval **ptr) {
}
void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC) {
-#ifdef HAVE_JSON
zval *free_zv = NULL;
zval zv, *zvp;
HashTable *ht;
- php_json_decode(&zv, msg, len, 1, 1000 /* enough */ TSRMLS_CC);
+ php_unserialize_data_t var_hash;
- if (JSON_G(error_code) != PHP_JSON_ERROR_NONE) {
- phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed JSON was sent to this socket, arborting");
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ if (!php_var_unserialize(&zv, (const unsigned char **) &msg, (unsigned char *) msg + len, &var_hash TSRMLS_CC)) {
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed serialized was sent to this socket, arborting");
return;
}
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
ht = Z_ARRVAL(zv);
@@ -339,12 +340,11 @@ void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC) {
/* Reapply raw input */
/* ??? */
-#endif
}
PHPDBG_COMMAND(wait) /* {{{ */
{
-#ifdef HAVE_JSON
+#ifndef PHP_WIN32
struct sockaddr_un local, remote;
int rlen, sr, sl;
unlink(PHPDBG_G(socket_path));
@@ -394,7 +394,7 @@ PHPDBG_COMMAND(wait) /* {{{ */
efree(data);
phpdbg_notice("wait", "import=\"success\"", "Successfully imported request data, stopped before executing");
+#endif
return SUCCESS;
-#endif
} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_webdata_transfer.c b/sapi/phpdbg/phpdbg_webdata_transfer.c
index 2f18b9d082..5ce6759062 100644
--- a/sapi/phpdbg/phpdbg_webdata_transfer.c
+++ b/sapi/phpdbg/phpdbg_webdata_transfer.c
@@ -17,7 +17,7 @@
*/
#include "phpdbg_webdata_transfer.h"
-#include "ext/json/php_json.h"
+#include "ext/standard/php_var.h"
static int phpdbg_is_auto_global(char *name, int len TSRMLS_DC) {
int ret;
@@ -28,8 +28,6 @@ static int phpdbg_is_auto_global(char *name, int len TSRMLS_DC) {
}
PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC) {
-#ifdef HAVE_JSON
- smart_str buf = {0};
zval array;
HashTable *ht;
zval zv[9] = {{{0}}};
@@ -162,9 +160,16 @@ PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC) {
}
/* encode data */
- php_json_encode(&buf, &array, 0 TSRMLS_CC);
- *msg = buf.s->val;
- *len = buf.s->len;
+ {
+ php_serialize_data_t var_hash;
+ smart_str buf = {0};
+
+ PHP_VAR_SERIALIZE_INIT(var_hash);
+ php_var_serialize(&buf, &array, &var_hash TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+ *msg = buf.s->val;
+ *len = buf.s->len;
+ }
+
zval_dtor(&array);
-#endif
}
diff --git a/sapi/phpdbg/tests/commands/0104_clean.test b/sapi/phpdbg/tests/commands/0104_clean.test
index d50903c479..2c7660ad60 100644
--- a/sapi/phpdbg/tests/commands/0104_clean.test
+++ b/sapi/phpdbg/tests/commands/0104_clean.test
@@ -9,7 +9,6 @@
#Functions %d
#Constants %d
#Includes %d
-#[Nothing to execute!]
#################################################
clean
quit