summaryrefslogtreecommitdiff
path: root/sapi
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2014-01-28 10:57:59 +0100
committerOndřej Surý <ondrej@sury.org>2014-01-28 10:57:59 +0100
commit575107aad92a460051e02de029067359083542b9 (patch)
tree462d4270312d11a5c064e151e3fdd2f671bd540b /sapi
parent650fb41a77b3a24ab4130b05fff243b64b241877 (diff)
downloadphp-575107aad92a460051e02de029067359083542b9.tar.gz
New upstream version 5.6.0~alpha1+dfsgupstream/5.6.0_alpha1+dfsg
Diffstat (limited to 'sapi')
-rw-r--r--sapi/aolserver/aolserver.c2
-rw-r--r--sapi/apache/libpre.c2
-rw-r--r--sapi/apache/mod_php5.c2
-rw-r--r--sapi/apache/mod_php5.h2
-rw-r--r--sapi/apache/php_apache.c2
-rw-r--r--sapi/apache/php_apache_http.h2
-rw-r--r--sapi/apache/sapi_apache.c2
-rw-r--r--sapi/apache2filter/apache_config.c2
-rw-r--r--sapi/apache2filter/php_apache.h2
-rw-r--r--sapi/apache2filter/php_functions.c2
-rw-r--r--sapi/apache2filter/sapi_apache2.c2
-rw-r--r--sapi/apache2handler/apache_config.c2
-rw-r--r--sapi/apache2handler/mod_php5.c2
-rw-r--r--sapi/apache2handler/php_apache.h2
-rw-r--r--sapi/apache2handler/php_functions.c2
-rw-r--r--sapi/apache2handler/sapi_apache2.c2
-rw-r--r--sapi/apache_hooks/mod_php5.c2
-rw-r--r--sapi/apache_hooks/mod_php5.h2
-rw-r--r--sapi/apache_hooks/php_apache.c2
-rw-r--r--sapi/apache_hooks/sapi_apache.c2
-rw-r--r--sapi/caudium/caudium.c2
-rw-r--r--sapi/cgi/cgi_main.c17
-rw-r--r--sapi/cgi/fastcgi.c2
-rw-r--r--sapi/cgi/fastcgi.h2
-rw-r--r--sapi/cli/cli.h2
-rw-r--r--sapi/cli/php_cli.c4
-rw-r--r--sapi/cli/php_cli_process_title.c2
-rw-r--r--sapi/cli/php_cli_process_title.h2
-rw-r--r--sapi/cli/php_cli_server.c9
-rw-r--r--sapi/cli/php_cli_server.h2
-rw-r--r--sapi/cli/php_http_parser.h6
-rw-r--r--sapi/cli/ps_title.c2
-rw-r--r--sapi/cli/ps_title.h2
-rw-r--r--sapi/cli/tests/php_cli_server.inc6
-rw-r--r--sapi/cli/tests/upload_2G.phpt99
-rw-r--r--sapi/continuity/capi.c2
-rw-r--r--sapi/embed/php_embed.c2
-rw-r--r--sapi/embed/php_embed.h2
-rw-r--r--sapi/fpm/config.m433
-rw-r--r--sapi/fpm/fpm/events/devpoll.c2
-rw-r--r--sapi/fpm/fpm/events/devpoll.h2
-rw-r--r--sapi/fpm/fpm/events/epoll.c2
-rw-r--r--sapi/fpm/fpm/events/epoll.h2
-rw-r--r--sapi/fpm/fpm/events/kqueue.c2
-rw-r--r--sapi/fpm/fpm/events/kqueue.h2
-rw-r--r--sapi/fpm/fpm/events/poll.c2
-rw-r--r--sapi/fpm/fpm/events/poll.h2
-rw-r--r--sapi/fpm/fpm/events/port.c2
-rw-r--r--sapi/fpm/fpm/events/port.h2
-rw-r--r--sapi/fpm/fpm/events/select.c2
-rw-r--r--sapi/fpm/fpm/events/select.h2
-rw-r--r--sapi/fpm/fpm/fastcgi.c2
-rw-r--r--sapi/fpm/fpm/fastcgi.h2
-rw-r--r--sapi/fpm/fpm/fpm.c4
-rw-r--r--sapi/fpm/fpm/fpm.h3
-rw-r--r--sapi/fpm/fpm/fpm_conf.c6
-rw-r--r--sapi/fpm/fpm/fpm_conf.h3
-rw-r--r--sapi/fpm/fpm/fpm_main.c28
-rw-r--r--sapi/fpm/fpm/fpm_php_trace.c2
-rw-r--r--sapi/fpm/fpm/fpm_scoreboard.c8
-rw-r--r--sapi/fpm/fpm/fpm_stdio.c2
-rw-r--r--sapi/fpm/fpm/fpm_unix.c35
-rw-r--r--sapi/fpm/tests/001.phpt21
-rw-r--r--sapi/fpm/tests/002.phpt53
-rw-r--r--sapi/fpm/tests/apparmor.phpt54
-rw-r--r--sapi/fpm/tests/include.inc79
-rw-r--r--sapi/fpm/tests/skipapparmor.inc30
-rw-r--r--sapi/fpm/tests/skipif.inc13
-rw-r--r--sapi/isapi/php5isapi.c2
-rw-r--r--sapi/litespeed/Makefile.frag2
-rw-r--r--sapi/litespeed/lsapi_main.c1371
-rw-r--r--sapi/litespeed/lsapidef.h33
-rw-r--r--sapi/litespeed/lsapilib.c2486
-rw-r--r--sapi/litespeed/lsapilib.h100
-rw-r--r--sapi/milter/php_milter.c4
-rw-r--r--sapi/nsapi/nsapi.c2
-rw-r--r--sapi/phpdbg/.gdbinit10
-rw-r--r--sapi/phpdbg/.gitignore5
-rw-r--r--sapi/phpdbg/.phpdbginit105
-rw-r--r--sapi/phpdbg/.travis.yml3
-rw-r--r--sapi/phpdbg/CREDITS2
-rw-r--r--sapi/phpdbg/Changelog.md52
-rw-r--r--sapi/phpdbg/Makefile.frag28
-rw-r--r--sapi/phpdbg/README.md83
-rw-r--r--sapi/phpdbg/config.m461
-rw-r--r--sapi/phpdbg/config.w3219
-rw-r--r--sapi/phpdbg/phpdbg.c1348
-rw-r--r--sapi/phpdbg/phpdbg.h188
-rwxr-xr-xsapi/phpdbg/phpdbg.init.d122
-rw-r--r--sapi/phpdbg/phpdbg_bp.c1661
-rw-r--r--sapi/phpdbg/phpdbg_bp.h146
-rw-r--r--sapi/phpdbg/phpdbg_break.c155
-rw-r--r--sapi/phpdbg/phpdbg_break.h58
-rw-r--r--sapi/phpdbg/phpdbg_cmd.c682
-rw-r--r--sapi/phpdbg/phpdbg_cmd.h169
-rw-r--r--sapi/phpdbg/phpdbg_frame.c206
-rw-r--r--sapi/phpdbg/phpdbg_frame.h30
-rw-r--r--sapi/phpdbg/phpdbg_help.c603
-rw-r--r--sapi/phpdbg/phpdbg_help.h92
-rw-r--r--sapi/phpdbg/phpdbg_info.c355
-rw-r--r--sapi/phpdbg/phpdbg_info.h49
-rw-r--r--sapi/phpdbg/phpdbg_list.c279
-rw-r--r--sapi/phpdbg/phpdbg_list.h47
-rw-r--r--sapi/phpdbg/phpdbg_opcode.c363
-rw-r--r--sapi/phpdbg/phpdbg_opcode.h31
-rw-r--r--sapi/phpdbg/phpdbg_print.c258
-rw-r--r--sapi/phpdbg/phpdbg_print.h51
-rw-r--r--sapi/phpdbg/phpdbg_prompt.c1330
-rw-r--r--sapi/phpdbg/phpdbg_prompt.h68
-rw-r--r--sapi/phpdbg/phpdbg_set.c208
-rw-r--r--sapi/phpdbg/phpdbg_set.h47
-rw-r--r--sapi/phpdbg/phpdbg_utils.c387
-rw-r--r--sapi/phpdbg/phpdbg_utils.h110
-rw-r--r--sapi/phpdbg/test.php51
-rw-r--r--sapi/phpdbg/tests/commands/0001_basic.test8
-rw-r--r--sapi/phpdbg/tests/commands/0002_set.test23
-rw-r--r--sapi/phpdbg/tests/commands/0101_info.test19
-rw-r--r--sapi/phpdbg/tests/commands/0102_print.test28
-rw-r--r--sapi/phpdbg/tests/commands/0103_register.test28
-rw-r--r--sapi/phpdbg/tests/commands/0104_clean.test15
-rw-r--r--sapi/phpdbg/tests/commands/0105_clear.test18
-rw-r--r--sapi/phpdbg/tests/commands/0106_compile.test19
-rw-r--r--sapi/phpdbg/tests/run-tests.php583
-rwxr-xr-xsapi/phpdbg/travis/ci.sh9
-rw-r--r--sapi/phpdbg/web-bootstrap.php64
-rw-r--r--sapi/phttpd/php_phttpd.h2
-rw-r--r--sapi/phttpd/phttpd.c2
-rw-r--r--sapi/pi3web/pi3web_sapi.c2
-rw-r--r--sapi/roxen/roxen.c2
-rw-r--r--sapi/thttpd/php_thttpd.h2
-rw-r--r--sapi/thttpd/thttpd.c2
-rw-r--r--sapi/tux/php_tux.c2
-rw-r--r--sapi/webjames/php_webjames.h2
-rw-r--r--sapi/webjames/webjames.c2
134 files changed, 13574 insertions, 1327 deletions
diff --git a/sapi/aolserver/aolserver.c b/sapi/aolserver/aolserver.c
index 3dcbc8d21..a89b98e57 100644
--- a/sapi/aolserver/aolserver.c
+++ b/sapi/aolserver/aolserver.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache/libpre.c b/sapi/apache/libpre.c
index 35b47cf5d..ca10e34cd 100644
--- a/sapi/apache/libpre.c
+++ b/sapi/apache/libpre.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache/mod_php5.c b/sapi/apache/mod_php5.c
index 8361f7f41..a1e5a70e8 100644
--- a/sapi/apache/mod_php5.c
+++ b/sapi/apache/mod_php5.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache/mod_php5.h b/sapi/apache/mod_php5.h
index bdbdd478d..3bc785738 100644
--- a/sapi/apache/mod_php5.h
+++ b/sapi/apache/mod_php5.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache/php_apache.c b/sapi/apache/php_apache.c
index 374519743..43a4c90ef 100644
--- a/sapi/apache/php_apache.c
+++ b/sapi/apache/php_apache.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache/php_apache_http.h b/sapi/apache/php_apache_http.h
index 12788d304..a18e5dbac 100644
--- a/sapi/apache/php_apache_http.h
+++ b/sapi/apache/php_apache_http.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache/sapi_apache.c b/sapi/apache/sapi_apache.c
index 88c99855c..f19586da1 100644
--- a/sapi/apache/sapi_apache.c
+++ b/sapi/apache/sapi_apache.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2filter/apache_config.c b/sapi/apache2filter/apache_config.c
index 333c7b8cf..7c50b9e6a 100644
--- a/sapi/apache2filter/apache_config.c
+++ b/sapi/apache2filter/apache_config.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2filter/php_apache.h b/sapi/apache2filter/php_apache.h
index 4ee3c0aa9..47fe98b5f 100644
--- a/sapi/apache2filter/php_apache.h
+++ b/sapi/apache2filter/php_apache.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2filter/php_functions.c b/sapi/apache2filter/php_functions.c
index e96ceda3f..f1ae9c974 100644
--- a/sapi/apache2filter/php_functions.c
+++ b/sapi/apache2filter/php_functions.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2filter/sapi_apache2.c b/sapi/apache2filter/sapi_apache2.c
index 8ce490ea4..da920f818 100644
--- a/sapi/apache2filter/sapi_apache2.c
+++ b/sapi/apache2filter/sapi_apache2.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2handler/apache_config.c b/sapi/apache2handler/apache_config.c
index 2b519393d..76d3ee226 100644
--- a/sapi/apache2handler/apache_config.c
+++ b/sapi/apache2handler/apache_config.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2handler/mod_php5.c b/sapi/apache2handler/mod_php5.c
index 56ef1bca4..4a01ebfd5 100644
--- a/sapi/apache2handler/mod_php5.c
+++ b/sapi/apache2handler/mod_php5.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2handler/php_apache.h b/sapi/apache2handler/php_apache.h
index 8bc46089d..34846048b 100644
--- a/sapi/apache2handler/php_apache.h
+++ b/sapi/apache2handler/php_apache.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2handler/php_functions.c b/sapi/apache2handler/php_functions.c
index 1f79a538f..2c5730092 100644
--- a/sapi/apache2handler/php_functions.c
+++ b/sapi/apache2handler/php_functions.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c
index b7f95e0c1..d2b3a327f 100644
--- a/sapi/apache2handler/sapi_apache2.c
+++ b/sapi/apache2handler/sapi_apache2.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache_hooks/mod_php5.c b/sapi/apache_hooks/mod_php5.c
index 66adb482e..a069e324c 100644
--- a/sapi/apache_hooks/mod_php5.c
+++ b/sapi/apache_hooks/mod_php5.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache_hooks/mod_php5.h b/sapi/apache_hooks/mod_php5.h
index 86a5863ab..3db828ec8 100644
--- a/sapi/apache_hooks/mod_php5.h
+++ b/sapi/apache_hooks/mod_php5.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache_hooks/php_apache.c b/sapi/apache_hooks/php_apache.c
index dde6d8877..6531ca20e 100644
--- a/sapi/apache_hooks/php_apache.c
+++ b/sapi/apache_hooks/php_apache.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/apache_hooks/sapi_apache.c b/sapi/apache_hooks/sapi_apache.c
index a9c9d674e..9ed93aea6 100644
--- a/sapi/apache_hooks/sapi_apache.c
+++ b/sapi/apache_hooks/sapi_apache.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/caudium/caudium.c b/sapi/caudium/caudium.c
index d3b834fe9..e707f3576 100644
--- a/sapi/caudium/caudium.c
+++ b/sapi/caudium/caudium.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
index 6c83f2800..f464e1e92 100644
--- a/sapi/cgi/cgi_main.c
+++ b/sapi/cgi/cgi_main.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -508,7 +508,7 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
uint read_bytes = 0;
int tmp_read_bytes;
- count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
+ count_bytes = MIN(count_bytes, SG(request_info).content_length - SG(read_post_bytes));
while (read_bytes < count_bytes) {
tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes);
if (tmp_read_bytes <= 0) {
@@ -524,8 +524,11 @@ static int sapi_fcgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
uint read_bytes = 0;
int tmp_read_bytes;
fcgi_request *request = (fcgi_request*) SG(server_context);
+ size_t remaining = SG(request_info).content_length - SG(read_post_bytes);
- count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
+ if (remaining < count_bytes) {
+ count_bytes = remaining;
+ }
while (read_bytes < count_bytes) {
tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
if (tmp_read_bytes <= 0) {
@@ -815,7 +818,7 @@ static void php_cgi_ini_activate_user_config(char *path, int path_len, const cha
}
if (real_path) {
- free(real_path);
+ efree(real_path);
}
entry->expires = request_time + PG(user_ini_cache_ttl);
}
@@ -1396,7 +1399,7 @@ static void init_request_info(fcgi_request *request TSRMLS_DC)
} else {
SG(request_info).request_uri = env_script_name;
}
- free(real_path);
+ efree(real_path);
}
} else {
/* pre 4.3 behaviour, shouldn't be used but provides BC */
@@ -2223,9 +2226,9 @@ consult the installation file that came with this distribution, or visit \n\
SG(request_info).no_headers = 1;
}
#if ZEND_DEBUG
- php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+ php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2014 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
#else
- php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+ php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2014 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
#endif
php_request_shutdown((void *) 0);
fcgi_shutdown();
diff --git a/sapi/cgi/fastcgi.c b/sapi/cgi/fastcgi.c
index 72977b633..8ddc2e457 100644
--- a/sapi/cgi/fastcgi.c
+++ b/sapi/cgi/fastcgi.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cgi/fastcgi.h b/sapi/cgi/fastcgi.h
index f1f464dc0..702f51df6 100644
--- a/sapi/cgi/fastcgi.h
+++ b/sapi/cgi/fastcgi.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cli/cli.h b/sapi/cli/cli.h
index 7686522a2..dc85893a0 100644
--- a/sapi/cli/cli.h
+++ b/sapi/cli/cli.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c
index 9f3fc4b5b..9daa382ee 100644
--- a/sapi/cli/php_cli.c
+++ b/sapi/cli/php_cli.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -693,7 +693,7 @@ static int do_cli(int argc, char **argv TSRMLS_DC) /* {{{ */
goto out;
case 'v': /* show php version & quit */
- php_printf("PHP %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2013 The PHP Group\n%s",
+ php_printf("PHP %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2014 The PHP Group\n%s",
PHP_VERSION, cli_sapi_module.name, __DATE__, __TIME__,
#if ZEND_DEBUG && defined(HAVE_GCOV)
"(DEBUG GCOV)",
diff --git a/sapi/cli/php_cli_process_title.c b/sapi/cli/php_cli_process_title.c
index c50c412b1..dec561367 100644
--- a/sapi/cli/php_cli_process_title.c
+++ b/sapi/cli/php_cli_process_title.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cli/php_cli_process_title.h b/sapi/cli/php_cli_process_title.h
index b4b0861a2..bd44d9911 100644
--- a/sapi/cli/php_cli_process_title.h
+++ b/sapi/cli/php_cli_process_title.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
index 1a634725f..3f2aaf008 100644
--- a/sapi/cli/php_cli_server.c
+++ b/sapi/cli/php_cli_server.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -893,9 +893,11 @@ static void php_cli_server_poller_remove(php_cli_server_poller *poller, int mode
static int php_cli_server_poller_poll(php_cli_server_poller *poller, const struct timeval *tv) /* {{{ */
{
+ struct timeval t = *tv;
+
memmove(&poller->active.rfds, &poller->rfds, sizeof(poller->rfds));
memmove(&poller->active.wfds, &poller->wfds, sizeof(poller->wfds));
- return php_select(poller->max_fd + 1, &poller->active.rfds, &poller->active.wfds, NULL, (struct timeval *)tv);
+ return php_select(poller->max_fd + 1, &poller->active.rfds, &poller->active.wfds, NULL, &t);
} /* }}} */
static int php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, void *opaque, int(*callback)(void *, int fd, int events)) /* {{{ */
@@ -1840,8 +1842,7 @@ static void php_cli_server_client_populate_request_info(const php_cli_server_cli
request_info->request_uri = client->request.request_uri;
request_info->path_translated = client->request.path_translated;
request_info->query_string = client->request.query_string;
- request_info->post_data = client->request.content;
- request_info->content_length = request_info->post_data_length = client->request.content_len;
+ request_info->content_length = client->request.content_len;
request_info->auth_user = request_info->auth_password = request_info->auth_digest = NULL;
if (SUCCESS == zend_hash_find(&client->request.headers, "content-type", sizeof("content-type"), (void**)&val)) {
request_info->content_type = *val;
diff --git a/sapi/cli/php_cli_server.h b/sapi/cli/php_cli_server.h
index 9a29626c7..a8d7f46e7 100644
--- a/sapi/cli/php_cli_server.h
+++ b/sapi/cli/php_cli_server.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cli/php_http_parser.h b/sapi/cli/php_http_parser.h
index 2bf235672..31502e213 100644
--- a/sapi/cli/php_http_parser.h
+++ b/sapi/cli/php_http_parser.h
@@ -29,15 +29,13 @@ extern "C" {
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__)
# include <windows.h>
-# include "win32/php_stdint.h"
# include "config.w32.h"
#else
# include "php_config.h"
-# ifdef HAVE_STDINT_H
-# include <stdint.h>
-# endif
#endif
+#include "php_stdint.h"
+
/* Compile with -DPHP_HTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
diff --git a/sapi/cli/ps_title.c b/sapi/cli/ps_title.c
index 6f3bdb862..53cd5fc9a 100644
--- a/sapi/cli/ps_title.c
+++ b/sapi/cli/ps_title.c
@@ -4,7 +4,7 @@
* PostgreSQL Database Management System (formerly known as Postgres, then as
* Postgres95)
*
- * Portions Copyright (c) 1996-2013, The PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2014, The PostgreSQL Global Development Group
*
* Portions Copyright (c) 1994, The Regents of the University of California
*
diff --git a/sapi/cli/ps_title.h b/sapi/cli/ps_title.h
index 5623653e4..09650fed0 100644
--- a/sapi/cli/ps_title.h
+++ b/sapi/cli/ps_title.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/cli/tests/php_cli_server.inc b/sapi/cli/tests/php_cli_server.inc
index 40c536199..77a79e0f0 100644
--- a/sapi/cli/tests/php_cli_server.inc
+++ b/sapi/cli/tests/php_cli_server.inc
@@ -3,7 +3,7 @@ define ("PHP_CLI_SERVER_HOSTNAME", "localhost");
define ("PHP_CLI_SERVER_PORT", 8964);
define ("PHP_CLI_SERVER_ADDRESS", PHP_CLI_SERVER_HOSTNAME.":".PHP_CLI_SERVER_PORT);
-function php_cli_server_start($code = 'echo "Hello world";', $no_router = FALSE) {
+function php_cli_server_start($code = 'echo "Hello world";', $no_router = FALSE, $cmd_args = null) {
$php_executable = getenv('TEST_PHP_EXECUTABLE');
$doc_root = __DIR__;
$router = "index.php";
@@ -19,14 +19,14 @@ function php_cli_server_start($code = 'echo "Hello world";', $no_router = FALSE)
);
if (substr(PHP_OS, 0, 3) == 'WIN') {
- $cmd = "{$php_executable} -t {$doc_root} -n -S " . PHP_CLI_SERVER_ADDRESS;
+ $cmd = "{$php_executable} -t {$doc_root} -n {$cmd_args} -S " . PHP_CLI_SERVER_ADDRESS;
if (!$no_router) {
$cmd .= " {$router}";
}
$handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, $doc_root, NULL, array("bypass_shell" => true, "suppress_errors" => true));
} else {
- $cmd = "exec {$php_executable} -t {$doc_root} -n -S " . PHP_CLI_SERVER_ADDRESS;
+ $cmd = "exec {$php_executable} -t {$doc_root} -n {$cmd_args} -S " . PHP_CLI_SERVER_ADDRESS;
if (!$no_router) {
$cmd .= " {$router}";
}
diff --git a/sapi/cli/tests/upload_2G.phpt b/sapi/cli/tests/upload_2G.phpt
new file mode 100644
index 000000000..b8416ea73
--- /dev/null
+++ b/sapi/cli/tests/upload_2G.phpt
@@ -0,0 +1,99 @@
+--TEST--
+file upload greater than 2G
+--SKIPIF--
+<?php
+include "skipif.inc";
+
+if (PHP_INT_SIZE < 8) {
+ die("skip need PHP_INT_SIZE>=8");
+}
+
+if ($f = fopen("/proc/meminfo","r")) {
+ while (!feof($f)) {
+ if (!strncmp($line = fgets($f), "MemFree", 7)) {
+ if (substr($line,8)/1024/1024 > 3) {
+ $enough_free_ram = true;
+ }
+ }
+ }
+}
+
+if (empty($enough_free_ram)) {
+ die("need +3G free RAM");
+}
+?>
+--FILE--
+<?php
+
+echo "Test\n";
+
+include "php_cli_server.inc";
+
+php_cli_server_start("var_dump(\$_FILES);", false,
+ "-d post_max_size=3G -d upload_max_filesize=3G");
+
+list($host, $port) = explode(':', PHP_CLI_SERVER_ADDRESS);
+$port = intval($port)?:80;
+$length = 2150000000;
+$output = "";
+
+$fp = fsockopen($host, $port, $errno, $errstr, 0.5);
+if (!$fp) {
+ die("connect failed");
+}
+
+$prev = "----123
+Content-Type: text/plain
+Content-Disposition: form-data; name=\"file1\"; filename=\"file1.txt\"\n\n";
+$post = "\n----123--\n";
+$total = $length + strlen($prev) + strlen($post);
+
+fwrite($fp, <<<EOF
+POST /index.php HTTP/1.1
+Host: {$host}
+Content-Type: multipart/form-data; boundary=--123
+Content-Length: {$total}
+
+{$prev}
+EOF
+) or die("write prev failed");
+
+$data = str_repeat("0123456789", 10000);
+for ($i = 0; $i < $length; $i += 10000 * 10) {
+ fwrite($fp, $data) or die("write failed @ ($i)");
+}
+
+fwrite($fp, $post) or die("write post failed");
+
+while (!feof($fp)) {
+ $output .= fgets($fp);
+}
+echo $output;
+fclose($fp);
+?>
+Done
+--EXPECTF--
+Test
+
+HTTP/1.1 200 OK
+Host: %s
+Connection: close
+X-Powered-By: PHP/%s
+Content-type: text/html
+
+array(1) {
+ ["file1"]=>
+ array(5) {
+ ["name"]=>
+ string(9) "file1.txt"
+ ["type"]=>
+ string(10) "text/plain"
+ ["tmp_name"]=>
+ string(%d) "%s"
+ ["error"]=>
+ int(0)
+ ["size"]=>
+ int(2150000000)
+ }
+}
+Done
diff --git a/sapi/continuity/capi.c b/sapi/continuity/capi.c
index 26762a5a9..953991474 100644
--- a/sapi/continuity/capi.c
+++ b/sapi/continuity/capi.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/embed/php_embed.c b/sapi/embed/php_embed.c
index 414b4dbb0..dad54de1a 100644
--- a/sapi/embed/php_embed.c
+++ b/sapi/embed/php_embed.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/embed/php_embed.h b/sapi/embed/php_embed.h
index ad5f4bc47..84c0e3633 100644
--- a/sapi/embed/php_embed.h
+++ b/sapi/embed/php_embed.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4
index bd6d64930..40cd69c71 100644
--- a/sapi/fpm/config.m4
+++ b/sapi/fpm/config.m4
@@ -536,6 +536,22 @@ AC_DEFUN([AC_FPM_SELECT],
])
dnl }}}
+AC_DEFUN([AC_FPM_APPARMOR],
+[
+ AC_MSG_CHECKING([for apparmor])
+
+ SAVED_LIBS="$LIBS"
+ LIBS="$LIBS -lapparmor"
+
+ AC_TRY_LINK([ #include <sys/apparmor.h> ], [change_hat("test", 0);], [
+ AC_DEFINE([HAVE_APPARMOR], 1, [do we have apparmor support?])
+ AC_MSG_RESULT([yes])
+ ], [
+ LIBS="$SAVED_LIBS"
+ AC_MSG_RESULT([no])
+ ])
+])
+
AC_MSG_CHECKING(for FPM build)
if test "$PHP_FPM" != "no"; then
@@ -547,14 +563,15 @@ if test "$PHP_FPM" != "no"; then
AC_FPM_TRACE
AC_FPM_BUILTIN_ATOMIC
AC_FPM_LQ
- AC_FPM_SYSCONF
- AC_FPM_TIMES
- AC_FPM_KQUEUE
- AC_FPM_PORT
- AC_FPM_DEVPOLL
- AC_FPM_EPOLL
- AC_FPM_POLL
- AC_FPM_SELECT
+ AC_FPM_SYSCONF
+ AC_FPM_TIMES
+ AC_FPM_KQUEUE
+ AC_FPM_PORT
+ AC_FPM_DEVPOLL
+ AC_FPM_EPOLL
+ AC_FPM_POLL
+ AC_FPM_SELECT
+ AC_FPM_APPARMOR
PHP_ARG_WITH(fpm-user,,
[ --with-fpm-user[=USER] Set the user for php-fpm to run as. (default: nobody)], nobody, no)
diff --git a/sapi/fpm/fpm/events/devpoll.c b/sapi/fpm/fpm/events/devpoll.c
index 223d0729c..3fa7cd454 100644
--- a/sapi/fpm/fpm/events/devpoll.c
+++ b/sapi/fpm/fpm/events/devpoll.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/devpoll.h b/sapi/fpm/fpm/events/devpoll.h
index f9bc4af19..2753cb5ab 100644
--- a/sapi/fpm/fpm/events/devpoll.h
+++ b/sapi/fpm/fpm/events/devpoll.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/epoll.c b/sapi/fpm/fpm/events/epoll.c
index c9c7f1fd6..2857ea2a0 100644
--- a/sapi/fpm/fpm/events/epoll.c
+++ b/sapi/fpm/fpm/events/epoll.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/epoll.h b/sapi/fpm/fpm/events/epoll.h
index abc5a21b1..f89e59a5f 100644
--- a/sapi/fpm/fpm/events/epoll.h
+++ b/sapi/fpm/fpm/events/epoll.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/kqueue.c b/sapi/fpm/fpm/events/kqueue.c
index 7ce076069..9fde33842 100644
--- a/sapi/fpm/fpm/events/kqueue.c
+++ b/sapi/fpm/fpm/events/kqueue.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/kqueue.h b/sapi/fpm/fpm/events/kqueue.h
index 2642acaae..16f804652 100644
--- a/sapi/fpm/fpm/events/kqueue.h
+++ b/sapi/fpm/fpm/events/kqueue.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/poll.c b/sapi/fpm/fpm/events/poll.c
index 185eceb1a..d49661413 100644
--- a/sapi/fpm/fpm/events/poll.c
+++ b/sapi/fpm/fpm/events/poll.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/poll.h b/sapi/fpm/fpm/events/poll.h
index d55319214..4a05755d0 100644
--- a/sapi/fpm/fpm/events/poll.h
+++ b/sapi/fpm/fpm/events/poll.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/port.c b/sapi/fpm/fpm/events/port.c
index 3cbf092cb..0e6a88055 100644
--- a/sapi/fpm/fpm/events/port.c
+++ b/sapi/fpm/fpm/events/port.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/port.h b/sapi/fpm/fpm/events/port.h
index 666a157d2..f127b8cda 100644
--- a/sapi/fpm/fpm/events/port.h
+++ b/sapi/fpm/fpm/events/port.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/select.c b/sapi/fpm/fpm/events/select.c
index e3af067d8..cf3331c04 100644
--- a/sapi/fpm/fpm/events/select.c
+++ b/sapi/fpm/fpm/events/select.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/events/select.h b/sapi/fpm/fpm/events/select.h
index db52503fc..74f7be2bc 100644
--- a/sapi/fpm/fpm/events/select.h
+++ b/sapi/fpm/fpm/events/select.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/fastcgi.c b/sapi/fpm/fpm/fastcgi.c
index ec579eadf..d77b6f8ca 100644
--- a/sapi/fpm/fpm/fastcgi.c
+++ b/sapi/fpm/fpm/fastcgi.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/fastcgi.h b/sapi/fpm/fpm/fastcgi.h
index ee786752e..34f9eef9d 100644
--- a/sapi/fpm/fpm/fastcgi.h
+++ b/sapi/fpm/fpm/fastcgi.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c
index b866f37f2..96a29c5f1 100644
--- a/sapi/fpm/fpm/fpm.c
+++ b/sapi/fpm/fpm/fpm.c
@@ -39,10 +39,11 @@ struct fpm_globals_s fpm_globals = {
.test_successful = 0,
.heartbeat = 0,
.run_as_root = 0,
+ .force_stderr = 0,
.send_config_pipe = {0, 0},
};
-int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon) /* {{{ */
+int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr) /* {{{ */
{
fpm_globals.argc = argc;
fpm_globals.argv = argv;
@@ -52,6 +53,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t
fpm_globals.prefix = prefix;
fpm_globals.pid = pid;
fpm_globals.run_as_root = run_as_root;
+ fpm_globals.force_stderr = force_stderr;
if (0 > fpm_php_init_main() ||
0 > fpm_stdio_init_main() ||
diff --git a/sapi/fpm/fpm/fpm.h b/sapi/fpm/fpm/fpm.h
index 65d0e0d69..4916140e1 100644
--- a/sapi/fpm/fpm/fpm.h
+++ b/sapi/fpm/fpm/fpm.h
@@ -37,7 +37,7 @@
int fpm_run(int *max_requests);
-int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon);
+int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr);
struct fpm_globals_s {
pid_t parent_pid;
@@ -55,6 +55,7 @@ struct fpm_globals_s {
int test_successful;
int heartbeat;
int run_as_root;
+ int force_stderr;
int send_config_pipe[2];
};
diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c
index cd5fc34d0..20adf91df 100644
--- a/sapi/fpm/fpm/fpm_conf.c
+++ b/sapi/fpm/fpm/fpm_conf.c
@@ -149,6 +149,9 @@ static struct ini_value_parser_s ini_fpm_pool_options[] = {
{ "chdir", &fpm_conf_set_string, WPO(chdir) },
{ "catch_workers_output", &fpm_conf_set_boolean, WPO(catch_workers_output) },
{ "security.limit_extensions", &fpm_conf_set_string, WPO(security_limit_extensions) },
+#ifdef HAVE_APPARMOR
+ { "apparmor_hat", &fpm_conf_set_string, WPO(apparmor_hat) },
+#endif
{ 0, 0, 0 }
};
@@ -644,6 +647,9 @@ int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */
free(wpc->chroot);
free(wpc->chdir);
free(wpc->security_limit_extensions);
+#ifdef HAVE_APPARMOR
+ free(wpc->apparmor_hat);
+#endif
for (kv = wpc->php_values; kv; kv = kv_next) {
kv_next = kv->next;
diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h
index efd65dc6d..4b2974904 100644
--- a/sapi/fpm/fpm/fpm_conf.h
+++ b/sapi/fpm/fpm/fpm_conf.h
@@ -87,6 +87,9 @@ struct fpm_worker_pool_config_s {
struct key_value_s *env;
struct key_value_s *php_admin_values;
struct key_value_s *php_values;
+#ifdef HAVE_APPARMOR
+ char *apparmor_hat;
+#endif
};
struct ini_value_parser_s {
diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c
index 043e0e00a..93090832f 100644
--- a/sapi/fpm/fpm/fpm_main.c
+++ b/sapi/fpm/fpm/fpm_main.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -157,6 +157,7 @@ static const opt_struct OPTIONS[] = {
{'R', 0, "allow-to-run-as-root"},
{'D', 0, "daemonize"},
{'F', 0, "nodaemonize"},
+ {'O', 0, "force-stderr"},
{'-', 0, NULL} /* end of args */
};
@@ -498,8 +499,11 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
{
uint read_bytes = 0;
int tmp_read_bytes;
+ size_t remaining = SG(request_info).content_length - SG(read_post_bytes);
- count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
+ if (remaining < count_bytes) {
+ count_bytes = remaining;
+ }
while (read_bytes < count_bytes) {
fcgi_request *request = (fcgi_request*) SG(server_context);
if (request_body_fd == -1) {
@@ -918,7 +922,7 @@ static void php_cgi_usage(char *argv0)
prog = "php";
}
- php_printf( "Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-t] [-p <prefix>] [-g <pid>] [-c <file>] [-d foo[=bar]] [-y <file>] [-D] [-F]\n"
+ php_printf( "Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-t] [-p <prefix>] [-g <pid>] [-c <file>] [-d foo[=bar]] [-y <file>] [-D] [-F [-O]]\n"
" -c <path>|<file> Look for php.ini file in this directory\n"
" -n No php.ini file will be used\n"
" -d foo[=bar] Define INI entry foo with value 'bar'\n"
@@ -937,6 +941,8 @@ static void php_cgi_usage(char *argv0)
" -D, --daemonize force to run in background, and ignore daemonize option from config file\n"
" -F, --nodaemonize\n"
" force to stay in foreground, and ignore daemonize option from config file\n"
+ " -O, --force-stderr\n"
+ " force output to stderr in nodaemonize even if stderr is not a TTY\n"
" -R, --allow-to-run-as-root\n"
" Allow pool to run as root (disabled by default)\n",
prog, PHP_PREFIX);
@@ -1350,7 +1356,7 @@ static void init_request_info(TSRMLS_D)
} else {
SG(request_info).request_uri = env_script_name;
}
- free(real_path);
+ efree(real_path);
}
} else {
/* pre 4.3 behaviour, shouldn't be used but provides BC */
@@ -1569,6 +1575,7 @@ int main(int argc, char *argv[])
char *fpm_pid = NULL;
int test_conf = 0;
int force_daemon = -1;
+ int force_stderr = 0;
int php_information = 0;
int php_allow_to_run_as_root = 0;
@@ -1697,6 +1704,10 @@ int main(int argc, char *argv[])
force_daemon = 0;
break;
+ case 'O': /* force stderr even on non tty */
+ force_stderr = 1;
+ break;
+
default:
case 'h':
case '?':
@@ -1721,9 +1732,9 @@ int main(int argc, char *argv[])
SG(request_info).no_headers = 1;
#if ZEND_DEBUG
- php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+ php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2014 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
#else
- php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+ php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2014 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
#endif
php_request_shutdown((void *) 0);
fcgi_shutdown();
@@ -1824,7 +1835,7 @@ consult the installation file that came with this distribution, or visit \n\
}
}
- if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon)) {
+ if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr)) {
if (fpm_globals.send_config_pipe[1]) {
int writeval = 0;
@@ -1982,8 +1993,9 @@ fastcgi_request_done:
out:
SG(server_context) = NULL;
+ php_module_shutdown(TSRMLS_C);
+
if (parent) {
- php_module_shutdown(TSRMLS_C);
sapi_shutdown();
}
diff --git a/sapi/fpm/fpm/fpm_php_trace.c b/sapi/fpm/fpm/fpm_php_trace.c
index d95d66a75..925f2de64 100644
--- a/sapi/fpm/fpm/fpm_php_trace.c
+++ b/sapi/fpm/fpm/fpm_php_trace.c
@@ -138,7 +138,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC
void fpm_php_trace(struct fpm_child_s *child) /* {{{ */
{
TSRMLS_FETCH();
- fpm_scoreboard_update(0, 0, 0, 0, 0, 0, 1, FPM_SCOREBOARD_ACTION_SET, child->wp->scoreboard);
+ fpm_scoreboard_update(0, 0, 0, 0, 0, 0, 1, FPM_SCOREBOARD_ACTION_INC, child->wp->scoreboard);
FILE *slowlog;
zlog(ZLOG_NOTICE, "about to trace %d", (int) child->pid);
diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c
index 24463a90d..8d0868182 100644
--- a/sapi/fpm/fpm/fpm_scoreboard.c
+++ b/sapi/fpm/fpm/fpm_scoreboard.c
@@ -111,7 +111,7 @@ void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int request
scoreboard->max_children_reached = max_children_reached;
}
if (slow_rq > 0) {
- scoreboard->slow_rq += slow_rq;
+ scoreboard->slow_rq = slow_rq;
}
} else {
if (scoreboard->idle + idle > 0) {
@@ -137,6 +137,12 @@ void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int request
} else {
scoreboard->max_children_reached = 0;
}
+
+ if (scoreboard->slow_rq + slow_rq > 0) {
+ scoreboard->slow_rq += slow_rq;
+ } else {
+ scoreboard->slow_rq = 0;
+ }
}
if (scoreboard->active > scoreboard->active_max) {
diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c
index d81e10150..33b0e01c8 100644
--- a/sapi/fpm/fpm/fpm_stdio.c
+++ b/sapi/fpm/fpm/fpm_stdio.c
@@ -292,7 +292,7 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */
} else {
fpm_globals.error_log_fd = fd;
#if HAVE_UNISTD_H
- if (fpm_global_config.daemonize || !isatty(STDERR_FILENO)) {
+ if (fpm_global_config.daemonize || (!isatty(STDERR_FILENO) && !fpm_globals.force_stderr)) {
#else
if (fpm_global_config.daemonize) {
#endif
diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c
index 48249e8a4..b32213fa7 100644
--- a/sapi/fpm/fpm/fpm_unix.c
+++ b/sapi/fpm/fpm/fpm_unix.c
@@ -17,6 +17,10 @@
#include <sys/prctl.h>
#endif
+#ifdef HAVE_APPARMOR
+#include <sys/apparmor.h>
+#endif
+
#include "fpm.h"
#include "fpm_conf.h"
#include "fpm_cleanup.h"
@@ -222,6 +226,37 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
if (0 > fpm_clock_init()) {
return -1;
}
+
+#ifdef HAVE_APPARMOR
+ if (wp->config->apparmor_hat) {
+ char *con, *new_con;
+
+ if (aa_getcon(&con, NULL) == -1) {
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to query apparmor confinement. Please check if \"/proc/*/attr/current\" is read and writeable.", wp->config->name);
+ return -1;
+ }
+
+ new_con = malloc(strlen(con) + strlen(wp->config->apparmor_hat) + 3); // // + 0 Byte
+ if (!new_con) {
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to allocate memory for apparmor hat change.", wp->config->name);
+ return -1;
+ }
+
+ if (0 > sprintf(new_con, "%s//%s", con, wp->config->apparmor_hat)) {
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to construct apparmor confinement.", wp->config->name);
+ return -1;
+ }
+
+ if (0 > aa_change_profile(new_con)) {
+ zlog(ZLOG_SYSERROR, "[pool %s] failed to change to new confinement (%s). Please check if \"/proc/*/attr/current\" is read and writeable and \"change_profile -> %s//*\" is allowed.", wp->config->name, new_con, con);
+ return -1;
+ }
+
+ free(con);
+ free(new_con);
+ }
+#endif
+
return 0;
}
/* }}} */
diff --git a/sapi/fpm/tests/001.phpt b/sapi/fpm/tests/001.phpt
new file mode 100644
index 000000000..b721bfa92
--- /dev/null
+++ b/sapi/fpm/tests/001.phpt
@@ -0,0 +1,21 @@
+--TEST--
+FPM: version string
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$php = get_fpm_path();
+
+var_dump(`$php -n -v`);
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(%d) "PHP %s (fpm%s (built: %s
+Copyright (c) 1997-20%s The PHP Group
+Zend Engine v%s, Copyright (c) 1998-20%s Zend Technologies
+"
+Done
diff --git a/sapi/fpm/tests/002.phpt b/sapi/fpm/tests/002.phpt
new file mode 100644
index 000000000..2ef6cedc3
--- /dev/null
+++ b/sapi/fpm/tests/002.phpt
@@ -0,0 +1,53 @@
+--TEST--
+FPM: Startup and connect
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[unconfined]
+listen = 127.0.0.1:9000
+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)) {
+ var_dump(fgets($tail));
+ var_dump(fgets($tail));
+ $i = 0;
+ while (($i++ < 30) && !($fp = @fsockopen('127.0.0.1', 9000))) {
+ usleep(10000);
+ }
+ if ($fp) {
+ echo "Done\n";
+ fclose($fp);
+ }
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($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
+"
+Done
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/apparmor.phpt b/sapi/fpm/tests/apparmor.phpt
new file mode 100644
index 000000000..cf9bd7111
--- /dev/null
+++ b/sapi/fpm/tests/apparmor.phpt
@@ -0,0 +1,54 @@
+--TEST--
+FPM: Apparmor Test
+--DESCRIPTION--
+This test tries to launches a pool which tries to change to non existing
+apparmor hat a. Test succeeds if apparmor is not running or hat is non
+existant.
+--SKIPIF--
+<?php
+include "skipif.inc";
+include "skipapparmor.inc";
+
+?>
+--FILE--
+<?php
+
+include "include.inc";
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[a]
+listen = 127.0.0.1:9001
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+apparmor_hat = a
+EOT;
+
+/* libapparmor has a bug which can cause SIGSEGV till Version 2.8.0-0ubuntu28
+ See https://bugs.launchpad.net/apparmor/+bug/1196880
+ Possible outcomes:
+
+ - SIGSEGV|failed to query apparmor confinement
+ apparmor not running
+ - failed to change to new confinement
+ something in apparmor went wrong
+ - exited with code 70
+ Change to successful; Hat not existant (Process gets killed by apparmor)
+ */
+var_dump(run_fpm_till('/(SIGSEGV|failed to query apparmor confinement|failed to change to new confinement|exited with code 70)/', $cfg));
+
+?>
+--EXPECTF--
+string(%d) "%s
+"
+--CLEAN--
+<?php
+ $logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+ @unlink($logfile);
+?>
diff --git a/sapi/fpm/tests/include.inc b/sapi/fpm/tests/include.inc
new file mode 100644
index 000000000..983cbd345
--- /dev/null
+++ b/sapi/fpm/tests/include.inc
@@ -0,0 +1,79 @@
+<?php
+
+function get_fpm_path() /* {{{ */
+{
+ $php_path = getenv("TEST_PHP_EXECUTABLE");
+
+ for ($i = 0; $i < 2; $i++) {
+ $slash_pos = strrpos($php_path, "/");
+ if ($slash_pos) {
+ $php_path = substr($php_path, 0, $slash_pos);
+ } else {
+ return false;
+ }
+ }
+
+ if ($php_path && is_dir($php_path) && file_exists($php_path."/fpm/php-fpm") && is_executable($php_path."/fpm/php-fpm")) {
+ /* gotcha */
+ return $php_path."/fpm/php-fpm";
+ }
+ return false;
+}
+/* }}} */
+
+function run_fpm($config, &$out = false, $extra_args = '') /* {{{ */
+{
+ $cfg = dirname(__FILE__).'/test-fpm-config.tmp';
+ file_put_contents($cfg, $config);
+ $desc = [];
+ if ($out !== false) {
+ $desc = [1 => array('pipe', 'w')];
+ }
+ /* Since it's not possible to spawn a process under linux without using a
+ * shell in php (why?!?) we need a little shell trickery, so that we can
+ * actually kill php-fpm */
+ $fpm = proc_open('killit () { kill $child; }; trap killit TERM; '.get_fpm_path().' -F -O -y '.$cfg.' '.$extra_args.' 2>&1 & child=$!; wait', $desc, $pipes);
+ register_shutdown_function(
+ function($fpm) use($cfg) {
+ @unlink($cfg);
+ if (is_resource($fpm)) {
+ @proc_terminate($fpm);
+ while (proc_get_status($fpm)['running']) {
+ usleep(10000);
+ }
+ }
+ },
+ $fpm
+ );
+ if ($out !== false) {
+ $out = $pipes[1];
+ }
+ return $fpm;
+}
+/* }}} */
+
+function run_fpm_till($needle, $config, $max = 10) /* {{{ */
+{
+ $i = 0;
+ $fpm = run_fpm($config, $tail);
+ if (is_resource($fpm)) {
+ while($i < $max) {
+ $i++;
+ $line = fgets($tail);
+ if(preg_match($needle, $line) === 1) {
+ break;
+ }
+ }
+ if ($i >= $max) {
+ $line = false;
+ }
+ proc_terminate($fpm);
+ stream_get_contents($tail);
+ fclose($tail);
+ proc_close($fpm);
+ }
+ return $line;
+}
+/* }}} */
+
+?>
diff --git a/sapi/fpm/tests/skipapparmor.inc b/sapi/fpm/tests/skipapparmor.inc
new file mode 100644
index 000000000..b286d0361
--- /dev/null
+++ b/sapi/fpm/tests/skipapparmor.inc
@@ -0,0 +1,30 @@
+<?php
+
+$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
+$cfg = <<<EOT
+[global]
+error_log = $logfile
+[a]
+listen = 127.0.0.1:9001
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 2
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+apparmor_hat = a
+EOT;
+
+$fpm = run_fpm($cfg, $out, '-t');
+$ok = false;
+if (is_resource($fpm)) {
+ if (strpos(stream_get_contents($out), "test is successful") !== FALSE) {
+ $ok = true;
+ }
+ fclose($out);
+ proc_close($fpm);
+}
+if (!$ok) {
+ die("skip No apparmor support built in");
+}
+
+?>
diff --git a/sapi/fpm/tests/skipif.inc b/sapi/fpm/tests/skipif.inc
new file mode 100644
index 000000000..8c569daaf
--- /dev/null
+++ b/sapi/fpm/tests/skipif.inc
@@ -0,0 +1,13 @@
+<?php
+
+if (substr(PHP_OS, 0, 3) == 'WIN') {
+ die ("skip not for Windows");
+}
+
+include dirname(__FILE__)."/include.inc";
+
+if (!get_fpm_path()) {
+ die("skip FPM not found");
+}
+
+?>
diff --git a/sapi/isapi/php5isapi.c b/sapi/isapi/php5isapi.c
index 002ad2ae3..d83c81ad9 100644
--- a/sapi/isapi/php5isapi.c
+++ b/sapi/isapi/php5isapi.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/litespeed/Makefile.frag b/sapi/litespeed/Makefile.frag
index b70e5e870..767c2e5eb 100644
--- a/sapi/litespeed/Makefile.frag
+++ b/sapi/litespeed/Makefile.frag
@@ -4,6 +4,6 @@ $(SAPI_LITESPEED_PATH): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_LITESPEED_OB
$(BUILD_LITESPEED)
install-litespeed: $(SAPI_LITESPEED_PATH)
- @echo "Installing PHP LitSpeed binary: $(INSTALL_ROOT)$(bindir)/"
+ @echo "Installing PHP LiteSpeed binary: $(INSTALL_ROOT)$(bindir)/"
@$(INSTALL) -m 0755 $(SAPI_LITESPEED_PATH) $(INSTALL_ROOT)$(bindir)/lsphp
diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c
index 19364c66e..33ebb988a 100644
--- a/sapi/litespeed/lsapi_main.c
+++ b/sapi/litespeed/lsapi_main.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id$ */
+/* $Id: lsapi_main.c,v 1.57 2013/08/23 14:50:25 gwang Exp $ */
#include "php.h"
#include "SAPI.h"
@@ -75,7 +75,9 @@ static int lsapi_mode = 1;
static char *php_self = "";
static char *script_filename = "";
static int source_highlight = 0;
-
+static int ignore_php_ini = 0;
+static char * argv0 = NULL;
+static int engine = 1;
#ifdef ZTS
zend_compiler_globals *compiler_globals;
zend_executor_globals *executor_globals;
@@ -90,40 +92,65 @@ zend_module_entry litespeed_module_entry;
*/
static int php_lsapi_startup(sapi_module_struct *sapi_module)
{
- if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
- return FAILURE;
- }
- return SUCCESS;
+ if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
+ return FAILURE;
+ }
+ argv0 = sapi_module->executable_location;
+ return SUCCESS;
}
/* }}} */
+/* {{{ sapi_lsapi_ini_defaults */
+
+/* overwriteable ini defaults must be set in sapi_cli_ini_defaults() */
+#define INI_DEFAULT(name,value)\
+ ZVAL_STRING(tmp, value, 0);\
+ zend_hash_update(configuration_hash, name, sizeof(name), tmp, sizeof(zval), (void**)&entry);\
+ Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry))
+
+static void sapi_lsapi_ini_defaults(HashTable *configuration_hash)
+{
+ zval *tmp, *entry;
+
+#if PHP_MAJOR_VERSION > 4
+/*
+ MAKE_STD_ZVAL(tmp);
+
+ INI_DEFAULT("register_long_arrays", "0");
+
+ FREE_ZVAL(tmp);
+*/
+#endif
+
+}
+/* }}} */
/* {{{ sapi_lsapi_ub_write
*/
static int sapi_lsapi_ub_write(const char *str, uint str_length TSRMLS_DC)
{
- int ret;
- int remain;
- if ( lsapi_mode ) {
- ret = LSAPI_Write( str, str_length );
- if ( ret < str_length ) {
- php_handle_aborted_connection();
- return str_length - ret;
- }
- } else {
- remain = str_length;
- while( remain > 0 ) {
- ret = write( 1, str, remain );
- if ( ret <= 0 ) {
- php_handle_aborted_connection();
- return str_length - remain;
- }
- str += ret;
- remain -= ret;
- }
- }
- return str_length;
+ int ret;
+ int remain;
+ if ( lsapi_mode ) {
+ ret = LSAPI_Write( str, str_length );
+ if ( ret < str_length ) {
+ php_handle_aborted_connection();
+ return str_length - ret;
+ }
+ } else {
+ remain = str_length;
+ while( remain > 0 ) {
+ ret = write( 1, str, remain );
+ if ( ret <= 0 ) {
+ php_handle_aborted_connection();
+ return str_length - remain;
+ }
+ str += ret;
+ remain -= ret;
+ }
+ }
+ return str_length;
}
/* }}} */
@@ -132,11 +159,11 @@ static int sapi_lsapi_ub_write(const char *str, uint str_length TSRMLS_DC)
*/
static void sapi_lsapi_flush( void * server_context )
{
- if ( lsapi_mode ) {
- if ( LSAPI_Flush() == -1) {
- php_handle_aborted_connection();
- }
- }
+ if ( lsapi_mode ) {
+ if ( LSAPI_Flush() == -1) {
+ php_handle_aborted_connection();
+ }
+ }
}
/* }}} */
@@ -145,8 +172,12 @@ static void sapi_lsapi_flush( void * server_context )
*/
static int sapi_lsapi_deactivate(TSRMLS_D)
{
- LSAPI_Finish();
- return SUCCESS;
+ if ( SG(request_info).path_translated )
+ {
+ efree( SG(request_info).path_translated );
+ }
+
+ return SUCCESS;
}
/* }}} */
@@ -157,46 +188,99 @@ static int sapi_lsapi_deactivate(TSRMLS_D)
*/
static char *sapi_lsapi_getenv( char * name, size_t name_len TSRMLS_DC )
{
- if ( lsapi_mode ) {
- return LSAPI_GetEnv( name );
- } else {
- return getenv( name );
- }
+ if ( lsapi_mode ) {
+ return LSAPI_GetEnv( name );
+ } else {
+ return getenv( name );
+ }
}
/* }}} */
+/*
+static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen,
+ void * arg )
+{
+ php_register_variable_safe((char *)pKey, (char *)pValue, valLen, (zval *)arg TSRMLS_CC);
+ return 1;
+}
+*/
static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen,
- void * arg )
+ void * arg )
{
- php_register_variable_safe((char *)pKey, (char *)pValue, valLen, (zval *)arg TSRMLS_CC);
- return 1;
+ zval * gpc_element, **gpc_element_p;
+ HashTable * symtable1 = Z_ARRVAL_P((zval * )arg);
+ register char * pKey1 = (char *)pKey;
+
+ MAKE_STD_ZVAL(gpc_element);
+ Z_STRLEN_P( gpc_element ) = valLen;
+ Z_STRVAL_P( gpc_element ) = estrndup(pValue, valLen);
+ Z_TYPE_P( gpc_element ) = IS_STRING;
+#if PHP_MAJOR_VERSION > 4
+ zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#else
+ zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#endif
+ return 1;
}
+#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
+static int add_variable_magic_quote( const char * pKey, int keyLen, const char * pValue, int valLen,
+ void * arg )
+{
+ zval * gpc_element, **gpc_element_p;
+ HashTable * symtable1 = Z_ARRVAL_P((zval * )arg);
+ register char * pKey1 = (char *)pKey;
+
+ MAKE_STD_ZVAL(gpc_element);
+ Z_STRLEN_P( gpc_element ) = valLen;
+ Z_STRVAL_P( gpc_element ) = php_addslashes((char *)pValue, valLen, &Z_STRLEN_P( gpc_element ), 0 );
+ Z_TYPE_P( gpc_element ) = IS_STRING;
+#if PHP_MAJOR_VERSION > 4
+ zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#else
+ zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#endif
+ return 1;
+}
+
+#endif
/* {{{ sapi_lsapi_register_variables
*/
static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC)
{
+ char * php_self = "";
+ if ( lsapi_mode ) {
+ if ( (SG(request_info).request_uri ) )
+ php_self = (SG(request_info).request_uri );
- if ( lsapi_mode ) {
- LSAPI_ForeachHeader( add_variable, track_vars_array );
- LSAPI_ForeachEnv( add_variable, track_vars_array );
- php_import_environment_variables(track_vars_array TSRMLS_CC);
-
- php_register_variable("PHP_SELF", (SG(request_info).request_uri ? SG(request_info).request_uri:""), track_vars_array TSRMLS_CC);
- } else {
- php_import_environment_variables(track_vars_array TSRMLS_CC);
+#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
+ if (!PG(magic_quotes_gpc)) {
+#endif
+ LSAPI_ForeachHeader( add_variable, track_vars_array );
+ LSAPI_ForeachEnv( add_variable, track_vars_array );
+ add_variable("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array );
+#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
+ } else {
+ LSAPI_ForeachHeader( add_variable_magic_quote, track_vars_array );
+ LSAPI_ForeachEnv( add_variable_magic_quote, track_vars_array );
+ add_variable_magic_quote("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array );
+ }
+#endif
+ php_import_environment_variables(track_vars_array TSRMLS_CC);
+ } else {
+ php_import_environment_variables(track_vars_array TSRMLS_CC);
- php_register_variable("PHP_SELF", php_self, track_vars_array TSRMLS_CC);
- php_register_variable("SCRIPT_NAME", php_self, track_vars_array TSRMLS_CC);
- php_register_variable("SCRIPT_FILENAME", script_filename, track_vars_array TSRMLS_CC);
- php_register_variable("PATH_TRANSLATED", script_filename, track_vars_array TSRMLS_CC);
- php_register_variable("DOCUMENT_ROOT", "", track_vars_array TSRMLS_CC);
+ php_register_variable("PHP_SELF", php_self, track_vars_array TSRMLS_CC);
+ php_register_variable("SCRIPT_NAME", php_self, track_vars_array TSRMLS_CC);
+ php_register_variable("SCRIPT_FILENAME", script_filename, track_vars_array TSRMLS_CC);
+ php_register_variable("PATH_TRANSLATED", script_filename, track_vars_array TSRMLS_CC);
+ php_register_variable("DOCUMENT_ROOT", "", track_vars_array TSRMLS_CC);
- }
+ }
}
/* }}} */
@@ -205,11 +289,11 @@ static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC)
*/
static int sapi_lsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
{
- if ( lsapi_mode ) {
- return LSAPI_ReadReqBody( buffer, count_bytes );
- } else {
- return 0;
- }
+ if ( lsapi_mode ) {
+ return LSAPI_ReadReqBody( buffer, (unsigned long long)count_bytes );
+ } else {
+ return 0;
+ }
}
/* }}} */
@@ -220,11 +304,11 @@ static int sapi_lsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
*/
static char *sapi_lsapi_read_cookies(TSRMLS_D)
{
- if ( lsapi_mode ) {
- return LSAPI_GetHeader( H_COOKIE );
- } else {
- return NULL;
- }
+ if ( lsapi_mode ) {
+ return LSAPI_GetHeader( H_COOKIE );
+ } else {
+ return NULL;
+ }
}
/* }}} */
@@ -233,33 +317,33 @@ static char *sapi_lsapi_read_cookies(TSRMLS_D)
*/
static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
{
- sapi_header_struct *h;
- zend_llist_position pos;
- if ( lsapi_mode ) {
- LSAPI_SetRespStatus( SG(sapi_headers).http_response_code );
-
- h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
- while (h) {
- if ( h->header_len > 0 ) {
- LSAPI_AppendRespHeader(h->header, h->header_len);
- }
- h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
- }
- if (SG(sapi_headers).send_default_content_type) {
- char *hd;
- int len;
- char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
-
- hd = sapi_get_default_content_type(TSRMLS_C);
- len = snprintf( headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1,
- "Content-type: %s", hd );
- efree(hd);
-
- LSAPI_AppendRespHeader( headerBuf, len );
- }
- }
- LSAPI_FinalizeRespHeaders();
- return SAPI_HEADER_SENT_SUCCESSFULLY;
+ sapi_header_struct *h;
+ zend_llist_position pos;
+ if ( lsapi_mode ) {
+ LSAPI_SetRespStatus( SG(sapi_headers).http_response_code );
+
+ h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
+ while (h) {
+ if ( h->header_len > 0 ) {
+ LSAPI_AppendRespHeader(h->header, h->header_len);
+ }
+ h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
+ }
+ if (SG(sapi_headers).send_default_content_type) {
+ char *hd;
+ int len;
+ char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
+
+ hd = sapi_get_default_content_type(TSRMLS_C);
+ len = snprintf( headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1,
+ "Content-type: %s", hd );
+ efree(hd);
+
+ LSAPI_AppendRespHeader( headerBuf, len );
+ }
+ }
+ LSAPI_FinalizeRespHeaders();
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
}
@@ -270,8 +354,15 @@ static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
*/
static void sapi_lsapi_log_message(char *message TSRMLS_DC)
{
- int len = strlen( message );
- LSAPI_Write_Stderr( message, len);
+ char buf[8192];
+ int len = strlen( message );
+ if ( *(message + len - 1 ) != '\n' )
+ {
+ snprintf( buf, 8191, "%s\n", message );
+ message = buf;
+ ++len;
+ }
+ LSAPI_Write_Stderr( message, len);
}
/* }}} */
@@ -280,158 +371,251 @@ static void sapi_lsapi_log_message(char *message TSRMLS_DC)
*/
static sapi_module_struct lsapi_sapi_module =
{
- "litespeed",
- "LiteSpeed",
+ "litespeed",
+ "LiteSpeed V6.4",
- php_lsapi_startup, /* startup */
- php_module_shutdown_wrapper, /* shutdown */
+ php_lsapi_startup, /* startup */
+ php_module_shutdown_wrapper, /* shutdown */
- NULL, /* activate */
- sapi_lsapi_deactivate, /* deactivate */
+ NULL, /* activate */
+ sapi_lsapi_deactivate, /* deactivate */
- sapi_lsapi_ub_write, /* unbuffered write */
- sapi_lsapi_flush, /* flush */
- NULL, /* get uid */
- sapi_lsapi_getenv, /* getenv */
+ sapi_lsapi_ub_write, /* unbuffered write */
+ sapi_lsapi_flush, /* flush */
+ NULL, /* get uid */
+ sapi_lsapi_getenv, /* getenv */
- php_error, /* error handler */
+ php_error, /* error handler */
- NULL, /* header handler */
- sapi_lsapi_send_headers, /* send headers handler */
- NULL, /* send header handler */
+ NULL, /* header handler */
+ sapi_lsapi_send_headers, /* send headers handler */
+ NULL, /* send header handler */
- sapi_lsapi_read_post, /* read POST data */
- sapi_lsapi_read_cookies, /* read Cookies */
+ sapi_lsapi_read_post, /* read POST data */
+ sapi_lsapi_read_cookies, /* read Cookies */
- sapi_lsapi_register_variables, /* register server variables */
- sapi_lsapi_log_message, /* Log message */
+ sapi_lsapi_register_variables, /* register server variables */
+ sapi_lsapi_log_message, /* Log message */
- NULL, /* php.ini path override */
- NULL, /* block interruptions */
- NULL, /* unblock interruptions */
- NULL, /* default post reader */
- NULL, /* treat data */
- NULL, /* executable location */
+ NULL, /* php.ini path override */
+ NULL, /* block interruptions */
+ NULL, /* unblock interruptions */
+ NULL, /* default post reader */
+ NULL, /* treat data */
+ NULL, /* executable location */
- 0, /* php.ini ignore */
+ 0, /* php.ini ignore */
- STANDARD_SAPI_MODULE_PROPERTIES
+ STANDARD_SAPI_MODULE_PROPERTIES
};
/* }}} */
static int init_request_info( TSRMLS_D )
{
- char * pContentType = LSAPI_GetHeader( H_CONTENT_TYPE );
- char * pAuth;
-
- SG(request_info).content_type = pContentType ? pContentType : "";
- SG(request_info).request_method = LSAPI_GetRequestMethod();
- SG(request_info).query_string = LSAPI_GetQueryString();
- SG(request_info).request_uri = LSAPI_GetScriptName();
- SG(request_info).content_length = LSAPI_GetReqBodyLen();
- SG(request_info).path_translated = LSAPI_GetScriptFileName();
+ char * pContentType = LSAPI_GetHeader( H_CONTENT_TYPE );
+ char * pAuth;
+
+ SG(request_info).content_type = pContentType ? pContentType : "";
+ SG(request_info).request_method = LSAPI_GetRequestMethod();
+ SG(request_info).query_string = LSAPI_GetQueryString();
+ SG(request_info).request_uri = LSAPI_GetScriptName();
+ 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;
+
+ pAuth = LSAPI_GetHeader( H_AUTHORIZATION );
+ php_handle_auth_data(pAuth TSRMLS_CC);
+}
- /* It is not reset by zend engine, set it to 0. */
- SG(sapi_headers).http_response_code = 0;
-
- pAuth = LSAPI_GetHeader( H_AUTHORIZATION );
- php_handle_auth_data(pAuth TSRMLS_CC);
+static char s_cur_chdir[4096] = "";
+
+static int lsapi_chdir_primary_script( zend_file_handle * file_handle )
+{
+#if PHP_MAJOR_VERSION > 4
+ char * p;
+ char ch;
+
+ SG(options) |= SAPI_OPTION_NO_CHDIR;
+ getcwd( s_cur_chdir, sizeof( s_cur_chdir ) );
+
+ p = strrchr( file_handle->filename, '/' );
+ if ( *p )
+ {
+ *p = 0;
+ if ( strcmp( file_handle->filename, s_cur_chdir ) != 0 ) {
+ chdir( file_handle->filename );
+ }
+ *p++ = '/';
+ ch = *p;
+ *p = 0;
+ if ( !CWDG(cwd).cwd ||
+ ( strcmp( file_handle->filename, CWDG(cwd).cwd ) != 0 ) ) {
+ CWDG(cwd).cwd_length = p - file_handle->filename;
+ CWDG(cwd).cwd = (char *) realloc(CWDG(cwd).cwd, CWDG(cwd).cwd_length+1);
+ memmove( CWDG(cwd).cwd, file_handle->filename, CWDG(cwd).cwd_length+1 );
+ }
+ *p = ch;
+ }
+ /* virtual_file_ex(&CWDG(cwd), file_handle->filename, NULL, CWD_REALPATH); */
+#else
+ VCWD_CHDIR_FILE( file_handle->filename );
+#endif
+ return 0;
}
-static int lsapi_module_main(int show_source TSRMLS_DC)
+static int lsapi_fopen_primary_script( zend_file_handle * file_handle )
+{
+ FILE * fp;
+ char * p;
+ fp = fopen( SG(request_info).path_translated, "rb" );
+ if ( !fp )
+ {
+ return -1;
+ }
+ file_handle->type = ZEND_HANDLE_FP;
+ file_handle->handle.fp = fp;
+ file_handle->filename = SG(request_info).path_translated;
+ file_handle->free_filename = 0;
+ file_handle->opened_path = NULL;
+
+ lsapi_chdir_primary_script( file_handle );
+
+ return 0;
+}
+
+static int lsapi_execute_script( zend_file_handle * file_handle TSRMLS_DC)
{
- zend_file_handle file_handle = {0};
+ char *p;
+ int len;
+ file_handle->type = ZEND_HANDLE_FILENAME;
+ file_handle->handle.fd = 0;
+ file_handle->filename = SG(request_info).path_translated;
+ file_handle->free_filename = 0;
+ file_handle->opened_path = NULL;
+
+ p = argv0;
+ *p++ = ':';
+ len = strlen( SG(request_info).path_translated );
+ if ( len > 45 )
+ len = len - 45;
+ else
+ len = 0;
+ memccpy( p, SG(request_info).path_translated + len, 0, 46 );
+
+ php_execute_script(file_handle TSRMLS_CC);
+ return 0;
- if (php_request_startup(TSRMLS_C) == FAILURE ) {
- return -1;
- }
- if (show_source) {
- zend_syntax_highlighter_ini syntax_highlighter_ini;
+}
- php_get_highlight_struct(&syntax_highlighter_ini);
- highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
- } else {
- file_handle.type = ZEND_HANDLE_FILENAME;
- file_handle.handle.fd = 0;
- file_handle.filename = SG(request_info).path_translated;
- file_handle.free_filename = 0;
- file_handle.opened_path = NULL;
- php_execute_script(&file_handle TSRMLS_CC);
- }
- zend_try {
- php_request_shutdown(NULL);
- } zend_end_try();
- return 0;
+static int lsapi_module_main(int show_source TSRMLS_DC)
+{
+ zend_file_handle file_handle = {0};
+
+ if (php_request_startup(TSRMLS_C) == FAILURE ) {
+ return -1;
+ }
+ if (show_source) {
+ zend_syntax_highlighter_ini syntax_highlighter_ini;
+
+ php_get_highlight_struct(&syntax_highlighter_ini);
+ highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
+ } else {
+ lsapi_execute_script( &file_handle TSRMLS_CC);
+ }
+ zend_try {
+ php_request_shutdown(NULL);
+ memset( argv0, 0, 46 );
+ } zend_end_try();
+ return 0;
}
static int alter_ini( const char * pKey, int keyLen, const char * pValue, int valLen,
- void * arg )
+ void * arg )
{
- int type = ZEND_INI_PERDIR;
- if ( '\001' == *pKey ) {
- ++pKey;
- if ( *pKey == 4 ) {
- type = ZEND_INI_SYSTEM;
- }
- ++pKey;
- --keyLen;
- zend_alter_ini_entry((char *)pKey, keyLen,
- (char *)pValue, valLen,
- type, PHP_INI_STAGE_ACTIVATE);
- }
- return 1;
+ int type = ZEND_INI_PERDIR;
+ if ( '\001' == *pKey ) {
+ ++pKey;
+ if ( *pKey == 4 ) {
+ type = ZEND_INI_SYSTEM;
+ }
+ ++pKey;
+ --keyLen;
+ if (( keyLen == 7 )&&( strncasecmp( pKey, "engine", 6 )== 0 ))
+ {
+ if ( *pValue == '0' )
+ engine = 0;
+ }
+ else
+ zend_alter_ini_entry((char *)pKey, keyLen,
+ (char *)pValue, valLen,
+ type, PHP_INI_STAGE_ACTIVATE);
+ }
+ return 1;
}
static void override_ini()
{
- LSAPI_ForeachSpecialEnv( alter_ini, NULL );
+ LSAPI_ForeachSpecialEnv( alter_ini, NULL );
}
+
static int processReq( TSRMLS_D )
{
- int ret = 0;
- zend_first_try {
- /* avoid server_context==NULL checks */
- SG(server_context) = (void *) 1;
-
- init_request_info( TSRMLS_C );
-
- override_ini();
-
- if ( lsapi_module_main( source_highlight TSRMLS_CC ) == -1 ) {
- ret = -1;
- }
- } zend_end_try();
- return ret;
+ int ret = 0;
+ zend_first_try {
+
+ /* avoid server_context==NULL checks */
+ SG(server_context) = (void *) 1;
+
+ engine = 1;
+ override_ini();
+
+ if ( engine ) {
+ init_request_info( TSRMLS_C );
+
+ if ( lsapi_module_main( source_highlight TSRMLS_CC ) == -1 ) {
+ ret = -1;
+ }
+ } else {
+ LSAPI_AppendRespHeader( "status: 403", 11 );
+ LSAPI_AppendRespHeader( "content-type: text/html", 23 );
+ LSAPI_Write( "Forbidden: PHP engine is disable.\n", 34 );
+ }
+ } zend_end_try();
+ return ret;
}
static void cli_usage( TSRMLS_D )
{
- static const char * usage =
- "Usage: php\n"
- " php -[b|c|h|i|q|s|v|?] [<file>] [args...]\n"
- " Run in LSAPI mode, only '-b', '-s' and '-c' are effective\n"
- " Run in Command Line Interpreter mode when parameters are specified\n"
- "\n"
- " -b <address:port>|<port> Bind Path for external LSAPI Server mode\n"
- " -c <path>|<file> Look for php.ini file in this directory\n"
- " -h This help\n"
- " -i PHP information\n"
- " -q Quiet-mode. Suppress HTTP Header output.\n"
- " -s Display colour syntax highlighted source.\n"
- " -v Version number\n"
- " -? This help\n"
- "\n"
- " args... Arguments passed to script.\n";
- php_output_startup();
- php_output_activate(TSRMLS_C);
- php_printf( "%s", usage );
+ static const char * usage =
+ "Usage: php\n"
+ " php -[b|c|n|h|i|q|s|v|?] [<file>] [args...]\n"
+ " Run in LSAPI mode, only '-b', '-s' and '-c' are effective\n"
+ " Run in Command Line Interpreter mode when parameters are specified\n"
+ "\n"
+ " -b <address:port>|<port> Bind Path for external LSAPI Server mode\n"
+ " -c <path>|<file> Look for php.ini file in this directory\n"
+ " -n No php.ini file will be used\n"
+ " -h This help\n"
+ " -i PHP information\n"
+ " -l Syntax check\n"
+ " -q Quiet-mode. Suppress HTTP Header output.\n"
+ " -s Display colour syntax highlighted source.\n"
+ " -v Version number\n"
+ " -? This help\n"
+ "\n"
+ " args... Arguments passed to script.\n";
+ php_output_startup();
+ php_output_activate(TSRMLS_C);
+ php_printf( usage );
#ifdef PHP_OUTPUT_NEWAPI
php_output_end_all(TSRMLS_C);
#else
@@ -440,349 +624,419 @@ static void cli_usage( TSRMLS_D )
}
static int parse_opt( int argc, char * argv[], int *climode,
- char **php_ini_path, char ** php_bind )
-{
- char ** p = &argv[1];
- char ** argend= &argv[argc];
- int c;
- while (( p < argend )&&(**p == '-' )) {
- c = *((*p)+1);
- ++p;
- switch( c ) {
- case 'b':
- if ( p >= argend ) {
- fprintf( stderr, "TCP or socket address must be specified following '-b' option.\n");
- return -1;
- }
- *php_bind = *p++;
- break;
-
- case 'c':
- if ( p >= argend ) {
- fprintf( stderr, "<path> or <file> must be specified following '-c' option.\n");
-
- return -1;
- }
- *php_ini_path = *p++;
- break;
- case 's':
- source_highlight = 1;
- break;
- case 'h':
- case 'i':
- case 'q':
- case 'v':
- case '?':
- default:
- *climode = 1;
- break;
- }
- }
- if ( p - argv < argc ) {
- *climode = 1;
- }
- return 0;
+ char **php_ini_path, char ** php_bind )
+{
+ char ** p = &argv[1];
+ char ** argend= &argv[argc];
+ int c;
+ while (( p < argend )&&(**p == '-' )) {
+ c = *((*p)+1);
+ ++p;
+ switch( c ) {
+ case 'b':
+ if ( p >= argend ) {
+ fprintf( stderr, "TCP or socket address must be specified following '-b' option.\n");
+ return -1;
+ }
+ *php_bind = strdup(*p++);
+ break;
+
+ case 'c':
+ if ( p >= argend ) {
+ fprintf( stderr, "<path> or <file> must be specified following '-c' option.\n");
+
+ return -1;
+ }
+ *php_ini_path = strdup( *p++ );
+ break;
+ case 's':
+ source_highlight = 1;
+ break;
+ case 'n':
+ ignore_php_ini = 1;
+ break;
+ case '?':
+ if ( *((*(p-1))+2) == 's' )
+ exit( 99 );
+ case 'h':
+ case 'i':
+ case 'l':
+ case 'q':
+ case 'v':
+ default:
+ *climode = 1;
+ break;
+ }
+ }
+ if ( p - argv < argc ) {
+ *climode = 1;
+ }
+ return 0;
}
static int cli_main( int argc, char * argv[] )
{
- static const char * ini_defaults[] = {
- "report_zend_debug", "0",
- "display_errors", "1",
- "register_argc_argv", "1",
- "html_errors", "0",
- "implicit_flush", "1",
- "output_buffering", "0",
- "max_execution_time", "0",
- "max_input_time", "-1",
- NULL
- };
-
- const char ** ini;
- char ** p = &argv[1];
- char ** argend= &argv[argc];
- int ret = 0;
- int c;
- lsapi_mode = 0; /* enter CLI mode */
+ static const char * ini_defaults[] = {
+ "report_zend_debug", "0",
+ "display_errors", "1",
+ "register_argc_argv", "1",
+ "html_errors", "0",
+ "implicit_flush", "1",
+ "output_buffering", "0",
+ "max_execution_time", "0",
+ "max_input_time", "-1",
+ NULL
+ };
+
+ const char ** ini;
+ char ** p = &argv[1];
+ char ** argend= &argv[argc];
+ int ret = -1;
+ int c;
+ lsapi_mode = 0; /* enter CLI mode */
#ifdef PHP_WIN32
- _fmode = _O_BINARY; /*sets default for file streams to binary */
- setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
- setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
- setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
+ _fmode = _O_BINARY; /*sets default for file streams to binary */
+ setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
+ setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
+ setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
#endif
- zend_first_try {
- SG(server_context) = (void *) 1;
-
- zend_uv.html_errors = 0; /* tell the engine we're in non-html mode */
- CG(in_compilation) = 0; /* not initialized but needed for several options */
- EG(uninitialized_zval_ptr) = NULL;
-
- for( ini = ini_defaults; *ini; ini+=2 ) {
- zend_alter_ini_entry( (char *)*ini, strlen( *ini )+1,
- (char *)*(ini+1), strlen( *(ini+1) ),
- PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
- }
-
- while (( p < argend )&&(**p == '-' )) {
- c = *((*p)+1);
- ++p;
- switch( c ) {
- case 'q':
- break;
- case 'i':
- if (php_request_startup(TSRMLS_C) != FAILURE) {
- php_print_info(0xFFFFFFFF TSRMLS_CC);
+ zend_first_try {
+ SG(server_context) = (void *) 1;
+
+ zend_uv.html_errors = 0; /* tell the engine we're in non-html mode */
+ CG(in_compilation) = 0; /* not initialized but needed for several options */
+ EG(uninitialized_zval_ptr) = NULL;
+
+ for( ini = ini_defaults; *ini; ini+=2 ) {
+ zend_alter_ini_entry( (char *)*ini, strlen( *ini )+1,
+ (char *)*(ini+1), strlen( *(ini+1) ),
+ PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+ }
+
+ while (( p < argend )&&(**p == '-' )) {
+ c = *((*p)+1);
+ ++p;
+ switch( c ) {
+ case 'q':
+ break;
+ case 'i':
+ if (php_request_startup(TSRMLS_C) != FAILURE) {
+ php_print_info(0xFFFFFFFF TSRMLS_CC);
#ifdef PHP_OUTPUT_NEWAPI
php_output_end_all(TSRMLS_C);
#else
php_end_ob_buffers(1 TSRMLS_CC);
#endif
- php_request_shutdown( NULL );
- }
- ret = 1;
- break;
- case 'v':
- if (php_request_startup(TSRMLS_C) != FAILURE) {
+ php_request_shutdown( NULL );
+ ret = 0;
+ }
+ break;
+ case 'v':
+ if (php_request_startup(TSRMLS_C) != FAILURE) {
#if ZEND_DEBUG
- php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+ php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
#else
- php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+ php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
#endif
#ifdef PHP_OUTPUT_NEWAPI
php_output_end_all(TSRMLS_C);
#else
php_end_ob_buffers(1 TSRMLS_CC);
#endif
- php_request_shutdown( NULL );
- }
- ret = 1;
- break;
- case 'c':
- ++p;
- /* fall through */
- case 's':
- break;
-
- case 'h':
- case '?':
- default:
- cli_usage(TSRMLS_C);
- ret = 1;
- break;
-
- }
- }
- if ( !ret ) {
- if ( *p ) {
- zend_file_handle file_handle = {0};
-
- file_handle.type = ZEND_HANDLE_FP;
- file_handle.handle.fp = VCWD_FOPEN(*p, "rb");
-
- if ( file_handle.handle.fp ) {
- script_filename = *p;
- php_self = *p;
-
- SG(request_info).path_translated = *p;
- SG(request_info).argc = argc - (p - argv);
- SG(request_info).argv = p;
-
- if (php_request_startup(TSRMLS_C) == FAILURE ) {
- fclose( file_handle.handle.fp );
- ret = 2;
- } else {
- if (source_highlight) {
- zend_syntax_highlighter_ini syntax_highlighter_ini;
-
- php_get_highlight_struct(&syntax_highlighter_ini);
- highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
- } else {
- file_handle.filename = *p;
- file_handle.free_filename = 0;
- file_handle.opened_path = NULL;
-
- php_execute_script(&file_handle TSRMLS_CC);
- }
-
- php_request_shutdown( NULL );
- }
- } else {
- php_printf("Could not open input file: %s.\n", *p);
- }
- } else {
- cli_usage(TSRMLS_C);
- }
- }
-
- }zend_end_try();
-
- php_module_shutdown(TSRMLS_C);
+ php_request_shutdown( NULL );
+ ret = 0;
+ }
+ break;
+ case 'c':
+ ++p;
+ /* fall through */
+ case 's':
+ break;
+ case 'l':
+ source_highlight = 2;
+ break;
+ case 'h':
+ case '?':
+ default:
+ cli_usage(TSRMLS_C);
+ ret = 0;
+ break;
+
+ }
+ }
+ if ( ret == -1 ) {
+ if ( *p ) {
+ zend_file_handle file_handle = {0};
+
+ file_handle.type = ZEND_HANDLE_FP;
+ file_handle.handle.fp = VCWD_FOPEN(*p, "rb");
+
+ if ( file_handle.handle.fp ) {
+ script_filename = *p;
+ php_self = *p;
+
+ SG(request_info).path_translated = estrdup(*p);
+ SG(request_info).argc = argc - (p - argv);
+ SG(request_info).argv = p;
+
+ if (php_request_startup(TSRMLS_C) == FAILURE ) {
+ fclose( file_handle.handle.fp );
+ ret = 2;
+ } else {
+ if (source_highlight == 1) {
+ zend_syntax_highlighter_ini syntax_highlighter_ini;
+
+ php_get_highlight_struct(&syntax_highlighter_ini);
+ highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
+ } else if (source_highlight == 2) {
+ file_handle.filename = *p;
+ file_handle.free_filename = 0;
+ file_handle.opened_path = NULL;
+ ret = php_lint_script(&file_handle TSRMLS_CC);
+ if (ret==SUCCESS) {
+ zend_printf("No syntax errors detected in %s\n", file_handle.filename);
+ } else {
+ zend_printf("Errors parsing %s\n", file_handle.filename);
+ }
+
+ } else {
+ file_handle.filename = *p;
+ file_handle.free_filename = 0;
+ file_handle.opened_path = NULL;
+
+ php_execute_script(&file_handle TSRMLS_CC);
+ ret = EG(exit_status);
+ }
+
+ php_request_shutdown( NULL );
+ }
+ } else {
+ php_printf("Could not open input file: %s.\n", *p);
+ }
+ } else {
+ cli_usage(TSRMLS_C);
+ }
+ }
+
+ }zend_end_try();
+
+ php_module_shutdown(TSRMLS_C);
#ifdef ZTS
- tsrm_shutdown();
+ tsrm_shutdown();
#endif
- return ret;
+ return ret;
}
static int s_stop;
void litespeed_cleanup(int signal)
{
- s_stop = signal;
+ s_stop = signal;
}
void start_children( int children )
{
- struct sigaction act, old_term, old_quit, old_int, old_usr1;
- int running = 0;
- int status;
- pid_t pid;
-
- /* Create a process group */
- setsid();
-
- /* Set up handler to kill children upon exit */
- act.sa_flags = 0;
- act.sa_handler = litespeed_cleanup;
- if( sigaction( SIGTERM, &act, &old_term ) ||
- sigaction( SIGINT, &act, &old_int ) ||
- sigaction( SIGUSR1, &act, &old_usr1 ) ||
- sigaction( SIGQUIT, &act, &old_quit )) {
- perror( "Can't set signals" );
- exit( 1 );
- }
- s_stop = 0;
- while( 1 ) {
- while((!s_stop )&&( running < children )) {
- pid = fork();
- switch( pid ) {
- case 0: /* children process */
-
- /* don't catch our signals */
- sigaction( SIGTERM, &old_term, 0 );
- sigaction( SIGQUIT, &old_quit, 0 );
- sigaction( SIGINT, &old_int, 0 );
- sigaction( SIGUSR1, &old_usr1, 0 );
- return ;
- case -1:
- perror( "php (pre-forking)" );
- exit( 1 );
- break;
- default: /* parent process */
- running++;
- break;
- }
- }
- if ( s_stop ) {
- break;
- }
- pid = wait( &status );
- running--;
- }
- kill( -getpgrp(), SIGUSR1 );
- exit( 0 );
+ struct sigaction act, old_term, old_quit, old_int, old_usr1;
+ int running = 0;
+ int status;
+ pid_t pid;
+
+ /* Create a process group */
+ setsid();
+
+ /* Set up handler to kill children upon exit */
+ act.sa_flags = 0;
+ act.sa_handler = litespeed_cleanup;
+ if( sigaction( SIGTERM, &act, &old_term ) ||
+ sigaction( SIGINT, &act, &old_int ) ||
+ sigaction( SIGUSR1, &act, &old_usr1 ) ||
+ sigaction( SIGQUIT, &act, &old_quit )) {
+ perror( "Can't set signals" );
+ exit( 1 );
+ }
+ s_stop = 0;
+ while( 1 ) {
+ while((!s_stop )&&( running < children )) {
+ pid = fork();
+ switch( pid ) {
+ case 0: /* children process */
+
+ /* don't catch our signals */
+ sigaction( SIGTERM, &old_term, 0 );
+ sigaction( SIGQUIT, &old_quit, 0 );
+ sigaction( SIGINT, &old_int, 0 );
+ sigaction( SIGUSR1, &old_usr1, 0 );
+ return ;
+ case -1:
+ perror( "php (pre-forking)" );
+ exit( 1 );
+ break;
+ default: /* parent process */
+ running++;
+ break;
+ }
+ }
+ if ( s_stop ) {
+ break;
+ }
+ pid = wait( &status );
+ running--;
+ }
+ kill( -getpgrp(), SIGUSR1 );
+ exit( 0 );
}
-
+void setArgv0( int argc, char * argv[] )
+{
+ char * p;
+ int i;
+ argv0 = argv[0] + strlen( argv[0] );
+ p = argv0;
+ while(( p > argv[0] )&&( p[-1] != '/'))
+ --p;
+ if ( p > argv[0] )
+ {
+ memmove( argv[0], p, argv0 - p );
+ memset( argv[0] + ( argv0 - p ), 0, p - argv[0] );
+ argv0 = argv[0] + (argv0 - p);
+ }
+ for( i = 1; i < argc; ++i )
+ {
+ memset( argv[i], 0, strlen( argv[i] ) );
+ }
+}
#include <fcntl.h>
int main( int argc, char * argv[] )
{
- int ret;
- int bindFd;
-
- char * php_ini_path = NULL;
- char * php_bind = NULL;
- char * p;
- int n;
- int climode = 0;
-
+ int ret;
+ int bindFd;
+
+ char * php_ini_path = NULL;
+ char * php_bind = NULL;
+ int n;
+ int climode = 0;
+ struct timeval tv_req_begin;
+ struct timeval tv_req_end;
+ int slow_script_msec = 0;
+ char time_buf[40];
+
#ifdef HAVE_SIGNAL_H
#if defined(SIGPIPE) && defined(SIG_IGN)
- signal(SIGPIPE, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
#endif
#endif
#ifdef ZTS
- tsrm_startup(1, 1, 0, NULL);
+ tsrm_startup(1, 1, 0, NULL);
#endif
- if (argc > 1 ) {
- if ( parse_opt( argc, argv, &climode,
- &php_ini_path, &php_bind ) == -1 ) {
- return 1;
- }
- }
- if ( climode ) {
- lsapi_sapi_module.phpinfo_as_text = 1;
- }
- sapi_startup(&lsapi_sapi_module);
+ if (argc > 1 ) {
+ if ( parse_opt( argc, argv, &climode,
+ &php_ini_path, &php_bind ) == -1 ) {
+ return 1;
+ }
+ }
+ if ( climode ) {
+ lsapi_sapi_module.phpinfo_as_text = 1;
+ } else {
+ setArgv0(argc, argv );
+ }
+
+ sapi_startup(&lsapi_sapi_module);
#ifdef ZTS
- compiler_globals = ts_resource(compiler_globals_id);
- executor_globals = ts_resource(executor_globals_id);
- core_globals = ts_resource(core_globals_id);
- sapi_globals = ts_resource(sapi_globals_id);
- tsrm_ls = ts_resource(0);
+ compiler_globals = ts_resource(compiler_globals_id);
+ executor_globals = ts_resource(executor_globals_id);
+ core_globals = ts_resource(core_globals_id);
+ sapi_globals = ts_resource(sapi_globals_id);
+ tsrm_ls = ts_resource(0);
- SG(request_info).path_translated = NULL;
+ SG(request_info).path_translated = NULL;
#endif
- lsapi_sapi_module.executable_location = argv[0];
+ lsapi_sapi_module.executable_location = argv[0];
+
+ if ( ignore_php_ini )
+ lsapi_sapi_module.php_ini_ignore = 1;
+
+ if ( php_ini_path ) {
+ lsapi_sapi_module.php_ini_path_override = php_ini_path;
+ }
- if ( php_ini_path ) {
- lsapi_sapi_module.php_ini_path_override = php_ini_path;
- }
- if (php_module_startup(&lsapi_sapi_module, &litespeed_module_entry, 1) == FAILURE) {
+ lsapi_sapi_module.ini_defaults = sapi_lsapi_ini_defaults;
+
+ if (php_module_startup(&lsapi_sapi_module, &litespeed_module_entry, 1) == FAILURE) {
#ifdef ZTS
- tsrm_shutdown();
+ tsrm_shutdown();
#endif
- return FAILURE;
- }
-
- if ( climode ) {
- return cli_main(argc, argv);
- }
-
-
- if ( php_bind ) {
- bindFd = LSAPI_CreateListenSock( php_bind, 10 );
- if ( bindFd == -1 ) {
- fprintf( stderr,
- "Failed to bind socket [%s]: %s\n", php_bind, strerror( errno ) );
- exit( 2 );
- }
- if ( bindFd != 0 ) {
- dup2( bindFd, 0 );
- close( bindFd );
- }
- }
-
- LSAPI_Init();
+ return FAILURE;
+ }
+
+ if ( climode ) {
+ return cli_main(argc, argv);
+ }
+
+ if ( php_bind ) {
+ bindFd = LSAPI_CreateListenSock( php_bind, 10 );
+ if ( bindFd == -1 ) {
+ fprintf( stderr,
+ "Failed to bind socket [%s]: %s\n", php_bind, strerror( errno ) );
+ exit( 2 );
+ }
+ if ( bindFd != 0 ) {
+ dup2( bindFd, 0 );
+ close( bindFd );
+ }
+ }
+
+ LSAPI_Init();
- LSAPI_Init_Env_Parameters( NULL );
-
- if ( php_bind ) {
- LSAPI_No_Check_ppid();
- }
-
- while( LSAPI_Prefork_Accept_r( &g_req ) >= 0 ) {
- ret = processReq(TSRMLS_C);
- LSAPI_Finish();
- if ( ret ) {
- break;
- }
- }
- php_module_shutdown(TSRMLS_C);
+ LSAPI_Init_Env_Parameters( NULL );
+
+ slow_script_msec = LSAPI_Get_Slow_Req_Msecs();
+
+ if ( php_bind ) {
+ LSAPI_No_Check_ppid();
+ free( php_bind );
+ php_bind = NULL;
+ }
+
+ while( LSAPI_Prefork_Accept_r( &g_req ) >= 0 ) {
+ if ( slow_script_msec ) {
+ gettimeofday( &tv_req_begin, NULL );
+ }
+ ret = processReq(TSRMLS_C);
+ if ( slow_script_msec ) {
+ gettimeofday( &tv_req_end, NULL );
+ n = ((long) tv_req_end.tv_sec - tv_req_begin.tv_sec ) * 1000
+ + (tv_req_end.tv_usec - tv_req_begin.tv_usec) / 1000;
+ if ( n > slow_script_msec )
+ {
+ strftime( time_buf, 30, "%d/%b/%Y:%H:%M:%S", localtime( &tv_req_end.tv_sec ) );
+ fprintf( stderr, "[%s] Slow PHP script: %d ms\n URL: %s %s\n Query String: %s\n Script: %s\n",
+ time_buf, n, LSAPI_GetRequestMethod(),
+ LSAPI_GetScriptName(), LSAPI_GetQueryString(),
+ LSAPI_GetScriptFileName() );
+
+ }
+ }
+ LSAPI_Finish();
+ if ( ret ) {
+ break;
+ }
+ }
+ php_module_shutdown(TSRMLS_C);
#ifdef ZTS
- tsrm_shutdown();
+ tsrm_shutdown();
#endif
- return ret;
+ return ret;
}
@@ -795,49 +1049,51 @@ ZEND_END_ARG_INFO()
PHP_FUNCTION(litespeed_request_headers);
PHP_FUNCTION(litespeed_response_headers);
+PHP_FUNCTION(apache_get_modules);
PHP_MINFO_FUNCTION(litespeed);
zend_function_entry litespeed_functions[] = {
- PHP_FE(litespeed_request_headers, arginfo_litespeed__void)
- PHP_FE(litespeed_response_headers, arginfo_litespeed__void)
- PHP_FALIAS(getallheaders, litespeed_request_headers, arginfo_litespeed__void)
- PHP_FALIAS(apache_request_headers, litespeed_request_headers, arginfo_litespeed__void)
- PHP_FALIAS(apache_response_headers, litespeed_response_headers, arginfo_litespeed__void)
- {NULL, NULL, NULL}
+ PHP_FE(litespeed_request_headers, arginfo_litespeed__void)
+ PHP_FE(litespeed_response_headers, arginfo_litespeed__void)
+ PHP_FE(apache_get_modules, arginfo_litespeed__void)
+ PHP_FALIAS(getallheaders, litespeed_request_headers, arginfo_litespeed__void)
+ PHP_FALIAS(apache_request_headers, litespeed_request_headers, arginfo_litespeed__void)
+ PHP_FALIAS(apache_response_headers, litespeed_response_headers, arginfo_litespeed__void)
+ {NULL, NULL, NULL}
};
static PHP_MINIT_FUNCTION(litespeed)
{
- /* REGISTER_INI_ENTRIES(); */
- return SUCCESS;
+ /* REGISTER_INI_ENTRIES(); */
+ return SUCCESS;
}
static PHP_MSHUTDOWN_FUNCTION(litespeed)
{
- /* UNREGISTER_INI_ENTRIES(); */
- return SUCCESS;
+ /* UNREGISTER_INI_ENTRIES(); */
+ return SUCCESS;
}
zend_module_entry litespeed_module_entry = {
- STANDARD_MODULE_HEADER,
- "litespeed",
- litespeed_functions,
- PHP_MINIT(litespeed),
- PHP_MSHUTDOWN(litespeed),
- NULL,
- NULL,
- NULL,
- NO_VERSION_YET,
- STANDARD_MODULE_PROPERTIES
+ STANDARD_MODULE_HEADER,
+ "litespeed",
+ litespeed_functions,
+ PHP_MINIT(litespeed),
+ PHP_MSHUTDOWN(litespeed),
+ NULL,
+ NULL,
+ NULL,
+ NO_VERSION_YET,
+ STANDARD_MODULE_PROPERTIES
};
static int add_associate_array( const char * pKey, int keyLen, const char * pValue, int valLen,
- void * arg )
+ void * arg )
{
- add_assoc_string_ex( (zval *)arg, (char *)pKey, keyLen+1, (char *)pValue, 1 );
- return 1;
+ add_assoc_string_ex( (zval *)arg, (char *)pKey, keyLen+1, (char *)pValue, 1 );
+ return 1;
}
@@ -845,13 +1101,13 @@ static int add_associate_array( const char * pKey, int keyLen, const char * pVal
Fetch all HTTP request headers */
PHP_FUNCTION(litespeed_request_headers)
{
- /* TODO: */
- if (ZEND_NUM_ARGS() > 0) {
- WRONG_PARAM_COUNT;
- }
- array_init(return_value);
+ /* TODO: */
+ if (ZEND_NUM_ARGS() > 0) {
+ WRONG_PARAM_COUNT;
+ }
+ array_init(return_value);
- LSAPI_ForeachOrgHeader( add_associate_array, return_value );
+ LSAPI_ForeachOrgHeader( add_associate_array, return_value );
}
/* }}} */
@@ -862,45 +1118,62 @@ PHP_FUNCTION(litespeed_request_headers)
Fetch all HTTP response headers */
PHP_FUNCTION(litespeed_response_headers)
{
- sapi_header_struct *h;
- zend_llist_position pos;
- char * p;
- int len;
- char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
-
- if (ZEND_NUM_ARGS() > 0) {
- WRONG_PARAM_COUNT;
- }
-
- if (!&SG(sapi_headers).headers) {
- RETURN_FALSE;
- }
- array_init(return_value);
-
- h = zend_llist_get_first_ex(&SG(sapi_headers).headers, &pos);
- while (h) {
- if ( h->header_len > 0 ) {
- p = strchr( h->header, ':' );
- len = p - h->header;
- if (( p )&&( len > 0 )) {
- memmove( headerBuf, h->header, len );
- while( len > 0 && (isspace( headerBuf[len-1])) ) {
- --len;
- }
- headerBuf[len] = 0;
- if ( len ) {
- while( isspace(*++p));
- add_assoc_string_ex(return_value, headerBuf, len+1, p, 1 );
- }
- }
- }
- h = zend_llist_get_next_ex(&SG(sapi_headers).headers, &pos);
- }
+ sapi_header_struct *h;
+ zend_llist_position pos;
+ char * p;
+ int len;
+ char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
+
+ if (ZEND_NUM_ARGS() > 0) {
+ WRONG_PARAM_COUNT;
+ }
+
+ if (!&SG(sapi_headers).headers) {
+ RETURN_FALSE;
+ }
+ array_init(return_value);
+
+ h = zend_llist_get_first_ex(&SG(sapi_headers).headers, &pos);
+ while (h) {
+ if ( h->header_len > 0 ) {
+ p = strchr( h->header, ':' );
+ len = p - h->header;
+ if (( p )&&( len > 0 )) {
+ memmove( headerBuf, h->header, len );
+ while( len > 0 && (isspace( headerBuf[len-1])) ) {
+ --len;
+ }
+ headerBuf[len] = 0;
+ if ( len ) {
+ while( isspace(*++p));
+ add_assoc_string_ex(return_value, headerBuf, len+1, p, 1 );
+ }
+ }
+ }
+ h = zend_llist_get_next_ex(&SG(sapi_headers).headers, &pos);
+ }
}
/* }}} */
+/* {{{ proto array apache_get_modules(void)
+ Fetch all loaded module names */
+PHP_FUNCTION(apache_get_modules)
+{
+ /* TODO: */
+ if (ZEND_NUM_ARGS() > 0) {
+ WRONG_PARAM_COUNT;
+ }
+ array_init(return_value);
+ add_next_index_string(return_value, "mod_rewrite", 1);
+ add_next_index_string(return_value, "mod_mime", 1);
+ add_next_index_string(return_value, "mod_headers", 1);
+ add_next_index_string(return_value, "mod_expires", 1);
+}
+/* }}} */
+
+
/*
* Local variables:
* tab-width: 4
diff --git a/sapi/litespeed/lsapidef.h b/sapi/litespeed/lsapidef.h
index c8940a930..5d5b4c168 100644
--- a/sapi/litespeed/lsapidef.h
+++ b/sapi/litespeed/lsapidef.h
@@ -1,25 +1,5 @@
-
-/*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: George Wang <gwang@litespeedtech.com> |
- +----------------------------------------------------------------------+
-*/
-
-
/*
-Copyright (c) 2007, Lite Speed Technologies Inc.
+Copyright (c) 2005, Lite Speed Technologies Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -50,6 +30,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/***************************************************************************
+ $Id: lsapidef.h,v 1.17 2012/12/01 19:23:31 gwang Exp $
+ -------------------
+ begin : Thu Feb 10 2005
+ author : George Wang
+ email : gwang@litespeedtech.com
+ ***************************************************************************/
#ifndef _LSAPIDEF_H_
#define _LSAPIDEF_H_
@@ -113,12 +100,14 @@ enum
#define LSAPI_RESP_END 5
#define LSAPI_STDERR_STREAM 6
#define LSAPI_REQ_RECEIVED 7
+#define LSAPI_CONN_CLOSE 8
+#define LSAPI_INTERNAL_ERROR 9
#define LSAPI_MAX_HEADER_LEN 65535
#define LSAPI_MAX_DATA_PACKET_LEN 16384
-#define LSAPI_RESP_HTTP_HEADER_MAX 4096
+#define LSAPI_RESP_HTTP_HEADER_MAX 32768
#define LSAPI_PACKET_HEADER_LEN 8
diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c
index 3a13000e1..4a9affc60 100644
--- a/sapi/litespeed/lsapilib.c
+++ b/sapi/litespeed/lsapilib.c
@@ -1,25 +1,5 @@
/*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: George Wang <gwang@litespeedtech.com> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id$ */
-
-/*
-Copyright (c) 2007, Lite Speed Technologies Inc.
+Copyright (c) 2013, Lite Speed Technologies Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -50,17 +30,21 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <lsapilib.h>
+/***************************************************************************
+ lsapilib.c - description
+ -------------------
+ begin : Mon Feb 21 2005
+ copyright : (C) 2005 by George Wang
+ email : gwang@litespeedtech.com
+ ***************************************************************************/
+
#include <ctype.h>
+#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/un.h>
+#include <sys/stat.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
@@ -71,8 +55,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/wait.h>
+#include <grp.h>
+#include <pwd.h>
#include <time.h>
#include <unistd.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/un.h>
+
+#include "lsapilib.h"
+
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+#include <sys/prctl.h>
+#endif
+
+#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+#include <sys/sysctl.h>
+#endif
+
+#include <inttypes.h>
+#ifndef uint32
+#define uint32 uint32_t
+#endif
+
+struct lsapi_MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void lsapi_MD5Init(struct lsapi_MD5Context *context);
+void lsapi_MD5Update(struct lsapi_MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *context);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct lsapi_MD5Context lsapi_MD5_CTX;
+
#define LSAPI_ST_REQ_HEADER 1
#define LSAPI_ST_REQ_BODY 2
@@ -83,11 +107,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define LSAPI_INIT_RESP_HEADER_LEN 4096
+
static int g_inited = 0;
static int g_running = 1;
static int s_ppid;
+static int s_slow_req_msecs = 0;
+static int s_keepListener = 0;
+static int s_dump_debug_info = 0;
+static int s_pid_dump_debug_info = 0;
+
LSAPI_Request g_req = { -1, -1 };
+static char s_pSecret[24];
+
+
void Flush_RespBuf_r( LSAPI_Request * pReq );
static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] =
@@ -111,13 +144,13 @@ static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] =
"HTTP_TRANSFER_ENCODING"
};
-static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = {
- 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18,
- 22, 13, 18, 13, 24, 15, 10, 20, 8, 22
-};
+static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] =
+{ 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18,
+ 22, 13, 18, 13, 24, 15, 10, 20, 8, 22 };
-static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] = {
+static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] =
+{
"Accept", "Accept-Charset",
"Accept-Encoding",
"Accept-Language", "Authorization",
@@ -137,8 +170,8 @@ static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] = {
"Transfer-Encoding"
};
-static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] = {
- 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, /* user-agent */
+static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] =
+{ 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent
13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17
};
@@ -160,7 +193,8 @@ static void lsapi_signal(int signo, sighandler_t handler)
sigaction(signo, NULL, &sa);
- if (sa.sa_handler == SIG_DFL) {
+ if (sa.sa_handler == SIG_DFL)
+ {
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = handler;
@@ -169,6 +203,34 @@ static void lsapi_signal(int signo, sighandler_t handler)
}
+static int s_enable_core_dump = 0;
+static void lsapi_enable_core_dump()
+{
+#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+ int mib[2];
+ size_t len;
+
+ len = 2;
+ if ( sysctlnametomib("kern.sugid_coredump", mib, &len) == 0 )
+ {
+ len = sizeof(s_enable_core_dump);
+ if (sysctl(mib, 2, NULL, 0, &s_enable_core_dump, len) == -1)
+ perror( "sysctl: Failed to set 'kern.sugid_coredump', "
+ "core dump may not be available!");
+ }
+
+
+#endif
+
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+ if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1)
+ perror( "prctl: Failed to set dumpable, "
+ "core dump may not be available!");
+#endif
+}
+
+
static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader,
char type, int len )
{
@@ -199,75 +261,115 @@ static int lsapi_set_nblock( int fd, int nonblock )
return 0;
}
-
static int lsapi_close( int fd )
{
int ret;
- while( 1 ) {
+ while( 1 )
+ {
ret = close( fd );
- if (( ret == -1 )&&( errno == EINTR )&&(g_running)) {
+ if (( ret == -1 )&&( errno == EINTR )&&(g_running))
continue;
- }
return ret;
}
}
-static inline int lsapi_read( int fd, void * pBuf, int len )
+static inline ssize_t lsapi_read( int fd, void * pBuf, size_t len )
{
- int ret;
- while( 1 ) {
+ ssize_t ret;
+ while( 1 )
+ {
ret = read( fd, (char *)pBuf, len );
- if (( ret == -1 )&&( errno == EINTR )&&(g_running)) {
+ if (( ret == -1 )&&( errno == EINTR )&&(g_running))
continue;
- }
return ret;
}
}
+/*
+static int lsapi_write( int fd, const void * pBuf, int len )
+{
+ int ret;
+ const char * pCur;
+ const char * pEnd;
+ if ( len == 0 )
+ return 0;
+ pCur = (const char *)pBuf;
+ pEnd = pCur + len;
+ while( g_running && (pCur < pEnd) )
+ {
+ ret = write( fd, pCur, pEnd - pCur );
+ if ( ret >= 0)
+ pCur += ret;
+ else if (( ret == -1 )&&( errno != EINTR ))
+ return ret;
+ }
+ return pCur - (const char *)pBuf;
+}
+*/
static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen )
{
int ret;
int left = totalLen;
int n = count;
- while(( left > 0 )&&g_running ) {
+ while(( left > 0 )&&g_running )
+ {
ret = writev( fd, *pVec, n );
- if ( ret > 0 ) {
+ if ( ret > 0 )
+ {
left -= ret;
- if (( left <= 0)||( !g_running )) {
+ if (( left <= 0)||( !g_running ))
return totalLen - left;
- }
- while( ret > 0 ) {
- if ( (*pVec)->iov_len <= ret ) {
+ while( ret > 0 )
+ {
+ if ( (*pVec)->iov_len <= (unsigned int )ret )
+ {
ret -= (*pVec)->iov_len;
++(*pVec);
- } else {
+ }
+ else
+ {
(*pVec)->iov_base = (char *)(*pVec)->iov_base + ret;
(*pVec)->iov_len -= ret;
break;
}
}
- } else if ( ret == -1 ) {
- if ( errno == EAGAIN ) {
- if ( totalLen - left > 0 ) {
+ }
+ else if ( ret == -1 )
+ {
+ if ( errno == EAGAIN )
+ {
+ if ( totalLen - left > 0 )
return totalLen - left;
- } else {
+ else
return -1;
- }
- } else {
- if ( errno != EINTR ) {
- return ret;
- }
}
+ else if ( errno != EINTR )
+ return ret;
}
}
return totalLen - left;
}
+/*
+static int getTotalLen( struct iovec * pVec, int count )
+{
+ struct iovec * pEnd = pVec + count;
+ int total = 0;
+ while( pVec < pEnd )
+ {
+ total += pVec->iov_len;
+ ++pVec;
+ }
+ return total;
+}
+*/
+
static inline int allocateBuf( LSAPI_Request * pReq, int size )
{
char * pBuf = (char *)realloc( pReq->m_pReqBuf, size );
- if ( pBuf ) {
+ if ( pBuf )
+ {
pReq->m_pReqBuf = pBuf;
pReq->m_reqBufSize = size;
pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf;
@@ -281,9 +383,8 @@ static int allocateIovec( LSAPI_Request * pReq, int n )
{
struct iovec * p = (struct iovec *)realloc(
pReq->m_pIovec, sizeof(struct iovec) * n );
- if ( !p ) {
+ if ( !p )
return -1;
- }
pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec );
pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec );
pReq->m_pIovec = p;
@@ -294,9 +395,8 @@ static int allocateIovec( LSAPI_Request * pReq, int n )
static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size )
{
char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size );
- if ( !p ) {
+ if ( !p )
return -1;
- }
pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf );
pReq->m_pRespHeaderBuf = p;
pReq->m_pRespHeaderBufEnd = p + size;
@@ -308,10 +408,10 @@ static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktTy
{
if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )||
( LSAPI_VERSION_B1 != pHeader->m_versionB1 )||
- ( pktType != pHeader->m_type )) {
+ ( pktType != pHeader->m_type ))
return -1;
- }
- if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT )) {
+ if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT ))
+ {
register char b;
b = pHeader->m_packetLen.m_bytes[0];
pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3];
@@ -327,21 +427,20 @@ static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList,
int *curSize, int newSize )
{
struct LSAPI_key_value_pair * pBuf;
- if ( *curSize >= newSize ) {
+ if ( *curSize >= newSize )
return 0;
- }
- if ( newSize > 8192 ) {
+ if ( newSize > 8192 )
return -1;
- }
pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize *
sizeof(struct LSAPI_key_value_pair) );
- if ( pBuf ) {
+ if ( pBuf )
+ {
*pEnvList = pBuf;
*curSize = newSize;
return 0;
- } else {
- return -1;
}
+ else
+ return -1;
}
@@ -350,36 +449,32 @@ static inline int isPipe( int fd )
char achPeer[128];
socklen_t len = 128;
if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&&
- ( errno == ENOTCONN )) {
+ ( errno == ENOTCONN ))
return 0;
- } else {
+ else
return 1;
- }
}
static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count,
char **pBegin, char * pEnd )
{
struct LSAPI_key_value_pair * pEnvEnd;
- int keyLen = 0, valLen = 0;
- if ( count > 8192 ) {
+ int keyLen = 0, valLen = 0;
+ if ( count > 8192 )
return -1;
- }
pEnvEnd = pEnvList + count;
- while( pEnvList != pEnvEnd ) {
- if ( pEnd - *pBegin < 4 ) {
+ while( pEnvList != pEnvEnd )
+ {
+ if ( pEnd - *pBegin < 4 )
return -1;
- }
keyLen = *((unsigned char *)((*pBegin)++));
keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++));
valLen = *((unsigned char *)((*pBegin)++));
valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++));
- if ( *pBegin + keyLen + valLen > pEnd ) {
+ if ( *pBegin + keyLen + valLen > pEnd )
return -1;
- }
- if (( !keyLen )||( !valLen )) {
+ if (( !keyLen )||( !valLen ))
return -1;
- }
pEnvList->pKey = *pBegin;
*pBegin += keyLen;
@@ -390,9 +485,8 @@ static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count,
pEnvList->valLen = valLen - 1;
++pEnvList;
}
- if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 ) {
+ if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 )
return -1;
- }
*pBegin += 4;
return 0;
}
@@ -427,8 +521,10 @@ static inline void fixEndian( LSAPI_Request * pReq )
static void fixHeaderIndexEndian( LSAPI_Request * pReq )
{
int i;
- for( i = 0; i < H_TRANSFER_ENCODING; ++i ) {
- if ( pReq->m_pHeaderIndex->m_headerOff[i] ) {
+ for( i = 0; i < H_TRANSFER_ENCODING; ++i )
+ {
+ if ( pReq->m_pHeaderIndex->m_headerOff[i] )
+ {
register char b;
char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]);
b = p[0];
@@ -437,20 +533,434 @@ static void fixHeaderIndexEndian( LSAPI_Request * pReq )
swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] );
}
}
- if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) {
+ if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
+ {
struct lsapi_header_offset * pCur, *pEnd;
pCur = pReq->m_pUnknownHeader;
pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
- while( pCur < pEnd ) {
+ while( pCur < pEnd )
+ {
swapIntEndian( &pCur->nameOff );
swapIntEndian( &pCur->nameLen );
swapIntEndian( &pCur->valueOff );
swapIntEndian( &pCur->valueLen );
++pCur;
}
- }
+ }
+}
+
+static uid_t s_uid = 0;
+static uid_t s_defaultUid; //web server need set this
+static gid_t s_defaultGid;
+
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+
+#define LSAPI_LVE_DISABLED 0
+#define LSAPI_LVE_ENABLED 1
+#define LSAPI_CAGEFS_ENABLED 2
+#define LSAPI_CAGEFS_NO_SUEXEC 3
+struct liblve;
+static int s_enable_lve = LSAPI_LVE_DISABLED;
+static struct liblve * s_lve = NULL;
+
+static void *s_liblve;
+static int (*fp_lve_is_available)(void) = NULL;
+static int (*fp_lve_instance_init)(struct liblve *) = NULL;
+static int (*fp_lve_destroy)(struct liblve *) = NULL;
+static int (*fp_lve_enter)(struct liblve *, uint32_t, int32_t, int32_t, uint32_t *) = NULL;
+static int (*fp_lve_leave)(struct liblve *, uint32_t *) = NULL;
+static int (*fp_lve_jail)( struct passwd *, char *) = NULL;
+static int lsapi_load_lve_lib()
+{
+ s_liblve = dlopen("liblve.so.0", RTLD_LAZY);
+ if (s_liblve)
+ {
+ fp_lve_is_available = dlsym(s_liblve, "lve_is_available");
+ if (dlerror() == NULL)
+ {
+ if ( !(*fp_lve_is_available)() )
+ {
+ int uid = getuid();
+ if ( uid )
+ {
+ setreuid( s_uid, uid );
+ if ( !(*fp_lve_is_available)() )
+ s_enable_lve = 0;
+ setreuid( uid, s_uid );
+ }
+ }
+ }
+ }
+ else
+ {
+ s_enable_lve = LSAPI_LVE_DISABLED;
+ }
+ return (s_liblve)? 0 : -1;
+}
+
+static int init_lve_ex()
+{
+ int rc;
+ if ( !s_liblve )
+ return -1;
+ fp_lve_instance_init = dlsym(s_liblve, "lve_instance_init");
+ fp_lve_destroy = dlsym(s_liblve, "lve_destroy");
+ fp_lve_enter = dlsym(s_liblve, "lve_enter");
+ fp_lve_leave = dlsym(s_liblve, "lve_leave");
+ if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED )
+ fp_lve_jail = dlsym(s_liblve, "jail" );
+
+ if ( s_lve == NULL )
+ {
+ rc = (*fp_lve_instance_init)(NULL);
+ s_lve = malloc(rc);
+ }
+ rc = (*fp_lve_instance_init)(s_lve);
+ if (rc != 0)
+ {
+ perror( "LSAPI: Unable to initialize LVE" );
+ free( s_lve );
+ s_lve = NULL;
+ return -1;
+ }
+ return 0;
+
+}
+
+#endif
+
+
+
+static int readSecret( const char * pSecretFile )
+{
+ struct stat st;
+ int fd = open( pSecretFile, O_RDONLY , 0600 );
+ if ( fd == -1 )
+ {
+ fprintf( stderr, "LSAPI: failed to open secret file: %s!\n", pSecretFile );
+ return -1;
+ }
+ if ( fstat( fd, &st ) == -1 )
+ {
+ fprintf( stderr, "LSAPI: failed to check state of file: %s!\n", pSecretFile );
+ close( fd );
+ return -1;
+ }
+/*
+ if ( st.st_uid != s_uid )
+ {
+ fprintf( stderr, "LSAPI: file owner check failure: %s!\n", pSecretFile );
+ close( fd );
+ return -1;
+ }
+*/
+ if ( st.st_mode & 0077 )
+ {
+ fprintf( stderr, "LSAPI: file permission check failure: %s\n", pSecretFile );
+ close( fd );
+ return -1;
+ }
+ if ( read( fd, s_pSecret, 16 ) < 16 )
+ {
+ fprintf( stderr, "LSAPI: failed to read secret from secret file: %s\n", pSecretFile );
+ close( fd );
+ return -1;
+ }
+ close( fd );
+ return 0;
+}
+
+int LSAPI_is_suEXEC_Daemon()
+{
+ if (( !s_uid )&&( s_pSecret[0] ))
+ return 1;
+ else
+ return 0;
+}
+
+static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char *pErr2 )
+{
+ char achError[1024];
+ int n = snprintf(achError, 1024, "%s:%s: %s\n", pErr1, (pErr2)?pErr2:"", strerror( errno ) );
+ if ( pReq )
+ LSAPI_Write_Stderr_r( pReq, achError, n );
+ else
+ write( STDERR_FILENO, achError, n );
+ return 0;
+}
+
+static int lsapi_lve_error( LSAPI_Request * pReq )
+{
+ static const char * headers[] =
+ {
+ "Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0",
+ "Pragma: no-cache",
+ "Retry-After: 60",
+ "Content-Type: text/html",
+ NULL
+ };
+ static const char achBody[] =
+ "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
+ "<HTML><HEAD>\n<TITLE>508 Resource Limit Is Reached</TITLE>\n"
+ "</HEAD><BODY>\n" "<H1>Resource Limit Is Reached</H1>\n"
+ "The website is temporarily unable to service your request as it exceeded resource limit.\n"
+ "Please try again later.\n"
+ "<HR>\n"
+ "</BODY></HTML>\n";
+
+ LSAPI_ErrResponse_r( pReq, 508, headers, achBody, sizeof( achBody ) - 1 );
+ return 0;
+}
+
+static int lsapi_enterLVE( LSAPI_Request * pReq, uid_t uid )
+{
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+ if ( s_lve && uid ) //root user should not do that
+ {
+ uint32_t cookie;
+ int ret = -1;
+ ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie);
+ if ( ret < 0 )
+ {
+ fprintf( stderr, "Pid (%d): enter LVE (%d) : ressult: %d !\n", getpid(), uid, ret );
+ LSAPI_perror_r(pReq, "LSAPI: lve_enter() failure, reached resource limit.", NULL );
+ lsapi_lve_error( pReq );
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static int lsapi_jailLVE( LSAPI_Request * pReq, uid_t uid, struct passwd * pw )
+{
+ int ret = 0;
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+ char error_msg[1024] = "";
+ ret = (*fp_lve_jail)( pw, error_msg );
+ if ( ret < 0 )
+ {
+ fprintf( stderr, "LSAPI (%d): LVE jail(%d) ressult: %d, error: %s !\n",
+ getpid(), uid, ret, error_msg );
+ LSAPI_perror_r( pReq, "LSAPI: jail() failure.", NULL );
+ return -1;
+ }
+#endif
+ return ret;
}
+
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+static int lsapi_initLVE()
+{
+ const char * pEnv;
+ if ( (pEnv = getenv( "LSAPI_LVE_ENABLE" ))!= NULL )
+ {
+ s_enable_lve = atol( pEnv );
+ pEnv = NULL;
+ }
+ else if ( (pEnv = getenv( "LVE_ENABLE" ))!= NULL )
+ {
+ s_enable_lve = atol( pEnv );
+ pEnv = NULL;
+ }
+ if ( s_enable_lve && !s_uid )
+ {
+ lsapi_load_lve_lib();
+ if ( s_enable_lve )
+ {
+ return init_lve_ex();
+ }
+
+ }
+ return 0;
+}
+#endif
+
+
+static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * pChroot)
+{
+ int rv;
+ struct passwd * pw;
+ pw = getpwuid( uid );
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+ if ( s_lve )
+ {
+ if( lsapi_enterLVE( pReq, uid ) == -1 )
+ return -1;
+ if ( pw && fp_lve_jail)
+ {
+ rv = lsapi_jailLVE( pReq, uid, pw );
+ if ( rv == -1 )
+ return -1;
+ if (( rv == 1 )&&(s_enable_lve == LSAPI_CAGEFS_NO_SUEXEC )) //this mode only use cageFS, does not use suEXEC
+ {
+ uid = s_defaultUid;
+ gid = s_defaultGid;
+ pw = getpwuid( uid );
+ }
+ }
+ }
+#endif
+ //if ( !uid || !gid ) //do not allow root
+ //{
+ // return -1;
+ //}
+
+#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+ if ( s_enable_core_dump )
+ lsapi_enable_core_dump();
+#endif
+
+ rv = setgid(gid);
+ if (rv == -1)
+ {
+ LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL);
+ return -1;
+ }
+ if ( pw && (pw->pw_gid == gid ))
+ {
+ rv = initgroups( pw->pw_name, gid );
+ if (rv == -1)
+ {
+ LSAPI_perror_r(pReq, "LSAPI: initgroups()", NULL);
+ return -1;
+ }
+ }
+ else
+ {
+ rv = setgroups(1, &gid);
+ if (rv == -1)
+ {
+ LSAPI_perror_r(pReq, "LSAPI: setgroups()", NULL);
+ }
+ }
+ if ( pChroot )
+ {
+ rv = chroot( pChroot );
+ if ( rv == -1 )
+ {
+ LSAPI_perror_r(pReq, "LSAPI: chroot()", NULL);
+ return -1;
+ }
+ }
+ rv = setuid(uid);
+ if (rv == -1)
+ {
+ LSAPI_perror_r(pReq, "LSAPI: setuid()", NULL);
+ return -1;
+ }
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+ if ( s_enable_core_dump )
+ lsapi_enable_core_dump();
+#endif
+ return 0;
+}
+
+static int lsapi_suexec_auth( LSAPI_Request *pReq,
+ char * pAuth, int len, char * pUgid, int ugidLen )
+{
+ lsapi_MD5_CTX md5ctx;
+ unsigned char achMD5[16];
+ if ( len < 32 )
+ return -1;
+ memmove( achMD5, pAuth + 16, 16 );
+ memmove( pAuth + 16, s_pSecret, 16 );
+ lsapi_MD5Init( &md5ctx );
+ lsapi_MD5Update( &md5ctx, (unsigned char *)pAuth, 32 );
+ lsapi_MD5Update( &md5ctx, (unsigned char *)pUgid, 8 );
+ lsapi_MD5Final( (unsigned char *)pAuth + 16, &md5ctx);
+ if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 )
+ return 0;
+ return 1;
+}
+
+
+static int lsapi_changeUGid( LSAPI_Request * pReq )
+{
+ int uid = s_defaultUid;
+ int gid = s_defaultGid;
+ const char * pChroot = NULL;
+ struct LSAPI_key_value_pair * pEnv;
+ struct LSAPI_key_value_pair * pAuth;
+ int i;
+ if ( s_uid )
+ return 0;
+ //with special ID 0x00
+ //authenticate the suEXEC request;
+ //first one should be MD5( nonce + lscgid secret )
+ //remember to clear the secret after verification
+ //it should be set at the end of special env
+ i = pReq->m_pHeader->m_cntSpecialEnv - 1;
+ if ( i >= 0 )
+ {
+ pEnv = pReq->m_pSpecialEnvList + i;
+ if (( *pEnv->pKey == '\000' )&&
+ ( strcmp( pEnv->pKey+1, "SUEXEC_AUTH" ) == 0 ))
+ {
+ --pReq->m_pHeader->m_cntSpecialEnv;
+ pAuth = pEnv--;
+ if (( *pEnv->pKey == '\000' )&&
+ ( strcmp( pEnv->pKey+1, "SUEXEC_UGID" ) == 0 ))
+ {
+ --pReq->m_pHeader->m_cntSpecialEnv;
+ uid = *(uint32_t *)pEnv->pValue;
+ gid = *(((uint32_t *)pEnv->pValue) + 1 );
+ //fprintf( stderr, "LSAPI: SUEXEC_UGID set UID: %d, GID: %d\n", uid, gid );
+ }
+ else
+ {
+ fprintf( stderr, "LSAPI: missing SUEXEC_UGID env, use default user!\n" );
+ pEnv = NULL;
+ }
+ if ( pEnv&& lsapi_suexec_auth( pReq, pAuth->pValue, pAuth->valLen, pEnv->pValue, pEnv->valLen ) == 0 )
+ {
+ //read UID, GID from specialEnv
+
+ }
+ else
+ {
+ //authentication error
+ fprintf( stderr, "LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" );
+ uid = 0;
+ }
+ }
+ else
+ {
+ //fprintf( stderr, "LSAPI: no SUEXEC_AUTH env, use default user!\n" );
+ }
+ }
+
+
+ if ( !uid )
+ {
+ uid = s_defaultUid;
+ gid = s_defaultGid;
+ }
+
+ //change uid
+ if ( setUID_LVE( pReq, uid, gid, pChroot ) == -1 )
+ {
+ return -1;
+ }
+
+ s_uid = uid;
+
+ return 0;
+
+}
+
+static int parseContentLenFromHeader(LSAPI_Request * pReq)
+{
+ const char * pContentLen = LSAPI_GetHeader_r( pReq, H_CONTENT_LENGTH );
+ if ( pContentLen )
+ pReq->m_reqBodyLen = strtoll( pContentLen, NULL, 10 );
+ return 0;
+}
+
+
static int parseRequest( LSAPI_Request * pReq, int totalLen )
{
int shouldFixEndian;
@@ -458,29 +968,28 @@ static int parseRequest( LSAPI_Request * pReq, int totalLen )
char * pEnd = pReq->m_pReqBuf + totalLen;
shouldFixEndian = ( LSAPI_ENDIAN != (
pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) );
- if ( shouldFixEndian ) {
+ if ( shouldFixEndian )
+ {
fixEndian( pReq );
}
if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&&
allocateEnvList( &pReq->m_pSpecialEnvList,
- &pReq->m_specialEnvListSize,
- pReq->m_pHeader->m_cntSpecialEnv ) == -1 ) {
+ &pReq->m_specialEnvListSize,
+ pReq->m_pHeader->m_cntSpecialEnv ) == -1 )
return -1;
- }
if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&&
allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize,
- pReq->m_pHeader->m_cntEnv ) == -1 ) {
+ pReq->m_pHeader->m_cntEnv ) == -1 )
return -1;
- }
+
if ( parseEnv( pReq->m_pSpecialEnvList,
- pReq->m_pHeader->m_cntSpecialEnv,
- &pBegin, pEnd ) == -1 ) {
+ pReq->m_pHeader->m_cntSpecialEnv,
+ &pBegin, pEnd ) == -1 )
return -1;
- }
if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
- &pBegin, pEnd ) == -1 ) {
+ &pBegin, pEnd ) == -1 )
return -1;
- }
+
pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff;
pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff;
pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff;
@@ -496,85 +1005,183 @@ static int parseRequest( LSAPI_Request * pReq, int totalLen )
pReq->m_pHttpHeader = pBegin;
pBegin += pReq->m_pHeader->m_httpHeaderLen;
- if ( pBegin != pEnd ) {
+ if ( pBegin != pEnd )
+ {
+ fprintf( stderr, "%d: request header does match total size, total: %d, real: %ld\n", getpid(), totalLen,
+ pBegin - pReq->m_pReqBuf );
return -1;
}
-
- if ( shouldFixEndian ) {
+ if ( shouldFixEndian )
+ {
fixHeaderIndexEndian( pReq );
}
-
+ pReq->m_reqBodyLen = pReq->m_pHeader->m_reqBodyLen;
+ if ( pReq->m_reqBodyLen == -2 )
+ {
+ parseContentLenFromHeader(pReq);
+ }
+
return 0;
}
-static struct lsapi_packet_header ack = {'L', 'S',
+//OPTIMIZATION
+static char s_accept_notify = 0;
+static char s_schedule_notify = 0;
+static char s_notify_scheduled = 0;
+static char s_notified_pid = 0;
+
+static struct lsapi_packet_header s_ack = {'L', 'S',
LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} };
-static inline int notify_req_received( LSAPI_Request * pReq )
+
+
+static inline int write_req_received_notification( int fd )
{
- if ( write( pReq->m_fd, &ack, LSAPI_PACKET_HEADER_LEN )
- < LSAPI_PACKET_HEADER_LEN ) {
+ if ( write( fd, &s_ack, LSAPI_PACKET_HEADER_LEN )
+ < LSAPI_PACKET_HEADER_LEN )
return -1;
+ return 0;
+}
+
+static void lsapi_sigalarm( int sig )
+{
+ if ( s_notify_scheduled )
+ {
+ s_notify_scheduled = 0;
+ if ( g_req.m_fd != -1 )
+ write_req_received_notification( g_req.m_fd );
+ }
+}
+
+static inline int lsapi_schedule_notify()
+{
+ if ( !s_notify_scheduled )
+ {
+ alarm( 2 );
+ s_notify_scheduled = 1;
}
return 0;
}
+static inline int notify_req_received( int fd )
+{
+ if ( s_schedule_notify )
+ return lsapi_schedule_notify();
+ return write_req_received_notification( fd );
+
+}
+
+
+static inline int lsapi_notify_pid( int fd )
+{
+ char achBuf[16];
+ lsapi_buildPacketHeader( (struct lsapi_packet_header *)achBuf, LSAPI_STDERR_STREAM,
+ 8 + LSAPI_PACKET_HEADER_LEN );
+ memmove( &achBuf[8], "\0PID", 4 );
+ *((int *)&achBuf[12]) = getpid();
+
+ if ( write( fd, achBuf, 16 ) < 16 )
+ return -1;
+ return 0;
+}
+
+static char s_conn_key_packet[16];
+static inline int init_conn_key( int fd )
+{
+ struct lsapi_packet_header * pHeader = (struct lsapi_packet_header *)s_conn_key_packet;
+ struct timeval tv;
+ int i;
+ gettimeofday( &tv, NULL );
+ srand( (tv.tv_sec % 0x1000 + tv.tv_usec) ^ rand() );
+ for( i = 8; i < 16; ++i )
+ {
+ s_conn_key_packet[i]=(int) (256.0*rand()/(RAND_MAX+1.0));
+ }
+ lsapi_buildPacketHeader( pHeader, LSAPI_REQ_RECEIVED,
+ 8 + LSAPI_PACKET_HEADER_LEN );
+ if ( write( fd, s_conn_key_packet, LSAPI_PACKET_HEADER_LEN+8 )
+ < LSAPI_PACKET_HEADER_LEN+8 )
+ return -1;
+ return 0;
+
+
+}
static int readReq( LSAPI_Request * pReq )
{
int len;
int packetLen;
- if ( !pReq ) {
+ if ( !pReq )
return -1;
- }
- if ( pReq->m_reqBufSize < 8192 ) {
- if ( allocateBuf( pReq, 8192 ) == -1 ) {
+ if ( pReq->m_reqBufSize < 8192 )
+ {
+ if ( allocateBuf( pReq, 8192 ) == -1 )
return -1;
- }
}
- while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN ) {
+ while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN )
+ {
len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize );
- if ( len <= 0 ) {
+ if ( len <= 0 )
return -1;
- }
pReq->m_bufRead += len;
}
pReq->m_reqState = LSAPI_ST_REQ_HEADER;
packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST );
- if ( packetLen < 0 ) {
+ if ( packetLen < 0 )
+ {
+ fprintf( stderr, "%d: packetLen < 0\n", getpid() );
return -1;
}
- if ( packetLen > LSAPI_MAX_HEADER_LEN ) {
+ if ( packetLen > LSAPI_MAX_HEADER_LEN )
+ {
+ fprintf( stderr, "%d: packetLen > %d\n", getpid(), LSAPI_MAX_HEADER_LEN );
return -1;
}
- if ( packetLen + 1024 > pReq->m_reqBufSize ) {
- if ( allocateBuf( pReq, packetLen + 1024 ) == -1 ) {
+ if ( packetLen + 1024 > pReq->m_reqBufSize )
+ {
+ if ( allocateBuf( pReq, packetLen + 1024 ) == -1 )
return -1;
- }
}
- while( packetLen > pReq->m_bufRead ) {
+ while( packetLen > pReq->m_bufRead )
+ {
len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead );
- if ( len <= 0 ) {
+ if ( len <= 0 )
return -1;
- }
pReq->m_bufRead += len;
}
- if ( parseRequest( pReq, packetLen ) < 0 ) {
+ if ( parseRequest( pReq, packetLen ) < 0 )
+ {
+ fprintf( stderr, "%d: parseRequest error\n", getpid() );
return -1;
}
- pReq->m_bufProcessed = packetLen;
+
pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER;
- return notify_req_received( pReq );
+ if ( !s_uid )
+ if ( lsapi_changeUGid( pReq ) )
+ return -1;
+ pReq->m_bufProcessed = packetLen;
+
+ //OPTIMIZATION
+ if ( !s_accept_notify && !s_notified_pid )
+ return notify_req_received( pReq->m_fd );
+ else
+ {
+ s_notified_pid = 0;
+ return 0;
+ }
}
int LSAPI_Init(void)
{
- if ( !g_inited ) {
+ if ( !g_inited )
+ {
+ s_uid = geteuid();
+ s_pSecret[0] = 0;
lsapi_signal(SIGPIPE, lsapi_sigpipe);
lsapi_signal(SIGUSR1, lsapi_siguser1);
@@ -583,11 +1190,9 @@ int LSAPI_Init(void)
#endif
/* let STDOUT function as STDERR,
just in case writing to STDOUT directly */
- dup2( 2, 1 );
-
- if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) {
+ dup2( 2, 1 );
+ if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 )
return -1;
- }
g_inited = 1;
s_ppid = getppid();
}
@@ -606,28 +1211,27 @@ int LSAPI_IsRunning(void)
int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
{
- if ( !pReq ) {
+ if ( !pReq )
return -1;
- }
memset( pReq, 0, sizeof( LSAPI_Request ) );
- if ( allocateIovec( pReq, 16 ) == -1 ) {
+ if ( allocateIovec( pReq, 16 ) == -1 )
return -1;
- }
pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE );
- if ( !pReq->m_pRespBuf ) {
+ if ( !pReq->m_pRespBuf )
return -1;
- }
pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE;
pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5];
- if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 ) {
+ if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 )
return -1;
- }
- if ( isPipe( fd ) ) {
+ if ( isPipe( fd ) )
+ {
pReq->m_fdListen = -1;
pReq->m_fd = fd;
- } else {
+ }
+ else
+ {
pReq->m_fdListen = fd;
pReq->m_fd = -1;
lsapi_set_nblock( fd, 1 );
@@ -653,38 +1257,48 @@ int LSAPI_Accept_r( LSAPI_Request * pReq )
socklen_t len;
int nodelay = 1;
- if ( !pReq ) {
+ if ( !pReq )
return -1;
- }
- if ( LSAPI_Finish_r( pReq ) == -1 ) {
+ if ( LSAPI_Finish_r( pReq ) == -1 )
return -1;
- }
- while( g_running ) {
- if ( pReq->m_fd == -1 ) {
- if ( pReq->m_fdListen != -1) {
+ lsapi_set_nblock( pReq->m_fdListen , 0 );
+ while( g_running )
+ {
+ if ( pReq->m_fd == -1 )
+ {
+ if ( pReq->m_fdListen != -1)
+ {
len = sizeof( achPeer );
pReq->m_fd = accept( pReq->m_fdListen,
(struct sockaddr *)&achPeer, &len );
- if ( pReq->m_fd == -1 ) {
- if (( errno == EINTR )||( errno == EAGAIN)) {
+ if ( pReq->m_fd == -1 )
+ {
+ if (( errno == EINTR )||( errno == EAGAIN))
continue;
- } else {
+ else
return -1;
- }
- } else {
+ }
+ else
+ {
lsapi_set_nblock( pReq->m_fd , 0 );
- if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) {
+ if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
+ {
setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY,
- (char *)&nodelay, sizeof(nodelay));
+ (char *)&nodelay, sizeof(nodelay));
}
+ //init_conn_key( pReq->m_fd );
+ //OPTIMIZATION
+ if ( s_accept_notify )
+ if ( notify_req_received( pReq->m_fd ) == -1 )
+ return -1;
}
- } else {
- return -1;
}
+ else
+ return -1;
}
- if ( !readReq( pReq ) ) {
+ if ( !readReq( pReq ) )
break;
- }
+ //abort();
lsapi_close( pReq->m_fd );
pReq->m_fd = -1;
LSAPI_Reset_r( pReq );
@@ -698,15 +1312,18 @@ static struct lsapi_packet_header finish = {'L', 'S',
int LSAPI_Finish_r( LSAPI_Request * pReq )
{
/* finish req body */
- if ( !pReq ) {
+ if ( !pReq )
return -1;
- }
- if (pReq->m_reqState) {
- if ( pReq->m_fd != -1 ) {
- if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) {
+ if (pReq->m_reqState)
+ {
+ if ( pReq->m_fd != -1 )
+ {
+ if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
+ {
LSAPI_FinalizeRespHeaders_r( pReq );
}
- if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) {
+ if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
+ {
Flush_RespBuf_r( pReq );
}
@@ -735,18 +1352,14 @@ void LSAPI_Reset_r( LSAPI_Request * pReq )
int LSAPI_Release_r( LSAPI_Request * pReq )
{
- if ( pReq->m_pReqBuf ) {
+ if ( pReq->m_pReqBuf )
free( pReq->m_pReqBuf );
- }
- if ( pReq->m_pSpecialEnvList ) {
+ if ( pReq->m_pSpecialEnvList )
free( pReq->m_pSpecialEnvList );
- }
- if ( pReq->m_pEnvList ) {
+ if ( pReq->m_pEnvList )
free( pReq->m_pEnvList );
- }
- if ( pReq->m_pRespHeaderBuf ) {
+ if ( pReq->m_pRespHeaderBuf )
free( pReq->m_pRespHeaderBuf );
- }
return 0;
}
@@ -754,55 +1367,48 @@ int LSAPI_Release_r( LSAPI_Request * pReq )
char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex )
{
int off;
- if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) ) {
+ if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) )
return NULL;
- }
off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ];
- if ( !off ) {
+ if ( !off )
return NULL;
- }
- if ( *(pReq->m_pHttpHeader + off +
- pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) {
- *( pReq->m_pHttpHeader + off +
- pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0;
- }
+ if ( *(pReq->m_pHttpHeader + off +
+ pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) )
+ *( pReq->m_pHttpHeader + off +
+ pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0;
return pReq->m_pHttpHeader + off;
}
static int readBodyToReqBuf( LSAPI_Request * pReq )
{
- int bodyLeft;
- int len = pReq->m_bufRead - pReq->m_bufProcessed;
- if ( len > 0 ) {
+ off_t bodyLeft;
+ ssize_t len = pReq->m_bufRead - pReq->m_bufProcessed;
+ if ( len > 0 )
return len;
- }
pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen;
- bodyLeft = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
+ bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead;
len = pReq->m_reqBufSize - pReq->m_bufRead;
- if ( len < 0 ) {
+ if ( len < 0 )
return -1;
- }
- if ( len > bodyLeft ) {
+ if ( len > bodyLeft )
len = bodyLeft;
- }
+
len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len );
- if ( len > 0 ) {
+ if ( len > 0 )
pReq->m_bufRead += len;
- }
return len;
}
int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq )
{
- if (!pReq || (pReq->m_fd ==-1) ) {
+ if (!pReq || (pReq->m_fd ==-1) )
return EOF;
- }
- if ( pReq->m_bufProcessed >= pReq->m_bufRead ) {
- if ( readBodyToReqBuf( pReq ) <= 0 ) {
+ if ( pReq->m_bufProcessed >= pReq->m_bufRead )
+ {
+ if ( readBodyToReqBuf( pReq ) <= 0 )
return EOF;
- }
}
++pReq->m_reqBodyRead;
return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++);
@@ -810,42 +1416,43 @@ int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq )
-int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, int bufLen, int *getLF )
+int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF )
{
- int len;
- int left;
+ ssize_t len;
+ ssize_t left;
char * pBufEnd = pBuf + bufLen - 1;
char * pBufCur = pBuf;
char * pCur;
char * p;
- if (!pReq || (pReq->m_fd ==-1) ||( !pBuf )||(bufLen < 0 )|| !getLF ) {
+ if (!pReq || (pReq->m_fd ==-1) ||( !pBuf )||(bufLen < 0 )|| !getLF )
return -1;
- }
*getLF = 0;
- while( (left = pBufEnd - pBufCur ) > 0 ) {
+ while( (left = pBufEnd - pBufCur ) > 0 )
+ {
len = pReq->m_bufRead - pReq->m_bufProcessed;
- if ( len <= 0 ) {
- if ( (len = readBodyToReqBuf( pReq )) <= 0 ) {
+ if ( len <= 0 )
+ {
+ if ( (len = readBodyToReqBuf( pReq )) <= 0 )
+ {
*getLF = 1;
break;
}
}
- if ( len > left ) {
+ if ( len > left )
len = left;
- }
pCur = pReq->m_pReqBuf + pReq->m_bufProcessed;
p = memchr( pCur, '\n', len );
- if ( p ) {
+ if ( p )
len = p - pCur + 1;
- }
memmove( pBufCur, pCur, len );
pBufCur += len;
pReq->m_bufProcessed += len;
pReq->m_reqBodyRead += len;
- if ( p ) {
+ if ( p )
+ {
*getLF = 1;
break;
}
@@ -856,48 +1463,47 @@ int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, int bufLen, int *
}
-int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen )
+ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen )
{
- int len;
- int total;
+ ssize_t len;
+ off_t total;
/* char *pOldBuf = pBuf; */
- if (!pReq || (pReq->m_fd ==-1) || ( !pBuf )||(bufLen < 0 )) {
+ if (!pReq || (pReq->m_fd ==-1) || ( !pBuf )||(bufLen < 0 ))
return -1;
- }
- total = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
+
+ total = pReq->m_reqBodyLen - pReq->m_reqBodyRead;
- if ( total <= 0 ) {
+ if ( total <= 0 )
return 0;
- }
- if ( total < bufLen ) {
+ if ( total < bufLen )
bufLen = total;
- }
total = 0;
len = pReq->m_bufRead - pReq->m_bufProcessed;
- if ( len > 0 ) {
- if ( len > bufLen ) {
+ if ( len > 0 )
+ {
+ if ( len > bufLen )
len = bufLen;
- }
memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len );
pReq->m_bufProcessed += len;
total += len;
pBuf += len;
bufLen -= len;
}
- while( bufLen > 0 ) {
+ while( bufLen > 0 )
+ {
len = lsapi_read( pReq->m_fd, pBuf, bufLen );
- if ( len > 0 ) {
+ if ( len > 0 )
+ {
total += len;
pBuf += len;
bufLen -= len;
- } else {
- if ( len <= 0 ) {
- if ( !total) {
- return -1;
- }
- break;
- }
+ }
+ else if ( len <= 0 )
+ {
+ if ( !total)
+ return -1;
+ break;
}
}
pReq->m_reqBodyRead += total;
@@ -906,37 +1512,52 @@ int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen )
}
-int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
+ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
{
struct lsapi_packet_header * pHeader;
const char * pEnd;
const char * p;
- int bufLen;
- int toWrite;
- int packetLen;
+ ssize_t bufLen;
+ ssize_t toWrite;
+ ssize_t packetLen;
+ int skip = 0;
- if ( !pReq || !pBuf || (pReq->m_fd == -1) ) {
+ if ( !pReq || !pBuf || (pReq->m_fd == -1) )
return -1;
+ if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
+ {
+ LSAPI_FinalizeRespHeaders_r( pReq );
+/*
+ if ( *pBuf == '\r' )
+ {
+ ++skip;
+ }
+ if ( *pBuf == '\n' )
+ {
+ ++skip;
+ }
+*/
}
- if ( len < pReq->m_pRespBufEnd - pReq->m_pRespBufPos ) {
- memmove( pReq->m_pRespBufPos, pBuf, len );
- pReq->m_pRespBufPos += len;
+ pReq->m_reqState |= LSAPI_ST_RESP_BODY;
+
+ if ( (len - skip) < pReq->m_pRespBufEnd - pReq->m_pRespBufPos )
+ {
+ memmove( pReq->m_pRespBufPos, pBuf + skip, len - skip );
+ pReq->m_pRespBufPos += len - skip;
return len;
}
- if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) {
- LSAPI_FinalizeRespHeaders_r( pReq );
- }
- pReq->m_reqState |= LSAPI_ST_RESP_BODY;
pHeader = pReq->m_respPktHeader;
- p = pBuf;
+ p = pBuf + skip;
pEnd = pBuf + len;
bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf;
- while( ( toWrite = pEnd - p ) > 0 ) {
+ while( ( toWrite = pEnd - p ) > 0 )
+ {
packetLen = toWrite + bufLen;
- if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) {
+ if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen)
+ {
packetLen = LSAPI_MAX_DATA_PACKET_LEN;
toWrite = packetLen - bufLen;
}
@@ -949,7 +1570,8 @@ int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
++pReq->m_pIovecCur;
++pHeader;
- if ( bufLen > 0 ) {
+ if ( bufLen > 0 )
+ {
pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
pReq->m_pIovecCur->iov_len = bufLen;
pReq->m_pRespBufPos = pReq->m_pRespBuf;
@@ -962,21 +1584,108 @@ int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
++pReq->m_pIovecCur;
p += toWrite;
- if ( pHeader >= pReq->m_respPktHeaderEnd - 1) {
- if ( LSAPI_Flush_r( pReq ) == -1 ) {
+ if ( pHeader >= pReq->m_respPktHeaderEnd - 1)
+ {
+ if ( LSAPI_Flush_r( pReq ) == -1 )
return -1;
- }
pHeader = pReq->m_respPktHeader;
}
}
- if ( pHeader != pReq->m_respPktHeader ) {
- if ( LSAPI_Flush_r( pReq ) == -1 ) {
+ if ( pHeader != pReq->m_respPktHeader )
+ if ( LSAPI_Flush_r( pReq ) == -1 )
return -1;
- }
- }
return p - pBuf;
}
+#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__)
+ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size )
+{
+ ssize_t ret;
+ off_t written;
+ ret = sendfile( fdIn, fdOut, *off, size, NULL, &written, 0 );
+ if ( written > 0 )
+ {
+ ret = written;
+ *off += ret;
+ }
+ return ret;
+}
+#endif
+
+#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size )
+{
+ ssize_t ret;
+ off_t len = size;
+ ret = sendfile( fdIn, fdOut, *off, &len, NULL, 0 );
+ if (( ret == 0 )&&( len > 0 ))
+ {
+ ret = len;
+ *off += len;
+ }
+ return ret;
+}
+#endif
+
+#if defined(sun) || defined(__sun)
+#include <sys/sendfile.h>
+ssize_t gsendfile( int fdOut, int fdIn, off_t *off, size_t size )
+{
+ int n = 0 ;
+ sendfilevec_t vec[1];
+
+ vec[n].sfv_fd = fdIn;
+ vec[n].sfv_flag = 0;
+ vec[n].sfv_off = *off;
+ vec[n].sfv_len = size;
+ ++n;
+
+ size_t written;
+ ssize_t ret = sendfilev( fdOut, vec, n, &written );
+ if (( !ret )||( errno == EAGAIN ))
+ ret = written;
+ if ( ret > 0 )
+ *off += ret;
+ return ret;
+}
+#endif
+
+#if defined(linux) || defined(__linux) || defined(__linux__) || \
+ defined(__gnu_linux__)
+#include <sys/sendfile.h>
+#define gsendfile sendfile
+#endif
+#if defined(HPUX)
+ssize_t gsendfile( int fdOut, int fdIn, off_t * off, size_t size )
+{
+ return sendfile( fdOut, fdIn, off, size, NULL, 0 );
+}
+#endif
+
+ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size )
+{
+ struct lsapi_packet_header * pHeader = pReq->m_respPktHeader;
+ if ( !pReq || (pReq->m_fd == -1) || fdIn == -1 )
+ return -1;
+ if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
+ {
+ LSAPI_FinalizeRespHeaders_r( pReq );
+ }
+ pReq->m_reqState |= LSAPI_ST_RESP_BODY;
+
+ LSAPI_Flush_r(pReq);
+
+ lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
+ size + LSAPI_PACKET_HEADER_LEN );
+
+
+ if (write(pReq->m_fd, (const char *) pHeader, LSAPI_PACKET_HEADER_LEN ) != LSAPI_PACKET_HEADER_LEN)
+ return -1;
+
+ return gsendfile( pReq->m_fd, fdIn, off, size );
+}
+
+
void Flush_RespBuf_r( LSAPI_Request * pReq )
{
struct lsapi_packet_header * pHeader = pReq->m_respPktHeader;
@@ -990,7 +1699,8 @@ void Flush_RespBuf_r( LSAPI_Request * pReq )
pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
++pReq->m_pIovecCur;
++pHeader;
- if ( bufLen > 0 ) {
+ if ( bufLen > 0 )
+ {
pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
pReq->m_pIovecCur->iov_len = bufLen;
pReq->m_pRespBufPos = pReq->m_pRespBuf;
@@ -1006,32 +1716,35 @@ int LSAPI_Flush_r( LSAPI_Request * pReq )
{
int ret = 0;
int n;
- if ( !pReq ) {
+ if ( !pReq )
return -1;
- }
n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
- if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf )) {
+ if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf ))
return 0;
- }
- if ( pReq->m_fd == -1 ) {
+ if ( pReq->m_fd == -1 )
+ {
pReq->m_pRespBufPos = pReq->m_pRespBuf;
pReq->m_totalLen = 0;
pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec;
return -1;
}
- if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) {
+ if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
+ {
LSAPI_FinalizeRespHeaders_r( pReq );
}
- if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) {
+ if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
+ {
Flush_RespBuf_r( pReq );
}
n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
- if ( n > 0 ) {
+ if ( n > 0 )
+ {
ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite,
n, pReq->m_totalLen );
- if ( ret < pReq->m_totalLen ) {
+ if ( ret < pReq->m_totalLen )
+ {
lsapi_close( pReq->m_fd );
pReq->m_fd = -1;
ret = -1;
@@ -1043,32 +1756,33 @@ int LSAPI_Flush_r( LSAPI_Request * pReq )
}
-int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
+ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
{
struct lsapi_packet_header header;
const char * pEnd;
const char * p;
- int packetLen;
- int totalLen;
+ ssize_t packetLen;
+ ssize_t totalLen;
int ret;
struct iovec iov[2];
struct iovec *pIov;
- if ( !pReq ) {
+ if ( !pReq )
return -1;
- }
- if (( pReq->m_fd == -1 )||(pReq->m_fd == pReq->m_fdListen )) {
+ if (( pReq->m_fd == -1 )||(pReq->m_fd == pReq->m_fdListen ))
return write( 2, pBuf, len );
- }
- if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) {
+ if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
+ {
LSAPI_Flush_r( pReq );
}
p = pBuf;
pEnd = pBuf + len;
- while( ( packetLen = pEnd - p ) > 0 ) {
- if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) {
+ while( ( packetLen = pEnd - p ) > 0 )
+ {
+ if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen)
+ {
packetLen = LSAPI_MAX_DATA_PACKET_LEN;
}
@@ -1085,7 +1799,8 @@ int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
pIov = iov;
ret = lsapi_writev( pReq->m_fd, &pIov,
2, totalLen );
- if ( ret < totalLen ) {
+ if ( ret < totalLen )
+ {
lsapi_close( pReq->m_fd );
pReq->m_fd = -1;
ret = -1;
@@ -1097,14 +1812,16 @@ int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
{
int i;
- for( i = 0; i < H_TRANSFER_ENCODING; ++i ) {
- if ( pReq->m_pHeaderIndex->m_headerOff[i] ) {
- if ( strcmp( name, CGI_HEADERS[i] ) == 0 ) {
+ for( i = 0; i < H_TRANSFER_ENCODING; ++i )
+ {
+ if ( pReq->m_pHeaderIndex->m_headerOff[i] )
+ {
+ if ( strcmp( name, CGI_HEADERS[i] ) == 0 )
return pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
- }
}
}
- if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) {
+ if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
+ {
const char *p;
char *pKey;
char *pKeyEnd;
@@ -1112,22 +1829,22 @@ static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
struct lsapi_header_offset * pCur, *pEnd;
pCur = pReq->m_pUnknownHeader;
pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
- while( pCur < pEnd ) {
+ while( pCur < pEnd )
+ {
pKey = pReq->m_pHttpHeader + pCur->nameOff;
keyLen = pCur->nameLen;
pKeyEnd = pKey + keyLen;
p = &name[5];
- while(( pKey < pKeyEnd )&&( *p )) {
+ while(( pKey < pKeyEnd )&&( *p ))
+ {
char ch = toupper( *pKey );
- if ((ch != *p )||(( *p == '_' )&&( ch != '-'))) {
+ if ((ch != *p )||(( *p == '_' )&&( ch != '-')))
break;
- }
++p; ++pKey;
}
- if (( pKey == pKeyEnd )&& (!*p )) {
+ if (( pKey == pKeyEnd )&& (!*p ))
return pReq->m_pHttpHeader + pCur->valueOff;
- }
++pCur;
}
}
@@ -1139,21 +1856,35 @@ char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name )
{
struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList;
struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv;
- if ( !pReq || !name ) {
+ if ( !pReq || !name )
return NULL;
- }
- if ( strncmp( name, "HTTP_", 5 ) == 0 ) {
+ if ( strncmp( name, "HTTP_", 5 ) == 0 )
+ {
return GetHeaderVar( pReq, name );
}
- while( pBegin < pEnd ) {
- if ( strcmp( name, pBegin->pKey ) == 0 ) {
+ while( pBegin < pEnd )
+ {
+ if ( strcmp( name, pBegin->pKey ) == 0 )
return pBegin->pValue;
- }
++pBegin;
}
return NULL;
}
+struct _headerInfo
+{
+ const char * _name;
+ int _nameLen;
+ const char * _value;
+ int _valueLen;
+};
+
+int compareValueLocation(const void * v1, const void *v2 )
+{
+ return ((const struct _headerInfo *)v1)->_value -
+ ((const struct _headerInfo *)v2)->_value;
+}
+
int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq,
LSAPI_CB_EnvHandler fn, void * arg )
{
@@ -1162,43 +1893,66 @@ int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq,
char * pValue;
int ret;
int count = 0;
- if ( !pReq || !fn ) {
+ struct _headerInfo headers[512];
+ if ( !pReq || !fn )
return -1;
- }
- for( i = 0; i < H_TRANSFER_ENCODING; ++i ) {
- if ( pReq->m_pHeaderIndex->m_headerOff[i] ) {
+
+ for( i = 0; i < H_TRANSFER_ENCODING; ++i )
+ {
+ if ( pReq->m_pHeaderIndex->m_headerOff[i] )
+ {
len = pReq->m_pHeaderIndex->m_headerLen[i];
pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
*(pValue + len ) = 0;
- ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i],
- pValue, len, arg );
+ headers[count]._name = HTTP_HEADERS[i];
+ headers[count]._nameLen = HTTP_HEADER_LEN[i];
+ headers[count]._value = pValue;
+ headers[count]._valueLen = len;
++count;
- if ( ret <= 0 ) {
- return ret;
- }
+
+ //ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i],
+ // pValue, len, arg );
+ //if ( ret <= 0 )
+ // return ret;
}
}
- if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) {
+ if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
+ {
char *pKey;
int keyLen;
struct lsapi_header_offset * pCur, *pEnd;
pCur = pReq->m_pUnknownHeader;
pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
- while( pCur < pEnd ) {
+ while( pCur < pEnd )
+ {
pKey = pReq->m_pHttpHeader + pCur->nameOff;
keyLen = pCur->nameLen;
pValue = pReq->m_pHttpHeader + pCur->valueOff;
*(pValue + pCur->valueLen ) = 0;
- ret = (*fn)( pKey, keyLen,
- pValue, pCur->valueLen, arg );
- if ( ret <= 0 ) {
- return ret;
- }
+ headers[count]._name = pKey;
+ headers[count]._nameLen = keyLen;
+ headers[count]._value = pValue;
+ headers[count]._valueLen = pCur->valueLen;
+ ++count;
+ if ( count == 512 )
+ break;
+ //ret = (*fn)( pKey, keyLen,
+ // pValue, pCur->valueLen, arg );
+ //if ( ret <= 0 )
+ // return ret;
++pCur;
}
}
- return count + pReq->m_pHeader->m_cntUnknownHeaders;
+ qsort( headers, count, sizeof( struct _headerInfo ), compareValueLocation );
+ for( i = 0; i < count; ++i )
+ {
+ ret = (*fn)( headers[i]._name, headers[i]._nameLen,
+ headers[i]._value, headers[i]._valueLen, arg );
+ if ( ret <= 0 )
+ return ret;
+ }
+ return count;
}
@@ -1211,23 +1965,24 @@ int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
char * pValue;
int ret;
int count = 0;
- if ( !pReq || !fn ) {
+ if ( !pReq || !fn )
return -1;
- }
- for( i = 0; i < H_TRANSFER_ENCODING; ++i ) {
- if ( pReq->m_pHeaderIndex->m_headerOff[i] ) {
+ for( i = 0; i < H_TRANSFER_ENCODING; ++i )
+ {
+ if ( pReq->m_pHeaderIndex->m_headerOff[i] )
+ {
len = pReq->m_pHeaderIndex->m_headerLen[i];
pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
*(pValue + len ) = 0;
ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i],
pValue, len, arg );
++count;
- if ( ret <= 0 ) {
+ if ( ret <= 0 )
return ret;
- }
}
}
- if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) {
+ if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
+ {
char achHeaderName[256];
char *p;
char *pKey;
@@ -1236,23 +1991,23 @@ int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
struct lsapi_header_offset * pCur, *pEnd;
pCur = pReq->m_pUnknownHeader;
pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
- while( pCur < pEnd ) {
+ while( pCur < pEnd )
+ {
pKey = pReq->m_pHttpHeader + pCur->nameOff;
keyLen = pCur->nameLen;
+ if ( keyLen > 250 )
+ keyLen = 250;
pKeyEnd = pKey + keyLen;
memcpy( achHeaderName, "HTTP_", 5 );
p = &achHeaderName[5];
- if ( keyLen > 250 ) {
- keyLen = 250;
- }
- while( pKey < pKeyEnd ) {
+ while( pKey < pKeyEnd )
+ {
char ch = *pKey++;
- if ( ch == '-' ) {
+ if ( ch == '-' )
*p++ = '_';
- } else {
+ else
*p++ = toupper( ch );
- }
}
*p = 0;
keyLen += 5;
@@ -1261,9 +2016,8 @@ int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
*(pValue + pCur->valueLen ) = 0;
ret = (*fn)( achHeaderName, keyLen,
pValue, pCur->valueLen, arg );
- if ( ret <= 0 ) {
+ if ( ret <= 0 )
return ret;
- }
++pCur;
}
}
@@ -1276,15 +2030,14 @@ static int EnvForeach( struct LSAPI_key_value_pair * pEnv,
{
struct LSAPI_key_value_pair * pEnd = pEnv + n;
int ret;
- if ( !pEnv || !fn ) {
+ if ( !pEnv || !fn )
return -1;
- }
- while( pEnv < pEnd ) {
+ while( pEnv < pEnd )
+ {
ret = (*fn)( pEnv->pKey, pEnv->keyLen,
pEnv->pValue, pEnv->valLen, arg );
- if ( ret <= 0 ) {
+ if ( ret <= 0 )
return ret;
- }
++pEnv;
}
return n;
@@ -1295,10 +2048,10 @@ static int EnvForeach( struct LSAPI_key_value_pair * pEnv,
int LSAPI_ForeachEnv_r( LSAPI_Request * pReq,
LSAPI_CB_EnvHandler fn, void * arg )
{
- if ( !pReq || !fn ) {
+ if ( !pReq || !fn )
return -1;
- }
- if ( pReq->m_pHeader->m_cntEnv > 0 ) {
+ if ( pReq->m_pHeader->m_cntEnv > 0 )
+ {
return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
fn, arg );
}
@@ -1310,10 +2063,10 @@ int LSAPI_ForeachEnv_r( LSAPI_Request * pReq,
int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
LSAPI_CB_EnvHandler fn, void * arg )
{
- if ( !pReq || !fn ) {
+ if ( !pReq || !fn )
return -1;
- }
- if ( pReq->m_pHeader->m_cntSpecialEnv > 0 ) {
+ if ( pReq->m_pHeader->m_cntSpecialEnv > 0 )
+ {
return EnvForeach( pReq->m_pSpecialEnvList,
pReq->m_pHeader->m_cntSpecialEnv,
fn, arg );
@@ -1326,14 +2079,13 @@ int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq )
{
- if ( !pReq || !pReq->m_pIovec ) {
+ if ( !pReq || !pReq->m_pIovec )
return -1;
- }
- if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) ) {
+ if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) )
return 0;
- }
pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER;
- if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf ) {
+ if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf )
+ {
pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf;
pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf;
pReq->m_totalLen += pReq->m_pIovecCur->iov_len;
@@ -1352,25 +2104,87 @@ int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq )
}
-
-
-int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, char * pBuf, int len )
+int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
+ const char * pHeaderValue )
{
- if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX ) {
+ int nameLen, valLen, len;
+ if ( !pReq || !pHeaderName || !pHeaderValue )
+ return -1;
+ if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
return -1;
+ if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS )
+ return -1;
+ nameLen = strlen( pHeaderName );
+ valLen = strlen( pHeaderValue );
+ if ( nameLen == 0 )
+ return -1;
+ while( nameLen > 0 )
+ {
+ char ch = *(pHeaderName + nameLen - 1 );
+ if (( ch == '\n' )||( ch == '\r' ))
+ --nameLen;
+ else
+ break;
+ }
+ if ( nameLen <= 0 )
+ return 0;
+ while( valLen > 0 )
+ {
+ char ch = *(pHeaderValue + valLen - 1 );
+ if (( ch == '\n' )||( ch == '\r' ))
+ --valLen;
+ else
+ break;
}
- if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) {
+ len = nameLen + valLen + 1;
+ if ( len > LSAPI_RESP_HTTP_HEADER_MAX )
return -1;
+
+ if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
+ {
+ int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
+ newlen -= newlen % 4096;
+ if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
+ return -1;
}
- if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) {
+ memmove( pReq->m_pRespHeaderBufPos, pHeaderName, nameLen );
+ pReq->m_pRespHeaderBufPos += nameLen;
+ *pReq->m_pRespHeaderBufPos++ = ':';
+ memmove( pReq->m_pRespHeaderBufPos, pHeaderValue, valLen );
+ pReq->m_pRespHeaderBufPos += valLen;
+ *pReq->m_pRespHeaderBufPos++ = 0;
+ ++len; /* add one byte padding for \0 */
+ pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len;
+ ++pReq->m_respHeader.m_respInfo.m_cntHeaders;
+ return 0;
+}
+
+
+
+int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len )
+{
+ if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX )
+ return -1;
+ if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
return -1;
+ if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS )
+ return -1;
+ while( len > 0 )
+ {
+ char ch = *(pBuf + len - 1 );
+ if (( ch == '\n' )||( ch == '\r' ))
+ --len;
+ else
+ break;
}
- if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) {
+ if ( len <= 0 )
+ return 0;
+ if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
+ {
int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
newlen -= newlen % 4096;
- if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) {
+ if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
return -1;
- }
}
memmove( pReq->m_pRespHeaderBufPos, pBuf, len );
pReq->m_pRespHeaderBufPos += len;
@@ -1389,7 +2203,8 @@ int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog )
int flag = 1;
int addr_len;
- switch( pServerAddr->sa_family ) {
+ switch( pServerAddr->sa_family )
+ {
case AF_INET:
addr_len = 16;
break;
@@ -1405,20 +2220,20 @@ int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog )
}
fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 );
- if ( fd == -1 ) {
+ if ( fd == -1 )
return -1;
- }
fcntl( fd, F_SETFD, FD_CLOEXEC );
if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
- (char *)( &flag ), sizeof(flag)) == 0) {
+ (char *)( &flag ), sizeof(flag)) == 0)
+ {
ret = bind( fd, pServerAddr, addr_len );
- if ( !ret ) {
+ if ( !ret )
+ {
ret = listen( fd, backlog );
- if ( !ret ) {
+ if ( !ret )
return fd;
- }
}
}
@@ -1438,17 +2253,16 @@ int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
int doAddrInfo = 0;
int port;
- if ( !pBind ) {
+ if ( !pBind )
return -1;
- }
- while( isspace( *pBind ) ) {
+ while( isspace( *pBind ) )
++pBind;
- }
strncpy( achAddr, pBind, 256 );
- switch( *p ) {
+ switch( *p )
+ {
case '/':
pAddr->sa_family = AF_UNIX;
strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p,
@@ -1463,7 +2277,8 @@ int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
return -1;
*pEnd++ = 0;
- if ( *p == '*' ) {
+ if ( *p == '*' )
+ {
strcpy( achAddr, "::" );
p = achAddr;
}
@@ -1473,35 +2288,35 @@ int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
default:
pAddr->sa_family = AF_INET;
pEnd = strchr( p, ':' );
- if ( !pEnd ) {
+ if ( !pEnd )
return -1;
- }
*pEnd++ = 0;
doAddrInfo = 0;
- if ( *p == '*' ) {
+ if ( *p == '*' )
+ {
((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY);
- } else {
- if (!strcasecmp( p, "localhost" ) ) {
- ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK );
- } else {
- ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p );
- if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST) {
- doAddrInfo = 1;
- }
+ }
+ else if (!strcasecmp( p, "localhost" ) )
+ ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK );
+ else
+ {
+ ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p );
+ if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST)
+ {
+ doAddrInfo = 1;
}
}
break;
}
- if ( *pEnd == ':' ) {
+ if ( *pEnd == ':' )
++pEnd;
- }
port = atoi( pEnd );
- if (( port <= 0 )||( port > 65535 )) {
+ if (( port <= 0 )||( port > 65535 ))
return -1;
- }
- if ( doAddrInfo ) {
+ if ( doAddrInfo )
+ {
memset(&hints, 0, sizeof(hints));
@@ -1509,7 +2324,8 @@ int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
- if ( getaddrinfo(p, NULL, &hints, &res) ) {
+ if ( getaddrinfo(p, NULL, &hints, &res) )
+ {
return -1;
}
@@ -1517,11 +2333,10 @@ int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
freeaddrinfo(res);
}
- if ( pAddr->sa_family == AF_INET ) {
+ if ( pAddr->sa_family == AF_INET )
((struct sockaddr_in *)pAddr)->sin_port = htons( port );
- } else {
+ else
((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port );
- }
return 0;
}
@@ -1532,7 +2347,8 @@ int LSAPI_CreateListenSock( const char * pBind, int backlog )
int ret;
int fd = -1;
ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr );
- if ( !ret ) {
+ if ( !ret )
+ {
fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog );
}
return fd;
@@ -1543,9 +2359,11 @@ static fn_select_t g_fnSelect = select;
typedef struct _lsapi_child_status
{
int m_pid;
+ long m_tmStart;
volatile short m_iKillSent;
volatile short m_inProcess;
+ volatile int m_iReqCounter;
volatile long m_tmWaitBegin;
volatile long m_tmReqBegin;
@@ -1575,43 +2393,42 @@ static lsapi_prefork_server * g_prefork_server = NULL;
int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
{
- if ( g_prefork_server ) {
+ int pid;
+ if ( g_prefork_server )
return 0;
- }
- if ( max_children <= 1 ) {
+ if ( max_children <= 1 )
return -1;
- }
- if ( max_children >= 10000) {
+ if ( max_children >= 10000)
max_children = 10000;
- }
g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) );
- if ( !g_prefork_server ) {
+ if ( !g_prefork_server )
return -1;
- }
memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) );
- if ( fp != NULL ) {
+ if ( fp != NULL )
g_fnSelect = fp;
- }
s_ppid = getppid();
+ pid = getpid();
+ setpgid( pid, pid );
g_prefork_server->m_iAvoidFork = avoidFork;
g_prefork_server->m_iMaxChildren = max_children;
g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ;
g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3);
+ if ( g_prefork_server->m_iMaxIdleChildren == 0 )
+ g_prefork_server->m_iMaxIdleChildren = 1;
g_prefork_server->m_iChildrenMaxIdleTime = 300;
- g_prefork_server->m_iMaxReqProcessTime = 300;
+ g_prefork_server->m_iMaxReqProcessTime = 3600;
return 0;
}
void LSAPI_Set_Server_fd( int fd )
{
- if( g_prefork_server ) {
+ if( g_prefork_server )
g_prefork_server->m_fd = fd;
- }
}
@@ -1624,11 +2441,17 @@ static int lsapi_accept( int fdListen )
len = sizeof( achPeer );
fd = accept( fdListen, (struct sockaddr *)&achPeer, &len );
- if ( fd != -1 ) {
- if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) {
+ if ( fd != -1 )
+ {
+ if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
+ {
setsockopt( fd, IPPROTO_TCP, TCP_NODELAY,
(char *)&nodelay, sizeof(nodelay));
}
+
+ //OPTIMIZATION
+ //if ( s_accept_notify )
+ // notify_req_received( fd );
}
return fd;
@@ -1652,10 +2475,10 @@ static lsapi_child_status * find_child_status( int pid )
{
lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2;
- while( pStatus < pEnd ) {
- if ( pStatus->m_pid == pid ) {
+ while( pStatus < pEnd )
+ {
+ if ( pStatus->m_pid == pid )
return pStatus;
- }
++pStatus;
}
return NULL;
@@ -1667,16 +2490,30 @@ static void lsapi_sigchild( int signal )
{
int status, pid;
lsapi_child_status * child_status;
- while( 1 ) {
+ while( 1 )
+ {
pid = waitpid( -1, &status, WNOHANG|WUNTRACED );
- if ( pid <= 0 ) {
+ if ( pid <= 0 )
+ {
break;
}
+ if ( WIFSIGNALED( status ))
+ {
+ int sig_num = WTERMSIG( status );
+ int dump = WCOREDUMP( status );
+ fprintf( stderr, "Child process with pid: %d was killed by signal: %d, core dump: %d\n", pid, sig_num, dump );
+ }
+ if ( pid == s_pid_dump_debug_info )
+ {
+ pid = 0;
+ continue;
+ }
child_status = find_child_status( pid );
- if ( child_status ) {
+ if ( child_status )
+ {
child_status->m_pid = 0;
+ --g_prefork_server->m_iCurChildren;
}
- --g_prefork_server->m_iCurChildren;
}
}
@@ -1690,76 +2527,108 @@ static int lsapi_init_children_status()
size = (size + 4095 ) / 4096 * 4096;
pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0 );
- if ( pBuf == MAP_FAILED ) {
+ if ( pBuf == MAP_FAILED )
+ {
perror( "Anonymous mmap() failed" );
return -1;
}
memset( pBuf, 0, size );
- g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf;
+ g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf;
return 0;
}
+static void dump_debug_info( lsapi_child_status * pStatus, long tmCur )
+{
+ char achCmd[1024];
+ if ( s_pid_dump_debug_info )
+ {
+ if ( kill( s_pid_dump_debug_info, 0 ) == 0 )
+ return;
+ }
+ s_pid_dump_debug_info = fork();
+
+ fprintf( stderr, "[%s] Possible runaway process, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld\n",
+ ctime(&tmCur), getpid(), pStatus->m_pid, pStatus->m_iReqCounter,
+ tmCur - pStatus->m_tmReqBegin, tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart );
+ snprintf( achCmd, 1024, "gdb --batch -ex \"attach %d\" -ex \"set height 0\" -ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2", pStatus->m_pid, pStatus->m_pid );
+ if ( system( achCmd ) == -1 )
+ perror( "system()" );
+ exit( 0 );
+}
+
static void lsapi_check_child_status( long tmCur )
{
int idle = 0;
int tobekilled;
int dying = 0;
+ int count = 0;
lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2;
- while( pStatus < pEnd ) {
- tobekilled = pStatus->m_iKillSent;
- if ( pStatus->m_pid != 0 ) {
- if ( !tobekilled ) {
- if ( !pStatus->m_inProcess ) {
-
- if (( g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren)||
- ( idle >= g_prefork_server->m_iMaxIdleChildren )) {
-
- tobekilled = 1;
- } else {
- if (( s_max_idle_secs> 0)&&(tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5 )) {
- tobekilled = 1;
- }
- }
- if ( !tobekilled ) {
- ++idle;
- }
- } else {
- if ( tmCur - pStatus->m_tmReqBegin >
- g_prefork_server->m_iMaxReqProcessTime ) {
- tobekilled = 1;
- }
+ while( pStatus < pEnd )
+ {
+ tobekilled = 0;
+ if ( pStatus->m_pid != 0 )
+ {
+ ++count;
+ if ( !pStatus->m_inProcess )
+ {
+
+ if (( g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren)||
+ ( idle > g_prefork_server->m_iMaxIdleChildren ))
+ {
+ tobekilled = SIGUSR1;
}
- } else {
- if ( pStatus->m_inProcess ) {
- tobekilled = pStatus->m_iKillSent = 0;
+ else
+ {
+ if (( s_max_idle_secs> 0)&&(tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5 ))
+ {
+ tobekilled = SIGUSR1;
+ }
}
+ if ( !tobekilled )
+ ++idle;
}
- if ( tobekilled ) {
- tobekilled = 0;
- if ( pStatus->m_iKillSent > 5 ) {
- tobekilled = SIGKILL;
- } else {
- if ( pStatus->m_iKillSent == 3 ) {
+ else
+ {
+ if ( tmCur - pStatus->m_tmReqBegin >
+ g_prefork_server->m_iMaxReqProcessTime )
+ {
+ if (( ( pStatus->m_iKillSent % 5 ) == 0 )&&( s_dump_debug_info ))
+ dump_debug_info( pStatus, tmCur );
+ if ( pStatus->m_iKillSent > 5 )
+ {
+ tobekilled = SIGKILL;
+ fprintf( stderr, "Force killing runaway process PID: %d with SIGKILL\n", pStatus->m_pid );
+ }
+ else
+ {
tobekilled = SIGTERM;
- } else {
- if ( pStatus->m_iKillSent == 1 ) {
- tobekilled = SIGUSR1;
- }
+ fprintf( stderr, "Killing runaway process PID: %d with SIGTERM\n", pStatus->m_pid );
}
}
- if ( tobekilled ) {
- kill( pStatus->m_pid, tobekilled );
+ }
+ if ( tobekilled )
+ {
+ if (( kill( pStatus->m_pid, tobekilled ) == -1 )&&( errno == ESRCH ))
+ {
+ pStatus->m_pid = 0;
+ --count;
+ }
+ else
+ {
+ ++pStatus->m_iKillSent;
+ ++dying;
}
- ++pStatus->m_iKillSent;
- ++dying;
}
-
- } else {
- ++dying;
}
++pStatus;
}
+ if ( abs( g_prefork_server->m_iCurChildren - count ) > 1 )
+ {
+ fprintf( stderr, "Children tracking is wrong: PID: %d, Cur Childen: %d, count: %d, idle: %d, dying: %d\n", getpid(),
+ g_prefork_server->m_iCurChildren, count, idle, dying );
+
+ }
}
static int lsapi_all_children_must_die()
@@ -1770,14 +2639,14 @@ static int lsapi_all_children_must_die()
g_prefork_server->m_iMaxIdleChildren = -1;
maxWait = 15;
- while( g_prefork_server->m_iCurChildren && (sec < maxWait) ) {
+ while( g_prefork_server->m_iCurChildren && (sec < maxWait) )
+ {
lsapi_check_child_status(time(NULL));
sleep( 1 );
sec++;
}
- if ( g_prefork_server->m_iCurChildren != 0 ) {
+ if ( g_prefork_server->m_iCurChildren != 0 )
kill( -getpgrp(), SIGKILL );
- }
return 0;
}
@@ -1796,13 +2665,17 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Re
fd_set readfds;
struct timeval timeout;
+ sigset_t mask;
+ sigset_t orig_mask;
+
lsapi_init_children_status();
setsid();
act.sa_flags = 0;
act.sa_handler = lsapi_sigchild;
- if( sigaction( SIGCHLD, &act, &old_child ) ) {
+ if( sigaction( SIGCHLD, &act, &old_child ) )
+ {
perror( "Can't set signal handler for SIGCHILD" );
return -1;
}
@@ -1813,36 +2686,36 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Re
if( sigaction( SIGTERM, &act, &old_term ) ||
sigaction( SIGINT, &act, &old_int ) ||
sigaction( SIGUSR1, &act, &old_usr1 ) ||
- sigaction( SIGQUIT, &act, &old_quit )) {
+ sigaction( SIGQUIT, &act, &old_quit ))
+ {
perror( "Can't set signals" );
return -1;
}
s_stop = 0;
- while( !s_stop ) {
- if ( ret ) {
- curTime = time( NULL );
- } else {
- ++curTime;
- }
- if (curTime != lastTime ) {
+ while( !s_stop )
+ {
+ curTime = time( NULL );
+ if (curTime != lastTime )
+ {
lastTime = curTime;
- if (s_ppid && (getppid() != s_ppid )) {
+ if (s_ppid && (getppid() != s_ppid ))
break;
- }
lsapi_check_child_status(curTime );
- if (pServer->m_iServerMaxIdle) {
- if ( pServer->m_iCurChildren <= 0 ) {
+ if (pServer->m_iServerMaxIdle)
+ {
+ if ( pServer->m_iCurChildren <= 0 )
+ {
++wait_secs;
- if ( wait_secs > pServer->m_iServerMaxIdle ) {
+ if ( wait_secs > pServer->m_iServerMaxIdle )
return -1;
- }
- } else {
- wait_secs = 0;
}
+ else
+ wait_secs = 0;
}
}
- if ( pServer->m_iCurChildren >= (pServer->m_iMaxChildren + pServer->m_iExtraChildren ) ) {
+ if ( pServer->m_iCurChildren >= (pServer->m_iMaxChildren + pServer->m_iExtraChildren ) )
+ {
usleep( 100000 );
continue;
}
@@ -1850,66 +2723,100 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Re
FD_ZERO( &readfds );
FD_SET( pServer->m_fd, &readfds );
timeout.tv_sec = 1; timeout.tv_usec = 0;
- if ((ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout)) == 1 ) {
- if ( pServer->m_iCurChildren >= 0 ) {
+ if ((ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout)) == 1 )
+ {
+ /*
+ if ( pServer->m_iCurChildren >= 0 )
+ {
usleep( 10 );
FD_ZERO( &readfds );
FD_SET( pServer->m_fd, &readfds );
timeout.tv_sec = 0; timeout.tv_usec = 0;
- if ( (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout) == 0 ) {
- continue;
- }
- }
- } else {
- if ( ret == -1 ) {
- if ( errno == EINTR ) {
+ if ( (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout) == 0 )
continue;
- }
- /* perror( "select()" ); */
- break;
- } else {
+ }*/
+ }
+ else if ( ret == -1 )
+ {
+ if ( errno == EINTR )
continue;
- }
+ /* perror( "select()" ); */
+ break;
+ }
+ else
+ {
+ continue;
}
pReq->m_fd = lsapi_accept( pServer->m_fd );
- if ( pReq->m_fd != -1 ) {
+ if ( pReq->m_fd != -1 )
+ {
child_status = find_child_status( 0 );
+ if ( child_status )
+ memset( child_status, 0, sizeof( *child_status ) );
+
+ sigemptyset( &mask );
+ sigaddset( &mask, SIGCHLD );
+
+ if ( sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0 )
+ {
+ perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" );
+ }
+
pid = fork();
- if ( !pid ) {
+
+ if ( !pid )
+ {
+ if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0)
+ perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" );
g_prefork_server = NULL;
s_ppid = getppid();
s_req_processed = 0;
s_pChildStatus = child_status;
- child_status->m_iKillSent = 0;
lsapi_set_nblock( pReq->m_fd, 0 );
-
+ if ( pReq->m_fdListen != -1 )
+ {
+ close( pReq->m_fdListen );
+ pReq->m_fdListen = -1;
+ }
/* don't catch our signals */
sigaction( SIGCHLD, &old_child, 0 );
sigaction( SIGTERM, &old_term, 0 );
sigaction( SIGQUIT, &old_quit, 0 );
sigaction( SIGINT, &old_int, 0 );
sigaction( SIGUSR1, &old_usr1, 0 );
+ //init_conn_key( pReq->m_fd );
+ lsapi_notify_pid( pReq->m_fd );
+ s_notified_pid = 1;
+ //if ( s_accept_notify )
+ // return notify_req_received( pReq->m_fd );
return 0;
- } else {
- if ( pid == -1 ) {
- perror( "fork() failed, please increase process limit" );
- } else {
- ++pServer->m_iCurChildren;
- if ( child_status ) {
- child_status->m_pid = pid;
- child_status->m_iKillSent = 0;
- child_status->m_tmWaitBegin = time(NULL);
- }
+ }
+ else if ( pid == -1 )
+ {
+ perror( "fork() failed, please increase process limit" );
+ }
+ else
+ {
+ ++pServer->m_iCurChildren;
+ if ( child_status )
+ {
+ child_status->m_pid = pid;
+ child_status->m_tmWaitBegin = curTime;
+ child_status->m_tmStart = curTime;
}
}
close( pReq->m_fd );
pReq->m_fd = -1;
- } else {
- if (( errno == EINTR )||( errno == EAGAIN)) {
+ if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0)
+ perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK" );
+
+ }
+ else
+ {
+ if (( errno == EINTR )||( errno == EAGAIN))
continue;
- }
perror( "accept() failed" );
return -1;
}
@@ -1921,6 +2828,11 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Re
}
+void lsapi_error( const char * pMessage, int err_no )
+{
+ fprintf( stderr, "%d: %s, errno: %d (%s)\n", getpid(), pMessage, err_no, strerror( err_no ) );
+}
+
int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
{
int fd;
@@ -1932,88 +2844,105 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
LSAPI_Finish_r( pReq );
- if ( g_prefork_server ) {
- if ( g_prefork_server->m_fd != -1 ) {
- if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 ) {
+ if ( g_prefork_server )
+ {
+ if ( g_prefork_server->m_fd != -1 )
+ if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 )
return -1;
- }
- }
}
- if ( s_req_processed >= s_max_reqs ) {
+ if ( s_req_processed >= s_max_reqs )
return -1;
- }
- if ( s_pChildStatus ) {
+ if ( s_pChildStatus )
+ {
s_pChildStatus->m_tmWaitBegin = time( NULL );
}
+
- while( g_running ) {
- if ( pReq->m_fd != -1 ) {
+ while( g_running )
+ {
+ if ( pReq->m_fd != -1 )
+ {
fd = pReq->m_fd;
- } else {
- if ( pReq->m_fdListen != -1 ) {
- fd = pReq->m_fdListen;
- } else {
- return -1;
- }
+ }
+ else if ( pReq->m_fdListen != -1 )
+ fd = pReq->m_fdListen;
+ else
+ {
+ break;
}
wait_secs = 0;
- while( 1 ) {
- if ( !g_running ) {
+ while( 1 )
+ {
+ if ( !g_running )
return -1;
- }
- if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent )) {
+ if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
return -1;
- }
FD_ZERO( &readfds );
FD_SET( fd, &readfds );
timeout.tv_sec = 1;
timeout.tv_usec = 0;
ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout);
- if ( ret == 0 ) {
- if ( s_pChildStatus ) {
+ if ( ret == 0 )
+ {
+ if ( s_pChildStatus )
+ {
s_pChildStatus->m_inProcess = 0;
}
++wait_secs;
- if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs )) {
+ if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
return -1;
- }
- if ( s_ppid &&( getppid() != s_ppid)) {
+ if ( s_ppid &&( getppid() != s_ppid))
return -1;
- }
- } else {
- if ( ret == -1 ) {
- if ( errno == EINTR ) {
- continue;
- } else {
- return -1;
- }
- } else {
- if ( ret >= 1 ) {
- if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent )) {
- return -1;
+ }
+ else if ( ret == -1 )
+ {
+ if ( errno == EINTR )
+ continue;
+ else
+ return -1;
+ }
+ else if ( ret >= 1 )
+ {
+ if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
+ return -1;
+ if ( fd == pReq->m_fdListen )
+ {
+ pReq->m_fd = lsapi_accept( pReq->m_fdListen );
+ if ( pReq->m_fd != -1 )
+ {
+ fd = pReq->m_fd;
+ lsapi_set_nblock( fd, 0 );
+ //init_conn_key( pReq->m_fd );
+ if ( !s_keepListener )
+ {
+ close( pReq->m_fdListen );
+ pReq->m_fdListen = -1;
}
- if ( fd == pReq->m_fdListen ) {
- pReq->m_fd = lsapi_accept( pReq->m_fdListen );
- if ( pReq->m_fd != -1 ) {
- fd = pReq->m_fd;
- lsapi_set_nblock( fd, 0 );
- } else {
- if (( errno == EINTR )||( errno == EAGAIN)) {
- continue;
- }
+ if ( s_accept_notify )
+ if ( notify_req_received( pReq->m_fd ) == -1 )
return -1;
- }
- } else {
- break;
- }
+ }
+ else
+ {
+ if (( errno == EINTR )||( errno == EAGAIN))
+ continue;
+ lsapi_error( "lsapi_accept() error", errno );
+ return -1;
}
}
+ else
+ break;
}
}
- if ( !readReq( pReq ) ) {
- if ( s_pChildStatus ) {
+
+ if ( !readReq( pReq ) )
+ {
+ if ( s_pChildStatus )
+ {
+ s_pChildStatus->m_iKillSent = 0;
s_pChildStatus->m_inProcess = 1;
+ ++s_pChildStatus->m_iReqCounter;
s_pChildStatus->m_tmReqBegin = s_pChildStatus->m_tmLastCheckPoint = time(NULL);
}
++s_req_processed;
@@ -2028,49 +2957,50 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
}
void LSAPI_Set_Max_Reqs( int reqs )
-{
- s_max_reqs = reqs;
-}
+{ s_max_reqs = reqs; }
void LSAPI_Set_Max_Idle( int secs )
-{
- s_max_idle_secs = secs;
-}
+{ s_max_idle_secs = secs; }
void LSAPI_Set_Max_Children( int maxChildren )
{
- if ( g_prefork_server ) {
+ if ( g_prefork_server )
g_prefork_server->m_iMaxChildren = maxChildren;
- }
}
void LSAPI_Set_Extra_Children( int extraChildren )
{
- if (( g_prefork_server )&&( extraChildren >= 0 )) {
+ if (( g_prefork_server )&&( extraChildren >= 0 ))
g_prefork_server->m_iExtraChildren = extraChildren;
- }
}
void LSAPI_Set_Max_Process_Time( int secs )
{
- if (( g_prefork_server )&&( secs > 0 )) {
+ if (( g_prefork_server )&&( secs > 0 ))
g_prefork_server->m_iMaxReqProcessTime = secs;
- }
}
void LSAPI_Set_Max_Idle_Children( int maxIdleChld )
{
- if (( g_prefork_server )&&( maxIdleChld > 0 )) {
+ if (( g_prefork_server )&&( maxIdleChld > 0 ))
g_prefork_server->m_iMaxIdleChildren = maxIdleChld;
- }
}
void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle )
{
- if ( g_prefork_server ) {
+ if ( g_prefork_server )
g_prefork_server->m_iServerMaxIdle = serverMaxIdle;
- }
+}
+
+void LSAPI_Set_Slow_Req_Msecs( int msecs )
+{
+ s_slow_req_msecs = msecs;
+}
+
+int LSAPI_Get_Slow_Req_Msecs()
+{
+ return s_slow_req_msecs;
}
@@ -2092,101 +3022,419 @@ static void unset_lsapi_envs()
#else
env = environ;
#endif
- while( env != NULL && *env != NULL ) {
- if ( !strncmp(*env, "LSAPI_", 6) ||
- !strncmp( *env, "PHP_LSAPI_", 10 ) ) {
+ while( env != NULL && *env != NULL )
+ {
+ if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 )
+ || (!strncmp( *env, "PHPRC=", 6 )&&(!s_uid)))
+ {
char ** del = env;
- do {
+ do
*del = del[1];
- } while( *del++ );
- } else {
- ++env;
+ while( *del++ );
}
+ else
+ ++env;
}
}
-void LSAPI_Init_Env_Parameters( fn_select_t fp )
+static int lsapi_initSuEXEC()
+{
+ int i;
+ struct passwd * pw;
+ s_defaultUid = 0;
+ s_defaultGid = 0;
+ if ( s_uid == 0 )
+ {
+ const char * p = getenv( "LSAPI_DEFAULT_UID" );
+ if ( p )
+ {
+ i = atoi( p );
+ if ( i > 0 )
+ s_defaultUid = i;
+ }
+ p = getenv( "LSAPI_DEFAULT_GID" );
+ if ( p )
+ {
+ i = atoi( p );
+ if ( i > 0 )
+ s_defaultGid = i;
+ }
+ p = getenv( "LSAPI_SECRET" );
+ if (( !p )||( readSecret(p) == -1 ))
+ return -1;
+ if ( g_prefork_server )
+ {
+ if ( g_prefork_server->m_iMaxChildren < 100 )
+ g_prefork_server->m_iMaxChildren = 100;
+ }
+ }
+ if ( !s_defaultUid || !s_defaultGid )
+ {
+ pw = getpwnam( "nobody" );
+ if ( !s_defaultUid )
+ s_defaultUid = pw->pw_uid;
+ if ( !s_defaultGid )
+ s_defaultGid = pw->pw_gid;
+ }
+ return 0;
+}
+
+
+int LSAPI_Init_Env_Parameters( fn_select_t fp )
{
const char *p;
int n;
int avoidFork = 0;
p = getenv( "PHP_LSAPI_MAX_REQUESTS" );
- if ( !p ) {
+ if ( !p )
p = getenv( "LSAPI_MAX_REQS" );
- }
- if ( p ) {
+ if ( p )
+ {
n = atoi( p );
- if ( n > 0 ) {
+ if ( n > 0 )
LSAPI_Set_Max_Reqs( n );
- }
}
p = getenv( "LSAPI_AVOID_FORK" );
- if ( p ) {
+ if ( p )
+ {
avoidFork = atoi( p );
}
+ p = getenv( "LSAPI_ACCEPT_NOTIFY" );
+ if ( p )
+ {
+ s_accept_notify = atoi( p );
+ }
+
+ p = getenv( "LSAPI_SLOW_REQ_MSECS" );
+ if ( p )
+ {
+ n = atoi( p );
+ LSAPI_Set_Slow_Req_Msecs( n );
+ }
+
#if defined( RLIMIT_CORE )
p = getenv( "LSAPI_ALLOW_CORE_DUMP" );
- if ( !p ) {
+ if ( !p )
+ {
struct rlimit limit = { 0, 0 };
setrlimit( RLIMIT_CORE, &limit );
}
-#endif
+ else
+ s_enable_core_dump = 1;
+
+#endif
p = getenv( "LSAPI_MAX_IDLE" );
- if ( p ) {
+ if ( p )
+ {
n = atoi( p );
LSAPI_Set_Max_Idle( n );
}
- if ( LSAPI_Is_Listen() ) {
+ p = getenv( "LSAPI_KEEP_LISTEN" );
+ if ( p )
+ {
+ n = atoi( p );
+ s_keepListener = n;
+ }
+
+
+ if ( LSAPI_Is_Listen() )
+ {
n = 0;
p = getenv( "PHP_LSAPI_CHILDREN" );
- if ( !p ) {
+ if ( !p )
p = getenv( "LSAPI_CHILDREN" );
- }
- if ( p ) {
+ if ( p )
n = atoi( p );
- }
- if ( n > 1 ) {
+ if ( n > 1 )
+ {
LSAPI_Init_Prefork_Server( n, fp, avoidFork );
LSAPI_Set_Server_fd( g_req.m_fdListen );
}
p = getenv( "LSAPI_EXTRA_CHILDREN" );
- if ( p ) {
+ if ( p )
LSAPI_Set_Extra_Children( atoi( p ) );
- }
p = getenv( "LSAPI_MAX_IDLE_CHILDREN" );
- if ( p ) {
+ if ( p )
LSAPI_Set_Max_Idle_Children( atoi( p ) );
- }
+
p = getenv( "LSAPI_PGRP_MAX_IDLE" );
- if ( p ) {
+ if ( p )
+ {
LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) );
}
p = getenv( "LSAPI_MAX_PROCESS_TIME" );
- if ( p ) {
+ if ( p )
LSAPI_Set_Max_Process_Time( atoi( p ) );
- }
- if ( getenv( "LSAPI_PPID_NO_CHECK" ) ) {
+
+ if ( getenv( "LSAPI_PPID_NO_CHECK" ) )
+ {
LSAPI_No_Check_ppid();
}
+
+ p = getenv( "LSAPI_DUMP_DEBUG_INFO" );
+ if ( p )
+ s_dump_debug_info = atoi( p );
+
+ if ( lsapi_initSuEXEC() == -1 )
+ return -1;
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
+ lsapi_initLVE();
+#endif
}
unset_lsapi_envs();
+ return 0;
}
+int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders,
+ const char * pBody, int bodyLen )
+{
+ LSAPI_SetRespStatus_r( pReq, code );
+ if ( pRespHeaders )
+ {
+ while( *pRespHeaders )
+ {
+ LSAPI_AppendRespHeader_r( pReq, *pRespHeaders, strlen( *pRespHeaders ) );
+ ++pRespHeaders;
+ }
+ }
+ if ( pBody &&( bodyLen > 0 ))
+ {
+ LSAPI_Write_r( pReq, pBody, bodyLen );
+ }
+ LSAPI_Finish_r( pReq );
+ return 0;
+}
+
+
+static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void lsapi_MD5Init(struct lsapi_MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void lsapi_MD5Update(struct lsapi_MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ register uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memmove(p, buf, len);
+ return;
+ }
+ memmove(p, buf, t);
+ byteReverse(ctx->in, 16);
+ lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memmove(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memmove(ctx->in, buf, len);
+}
+
/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
*/
+void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *ctx)
+{
+ unsigned int count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memmove(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
diff --git a/sapi/litespeed/lsapilib.h b/sapi/litespeed/lsapilib.h
index 538a170b4..b0638fd43 100644
--- a/sapi/litespeed/lsapilib.h
+++ b/sapi/litespeed/lsapilib.h
@@ -1,24 +1,5 @@
-
-/*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: George Wang <gwang@litespeedtech.com> |
- +----------------------------------------------------------------------+
-*/
-
/*
-Copyright (c) 2007, Lite Speed Technologies Inc.
+Copyright (c) 2013, Lite Speed Technologies Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -49,6 +30,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/***************************************************************************
+ lsapilib.h - description
+ -------------------
+ begin : Mon Feb 21 2005
+ copyright : (C) 2005 by George Wang
+ email : gwang@litespeedtech.com
+ ***************************************************************************/
#ifndef _LSAPILIB_H_
@@ -118,7 +106,8 @@ typedef struct lsapi_request
char * m_pRequestMethod;
int m_totalLen;
int m_reqState;
- int m_reqBodyRead;
+ off_t m_reqBodyLen;
+ off_t m_reqBodyRead;
int m_bufProcessed;
int m_bufRead;
@@ -126,6 +115,7 @@ typedef struct lsapi_request
struct lsapi_resp_header m_respHeader;
short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS];
+ void * m_pAppData;
}LSAPI_Request;
@@ -170,22 +160,30 @@ int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name );
-int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int len );
+ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t len );
int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq );
-int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, int bufLen, int *getLF );
+int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF );
int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq );
-int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len );
+ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len );
-int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len );
+ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size );
+
+ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len );
int LSAPI_Flush_r( LSAPI_Request * pReq );
-int LSAPI_AppendRespHeader_r( LSAPI_Request * pHeader, char * pBuf, int len );
+int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len );
+
+int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
+ const char * pHeaderValue );
+
+int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders,
+ const char * pBody, int bodyLen );
static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code )
{
@@ -195,6 +193,21 @@ static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code )
return 0;
}
+static inline int LSAPI_SetAppData_r( LSAPI_Request * pReq, void * data )
+{
+ if ( !pReq )
+ return -1;
+ pReq->m_pAppData = data;
+ return 0;
+}
+
+static inline void * LSAPI_GetAppData_r( LSAPI_Request * pReq )
+{
+ if ( !pReq )
+ return NULL;
+ return pReq->m_pAppData;
+}
+
static inline char * LSAPI_GetQueryString_r( LSAPI_Request * pReq )
{
if ( pReq )
@@ -228,21 +241,22 @@ static inline char * LSAPI_GetRequestMethod_r( LSAPI_Request * pReq)
-static inline int LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq )
+static inline off_t LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq )
{
if ( pReq )
- return pReq->m_pHeader->m_reqBodyLen;
+ return pReq->m_reqBodyLen;
return -1;
}
-static inline int LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq )
+static inline off_t LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq )
{
if ( pReq )
- return pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
+ return pReq->m_reqBodyLen - pReq->m_reqBodyRead;
return -1;
}
+
int LSAPI_Is_Listen(void);
static inline int LSAPI_Accept( void )
@@ -282,13 +296,13 @@ static inline char * LSAPI_GetScriptName()
static inline char * LSAPI_GetRequestMethod()
{ return LSAPI_GetRequestMethod_r( &g_req ); }
-static inline int LSAPI_GetReqBodyLen()
+static inline off_t LSAPI_GetReqBodyLen()
{ return LSAPI_GetReqBodyLen_r( &g_req ); }
-static inline int LSAPI_GetReqBodyRemain()
+static inline off_t LSAPI_GetReqBodyRemain()
{ return LSAPI_GetReqBodyRemain_r( &g_req ); }
-static inline int LSAPI_ReadReqBody( char * pBuf, int len )
+static inline ssize_t LSAPI_ReadReqBody( char * pBuf, size_t len )
{ return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); }
static inline int LSAPI_ReqBodyGetChar()
@@ -302,10 +316,15 @@ static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF )
static inline int LSAPI_FinalizeRespHeaders(void)
{ return LSAPI_FinalizeRespHeaders_r( &g_req ); }
-static inline int LSAPI_Write( const char * pBuf, int len )
+static inline ssize_t LSAPI_Write( const char * pBuf, ssize_t len )
{ return LSAPI_Write_r( &g_req, pBuf, len ); }
-static inline int LSAPI_Write_Stderr( const char * pBuf, int len )
+static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size )
+{
+ return LSAPI_sendfile_r(&g_req, fdIn, off, size );
+}
+
+static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len )
{ return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); }
static inline int LSAPI_Flush()
@@ -317,6 +336,9 @@ static inline int LSAPI_AppendRespHeader( char * pBuf, int len )
static inline int LSAPI_SetRespStatus( int code )
{ return LSAPI_SetRespStatus_r( &g_req, code ); }
+static inline int LSAPI_ErrResponse( int code, const char ** pRespHeaders, const char * pBody, int bodyLen )
+{ return LSAPI_ErrResponse_r( &g_req, code, pRespHeaders, pBody, bodyLen ); }
+
int LSAPI_IsRunning(void);
int LSAPI_CreateListenSock( const char * pBind, int backlog );
@@ -341,7 +363,13 @@ void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle );
void LSAPI_Set_Max_Process_Time( int secs );
-void LSAPI_Init_Env_Parameters( fn_select_t fp );
+int LSAPI_Init_Env_Parameters( fn_select_t fp );
+
+void LSAPI_Set_Slow_Req_Msecs( int msecs );
+
+int LSAPI_Get_Slow_Req_Msecs( );
+
+int LSAPI_is_suEXEC_Daemon();
#if defined (c_plusplus) || defined (__cplusplus)
}
diff --git a/sapi/milter/php_milter.c b/sapi/milter/php_milter.c
index 6856c07bb..432fd806c 100644
--- a/sapi/milter/php_milter.c
+++ b/sapi/milter/php_milter.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -1109,7 +1109,7 @@ int main(int argc, char *argv[])
}
SG(headers_sent) = 1;
SG(request_info).no_headers = 1;
- php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+ php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2014 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
php_output_teardown();
exit(1);
break;
diff --git a/sapi/nsapi/nsapi.c b/sapi/nsapi/nsapi.c
index 1e6a680c9..ec3137ca5 100644
--- a/sapi/nsapi/nsapi.c
+++ b/sapi/nsapi/nsapi.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/phpdbg/.gdbinit b/sapi/phpdbg/.gdbinit
new file mode 100644
index 000000000..401a4bb88
--- /dev/null
+++ b/sapi/phpdbg/.gdbinit
@@ -0,0 +1,10 @@
+define ____phpdbg_globals
+ if basic_functions_module.zts
+ if !$tsrm_ls
+ set $tsrm_ls = ts_resource_ex(0, 0)
+ end
+ set $phpdbg = ((zend_phpdbg_globals*) (*((void ***) $tsrm_ls))[phpdbg_globals_id-1])
+ else
+ set $phpdbg = phpdbg_globals
+ end
+end
diff --git a/sapi/phpdbg/.gitignore b/sapi/phpdbg/.gitignore
new file mode 100644
index 000000000..297efcbc4
--- /dev/null
+++ b/sapi/phpdbg/.gitignore
@@ -0,0 +1,5 @@
+.libs/
+./phpdbg
+*.lo
+*.o
+build
diff --git a/sapi/phpdbg/.phpdbginit b/sapi/phpdbg/.phpdbginit
new file mode 100644
index 000000000..1ad35218e
--- /dev/null
+++ b/sapi/phpdbg/.phpdbginit
@@ -0,0 +1,105 @@
+##########################################################
+# .phpdbginit
+#
+# Lines starting with # are ignored
+# Code must start and end with <: and :> respectively
+##########################################################
+# Place initialization commands one per line
+##########################################################
+# exec sapi/phpdbg/test.php
+# set color prompt white-bold
+# set color notice green
+# set color error red
+
+##########################################################
+# Embedding code in .phpdbginit
+##########################################################
+<:
+/*
+* This embedded PHP is executed at init time
+*/
+
+/*
+* Functions defined and registered by init
+* will persist across cleans
+*/
+
+/*
+function my_debugging_function()
+{
+ var_dump(func_get_args());
+}
+*/
+
+/* phpdbg_break(PHPDBG_METHOD, "phpdbg::method"); */
+/* phpdbg_break(PHPDBG_FUNC, "my_global_function"); */
+/* phpdbg_break(PHPDBG_FILE, "/path/to/file.php:10"); */
+
+/*
+ If readline is loaded, you might want to setup completion:
+*/
+if (function_exists('readline_completion_function')) {
+ readline_completion_function(function(){
+ return array_merge(
+ get_defined_functions()['user'],
+ array_keys(get_defined_constants())
+ );
+ });
+}
+
+/*
+ Setting argv made trivial ...
+
+ argv 1 2 3 4
+ ^ set argv for next execution
+
+ argv
+ ^ unset argv for next execution
+
+*/
+function argv()
+{
+ $argv = func_get_args();
+
+ if (!$argv) {
+ $_SERVER['argv'] = array();
+ $_SERVER['argc'] = 0;
+ return;
+ }
+
+ $_SERVER['argv'] = array_merge
+ (
+ array("phpdbg"),
+ $argv
+ );
+ $_SERVER['argc'] = count($_SERVER['argv']);
+
+ return $_SERVER['argv'];
+}
+:>
+##########################################################
+# Now carry on initializing phpdbg ...
+##########################################################
+# R my_debugging_function
+# R argv
+
+##########################################################
+# PHP has many functions that might be useful
+# ... you choose ...
+##########################################################
+# R touch
+# R unlink
+# R scandir
+# R glob
+
+##########################################################
+# Remember: *you have access to the shell*
+##########################################################
+# The output of registered function calls is not,
+# by default, very pretty (unless you implement
+# and register a new implementation for phpdbg)
+# The output of shell commands will usually be more
+# readable on the console
+##########################################################
+# TLDR; if you have a good shell, use it ...
+##########################################################
diff --git a/sapi/phpdbg/.travis.yml b/sapi/phpdbg/.travis.yml
new file mode 100644
index 000000000..353402858
--- /dev/null
+++ b/sapi/phpdbg/.travis.yml
@@ -0,0 +1,3 @@
+language: c
+
+script: ./travis/ci.sh
diff --git a/sapi/phpdbg/CREDITS b/sapi/phpdbg/CREDITS
new file mode 100644
index 000000000..036bafe1d
--- /dev/null
+++ b/sapi/phpdbg/CREDITS
@@ -0,0 +1,2 @@
+phpdbg
+Felipe Pena, Joe Watkins, Bob Weinand
diff --git a/sapi/phpdbg/Changelog.md b/sapi/phpdbg/Changelog.md
new file mode 100644
index 000000000..c5d8b5151
--- /dev/null
+++ b/sapi/phpdbg/Changelog.md
@@ -0,0 +1,52 @@
+ChangeLog for phpdbg
+====================
+
+Version 0.3.0 2013-00-00
+------------------------
+
+1. Added ability to disable an enable a single breakpoint
+2. Added ability to override SAPI name
+3. Added extended conditional breakpoint support "break at"
+4. Fix loading of zend extnsions with -z
+5. Fix crash when loading .phpdbginit with command line switch
+6. Fix crash on startup errors
+7. Added init.d for remote console (redhat)
+8. Added phpdbg_exec userland function
+9. Added testing facilities
+10. Added break on n-th opline support
+11. Improved trace output
+
+Version 0.2.0 2013-11-31
+------------------------
+
+1. Added "break delete <id>" command
+2. Added "break opcode <opcode>" command
+3. Added "set" command - control prompt and console colors
+4. .phpdbginit now searched in (additional) ini dirs
+5. Added source command - load additional .phpdbginit script during session
+6. Added remote console mode
+7. Added info memory command
+
+Version 0.1.0 2013-11-23
+------------------------
+
+1. New commands:
+ - until (continue until the current line is executed)
+ - frame (switch to a frame in the current stack for inspection)
+ - info (quick access to useful information on the console)
+ - finish (continue until the current function has returned)
+ - leave (continue until the current function is returning)
+ - shell (shell a command)
+ - register (register a function for use as a command)
+2. Added printers for class and method
+3. Make uniform commands and aliases where possible
+4. Include all alias information and sub-command information in help
+5. Added signal handling to break execution (ctrl-c)
+6. Fixed #13 (Output Buffering Control seems fail)
+7. Fixed #14 (Fixed typo in Makefile.frag)
+
+
+Version 0.0.1 2013-11-15
+------------------------
+
+1. Initial features
diff --git a/sapi/phpdbg/Makefile.frag b/sapi/phpdbg/Makefile.frag
new file mode 100644
index 000000000..5be6d5b00
--- /dev/null
+++ b/sapi/phpdbg/Makefile.frag
@@ -0,0 +1,28 @@
+phpdbg: $(BUILD_BINARY)
+
+phpdbg-shared: $(BUILD_SHARED)
+
+$(BUILD_SHARED): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS)
+ $(BUILD_PHPDBG_SHARED)
+
+$(BUILD_BINARY): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS)
+ $(BUILD_PHPDBG)
+
+install-phpdbg: $(BUILD_BINARY)
+ @echo "Installing phpdbg binary: $(INSTALL_ROOT)$(bindir)/"
+ @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir)
+ @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log
+ @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run
+ @$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT)
+
+clean-phpdbg:
+ @echo "Cleaning phpdbg object files ..."
+ find sapi/phpdbg/ -name *.lo -o -name *.o | xargs rm -f
+
+test-phpdbg:
+ @echo "Running phpdbg tests ..."
+ @$(top_builddir)/sapi/cli/php sapi/phpdbg/tests/run-tests.php --phpdbg sapi/phpdbg/phpdbg
+
+.PHONY: clean-phpdbg test-phpdbg
+
+
diff --git a/sapi/phpdbg/README.md b/sapi/phpdbg/README.md
new file mode 100644
index 000000000..e7e5c731a
--- /dev/null
+++ b/sapi/phpdbg/README.md
@@ -0,0 +1,83 @@
+The interactive PHP debugger
+============================
+
+Implemented as a SAPI module, phpdbg can excert complete control over the environment without impacting the functionality or performance of your code.
+
+phpdbg aims to be a lightweight, powerful, easy to use debugging platform for PHP 5.4+
+
+[![phpdbg on travis-ci](https://travis-ci.org/krakjoe/phpdbg.png?branch=master)](https://travis-ci.org/krakjoe/phpdbg)
+
+Features
+========
+
+ - Stepthrough Debugging
+ - Flexible Breakpoints (Class Method, Function, File:Line, Address, Opcode)
+ - Easy Access to PHP with built-in eval()
+ - Easy Access to Currently Executing Code
+ - Userland API
+ - SAPI Agnostic - Easily Integrated
+ - PHP Configuration File Support
+ - JIT Super Globals - Set Your Own!!
+ - Optional readline Support - Comfortable Terminal Operation
+ - Remote Debugging Support - Bundled Java GUI
+ - Easy Operation - See Help :)
+
+Planned
+=======
+
+ - Improve Everything :)
+
+Installation
+============
+
+To install **phpdbg**, you must compile the source against your PHP installation sources, and enable the SAPI with the configure command.
+
+```
+cd /usr/src/php-src/sapi
+git clone https://github.com/krakjoe/phpdbg
+cd ../
+./buildconf --force
+./configure --enable-phpdbg
+make -j8
+make install-phpdbg
+```
+
+Where the source directory has been used previously to build PHP, there exists a file named *config.nice* which can be used to invoke configure with the same
+parameters as were used by the last execution of *configure*.
+
+**Note:** PHP must be configured with the switch --with-readline for phpdbg to support history, autocompletion, tab-listing etc.
+
+Command Line Options
+====================
+
+The following switches are implemented (just like cli SAPI):
+
+ - -n ignore php ini
+ - -c search for php ini in path
+ - -z load zend extension
+ - -d define php ini entry
+
+The following switches change the default behaviour of phpdbg:
+
+ - -v disables quietness
+ - -s enabled stepping
+ - -e sets execution context
+ - -b boring - disables use of colour on the console
+ - -I ignore .phpdbginit (default init file)
+ - -i override .phpgdbinit location (implies -I)
+ - -O set oplog output file
+ - -q do not print banner on startup
+ - -r jump straight to run
+ - -E enable step through eval()
+ - -l listen ports for remote mode
+ - -a listen address for remote mode
+ - -S override SAPI name
+
+**Note:** Passing -rr will cause phpdbg to quit after execution, rather than returning to the console.
+
+Getting Started
+===============
+
+See the website for tutorials/documentation
+
+http://phpdbg.com
diff --git a/sapi/phpdbg/config.m4 b/sapi/phpdbg/config.m4
new file mode 100644
index 000000000..274e6409d
--- /dev/null
+++ b/sapi/phpdbg/config.m4
@@ -0,0 +1,61 @@
+dnl
+dnl $Id$
+dnl
+
+PHP_ARG_ENABLE(phpdbg, for phpdbg support,
+[ --enable-phpdbg Build phpdbg], yes, yes)
+
+PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build,
+[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no)
+
+if test "$PHP_PHPDBG" != "no"; then
+ AC_DEFINE(HAVE_PHPDBG, 1, [ ])
+
+ if test "$PHP_PHPDBG_DEBUG" != "no"; then
+ AC_DEFINE(PHPDBG_DEBUG, 1, [ ])
+ else
+ AC_DEFINE(PHPDBG_DEBUG, 0, [ ])
+ fi
+
+ PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
+ PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c"
+
+ PHP_SUBST(PHP_PHPDBG_CFLAGS)
+ PHP_SUBST(PHP_PHPDBG_FILES)
+
+ PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/phpdbg/Makefile.frag])
+ PHP_SELECT_SAPI(phpdbg, program, $PHP_PHPDBG_FILES, $PHP_PHPDBG_CFLAGS, [$(SAPI_PHPDBG_PATH)])
+
+ BUILD_BINARY="sapi/phpdbg/phpdbg"
+ BUILD_SHARED="sapi/phpdbg/libphpdbg.la"
+
+ BUILD_PHPDBG="\$(LIBTOOL) --mode=link \
+ \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \
+ \$(PHP_GLOBAL_OBJS) \
+ \$(PHP_BINARY_OBJS) \
+ \$(PHP_PHPDBG_OBJS) \
+ \$(EXTRA_LIBS) \
+ \$(PHPDBG_EXTRA_LIBS) \
+ \$(ZEND_EXTRA_LIBS) \
+ -o \$(BUILD_BINARY)"
+
+ BUILD_PHPDBG_SHARED="\$(LIBTOOL) --mode=link \
+ \$(CC) -shared -Wl,-soname,libphpdbg.so -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \
+ \$(PHP_GLOBAL_OBJS) \
+ \$(PHP_BINARY_OBJS) \
+ \$(PHP_PHPDBG_OBJS) \
+ \$(EXTRA_LIBS) \
+ \$(PHPDBG_EXTRA_LIBS) \
+ \$(ZEND_EXTRA_LIBS) \
+ \-DPHPDBG_SHARED \
+ -o \$(BUILD_SHARED)"
+
+ PHP_SUBST(BUILD_BINARY)
+ PHP_SUBST(BUILD_SHARED)
+ PHP_SUBST(BUILD_PHPDBG)
+ PHP_SUBST(BUILD_PHPDBG_SHARED)
+fi
+
+dnl ## Local Variables:
+dnl ## tab-width: 4
+dnl ## End:
diff --git a/sapi/phpdbg/config.w32 b/sapi/phpdbg/config.w32
new file mode 100644
index 000000000..29031507b
--- /dev/null
+++ b/sapi/phpdbg/config.w32
@@ -0,0 +1,19 @@
+ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes');
+ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no');
+
+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 phpdbg_set.c phpdbg_frame.c';
+PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll';
+PHPDBG_EXE='phpdbg.exe';
+
+if (PHP_PHPDBG == "yes") {
+ /* build phpdbg binary */
+ SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE);
+ ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib");
+}
+
+if (PHP_PHPDBGS == "yes") {
+ SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32');
+ ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib");
+}
+
+
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c
new file mode 100644
index 000000000..e7f841c0b
--- /dev/null
+++ b/sapi/phpdbg/phpdbg.c
@@ -0,0 +1,1348 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_SIGNALS
+# include <signal.h>
+#endif
+#include "phpdbg.h"
+#include "phpdbg_prompt.h"
+#include "phpdbg_bp.h"
+#include "phpdbg_break.h"
+#include "phpdbg_list.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_set.h"
+
+/* {{{ remote console headers */
+#ifndef _WIN32
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <sys/time.h>
+# include <sys/types.h>
+# include <unistd.h>
+# include <arpa/inet.h>
+#endif /* }}} */
+
+ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
+
+static zend_bool phpdbg_booted = 0;
+
+#if PHP_VERSION_ID >= 50500
+void (*zend_execute_old)(zend_execute_data *execute_data TSRMLS_DC);
+#else
+void (*zend_execute_old)(zend_op_array *op_array TSRMLS_DC);
+#endif
+
+static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
+{
+ pg->prompt[0] = NULL;
+ pg->prompt[1] = NULL;
+
+ pg->colors[0] = NULL;
+ pg->colors[1] = NULL;
+ pg->colors[2] = NULL;
+
+ pg->exec = NULL;
+ pg->exec_len = 0;
+ pg->ops = NULL;
+ pg->vmret = 0;
+ pg->bp_count = 0;
+ pg->lcmd = NULL;
+ pg->flags = PHPDBG_DEFAULT_FLAGS;
+ pg->oplog = NULL;
+ pg->io[PHPDBG_STDIN] = NULL;
+ pg->io[PHPDBG_STDOUT] = NULL;
+ pg->io[PHPDBG_STDERR] = NULL;
+ memset(&pg->lparam, 0, sizeof(phpdbg_param_t));
+ pg->frame.num = 0;
+} /* }}} */
+
+static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
+{
+ ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
+#if PHP_VERSION_ID >= 50500
+ zend_execute_old = zend_execute_ex;
+ zend_execute_ex = phpdbg_execute_ex;
+#else
+ zend_execute_old = zend_execute;
+ zend_execute = phpdbg_execute_ex;
+#endif
+
+ REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PHPDBG_FUNC", STR_PARAM, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("PHPDBG_COLOR_PROMPT", PHPDBG_COLOR_PROMPT, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PHPDBG_COLOR_NOTICE", PHPDBG_COLOR_NOTICE, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PHPDBG_COLOR_ERROR", PHPDBG_COLOR_ERROR, CONST_CS|CONST_PERSISTENT);
+
+ return SUCCESS;
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */
+{
+ zend_hash_destroy((HashTable*)brake);
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */
+{
+ efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol);
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_opcode(void *brake) /* {{{ */
+{
+ efree((char*)((phpdbg_breakop_t*)brake)->name);
+} /* }}} */
+
+
+static void php_phpdbg_destroy_bp_methods(void *brake) /* {{{ */
+{
+ zend_hash_destroy((HashTable*)brake);
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */
+{
+ phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data;
+
+ if (brake) {
+ if (brake->ops) {
+ TSRMLS_FETCH();
+
+ destroy_op_array(
+ brake->ops TSRMLS_CC);
+ efree(brake->ops);
+ }
+ efree((char*)brake->code);
+ }
+} /* }}} */
+
+static void php_phpdbg_destroy_registered(void *data) /* {{{ */
+{
+ zend_function *function = (zend_function*) data;
+ TSRMLS_FETCH();
+
+ destroy_zend_function(
+ function TSRMLS_CC);
+} /* }}} */
+
+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_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);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
+ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
+
+ zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
+ zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
+
+ return SUCCESS;
+} /* }}} */
+
+static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
+{
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
+ 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));
+
+ if (PHPDBG_G(exec)) {
+ efree(PHPDBG_G(exec));
+ PHPDBG_G(exec) = NULL;
+ }
+
+ if (PHPDBG_G(prompt)[0]) {
+ free(PHPDBG_G(prompt)[0]);
+ }
+ if (PHPDBG_G(prompt)[1]) {
+ free(PHPDBG_G(prompt)[1]);
+ }
+
+ PHPDBG_G(prompt)[0] = NULL;
+ PHPDBG_G(prompt)[1] = NULL;
+
+ if (PHPDBG_G(oplog)) {
+ fclose(
+ PHPDBG_G(oplog));
+ PHPDBG_G(oplog) = NULL;
+ }
+
+ if (PHPDBG_G(ops)) {
+ destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
+ efree(PHPDBG_G(ops));
+ PHPDBG_G(ops) = NULL;
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+/* {{{ proto mixed phpdbg_exec(string context)
+ Attempt to set the execution context for phpdbg
+ If the execution context was set previously it is returned
+ If the execution context was not set previously boolean true is returned
+ If the request to set the context fails, boolean false is returned, and an E_WARNING raised */
+static PHP_FUNCTION(phpdbg_exec)
+{
+ char *exec = NULL;
+ zend_ulong exec_len = 0L;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) {
+ return;
+ }
+
+ {
+ struct stat sb;
+ zend_bool result = 1;
+
+ if (VCWD_STAT(exec, &sb) != FAILURE) {
+ if (sb.st_mode & (S_IFREG|S_IFLNK)) {
+ if (PHPDBG_G(exec)) {
+ ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1);
+ efree(PHPDBG_G(exec));
+ result = 0;
+ }
+
+ PHPDBG_G(exec) = estrndup(exec, exec_len);
+ PHPDBG_G(exec_len) = exec_len;
+
+ if (result)
+ ZVAL_BOOL(return_value, 1);
+ } else {
+ zend_error(
+ E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec);
+ ZVAL_BOOL(return_value, 0);
+ }
+ } else {
+ zend_error(
+ E_WARNING, "Failed to set execution context (%s) the file does not exist", exec);
+
+ ZVAL_BOOL(return_value, 0);
+ }
+ }
+} /* }}} */
+
+/* {{{ proto void phpdbg_break([integer type, string expression])
+ instructs phpdbg to insert a breakpoint at the next opcode */
+static PHP_FUNCTION(phpdbg_break)
+{
+ if (ZEND_NUM_ARGS() > 0) {
+ long type;
+ char *expr = NULL;
+ zend_uint expr_len = 0;
+ phpdbg_param_t param;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &type, &expr, &expr_len) == FAILURE) {
+ return;
+ }
+
+ phpdbg_parse_param(expr, expr_len, &param TSRMLS_CC);
+
+ switch (type) {
+ case METHOD_PARAM:
+ phpdbg_do_break_method(&param, NULL TSRMLS_CC);
+ break;
+
+ case FILE_PARAM:
+ phpdbg_do_break_file(&param, NULL TSRMLS_CC);
+ break;
+
+ case NUMERIC_PARAM:
+ phpdbg_do_break_lineno(&param, NULL TSRMLS_CC);
+ break;
+
+ case STR_PARAM:
+ phpdbg_do_break_func(&param, NULL TSRMLS_CC);
+ break;
+
+ default: zend_error(
+ E_WARNING, "unrecognized parameter type %ld", type);
+ }
+
+ phpdbg_clear_param(&param TSRMLS_CC);
+
+ } else if (EG(current_execute_data) && EG(active_op_array)) {
+ zend_ulong opline_num = (EG(current_execute_data)->opline -
+ EG(active_op_array)->opcodes);
+
+ phpdbg_set_breakpoint_opline_ex(
+ &EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC);
+ }
+} /* }}} */
+
+/* {{{ proto void phpdbg_clear(void)
+ instructs phpdbg to clear breakpoints */
+static PHP_FUNCTION(phpdbg_clear)
+{
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
+ 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]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
+} /* }}} */
+
+/* {{{ proto void phpdbg_color(integer element, string color) */
+static PHP_FUNCTION(phpdbg_color)
+{
+ long element;
+ char *color;
+ zend_uint color_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) {
+ return;
+ }
+
+ switch (element) {
+ case PHPDBG_COLOR_NOTICE:
+ case PHPDBG_COLOR_ERROR:
+ case PHPDBG_COLOR_PROMPT:
+ phpdbg_set_color_ex(element, color, color_len TSRMLS_CC);
+ break;
+
+ default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant");
+ }
+} /* }}} */
+
+/* {{{ proto void phpdbg_prompt(string prompt) */
+static PHP_FUNCTION(phpdbg_prompt)
+{
+ char *prompt;
+ zend_uint prompt_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) {
+ return;
+ }
+
+ 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_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0)
+ ZEND_ARG_INFO(0, element)
+ ZEND_ARG_INFO(0, color)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_prompt_arginfo, 0, 0, 0)
+ ZEND_ARG_INFO(0, string)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_exec_arginfo, 0, 0, 0)
+ ZEND_ARG_INFO(0, context)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0)
+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_exec, phpdbg_exec_arginfo)
+ PHP_FE(phpdbg_color, phpdbg_color_arginfo)
+ PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
+#ifdef PHP_FE_END
+ PHP_FE_END
+#else
+ {NULL,NULL,NULL}
+#endif
+};
+
+static zend_module_entry sapi_phpdbg_module_entry = {
+ STANDARD_MODULE_HEADER,
+ PHPDBG_NAME,
+ phpdbg_user_functions,
+ PHP_MINIT(phpdbg),
+ NULL,
+ PHP_RINIT(phpdbg),
+ PHP_RSHUTDOWN(phpdbg),
+ NULL,
+ PHPDBG_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+
+static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */
+{
+ if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {
+ return FAILURE;
+ }
+
+ phpdbg_booted=1;
+
+ return SUCCESS;
+} /* }}} */
+
+static char* php_sapi_phpdbg_read_cookies(TSRMLS_D) /* {{{ */
+{
+ return NULL;
+} /* }}} */
+
+static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */
+{
+ return 0;
+}
+/* }}} */
+
+static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */
+{
+ /* We do nothing here, this function is needed to prevent that the fallback
+ * header handling is called. */
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
+}
+/* }}} */
+
+static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /* {{{ */
+{
+}
+/* }}} */
+
+static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
+{
+ /*
+ * We must not request TSRM before being boot
+ */
+ if (phpdbg_booted) {
+ phpdbg_error("%s", message);
+
+ switch (PG(last_error_type)) {
+ case E_ERROR:
+ case E_CORE_ERROR:
+ case E_COMPILE_ERROR:
+ case E_USER_ERROR:
+ case E_PARSE:
+ case E_RECOVERABLE_ERROR:
+ if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
+ phpdbg_list_file(
+ zend_get_executed_filename(TSRMLS_C),
+ 3,
+ zend_get_executed_lineno(TSRMLS_C)-1,
+ zend_get_executed_lineno(TSRMLS_C)
+ TSRMLS_CC
+ );
+ }
+
+ do {
+ switch (phpdbg_interactive(TSRMLS_C)) {
+ case PHPDBG_LEAVE:
+ case PHPDBG_FINISH:
+ case PHPDBG_UNTIL:
+ case PHPDBG_NEXT:
+ return;
+ }
+ } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
+
+ }
+ } else fprintf(stdout, "%s\n", message);
+}
+/* }}} */
+
+static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */
+{
+ fflush(stdout);
+ if(SG(request_info).argv0) {
+ free(SG(request_info).argv0);
+ SG(request_info).argv0 = NULL;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {{{ */
+{
+ unsigned int len;
+ char *docroot = "";
+
+ /* In phpdbg mode, we consider the environment to be a part of the server variables
+ */
+ php_import_environment_variables(track_vars_array TSRMLS_CC);
+
+ if (PHPDBG_G(exec)) {
+ len = PHPDBG_G(exec_len);
+ if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF",
+ &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
+ php_register_variable("PHP_SELF", PHPDBG_G(exec),
+ track_vars_array TSRMLS_CC);
+ }
+ if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME",
+ &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
+ php_register_variable("SCRIPT_NAME", PHPDBG_G(exec),
+ track_vars_array TSRMLS_CC);
+ }
+
+ if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME",
+ &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
+ php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec),
+ track_vars_array TSRMLS_CC);
+ }
+ if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED",
+ &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
+ php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec),
+ track_vars_array TSRMLS_CC);
+ }
+ }
+
+ /* any old docroot will doo */
+ len = 0U;
+ if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT",
+ &docroot, len, &len TSRMLS_CC)) {
+ php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC);
+ }
+}
+/* }}} */
+
+static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */
+{
+ return phpdbg_write("%s", message);
+} /* }}} */
+
+#if PHP_VERSION_ID >= 50700
+static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC) /* {{{ */
+{
+#else
+static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
+{
+ TSRMLS_FETCH();
+#endif
+
+ fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
+} /* }}} */
+
+/* {{{ sapi_module_struct phpdbg_sapi_module
+*/
+static sapi_module_struct phpdbg_sapi_module = {
+ "phpdbg", /* name */
+ "phpdbg", /* pretty name */
+
+ php_sapi_phpdbg_module_startup, /* startup */
+ php_module_shutdown_wrapper, /* shutdown */
+
+ NULL, /* activate */
+ php_sapi_phpdbg_deactivate, /* deactivate */
+
+ php_sapi_phpdbg_ub_write, /* unbuffered write */
+ php_sapi_phpdbg_flush, /* flush */
+ NULL, /* get uid */
+ NULL, /* getenv */
+
+ php_error, /* error handler */
+
+ php_sapi_phpdbg_header_handler, /* header handler */
+ php_sapi_phpdbg_send_headers, /* send headers handler */
+ php_sapi_phpdbg_send_header, /* send header handler */
+
+ NULL, /* read POST data */
+ php_sapi_phpdbg_read_cookies, /* read Cookies */
+
+ php_sapi_phpdbg_register_vars, /* register server variables */
+ php_sapi_phpdbg_log_message, /* Log message */
+ NULL, /* Get request time */
+ NULL, /* Child terminate */
+ STANDARD_SAPI_MODULE_PROPERTIES
+};
+/* }}} */
+
+const opt_struct OPTIONS[] = { /* {{{ */
+ {'c', 1, "ini path override"},
+ {'d', 1, "define ini entry on command line"},
+ {'n', 0, "no php.ini"},
+ {'z', 1, "load zend_extension"},
+ /* phpdbg options */
+ {'q', 0, "no banner"},
+ {'e', 1, "exec"},
+ {'v', 0, "disable quietness"},
+ {'s', 0, "enable stepping"},
+ {'b', 0, "boring colours"},
+ {'i', 1, "specify init"},
+ {'I', 0, "ignore init"},
+ {'O', 1, "opline log"},
+ {'r', 0, "run"},
+ {'E', 0, "step-through-eval"},
+ {'S', 1, "sapi-name"},
+#ifndef _WIN32
+ {'l', 1, "listen"},
+ {'a', 1, "address-or-any"},
+#endif
+ {'V', 0, "version"},
+ {'-', 0, NULL}
+}; /* }}} */
+
+const char phpdbg_ini_hardcoded[] =
+"html_errors=Off\n"
+"register_argc_argv=On\n"
+"implicit_flush=On\n"
+"display_errors=Off\n"
+"log_errors=On\n"
+"max_execution_time=0\n"
+"max_input_time=-1\n"
+"error_log=\n\0";
+
+/* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
+#define INI_DEFAULT(name, value) \
+ Z_SET_REFCOUNT(tmp, 0); \
+ Z_UNSET_ISREF(tmp); \
+ ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \
+ zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL);
+
+void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */
+{
+ zval tmp;
+ INI_DEFAULT("report_zend_debug", "0");
+} /* }}} */
+
+static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */
+{
+ /* print blurb */
+ if (!cleaning) {
+ phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
+ PHPDBG_VERSION);
+ phpdbg_writeln("To get help using phpdbg type \"help\" and press enter");
+ phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
+ } else {
+ phpdbg_notice("Clean Execution Environment");
+
+ phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table)));
+ phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table)));
+ phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants)));
+ phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files)));
+ }
+} /* }}} */
+
+static inline void phpdbg_sigint_handler(int signo) /* {{{ */
+{
+ TSRMLS_FETCH();
+
+ if (EG(in_execution)) {
+ /* set signalled only when not interactive */
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
+ PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
+ }
+ } else {
+ /* we quit remote consoles on recv SIGINT */
+ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+ zend_bailout();
+ }
+ }
+} /* }}} */
+
+#ifndef _WIN32
+int phpdbg_open_socket(const char *interface, short port) /* {{{ */
+{
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ switch (fd) {
+ case -1:
+ return -1;
+
+ default: {
+ int reuse = 1;
+
+ switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) {
+ case -1:
+ close(fd);
+ return -2;
+
+ default: {
+ struct sockaddr_in address;
+
+ memset(&address, 0, sizeof(address));
+
+ address.sin_port = htons(port);
+ address.sin_family = AF_INET;
+
+ if ((*interface == '*')) {
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+ } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) {
+ close(fd);
+ return -3;
+ }
+
+ switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) {
+ case -1:
+ close(fd);
+ return -4;
+
+ default: {
+ listen(fd, 5);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return fd;
+} /* }}} */
+
+static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */
+{
+ if ((*socket)[0] >= 0) {
+ shutdown(
+ (*socket)[0], SHUT_RDWR);
+ close((*socket)[0]);
+ }
+
+ if (streams[0]) {
+ fclose(streams[0]);
+ }
+
+ if ((*socket)[1] >= 0) {
+ shutdown(
+ (*socket)[1], SHUT_RDWR);
+ close((*socket)[1]);
+ }
+
+ if (streams[1]) {
+ fclose(streams[1]);
+ }
+} /* }}} */
+
+/* don't inline this, want to debug it easily, will inline when done */
+
+int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */
+{
+ if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) {
+ ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]);
+ ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]);
+ }
+
+ streams[0] = NULL;
+ streams[1] = NULL;
+
+ if ((*listen)[0] < 0 || (*listen)[1] < 0) {
+ if ((*listen)[0] < 0) {
+ phpdbg_rlog(stderr,
+ "console failed to initialize (stdin) on %s:%d", address, port[0]);
+ }
+
+ if ((*listen)[1] < 0) {
+ phpdbg_rlog(stderr,
+ "console failed to initialize (stdout) on %s:%d", address, port[1]);
+ }
+
+ if ((*listen)[0] >= 0) {
+ close((*listen)[0]);
+ }
+
+ if ((*listen)[1] >= 0) {
+ close((*listen)[1]);
+ }
+
+ return FAILURE;
+ }
+
+ phpdbg_close_sockets(socket, streams);
+
+ phpdbg_rlog(stderr,
+ "accepting connections on %s:%d/%d", address, port[0], port[1]);
+ {
+ struct sockaddr_in address;
+ socklen_t size = sizeof(address);
+ char buffer[20] = {0};
+
+ {
+ memset(&address, 0, size);
+ (*socket)[0] = accept(
+ (*listen)[0], (struct sockaddr *) &address, &size);
+ inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
+
+ phpdbg_rlog(stderr, "connection (stdin) from %s", buffer);
+ }
+
+ {
+ memset(&address, 0, size);
+ (*socket)[1] = accept(
+ (*listen)[1], (struct sockaddr *) &address, &size);
+ inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
+
+ phpdbg_rlog(stderr, "connection (stdout) from %s", buffer);
+ }
+ }
+
+ dup2((*socket)[0], fileno(stdin));
+ dup2((*socket)[1], fileno(stdout));
+
+ setbuf(stdout, NULL);
+
+ streams[0] = fdopen((*socket)[0], "r");
+ streams[1] = fdopen((*socket)[1], "w");
+
+ return SUCCESS;
+} /* }}} */
+#endif
+
+int main(int argc, char **argv) /* {{{ */
+{
+ sapi_module_struct *phpdbg = &phpdbg_sapi_module;
+ char *sapi_name;
+ char *ini_entries;
+ int ini_entries_len;
+ char **zend_extensions = NULL;
+ zend_ulong zend_extensions_len = 0L;
+ zend_bool ini_ignore;
+ char *ini_override;
+ char *exec;
+ size_t exec_len;
+ char *init_file;
+ size_t init_file_len;
+ zend_bool init_file_default;
+ char *oplog_file;
+ size_t oplog_file_len;
+ zend_ulong flags;
+ char *php_optarg;
+ int php_optind, opt, show_banner = 1;
+ long cleaning = 0;
+ zend_bool remote = 0;
+ int run = 0;
+ int step = 0;
+ char *bp_tmp_file;
+#ifndef _WIN32
+ char *address;
+ int listen[2];
+ int server[2];
+ int socket[2];
+ FILE* streams[2] = {NULL, NULL};
+#endif
+
+#ifdef ZTS
+ void ***tsrm_ls;
+#endif
+
+#ifndef _WIN32
+ address = strdup("127.0.0.1");
+ socket[0] = -1;
+ socket[1] = -1;
+ listen[0] = -1;
+ listen[1] = -1;
+ server[0] = -1;
+ server[1] = -1;
+ streams[0] = NULL;
+ streams[1] = NULL;
+#endif
+
+#ifdef PHP_WIN32
+ _fmode = _O_BINARY; /* sets default for file streams to binary */
+ setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
+ setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
+ setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
+#endif
+
+#ifdef ZTS
+ tsrm_startup(1, 1, 0, NULL);
+
+ tsrm_ls = ts_resource(0);
+#endif
+
+phpdbg_main:
+ if (!cleaning) {
+ bp_tmp_file = malloc(L_tmpnam);
+ tmpnam(bp_tmp_file);
+ if (bp_tmp_file == NULL) {
+ phpdbg_error("Unable to create temporary file");
+ }
+ }
+ 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;
+ oplog_file = NULL;
+ oplog_file_len = 0;
+ flags = PHPDBG_DEFAULT_FLAGS;
+ php_optarg = NULL;
+ php_optind = 1;
+ opt = 0;
+ run = 0;
+ step = 0;
+ sapi_name = NULL;
+
+
+ while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
+ switch (opt) {
+ case 'r':
+ run++;
+ break;
+ case 'n':
+ ini_ignore = 1;
+ break;
+ case 'c':
+ if (ini_override) {
+ free(ini_override);
+ }
+ ini_override = strdup(php_optarg);
+ break;
+ case 'd': {
+ int len = strlen(php_optarg);
+ char *val;
+
+ if ((val = strchr(php_optarg, '='))) {
+ val++;
+ if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
+ ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
+ memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
+ ini_entries_len += (val - php_optarg);
+ memcpy(ini_entries + ini_entries_len, "\"", 1);
+ ini_entries_len++;
+ memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
+ ini_entries_len += len - (val - php_optarg);
+ memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
+ ini_entries_len += sizeof("\n\0\"") - 2;
+ } else {
+ ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
+ memcpy(ini_entries + ini_entries_len, php_optarg, len);
+ memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
+ ini_entries_len += len + sizeof("\n\0") - 2;
+ }
+ } else {
+ ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
+ memcpy(ini_entries + ini_entries_len, php_optarg, len);
+ memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
+ ini_entries_len += len + sizeof("=1\n\0") - 2;
+ }
+ } break;
+
+ case 'z':
+ zend_extensions_len++;
+ if (zend_extensions) {
+ zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
+ } else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
+ zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
+ break;
+
+ /* begin phpdbg options */
+
+ case 'e': { /* set execution context */
+ exec_len = strlen(php_optarg);
+ if (exec_len) {
+ if (exec) {
+ free(exec);
+ }
+ exec = strdup(php_optarg);
+ }
+ } break;
+
+ case 'S': { /* set SAPI name */
+ if (sapi_name) {
+ free(sapi_name);
+ }
+ sapi_name = strdup(php_optarg);
+ } break;
+
+ case 'I': { /* ignore .phpdbginit */
+ init_file_default = 0;
+ } break;
+
+ case 'i': { /* set init file */
+ if (init_file) {
+ free(init_file);
+ }
+
+ init_file_len = strlen(php_optarg);
+ if (init_file_len) {
+ init_file = strdup(php_optarg);
+ }
+ } break;
+
+ case 'O': { /* set oplog output */
+ oplog_file_len = strlen(php_optarg);
+ if (oplog_file_len) {
+ oplog_file = strdup(php_optarg);
+ }
+ } break;
+
+ case 'v': /* set quietness off */
+ flags &= ~PHPDBG_IS_QUIET;
+ break;
+
+ case 's': /* set stepping on */
+ step = 1;
+ break;
+
+ case 'E': /* stepping through eval on */
+ flags |= PHPDBG_IS_STEPONEVAL;
+ break;
+
+ case 'b': /* set colours off */
+ flags &= ~PHPDBG_IS_COLOURED;
+ break;
+
+ case 'q': /* hide banner */
+ show_banner = 0;
+ break;
+
+#ifndef _WIN32
+ /* if you pass a listen port, we will accept input on listen port */
+ /* and write output to listen port * 2 */
+
+ case 'l': { /* set listen ports */
+ if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) {
+ if (sscanf(php_optarg, "%d", &listen[0]) != 1) {
+ /* default to hardcoded ports */
+ listen[0] = 4000;
+ listen[1] = 8000;
+ } else {
+ listen[1] = (listen[0] * 2);
+ }
+ }
+ } break;
+
+ case 'a': { /* set bind address */
+ free(address);
+ if (!php_optarg) {
+ address = strdup("*");
+ } else address = strdup(php_optarg);
+ } break;
+#endif
+
+ case 'V': {
+ sapi_startup(phpdbg);
+ phpdbg->startup(phpdbg);
+ printf(
+ "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2014 The PHP Group\n%s",
+ PHPDBG_VERSION,
+ __DATE__,
+ __TIME__,
+ PHP_VERSION,
+ get_zend_version()
+ );
+ sapi_deactivate(TSRMLS_C);
+ sapi_shutdown();
+ return 0;
+ } break;
+ }
+ }
+
+#ifndef _WIN32
+ /* setup remote server if necessary */
+ if (!cleaning &&
+ (listen[0] > 0 && listen[1] > 0)) {
+ if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) {
+ remote = 0;
+ exit(0);
+ }
+ /* set remote flag to stop service shutting down upon quit */
+ remote = 1;
+ }
+#endif
+
+ if (sapi_name) {
+ phpdbg->name = sapi_name;
+ }
+
+ phpdbg->ini_defaults = phpdbg_ini_defaults;
+ phpdbg->phpinfo_as_text = 1;
+ phpdbg->php_ini_ignore_cwd = 1;
+
+ sapi_startup(phpdbg);
+
+ phpdbg->executable_location = argv[0];
+ phpdbg->phpinfo_as_text = 1;
+ phpdbg->php_ini_ignore = ini_ignore;
+ phpdbg->php_ini_path_override = ini_override;
+
+ if (ini_entries) {
+ ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded));
+ memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1);
+ memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2);
+ } else {
+ ini_entries = malloc(sizeof(phpdbg_ini_hardcoded));
+ memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
+ }
+ ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
+
+ if (zend_extensions_len) {
+ zend_ulong zend_extension = 0L;
+
+ while (zend_extension < zend_extensions_len) {
+ const char *ze = zend_extensions[zend_extension];
+ size_t ze_len = strlen(ze);
+
+ ini_entries = realloc(
+ ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
+ memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
+ ini_entries_len += (sizeof("zend_extension=")-1);
+ memcpy(&ini_entries[ini_entries_len], ze, ze_len);
+ ini_entries_len += ze_len;
+ memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
+
+ free(zend_extensions[zend_extension]);
+ zend_extension++;
+ }
+
+ free(zend_extensions);
+ }
+
+ phpdbg->ini_entries = ini_entries;
+
+ if (phpdbg->startup(phpdbg) == SUCCESS) {
+
+ zend_activate(TSRMLS_C);
+
+ /* do not install sigint handlers for remote consoles */
+ /* sending SIGINT then provides a decent way of shutting down the server */
+#ifdef ZEND_SIGNALS
+# ifndef _WIN32
+ if (listen[0] < 0) {
+# endif
+ zend_try {
+ zend_signal_activate(TSRMLS_C);
+ zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC);
+ } zend_end_try();
+# ifndef _WIN32
+ }
+# endif
+#else
+# ifndef _WIN32
+ if (listen[0] < 0) {
+# endif
+ signal(SIGINT, phpdbg_sigint_handler);
+#ifndef _WIN32
+ }
+#endif
+#endif
+
+ PG(modules_activated) = 0;
+
+ /* set flags from command line */
+ PHPDBG_G(flags) = flags;
+
+#ifndef _WIN32
+ /* setup io here */
+ if (streams[0] && streams[1]) {
+ PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
+
+ signal(SIGPIPE, SIG_IGN);
+ }
+#endif
+
+ PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
+ PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
+ PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
+
+ if (exec) { /* set execution context */
+ PHPDBG_G(exec) = phpdbg_resolve_path(
+ exec TSRMLS_CC);
+ PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
+
+ free(exec);
+ }
+
+ if (oplog_file) { /* open oplog */
+ PHPDBG_G(oplog) = fopen(oplog_file, "w+");
+ if (!PHPDBG_G(oplog)) {
+ phpdbg_error(
+ "Failed to open oplog %s", oplog_file);
+ }
+ free(oplog_file);
+ }
+
+ /* set default colors */
+ phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold") TSRMLS_CC);
+ phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold") TSRMLS_CC);
+ phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC);
+
+ /* set default prompt */
+ phpdbg_set_prompt(PROMPT TSRMLS_CC);
+
+ zend_try {
+ zend_activate_modules(TSRMLS_C);
+ } zend_end_try();
+
+ if (show_banner) {
+ /* print blurb */
+ phpdbg_welcome((cleaning > 0) TSRMLS_CC);
+ }
+
+ zend_try {
+ /* activate globals, they can be overwritten */
+ zend_activate_auto_globals(TSRMLS_C);
+ } zend_end_try();
+
+ /* 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);
+ } zend_end_try();
+ PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
+
+ /* quit if init says so */
+ if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
+ goto phpdbg_out;
+ }
+
+ /* 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, NULL TSRMLS_CC);
+ if (run > 1) {
+ /* if -r is on the command line more than once just quit */
+ goto phpdbg_out;
+ }
+ }
+
+phpdbg_interact:
+ /* phpdbg main() */
+ do {
+ zend_try {
+ phpdbg_interactive(TSRMLS_C);
+ } 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);
+ cleaning = 1;
+ } else {
+ cleaning = 0;
+ }
+
+#ifndef _WIN32
+ if (!cleaning) {
+ /* remote client disconnected */
+ if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
+
+ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
+ /* renegociate connections */
+ phpdbg_open_sockets(
+ address, listen, &server, &socket, streams);
+
+ /* set streams */
+ if (streams[0] && streams[1]) {
+ PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
+ }
+
+ /* this must be forced */
+ CG(unclean_shutdown) = 0;
+ } else {
+ /* local consoles cannot disconnect, ignore EOF */
+ PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
+ }
+ }
+ }
+#endif
+ } zend_end_try();
+ } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
+
+ /* this must be forced */
+ CG(unclean_shutdown) = 0;
+
+ /* this is just helpful */
+ PG(report_memleaks) = 0;
+
+phpdbg_out:
+#ifndef _WIN32
+ if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
+ PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
+ goto phpdbg_interact;
+ }
+#endif
+
+#ifndef ZTS
+ /* force cleanup of auto and core globals */
+ zend_hash_clean(CG(auto_globals));
+ memset(
+ &core_globals, 0, sizeof(php_core_globals));
+#endif
+
+ if (ini_entries) {
+ free(ini_entries);
+ }
+
+ if (ini_override) {
+ free(ini_override);
+ }
+
+ if (PG(modules_activated)) {
+ zend_try {
+ zend_deactivate_modules(TSRMLS_C);
+ } zend_end_try();
+ }
+
+ zend_deactivate(TSRMLS_C);
+
+ zend_try {
+ zend_post_deactivate_modules(TSRMLS_C);
+ } zend_end_try();
+
+#ifdef ZEND_SIGNALS
+ zend_try {
+ zend_signal_deactivate(TSRMLS_C);
+ } zend_end_try();
+#endif
+
+ zend_try {
+ php_module_shutdown(TSRMLS_C);
+ } zend_end_try();
+
+ sapi_shutdown();
+ }
+
+ if (cleaning || remote) {
+ goto phpdbg_main;
+ }
+
+#ifdef ZTS
+ /* bugggy */
+ /* tsrm_shutdown(); */
+#endif
+
+#ifndef _WIN32
+ if (address) {
+ free(address);
+ }
+#endif
+
+ if (sapi_name) {
+ free(sapi_name);
+ }
+
+ free(bp_tmp_file);
+
+ return 0;
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h
new file mode 100644
index 000000000..6b7afb237
--- /dev/null
+++ b/sapi/phpdbg/phpdbg.h
@@ -0,0 +1,188 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_H
+#define PHPDBG_H
+
+#ifdef PHP_WIN32
+# define PHPDBG_API __declspec(dllexport)
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define PHPDBG_API __attribute__ ((visibility("default")))
+#else
+# define PHPDBG_API
+#endif
+
+#include "php.h"
+#include "php_globals.h"
+#include "php_variables.h"
+#include "php_getopt.h"
+#include "zend_builtin_functions.h"
+#include "zend_extensions.h"
+#include "zend_modules.h"
+#include "zend_globals.h"
+#include "zend_ini_scanner.h"
+#include "zend_stream.h"
+#include "SAPI.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#if defined(_WIN32) && !defined(__MINGW32__)
+# include <windows.h>
+# include "config.w32.h"
+# undef strcasecmp
+# undef strncasecmp
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+#else
+# include "php_config.h"
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+#include "php_main.h"
+
+#ifdef ZTS
+# include "TSRM.h"
+#endif
+
+#ifdef HAVE_LIBREADLINE
+# include <readline/readline.h>
+# include <readline/history.h>
+#endif
+
+#include "phpdbg_cmd.h"
+#include "phpdbg_utils.h"
+
+#ifdef ZTS
+# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
+#else
+# define PHPDBG_G(v) (phpdbg_globals.v)
+#endif
+
+#define PHPDBG_NEXT 2
+#define PHPDBG_UNTIL 3
+#define PHPDBG_FINISH 4
+#define PHPDBG_LEAVE 5
+
+/*
+ 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) /* }}} */
+
+/*
+ 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_IS_STEPPING (1<<12)
+#define PHPDBG_IS_QUIET (1<<13)
+#define PHPDBG_IS_QUITTING (1<<14)
+#define PHPDBG_IS_COLOURED (1<<15)
+#define PHPDBG_IS_CLEANING (1<<16)
+
+#define PHPDBG_IN_UNTIL (1<<17)
+#define PHPDBG_IN_FINISH (1<<18)
+#define PHPDBG_IN_LEAVE (1<<19)
+
+#define PHPDBG_IS_REGISTERED (1<<20)
+#define PHPDBG_IS_STEPONEVAL (1<<21)
+#define PHPDBG_IS_INITIALIZING (1<<22)
+#define PHPDBG_IS_SIGNALED (1<<23)
+#define PHPDBG_IS_INTERACTIVE (1<<24)
+#define PHPDBG_IS_BP_ENABLED (1<<25)
+#define PHPDBG_IS_REMOTE (1<<26)
+#define PHPDBG_IS_DISCONNECTED (1<<27)
+
+#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)
+
+#ifndef _WIN32
+# 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)
+#endif /* }}} */
+
+/* {{{ strings */
+#define PHPDBG_NAME "phpdbg"
+#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
+#define PHPDBG_URL "http://phpdbg.com"
+#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
+#define PHPDBG_VERSION "0.3.1"
+#define PHPDBG_INIT_FILENAME ".phpdbginit"
+/* }}} */
+
+/* {{{ output descriptors */
+#define PHPDBG_STDIN 0
+#define PHPDBG_STDOUT 1
+#define PHPDBG_STDERR 2
+#define PHPDBG_IO_FDS 3 /* }}} */
+
+/* {{{ structs */
+ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
+ HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */
+ HashTable registered; /* registered */
+ HashTable seek; /* seek oplines */
+ phpdbg_frame_t frame; /* frame */
+
+ char *exec; /* file to execute */
+ size_t exec_len; /* size of exec */
+ zend_op_array *ops; /* op_array */
+ zval *retval; /* return value */
+ int bp_count; /* breakpoint count */
+ int vmret; /* return from last opcode handler execution */
+
+ FILE *oplog; /* opline log */
+ FILE *io[PHPDBG_IO_FDS]; /* io */
+
+ char *prompt[2]; /* prompt */
+ const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */
+
+ phpdbg_command_t *lcmd; /* last command */
+ phpdbg_param_t lparam; /* last param */
+
+ zend_ulong flags; /* phpdbg flags */
+ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
+
+#endif /* PHPDBG_H */
diff --git a/sapi/phpdbg/phpdbg.init.d b/sapi/phpdbg/phpdbg.init.d
new file mode 100755
index 000000000..99a1ab328
--- /dev/null
+++ b/sapi/phpdbg/phpdbg.init.d
@@ -0,0 +1,122 @@
+################################################################
+# File: /etc/init.d/phpdbg #
+# Author: krakjoe #
+# Purpose: Daemonize phpdbg automatically on boot #
+# chkconfig: 2345 07 09 #
+# description: Starts, stops and restarts phpdbg daemon #
+################################################################
+LOCKFILE=/var/lock/subsys/phpdbg
+PIDFILE=/var/run/phpdbg.pid
+STDIN=4000
+STDOUT=8000
+################################################################
+# Either set path to phpdbg here or rely on phpdbg in ENV/PATH #
+################################################################
+if [ "x${PHPDBG}" == "x" ]; then
+ PHPDBG=$(which phpdbg 2>/dev/null)
+fi
+################################################################
+# Options to pass to phpdbg upon boot #
+################################################################
+OPTIONS=
+LOGFILE=/var/log/phpdbg.log
+################################################################
+# STOP EDITING STOP EDITING STOP EDITING STOP EDITING #
+################################################################
+. /etc/rc.d/init.d/functions
+RETVAL=1
+################################################################
+insanity()
+{
+ if [ "x${PHPDBG}" == "x" ]; then
+ PHPDBG=$(which phpdbg 2>>/dev/null)
+ if [ $? != 0 ]; then
+ echo -n $"Fatal: cannot find phpdbg ${PHPDBG}"
+ echo_failure
+ echo
+ return 1
+ fi
+ else
+ if [ ! -x ${PHPDBG} ]; then
+ echo -n $"Fatal: cannot execute phpdbg ${PHPDBG}"
+ echo_failure
+ echo
+ return 1
+ fi
+ fi
+
+ return 0
+}
+
+start()
+{
+ insanity
+
+ if [ $? -eq 1 ]; then
+ return $RETVAL
+ fi
+
+ echo -n $"Starting: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} "
+ nohup ${PHPDBG} -l${STDIN}/${STDOUT} ${OPTIONS} 2>>${LOGFILE} 1>/dev/null </dev/null &
+ PID=$!
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+ echo $PID > $PIDFILE
+ echo_success
+ else
+ echo_failure
+ fi
+ echo
+ [ $RETVAL = 0 ] && touch ${LOCKFILE}
+ return $RETVAL
+}
+
+stop()
+{
+ insanity
+
+ if [ $? -eq 1 ]; then
+ return $RETVAL
+ fi
+
+ if [ -f ${LOCKFILE} ] && [ -f ${PIDFILE} ]
+ then
+ echo -n $"Stopping: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} "
+ kill -s TERM $(cat $PIDFILE)
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+ echo_success
+ else
+ echo_failure
+ fi
+ echo
+ [ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
+ else
+ echo -n $"Error: phpdbg not running"
+ echo_failure
+ echo
+ [ $RETVAL = 1 ]
+ fi
+ return $RETVAL
+}
+##################################################################
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ status)
+ status $PHPDBG
+ ;;
+ restart)
+ $0 stop
+ $0 start
+ ;;
+ *)
+ echo "usage: $0 start|stop|restart|status"
+ ;;
+esac
+###################################################################
+exit $RETVAL
diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c
new file mode 100644
index 000000000..511d1db57
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_bp.c
@@ -0,0 +1,1661 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend.h"
+#include "zend_hash.h"
+#include "phpdbg.h"
+#include "phpdbg_bp.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_opcode.h"
+#include "zend_globals.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+/* {{{ private api functions */
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array* TSRMLS_DC);
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function* TSRMLS_DC);
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array* TSRMLS_DC);
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t TSRMLS_DC);
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar TSRMLS_DC);
+static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC); /* }}} */
+
+/*
+* Note:
+* A break point must always set the correct id and type
+* A set breakpoint function must always map new points
+*/
+static inline void _phpdbg_break_mapping(int id, HashTable *table TSRMLS_DC)
+{
+ zend_hash_index_update(
+ &PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id), (void**) &table, sizeof(void*), NULL);
+}
+
+#define PHPDBG_BREAK_MAPPING(id, table) _phpdbg_break_mapping(id, table TSRMLS_CC)
+#define PHPDBG_BREAK_UNMAPPING(id) \
+ zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id))
+
+#define PHPDBG_BREAK_INIT(b, t) do {\
+ b.id = PHPDBG_G(bp_count)++; \
+ b.type = t; \
+ b.disabled = 0;\
+ b.hits = 0; \
+} while(0)
+
+static void phpdbg_file_breaks_dtor(void *data) /* {{{ */
+{
+ phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) data;
+
+ efree((char*)bp->filename);
+} /* }}} */
+
+static void phpdbg_class_breaks_dtor(void *data) /* {{{ */
+{
+ phpdbg_breakmethod_t *bp = (phpdbg_breakmethod_t*) data;
+
+ efree((char*)bp->class_name);
+ efree((char*)bp->func_name);
+} /* }}} */
+
+static void phpdbg_opline_class_breaks_dtor(void *data) /* {{{ */
+{
+ zend_hash_destroy((HashTable *)data);
+} /* }}} */
+
+static void phpdbg_opline_breaks_dtor(void *data) /* {{{ */
+{
+ phpdbg_breakopline_t *bp = (phpdbg_breakopline_t *) data;
+
+ if (bp->class_name) {
+ efree((char*)bp->class_name);
+ }
+ if (bp->func_name) {
+ efree((char*)bp->func_name);
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */
+{
+ if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) {
+ HashPosition position[2];
+ HashTable **table = NULL;
+
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) {
+ phpdbg_breakbase_t *brake;
+
+ for (zend_hash_internal_pointer_reset_ex((*table), &position[1]);
+ zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS;
+ zend_hash_move_forward_ex((*table), &position[1])) {
+ brake->hits = 0;
+ }
+ }
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
+{
+ HashPosition position[2];
+ HashTable **table = NULL;
+ zend_ulong id = 0L;
+
+ if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) {
+ phpdbg_notice(
+ "Exporting %d breakpoints",
+ zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]));
+ /* this only looks like magic, it isn't */
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) {
+ phpdbg_breakbase_t *brake;
+
+ zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], NULL, NULL, &id, 0, &position[0]);
+
+ for (zend_hash_internal_pointer_reset_ex((*table), &position[1]);
+ zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS;
+ zend_hash_move_forward_ex((*table), &position[1])) {
+ if (brake->id == id) {
+ switch (brake->type) {
+ case PHPDBG_BREAK_FILE: {
+ fprintf(handle,
+ "break file %s:%lu\n",
+ ((phpdbg_breakfile_t*)brake)->filename,
+ ((phpdbg_breakfile_t*)brake)->line);
+ } break;
+
+ case PHPDBG_BREAK_SYM: {
+ fprintf(handle,
+ "break func %s\n",
+ ((phpdbg_breaksymbol_t*)brake)->symbol);
+ } break;
+
+ case PHPDBG_BREAK_METHOD: {
+ fprintf(handle,
+ "break method %s::%s\n",
+ ((phpdbg_breakmethod_t*)brake)->class_name,
+ ((phpdbg_breakmethod_t*)brake)->func_name);
+ } break;
+
+ case PHPDBG_BREAK_METHOD_OPLINE: {
+ fprintf(handle,
+ "break address %s::%s#%ld\n",
+ ((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 address %s#%ld\n",
+ ((phpdbg_breakopline_t*)brake)->func_name,
+ ((phpdbg_breakopline_t*)brake)->opline_num);
+ } break;
+
+ case PHPDBG_BREAK_FILE_OPLINE: {
+ fprintf(handle,
+ "break address %s:%ld\n",
+ ((phpdbg_breakopline_t*)brake)->class_name,
+ ((phpdbg_breakopline_t*)brake)->opline_num);
+ } break;
+
+ case PHPDBG_BREAK_OPCODE: {
+ fprintf(handle,
+ "break op %s\n",
+ ((phpdbg_breakop_t*)brake)->name);
+ } break;
+
+ case PHPDBG_BREAK_COND: {
+ phpdbg_breakcond_t *conditional = (phpdbg_breakcond_t*) brake;
+
+ if (conditional->paramed) {
+ switch (conditional->param.type) {
+ case STR_PARAM:
+ fprintf(handle,
+ "break at %s if %s\n", conditional->param.str, conditional->code);
+ break;
+
+ case METHOD_PARAM:
+ fprintf(handle,
+ "break at %s::%s if %s\n",
+ conditional->param.method.class, conditional->param.method.name,
+ conditional->code);
+ break;
+
+ case FILE_PARAM:
+ fprintf(handle,
+ "break at %s:%lu if %s\n",
+ conditional->param.file.name, conditional->param.file.line,
+ conditional->code);
+ break;
+
+ default: { /* do nothing */ } break;
+ }
+ } else {
+ fprintf(
+ handle, "break on %s\n", conditional->code);
+ }
+ } break;
+ }
+ }
+ }
+ }
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRMLS_DC) /* {{{ */
+{
+ struct stat sb;
+
+ if (VCWD_STAT(path, &sb) != FAILURE) {
+ if (sb.st_mode & (S_IFREG|S_IFLNK)) {
+ HashTable *broken;
+ phpdbg_breakfile_t new_break;
+ size_t path_len = strlen(path);
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],
+ path, path_len, (void**)&broken) == FAILURE) {
+ HashTable breaks;
+
+ zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0);
+
+ zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],
+ path, path_len, &breaks, sizeof(HashTable),
+ (void**)&broken);
+ }
+
+ if (!zend_hash_index_exists(broken, line_num)) {
+ PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE);
+ new_break.filename = estrndup(path, path_len);
+ new_break.line = line_num;
+
+ zend_hash_index_update(
+ broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL);
+
+ phpdbg_notice("Breakpoint #%d added at %s:%ld",
+ new_break.id, new_break.filename, new_break.line);
+
+ PHPDBG_BREAK_MAPPING(new_break.id, broken);
+ } else {
+ phpdbg_error("Breakpoint at %s:%ld exists", path, line_num);
+ }
+
+ } else {
+ phpdbg_error("Cannot set breakpoint in %s, it is not a regular file", path);
+ }
+ } else {
+ phpdbg_error("Cannot stat %s, it does not exist", path);
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len TSRMLS_DC) /* {{{ */
+{
+ if (!zend_hash_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) {
+ phpdbg_breaksymbol_t new_break;
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_SYM_BP;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_SYM);
+ new_break.symbol = estrndup(name, name_len);
+
+ zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol,
+ name_len, &new_break, sizeof(phpdbg_breaksymbol_t), NULL);
+
+ phpdbg_notice("Breakpoint #%d added at %s",
+ new_break.id, new_break.symbol);
+
+ PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
+ } else {
+ phpdbg_notice("Breakpoint exists at %s", name);
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char *func_name TSRMLS_DC) /* {{{ */
+{
+ HashTable class_breaks, *class_table;
+ size_t class_len = strlen(class_name);
+ size_t func_len = strlen(func_name);
+ char *lcname = zend_str_tolower_dup(func_name, func_len);
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name,
+ class_len, (void**)&class_table) != SUCCESS) {
+ zend_hash_init(&class_breaks, 8, NULL, phpdbg_class_breaks_dtor, 0);
+ zend_hash_update(
+ &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD],
+ class_name, class_len,
+ (void**)&class_breaks, sizeof(HashTable), (void**)&class_table);
+ }
+
+ if (!zend_hash_exists(class_table, lcname, func_len)) {
+ phpdbg_breakmethod_t new_break;
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_BP;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_METHOD);
+ new_break.class_name = estrndup(class_name, class_len);
+ new_break.class_len = class_len;
+ new_break.func_name = estrndup(func_name, func_len);
+ new_break.func_len = func_len;
+
+ zend_hash_update(class_table, lcname, func_len,
+ &new_break, sizeof(phpdbg_breakmethod_t), NULL);
+
+ phpdbg_notice("Breakpoint #%d added at %s::%s",
+ new_break.id, class_name, func_name);
+
+ PHPDBG_BREAK_MAPPING(new_break.id, class_table);
+ } else {
+ phpdbg_notice("Breakpoint exists at %s::%s", class_name, func_name);
+ }
+
+ efree(lcname);
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ */
+{
+ if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline)) {
+ phpdbg_breakline_t new_break;
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE);
+ new_break.name = NULL;
+ new_break.opline = opline;
+ new_break.base = NULL;
+
+ zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline,
+ &new_break, sizeof(phpdbg_breakline_t), NULL);
+
+ phpdbg_notice("Breakpoint #%d added at %#lx",
+ new_break.id, new_break.opline);
+ PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
+ } else {
+ phpdbg_notice("Breakpoint exists at %#lx", opline);
+ }
+} /* }}} */
+
+PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakline_t opline_break;
+ if (op_array->last < brake->opline_num) {
+ if (brake->class_name == NULL) {
+ phpdbg_error("There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num);
+ } else if (brake->func_name == NULL) {
+ phpdbg_error("There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num);
+ } else {
+ phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num);
+ }
+
+ return FAILURE;
+ }
+
+ opline_break.disabled = 0;
+ opline_break.hits = 0;
+ opline_break.id = brake->id;
+ opline_break.opline = brake->opline = (zend_ulong)(op_array->opcodes + brake->opline_num);
+ opline_break.name = NULL;
+ opline_break.base = brake;
+ if (op_array->scope) {
+ opline_break.type = PHPDBG_BREAK_METHOD_OPLINE;
+ } else if (op_array->function_name) {
+ opline_break.type = PHPDBG_BREAK_FUNCTION_OPLINE;
+ } else {
+ opline_break.type = PHPDBG_BREAK_FILE_OPLINE;
+ }
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
+
+ zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline_break.opline, &opline_break, sizeof(phpdbg_breakline_t), NULL);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+ HashTable *func_table = &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE];
+ HashTable *oplines_table;
+ HashPosition position;
+ phpdbg_breakopline_t *brake;
+
+ if (op_array->scope != NULL &&
+ zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], op_array->scope->name, op_array->scope->name_length, (void **)&func_table) == FAILURE) {
+ return;
+ }
+
+ if (op_array->function_name == NULL) {
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], op_array->filename, strlen(op_array->filename), (void **)&oplines_table) == FAILURE) {
+ return;
+ }
+ } else if (zend_hash_find(func_table, op_array->function_name?op_array->function_name:"", op_array->function_name?strlen(op_array->function_name):0, (void **)&oplines_table) == FAILURE) {
+ return;
+ }
+
+ for (zend_hash_internal_pointer_reset_ex(oplines_table, &position);
+ zend_hash_get_current_data_ex(oplines_table, (void**) &brake, &position) == SUCCESS;
+ zend_hash_move_forward_ex(oplines_table, &position)) {
+ if (phpdbg_resolve_op_array_break(brake, op_array TSRMLS_CC) == SUCCESS) {
+ phpdbg_breakline_t *opline_break;
+
+ zend_hash_internal_pointer_end(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
+ zend_hash_get_current_data(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void **)&opline_break);
+
+ phpdbg_notice("Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)",
+ brake->id,
+ brake->class_name?brake->class_name:"",
+ brake->class_name&&brake->func_name?"::":"",
+ brake->func_name?brake->func_name:"",
+ brake->opline_num,
+ brake->opline);
+ }
+ }
+} /* }}} */
+
+PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC) /* {{{ */
+{
+ HashTable *func_table = EG(function_table);
+ zend_function *func;
+
+ if (new_break->func_name == NULL) {
+ if (EG(current_execute_data) == NULL) {
+ if (PHPDBG_G(ops) != NULL && !memcmp(PHPDBG_G(ops)->filename, new_break->class_name, new_break->class_len)) {
+ if (phpdbg_resolve_op_array_break(new_break, PHPDBG_G(ops) TSRMLS_CC) == SUCCESS) {
+ return SUCCESS;
+ } else {
+ return 2;
+ }
+ }
+ return FAILURE;
+ } else {
+ zend_execute_data *execute_data = EG(current_execute_data);
+ do {
+ if (execute_data->op_array->function_name == NULL && execute_data->op_array->scope == NULL && !memcmp(execute_data->op_array->filename, new_break->class_name, new_break->class_len)) {
+ if (phpdbg_resolve_op_array_break(new_break, execute_data->op_array TSRMLS_CC) == SUCCESS) {
+ return SUCCESS;
+ } else {
+ return 2;
+ }
+ }
+ } while ((execute_data = execute_data->prev_execute_data) != NULL);
+ return FAILURE;
+ }
+ }
+
+ if (new_break->class_name != NULL) {
+ zend_class_entry **ce;
+ if (zend_hash_find(EG(class_table), zend_str_tolower_dup(new_break->class_name, new_break->class_len), new_break->class_len + 1, (void **)&ce) == FAILURE) {
+ return FAILURE;
+ }
+ func_table = &(*ce)->function_table;
+ }
+
+ if (zend_hash_find(func_table, zend_str_tolower_dup(new_break->func_name, new_break->func_len), new_break->func_len + 1, (void **)&func) == FAILURE) {
+ if (new_break->class_name != NULL && new_break->func_name != NULL) {
+ phpdbg_error("Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name);
+ return 2;
+ }
+ return FAILURE;
+ }
+
+ if (func->type != ZEND_USER_FUNCTION) {
+ if (new_break->class_name == NULL) {
+ phpdbg_error("%s is not an user defined function, no oplines exist", new_break->func_name);
+ } else {
+ phpdbg_error("%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name);
+ }
+ return 2;
+ }
+
+ if (phpdbg_resolve_op_array_break(new_break, &func->op_array TSRMLS_CC) == FAILURE) {
+ return 2;
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakopline_t new_break;
+ HashTable class_breaks, *class_table;
+ HashTable method_breaks, *method_table;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_METHOD_OPLINE);
+ new_break.func_len = strlen(method);
+ new_break.func_name = estrndup(method, new_break.func_len);
+ new_break.class_len = strlen(class);
+ new_break.class_name = estrndup(class, new_break.class_len);
+ new_break.opline_num = opline;
+ new_break.opline = 0;
+
+ switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
+ case FAILURE:
+ phpdbg_notice("Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline);
+ break;
+
+ case SUCCESS:
+ phpdbg_notice("Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline);
+ break;
+
+ case 2:
+ return;
+ }
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len, (void **)&class_table) == FAILURE) {
+ zend_hash_init(&class_breaks, 8, NULL, phpdbg_opline_class_breaks_dtor, 0);
+ zend_hash_update(
+ &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
+ new_break.class_name,
+ new_break.class_len,
+ (void **)&class_breaks, sizeof(HashTable), (void **)&class_table);
+ }
+
+ if (zend_hash_find(class_table, new_break.func_name, new_break.func_len, (void **)&method_table) == FAILURE) {
+ zend_hash_init(&method_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
+ zend_hash_update(
+ class_table,
+ new_break.func_name,
+ new_break.func_len,
+ (void **)&method_breaks, sizeof(HashTable), (void **)&method_table);
+ }
+
+ if (zend_hash_index_exists(method_table, opline)) {
+ phpdbg_notice("Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline);
+ efree((char*)new_break.func_name);
+ efree((char*)new_break.class_name);
+ PHPDBG_G(bp_count)--;
+ return;
+ }
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_OPLINE_BP;
+
+ PHPDBG_BREAK_MAPPING(new_break.id, method_table);
+
+ zend_hash_index_update(method_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
+}
+
+PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakopline_t new_break;
+ HashTable func_breaks, *func_table;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FUNCTION_OPLINE);
+ new_break.func_len = strlen(function);
+ new_break.func_name = estrndup(function, new_break.func_len);
+ new_break.class_len = 0;
+ new_break.class_name = NULL;
+ new_break.opline_num = opline;
+ new_break.opline = 0;
+
+ switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
+ case FAILURE:
+ phpdbg_notice("Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline);
+ break;
+
+ case SUCCESS:
+ phpdbg_notice("Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline);
+ break;
+
+ case 2:
+ return;
+ }
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len, (void **)&func_table) == FAILURE) {
+ zend_hash_init(&func_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
+ zend_hash_update(
+ &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE],
+ new_break.func_name,
+ new_break.func_len,
+ (void **)&func_breaks, sizeof(HashTable), (void **)&func_table);
+ }
+
+ if (zend_hash_index_exists(func_table, opline)) {
+ phpdbg_notice("Breakpoint already exists for %s#%ld", new_break.func_name, opline);
+ efree((char*)new_break.func_name);
+ PHPDBG_G(bp_count)--;
+ return;
+ }
+
+ PHPDBG_BREAK_MAPPING(new_break.id, func_table);
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_FUNCTION_OPLINE_BP;
+
+ zend_hash_index_update(func_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
+}
+
+PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakopline_t new_break;
+ HashTable file_breaks, *file_table;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE_OPLINE);
+ new_break.func_len = 0;
+ new_break.func_name = NULL;
+ new_break.class_len = strlen(file);
+ new_break.class_name = estrndup(file, new_break.class_len);
+ new_break.opline_num = opline;
+ new_break.opline = 0;
+
+ switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
+ case FAILURE:
+ phpdbg_notice("Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline);
+ break;
+
+ case SUCCESS:
+ phpdbg_notice("Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline);
+ break;
+
+ case 2:
+ return;
+ }
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], new_break.class_name, new_break.class_len, (void **)&file_table) == FAILURE) {
+ zend_hash_init(&file_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
+ zend_hash_update(
+ &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE],
+ new_break.class_name,
+ new_break.class_len,
+ (void **)&file_breaks, sizeof(HashTable), (void **)&file_table);
+ }
+
+ if (zend_hash_index_exists(file_table, opline)) {
+ phpdbg_notice("Breakpoint already exists for %s:%ld", new_break.class_name, opline);
+ efree((char*)new_break.class_name);
+ PHPDBG_G(bp_count)--;
+ return;
+ }
+
+ PHPDBG_BREAK_MAPPING(new_break.id, file_table);
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_FILE_OPLINE_BP;
+
+ zend_hash_index_update(file_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
+}
+
+PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakop_t new_break;
+ zend_ulong hash = zend_hash_func(name, name_len);
+
+ if (zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash)) {
+ phpdbg_notice(
+ "Breakpoint exists for %s", name);
+ return;
+ }
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPCODE);
+ new_break.hash = hash;
+ new_break.name = estrndup(name, name_len);
+
+ zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash,
+ &new_break, sizeof(phpdbg_breakop_t), NULL);
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_OPCODE_BP;
+
+ phpdbg_notice("Breakpoint #%d added at %s", new_break.id, name);
+ PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */
+{
+ if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline)) {
+ phpdbg_breakline_t new_break;
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE);
+ new_break.opline = (zend_ulong) opline;
+
+ zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE],
+ (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t), NULL);
+
+ phpdbg_notice("Breakpoint #%d added at %#lx",
+ new_break.id, new_break.opline);
+ PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
+ }
+} /* }}} */
+
+static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, const phpdbg_param_t *param, const char *expr, size_t expr_len, zend_ulong hash TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakcond_t new_break;
+ zend_uint cops = CG(compiler_options);
+ zval pv;
+
+ PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_COND);
+ new_break.hash = hash;
+
+ if (param) {
+ new_break.paramed = 1;
+ phpdbg_copy_param(
+ param, &new_break.param TSRMLS_CC);
+ } else {
+ new_break.paramed = 0;
+ }
+
+ cops = CG(compiler_options);
+
+ CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
+
+ new_break.code = estrndup(expr, expr_len);
+ new_break.code_len = expr_len;
+
+ Z_STRLEN(pv) = expr_len + sizeof("return ;") - 1;
+ Z_STRVAL(pv) = emalloc(Z_STRLEN(pv) + 1);
+ memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1);
+ memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, expr, expr_len);
+ Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';';
+ Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0';
+ Z_TYPE(pv) = IS_STRING;
+
+ new_break.ops = zend_compile_string(
+ &pv, "Conditional Breakpoint Code" TSRMLS_CC);
+
+ zval_dtor(&pv);
+
+ if (new_break.ops) {
+ zend_hash_index_update(
+ &PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash, &new_break,
+ sizeof(phpdbg_breakcond_t), (void**)&brake);
+
+ phpdbg_notice("Conditional breakpoint #%d added %s/%p",
+ brake->id, brake->code, brake->ops);
+
+ PHPDBG_G(flags) |= PHPDBG_HAS_COND_BP;
+ PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
+ } else {
+ phpdbg_error(
+ "Failed to compile code for expression %s", expr);
+ efree((char*)new_break.code);
+ PHPDBG_G(bp_count)--;
+ }
+ CG(compiler_options) = cops;
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_expression(const char *expr, size_t expr_len TSRMLS_DC) /* {{{ */
+{
+ zend_ulong expr_hash = zend_inline_hash_func(expr, expr_len);
+ phpdbg_breakcond_t new_break;
+
+ if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], expr_hash)) {
+ phpdbg_create_conditional_break(
+ &new_break, NULL, expr, expr_len, expr_hash TSRMLS_CC);
+ } else {
+ phpdbg_notice("Conditional break %s exists", expr);
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC) /* {{{ */
+{
+ if (input->argc > 3 && phpdbg_argv_is(2, "if")) {
+ phpdbg_breakcond_t new_break;
+ phpdbg_param_t new_param;
+
+ zend_ulong expr_hash = 0L;
+ size_t expr_len;
+ const char *join = strstr(input->string, "if");
+ const char *expr = (join) + sizeof("if");
+
+ expr_len = strlen(expr);
+ expr = phpdbg_trim(expr, expr_len, &expr_len);
+ expr_hash = zend_inline_hash_func(expr, expr_len);
+
+ {
+ /* get a clean parameter from input string */
+ size_t sparam_len = 0L;
+ char *sparam = input->string;
+
+ sparam[
+ strstr(input->string, " ") - input->string] = 0;
+ sparam_len = strlen(sparam);
+
+ switch (phpdbg_parse_param(sparam, sparam_len, &new_param TSRMLS_CC)) {
+ case EMPTY_PARAM:
+ case NUMERIC_PARAM:
+ phpdbg_clear_param(
+ &new_param TSRMLS_CC);
+ goto usage;
+
+ default: { /* do nothing */ } break;
+ }
+
+ expr_hash += phpdbg_hash_param(&new_param TSRMLS_CC);
+ }
+
+ if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], expr_hash)) {
+ phpdbg_create_conditional_break(
+ &new_break, &new_param, expr, expr_len, expr_hash TSRMLS_CC);
+ } else {
+ phpdbg_notice(
+ "Conditional break %s exists at the specified location", expr);
+ }
+
+ phpdbg_clear_param(&new_param TSRMLS_CC);
+ } else {
+usage:
+ phpdbg_error("usage: break at <func|method|file:line|address> if <expression>");
+ }
+} /* }}} */
+
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+ HashTable *breaks;
+ phpdbg_breakbase_t *brake;
+ size_t name_len = strlen(op_array->filename);
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename,
+ name_len, (void**)&breaks) == FAILURE) {
+ return NULL;
+ }
+
+ if (zend_hash_index_find(breaks, (*EG(opline_ptr))->lineno, (void**)&brake) == SUCCESS) {
+ return brake;
+ }
+
+ return NULL;
+} /* }}} */
+
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *fbc TSRMLS_DC) /* {{{ */
+{
+ const char *fname;
+ zend_op_array *ops;
+ phpdbg_breakbase_t *brake;
+
+ if (fbc->type != ZEND_USER_FUNCTION) {
+ return NULL;
+ }
+
+ ops = (zend_op_array*)fbc;
+
+ if (ops->scope) {
+ /* find method breaks here */
+ return phpdbg_find_breakpoint_method(ops TSRMLS_CC);
+ }
+
+ fname = ops->function_name;
+
+ if (!fname) {
+ fname = "main";
+ }
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname, strlen(fname), (void**)&brake) == SUCCESS) {
+ return brake;
+ }
+
+ return NULL;
+} /* }}} */
+
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array *ops TSRMLS_DC) /* {{{ */
+{
+ HashTable *class_table;
+ phpdbg_breakbase_t *brake;
+
+ if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name,
+ ops->scope->name_length, (void**)&class_table) == SUCCESS) {
+ char *lcname = zend_str_tolower_dup(ops->function_name, strlen(ops->function_name));
+ size_t lcname_len = strlen(lcname);
+
+ if (zend_hash_find(
+ class_table,
+ lcname,
+ lcname_len, (void**)&brake) == SUCCESS) {
+ efree(lcname);
+ return brake;
+ }
+
+ efree(lcname);
+ }
+
+ return NULL;
+} /* }}} */
+
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakline_t *brake;
+
+ if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE],
+ (zend_ulong) opline, (void**)&brake) == SUCCESS) {
+ return (brake->base?(phpdbg_breakbase_t *)brake->base:(phpdbg_breakbase_t *)brake);
+ }
+
+ return NULL;
+} /* }}} */
+
+static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakbase_t *brake;
+ const char *opname = phpdbg_decode_opcode(opcode);
+
+ if (memcmp(opname, PHPDBG_STRL("UNKNOWN")) == 0) {
+ return NULL;
+ }
+
+ if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE],
+ zend_hash_func(opname, strlen(opname)), (void**)&brake) == SUCCESS) {
+ return brake;
+ }
+ return NULL;
+} /* }}} */
+
+static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
+{
+ zend_function *function = (zend_function*) execute_data->function_state.function;
+
+ switch (param->type) {
+ case NUMERIC_FUNCTION_PARAM:
+ case STR_PARAM: {
+ /* function breakpoint */
+
+ if (function->type != ZEND_USER_FUNCTION) {
+ return 0;
+ }
+
+ {
+ const char *str = NULL;
+ size_t len = 0L;
+ zend_op_array *ops = (zend_op_array*)function;
+ str = ops->function_name ? ops->function_name : "main";
+ len = strlen(str);
+
+ if (len == param->len && memcmp(param->str, str, len) == SUCCESS) {
+ return param->type == STR_PARAM || execute_data->opline - ops->opcodes == param->num;
+ }
+ }
+ } break;
+
+ case FILE_PARAM: {
+ if (param->file.line == zend_get_executed_lineno(TSRMLS_C)) {
+ const char *str = zend_get_executed_filename(TSRMLS_C);
+ size_t lengths[2] = {strlen(param->file.name), strlen(str)};
+
+ if (lengths[0] == lengths[1]) {
+ return (memcmp(
+ param->file.name, str, lengths[0]) == SUCCESS);
+ }
+ }
+ } break;
+
+ case NUMERIC_METHOD_PARAM:
+ case METHOD_PARAM: {
+ if (function->type != ZEND_USER_FUNCTION) {
+ return 0;
+ }
+
+ {
+ zend_op_array *ops = (zend_op_array*) function;
+
+ if (ops->scope) {
+ size_t lengths[2] = {strlen(param->method.class), ops->scope->name_length};
+ if (lengths[0] == lengths[1] && memcmp(param->method.class, ops->scope->name, lengths[0]) == SUCCESS) {
+ lengths[0] = strlen(param->method.name);
+ lengths[1] = strlen(ops->function_name);
+
+ if (lengths[0] == lengths[1] && memcmp(param->method.name, ops->function_name, lengths[0]) == SUCCESS) {
+ return param->type == METHOD_PARAM || (execute_data->opline - ops->opcodes) == param->num;
+ }
+ }
+ }
+ }
+ } break;
+
+ case ADDR_PARAM: {
+ return ((zend_ulong)(phpdbg_opline_ptr_t)execute_data->opline == param->addr);
+ } break;
+
+ default: {
+ /* do nothing */
+ } break;
+ }
+ return 0;
+} /* }}} */
+
+static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakcond_t *bp;
+ HashPosition position;
+ int breakpoint = FAILURE;
+
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void*)&bp, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) {
+ zval *retval = NULL;
+ int orig_interactive = CG(interactive);
+ zval **orig_retval = EG(return_value_ptr_ptr);
+ zend_op_array *orig_ops = EG(active_op_array);
+ zend_op **orig_opline = EG(opline_ptr);
+
+ if (((phpdbg_breakbase_t*)bp)->disabled) {
+ continue;
+ }
+
+ if (bp->paramed) {
+ if (!phpdbg_find_breakpoint_param(&bp->param, execute_data TSRMLS_CC)) {
+ continue;
+ }
+ }
+
+ ALLOC_INIT_ZVAL(retval);
+
+ EG(return_value_ptr_ptr) = &retval;
+ EG(active_op_array) = bp->ops;
+ EG(no_extensions) = 1;
+
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+
+ CG(interactive) = 0;
+
+ zend_try {
+ PHPDBG_G(flags) |= PHPDBG_IN_COND_BP;
+ zend_execute(EG(active_op_array) TSRMLS_CC);
+#if PHP_VERSION_ID >= 50700
+ if (zend_is_true(retval TSRMLS_CC)) {
+#else
+ if (zend_is_true(retval)) {
+#endif
+ breakpoint = SUCCESS;
+ }
+ } zend_catch {
+ CG(interactive) = orig_interactive;
+
+ EG(no_extensions)=1;
+ EG(return_value_ptr_ptr) = orig_retval;
+ EG(active_op_array) = orig_ops;
+ EG(opline_ptr) = orig_opline;
+ PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP;
+ } zend_end_try();
+
+ CG(interactive) = orig_interactive;
+
+ EG(no_extensions)=1;
+ EG(return_value_ptr_ptr) = orig_retval;
+ EG(active_op_array) = orig_ops;
+ EG(opline_ptr) = orig_opline;
+ PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP;
+
+ if (breakpoint == SUCCESS) {
+ break;
+ }
+ }
+
+ return (breakpoint == SUCCESS) ? ((phpdbg_breakbase_t*)bp) : NULL;
+} /* }}} */
+
+PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data* execute_data TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakbase_t *base = NULL;
+
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED)) {
+ return NULL;
+ }
+
+ /* conditions cannot be executed by eval()'d code */
+ if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL) &&
+ (PHPDBG_G(flags) & PHPDBG_HAS_COND_BP) &&
+ (base = phpdbg_find_conditional_breakpoint(execute_data TSRMLS_CC))) {
+ goto result;
+ }
+
+ if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP) &&
+ (base = phpdbg_find_breakpoint_file(execute_data->op_array TSRMLS_CC))) {
+ goto result;
+ }
+
+ if (PHPDBG_G(flags) & (PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_SYM_BP)) {
+ /* check we are at the beginning of the stack */
+ if (execute_data->opline == EG(active_op_array)->opcodes) {
+ if ((base = phpdbg_find_breakpoint_symbol(
+ execute_data->function_state.function TSRMLS_CC))) {
+ goto result;
+ }
+ }
+ }
+
+ if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP) &&
+ (base = phpdbg_find_breakpoint_opline(execute_data->opline TSRMLS_CC))) {
+ goto result;
+ }
+
+ if ((PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) &&
+ (base = phpdbg_find_breakpoint_opcode(execute_data->opline->opcode TSRMLS_CC))) {
+ goto result;
+ }
+
+ return NULL;
+
+result:
+ /* we return nothing for disable breakpoints */
+ if (base->disabled) {
+ return NULL;
+ }
+
+ return base;
+} /* }}} */
+
+PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */
+{
+ HashTable **table;
+ HashPosition position;
+ phpdbg_breakbase_t *brake;
+
+ if ((brake = phpdbg_find_breakbase_ex(num, &table, &position TSRMLS_CC))) {
+ char *key;
+ zend_uint klen;
+ zend_ulong idx;
+ int type = brake->type;
+ char *name = NULL;
+ size_t name_len = 0L;
+
+ switch (type) {
+ case PHPDBG_BREAK_FILE:
+ case PHPDBG_BREAK_METHOD:
+ if (zend_hash_num_elements((*table)) == 1) {
+ name = estrdup(brake->name);
+ name_len = strlen(name);
+ if (zend_hash_num_elements(&PHPDBG_G(bp)[type]) == 1) {
+ PHPDBG_G(flags) &= ~(1<<(brake->type+1));
+ }
+ }
+ break;
+
+ default: {
+ if (zend_hash_num_elements((*table)) == 1) {
+ PHPDBG_G(flags) &= ~(1<<(brake->type+1));
+ }
+ }
+ }
+
+ switch (type) {
+ case PHPDBG_BREAK_FILE_OPLINE:
+ case PHPDBG_BREAK_FUNCTION_OPLINE:
+ case PHPDBG_BREAK_METHOD_OPLINE:
+ if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]) == 1) {
+ PHPDBG_G(flags) &= PHPDBG_HAS_OPLINE_BP;
+ }
+ zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], ((phpdbg_breakopline_t*)brake)->opline);
+ }
+
+ switch (zend_hash_get_current_key_ex(
+ (*table), &key, &klen, &idx, 0, &position)) {
+
+ case HASH_KEY_IS_STRING:
+ zend_hash_del((*table), key, klen);
+ break;
+
+ default:
+ zend_hash_index_del((*table), idx);
+ }
+
+ switch (type) {
+ case PHPDBG_BREAK_FILE:
+ case PHPDBG_BREAK_METHOD:
+ if (name) {
+ zend_hash_del(&PHPDBG_G(bp)[type], name, name_len);
+ efree(name);
+ }
+ break;
+ }
+
+ phpdbg_notice("Deleted breakpoint #%ld", num);
+ PHPDBG_BREAK_UNMAPPING(num);
+ } else {
+ phpdbg_error("Failed to find breakpoint #%ld", num);
+ }
+} /* }}} */
+
+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_SYM]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
+ zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
+
+ PHPDBG_G(flags) &= ~PHPDBG_BP_MASK;
+
+ PHPDBG_G(bp_count) = 0;
+} /* }}} */
+
+PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t *brake, zend_bool output TSRMLS_DC) /* {{{ */
+{
+ brake->hits++;
+
+ if (output) {
+ phpdbg_print_breakpoint(brake TSRMLS_CC);
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* {{{ */
+{
+ if (!brake)
+ goto unknown;
+
+ switch (brake->type) {
+ case PHPDBG_BREAK_FILE: {
+ phpdbg_notice("Breakpoint #%d at %s:%ld, hits: %lu",
+ ((phpdbg_breakfile_t*)brake)->id,
+ ((phpdbg_breakfile_t*)brake)->filename,
+ ((phpdbg_breakfile_t*)brake)->line,
+ ((phpdbg_breakfile_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_SYM: {
+ phpdbg_notice("Breakpoint #%d in %s() at %s:%u, hits: %lu",
+ ((phpdbg_breaksymbol_t*)brake)->id,
+ ((phpdbg_breaksymbol_t*)brake)->symbol,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakfile_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_OPLINE: {
+ phpdbg_notice("Breakpoint #%d in %#lx at %s:%u, hits: %lu",
+ ((phpdbg_breakline_t*)brake)->id,
+ ((phpdbg_breakline_t*)brake)->opline,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakline_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_METHOD_OPLINE: {
+ phpdbg_notice("Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu",
+ ((phpdbg_breakopline_t*)brake)->id,
+ ((phpdbg_breakopline_t*)brake)->class_name,
+ ((phpdbg_breakopline_t*)brake)->func_name,
+ ((phpdbg_breakopline_t*)brake)->opline_num,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakopline_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_FUNCTION_OPLINE: {
+ phpdbg_notice("Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu",
+ ((phpdbg_breakopline_t*)brake)->id,
+ ((phpdbg_breakopline_t*)brake)->func_name,
+ ((phpdbg_breakopline_t*)brake)->opline_num,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakopline_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_FILE_OPLINE: {
+ phpdbg_notice("Breakpoint #%d in %s:%lu at %s:%u, hits: %lu",
+ ((phpdbg_breakopline_t*)brake)->id,
+ ((phpdbg_breakopline_t*)brake)->class_name,
+ ((phpdbg_breakopline_t*)brake)->opline_num,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakopline_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_OPCODE: {
+ phpdbg_notice("Breakpoint #%d in %s at %s:%u, hits: %lu",
+ ((phpdbg_breakop_t*)brake)->id,
+ ((phpdbg_breakop_t*)brake)->name,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakop_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_METHOD: {
+ phpdbg_notice("Breakpoint #%d in %s::%s() at %s:%u, hits: %lu",
+ ((phpdbg_breakmethod_t*)brake)->id,
+ ((phpdbg_breakmethod_t*)brake)->class_name,
+ ((phpdbg_breakmethod_t*)brake)->func_name,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakmethod_t*)brake)->hits);
+ } break;
+
+ case PHPDBG_BREAK_COND: {
+ if (((phpdbg_breakcond_t*)brake)->paramed) {
+ char *param;
+ phpdbg_notice("Conditional breakpoint #%d: at %s if %s %s:%u, hits: %lu",
+ ((phpdbg_breakcond_t*)brake)->id,
+ phpdbg_param_tostring(&((phpdbg_breakcond_t*)brake)->param, &param TSRMLS_CC),
+ ((phpdbg_breakcond_t*)brake)->code,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakcond_t*)brake)->hits);
+ if (param)
+ free(param);
+ } else {
+ phpdbg_notice("Conditional breakpoint #%d: on %s == true %s:%u, hits: %lu",
+ ((phpdbg_breakcond_t*)brake)->id,
+ ((phpdbg_breakcond_t*)brake)->code,
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C),
+ ((phpdbg_breakcond_t*)brake)->hits);
+ }
+
+ } break;
+
+ default: {
+unknown:
+ phpdbg_notice("Unknown breakpoint at %s:%u",
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C));
+ }
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC);
+
+ if (brake) {
+ brake->disabled = 0;
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */
+{
+ phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC);
+
+ if (brake) {
+ brake->disabled = 1;
+ }
+} /* }}} */
+
+PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D) /* {{{ */
+{
+ PHPDBG_G(flags) |= PHPDBG_IS_BP_ENABLED;
+} /* }}} */
+
+PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D) { /* {{{ */
+ PHPDBG_G(flags) &= ~PHPDBG_IS_BP_ENABLED;
+} /* }}} */
+
+PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC) /* {{{ */
+{
+ HashTable **table;
+ HashPosition position;
+
+ return phpdbg_find_breakbase_ex(id, &table, &position TSRMLS_CC);
+} /* }}} */
+
+PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC) /* {{{ */
+{
+ if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id, (void**)table) == SUCCESS) {
+ phpdbg_breakbase_t *brake;
+
+ for (zend_hash_internal_pointer_reset_ex((**table), position);
+ zend_hash_get_current_data_ex((**table), (void**)&brake, position) == SUCCESS;
+ zend_hash_move_forward_ex((**table), position)) {
+
+ if (brake->id == id) {
+ return brake;
+ }
+ }
+ }
+ return NULL;
+} /* }}} */
+
+PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */
+{
+ switch (type) {
+ case PHPDBG_BREAK_SYM: if ((PHPDBG_G(flags) & PHPDBG_HAS_SYM_BP)) {
+ HashPosition position;
+ phpdbg_breaksymbol_t *brake;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("Function Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], (void**) &brake, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position)) {
+ phpdbg_writeln("#%d\t\t%s%s",
+ brake->id, brake->symbol,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ } break;
+
+ case PHPDBG_BREAK_METHOD: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_BP)) {
+ HashPosition position[2];
+ HashTable *class_table;
+ char *class_name = NULL;
+ zend_uint class_len = 0;
+ zend_ulong class_idx = 0L;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("Method Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0]);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], (void**) &class_table, &position[0]) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0])) {
+
+ if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD],
+ &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
+ phpdbg_breakmethod_t *brake;
+
+ for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]);
+ zend_hash_get_current_data_ex(class_table, (void**)&brake, &position[1]) == SUCCESS;
+ zend_hash_move_forward_ex(class_table, &position[1])) {
+ phpdbg_writeln("#%d\t\t%s::%s%s",
+ brake->id, brake->class_name, brake->func_name,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ }
+
+ }
+ } break;
+
+ case PHPDBG_BREAK_FILE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP)) {
+ HashPosition position[2];
+ HashTable *points;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("File Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0]);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], (void**) &points, &position[0]) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0])) {
+ phpdbg_breakfile_t *brake;
+
+ for (zend_hash_internal_pointer_reset_ex(points, &position[1]);
+ zend_hash_get_current_data_ex(points, (void**)&brake, &position[1]) == SUCCESS;
+ zend_hash_move_forward_ex(points, &position[1])) {
+ phpdbg_writeln("#%d\t\t%s:%lu%s",
+ brake->id, brake->filename, brake->line,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ }
+
+ } break;
+
+ case PHPDBG_BREAK_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)) {
+ HashPosition position;
+ phpdbg_breakline_t *brake;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("Opline Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void**) &brake, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position)) {
+ switch (brake->type) {
+ case PHPDBG_BREAK_METHOD_OPLINE:
+ case PHPDBG_BREAK_FUNCTION_OPLINE:
+ case PHPDBG_BREAK_FILE_OPLINE:
+ phpdbg_writeln("#%d\t\t%#lx\t\t(%s breakpoint)%s", brake->id, brake->opline,
+ brake->type == PHPDBG_BREAK_METHOD_OPLINE?"method":
+ brake->type == PHPDBG_BREAK_FUNCTION_OPLINE?"function":
+ brake->type == PHPDBG_BREAK_FILE_OPLINE?"file":
+ "--- error ---",
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ break;
+
+ default:
+ phpdbg_writeln("#%d\t\t%#lx", brake->id, brake->opline);
+ break;
+ }
+ }
+ } break;
+
+ case PHPDBG_BREAK_METHOD_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_OPLINE_BP)) {
+ HashPosition position[3];
+ HashTable *class_table, *method_table;
+ char *class_name = NULL, *method_name = NULL;
+ zend_uint class_len = 0, method_len = 0;
+ zend_ulong class_idx = 0L, method_idx = 0L;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("Method opline Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0]);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], (void**) &class_table, &position[0]) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0])) {
+
+ if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
+ &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
+
+ for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]);
+ zend_hash_get_current_data_ex(class_table, (void**) &method_table, &position[1]) == SUCCESS;
+ zend_hash_move_forward_ex(class_table, &position[1])) {
+
+ if (zend_hash_get_current_key_ex(class_table,
+ &method_name, &method_len, &method_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
+
+ phpdbg_breakopline_t *brake;
+
+ for (zend_hash_internal_pointer_reset_ex(method_table, &position[2]);
+ zend_hash_get_current_data_ex(method_table, (void**)&brake, &position[2]) == SUCCESS;
+ zend_hash_move_forward_ex(method_table, &position[2])) {
+ phpdbg_writeln("#%d\t\t%s::%s opline %ld%s",
+ brake->id, brake->class_name, brake->func_name, brake->opline_num,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ }
+ }
+ }
+
+ }
+ } break;
+
+ case PHPDBG_BREAK_FUNCTION_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FUNCTION_OPLINE_BP)) {
+ HashPosition position[2];
+ HashTable *function_table;
+ char *function_name = NULL;
+ zend_uint function_len = 0;
+ zend_ulong function_idx = 0L;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("Function opline Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0]);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], (void**) &function_table, &position[0]) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0])) {
+
+ if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE],
+ &function_name, &function_len, &function_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
+
+ phpdbg_breakopline_t *brake;
+
+ for (zend_hash_internal_pointer_reset_ex(function_table, &position[1]);
+ zend_hash_get_current_data_ex(function_table, (void**)&brake, &position[1]) == SUCCESS;
+ zend_hash_move_forward_ex(function_table, &position[1])) {
+ phpdbg_writeln("#%d\t\t%s opline %ld%s",
+ brake->id, brake->func_name, brake->opline_num,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ }
+
+ }
+ } break;
+
+ case PHPDBG_BREAK_FILE_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_OPLINE_BP)) {
+ HashPosition position[2];
+ HashTable *file_table;
+ char *file_name = NULL;
+ zend_uint file_len = 0;
+ zend_ulong file_idx = 0L;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("File opline Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0]);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], (void**) &file_table, &position[0]) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0])) {
+
+ if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE],
+ &file_name, &file_len, &file_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
+
+ phpdbg_breakopline_t *brake;
+
+ for (zend_hash_internal_pointer_reset_ex(file_table, &position[1]);
+ zend_hash_get_current_data_ex(file_table, (void**)&brake, &position[1]) == SUCCESS;
+ zend_hash_move_forward_ex(file_table, &position[1])) {
+ phpdbg_writeln("#%d\t\t%s opline %ld%s",
+ brake->id, brake->class_name, brake->opline_num,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ }
+ }
+ } break;
+
+ case PHPDBG_BREAK_COND: if ((PHPDBG_G(flags) & PHPDBG_HAS_COND_BP)) {
+ HashPosition position;
+ phpdbg_breakcond_t *brake;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("Conditional Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void**) &brake, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) {
+ if (brake->paramed) {
+ switch (brake->param.type) {
+ case STR_PARAM:
+ phpdbg_writeln("#%d\t\tat %s if %s%s",
+ brake->id,
+ brake->param.str,
+ brake->code,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ break;
+
+ case NUMERIC_FUNCTION_PARAM:
+ phpdbg_writeln("#%d\t\tat %s#%ld if %s%s",
+ brake->id,
+ brake->param.str,
+ brake->param.num,
+ brake->code,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ break;
+
+ case METHOD_PARAM:
+ phpdbg_writeln("#%d\t\tat %s::%s if %s%s",
+ brake->id,
+ brake->param.method.class,
+ brake->param.method.name,
+ brake->code,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ break;
+
+ case NUMERIC_METHOD_PARAM:
+ phpdbg_writeln("#%d\t\tat %s::%s#%ld if %s%s",
+ brake->id,
+ brake->param.method.class,
+ brake->param.method.name,
+ brake->param.num,
+ brake->code,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ break;
+
+ case FILE_PARAM:
+ phpdbg_writeln("#%d\t\tat %s:%lu if %s%s",
+ brake->id,
+ brake->param.file.name,
+ brake->param.file.line,
+ brake->code,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ break;
+
+ case ADDR_PARAM:
+ phpdbg_writeln("#%d\t\tat #%lx if %s%s",
+ brake->id,
+ brake->param.addr,
+ brake->code,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ break;
+
+ default:
+ phpdbg_error("Invalid parameter type for conditional breakpoint");
+ return;
+ }
+ } else {
+ phpdbg_writeln("#%d\t\tif %s%s",
+ brake->id, brake->code,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ }
+ } break;
+
+ case PHPDBG_BREAK_OPCODE: if (PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) {
+ HashPosition position;
+ phpdbg_breakop_t *brake;
+
+ phpdbg_writeln(SEPARATE);
+ phpdbg_writeln("Opcode Breakpoints:");
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position);
+ zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], (void**) &brake, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position)) {
+ phpdbg_writeln("#%d\t\t%s%s",
+ brake->id, brake->name,
+ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
+ }
+ } break;
+ }
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_bp.h b/sapi/phpdbg/phpdbg_bp.h
new file mode 100644
index 000000000..b1a9ddf47
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_bp.h
@@ -0,0 +1,146 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_BP_H
+#define PHPDBG_BP_H
+
+/* {{{ */
+typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */
+
+/* {{{ breakpoint base structure */
+#define phpdbg_breakbase(name) \
+ int id; \
+ zend_uchar type; \
+ zend_ulong hits; \
+ zend_bool disabled; \
+ const char *name /* }}} */
+
+/* {{{ breakpoint base */
+typedef struct _phpdbg_breakbase_t {
+ phpdbg_breakbase(name);
+} phpdbg_breakbase_t; /* }}} */
+
+/**
+ * Breakpoint file-based representation
+ */
+typedef struct _phpdbg_breakfile_t {
+ phpdbg_breakbase(filename);
+ long line;
+} phpdbg_breakfile_t;
+
+/**
+ * Breakpoint symbol-based representation
+ */
+typedef struct _phpdbg_breaksymbol_t {
+ phpdbg_breakbase(symbol);
+} phpdbg_breaksymbol_t;
+
+/**
+ * Breakpoint method based representation
+ */
+typedef struct _phpdbg_breakmethod_t {
+ phpdbg_breakbase(class_name);
+ size_t class_len;
+ const char *func_name;
+ size_t func_len;
+} phpdbg_breakmethod_t;
+
+/**
+ * Breakpoint opline num based representation
+ */
+typedef struct _phpdbg_breakopline_t {
+ phpdbg_breakbase(func_name);
+ size_t func_len;
+ const char *class_name;
+ size_t class_len;
+ zend_ulong opline_num;
+ zend_ulong opline;
+} phpdbg_breakopline_t;
+
+/**
+ * Breakpoint opline based representation
+ */
+typedef struct _phpdbg_breakline_t {
+ phpdbg_breakbase(name);
+ zend_ulong opline;
+ phpdbg_breakopline_t *base;
+} phpdbg_breakline_t;
+
+/**
+ * Breakpoint opcode based representation
+ */
+typedef struct _phpdbg_breakop_t {
+ phpdbg_breakbase(name);
+ zend_ulong hash;
+} phpdbg_breakop_t;
+
+/**
+ * Breakpoint condition based representation
+ */
+typedef struct _phpdbg_breakcond_t {
+ phpdbg_breakbase(code);
+ size_t code_len;
+ zend_bool paramed;
+ phpdbg_param_t param;
+ zend_ulong hash;
+ zend_op_array *ops;
+} phpdbg_breakcond_t;
+
+/* {{{ Opline 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); /* }}} */
+
+/* {{{ Breakpoint Creation API */
+PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_expression(const char* expression, size_t expression_len TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC); /* }}} */
+
+/* {{{ Breakpoint Detection API */
+PHPDBG_API phpdbg_breakbase_t* phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC); /* }}} */
+
+/* {{{ Misc Breakpoint API */
+PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t* brake, zend_bool output TSRMLS_DC);
+PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC);
+PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t* brake TSRMLS_DC);
+PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D);
+PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D);
+PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC);
+PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D);
+PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC);
+PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC);
+PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D); /* }}} */
+
+/* {{{ Breakbase API */
+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, HashPosition *position TSRMLS_DC); /* }}} */
+
+/* {{{ Breakpoint Exportation API */
+PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */
+
+#endif /* PHPDBG_BP_H */
diff --git a/sapi/phpdbg/phpdbg_break.c b/sapi/phpdbg/phpdbg_break.c
new file mode 100644
index 000000000..f56f76fac
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_break.c
@@ -0,0 +1,155 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg.h"
+#include "phpdbg_print.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_opcode.h"
+#include "phpdbg_break.h"
+#include "phpdbg_bp.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+PHPDBG_BREAK(file) /* {{{ */
+{
+ switch (param->type) {
+ case FILE_PARAM:
+ phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(method) /* {{{ */
+{
+ switch (param->type) {
+ case METHOD_PARAM:
+ phpdbg_set_breakpoint_method(param->method.class, param->method.name TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(address) /* {{{ */
+{
+ switch (param->type) {
+ case ADDR_PARAM:
+ phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC);
+ break;
+
+ case NUMERIC_METHOD_PARAM:
+ phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num TSRMLS_CC);
+ break;
+
+ case NUMERIC_FUNCTION_PARAM:
+ phpdbg_set_breakpoint_function_opline(param->str, param->num TSRMLS_CC);
+ break;
+
+ case FILE_PARAM:
+ phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(on) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM:
+ phpdbg_set_breakpoint_expression(param->str, param->len TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(at) /* {{{ */
+{
+ phpdbg_set_breakpoint_at(param, input TSRMLS_CC);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(lineno) /* {{{ */
+{
+ switch (param->type) {
+ case NUMERIC_PARAM: {
+ if (PHPDBG_G(exec)) {
+ phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC);
+ } else {
+ phpdbg_error("Execution context not set!");
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(func) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM:
+ phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(op) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM:
+ phpdbg_set_breakpoint_opcode(param->str, param->len TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_BREAK(del) /* {{{ */
+{
+ switch (param->type) {
+ case NUMERIC_PARAM: {
+ phpdbg_delete_breakpoint(param->num TSRMLS_CC);
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_break.h b/sapi/phpdbg/phpdbg_break.h
new file mode 100644
index 000000000..f90e351d6
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_break.h
@@ -0,0 +1,58 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_BREAK_H
+#define PHPDBG_BREAK_H
+
+#include "TSRM.h"
+#include "phpdbg_cmd.h"
+
+#define PHPDBG_BREAK(name) PHPDBG_COMMAND(break_##name)
+
+/**
+ * Printer Forward Declarations
+ */
+PHPDBG_BREAK(file);
+PHPDBG_BREAK(func);
+PHPDBG_BREAK(method);
+PHPDBG_BREAK(address);
+PHPDBG_BREAK(at);
+PHPDBG_BREAK(op);
+PHPDBG_BREAK(on);
+PHPDBG_BREAK(lineno);
+PHPDBG_BREAK(del);
+
+/**
+ * Commands
+ */
+static const phpdbg_command_t phpdbg_break_commands[] = {
+ PHPDBG_COMMAND_D_EX(file, "specify breakpoint by file:line", 'F', break_file, NULL, 1),
+ PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, 1),
+ PHPDBG_COMMAND_D_EX(method, "specify breakpoint by class::method", 'm', break_method, NULL, 1),
+ PHPDBG_COMMAND_D_EX(address, "specify breakpoint by address", 'a', break_address, NULL, 1),
+ PHPDBG_COMMAND_D_EX(op, "specify breakpoint by opcode", 'O', break_op, NULL, 1),
+ PHPDBG_COMMAND_D_EX(on, "specify breakpoint by condition", 'o', break_on, NULL, 1),
+ PHPDBG_COMMAND_D_EX(at, "specify breakpoint by location and condition", 'A', break_at, NULL, 1),
+ PHPDBG_COMMAND_D_EX(lineno, "specify breakpoint by line of currently executing file", 'l', break_lineno, NULL, 1),
+ PHPDBG_COMMAND_D_EX(del, "delete breakpoint by identifier number", 'd', break_del, NULL, 1),
+ PHPDBG_END_COMMAND
+};
+
+#endif /* PHPDBG_BREAK_H */
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c
new file mode 100644
index 000000000..c70085124
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_cmd.c
@@ -0,0 +1,682 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg.h"
+#include "phpdbg_cmd.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_set.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM:
+ return "empty";
+ case ADDR_PARAM:
+ return "address";
+ case NUMERIC_PARAM:
+ return "numeric";
+ case METHOD_PARAM:
+ return "method";
+ case NUMERIC_FUNCTION_PARAM:
+ return "function opline";
+ case NUMERIC_METHOD_PARAM:
+ return "method opline";
+ case FILE_PARAM:
+ return "file or file opline";
+ case STR_PARAM:
+ return "string";
+ default: /* this is bad */
+ return "unknown";
+ }
+}
+
+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) {
+ switch (param->type) {
+ case FILE_PARAM:
+ efree(param->file.name);
+ break;
+ case METHOD_PARAM:
+ efree(param->method.class);
+ efree(param->method.name);
+ break;
+ case STR_PARAM:
+ efree(param->str);
+ break;
+ default:
+ break;
+ }
+ }
+
+} /* }}} */
+
+PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM:
+ asprintf(pointer,
+ "%s", param->str);
+ break;
+
+ case ADDR_PARAM:
+ asprintf(pointer,
+ "%#lx", param->addr);
+ break;
+
+ case NUMERIC_PARAM:
+ asprintf(pointer,
+ "%li",
+ param->num);
+ break;
+
+ case METHOD_PARAM:
+ asprintf(pointer,
+ "%s::%s",
+ param->method.class,
+ param->method.name);
+ break;
+
+ case FILE_PARAM:
+ if (param->num) {
+ asprintf(pointer,
+ "%s:%lu#%lu",
+ param->file.name,
+ param->file.line,
+ param->num);
+ } else {
+ asprintf(pointer,
+ "%s:%lu",
+ param->file.name,
+ param->file.line);
+ }
+ break;
+
+ case NUMERIC_FUNCTION_PARAM:
+ asprintf(pointer,
+ "%s#%lu", param->str, param->num);
+ break;
+
+ case NUMERIC_METHOD_PARAM:
+ asprintf(pointer,
+ "%s::%s#%lu",
+ param->method.class,
+ param->method.name,
+ param->num);
+ break;
+
+ default:
+ asprintf(pointer,
+ "%s", "unknown");
+ }
+
+ return *pointer;
+} /* }}} */
+
+PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest TSRMLS_DC) /* {{{ */
+{
+ switch ((dest->type = src->type)) {
+ case STR_PARAM:
+ dest->str = estrndup(src->str, src->len);
+ dest->len = src->len;
+ break;
+
+ case ADDR_PARAM:
+ dest->addr = src->addr;
+ break;
+
+ case NUMERIC_PARAM:
+ dest->num = src->num;
+ break;
+
+ case METHOD_PARAM:
+ dest->method.class = estrdup(src->method.class);
+ dest->method.name = estrdup(src->method.name);
+ break;
+
+ case FILE_PARAM:
+ dest->file.name = estrdup(src->file.name);
+ dest->file.line = src->file.line;
+ if (src->num)
+ dest->num = src->num;
+ break;
+
+ case NUMERIC_FUNCTION_PARAM:
+ dest->str = estrndup(src->str, src->len);
+ dest->num = src->num;
+ dest->len = src->len;
+ break;
+
+ case NUMERIC_METHOD_PARAM:
+ dest->method.class = estrdup(src->method.class);
+ dest->method.name = estrdup(src->method.name);
+ dest->num = src->num;
+ break;
+
+ case EMPTY_PARAM: { /* do nothing */ } break;
+ }
+} /* }}} */
+
+PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
+{
+ zend_ulong hash = param->type;
+
+ switch (param->type) {
+ case STR_PARAM:
+ hash += zend_inline_hash_func(param->str, param->len);
+ break;
+
+ case METHOD_PARAM:
+ hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
+ hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
+ break;
+
+ case FILE_PARAM:
+ hash += zend_inline_hash_func(param->file.name, strlen(param->file.name));
+ hash += param->file.line;
+ if (param->num)
+ hash += param->num;
+ break;
+
+ case ADDR_PARAM:
+ hash += param->addr;
+ break;
+
+ case NUMERIC_PARAM:
+ hash += param->num;
+ break;
+
+ case NUMERIC_FUNCTION_PARAM:
+ hash += zend_inline_hash_func(param->str, param->len);
+ hash += param->num;
+ break;
+
+ case NUMERIC_METHOD_PARAM:
+ hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
+ hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
+ if (param->num)
+ hash+= param->num;
+ break;
+
+ case EMPTY_PARAM: { /* do nothing */ } break;
+ }
+
+ return hash;
+} /* }}} */
+
+PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_param_t *r TSRMLS_DC) /* {{{ */
+{
+ if (l && r) {
+ if (l->type == r->type) {
+ switch (l->type) {
+
+ case NUMERIC_FUNCTION_PARAM:
+ if (l->num != r->num) {
+ break;
+ }
+ /* break intentionally omitted */
+
+ case STR_PARAM:
+ return (l->len == r->len) &&
+ (memcmp(l->str, r->str, l->len) == SUCCESS);
+
+ case NUMERIC_PARAM:
+ return (l->num == r->num);
+
+ case ADDR_PARAM:
+ return (l->addr == r->addr);
+
+ case FILE_PARAM: {
+ if (l->file.line == r->file.line) {
+ size_t lengths[2] = {
+ strlen(l->file.name), strlen(r->file.name)};
+
+ if (lengths[0] == lengths[1]) {
+ if ((!l->num && !r->num) || (l->num == r->num)) {
+ return (memcmp(
+ l->file.name, r->file.name, lengths[0]) == SUCCESS);
+ }
+ }
+ }
+ } break;
+
+ case NUMERIC_METHOD_PARAM:
+ if (l->num != r->num) {
+ break;
+ }
+ /* break intentionally omitted */
+
+ case METHOD_PARAM: {
+ size_t lengths[2] = {
+ strlen(l->method.class), strlen(r->method.class)};
+ if (lengths[0] == lengths[1]) {
+ if (memcmp(l->method.class, r->method.class, lengths[0]) == SUCCESS) {
+ lengths[0] = strlen(l->method.name);
+ lengths[1] = strlen(r->method.name);
+
+ if (lengths[0] == lengths[1]) {
+ return (memcmp(
+ l->method.name, r->method.name, lengths[0]) == SUCCESS);
+ }
+ }
+ }
+ } break;
+
+ case EMPTY_PARAM:
+ return 1;
+ }
+ }
+ }
+ return 0;
+} /* }}} */
+
+PHPDBG_API phpdbg_input_t **phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC) /* {{{ */
+{
+ char *p;
+ char b[PHPDBG_MAX_CMD];
+ int l=0;
+ enum states {
+ IN_BETWEEN,
+ IN_WORD,
+ IN_STRING
+ } state = IN_BETWEEN;
+ phpdbg_input_t **argv = NULL;
+
+ argv = (phpdbg_input_t**) emalloc(sizeof(phpdbg_input_t*));
+ (*argc) = 0;
+
+#define RESET_STATE() do { \
+ phpdbg_input_t *arg = emalloc(sizeof(phpdbg_input_t)); \
+ if (arg) { \
+ b[l]=0; \
+ arg->length = l; \
+ arg->string = estrndup(b, arg->length); \
+ arg->argv = NULL; \
+ arg->argc = 0; \
+ argv = (phpdbg_input_t**) erealloc(argv, sizeof(phpdbg_input_t*) * ((*argc)+1)); \
+ argv[(*argc)++] = arg; \
+ l = 0; \
+ } \
+ state = IN_BETWEEN; \
+} while (0)
+
+ for (p = buffer; *p != '\0'; p++) {
+ int c = (unsigned char) *p;
+ switch (state) {
+ case IN_BETWEEN:
+ if (isspace(c)) {
+ continue;
+ }
+ if (c == '"') {
+ state = IN_STRING;
+ continue;
+ }
+ state = IN_WORD;
+ b[l++]=c;
+ continue;
+
+ case IN_STRING:
+ if (c == '"') {
+ if (buffer[(p - buffer)-1] == '\\') {
+ b[l-1]=c;
+ continue;
+ }
+ RESET_STATE();
+ } else {
+ b[l++]=c;
+ }
+ continue;
+
+ case IN_WORD:
+ if (isspace(c)) {
+ RESET_STATE();
+ } else {
+ b[l++]=c;
+ }
+ continue;
+ }
+ }
+
+ switch (state) {
+ case IN_WORD: {
+ RESET_STATE();
+ } break;
+
+ case IN_STRING:
+ phpdbg_error(
+ "Malformed command line (unclosed quote) @ %ld: %s!",
+ (p - buffer)-1, &buffer[(p - buffer)-1]);
+ break;
+
+ case IN_BETWEEN:
+ break;
+ }
+
+ if ((*argc) == 0) {
+ /* not needed */
+ efree(argv);
+
+ /* to be sure */
+ return NULL;
+ }
+
+ return argv;
+} /* }}} */
+
+PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
+{
+ phpdbg_input_t *buffer = NULL;
+ char *cmd = NULL;
+#ifndef HAVE_LIBREADLINE
+ char buf[PHPDBG_MAX_CMD];
+#endif
+
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) &&
+ (buffered == NULL)) {
+ fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
+ }
+
+ if (buffered == NULL) {
+disconnect:
+ if (0) {
+ PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
+ zend_bailout();
+ return NULL;
+ }
+
+#ifndef HAVE_LIBREADLINE
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+ if (!phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) {
+ goto disconnect;
+ }
+ }
+
+ /* note: EOF is ignored */
+readline:
+ if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
+ /* the user has gone away */
+ if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+ goto disconnect;
+ } else goto readline;
+ }
+
+ cmd = buf;
+#else
+ /* note: EOF makes readline write prompt again in local console mode */
+readline:
+ if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+ char buf[PHPDBG_MAX_CMD];
+ if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
+ cmd = buf;
+ } else goto disconnect;
+ } else cmd = readline(phpdbg_get_prompt(TSRMLS_C));
+
+ if (!cmd) {
+ goto readline;
+ }
+
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+ add_history(cmd);
+ }
+#endif
+ } else cmd = buffered;
+
+ /* allocate and sanitize buffer */
+ buffer = (phpdbg_input_t*) ecalloc(1, sizeof(phpdbg_input_t));
+ if (!buffer) {
+ return NULL;
+ }
+
+ buffer->string = phpdbg_trim(cmd, strlen(cmd), &buffer->length);
+
+ /* store constant pointer to start of buffer */
+ buffer->start = (char* const*) buffer->string;
+
+ buffer->argv = phpdbg_read_argv(
+ buffer->string, &buffer->argc TSRMLS_CC);
+
+#ifdef PHPDBG_DEBUG
+ if (buffer->argc) {
+ int arg = 0;
+
+ while (arg < buffer->argc) {
+ phpdbg_debug(
+ "argv %d=%s", arg, buffer->argv[arg]->string);
+ arg++;
+ }
+ }
+#endif
+
+#ifdef HAVE_LIBREADLINE
+ if (!buffered && cmd &&
+ !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+ free(cmd);
+ }
+#endif
+
+ return buffer;
+ }
+
+ return NULL;
+} /* }}} */
+
+PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC) /* {{{ */
+{
+ if (argv) {
+ if (argc) {
+ int arg;
+ for (arg=0; arg<argc; arg++) {
+ phpdbg_destroy_input(
+ &argv[arg] TSRMLS_CC);
+ }
+ }
+ efree(argv);
+ }
+
+} /* }}} */
+
+PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t **input TSRMLS_DC) /*{{{ */
+{
+ if (*input) {
+ if ((*input)->string) {
+ efree((*input)->string);
+ }
+
+ phpdbg_destroy_argv(
+ (*input)->argv, (*input)->argc TSRMLS_CC);
+
+ efree(*input);
+ }
+} /* }}} */
+
+PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *input TSRMLS_DC) /* {{{ */
+{
+ int rc = FAILURE;
+
+ if (input->argc > 0) {
+ while (command && command->name && command->handler) {
+ if (((command->name_len == input->argv[0]->length) &&
+ (memcmp(command->name, input->argv[0]->string, command->name_len) == SUCCESS)) ||
+ (command->alias &&
+ (input->argv[0]->length == 1) &&
+ (command->alias == *input->argv[0]->string))) {
+
+ phpdbg_param_t param;
+
+ param.type = EMPTY_PARAM;
+
+ if (input->argc > 1) {
+ if (command->subs) {
+ phpdbg_input_t sub = *input;
+
+ sub.string += input->argv[0]->length;
+ sub.length -= input->argv[0]->length;
+
+ sub.string = phpdbg_trim(
+ sub.string, sub.length, &sub.length);
+
+ sub.argc--;
+ sub.argv++;
+
+ phpdbg_debug(
+ "trying sub commands in \"%s\" for \"%s\" with %d arguments",
+ command->name, sub.argv[0]->string, sub.argc-1);
+
+ if (phpdbg_do_cmd(command->subs, &sub TSRMLS_CC) == SUCCESS) {
+ efree(sub.string);
+ return SUCCESS;
+ }
+
+ efree(sub.string);
+ }
+
+ /* no sub command found */
+ {
+ char *store = input->string;
+
+ input->string += input->argv[0]->length;
+ input->length -= input->argv[0]->length;
+
+ input->string = phpdbg_trim(
+ input->string, input->length, &input->length);
+
+ efree(store);
+ }
+
+ /* pass parameter on */
+ phpdbg_parse_param(
+ input->string,
+ input->length,
+ &param TSRMLS_CC);
+ }
+
+ phpdbg_debug(
+ "found command %s for %s with %d arguments",
+ command->name, input->argv[0]->string, input->argc-1);
+ {
+ int arg;
+ for (arg=1; arg<input->argc; arg++) {
+ phpdbg_debug(
+ "\t#%d: [%s=%zu]",
+ arg,
+ input->argv[arg]->string,
+ input->argv[arg]->length);
+ }
+ }
+
+ rc = command->handler(&param, input TSRMLS_CC);
+
+ /* only set last command when it is worth it! */
+ if ((rc != FAILURE) &&
+ !(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) {
+ PHPDBG_G(lcmd) = (phpdbg_command_t*) command;
+ phpdbg_clear_param(
+ &PHPDBG_G(lparam) TSRMLS_CC);
+ PHPDBG_G(lparam) = param;
+ }
+ break;
+ }
+ command++;
+ }
+ } else {
+ /* this should NEVER happen */
+ phpdbg_error(
+ "No function executed!!");
+ }
+
+ return rc;
+} /* }}} */
+
diff --git a/sapi/phpdbg/phpdbg_cmd.h b/sapi/phpdbg/phpdbg_cmd.h
new file mode 100644
index 000000000..c86f92bb4
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_cmd.h
@@ -0,0 +1,169 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_CMD_H
+#define PHPDBG_CMD_H
+
+#include "TSRM.h"
+
+typedef struct _phpdbg_command_t phpdbg_command_t;
+
+/* {{{ Command and Parameter */
+enum {
+ NO_ARG = 0,
+ REQUIRED_ARG,
+ OPTIONAL_ARG
+};
+
+typedef enum {
+ EMPTY_PARAM = 0,
+ ADDR_PARAM,
+ FILE_PARAM,
+ METHOD_PARAM,
+ STR_PARAM,
+ NUMERIC_PARAM,
+ NUMERIC_FUNCTION_PARAM,
+ NUMERIC_METHOD_PARAM
+} phpdbg_param_type;
+
+typedef struct _phpdbg_input_t phpdbg_input_t;
+
+struct _phpdbg_input_t {
+ char * const *start;
+ char *string;
+ size_t length;
+ phpdbg_input_t **argv;
+ int argc;
+};
+
+typedef struct _phpdbg_param {
+ phpdbg_param_type type;
+ long num;
+ zend_ulong addr;
+ struct {
+ char *name;
+ long line;
+ } file;
+ struct {
+ char *class;
+ char *name;
+ } method;
+ char *str;
+ size_t len;
+} phpdbg_param_t;
+
+typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t*, const phpdbg_input_t* TSRMLS_DC);
+
+struct _phpdbg_command_t {
+ const char *name; /* Command name */
+ size_t name_len; /* Command name length */
+ const char *tip; /* Menu tip */
+ size_t tip_len; /* Menu tip length */
+ char alias; /* Alias */
+ phpdbg_command_handler_t handler; /* Command handler */
+ const phpdbg_command_t *subs; /* Sub Commands */
+ char arg_type; /* Accept args? */
+};
+/* }}} */
+
+/* {{{ misc */
+#define PHPDBG_STRL(s) s, sizeof(s)-1
+#define PHPDBG_MAX_CMD 500
+#define PHPDBG_FRAME(v) (PHPDBG_G(frame).v)
+#define PHPDBG_EX(v) (EG(current_execute_data)->v)
+
+typedef struct {
+ int num;
+ zend_execute_data *execute_data;
+} phpdbg_frame_t;
+/* }}} */
+
+
+
+/*
+* Workflow:
+* 1) read input
+* input takes the line from console, creates argc/argv
+* 2) parse parameters into suitable types based on arg_type
+* takes input from 1) and arg_type and creates parameters
+* 3) do command
+* executes commands
+* 4) destroy parameters
+* cleans up what was allocated by creation of parameters
+* 5) destroy input
+* cleans up what was allocated by creation of input
+*/
+
+/*
+* Input Management
+*/
+PHPDBG_API phpdbg_input_t* phpdbg_read_input(char *buffered TSRMLS_DC);
+PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t** TSRMLS_DC);
+
+/*
+* Argument Management
+*/
+PHPDBG_API phpdbg_input_t** phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC);
+PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC);
+#define phpdbg_argv_is(n, s) \
+ (memcmp(input->argv[n]->string, s, input->argv[n]->length) == SUCCESS)
+
+/*
+* 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);
+PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t * TSRMLS_DC);
+PHPDBG_API const char* phpdbg_get_param_type(const phpdbg_param_t* TSRMLS_DC);
+PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC);
+
+/*
+* Command Executor
+*/
+PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t*, phpdbg_input_t* TSRMLS_DC);
+
+/**
+ * Command Declarators
+ */
+#define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name
+
+#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, has_args) \
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, has_args}
+
+#define PHPDBG_COMMAND_D(name, tip, alias, children, has_args) \
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, has_args}
+
+#define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC)
+
+#define PHPDBG_COMMAND_ARGS param, input TSRMLS_CC
+
+#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0'}
+
+/*
+* Default Switch Case
+*/
+#define phpdbg_default_switch_case() \
+ default: \
+ phpdbg_error("Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \
+ break
+
+#endif /* PHPDBG_CMD_H */
diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c
new file mode 100644
index 000000000..de02addc1
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_frame.c
@@ -0,0 +1,206 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend.h"
+#include "phpdbg.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_frame.h"
+#include "phpdbg_list.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+void phpdbg_restore_frame(TSRMLS_D) /* {{{ */
+{
+ if (PHPDBG_FRAME(num) == 0) {
+ return;
+ }
+
+ PHPDBG_FRAME(num) = 0;
+
+ /* move things back */
+ EG(current_execute_data) = PHPDBG_FRAME(execute_data);
+
+ EG(opline_ptr) = &PHPDBG_EX(opline);
+ EG(active_op_array) = PHPDBG_EX(op_array);
+ EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
+ EG(active_symbol_table) = PHPDBG_EX(symbol_table);
+ EG(This) = PHPDBG_EX(current_this);
+ EG(scope) = PHPDBG_EX(current_scope);
+ EG(called_scope) = PHPDBG_EX(current_called_scope);
+} /* }}} */
+
+void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
+{
+ zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data);
+ int i = 0;
+
+ if (PHPDBG_FRAME(num) == frame) {
+ phpdbg_notice("Already in frame #%d", frame);
+ return;
+ }
+
+ while (execute_data) {
+ if (i++ == frame) {
+ break;
+ }
+
+ do {
+ execute_data = execute_data->prev_execute_data;
+ } while (execute_data && execute_data->opline == NULL);
+ }
+
+ if (execute_data == NULL) {
+ phpdbg_error("No frame #%d", frame);
+ return;
+ }
+
+ phpdbg_restore_frame(TSRMLS_C);
+
+ if (frame > 0) {
+ PHPDBG_FRAME(num) = frame;
+
+ /* backup things and jump back */
+ PHPDBG_FRAME(execute_data) = EG(current_execute_data);
+ EG(current_execute_data) = execute_data;
+
+ EG(opline_ptr) = &PHPDBG_EX(opline);
+ EG(active_op_array) = PHPDBG_EX(op_array);
+ PHPDBG_FRAME(execute_data)->original_return_value = EG(return_value_ptr_ptr);
+ EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
+ EG(active_symbol_table) = PHPDBG_EX(symbol_table);
+ EG(This) = PHPDBG_EX(current_this);
+ EG(scope) = PHPDBG_EX(current_scope);
+ EG(called_scope) = PHPDBG_EX(current_called_scope);
+ }
+
+ phpdbg_notice("Switched to frame #%d", frame);
+ phpdbg_list_file(
+ zend_get_executed_filename(TSRMLS_C),
+ 3,
+ zend_get_executed_lineno(TSRMLS_C)-1,
+ zend_get_executed_lineno(TSRMLS_C)
+ TSRMLS_CC
+ );
+} /* }}} */
+
+static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */
+{
+ zval **funcname, **class, **type, **args, **argstmp;
+ char is_class;
+
+ zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"),
+ (void **)&funcname);
+
+ if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp),
+ "object", sizeof("object"), (void **)&class)) == FAILURE) {
+ is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"),
+ (void **)&class);
+ } else {
+ zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class),
+ (zend_uint *)&Z_STRLEN_PP(class) TSRMLS_CC);
+ }
+
+ if (is_class == SUCCESS) {
+ zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type);
+ }
+
+ phpdbg_write("%s%s%s(",
+ is_class == FAILURE?"":Z_STRVAL_PP(class),
+ is_class == FAILURE?"":Z_STRVAL_PP(type),
+ Z_STRVAL_PP(funcname)
+ );
+
+ if (zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"),
+ (void **)&args) == SUCCESS) {
+ HashPosition iterator;
+ const zend_function *func = phpdbg_get_function(
+ Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC);
+ const zend_arg_info *arginfo = func ? func->common.arg_info : NULL;
+ int j = 0, m = func ? func->common.num_args : 0;
+ zend_bool is_variadic = 0;
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator);
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args),
+ (void **) &argstmp, &iterator) == SUCCESS) {
+ if (j) {
+ phpdbg_write(", ");
+ }
+ if (m && j < m) {
+#if PHP_VERSION_ID >= 50600
+ is_variadic = arginfo[j].is_variadic;
+#endif
+ phpdbg_write("%s=%s",
+ arginfo[j].name, is_variadic ? "[": "");
+ }
+ ++j;
+
+ zend_print_flat_zval_r(*argstmp TSRMLS_CC);
+ zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator);
+ }
+ if (is_variadic) {
+ phpdbg_write("]");
+ }
+ }
+ phpdbg_write(")");
+}
+
+void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
+{
+ zval zbacktrace;
+ zval **tmp;
+ zval **file, **line;
+ HashPosition position;
+ int i = 1, limit = num;
+ int user_defined;
+
+ if (limit < 0) {
+ phpdbg_error("Invalid backtrace size %d", limit);
+ }
+
+ zend_fetch_debug_backtrace(
+ &zbacktrace, 0, 0, limit TSRMLS_CC);
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
+ zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position);
+ while (1) {
+ user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file);
+ zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line);
+ zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
+
+ if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace),
+ (void**)&tmp, &position) == FAILURE) {
+ phpdbg_write("frame #0: {main} at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line));
+ break;
+ }
+
+ if (user_defined == SUCCESS) {
+ phpdbg_write("frame #%d: ", i++);
+ phpdbg_dump_prototype(tmp TSRMLS_CC);
+ phpdbg_writeln(" at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line));
+ } else {
+ phpdbg_write(" => ");
+ phpdbg_dump_prototype(tmp TSRMLS_CC);
+ phpdbg_writeln(" (internal function)");
+ }
+ }
+
+ phpdbg_writeln(EMPTY);
+ zval_dtor(&zbacktrace);
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_frame.h b/sapi/phpdbg/phpdbg_frame.h
new file mode 100644
index 000000000..7c4574ed2
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_frame.h
@@ -0,0 +1,30 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_FRAME_H
+#define PHPDBG_FRAME_H
+
+#include "TSRM.h"
+
+void phpdbg_restore_frame(TSRMLS_D);
+void phpdbg_switch_frame(int TSRMLS_DC);
+void phpdbg_dump_backtrace(size_t TSRMLS_DC);
+
+#endif /* PHPDBG_FRAME_H */
diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c
new file mode 100644
index 000000000..a02cb41c1
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_help.c
@@ -0,0 +1,603 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg.h"
+#include "phpdbg_help.h"
+#include "phpdbg_print.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_break.h"
+#include "phpdbg_list.h"
+#include "phpdbg_info.h"
+#include "phpdbg_set.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+PHPDBG_HELP(exec) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("\tWill attempt execution, if compilation has not yet taken place, it occurs now");
+ phpdbg_writeln("The execution context must be set before execution can take place");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(step) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("You can enable and disable stepping at any phpdbg prompt during execution");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sstepping 1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%ss 1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill enable stepping");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("While stepping is enabled you are presented with a prompt after the execution of each opcode");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(next) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_write("Step back into the vm and execute the next opcode");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%snext", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sn", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: is only useful while executing");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(until) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Step back into the vm, skipping breakpoints until the next source line");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%suntil", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%su", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: is only useful while executing");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(finish) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Step back into the vm, skipping breakpoints until past the end of the current stack");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sfinish", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sF", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: this allows all breakpoints that would otherwise break execution in the current scope to be skipped");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(leave) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Step back into the vm, skipping breakpoints until the current stack is returning");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sleave", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sL", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill cause a break when instructed to leave the current context");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: this allows inspection of the return value before it is returned");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(compile) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Pre-compilation of the execution context provides the opportunity to inspect opcodes before execution");
+ phpdbg_writeln("The execution context must be set for compilation to succeed");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%scompile", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sc", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill compile the current execution context, populating class/function/constant/etc tables");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: It is a good idea to clean the environment between each compilation");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(print) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("By default, print will show information about the current execution context");
+ phpdbg_writeln("Other printing commands give access to instruction information");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sprint class \\my\\class", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sp c \\my\\class", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the instructions for the methods in \\my\\class");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sprint method \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sp m \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the instructions for \\my\\class::method");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sprint func .getSomething", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sp f .getSomething", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the instructions for ::getSomething in the active scope");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sprint func my_function", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sp f my_function", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the instructions for the global function my_function");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sprint opline", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sp o", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the instruction for the current opline");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sprint exec", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sp e", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the instructions for the execution context");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sprint stack", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sp s", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the instructions for the current stack");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Specific printers loaded are show below:");
+ phpdbg_notice("Commands");
+ {
+ const phpdbg_command_t *print_command = phpdbg_print_commands;
+
+ phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
+ while (print_command && print_command->name) {
+ if (print_command->alias) {
+ phpdbg_writeln("\t[%c]\t%s\t\t%s", print_command->alias, print_command->name, print_command->tip);
+ } else {
+ phpdbg_writeln("\t[ ]\t%s\t\t%s", print_command->name, print_command->tip);
+ }
+ ++print_command;
+ }
+ }
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(run) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Execute the current context inside the phpdbg vm");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%srun", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sr", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill cause execution of the context, if it is set.");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: The execution context must be set, but not necessarily compiled before execution occurs");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(eval) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Access to eval() allows you to change the environment during execution, careful though!!");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%seval $variable", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sE $variable", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print_r($variable) on the console, if it is defined");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%seval $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sE $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill set $variable in the current scope");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: eval() will always show the result; do not prefix the code with \"return\"");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(break) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Setting a breakpoint stops execution at a specific stage");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sbreak [file] test.php:1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb [F] test.php:1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break execution on line 1 of test.php");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak [func] my_function", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb [f] my_function", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break execution on entry to my_function");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak [method] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb [m] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break execution on entry to \\my\\class::method");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak [address] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb [a] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break at the opline with the address provided");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak [address] my_function#1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb [a] my_function#1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break at the opline number 1 of the function my_function");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak [address] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb [a] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break at the opline number 2 of the method \\my\\class::method");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak address test.php:3", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb a test.php:3", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break at the opline number 3 of test.php");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak [lineno] 200", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb [l] 200", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break at line 200 of the currently executing file");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak on ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb on ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break when the condition evaluates to true");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak at phpdbg::isGreat if ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break at every opcode in phpdbg::isGreat when the condition evaluates to true");
+ phpdbg_writeln("\t%sbreak at test.php:20 if ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break at every opcode on line 20 of test.php when the condition evaluates to true");
+ phpdbg_write("\t");
+ phpdbg_notice("The location can be anything accepted by file, func, method, or address break commands");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak op ZEND_ADD", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb O ZEND_ADD", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill break on every occurence of the opcode provided");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%sbreak del 1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sb d 1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill remove the breakpoint with the given identifier");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: An address is only valid for the current compilation");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Specific breakers loaded are show below:");
+ phpdbg_notice("Commands");
+ {
+ const phpdbg_command_t *break_command = phpdbg_break_commands;
+
+ phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
+ while (break_command && break_command->name) {
+ if (break_command->alias) {
+ phpdbg_writeln("\t[%c]\t%s\t\t%s", break_command->alias, break_command->name, break_command->tip);
+ } else {
+ phpdbg_writeln("\t[ ]\t%s\t\t%s", break_command->name, break_command->tip);
+ }
+ ++break_command;
+ }
+ }
+ phpdbg_writeln("Note: Conditional breaks are costly, use them sparingly!");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(clean) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("While debugging you may experience errors because of attempts to redeclare classes, constants or functions");
+ phpdbg_writeln("Cleaning the environment cleans these tables, so that files can be recompiled without exiting phpdbg");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(clear) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Clearing breakpoints means you can once again run code without interruption");
+ phpdbg_writeln("Note: all breakpoints are lost; be sure debugging is complete before clearing");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(info) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("info commands provide quick access to various types of information about the PHP environment");
+ phpdbg_writeln("Specific info commands are show below:");
+ phpdbg_notice("Commands");
+ {
+ const phpdbg_command_t *info_command = phpdbg_info_commands;
+
+ phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
+ while (info_command && info_command->name) {
+ if (info_command->alias) {
+ phpdbg_writeln("\t[%c]\t%s\t\t%s", info_command->alias, info_command->name, info_command->tip);
+ } else {
+ phpdbg_writeln("\t[ ]\t%s\t\t%s", info_command->name, info_command->tip);
+ }
+ ++info_command;
+ }
+ }
+
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(quiet) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Setting quietness on will stop the OPLINE output during execution");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%squiet 1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sQ 1", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill silence OPLINE output, while");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%squiet 0", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sQ 0", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill enable OPLINE output again");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: Quietness is disabled automatically while stepping");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(back) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("The backtrace is built with the default debug backtrace functionality");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sback 5", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%st 5", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill limit the number of frames to 5, the default is no limit");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: it is not necessary for an exception to be thrown to show a backtrace");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(frame) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("When viewing a backtrace, it is sometimes useful to jump to a frame in that trace");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sframe 2", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sf 2", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill go to frame 2, temporarily affecting scope and allowing access to the variables in that frame");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: the current frame is restored when execution continues");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(list) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("The list command displays source code for the given argument");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%slist [lines] 2", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sl [l] 2", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print next 2 lines from the current file");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%slist [func] my_function", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sl [f] my_function", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the source of the global function \"my_function\"");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%slist [func] .mine", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sl [f] .mine", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the source of the method \"mine\" from the active scope");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%slist [method] my::method", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sl [m] my::method", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the source of \"my::method\"");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%slist c myClass", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sl c myClass", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill print the source of \"myClass\"");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: before listing functions you must have a populated function table, try compile!!");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Specific listers loaded are show below:");
+ phpdbg_notice("Commands");
+ {
+ const phpdbg_command_t *list_command = phpdbg_list_commands;
+
+ phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
+ while (list_command && list_command->name) {
+ if (list_command->alias) {
+ phpdbg_writeln("\t[%c]\t%s\t\t%s", list_command->alias, list_command->name, list_command->tip);
+ } else {
+ phpdbg_writeln("\t[ ]\t%s\t\t%s", list_command->name, list_command->tip);
+ }
+ ++list_command;
+ }
+ }
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(oplog) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Even when quietness is enabled you may wish to save opline logs to a file");
+ phpdbg_writeln("Setting a new oplog closes the previously open log");
+ phpdbg_writeln("The log includes a high resolution timestamp on each entry");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%soplog /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sO /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill open the file /path/to/my.oplog for writing, creating it if it does not exist");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("\t%soplog 0", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sO 0", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill close the currently open log file, disabling oplog");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: upon failure to open a new oplog, the last oplog is held open");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(set) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Configure how phpdbg looks and behaves with the set command");
+ phpdbg_writeln("Specific set commands are show below:");
+ phpdbg_notice("Commands");
+ {
+ const phpdbg_command_t *set_command = phpdbg_set_commands;
+
+ phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
+ while (set_command && set_command->name) {
+ if (set_command->alias) {
+ phpdbg_writeln("\t[%c]\t%s\t\t%s", set_command->alias, set_command->name, set_command->tip);
+ } else {
+ phpdbg_writeln("\t[ ]\t%s\t\t%s", set_command->name, set_command->tip);
+ }
+ ++set_command;
+ }
+ }
+#ifndef _WIN32
+ phpdbg_notice("Colors");
+ {
+ const phpdbg_color_t *color = phpdbg_get_colors(TSRMLS_C);
+
+ if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
+ phpdbg_writeln("\t%-20s\t\tExample", "Name");
+ } else {
+ phpdbg_writeln("\tName");
+ }
+
+ while (color && color->name) {
+ if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
+ phpdbg_writeln(
+ "\t%-20s\t\t\033[%smphpdbg rocks :)\033[0m", color->name, color->code);
+ } else {
+ phpdbg_writeln("\t%s", color->name);
+ }
+ ++color;
+ }
+ }
+ phpdbg_writeln("The <element> for set color can be \"prompt\", \"notice\", or \"error\"");
+#endif
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(register) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Register any global function for use as a command in phpdbg console");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sregister scandir", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%sR scandir", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill register the scandir function for use in phpdbg");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: arguments passed as strings, return (if present) print_r'd on console");
+ if (zend_hash_num_elements(&PHPDBG_G(registered))) {
+ HashPosition position;
+ char *name = NULL;
+ zend_uint name_len = 0;
+
+ phpdbg_notice("Registered Functions (%d)", zend_hash_num_elements(&PHPDBG_G(registered)));
+ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(registered), &position);
+ zend_hash_get_current_key_ex(&PHPDBG_G(registered), &name, &name_len, NULL, 1, &position) == HASH_KEY_IS_STRING;
+ zend_hash_move_forward_ex(&PHPDBG_G(registered), &position)) {
+ phpdbg_writeln("|-------> %s", name);
+ efree(name);
+ }
+ }
+
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(source) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Sourcing a phpdbginit during your debugging session might save some time");
+ phpdbg_writeln("The source command can also be used to export breakpoints to a phpdbginit file");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%ssource /my/init", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%s. /my/init", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill execute the phpdbginit file at /my/init");
+ phpdbg_writeln("\t%ssource export /my/init", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%s. export /my/init", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill export breakpoints to /my/init in phpdbginit file format");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(shell) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Direct access to shell commands saves having to switch windows/consoles");
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Examples");
+ phpdbg_writeln("\t%sshell ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\t%s- ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C));
+ phpdbg_writeln("\tWill execute ls /usr/src/php-src, displaying the output in the console");
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln("Note: read only commands please!");
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_HELP(options) /* {{{ */
+{
+ phpdbg_help_header();
+ phpdbg_writeln("Below are the command line options supported by phpdbg");
+ phpdbg_notice("Command Line Options and Flags");
+ phpdbg_writeln(" -c\t-c/my/php.ini\t\tSet php.ini file to load");
+ phpdbg_writeln(" -d\t-dmemory_limit=4G\tSet a php.ini directive");
+ phpdbg_writeln(" -n\tN/A\t\t\tDisable default php.ini");
+ phpdbg_writeln(" -q\tN/A\t\t\tSupress welcome banner");
+ phpdbg_writeln(" -e\t-emytest.php\t\tSet execution context");
+ phpdbg_writeln(" -v\tN/A\t\t\tEnable oplog output");
+ phpdbg_writeln(" -s\tN/A\t\t\tEnable stepping");
+ phpdbg_writeln(" -b\tN/A\t\t\tDisable colour");
+ phpdbg_writeln(" -i\t-imy.init\t\tSet .phpdbginit file");
+ phpdbg_writeln(" -I\tN/A\t\t\tIgnore default .phpdbginit");
+ phpdbg_writeln(" -O\t-Omy.oplog\t\tSets oplog output file");
+ phpdbg_writeln(" -r\tN/A\t\t\tRun execution context");
+ phpdbg_writeln(" -E\tN/A\t\t\tEnable step through eval, careful!");
+ phpdbg_writeln(" -S\t-Scli\t\t\tOverride SAPI name, careful!");
+#ifndef _WIN32
+ phpdbg_writeln(" -l\t-l4000\t\t\tSetup remote console ports");
+ phpdbg_writeln(" -a\t-a192.168.0.3\t\tSetup remote console bind address");
+#endif
+ phpdbg_writeln(" -V\tN/A\t\t\tVersion number");
+ phpdbg_notice("Passing -rr will quit automatically after execution");
+#ifndef _WIN32
+ phpdbg_writeln("Remote Console Mode");
+ phpdbg_notice("For security, phpdbg will bind only to the loopback interface by default");
+ phpdbg_writeln("-a without an argument implies all; phpdbg will bind to all available interfaces.");
+ phpdbg_writeln("specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2.");
+ phpdbg_notice("Steps should be taken to secure this service if bound to a public interface/port");
+#endif
+ phpdbg_help_footer();
+ return SUCCESS;
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_help.h b/sapi/phpdbg/phpdbg_help.h
new file mode 100644
index 000000000..319142cb5
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_help.h
@@ -0,0 +1,92 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_HELP_H
+#define PHPDBG_HELP_H
+
+#include "TSRM.h"
+#include "phpdbg.h"
+#include "phpdbg_cmd.h"
+
+#define PHPDBG_HELP(name) PHPDBG_COMMAND(help_##name)
+
+/**
+ * Helper Forward Declarations
+ */
+PHPDBG_HELP(exec);
+PHPDBG_HELP(compile);
+PHPDBG_HELP(step);
+PHPDBG_HELP(next);
+PHPDBG_HELP(run);
+PHPDBG_HELP(eval);
+PHPDBG_HELP(until);
+PHPDBG_HELP(finish);
+PHPDBG_HELP(leave);
+PHPDBG_HELP(print);
+PHPDBG_HELP(break);
+PHPDBG_HELP(clean);
+PHPDBG_HELP(clear);
+PHPDBG_HELP(info);
+PHPDBG_HELP(back);
+PHPDBG_HELP(frame);
+PHPDBG_HELP(quiet);
+PHPDBG_HELP(list);
+PHPDBG_HELP(set);
+PHPDBG_HELP(register);
+PHPDBG_HELP(options);
+PHPDBG_HELP(source);
+PHPDBG_HELP(shell);
+
+/**
+ * Commands
+ */
+static const phpdbg_command_t phpdbg_help_commands[] = {
+ PHPDBG_COMMAND_D_EX(exec, "the execution context should be a valid path", 'e', help_exec, NULL, 0),
+ PHPDBG_COMMAND_D_EX(compile, "allow inspection of code before execution", 'c', help_compile, NULL, 0),
+ PHPDBG_COMMAND_D_EX(step, "step through execution to break at every opcode", 's', help_step, NULL, 0),
+ PHPDBG_COMMAND_D_EX(next, "continue executing while stepping or after breaking", 'n', help_next, NULL, 0),
+ PHPDBG_COMMAND_D_EX(run, "execute inside the phpdbg vm", 'r', help_run, NULL, 0),
+ PHPDBG_COMMAND_D_EX(eval, "access to eval() allows affecting the environment", 'E', help_eval, NULL, 0),
+ PHPDBG_COMMAND_D_EX(until, "continue until the current line is executed", 'u', help_until, NULL, 0),
+ PHPDBG_COMMAND_D_EX(finish, "continue until the current function has returned", 'F', help_finish, NULL, 0),
+ PHPDBG_COMMAND_D_EX(leave, "continue until the current function is returning", 'L', help_leave, NULL, 0),
+ PHPDBG_COMMAND_D_EX(print, "print context information or instructions", 'p', help_print, NULL, 0),
+ PHPDBG_COMMAND_D_EX(break, "breakpoints allow execution interruption", 'b', help_break, NULL, 0),
+ PHPDBG_COMMAND_D_EX(clean, "resetting the environment is useful while debugging", 'X', help_clean, NULL, 0),
+ PHPDBG_COMMAND_D_EX(clear, "reset breakpoints to execute without interruption", 'c', help_clear, NULL, 0),
+ PHPDBG_COMMAND_D_EX(info, "quick access to useful information on the console", 'i', help_info, NULL, 0),
+ PHPDBG_COMMAND_D_EX(back, "show debug backtrace information during execution", 't', help_back, NULL, 0),
+ PHPDBG_COMMAND_D_EX(frame, "switch to a frame in the current stack for inspection", 'f', help_frame, NULL, 0),
+ PHPDBG_COMMAND_D_EX(quiet, "be quiet during execution", 'Q', help_quiet, NULL, 0),
+ PHPDBG_COMMAND_D_EX(list, "list code gives you quick access to code", 'l', help_list, NULL, 0),
+ PHPDBG_COMMAND_D_EX(set, "configure how phpdbg looks and behaves", 'S', help_set, NULL, 0),
+ PHPDBG_COMMAND_D_EX(register, "register a function for use as a command", 'R', help_register,NULL, 0),
+ PHPDBG_COMMAND_D_EX(options, "show information about command line options", 'o', help_options, NULL, 0),
+ PHPDBG_COMMAND_D_EX(source, "load a phpdbginit file at the console", '.', help_source, NULL, 0),
+ PHPDBG_COMMAND_D_EX(shell, "execute system commands with direct shell access", '-', help_shell, NULL, 0),
+ PHPDBG_END_COMMAND
+};
+
+#define phpdbg_help_header() \
+ phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
+#define phpdbg_help_footer() \
+ phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
+
+#endif /* PHPDBG_HELP_H */
diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c
new file mode 100644
index 000000000..0f4233bf3
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_info.c
@@ -0,0 +1,355 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "php.h"
+#include "phpdbg.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_info.h"
+#include "phpdbg_bp.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+PHPDBG_INFO(break) /* {{{ */
+{
+ phpdbg_print_breakpoints(PHPDBG_BREAK_FILE TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_SYM TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_OPLINE TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_FILE_OPLINE TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_FUNCTION_OPLINE TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD_OPLINE TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_COND TSRMLS_CC);
+ phpdbg_print_breakpoints(PHPDBG_BREAK_OPCODE TSRMLS_CC);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_INFO(files) /* {{{ */
+{
+ HashPosition pos;
+ char *fname;
+
+ phpdbg_notice("Included files: %d",
+ zend_hash_num_elements(&EG(included_files)));
+
+ zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos);
+ while (zend_hash_get_current_key_ex(&EG(included_files), &fname,
+ NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
+ phpdbg_writeln("File: %s", fname);
+ zend_hash_move_forward_ex(&EG(included_files), &pos);
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_INFO(error) /* {{{ */
+{
+ if (PG(last_error_message)) {
+ phpdbg_writeln("Last error: %s at %s line %d",
+ PG(last_error_message), PG(last_error_file), PG(last_error_lineno));
+ } else {
+ phpdbg_notice("No error found!");
+ }
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_INFO(vars) /* {{{ */
+{
+ HashTable vars;
+ HashPosition pos;
+ char *var;
+ zval **data;
+
+ if (!EG(active_op_array)) {
+ phpdbg_error("No active op array!");
+ return SUCCESS;
+ }
+
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+
+ if (!EG(active_symbol_table)) {
+ phpdbg_error("No active symbol table!");
+ return SUCCESS;
+ }
+ }
+
+ zend_hash_init(&vars, 8, NULL, NULL, 0);
+
+ zend_hash_internal_pointer_reset_ex(EG(active_symbol_table), &pos);
+ while (zend_hash_get_current_key_ex(EG(active_symbol_table), &var,
+ NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
+ zend_hash_get_current_data_ex(EG(active_symbol_table), (void **)&data, &pos);
+ if (*var != '_') {
+ zend_hash_update(
+ &vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL);
+ }
+ zend_hash_move_forward_ex(EG(active_symbol_table), &pos);
+ }
+
+ {
+ zend_op_array *ops = EG(active_op_array);
+
+ if (ops->function_name) {
+ if (ops->scope) {
+ phpdbg_notice(
+ "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars));
+ } else {
+ phpdbg_notice(
+ "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars));
+ }
+ } else {
+ if (ops->filename) {
+ phpdbg_notice(
+ "Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars));
+ } else {
+ phpdbg_notice(
+ "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars));
+ }
+ }
+ }
+
+ if (zend_hash_num_elements(&vars)) {
+ phpdbg_writeln("Address\t\tRefs\tType\t\tVariable");
+ for (zend_hash_internal_pointer_reset_ex(&vars, &pos);
+ zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(&vars, &pos)) {
+ char *var;
+
+ zend_hash_get_current_key_ex(&vars, &var, NULL, NULL, 0, &pos);
+
+ if (*data) {
+ phpdbg_write(
+ "%p\t%d\t",
+ *data,
+ Z_REFCOUNT_PP(data));
+
+ switch (Z_TYPE_PP(data)) {
+ case IS_STRING: phpdbg_write("(string)\t"); break;
+ case IS_LONG: phpdbg_write("(integer)\t"); break;
+ case IS_DOUBLE: phpdbg_write("(float)\t"); break;
+ case IS_RESOURCE: phpdbg_write("(resource)\t"); break;
+ case IS_ARRAY: phpdbg_write("(array)\t"); break;
+ case IS_OBJECT: phpdbg_write("(object)\t"); break;
+ case IS_NULL: phpdbg_write("(null)\t"); break;
+ }
+
+ if (Z_TYPE_PP(data) == IS_RESOURCE) {
+ int type;
+
+ phpdbg_writeln(
+ "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
+ if (zend_list_find(Z_RESVAL_PP(data), &type)) {
+ phpdbg_write(
+ "|-------(typeof)------> (%s)",
+ zend_rsrc_list_get_rsrc_type(type TSRMLS_CC));
+ } else {
+ phpdbg_write(
+ "|-------(typeof)------> (unknown)");
+ }
+ phpdbg_writeln(EMPTY);
+ } else if (Z_TYPE_PP(data) == IS_OBJECT) {
+ phpdbg_writeln(
+ "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
+ phpdbg_write(
+ "|-----(instanceof)----> (%s)", Z_OBJCE_PP(data)->name);
+ phpdbg_writeln(EMPTY);
+ } else {
+ phpdbg_write(
+ "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
+ }
+ } else {
+ phpdbg_write(
+ "n/a\tn/a\tn/a\t$%s", var);
+ }
+ phpdbg_writeln(EMPTY);
+ }
+ }
+
+ zend_hash_destroy(&vars);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_INFO(literal) /* {{{ */
+{
+ if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) {
+ zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops);
+ int literal = 0, count = ops->last_literal-1;
+
+ if (ops->function_name) {
+ if (ops->scope) {
+ phpdbg_notice(
+ "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count);
+ } else {
+ phpdbg_notice(
+ "Literal Constants in %s() (%d)", ops->function_name, count);
+ }
+ } else {
+ if (ops->filename) {
+ phpdbg_notice(
+ "Literal Constants in %s (%d)", ops->filename, count);
+ } else {
+ phpdbg_notice(
+ "Literal Constants @ %p (%d)", ops, count);
+ }
+ }
+
+ while (literal < ops->last_literal) {
+ if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) {
+ phpdbg_write("|-------- C%u -------> [", literal);
+ zend_print_zval(
+ &ops->literals[literal].constant, 0);
+ phpdbg_write("]");
+ phpdbg_writeln(EMPTY);
+ }
+ literal++;
+ }
+ } else {
+ phpdbg_error("Not executing!");
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_INFO(memory) /* {{{ */
+{
+ if (is_zend_mm(TSRMLS_C)) {
+ phpdbg_notice("Memory Manager Information");
+ phpdbg_notice("Current");
+ phpdbg_writeln("|-------> Used:\t%.3f kB",
+ (float) (zend_memory_usage(0 TSRMLS_CC)/1024));
+ phpdbg_writeln("|-------> Real:\t%.3f kB",
+ (float) (zend_memory_usage(1 TSRMLS_CC)/1024));
+ phpdbg_notice("Peak");
+ phpdbg_writeln("|-------> Used:\t%.3f kB",
+ (float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024));
+ phpdbg_writeln("|-------> Real:\t%.3f kB",
+ (float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024));
+ } else {
+ phpdbg_error("Memory Manager Disabled!");
+ }
+ return SUCCESS;
+} /* }}} */
+
+static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */
+{
+ phpdbg_write(
+ "%s %s %s (%d)",
+ ((*ce)->type == ZEND_USER_CLASS) ?
+ "User" : "Internal",
+ ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ?
+ "Interface" :
+ ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ?
+ "Abstract Class" :
+ "Class",
+ (*ce)->name, zend_hash_num_elements(&(*ce)->function_table));
+} /* }}} */
+
+PHPDBG_INFO(classes) /* {{{ */
+{
+ HashPosition position;
+ zend_class_entry **ce;
+ HashTable classes;
+
+ zend_hash_init(&classes, 8, NULL, NULL, 0);
+
+ for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position);
+ zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS;
+ zend_hash_move_forward_ex(EG(class_table), &position)) {
+
+ if ((*ce)->type == ZEND_USER_CLASS) {
+ zend_hash_next_index_insert(
+ &classes, ce, sizeof(ce), NULL);
+ }
+ }
+
+ phpdbg_notice("User Classes (%d)",
+ zend_hash_num_elements(&classes));
+
+ for (zend_hash_internal_pointer_reset_ex(&classes, &position);
+ zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&classes, &position)) {
+
+ phpdbg_print_class_name(ce TSRMLS_CC);
+ phpdbg_writeln(EMPTY);
+
+ if ((*ce)->parent) {
+ zend_class_entry *pce = (*ce)->parent;
+ do {
+ phpdbg_write("|-------- ");
+ phpdbg_print_class_name(&pce TSRMLS_CC);
+ phpdbg_writeln(EMPTY);
+ } while ((pce = pce->parent));
+ }
+
+ if ((*ce)->info.user.filename) {
+ phpdbg_writeln(
+ "|---- in %s on line %u",
+ (*ce)->info.user.filename,
+ (*ce)->info.user.line_start);
+ } else {
+ phpdbg_writeln("|---- no source code");
+ }
+ phpdbg_writeln(EMPTY);
+ }
+
+ zend_hash_destroy(&classes);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_INFO(funcs) /* {{{ */
+{
+ HashPosition position;
+ zend_function *zf, **pzf;
+ HashTable functions;
+
+ zend_hash_init(&functions, 8, NULL, NULL, 0);
+
+ for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position);
+ zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS;
+ zend_hash_move_forward_ex(EG(function_table), &position)) {
+
+ if (zf->type == ZEND_USER_FUNCTION) {
+ zend_hash_next_index_insert(
+ &functions, (void**) &zf, sizeof(zend_function), NULL);
+ }
+ }
+
+ phpdbg_notice("User Functions (%d)",
+ zend_hash_num_elements(&functions));
+
+ for (zend_hash_internal_pointer_reset_ex(&functions, &position);
+ zend_hash_get_current_data_ex(&functions, (void**)&pzf, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&functions, &position)) {
+ zend_op_array *op_array = &((*pzf)->op_array);
+
+ phpdbg_writeln(
+ "|-------- %s in %s on line %d",
+ op_array->function_name ? op_array->function_name : "{main}",
+ op_array->filename ? op_array->filename : "(no source code)",
+ op_array->line_start);
+ }
+
+ zend_hash_destroy(&functions);
+
+ return SUCCESS;
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_info.h b/sapi/phpdbg/phpdbg_info.h
new file mode 100644
index 000000000..a6b4e3719
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_info.h
@@ -0,0 +1,49 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_INFO_H
+#define PHPDBG_INFO_H
+
+#include "phpdbg_cmd.h"
+
+#define PHPDBG_INFO(name) PHPDBG_COMMAND(info_##name)
+
+PHPDBG_INFO(files);
+PHPDBG_INFO(break);
+PHPDBG_INFO(classes);
+PHPDBG_INFO(funcs);
+PHPDBG_INFO(error);
+PHPDBG_INFO(vars);
+PHPDBG_INFO(literal);
+PHPDBG_INFO(memory);
+
+static const phpdbg_command_t phpdbg_info_commands[] = {
+ PHPDBG_COMMAND_D_EX(break, "show breakpoints", 'b', info_break, NULL, 0),
+ PHPDBG_COMMAND_D_EX(files, "show included files", 'F', info_files, NULL, 0),
+ PHPDBG_COMMAND_D_EX(classes, "show loaded classes", 'c', info_classes, NULL, 0),
+ PHPDBG_COMMAND_D_EX(funcs, "show loaded classes", 'f', info_funcs, NULL, 0),
+ PHPDBG_COMMAND_D_EX(error, "show last error", 'e', info_error, NULL, 0),
+ PHPDBG_COMMAND_D_EX(vars, "show active variables", 'v', info_vars, NULL, 0),
+ PHPDBG_COMMAND_D_EX(literal, "show active literal constants", 'l', info_literal, NULL, 0),
+ PHPDBG_COMMAND_D_EX(memory, "show memory manager stats", 'm', info_memory, NULL, 0),
+ PHPDBG_END_COMMAND
+};
+
+#endif /* PHPDBG_INFO_H */
diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c
new file mode 100644
index 000000000..eb1091550
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_list.c
@@ -0,0 +1,279 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#ifndef _WIN32
+# include <sys/mman.h>
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+#include "phpdbg.h"
+#include "phpdbg_list.h"
+#include "phpdbg_utils.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+PHPDBG_LIST(lines) /* {{{ */
+{
+ if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) {
+ phpdbg_error("Not executing, and execution context not set");
+ return SUCCESS;
+ }
+
+ switch (param->type) {
+ case NUMERIC_PARAM:
+ case EMPTY_PARAM:
+ phpdbg_list_file(phpdbg_current_file(TSRMLS_C),
+ param->type == EMPTY_PARAM ? 0 : (param->num < 0 ? 1 - param->num : param->num),
+ (param->type != EMPTY_PARAM && param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C),
+ 0 TSRMLS_CC);
+ break;
+ case FILE_PARAM:
+ phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_LIST(func) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM:
+ phpdbg_list_function_byname(
+ param->str, param->len TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_LIST(method) /* {{{ */
+{
+ switch (param->type) {
+ case METHOD_PARAM: {
+ zend_class_entry **ce;
+
+ if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
+ zend_function *function;
+ char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
+
+ if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) {
+ phpdbg_list_function(function TSRMLS_CC);
+ } else {
+ phpdbg_error("Could not find %s::%s", param->method.class, param->method.name);
+ }
+
+ efree(lcname);
+ } else {
+ phpdbg_error("Could not find the class %s", param->method.class);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_LIST(class) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM: {
+ zend_class_entry **ce;
+
+ if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
+ if ((*ce)->type == ZEND_USER_CLASS) {
+ if ((*ce)->info.user.filename) {
+ phpdbg_list_file(
+ (*ce)->info.user.filename,
+ (*ce)->info.user.line_end - (*ce)->info.user.line_start + 1,
+ (*ce)->info.user.line_start, 0 TSRMLS_CC
+ );
+ } else {
+ phpdbg_error("The source of the requested class (%s) cannot be found", (*ce)->name);
+ }
+ } else {
+ phpdbg_error("The class requested (%s) is not user defined", (*ce)->name);
+ }
+ } else {
+ phpdbg_error("The requested class (%s) could not be found", param->str);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */
+{
+ unsigned char *mem, *pos, *last_pos, *end_pos;
+ struct stat st;
+#ifndef _WIN32
+ int fd;
+#else
+ HANDLE fd, map;
+#endif
+ int all_content = (count == 0);
+ int line = 0, displayed = 0;
+
+ if (VCWD_STAT(filename, &st) == FAILURE) {
+ phpdbg_error("Failed to stat file %s", filename);
+ return;
+ }
+
+#ifndef _WIN32
+ if ((fd = VCWD_OPEN(filename, O_RDONLY)) == FAILURE) {
+ phpdbg_error("Failed to open file %s to list", filename);
+ return;
+ }
+
+ pos = last_pos = mem = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ end_pos = mem + st.st_size;
+#else
+
+ fd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fd == INVALID_HANDLE_VALUE) {
+ phpdbg_error("Failed to open file!");
+ return;
+ }
+
+ map = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (map == NULL) {
+ phpdbg_error("Failed to map file!");
+ CloseHandle(fd);
+ return;
+ }
+
+ pos = last_pos = mem = (char*) MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
+ if (mem == NULL) {
+ phpdbg_error("Failed to map file in memory");
+ CloseHandle(map);
+ CloseHandle(fd);
+ return;
+ }
+ end_pos = mem + st.st_size;
+#endif
+ while (1) {
+ if (pos == end_pos) {
+ break;
+ }
+
+ pos = memchr(last_pos, '\n', end_pos - last_pos);
+
+ if (!pos) {
+ /* No more line breaks */
+ pos = end_pos;
+ }
+
+ ++line;
+
+ if (!offset || offset <= line) {
+ /* Without offset, or offset reached */
+ if (!highlight) {
+ phpdbg_writeln("%05u: %.*s", line, (int)(pos - last_pos), last_pos);
+ } else {
+ if (highlight != line) {
+ phpdbg_writeln(" %05u: %.*s", line, (int)(pos - last_pos), last_pos);
+ } else {
+ phpdbg_writeln(">%05u: %.*s", line, (int)(pos - last_pos), last_pos);
+ }
+ }
+ ++displayed;
+ }
+
+ last_pos = pos + 1;
+
+ if (!all_content && displayed == count) {
+ /* Reached max line to display */
+ break;
+ }
+ }
+
+#ifndef _WIN32
+ munmap(mem, st.st_size);
+ close(fd);
+#else
+ UnmapViewOfFile(mem);
+ CloseHandle(map);
+ CloseHandle(fd);
+#endif
+} /* }}} */
+
+void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */
+{
+ const zend_op_array *ops;
+
+ if (fbc->type != ZEND_USER_FUNCTION) {
+ phpdbg_error("The function requested (%s) is not user defined", fbc->common.function_name);
+ return;
+ }
+
+ ops = (zend_op_array*)fbc;
+
+ phpdbg_list_file(ops->filename,
+ ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC);
+} /* }}} */
+
+void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */
+{
+ HashTable *func_table = EG(function_table);
+ zend_function* fbc;
+ char *func_name = (char*) str;
+ size_t func_name_len = len;
+
+ /* search active scope if begins with period */
+ if (func_name[0] == '.') {
+ if (EG(scope)) {
+ func_name++;
+ func_name_len--;
+
+ func_table = &EG(scope)->function_table;
+ } else {
+ phpdbg_error("No active class");
+ return;
+ }
+ } else if (!EG(function_table)) {
+ phpdbg_error("No function table loaded");
+ return;
+ } else {
+ func_table = EG(function_table);
+ }
+
+ /* use lowercase names, case insensitive */
+ func_name = zend_str_tolower_dup(func_name, func_name_len);
+
+ if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) {
+ phpdbg_list_function(fbc TSRMLS_CC);
+ } else {
+ phpdbg_error("Function %s not found", func_name);
+ }
+
+ efree(func_name);
+} /* }}} */
+
diff --git a/sapi/phpdbg/phpdbg_list.h b/sapi/phpdbg/phpdbg_list.h
new file mode 100644
index 000000000..f9d1885ea
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_list.h
@@ -0,0 +1,47 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_LIST_H
+#define PHPDBG_LIST_H
+
+#include "TSRM.h"
+#include "phpdbg_cmd.h"
+
+#define PHPDBG_LIST(name) PHPDBG_COMMAND(list_##name)
+#define PHPDBG_LIST_HANDLER(name) PHPDBG_COMMAND_HANDLER(list_##name)
+
+PHPDBG_LIST(lines);
+PHPDBG_LIST(class);
+PHPDBG_LIST(method);
+PHPDBG_LIST(func);
+
+void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC);
+void phpdbg_list_function(const zend_function* TSRMLS_DC);
+void phpdbg_list_file(const char*, long, long, int TSRMLS_DC);
+
+static const phpdbg_command_t phpdbg_list_commands[] = {
+ PHPDBG_COMMAND_D_EX(lines, "lists the specified lines", 'l', list_lines, NULL, 1),
+ PHPDBG_COMMAND_D_EX(class, "lists the specified class", 'c', list_class, NULL, 1),
+ PHPDBG_COMMAND_D_EX(method, "lists the specified method", 'm', list_method, NULL, 1),
+ PHPDBG_COMMAND_D_EX(func, "lists the specified function", 'f', list_func, NULL, 1),
+ PHPDBG_END_COMMAND
+};
+
+#endif /* PHPDBG_LIST_H */
diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c
new file mode 100644
index 000000000..50073eb22
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_opcode.c
@@ -0,0 +1,363 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg.h"
+#include "zend_vm_opcodes.h"
+#include "zend_compile.h"
+#include "phpdbg_opcode.h"
+#include "phpdbg_utils.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+static inline zend_uint phpdbg_decode_literal(zend_op_array *ops, zend_literal *literal TSRMLS_DC) /* {{{ */
+{
+ int iter = 0;
+
+ while (iter < ops->last_literal) {
+ if (literal == &ops->literals[iter]) {
+ return iter;
+ }
+ iter++;
+ }
+
+ return 0;
+} /* }}} */
+
+static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint type, HashTable *vars TSRMLS_DC) /* {{{ */
+{
+ char *decode = NULL;
+
+ switch (type &~ EXT_TYPE_UNUSED) {
+ case IS_CV:
+ asprintf(&decode, "$%s", ops->vars[op->var].name);
+ break;
+
+ case IS_VAR:
+ case IS_TMP_VAR: {
+ zend_ulong id = 0, *pid = NULL;
+ if (vars != NULL) {
+ if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) {
+ id = zend_hash_num_elements(vars);
+ zend_hash_index_update(
+ vars, (zend_ulong) ops->vars - op->var,
+ (void**) &id,
+ sizeof(zend_ulong), NULL);
+ } else id = *pid;
+ }
+ asprintf(&decode, "@%lu", id);
+ } break;
+
+ case IS_CONST:
+ asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->literal TSRMLS_CC));
+ break;
+
+ case IS_UNUSED:
+ asprintf(&decode, "<unused>");
+ break;
+ }
+ return decode;
+} /* }}} */
+
+char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC) /*{{{ */
+{
+ char *decode[4] = {NULL, NULL, NULL, NULL};
+
+ switch (op->opcode) {
+ case ZEND_JMP:
+#ifdef ZEND_GOTO
+ case ZEND_GOTO:
+#endif
+#ifdef ZEND_FAST_CALL
+ case ZEND_FAST_CALL:
+#endif
+ asprintf(&decode[1], "J%ld", op->op1.jmp_addr - ops->opcodes);
+ goto format;
+
+ case ZEND_JMPZNZ:
+ decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
+ asprintf(
+ &decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value);
+ goto result;
+
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+
+#ifdef ZEND_JMP_SET
+ case ZEND_JMP_SET:
+#endif
+#ifdef ZEND_JMP_SET_VAR
+ case ZEND_JMP_SET_VAR:
+#endif
+ decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
+ asprintf(
+ &decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes);
+ goto result;
+
+ case ZEND_RECV_INIT:
+ goto result;
+
+ default: {
+ decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
+ decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars TSRMLS_CC);
+result:
+ decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC);
+format:
+ asprintf(
+ &decode[0],
+ "%-20s %-20s %-20s",
+ decode[1] ? decode[1] : "",
+ decode[2] ? decode[2] : "",
+ decode[3] ? decode[3] : "");
+ }
+ }
+
+ if (decode[1])
+ free(decode[1]);
+ if (decode[2])
+ free(decode[2]);
+ if (decode[3])
+ free(decode[3]);
+
+ return decode[0];
+} /* }}} */
+
+void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
+{
+ /* force out a line while stepping so the user knows what is happening */
+ if (ignore_flags ||
+ (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
+ (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ||
+ (PHPDBG_G(oplog)))) {
+
+ zend_op *opline = execute_data->opline;
+ char *decode = phpdbg_decode_opline(execute_data->op_array, opline, vars TSRMLS_CC);
+
+ if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
+ /* output line info */
+ phpdbg_notice("L%-5u %16p %-30s %s %s",
+ opline->lineno,
+ opline,
+ phpdbg_decode_opcode(opline->opcode),
+ decode,
+ execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
+ }
+
+ if (!ignore_flags && PHPDBG_G(oplog)) {
+ phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s",
+ opline->lineno,
+ opline,
+ phpdbg_decode_opcode(opline->opcode),
+ decode,
+ execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
+ }
+
+ if (decode) {
+ free(decode);
+ }
+ }
+} /* }}} */
+
+void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
+{
+ phpdbg_print_opline_ex(execute_data, NULL, ignore_flags TSRMLS_CC);
+} /* }}} */
+
+const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
+{
+#define CASE(s) case s: return #s
+ switch (opcode) {
+ CASE(ZEND_NOP);
+ CASE(ZEND_ADD);
+ CASE(ZEND_SUB);
+ CASE(ZEND_MUL);
+ CASE(ZEND_DIV);
+ CASE(ZEND_MOD);
+ CASE(ZEND_SL);
+ CASE(ZEND_SR);
+ CASE(ZEND_CONCAT);
+ CASE(ZEND_BW_OR);
+ CASE(ZEND_BW_AND);
+ CASE(ZEND_BW_XOR);
+ CASE(ZEND_BW_NOT);
+ CASE(ZEND_BOOL_NOT);
+ CASE(ZEND_BOOL_XOR);
+ CASE(ZEND_IS_IDENTICAL);
+ CASE(ZEND_IS_NOT_IDENTICAL);
+ CASE(ZEND_IS_EQUAL);
+ CASE(ZEND_IS_NOT_EQUAL);
+ CASE(ZEND_IS_SMALLER);
+ CASE(ZEND_IS_SMALLER_OR_EQUAL);
+ CASE(ZEND_CAST);
+ CASE(ZEND_QM_ASSIGN);
+ CASE(ZEND_ASSIGN_ADD);
+ CASE(ZEND_ASSIGN_SUB);
+ CASE(ZEND_ASSIGN_MUL);
+ CASE(ZEND_ASSIGN_DIV);
+ CASE(ZEND_ASSIGN_MOD);
+ CASE(ZEND_ASSIGN_SL);
+ CASE(ZEND_ASSIGN_SR);
+ CASE(ZEND_ASSIGN_CONCAT);
+ CASE(ZEND_ASSIGN_BW_OR);
+ CASE(ZEND_ASSIGN_BW_AND);
+ CASE(ZEND_ASSIGN_BW_XOR);
+ CASE(ZEND_PRE_INC);
+ CASE(ZEND_PRE_DEC);
+ CASE(ZEND_POST_INC);
+ CASE(ZEND_POST_DEC);
+ CASE(ZEND_ASSIGN);
+ CASE(ZEND_ASSIGN_REF);
+ CASE(ZEND_ECHO);
+ CASE(ZEND_PRINT);
+ CASE(ZEND_JMP);
+ CASE(ZEND_JMPZ);
+ CASE(ZEND_JMPNZ);
+ CASE(ZEND_JMPZNZ);
+ CASE(ZEND_JMPZ_EX);
+ CASE(ZEND_JMPNZ_EX);
+ CASE(ZEND_CASE);
+ CASE(ZEND_SWITCH_FREE);
+ CASE(ZEND_BRK);
+ CASE(ZEND_CONT);
+ CASE(ZEND_BOOL);
+ CASE(ZEND_INIT_STRING);
+ CASE(ZEND_ADD_CHAR);
+ CASE(ZEND_ADD_STRING);
+ CASE(ZEND_ADD_VAR);
+ CASE(ZEND_BEGIN_SILENCE);
+ CASE(ZEND_END_SILENCE);
+ CASE(ZEND_INIT_FCALL_BY_NAME);
+ CASE(ZEND_DO_FCALL);
+ CASE(ZEND_DO_FCALL_BY_NAME);
+ CASE(ZEND_RETURN);
+ CASE(ZEND_RECV);
+ CASE(ZEND_RECV_INIT);
+ CASE(ZEND_SEND_VAL);
+ CASE(ZEND_SEND_VAR);
+ CASE(ZEND_SEND_REF);
+ CASE(ZEND_NEW);
+ CASE(ZEND_INIT_NS_FCALL_BY_NAME);
+ CASE(ZEND_FREE);
+ CASE(ZEND_INIT_ARRAY);
+ CASE(ZEND_ADD_ARRAY_ELEMENT);
+ CASE(ZEND_INCLUDE_OR_EVAL);
+ CASE(ZEND_UNSET_VAR);
+ CASE(ZEND_UNSET_DIM);
+ CASE(ZEND_UNSET_OBJ);
+ CASE(ZEND_FE_RESET);
+ CASE(ZEND_FE_FETCH);
+ CASE(ZEND_EXIT);
+ CASE(ZEND_FETCH_R);
+ CASE(ZEND_FETCH_DIM_R);
+ CASE(ZEND_FETCH_OBJ_R);
+ CASE(ZEND_FETCH_W);
+ CASE(ZEND_FETCH_DIM_W);
+ CASE(ZEND_FETCH_OBJ_W);
+ CASE(ZEND_FETCH_RW);
+ CASE(ZEND_FETCH_DIM_RW);
+ CASE(ZEND_FETCH_OBJ_RW);
+ CASE(ZEND_FETCH_IS);
+ CASE(ZEND_FETCH_DIM_IS);
+ CASE(ZEND_FETCH_OBJ_IS);
+ CASE(ZEND_FETCH_FUNC_ARG);
+ CASE(ZEND_FETCH_DIM_FUNC_ARG);
+ CASE(ZEND_FETCH_OBJ_FUNC_ARG);
+ CASE(ZEND_FETCH_UNSET);
+ CASE(ZEND_FETCH_DIM_UNSET);
+ CASE(ZEND_FETCH_OBJ_UNSET);
+ CASE(ZEND_FETCH_DIM_TMP_VAR);
+ CASE(ZEND_FETCH_CONSTANT);
+ CASE(ZEND_GOTO);
+ CASE(ZEND_EXT_STMT);
+ CASE(ZEND_EXT_FCALL_BEGIN);
+ CASE(ZEND_EXT_FCALL_END);
+ CASE(ZEND_EXT_NOP);
+ CASE(ZEND_TICKS);
+ CASE(ZEND_SEND_VAR_NO_REF);
+ CASE(ZEND_CATCH);
+ CASE(ZEND_THROW);
+ CASE(ZEND_FETCH_CLASS);
+ CASE(ZEND_CLONE);
+ CASE(ZEND_RETURN_BY_REF);
+ CASE(ZEND_INIT_METHOD_CALL);
+ CASE(ZEND_INIT_STATIC_METHOD_CALL);
+ CASE(ZEND_ISSET_ISEMPTY_VAR);
+ CASE(ZEND_ISSET_ISEMPTY_DIM_OBJ);
+ CASE(ZEND_PRE_INC_OBJ);
+ CASE(ZEND_PRE_DEC_OBJ);
+ CASE(ZEND_POST_INC_OBJ);
+ CASE(ZEND_POST_DEC_OBJ);
+ CASE(ZEND_ASSIGN_OBJ);
+ CASE(ZEND_INSTANCEOF);
+ CASE(ZEND_DECLARE_CLASS);
+ CASE(ZEND_DECLARE_INHERITED_CLASS);
+ CASE(ZEND_DECLARE_FUNCTION);
+ CASE(ZEND_RAISE_ABSTRACT_ERROR);
+ CASE(ZEND_DECLARE_CONST);
+ CASE(ZEND_ADD_INTERFACE);
+ CASE(ZEND_DECLARE_INHERITED_CLASS_DELAYED);
+ CASE(ZEND_VERIFY_ABSTRACT_CLASS);
+ CASE(ZEND_ASSIGN_DIM);
+ CASE(ZEND_ISSET_ISEMPTY_PROP_OBJ);
+ CASE(ZEND_HANDLE_EXCEPTION);
+ CASE(ZEND_USER_OPCODE);
+#ifdef ZEND_JMP_SET
+ CASE(ZEND_JMP_SET);
+#endif
+ CASE(ZEND_DECLARE_LAMBDA_FUNCTION);
+#ifdef ZEND_ADD_TRAIT
+ CASE(ZEND_ADD_TRAIT);
+#endif
+#ifdef ZEND_BIND_TRAITS
+ CASE(ZEND_BIND_TRAITS);
+#endif
+#ifdef ZEND_SEPARATE
+ CASE(ZEND_SEPARATE);
+#endif
+#ifdef ZEND_QM_ASSIGN_VAR
+ CASE(ZEND_QM_ASSIGN_VAR);
+#endif
+#ifdef ZEND_JMP_SET_VAR
+ CASE(ZEND_JMP_SET_VAR);
+#endif
+#ifdef ZEND_DISCARD_EXCEPTION
+ CASE(ZEND_DISCARD_EXCEPTION);
+#endif
+#ifdef ZEND_YIELD
+ CASE(ZEND_YIELD);
+#endif
+#ifdef ZEND_GENERATOR_RETURN
+ CASE(ZEND_GENERATOR_RETURN);
+#endif
+#ifdef ZEND_FAST_CALL
+ CASE(ZEND_FAST_CALL);
+#endif
+#ifdef ZEND_FAST_RET
+ CASE(ZEND_FAST_RET);
+#endif
+#ifdef ZEND_RECV_VARIADIC
+ CASE(ZEND_RECV_VARIADIC);
+#endif
+ CASE(ZEND_OP_DATA);
+ default:
+ return "UNKNOWN";
+ }
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_opcode.h b/sapi/phpdbg/phpdbg_opcode.h
new file mode 100644
index 000000000..144442981
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_opcode.h
@@ -0,0 +1,31 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_OPCODE_H
+#define PHPDBG_OPCODE_H
+
+#include "zend_types.h"
+
+const char *phpdbg_decode_opcode(zend_uchar);
+char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC);
+void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC);
+void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC);
+
+#endif /* PHPDBG_OPCODE_H */
diff --git a/sapi/phpdbg/phpdbg_print.c b/sapi/phpdbg/phpdbg_print.c
new file mode 100644
index 000000000..c4925fe5f
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_print.c
@@ -0,0 +1,258 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg.h"
+#include "phpdbg_print.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_opcode.h"
+#include "phpdbg_prompt.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+PHPDBG_PRINT(opline) /* {{{ */
+{
+ if (EG(in_execution) && EG(current_execute_data)) {
+ phpdbg_print_opline(EG(current_execute_data), 1 TSRMLS_CC);
+ } else {
+ phpdbg_error("Not Executing!");
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) /* {{{ */
+{
+ switch (method->type) {
+ case ZEND_USER_FUNCTION: {
+ zend_op_array* op_array = &(method->op_array);
+ HashTable vars;
+
+ if (op_array) {
+ zend_op *opline = &(op_array->opcodes[0]);
+ zend_uint opcode = 0,
+ end = op_array->last-1;
+
+ if (method->common.scope) {
+ phpdbg_writeln("\tL%d-%d %s::%s() %s",
+ op_array->line_start, op_array->line_end,
+ method->common.scope->name,
+ method->common.function_name,
+ op_array->filename ? op_array->filename : "unknown");
+ } else {
+ phpdbg_writeln("\tL%d-%d %s() %s",
+ method->common.function_name ? op_array->line_start : 0,
+ method->common.function_name ? op_array->line_end : 0,
+ method->common.function_name ? method->common.function_name : "{main}",
+ op_array->filename ? op_array->filename : "unknown");
+ }
+
+ zend_hash_init(&vars, op_array->last, NULL, NULL, 0);
+ do {
+ char *decode = phpdbg_decode_opline(op_array, opline, &vars TSRMLS_CC);
+ if (decode != NULL) {
+ phpdbg_writeln("\t\tL%u\t%p %-30s %s",
+ opline->lineno,
+ opline,
+ phpdbg_decode_opcode(opline->opcode),
+ decode);
+ free(decode);
+ } else {
+ phpdbg_error("\tFailed to decode opline %16p", opline);
+ }
+ opline++;
+ } while (++opcode < end);
+ zend_hash_destroy(&vars);
+ }
+ } break;
+
+ default: {
+ if (method->common.scope) {
+ phpdbg_writeln("\tInternal %s::%s()", method->common.scope->name, method->common.function_name);
+ } else {
+ phpdbg_writeln("\tInternal %s()", method->common.function_name);
+ }
+ }
+ }
+} /* }}} */
+
+PHPDBG_PRINT(exec) /* {{{ */
+{
+ if (PHPDBG_G(exec)) {
+ if (!PHPDBG_G(ops)) {
+ phpdbg_compile(TSRMLS_C);
+ }
+
+ if (PHPDBG_G(ops)) {
+ phpdbg_notice("Context %s", PHPDBG_G(exec));
+
+ phpdbg_print_function_helper((zend_function*) PHPDBG_G(ops) TSRMLS_CC);
+ }
+ } else {
+ phpdbg_error("No execution context set");
+ }
+
+return SUCCESS;
+} /* }}} */
+
+PHPDBG_PRINT(stack) /* {{{ */
+{
+ zend_op_array *ops = EG(active_op_array);
+
+ if (EG(in_execution) && ops) {
+ if (ops->function_name) {
+ if (ops->scope) {
+ phpdbg_notice("Stack in %s::%s()", ops->scope->name, ops->function_name);
+ } else {
+ phpdbg_notice("Stack in %s()", ops->function_name);
+ }
+ } else {
+ if (ops->filename) {
+ phpdbg_notice("Stack in %s", ops->filename);
+ } else {
+ phpdbg_notice("Stack @ %p", ops);
+ }
+ }
+ phpdbg_print_function_helper((zend_function*) ops TSRMLS_CC);
+ } else {
+ phpdbg_error("Not Executing!");
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_PRINT(class) /* {{{ */
+{
+ zend_class_entry **ce;
+
+ switch (param->type) {
+ case STR_PARAM: {
+ if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
+ phpdbg_notice("%s %s: %s",
+ ((*ce)->type == ZEND_USER_CLASS) ?
+ "User" : "Internal",
+ ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ?
+ "Interface" :
+ ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ?
+ "Abstract Class" :
+ "Class",
+ (*ce)->name);
+
+ phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table));
+ if (zend_hash_num_elements(&(*ce)->function_table)) {
+ HashPosition position;
+ zend_function *method;
+
+ for (zend_hash_internal_pointer_reset_ex(&(*ce)->function_table, &position);
+ zend_hash_get_current_data_ex(&(*ce)->function_table, (void**) &method, &position) == SUCCESS;
+ zend_hash_move_forward_ex(&(*ce)->function_table, &position)) {
+ phpdbg_print_function_helper(method TSRMLS_CC);
+ }
+ }
+ } else {
+ phpdbg_error("The class %s could not be found", param->str);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_PRINT(method) /* {{{ */
+{
+ switch (param->type) {
+ case METHOD_PARAM: {
+ zend_class_entry **ce;
+
+ if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
+ zend_function *fbc;
+ char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
+
+ if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) {
+ phpdbg_notice("%s Method %s",
+ (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
+ fbc->common.function_name);
+
+ phpdbg_print_function_helper(fbc TSRMLS_CC);
+ } else {
+ phpdbg_error("The method %s could not be found", param->method.name);
+ }
+
+ efree(lcname);
+ } else {
+ phpdbg_error("The class %s could not be found", param->method.class);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_PRINT(func) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM: {
+ HashTable *func_table = EG(function_table);
+ zend_function* fbc;
+ const char *func_name = param->str;
+ size_t func_name_len = param->len;
+ char *lcname;
+ /* search active scope if begins with period */
+ if (func_name[0] == '.') {
+ if (EG(scope)) {
+ func_name++;
+ func_name_len--;
+
+ func_table = &EG(scope)->function_table;
+ } else {
+ phpdbg_error("No active class");
+ return SUCCESS;
+ }
+ } else if (!EG(function_table)) {
+ phpdbg_error("No function table loaded");
+ return SUCCESS;
+ } else {
+ func_table = EG(function_table);
+ }
+
+ lcname = zend_str_tolower_dup(func_name, func_name_len);
+
+ if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) {
+ phpdbg_notice("%s %s %s",
+ (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
+ (fbc->common.scope) ? "Method" : "Function",
+ fbc->common.function_name);
+
+ phpdbg_print_function_helper(fbc TSRMLS_CC);
+ } else {
+ phpdbg_error("The function %s could not be found", func_name);
+ }
+
+ efree(lcname);
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_print.h b/sapi/phpdbg/phpdbg_print.h
new file mode 100644
index 000000000..80010d5e7
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_print.h
@@ -0,0 +1,51 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_PRINT_H
+#define PHPDBG_PRINT_H
+
+#include "phpdbg_cmd.h"
+
+#define PHPDBG_PRINT(name) PHPDBG_COMMAND(print_##name)
+
+/**
+ * Printer Forward Declarations
+ */
+PHPDBG_PRINT(exec);
+PHPDBG_PRINT(opline);
+PHPDBG_PRINT(class);
+PHPDBG_PRINT(method);
+PHPDBG_PRINT(func);
+PHPDBG_PRINT(stack);
+
+/**
+ * Commands
+ */
+static const phpdbg_command_t phpdbg_print_commands[] = {
+ PHPDBG_COMMAND_D_EX(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0),
+ PHPDBG_COMMAND_D_EX(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0),
+ PHPDBG_COMMAND_D_EX(class, "print out the instructions in the specified class", 'c', print_class, NULL, 1),
+ PHPDBG_COMMAND_D_EX(method, "print out the instructions in the specified method", 'm', print_method, NULL, 1),
+ PHPDBG_COMMAND_D_EX(func, "print out the instructions in the specified function", 'f', print_func, NULL, 1),
+ PHPDBG_COMMAND_D_EX(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0),
+ PHPDBG_END_COMMAND
+};
+
+#endif /* PHPDBG_PRINT_H */
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
new file mode 100644
index 000000000..cb4640795
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -0,0 +1,1330 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "zend.h"
+#include "zend_compile.h"
+#include "phpdbg.h"
+#include "phpdbg_help.h"
+#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"
+#include "phpdbg_prompt.h"
+#include "phpdbg_cmd.h"
+#include "phpdbg_set.h"
+#include "phpdbg_frame.h"
+
+/* {{{ command declarations */
+const phpdbg_command_t phpdbg_prompt_commands[] = {
+ PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, 1),
+ PHPDBG_COMMAND_D(compile, "attempt compilation", 'c', NULL, 0),
+ PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 1),
+ PHPDBG_COMMAND_D(next, "continue execution", 'n', NULL, 0),
+ PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0),
+ PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, 1),
+ PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0),
+ PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0),
+ PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0),
+ PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 2),
+ PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1),
+ PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0),
+ PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, 1),
+ PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, 2),
+ PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, 1),
+ PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0),
+ PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0),
+ PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, 2),
+ PHPDBG_COMMAND_D(quiet, "silence some output", 'Q', NULL, 1),
+ PHPDBG_COMMAND_D(aliases, "show alias list", 'a', NULL, 0),
+ PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, 1),
+ PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, 1),
+ PHPDBG_COMMAND_D(source, "execute a phpdbginit", '.', NULL, 1),
+ PHPDBG_COMMAND_D(shell, "shell a command", '-', NULL, 1),
+ PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0),
+ PHPDBG_END_COMMAND
+}; /* }}} */
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+static inline int phpdbg_call_register(phpdbg_input_t *input TSRMLS_DC) /* {{{ */
+{
+ phpdbg_input_t *function = input->argv[0];
+
+ if (zend_hash_exists(
+ &PHPDBG_G(registered), function->string, function->length+1)) {
+
+ zval fname, *fretval;
+ zend_fcall_info fci;
+
+ ZVAL_STRINGL(&fname, function->string, function->length, 1);
+
+ memset(&fci, 0, sizeof(zend_fcall_info));
+
+ fci.size = sizeof(zend_fcall_info);
+ fci.function_table = &PHPDBG_G(registered);
+ fci.function_name = &fname;
+ fci.symbol_table = EG(active_symbol_table);
+ fci.object_ptr = NULL;
+ fci.retval_ptr_ptr = &fretval;
+ fci.no_separation = 1;
+
+ if (input->argc > 1) {
+ int param;
+ zval params;
+
+ array_init(&params);
+
+ for (param = 0; param < (input->argc-1); param++) {
+ add_next_index_stringl(
+ &params,
+ input->argv[param+1]->string,
+ input->argv[param+1]->length, 1);
+
+ phpdbg_debug(
+ "created param[%d] from argv[%d]: %s",
+ param, param+1, input->argv[param+1]->string);
+ }
+
+ zend_fcall_info_args(&fci, &params TSRMLS_CC);
+ } else {
+ fci.params = NULL;
+ fci.param_count = 0;
+ }
+
+ phpdbg_debug(
+ "created %d params from %d arguments",
+ fci.param_count, input->argc);
+
+ zend_call_function(&fci, NULL TSRMLS_CC);
+
+ if (fretval) {
+ zend_print_zval_r(
+ fretval, 0 TSRMLS_CC);
+ phpdbg_writeln(EMPTY);
+ }
+
+ zval_dtor(&fname);
+
+ return SUCCESS;
+ }
+
+ return FAILURE;
+} /* }}} */
+
+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) {
+ int line = 1;
+
+ char cmd[PHPDBG_MAX_CMD];
+ size_t cmd_len = 0L;
+ char *code = NULL;
+ size_t code_len = 0L;
+ zend_bool in_code = 0;
+
+ 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;
+ }
+ }
+ }
+
+ if (in_code) {
+ if (code == NULL) {
+ code = malloc(cmd_len + 1);
+ } else code = realloc(code, code_len + cmd_len + 1);
+
+ if (code) {
+ memcpy(
+ &code[code_len], cmd, cmd_len);
+ code_len += cmd_len;
+ }
+ goto next_line;
+ }
+
+ {
+ phpdbg_input_t *input = phpdbg_read_input(cmd TSRMLS_CC);
+ switch (phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) {
+ case FAILURE:
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) {
+ phpdbg_error("Unrecognized command in %s:%d: %s!", init_file, line, input->string);
+ }
+ }
+ break;
+ }
+ phpdbg_destroy_input(&input TSRMLS_CC);
+ }
+
+ }
+next_line:
+ line++;
+ }
+
+ if (code) {
+ free(code);
+ }
+
+ fclose(fp);
+ } else {
+ phpdbg_error(
+ "Failed to open %s for initialization", init_file);
+ }
+
+ if (free_init) {
+ free(init_file);
+ }
+ }
+} /* }}} */
+
+void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC) /* {{{ */
+{
+ if (!init_file && use_default) {
+ char *scan_dir = getenv("PHP_INI_SCAN_DIR");
+ int i;
+
+ phpdbg_try_file_init(PHPDBG_STRL(PHP_CONFIG_FILE_PATH "/" PHPDBG_INIT_FILENAME), 0 TSRMLS_CC);
+
+ if (!scan_dir) {
+ scan_dir = PHP_CONFIG_FILE_SCAN_DIR;
+ }
+ while (*scan_dir != 0) {
+ i = 0;
+ while (scan_dir[i] != ':') {
+ if (scan_dir[i++] == 0) {
+ i = -1;
+ break;
+ }
+ }
+ if (i != -1) {
+ scan_dir[i] = 0;
+ }
+
+ asprintf(
+ &init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME);
+ phpdbg_try_file_init(init_file, strlen(init_file), 1 TSRMLS_CC);
+ if (i == -1) {
+ break;
+ }
+ scan_dir += i + 1;
+ }
+
+ phpdbg_try_file_init(PHPDBG_STRL(PHPDBG_INIT_FILENAME), 0 TSRMLS_CC);
+ } else {
+ phpdbg_try_file_init(init_file, init_file_len, 1 TSRMLS_CC);
+ }
+}
+
+PHPDBG_COMMAND(exec) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM: {
+ struct stat sb;
+
+ if (VCWD_STAT(param->str, &sb) != FAILURE) {
+ if (sb.st_mode & (S_IFREG|S_IFLNK)) {
+ char *res = phpdbg_resolve_path(param->str TSRMLS_CC);
+ size_t res_len = strlen(res);
+
+ if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) {
+
+ if (PHPDBG_G(exec)) {
+ phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec));
+ efree(PHPDBG_G(exec));
+ PHPDBG_G(exec) = NULL;
+ PHPDBG_G(exec_len) = 0L;
+ }
+
+ if (PHPDBG_G(ops)) {
+ phpdbg_notice("Destroying compiled opcodes");
+ phpdbg_clean(0 TSRMLS_CC);
+ }
+
+ PHPDBG_G(exec) = res;
+ PHPDBG_G(exec_len) = res_len;
+
+ phpdbg_notice("Set execution context: %s", PHPDBG_G(exec));
+ } else {
+ phpdbg_notice("Execution context not changed");
+ }
+ } else {
+ phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str);
+ }
+ } else {
+ phpdbg_error("Cannot stat %s, ensure the file exists", param->str);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+int phpdbg_compile(TSRMLS_D) /* {{{ */
+{
+ zend_file_handle fh;
+
+ if (EG(in_execution)) {
+ phpdbg_error("Cannot compile while in execution");
+ return FAILURE;
+ }
+
+ phpdbg_notice("Attempting compilation of %s", PHPDBG_G(exec));
+
+ if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh,
+ USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC) == SUCCESS) {
+
+ PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE TSRMLS_CC);
+ zend_destroy_file_handle(&fh TSRMLS_CC);
+
+ phpdbg_notice("Success");
+ return SUCCESS;
+ } else {
+ phpdbg_error("Could not open file %s", PHPDBG_G(exec));
+ }
+
+ return FAILURE;
+} /* }}} */
+
+PHPDBG_COMMAND(compile) /* {{{ */
+{
+ if (!PHPDBG_G(exec)) {
+ phpdbg_error("No execution context");
+ return SUCCESS;
+ }
+
+ if (!EG(in_execution)) {
+ if (PHPDBG_G(ops)) {
+ phpdbg_error("Destroying previously compiled opcodes");
+ phpdbg_clean(0 TSRMLS_CC);
+ }
+ }
+
+ phpdbg_compile(TSRMLS_C);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(step) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM:
+ case NUMERIC_PARAM: {
+ if (param->type == NUMERIC_PARAM && param->num) {
+ PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
+ } else {
+ PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING;
+ }
+
+ phpdbg_notice("Stepping %s",
+ (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off");
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(next) /* {{{ */
+{
+ return PHPDBG_NEXT;
+} /* }}} */
+
+PHPDBG_COMMAND(until) /* {{{ */
+{
+ if (!EG(in_execution)) {
+ phpdbg_error("Not executing");
+ return SUCCESS;
+ }
+
+ PHPDBG_G(flags) |= PHPDBG_IN_UNTIL;
+ {
+ zend_uint next = 0,
+ self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes);
+ zend_op *opline = &EG(active_op_array)->opcodes[self];
+
+ for (next = self; next < EG(active_op_array)->last; next++) {
+ if (EG(active_op_array)->opcodes[next].lineno != opline->lineno) {
+ zend_hash_index_update(
+ &PHPDBG_G(seek),
+ (zend_ulong) &EG(active_op_array)->opcodes[next],
+ &EG(active_op_array)->opcodes[next],
+ sizeof(zend_op), NULL);
+ break;
+ }
+ }
+ }
+
+ return PHPDBG_UNTIL;
+} /* }}} */
+
+PHPDBG_COMMAND(finish) /* {{{ */
+{
+ if (!EG(in_execution)) {
+ phpdbg_error("Not executing");
+ return SUCCESS;
+ }
+
+ PHPDBG_G(flags) |= PHPDBG_IN_FINISH;
+ {
+ zend_uint next = 0,
+ self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes);
+
+ for (next = self; next < EG(active_op_array)->last; next++) {
+ switch (EG(active_op_array)->opcodes[next].opcode) {
+ case ZEND_RETURN:
+ case ZEND_THROW:
+ case ZEND_EXIT:
+#ifdef ZEND_YIELD
+ case ZEND_YIELD:
+#endif
+ zend_hash_index_update(
+ &PHPDBG_G(seek),
+ (zend_ulong) &EG(active_op_array)->opcodes[next],
+ &EG(active_op_array)->opcodes[next],
+ sizeof(zend_op), NULL);
+ break;
+ }
+ }
+ }
+
+ return PHPDBG_FINISH;
+} /* }}} */
+
+PHPDBG_COMMAND(leave) /* {{{ */
+{
+ if (!EG(in_execution)) {
+ phpdbg_error("Not executing");
+ return SUCCESS;
+ }
+
+ PHPDBG_G(flags) |= PHPDBG_IN_LEAVE;
+ {
+ zend_uint next = 0,
+ self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes);
+
+ for (next = self; next < EG(active_op_array)->last; next++) {
+ switch (EG(active_op_array)->opcodes[next].opcode) {
+ case ZEND_RETURN:
+ case ZEND_THROW:
+ case ZEND_EXIT:
+#ifdef ZEND_YIELD
+ case ZEND_YIELD:
+#endif
+ zend_hash_index_update(
+ &PHPDBG_G(seek),
+ (zend_ulong) &EG(active_op_array)->opcodes[next],
+ &EG(active_op_array)->opcodes[next],
+ sizeof(zend_op), NULL);
+ break;
+ }
+ }
+ }
+
+ return PHPDBG_LEAVE;
+} /* }}} */
+
+PHPDBG_COMMAND(frame) /* {{{ */
+{
+ switch (param->type) {
+ case NUMERIC_PARAM:
+ phpdbg_switch_frame(param->num TSRMLS_CC);
+ break;
+
+ case EMPTY_PARAM:
+ phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */
+{
+ zend_fcall_info fci;
+
+ zval fname,
+ *trace,
+ exception;
+
+ /* get filename and linenumber before unsetting exception */
+ const char *filename = zend_get_executed_filename(TSRMLS_C);
+ zend_uint lineno = zend_get_executed_lineno(TSRMLS_C);
+
+ /* copy exception */
+ exception = *EG(exception);
+ zval_copy_ctor(&exception);
+ EG(exception) = NULL;
+
+ phpdbg_error(
+ "Uncaught %s!",
+ Z_OBJCE(exception)->name);
+
+ /* call __toString */
+ ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring")-1, 1);
+ fci.size = sizeof(fci);
+ fci.function_table = &Z_OBJCE(exception)->function_table;
+ fci.function_name = &fname;
+ fci.symbol_table = NULL;
+ fci.object_ptr = &exception;
+ fci.retval_ptr_ptr = &trace;
+ fci.param_count = 0;
+ fci.params = NULL;
+ fci.no_separation = 1;
+ zend_call_function(&fci, NULL TSRMLS_CC);
+
+ if (trace) {
+ phpdbg_writeln(
+ "Uncaught %s", Z_STRVAL_P(trace));
+ /* remember to dtor trace */
+ zval_ptr_dtor(&trace);
+ }
+
+ /* output useful information about address */
+ phpdbg_writeln(
+ "Stacked entered at %p in %s on line %u",
+ EG(active_op_array)->opcodes, filename, lineno);
+
+ zval_dtor(&fname);
+ zval_dtor(&exception);
+} /* }}} */
+
+PHPDBG_COMMAND(run) /* {{{ */
+{
+ if (EG(in_execution)) {
+ phpdbg_error("Cannot start another execution while one is in progress");
+ return SUCCESS;
+ }
+
+ if (PHPDBG_G(ops) || PHPDBG_G(exec)) {
+ zend_op **orig_opline = EG(opline_ptr);
+ zend_op_array *orig_op_array = EG(active_op_array);
+ zval **orig_retval_ptr = EG(return_value_ptr_ptr);
+ zend_bool restore = 1;
+
+ if (!PHPDBG_G(ops)) {
+ if (phpdbg_compile(TSRMLS_C) == FAILURE) {
+ phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec));
+ goto out;
+ }
+ }
+
+ EG(active_op_array) = PHPDBG_G(ops);
+ EG(return_value_ptr_ptr) = &PHPDBG_G(retval);
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+
+ /* clean seek state */
+ PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK;
+ zend_hash_clean(
+ &PHPDBG_G(seek));
+
+ /* reset hit counters */
+ phpdbg_reset_breakpoints(TSRMLS_C);
+
+ zend_try {
+ php_output_activate(TSRMLS_C);
+ PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
+ zend_execute(EG(active_op_array) TSRMLS_CC);
+ PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
+ php_output_deactivate(TSRMLS_C);
+ } zend_catch {
+ EG(active_op_array) = orig_op_array;
+ EG(opline_ptr) = orig_opline;
+ EG(return_value_ptr_ptr) = orig_retval_ptr;
+
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ phpdbg_error("Caught exit/error from VM");
+ restore = 0;
+ }
+ } zend_end_try();
+
+ if (restore) {
+ if (EG(exception)) {
+ phpdbg_handle_exception(TSRMLS_C);
+ }
+
+ EG(active_op_array) = orig_op_array;
+ EG(opline_ptr) = orig_opline;
+ EG(return_value_ptr_ptr) = orig_retval_ptr;
+ }
+ } else {
+ phpdbg_error("Nothing to execute!");
+ }
+
+out:
+ PHPDBG_FRAME(num) = 0;
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(eval) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM: {
+ zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING);
+ zval retval;
+
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) {
+ PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING;
+ }
+
+ /* disable stepping while eval() in progress */
+ PHPDBG_G(flags) |= PHPDBG_IN_EVAL;
+ zend_try {
+ if (zend_eval_stringl(param->str, param->len,
+ &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) {
+ zend_print_zval_r(
+ &retval, 0 TSRMLS_CC);
+ phpdbg_writeln(EMPTY);
+ zval_dtor(&retval);
+ }
+ } zend_end_try();
+ PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL;
+
+ /* switch stepping back on */
+ if (stepping &&
+ !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) {
+ PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
+ }
+
+ CG(unclean_shutdown) = 0;
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(back) /* {{{ */
+{
+ if (!EG(in_execution)) {
+ phpdbg_error("Not executing!");
+ return SUCCESS;
+ }
+
+ switch (param->type) {
+ case EMPTY_PARAM:
+ case NUMERIC_PARAM:
+ phpdbg_dump_backtrace(
+ (param->type == NUMERIC_PARAM) ? param->num : 0 TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(print) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM: {
+ phpdbg_writeln(SEPARATE);
+ phpdbg_notice("Execution Context Information");
+#ifdef HAVE_LIBREADLINE
+ phpdbg_writeln("Readline\tyes");
+#else
+ phpdbg_writeln("Readline\tno");
+#endif
+
+ phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none");
+ phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no");
+ phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off");
+ phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off");
+ phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off");
+
+ if (PHPDBG_G(ops)) {
+ phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last);
+
+ if (PHPDBG_G(ops)->last_var) {
+ phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1);
+ } else {
+ phpdbg_writeln("Variables\tNone");
+ }
+ }
+
+ phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no");
+ if (EG(in_execution)) {
+ phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret));
+ }
+
+ phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table)));
+ phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table)));
+ phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants)));
+ phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files)));
+
+ phpdbg_writeln(SEPARATE);
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(info) /* {{{ */
+{
+ phpdbg_error(
+ "No information command selected!");
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(set) /* {{{ */
+{
+ phpdbg_error(
+ "No information command selected!");
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(break) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM:
+ phpdbg_set_breakpoint_file(
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
+ break;
+ case ADDR_PARAM:
+ phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC);
+ break;
+ case NUMERIC_PARAM:
+ if (PHPDBG_G(exec)) {
+ phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC);
+ } else {
+ phpdbg_error("Execution context not set!");
+ }
+ break;
+ case METHOD_PARAM:
+ phpdbg_set_breakpoint_method(param->method.class, param->method.name TSRMLS_CC);
+ break;
+ case NUMERIC_METHOD_PARAM:
+ phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num TSRMLS_CC);
+ break;
+ case NUMERIC_FUNCTION_PARAM:
+ phpdbg_set_breakpoint_function_opline(param->str, param->num TSRMLS_CC);
+ break;
+ case FILE_PARAM:
+ phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC);
+ break;
+ case STR_PARAM:
+ phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(shell) /* {{{ */
+{
+ /* don't allow this to loop, ever ... */
+ switch (param->type) {
+ case STR_PARAM: {
+ FILE *fd = NULL;
+ if ((fd=VCWD_POPEN((char*)param->str, "w"))) {
+ /* do something perhaps ?? do we want input ?? */
+ fclose(fd);
+ } else {
+ phpdbg_error(
+ "Failed to execute %s", param->str);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(source) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM: {
+ if (input->argc > 2) {
+ if (phpdbg_argv_is(1, "export")) {
+ FILE *h = VCWD_FOPEN(input->argv[2]->string, "w+");
+ if (h) {
+ phpdbg_export_breakpoints(h TSRMLS_CC);
+ fclose(h);
+ } else phpdbg_error("Failed to open %s", input->argv[1]->string);
+ } else {
+ phpdbg_error(
+ "Incorrect usage of source command, see help");
+ }
+ } else {
+ struct stat sb;
+ if (VCWD_STAT(param->str, &sb) != -1) {
+ phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC);
+ } else phpdbg_error("Cannot stat %s", param->str);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(register) /* {{{ */
+{
+ switch (param->type) {
+ case STR_PARAM: {
+ zend_function *function;
+ char *lcname = zend_str_tolower_dup(param->str, param->len);
+ size_t lcname_len = strlen(lcname);
+
+ if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) {
+ if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) {
+ zend_hash_update(
+ &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL);
+ function_add_ref(function);
+
+ phpdbg_notice(
+ "Registered %s", lcname);
+ } else {
+ phpdbg_error("The requested function (%s) could not be found", param->str);
+ }
+ } else {
+ phpdbg_error(
+ "The requested name (%s) is already in use", lcname);
+ }
+
+ efree(lcname);
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(quit) /* {{{ */
+{
+ /* don't allow this to loop, ever ... */
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+
+ phpdbg_destroy_input((phpdbg_input_t**)&input TSRMLS_CC);
+
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+ zend_bailout();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(clean) /* {{{ */
+{
+ if (EG(in_execution)) {
+ phpdbg_error("Cannot clean environment while executing");
+ return SUCCESS;
+ }
+
+ phpdbg_notice("Cleaning Execution Environment");
+
+ phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table)));
+ phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table)));
+ phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants)));
+ phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files)));
+
+ phpdbg_clean(1 TSRMLS_CC);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(clear) /* {{{ */
+{
+ phpdbg_notice("Clearing Breakpoints");
+
+ phpdbg_writeln("File\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]));
+ phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]));
+ phpdbg_writeln("Methods\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]));
+ phpdbg_writeln("Oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]));
+ phpdbg_writeln("File oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]));
+ phpdbg_writeln("Function oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]));
+ phpdbg_writeln("Method oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]));
+ phpdbg_writeln("Conditionals\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]));
+
+ phpdbg_clear_breakpoints(TSRMLS_C);
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(aliases) /* {{{ */
+{
+ const phpdbg_command_t *prompt_command = phpdbg_prompt_commands;
+
+ phpdbg_help_header();
+ phpdbg_writeln("Below are the aliased, short versions of all supported commands");
+ while (prompt_command && prompt_command->name) {
+ if (prompt_command->alias) {
+ if (prompt_command->subs) {
+ const phpdbg_command_t *sub_command = prompt_command->subs;
+ phpdbg_writeln(EMPTY);
+ phpdbg_writeln(" %c -> %9s", prompt_command->alias, prompt_command->name);
+ while (sub_command && sub_command->name) {
+ if (sub_command->alias) {
+ phpdbg_writeln(" |-------- %c -> %15s\t%s", sub_command->alias,
+ sub_command->name, sub_command->tip);
+ }
+ ++sub_command;
+ }
+ phpdbg_writeln(EMPTY);
+ } else {
+ phpdbg_writeln(" %c -> %9s\t\t\t%s", prompt_command->alias,
+ prompt_command->name, prompt_command->tip);
+ }
+ }
+
+ ++prompt_command;
+ }
+ phpdbg_help_footer();
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(help) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM: {
+ const phpdbg_command_t *prompt_command = phpdbg_prompt_commands;
+ const phpdbg_command_t *help_command = phpdbg_help_commands;
+
+ phpdbg_help_header();
+ phpdbg_writeln("To get help regarding a specific command type \"help command\"");
+
+ phpdbg_notice("Commands");
+
+ while (prompt_command && prompt_command->name) {
+ phpdbg_writeln(
+ " %10s\t%s", prompt_command->name, prompt_command->tip);
+ ++prompt_command;
+ }
+
+ phpdbg_notice("Help Commands");
+
+ while (help_command && help_command->name) {
+ phpdbg_writeln(" %10s\t%s", help_command->name, help_command->tip);
+ ++help_command;
+ }
+
+ phpdbg_help_footer();
+ } break;
+
+ default: {
+ phpdbg_error(
+ "No help can be found for the subject \"%s\"", param->str);
+ }
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(quiet) /* {{{ */
+{
+ switch (param->type) {
+ case NUMERIC_PARAM: {
+ if (param->num) {
+ PHPDBG_G(flags) |= PHPDBG_IS_QUIET;
+ } else {
+ PHPDBG_G(flags) &= ~PHPDBG_IS_QUIET;
+ }
+ phpdbg_notice("Quietness %s",
+ (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "enabled" : "disabled");
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_COMMAND(list) /* {{{ */
+{
+ switch (param->type) {
+ case NUMERIC_PARAM:
+ case EMPTY_PARAM:
+ return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS);
+
+ case FILE_PARAM:
+ return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS);
+
+ case STR_PARAM:
+ phpdbg_list_function_byname(param->str, param->len TSRMLS_CC);
+ break;
+
+ case METHOD_PARAM:
+ return PHPDBG_LIST_HANDLER(method)(PHPDBG_COMMAND_ARGS);
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+int phpdbg_interactive(TSRMLS_D) /* {{{ */
+{
+ int ret = SUCCESS;
+ phpdbg_input_t *input;
+
+ PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
+
+ input = phpdbg_read_input(NULL TSRMLS_CC);
+
+ if (input && input->length > 0L) {
+ do {
+ switch (ret = phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) {
+ case FAILURE:
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) {
+ phpdbg_error("Failed to execute %s!", input->string);
+ }
+ }
+ break;
+
+ case PHPDBG_LEAVE:
+ case PHPDBG_FINISH:
+ case PHPDBG_UNTIL:
+ case PHPDBG_NEXT: {
+ if (!EG(in_execution)) {
+ phpdbg_error("Not running");
+ }
+ goto out;
+ }
+ }
+
+ phpdbg_destroy_input(&input TSRMLS_CC);
+ } while ((input = phpdbg_read_input(NULL TSRMLS_CC)) && (input->length > 0L));
+
+ if (input && !input->length)
+ goto last;
+
+ } else {
+last:
+ if (PHPDBG_G(lcmd)) {
+ ret = PHPDBG_G(lcmd)->handler(
+ &PHPDBG_G(lparam), input TSRMLS_CC);
+ goto out;
+ }
+ }
+
+out:
+ phpdbg_destroy_input(&input TSRMLS_CC);
+
+ if (EG(in_execution)) {
+ phpdbg_restore_frame(TSRMLS_C);
+ }
+
+ PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE;
+
+ return ret;
+} /* }}} */
+
+void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */
+{
+ /* this is implicitly required */
+ if (PHPDBG_G(ops)) {
+ destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
+ efree(PHPDBG_G(ops));
+ PHPDBG_G(ops) = NULL;
+ }
+
+ if (full) {
+ PHPDBG_G(flags) |= PHPDBG_IS_CLEANING;
+
+ zend_bailout();
+ }
+} /* }}} */
+
+static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_array, zend_bool nested TSRMLS_DC) /* {{{ */
+{
+#if PHP_VERSION_ID >= 50500
+ return zend_create_execute_data_from_op_array(op_array, nested TSRMLS_CC);
+#else
+
+#undef EX
+#define EX(element) execute_data->element
+#undef EX_CV
+#define EX_CV(var) EX(CVs)[var]
+#undef EX_CVs
+#define EX_CVs() EX(CVs)
+#undef EX_T
+#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))
+#undef EX_Ts
+#define EX_Ts() EX(Ts)
+
+ zend_execute_data *execute_data = (zend_execute_data *)zend_vm_stack_alloc(
+ ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) +
+ ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) +
+ ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC);
+
+ EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)));
+ memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var);
+ EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)));
+ EX(fbc) = NULL;
+ EX(called_scope) = NULL;
+ EX(object) = NULL;
+ EX(old_error_reporting) = NULL;
+ EX(op_array) = op_array;
+ EX(symbol_table) = EG(active_symbol_table);
+ EX(prev_execute_data) = EG(current_execute_data);
+ EG(current_execute_data) = execute_data;
+ EX(nested) = nested;
+
+ if (!op_array->run_time_cache && op_array->last_cache_slot) {
+ op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
+ }
+
+ if (op_array->this_var != -1 && EG(This)) {
+ Z_ADDREF_P(EG(This)); /* For $this pointer */
+ if (!EG(active_symbol_table)) {
+ EX_CV(op_array->this_var) = (zval**)EX_CVs() + (op_array->last_var + op_array->this_var);
+ *EX_CV(op_array->this_var) = EG(This);
+ } else {
+ if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX_CV(op_array->this_var))==FAILURE) {
+ Z_DELREF_P(EG(This));
+ }
+ }
+ }
+
+ EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes;
+ EG(opline_ptr) = &EX(opline);
+
+ EX(function_state).function = (zend_function *) op_array;
+ EX(function_state).arguments = NULL;
+
+ return execute_data;
+#endif
+} /* }}} */
+
+#if PHP_VERSION_ID >= 50500
+void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
+{
+#else
+void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+ long long flags = 0;
+ zend_ulong address = 0L;
+ zend_execute_data *execute_data;
+ zend_bool nested = 0;
+#endif
+ zend_bool original_in_execution = EG(in_execution);
+ HashTable vars;
+
+#if PHP_VERSION_ID < 50500
+ if (EG(exception)) {
+ return;
+ }
+#endif
+
+ EG(in_execution) = 1;
+
+#if PHP_VERSION_ID >= 50500
+ if (0) {
+zend_vm_enter:
+ execute_data = phpdbg_create_execute_data(EG(active_op_array), 1 TSRMLS_CC);
+ }
+ zend_hash_init(&vars, EG(active_op_array)->last, NULL, NULL, 0);
+#else
+zend_vm_enter:
+ execute_data = phpdbg_create_execute_data(op_array, nested TSRMLS_CC);
+ nested = 1;
+ zend_hash_init(&vars, EG(active_op_array)->last, NULL, NULL, 0);
+#endif
+
+ while (1) {
+
+ if ((PHPDBG_G(flags) & PHPDBG_BP_RESOLVE_MASK)) {
+ /* resolve nth opline breakpoints */
+ phpdbg_resolve_op_array_breaks(EG(active_op_array) TSRMLS_CC);
+ }
+
+#ifdef ZEND_WIN32
+ if (EG(timed_out)) {
+ zend_timeout(0);
+ }
+#endif
+
+#define DO_INTERACTIVE() do { \
+ if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \
+ phpdbg_list_file( \
+ zend_get_executed_filename(TSRMLS_C), \
+ 3, \
+ zend_get_executed_lineno(TSRMLS_C)-1, \
+ zend_get_executed_lineno(TSRMLS_C) \
+ TSRMLS_CC \
+ ); \
+ } \
+ \
+ do { \
+ switch (phpdbg_interactive(TSRMLS_C)) { \
+ case PHPDBG_LEAVE: \
+ case PHPDBG_FINISH: \
+ case PHPDBG_UNTIL: \
+ case PHPDBG_NEXT:{ \
+ goto next; \
+ } \
+ } \
+ } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); \
+} while (0)
+
+ /* allow conditional breakpoints and
+ initialization to access the vm uninterrupted */
+ if ((PHPDBG_G(flags) & PHPDBG_IN_COND_BP) ||
+ (PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) {
+ /* skip possible breakpoints */
+ goto next;
+ }
+
+ /* perform seek operation */
+ if (PHPDBG_G(flags) & PHPDBG_SEEK_MASK) {
+ /* current address */
+ zend_ulong address = (zend_ulong) execute_data->opline;
+
+ /* run to next line */
+ if (PHPDBG_G(flags) & PHPDBG_IN_UNTIL) {
+ if (zend_hash_index_exists(&PHPDBG_G(seek), address)) {
+ PHPDBG_G(flags) &= ~PHPDBG_IN_UNTIL;
+ zend_hash_clean(
+ &PHPDBG_G(seek));
+ } else {
+ /* skip possible breakpoints */
+ goto next;
+ }
+ }
+
+ /* run to finish */
+ if (PHPDBG_G(flags) & PHPDBG_IN_FINISH) {
+ if (zend_hash_index_exists(&PHPDBG_G(seek), address)) {
+ PHPDBG_G(flags) &= ~PHPDBG_IN_FINISH;
+ zend_hash_clean(
+ &PHPDBG_G(seek));
+ }
+ /* skip possible breakpoints */
+ goto next;
+ }
+
+ /* break for leave */
+ if (PHPDBG_G(flags) & PHPDBG_IN_LEAVE) {
+ if (zend_hash_index_exists(&PHPDBG_G(seek), address)) {
+ PHPDBG_G(flags) &= ~PHPDBG_IN_LEAVE;
+ zend_hash_clean(
+ &PHPDBG_G(seek));
+ phpdbg_notice(
+ "Breaking for leave at %s:%u",
+ zend_get_executed_filename(TSRMLS_C),
+ zend_get_executed_lineno(TSRMLS_C)
+ );
+ DO_INTERACTIVE();
+ } else {
+ /* skip possible breakpoints */
+ goto next;
+ }
+ }
+ }
+
+ /* not while in conditionals */
+ phpdbg_print_opline_ex(
+ execute_data, &vars, 0 TSRMLS_CC);
+
+ /* search for breakpoints */
+ {
+ phpdbg_breakbase_t *brake;
+
+ if ((PHPDBG_G(flags) & PHPDBG_BP_MASK) &&
+ (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC))) {
+ phpdbg_hit_breakpoint(
+ brake, 1 TSRMLS_CC);
+ DO_INTERACTIVE();
+ }
+ }
+
+ if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) {
+ DO_INTERACTIVE();
+ }
+
+next:
+ if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
+ phpdbg_writeln(EMPTY);
+ phpdbg_notice("Program received signal SIGINT");
+ PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
+ DO_INTERACTIVE();
+ }
+
+ PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC);
+
+ if (PHPDBG_G(vmret) > 0) {
+ switch (PHPDBG_G(vmret)) {
+ case 1:
+ EG(in_execution) = original_in_execution;
+ zend_hash_destroy(&vars);
+ return;
+ case 2:
+#if PHP_VERSION_ID < 50500
+ op_array = EG(active_op_array);
+#endif
+ zend_hash_destroy(&vars);
+ goto zend_vm_enter;
+ break;
+ case 3:
+ execute_data = EG(current_execute_data);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_prompt.h b/sapi/phpdbg/phpdbg_prompt.h
new file mode 100644
index 000000000..6807d88f4
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_prompt.h
@@ -0,0 +1,68 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_PROMPT_H
+#define PHPDBG_PROMPT_H
+
+/* {{{ */
+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(TSRMLS_D);
+int phpdbg_compile(TSRMLS_D);
+void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */
+
+/* {{{ phpdbg command handlers */
+PHPDBG_COMMAND(exec);
+PHPDBG_COMMAND(compile);
+PHPDBG_COMMAND(step);
+PHPDBG_COMMAND(next);
+PHPDBG_COMMAND(run);
+PHPDBG_COMMAND(eval);
+PHPDBG_COMMAND(until);
+PHPDBG_COMMAND(finish);
+PHPDBG_COMMAND(leave);
+PHPDBG_COMMAND(frame);
+PHPDBG_COMMAND(print);
+PHPDBG_COMMAND(break);
+PHPDBG_COMMAND(back);
+PHPDBG_COMMAND(list);
+PHPDBG_COMMAND(info);
+PHPDBG_COMMAND(clean);
+PHPDBG_COMMAND(clear);
+PHPDBG_COMMAND(help);
+PHPDBG_COMMAND(quiet);
+PHPDBG_COMMAND(aliases);
+PHPDBG_COMMAND(shell);
+PHPDBG_COMMAND(set);
+PHPDBG_COMMAND(source);
+PHPDBG_COMMAND(register);
+PHPDBG_COMMAND(quit); /* }}} */
+
+/* {{{ prompt commands */
+extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */
+
+/* {{{ */
+#if PHP_VERSION_ID >= 50500
+void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC);
+#else
+void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC);
+#endif /* }}} */
+
+#endif /* PHPDBG_PROMPT_H */
diff --git a/sapi/phpdbg/phpdbg_set.c b/sapi/phpdbg/phpdbg_set.c
new file mode 100644
index 000000000..7c4da12a4
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_set.c
@@ -0,0 +1,208 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg.h"
+#include "phpdbg_cmd.h"
+#include "phpdbg_set.h"
+#include "phpdbg_utils.h"
+#include "phpdbg_bp.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+PHPDBG_SET(prompt) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM:
+ phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C));
+ break;
+
+ case STR_PARAM:
+ phpdbg_set_prompt(param->str TSRMLS_CC);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_SET(break) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM:
+ phpdbg_writeln("%s",
+ PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off");
+ break;
+
+ case STR_PARAM:
+ if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) {
+ phpdbg_enable_breakpoints(TSRMLS_C);
+ } else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) {
+ phpdbg_disable_breakpoints(TSRMLS_C);
+ }
+ break;
+
+ case NUMERIC_PARAM: {
+ if (input->argc > 2) {
+ if (phpdbg_argv_is(2, "on")) {
+ phpdbg_enable_breakpoint(param->num TSRMLS_CC);
+ } else if (phpdbg_argv_is(2, "off")) {
+ phpdbg_disable_breakpoint(param->num TSRMLS_CC);
+ }
+ } else {
+ phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC);
+ if (brake) {
+ phpdbg_writeln(
+ "%s", brake->disabled ? "off" : "on");
+ } else {
+ phpdbg_error("Failed to find breakpoint #%lx", param->num);
+ }
+ }
+ } break;
+
+ default:
+ phpdbg_error(
+ "set break used incorrectly: set break [id] <on|off>");
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+#ifndef _WIN32
+PHPDBG_SET(color) /* {{{ */
+{
+ if ((param->type == STR_PARAM) && (input->argc == 3)) {
+ const phpdbg_color_t *color = phpdbg_get_color(
+ input->argv[2]->string, input->argv[2]->length TSRMLS_CC);
+ int element = PHPDBG_COLOR_INVALID;
+
+ /* @TODO(anyone) make this consistent with other set commands */
+ if (color) {
+ if (phpdbg_argv_is(1, "prompt")) {
+ phpdbg_notice(
+ "setting prompt color to %s (%s)", color->name, color->code);
+ element = PHPDBG_COLOR_PROMPT;
+ if (PHPDBG_G(prompt)[1]) {
+ free(PHPDBG_G(prompt)[1]);
+ PHPDBG_G(prompt)[1]=NULL;
+ }
+ } else if (phpdbg_argv_is(1, "error")) {
+ phpdbg_notice(
+ "setting error color to %s (%s)", color->name, color->code);
+ element = PHPDBG_COLOR_ERROR;
+
+ } else if (phpdbg_argv_is(1, "notice")) {
+ phpdbg_notice(
+ "setting notice color to %s (%s)", color->name, color->code);
+ element = PHPDBG_COLOR_NOTICE;
+
+ } else goto usage;
+
+ /* set color for element */
+ phpdbg_set_color(element, color TSRMLS_CC);
+ } else {
+ phpdbg_error(
+ "Failed to find the requested color (%s)", input->argv[2]->string);
+ }
+ } else {
+usage:
+ phpdbg_error(
+ "set color used incorrectly: set color <prompt|error|notice> <color>");
+ }
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_SET(colors) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM: {
+ phpdbg_writeln(
+ "%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off");
+ goto done;
+ }
+
+ case STR_PARAM: {
+ if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) {
+ PHPDBG_G(flags) |= PHPDBG_IS_COLOURED;
+ goto done;
+ } else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) {
+ PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED;
+ goto done;
+ }
+ }
+
+ default:
+ phpdbg_error(
+ "set colors used incorrectly: set colors <on|off>");
+ }
+
+done:
+ return SUCCESS;
+} /* }}} */
+#endif
+
+PHPDBG_SET(oplog) /* {{{ */
+{
+ switch (param->type) {
+ case EMPTY_PARAM:
+ phpdbg_notice(
+ "Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled");
+ break;
+
+ case NUMERIC_PARAM: switch (param->num) {
+ case 1:
+ phpdbg_error(
+ "An output file must be provided to enable oplog");
+ break;
+
+ case 0: {
+ if (PHPDBG_G(oplog)) {
+ phpdbg_notice("Disabling oplog");
+ fclose(
+ PHPDBG_G(oplog));
+ } else {
+ phpdbg_error("Oplog is not enabled!");
+ }
+ } break;
+ } break;
+
+ case STR_PARAM: {
+ /* open oplog */
+ FILE *old = PHPDBG_G(oplog);
+
+ PHPDBG_G(oplog) = fopen(param->str, "w+");
+ if (!PHPDBG_G(oplog)) {
+ phpdbg_error("Failed to open %s for oplog", param->str);
+ PHPDBG_G(oplog) = old;
+ } else {
+ if (old) {
+ phpdbg_notice("Closing previously open oplog");
+ fclose(old);
+ }
+ phpdbg_notice("Successfully opened oplog %s", param->str);
+ }
+ } break;
+
+ phpdbg_default_switch_case();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
diff --git a/sapi/phpdbg/phpdbg_set.h b/sapi/phpdbg/phpdbg_set.h
new file mode 100644
index 000000000..120aeb34f
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_set.h
@@ -0,0 +1,47 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_SET_H
+#define PHPDBG_SET_H
+
+#include "phpdbg_cmd.h"
+
+#define PHPDBG_SET(name) PHPDBG_COMMAND(set_##name)
+
+PHPDBG_SET(prompt);
+#ifndef _WIN32
+PHPDBG_SET(color);
+PHPDBG_SET(colors);
+#endif
+PHPDBG_SET(oplog);
+PHPDBG_SET(break);
+
+static const phpdbg_command_t phpdbg_set_commands[] = {
+ PHPDBG_COMMAND_D_EX(prompt, "usage: set prompt <string>", 'p', set_prompt, NULL, 0),
+#ifndef _WIN32
+ PHPDBG_COMMAND_D_EX(color, "usage: set color <element> <color>", 'c', set_color, NULL, 1),
+ PHPDBG_COMMAND_D_EX(colors, "usage: set colors <on|off>", 'C', set_colors, NULL, 1),
+#endif
+ PHPDBG_COMMAND_D_EX(oplog, "usage: set oplog <output>", 'O', set_oplog, NULL, 0),
+ PHPDBG_COMMAND_D_EX(break, "usage: set break [id] <on|off>", 'b', set_break, NULL, 0),
+ PHPDBG_END_COMMAND
+};
+
+#endif /* PHPDBG_SET_H */
diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c
new file mode 100644
index 000000000..1effcfcca
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_utils.c
@@ -0,0 +1,387 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "zend.h"
+#include "php.h"
+#include "spprintf.h"
+#include "phpdbg.h"
+#include "phpdbg_opcode.h"
+#include "phpdbg_utils.h"
+
+#ifdef _WIN32
+# include "win32/time.h"
+#endif
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+/* {{{ color structures */
+const static phpdbg_color_t colors[] = {
+ PHPDBG_COLOR_D("none", "0;0"),
+
+ PHPDBG_COLOR_D("white", "0;64"),
+ PHPDBG_COLOR_D("white-bold", "1;64"),
+ PHPDBG_COLOR_D("white-underline", "4;64"),
+ PHPDBG_COLOR_D("red", "0;31"),
+ PHPDBG_COLOR_D("red-bold", "1;31"),
+ PHPDBG_COLOR_D("red-underline", "4;31"),
+ PHPDBG_COLOR_D("green", "0;32"),
+ PHPDBG_COLOR_D("green-bold", "1;32"),
+ PHPDBG_COLOR_D("green-underline", "4;32"),
+ PHPDBG_COLOR_D("yellow", "0;33"),
+ PHPDBG_COLOR_D("yellow-bold", "1;33"),
+ PHPDBG_COLOR_D("yellow-underline", "4;33"),
+ PHPDBG_COLOR_D("blue", "0;34"),
+ PHPDBG_COLOR_D("blue-bold", "1;34"),
+ PHPDBG_COLOR_D("blue-underline", "4;34"),
+ PHPDBG_COLOR_D("purple", "0;35"),
+ PHPDBG_COLOR_D("purple-bold", "1;35"),
+ PHPDBG_COLOR_D("purple-underline", "4;35"),
+ PHPDBG_COLOR_D("cyan", "0;36"),
+ PHPDBG_COLOR_D("cyan-bold", "1;36"),
+ PHPDBG_COLOR_D("cyan-underline", "4;36"),
+ PHPDBG_COLOR_D("black", "0;30"),
+ PHPDBG_COLOR_D("black-bold", "1;30"),
+ PHPDBG_COLOR_D("black-underline", "4;30"),
+ PHPDBG_COLOR_END
+}; /* }}} */
+
+PHPDBG_API int phpdbg_is_numeric(const char *str) /* {{{ */
+{
+ if (!str)
+ return 0;
+
+ for (; *str; str++) {
+ if (isspace(*str) || *str == '-') {
+ continue;
+ }
+ return isdigit(*str);
+ }
+ return 0;
+} /* }}} */
+
+PHPDBG_API int phpdbg_is_empty(const char *str) /* {{{ */
+{
+ if (!str)
+ return 1;
+
+ for (; *str; str++) {
+ if (isspace(*str)) {
+ continue;
+ }
+ return 0;
+ }
+ return 1;
+} /* }}} */
+
+PHPDBG_API int phpdbg_is_addr(const char *str) /* {{{ */
+{
+ return str[0] && str[1] && memcmp(str, "0x", 2) == 0;
+} /* }}} */
+
+PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class, char **method) /* {{{ */
+{
+ char *sep = NULL;
+
+ if (strstr(str, "#") != NULL)
+ return 0;
+
+ if (strstr(str, " ") != NULL)
+ return 0;
+
+ sep = strstr(str, "::");
+
+ if (!sep || sep == str || sep+2 == str+len-1) {
+ return 0;
+ }
+
+ if (class != NULL) {
+
+ if (str[0] == '\\') {
+ str++;
+ len--;
+ }
+
+ *class = estrndup(str, sep - str);
+ (*class)[sep - str] = 0;
+ }
+
+ if (method != NULL) {
+ *method = estrndup(sep+2, str + len - (sep + 2));
+ }
+
+ return 1;
+} /* }}} */
+
+PHPDBG_API char *phpdbg_resolve_path(const char *path TSRMLS_DC) /* {{{ */
+{
+ char resolved_name[MAXPATHLEN];
+
+ if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
+ return NULL;
+ }
+
+ return estrdup(resolved_name);
+} /* }}} */
+
+PHPDBG_API const char *phpdbg_current_file(TSRMLS_D) /* {{{ */
+{
+ const char *file = zend_get_executed_filename(TSRMLS_C);
+
+ if (memcmp(file, "[no active file]", sizeof("[no active file]")) == 0) {
+ return PHPDBG_G(exec);
+ }
+
+ return file;
+} /* }}} */
+
+PHPDBG_API const zend_function *phpdbg_get_function(const char *fname, const char *cname TSRMLS_DC) /* {{{ */
+{
+ zend_function *func = NULL;
+ size_t fname_len = strlen(fname);
+ char *lcname = zend_str_tolower_dup(fname, fname_len);
+
+ if (cname) {
+ zend_class_entry **ce;
+ size_t cname_len = strlen(cname);
+ char *lc_cname = zend_str_tolower_dup(cname, cname_len);
+ int ret = zend_lookup_class(lc_cname, cname_len, &ce TSRMLS_CC);
+
+ efree(lc_cname);
+
+ if (ret == SUCCESS) {
+ zend_hash_find(&(*ce)->function_table, lcname, fname_len+1,
+ (void**)&func);
+ }
+ } else {
+ zend_hash_find(EG(function_table), lcname, fname_len+1,
+ (void**)&func);
+ }
+
+ efree(lcname);
+ return func;
+} /* }}} */
+
+PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{{ */
+{
+ const char *p = str;
+ char *new = NULL;
+
+ while (p && isspace(*p)) {
+ ++p;
+ --len;
+ }
+
+ while (*p && isspace(*(p + len -1))) {
+ --len;
+ }
+
+ if (len == 0) {
+ new = estrndup("", sizeof(""));
+ *new_len = 0;
+ } else {
+ new = estrndup(p, len);
+ *(new + len) = '\0';
+
+ if (new_len) {
+ *new_len = len;
+ }
+ }
+
+ return new;
+
+} /* }}} */
+
+PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */
+{
+ int rc = 0;
+ char *buffer = NULL;
+ va_list args;
+
+ if (format != NULL && strlen(format) > 0L) {
+ va_start(args, format);
+ vspprintf(&buffer, 0, format, args);
+ va_end(args);
+ }
+
+ /* TODO(anyone) colours */
+
+ switch (type) {
+ case P_ERROR:
+ if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
+ rc = fprintf(fp,
+ "\033[%sm[%s]\033[0m\n",
+ PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer);
+ } else {
+ rc = fprintf(fp, "[%s]\n", buffer);
+ }
+ break;
+
+ case P_NOTICE:
+ if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
+ rc = fprintf(fp,
+ "\033[%sm[%s]\033[0m\n",
+ PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer);
+ } else {
+ rc = fprintf(fp, "[%s]\n", buffer);
+ }
+ break;
+
+ case P_WRITELN: {
+ if (buffer) {
+ rc = fprintf(fp, "%s\n", buffer);
+ } else {
+ rc = fprintf(fp, "\n");
+ }
+ } break;
+
+ case P_WRITE:
+ if (buffer) {
+ rc = fprintf(fp, "%s", buffer);
+ }
+ break;
+
+ /* no formatting on logging output */
+ case P_LOG:
+ if (buffer) {
+ struct timeval tp;
+ if (gettimeofday(&tp, NULL) == SUCCESS) {
+ rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer);
+ } else {
+ rc = FAILURE;
+ }
+ }
+ break;
+ }
+
+ if (buffer) {
+ efree(buffer);
+ }
+
+ return rc;
+} /* }}} */
+
+PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
+ int rc = 0;
+
+ va_list args;
+ struct timeval tp;
+
+ va_start(args, fmt);
+ if (gettimeofday(&tp, NULL) == SUCCESS) {
+ char friendly[100];
+ char *format = NULL, *buffer = NULL;
+ const time_t tt = tp.tv_sec;
+
+ strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt));
+ asprintf(
+ &buffer, friendly, tp.tv_usec/1000);
+ asprintf(
+ &format, "[%s]: %s\n", buffer, fmt);
+ rc = vfprintf(
+ fp, format, args);
+
+ free(format);
+ free(buffer);
+ }
+ va_end(args);
+
+ return rc;
+} /* }}} */
+
+PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */
+{
+ const phpdbg_color_t *color = colors;
+
+ while (color && color->name) {
+ if (name_length == color->name_length &&
+ memcmp(name, color->name, name_length) == SUCCESS) {
+ phpdbg_debug(
+ "phpdbg_get_color(%s, %lu): %s", name, name_length, color->code);
+ return color;
+ }
+ ++color;
+ }
+
+ phpdbg_debug(
+ "phpdbg_get_color(%s, %lu): failed", name, name_length);
+
+ return NULL;
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC) /* {{{ */
+{
+ PHPDBG_G(colors)[element] = color;
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC) /* {{{ */
+{
+ const phpdbg_color_t *color = phpdbg_get_color(name, name_length TSRMLS_CC);
+
+ if (color) {
+ phpdbg_set_color(element, color TSRMLS_CC);
+ } else PHPDBG_G(colors)[element] = colors;
+} /* }}} */
+
+PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D) /* {{{ */
+{
+ return colors;
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_prompt(const char *prompt TSRMLS_DC) /* {{{ */
+{
+ /* free formatted prompt */
+ if (PHPDBG_G(prompt)[1]) {
+ free(PHPDBG_G(prompt)[1]);
+ PHPDBG_G(prompt)[1] = NULL;
+ }
+ /* free old prompt */
+ if (PHPDBG_G(prompt)[0]) {
+ free(PHPDBG_G(prompt)[0]);
+ PHPDBG_G(prompt)[0] = NULL;
+ }
+
+ /* copy new prompt */
+ PHPDBG_G(prompt)[0] = strdup(prompt);
+} /* }}} */
+
+PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */
+{
+ /* find cached prompt */
+ if (PHPDBG_G(prompt)[1]) {
+ return PHPDBG_G(prompt)[1];
+ }
+
+ /* create cached prompt */
+ if ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED)) {
+ asprintf(
+ &PHPDBG_G(prompt)[1], "\033[%sm%s\033[0m ",
+ PHPDBG_G(colors)[PHPDBG_COLOR_PROMPT]->code,
+ PHPDBG_G(prompt)[0]);
+ } else {
+ asprintf(
+ &PHPDBG_G(prompt)[1], "%s ",
+ PHPDBG_G(prompt)[0]);
+ }
+
+ return PHPDBG_G(prompt)[1];
+} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_utils.h b/sapi/phpdbg/phpdbg_utils.h
new file mode 100644
index 000000000..c5164c3ac
--- /dev/null
+++ b/sapi/phpdbg/phpdbg_utils.h
@@ -0,0 +1,110 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2014 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_UTILS_H
+#define PHPDBG_UTILS_H
+
+/**
+ * Input scan functions
+ */
+PHPDBG_API int phpdbg_is_numeric(const char*);
+PHPDBG_API int phpdbg_is_empty(const char*);
+PHPDBG_API int phpdbg_is_addr(const char*);
+PHPDBG_API int phpdbg_is_class_method(const char*, size_t, char**, char**);
+PHPDBG_API const char *phpdbg_current_file(TSRMLS_D);
+PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC);
+PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*);
+PHPDBG_API const zend_function *phpdbg_get_function(const char*, const char* TSRMLS_DC);
+
+/**
+ * Error/notice/formatting helpers
+ */
+enum {
+ P_ERROR = 1,
+ P_NOTICE,
+ P_WRITELN,
+ P_WRITE,
+ P_LOG
+};
+
+#ifdef ZTS
+PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5);
+#else
+PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
+#endif
+
+PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...);
+
+#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
+#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
+#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
+#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
+#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
+
+#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__)
+#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
+#define phpdbg_writeln_ex(out, fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, fmt, ##__VA_ARGS__)
+#define phpdbg_write_ex(out, fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
+#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__)
+
+#if PHPDBG_DEBUG
+# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__)
+#else
+# define phpdbg_debug(fmt, ...)
+#endif
+
+/* {{{ For writing blank lines */
+#define EMPTY NULL /* }}} */
+
+/* {{{ For prompt lines */
+#define PROMPT "phpdbg>" /* }}} */
+
+/* {{{ For separation */
+#define SEPARATE "------------------------------------------------" /* }}} */
+
+/* {{{ Color Management */
+#define PHPDBG_COLOR_LEN 12
+#define PHPDBG_COLOR_D(color, code) \
+ {color, sizeof(color)-1, code}
+#define PHPDBG_COLOR_END \
+ {NULL, 0L, {0}}
+
+#define PHPDBG_COLOR_INVALID -1
+#define PHPDBG_COLOR_PROMPT 0
+#define PHPDBG_COLOR_ERROR 1
+#define PHPDBG_COLOR_NOTICE 2
+#define PHPDBG_COLORS 3
+
+typedef struct _phpdbg_color_t {
+ char *name;
+ size_t name_length;
+ const char code[PHPDBG_COLOR_LEN];
+} phpdbg_color_t;
+
+PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC);
+PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC);
+PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC);
+PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D); /* }}} */
+
+/* {{{ Prompt Management */
+PHPDBG_API void phpdbg_set_prompt(const char* TSRMLS_DC);
+PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */
+
+#endif /* PHPDBG_UTILS_H */
diff --git a/sapi/phpdbg/test.php b/sapi/phpdbg/test.php
new file mode 100644
index 000000000..5fdbcbe1a
--- /dev/null
+++ b/sapi/phpdbg/test.php
@@ -0,0 +1,51 @@
+<?php
+if (isset($include)) {
+ include (sprintf("%s/web-bootstrap.php", dirname(__FILE__)));
+}
+
+$stdout = fopen("php://stdout", "w+");
+
+class phpdbg {
+ public function isGreat($greeting = null) {
+ printf(
+ "%s: %s\n", __METHOD__, $greeting);
+ return $this;
+ }
+}
+
+function test($x, $y = 0) {
+ $var = $x + 1;
+ $var += 2;
+ $var <<= 3;
+
+ $foo = function () {
+ echo "bar!\n";
+ };
+
+ $foo();
+
+ yield $var;
+}
+
+$dbg = new phpdbg();
+
+var_dump(
+ $dbg->isGreat("PHP Rocks!!"));
+
+foreach (test(1,2) as $gen)
+ continue;
+
+echo "it works!\n";
+
+if (isset($dump))
+ var_dump($_SERVER);
+
+function phpdbg_test_ob()
+{
+ echo 'Start';
+ ob_start();
+ echo 'Hello';
+ $b = ob_get_clean();
+ echo 'End';
+ echo $b;
+}
diff --git a/sapi/phpdbg/tests/commands/0001_basic.test b/sapi/phpdbg/tests/commands/0001_basic.test
new file mode 100644
index 000000000..08aa9ab66
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0001_basic.test
@@ -0,0 +1,8 @@
+#######################################################
+# name: basic
+# purpose: check basic functionality of phpdbg console
+# expect: TEST::EXACT
+# options: -rr
+#######################################################
+# [Nothing to execute!]
+#######################################################
diff --git a/sapi/phpdbg/tests/commands/0002_set.test b/sapi/phpdbg/tests/commands/0002_set.test
new file mode 100644
index 000000000..7720f94ff
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0002_set.test
@@ -0,0 +1,23 @@
+#################################################
+# name: set
+# purpose: tests for set commands
+# expect: TEST::CISTRING
+# options: -rr
+#################################################
+# setting prompt color
+# setting error color
+# setting notice color
+# Failed to find breakpoint #0
+# oplog disabled
+# not enabled
+# opened oplog test.log
+# nothing
+#################################################
+set color prompt none
+set color error none
+set color notice none
+set prompt promot>
+set break 0
+set oplog
+set oplog 0
+set oplog test.log
diff --git a/sapi/phpdbg/tests/commands/0101_info.test b/sapi/phpdbg/tests/commands/0101_info.test
new file mode 100644
index 000000000..397a45c99
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0101_info.test
@@ -0,0 +1,19 @@
+#################################################
+# name: info
+# purpose: test info commands
+# expect: TEST::FORMAT
+# options: -rr
+#################################################
+#[User Classes (%d)]
+#User Class test (3)
+#|---- in phpdbginit code on line %d
+#################################################
+<:
+class test {
+ public function testMethod(){}
+ private function testPrivateMethod(){}
+ protected function testProtectedMethod(){}
+}
+:>
+info classes
+q
diff --git a/sapi/phpdbg/tests/commands/0102_print.test b/sapi/phpdbg/tests/commands/0102_print.test
new file mode 100644
index 000000000..de4acb765
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0102_print.test
@@ -0,0 +1,28 @@
+#################################################
+# name: print
+# purpose: test print commands
+# expect: TEST::FORMAT
+# options: -rr
+#################################################
+#[User Class: test]
+#Methods (3):
+#L%d-%d test::testMethod() %s
+# L%d %s ZEND_RETURN C%d <unused> <unused>
+# L%d-%d test::testPrivateMethod() %s
+# L%d %s ZEND_RETURN C%d <unused> <unused>
+# L%d-%d test::testProtectedMethod() %s
+# L%d %s ZEND_RETURN C%d <unused> <unused>
+#[User Method testMethod]
+# L%d-%d test::testMethod() %s
+# L%d %s ZEND_RETURN C%d <unused> <unused>
+#################################################
+<:
+class test {
+ public function testMethod(){}
+ private function testPrivateMethod(){}
+ protected function testProtectedMethod(){}
+}
+:>
+print class test
+print method test::testMethod
+q
diff --git a/sapi/phpdbg/tests/commands/0103_register.test b/sapi/phpdbg/tests/commands/0103_register.test
new file mode 100644
index 000000000..38841591c
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0103_register.test
@@ -0,0 +1,28 @@
+#################################################
+# name: register
+# purpose: test registration functions
+# expect: TEST::FORMAT
+# options: -rr
+#################################################
+#[Registered test_function]
+#array(5) {
+# [0]=>
+# string(1) "1"
+# [1]=>
+# string(1) "2"
+# [2]=>
+# string(1) "3"
+# [3]=>
+# string(1) "4"
+# [4]=>
+# string(1) "5"
+#}
+#################################################
+<:
+function test_function() {
+ var_dump(func_get_args());
+}
+:>
+R test_function
+test_function 1 2 3 4 5
+q
diff --git a/sapi/phpdbg/tests/commands/0104_clean.test b/sapi/phpdbg/tests/commands/0104_clean.test
new file mode 100644
index 000000000..c7a579be1
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0104_clean.test
@@ -0,0 +1,15 @@
+#################################################
+# name: clean
+# purpose: test cleaning environment
+# expect: TEST::FORMAT
+# options: -rr
+#################################################
+#[Cleaning Execution Environment]
+#Classes %d
+#Functions %d
+#Constants %d
+#Includes %d
+#[Nothing to execute!]
+#################################################
+clean
+quit
diff --git a/sapi/phpdbg/tests/commands/0105_clear.test b/sapi/phpdbg/tests/commands/0105_clear.test
new file mode 100644
index 000000000..b547b0d6b
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0105_clear.test
@@ -0,0 +1,18 @@
+#################################################
+# name: clear
+# purpose: test clearing breakpoints
+# expect: TEST::FORMAT
+# options: -rr
+#################################################
+#[Clearing Breakpoints]
+#File%w%d
+#Functions%w%d
+#Methods%w%d
+#Oplines%w%d
+#File oplines%w%d
+#Function oplines%w%d
+#Method oplines%w%d
+#Conditionals%w%d
+#################################################
+clear
+quit
diff --git a/sapi/phpdbg/tests/commands/0106_compile.test b/sapi/phpdbg/tests/commands/0106_compile.test
new file mode 100644
index 000000000..d79211ddf
--- /dev/null
+++ b/sapi/phpdbg/tests/commands/0106_compile.test
@@ -0,0 +1,19 @@
+#################################################
+# name: compile
+# purpose: test compiling code
+# expect: TEST::FORMAT
+# options: -rr
+#################################################
+#[Attempting compilation of %s]
+#[Success]
+#Hello World
+#################################################
+<:
+define('OUT',
+ tempnam(null, "phpdbg"));
+file_put_contents(OUT, "<?php echo \"Hello World\"; ?>");
+phpdbg_exec(OUT);
+:>
+compile
+run
+quit
diff --git a/sapi/phpdbg/tests/run-tests.php b/sapi/phpdbg/tests/run-tests.php
new file mode 100644
index 000000000..1fb6fa122
--- /dev/null
+++ b/sapi/phpdbg/tests/run-tests.php
@@ -0,0 +1,583 @@
+<?php
+namespace phpdbg\testing {
+
+ /*
+ * Workaround ...
+ */
+ if (!defined('DIR_SEP'))
+ define('DIR_SEP', '\\' . DIRECTORY_SEPARATOR);
+
+ /**
+ * TestConfigurationExceptions are thrown
+ * when the configuration prohibits tests executing
+ *
+ * @package phpdbg
+ * @subpackage testing
+ */
+ class TestConfigurationException extends \Exception {
+
+ /**
+ *
+ * @param array Tests confguration
+ * @param message Exception message
+ * @param ... formatting parameters
+ */
+ public function __construct() {
+ $argv = func_get_args();
+
+ if (count($argv)) {
+
+ $this->config = array_shift($argv);
+ $this->message = vsprintf(
+ array_shift($argv), $argv);
+ }
+ }
+ }
+
+ /**
+ *
+ * @package phpdbg
+ * @subpackage testing
+ */
+ class TestsConfiguration implements \ArrayAccess {
+
+ /**
+ *
+ * @param array basic configuration
+ * @param array argv
+ */
+ public function __construct($config, $cmd) {
+ $this->options = $config;
+ while (($key = array_shift($cmd))) {
+ switch (substr($key, 0, 1)) {
+ case '-': switch(substr($key, 1, 1)) {
+ case '-': {
+ $arg = substr($key, 2);
+ if (($e=strpos($arg, '=')) !== false) {
+ $key = substr($arg, 0, $e);
+ $value = substr($arg, $e+1);
+ } else {
+ $key = $arg;
+ $value = array_shift($cmd);
+ }
+
+ if (isset($key) && isset($value)) {
+ switch ($key) {
+ case 'phpdbg':
+ case 'width':
+ $this->options[$key] = $value;
+ break;
+
+ default: {
+ if (isset($config[$key])) {
+ if (is_array($config[$key])) {
+ $this->options[$key][] = $value;
+ } else {
+ $this->options[$key] = array($config[$key], $value);
+ }
+ } else {
+ $this->options[$key] = $value;
+ }
+ }
+ }
+
+ }
+ } break;
+
+ default:
+ $this->flags[] = substr($key, 1);
+ } break;
+ }
+ }
+
+ if (!is_executable($this->options['phpdbg'])) {
+ throw new TestConfigurationException(
+ $this->options, 'phpdbg could not be found at the specified path (%s)', $this->options['phpdbg']);
+ } else $this->options['phpdbg'] = realpath($this->options['phpdbg']);
+
+ $this->options['width'] = (integer) $this->options['width'];
+
+ /* display properly, all the time */
+ if ($this->options['width'] < 50) {
+ $this->options['width'] = 50;
+ }
+
+ /* calculate column widths */
+ $this->options['lwidth'] = ceil($this->options['width'] / 3);
+ $this->options['rwidth'] = ceil($this->options['width'] - $this->options['lwidth']) - 5;
+ }
+
+ public function hasFlag($flag) {
+ return in_array(
+ $flag, $this->flags);
+ }
+
+ public function offsetExists($offset) { return isset($this->options[$offset]); }
+ public function offsetGet($offset) { return $this->options[$offset]; }
+ public function offsetUnset($offset) { unset($this->options[$offset]); }
+ public function offsetSet($offset, $data) { $this->options[$offset] = $data; }
+
+ protected $options = array();
+ protected $flags = array();
+ }
+
+ /**
+ * Tests is the console programming API for the test suite
+ *
+ * @package phpdbg
+ * @subpackage testing
+ */
+ class Tests {
+
+ /**
+ * Construct the console object
+ *
+ * @param array basic configuration
+ * @param array command line
+ */
+ public function __construct(TestsConfiguration &$config) {
+ $this->config = &$config;
+
+ if ($this->config->hasFlag('help') ||
+ $this->config->hasFlag('h')) {
+ $this->showUsage();
+ exit;
+ }
+ }
+
+ /**
+ * Find valid paths as specified by configuration
+ *
+ */
+ public function findPaths($in = null) {
+ $paths = array();
+ $where = ($in != null) ? array($in) : $this->config['path'];
+
+ foreach ($where as &$path) {
+ if ($path) {
+ if (is_dir($path)) {
+ $paths[] = $path;
+ foreach (scandir($path) as $child) {
+ if ($child != '.' && $child != '..') {
+ $paths = array_merge(
+ $paths, $this->findPaths("$path/$child"));
+ }
+ }
+ }
+ }
+ }
+
+ return $paths;
+ }
+
+ /**
+ *
+ * @param string the path to log
+ */
+ public function logPath($path) {
+ printf(
+ '%s [%s]%s',
+ str_repeat(
+ '-', $this->config['width'] - strlen($path)),
+ $path, PHP_EOL);
+ }
+
+ /**
+ *
+ * @param string the path to log
+ */
+ public function logPathStats($path) {
+ if (!isset($this->stats[$path])) {
+ return;
+ }
+
+ $total = array_sum($this->stats[$path]);
+
+ if ($total) {
+ @$this->totals[true] += $this->stats[$path][true];
+ @$this->totals[false] += $this->stats[$path][false];
+
+ $stats = @sprintf(
+ "%d/%d %%%d",
+ $this->stats[$path][true],
+ $this->stats[$path][false],
+ (100 / $total) * $this->stats[$path][true]);
+
+ printf(
+ '%s [%s]%s',
+ str_repeat(
+ ' ', $this->config['width'] - strlen($stats)),
+ $stats, PHP_EOL);
+
+ printf("%s%s", str_repeat('-', $this->config['width']+3), PHP_EOL);
+ printf("%s", PHP_EOL);
+ }
+ }
+
+ /**
+ *
+ */
+ public function logStats() {
+ $total = array_sum($this->totals);
+ $stats = @sprintf(
+ "%d/%d %%%d",
+ $this->totals[true],
+ $this->totals[false],
+ (100 / $total) * $this->totals[true]);
+ printf(
+ '%s [%s]%s',
+ str_repeat(
+ ' ', $this->config['width'] - strlen($stats)),
+ $stats, PHP_EOL);
+
+ }
+
+ /**
+ *
+ */
+ protected function showUsage() {
+ printf('usage: php %s [flags] [options]%s', $this->config['exec'], PHP_EOL);
+ printf('[options]:%s', PHP_EOL);
+ printf("\t--path\t\tadd a path to scan outside of tests directory%s", PHP_EOL);
+ printf("\t--width\t\tset line width%s", PHP_EOL);
+ printf("\t--options\toptions to pass to phpdbg%s", PHP_EOL);
+ printf("\t--phpdbg\tpath to phpdbg binary%s", PHP_EOL);
+ printf('[flags]:%s', PHP_EOL);
+ printf("\t-nodiff\t\tdo not write diffs on failure%s", PHP_EOL);
+ printf("\t-nolog\t\tdo not write logs on failure%s", PHP_EOL);
+ printf('[examples]:%s', PHP_EOL);
+ printf("\tphp %s --phpdbg=/usr/local/bin/phpdbg --path=/usr/src/phpdbg/tests --options -n%s",
+ $this->config['exec'], PHP_EOL);
+
+ }
+
+ /**
+ * Find valid tests at the specified path (assumed valid)
+ *
+ * @param string a valid path
+ */
+ public function findTests($path) {
+ $tests = array();
+
+ foreach (scandir($path) as $file) {
+ if ($file == '.' || $file == '..')
+ continue;
+
+ $test = sprintf('%s/%s', $path, $file);
+
+ if (preg_match('~\.test$~', $test)) {
+ yield new Test($this->config, $test);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param Test the test to log
+ */
+ public function logTest($path, Test $test) {
+ @$this->stats[$path][($result=$test->getResult())]++;
+
+ printf(
+ "%-{$this->config['lwidth']}s %-{$this->config['rwidth']}s [%s]%s",
+ $test->name,
+ $test->purpose,
+ $result ? "PASS" : "FAIL",
+ PHP_EOL);
+ }
+
+ protected $config;
+ }
+
+ class Test {
+ /*
+ * Expect exact line for line match
+ */
+ const EXACT = 0x00000001;
+
+ /*
+ * Expect strpos() !== false
+ */
+ const STRING = 0x00000010;
+
+ /*
+ * Expect stripos() !== false
+ */
+ const CISTRING = 0x00000100;
+
+ /*
+ * Formatted output
+ */
+ const FORMAT = 0x00001000;
+
+ /**
+ * Format specifiers
+ */
+ private static $format = array(
+ 'search' => array(
+ '%e',
+ '%s',
+ '%S',
+ '%a',
+ '%A',
+ '%w',
+ '%i',
+ '%d',
+ '%x',
+ '%f',
+ '%c',
+ '%t',
+ '%T'
+ ),
+ 'replace' => array(
+ DIR_SEP,
+ '[^\r\n]+',
+ '[^\r\n]*',
+ '.+',
+ '.*',
+ '\s*',
+ '[+-]?\d+',
+ '\d+',
+ '[0-9a-fA-F]+',
+ '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
+ '.',
+ '\t',
+ '\t+'
+ )
+ );
+
+ /**
+ * Constructs a new Test object given a specilized phpdbginit file
+ *
+ * @param array configuration
+ * @param string file
+ */
+ public function __construct(TestsConfiguration &$config, &$file) {
+ if (($handle = fopen($file, 'r'))) {
+ while (($line = fgets($handle))) {
+ $trim = trim($line);
+
+ switch (substr($trim, 0, 1)) {
+ case '#': if (($chunks = array_map('trim', preg_split('~:~', substr($trim, 1), 2)))) {
+ if (property_exists($this, $chunks[0])) {
+ switch ($chunks[0]) {
+ case 'expect': {
+ if ($chunks[1]) {
+ switch (strtoupper($chunks[1])) {
+ case 'TEST::EXACT':
+ case 'EXACT': { $this->expect = TEST::EXACT; } break;
+
+ case 'TEST::STRING':
+ case 'STRING': { $this->expect = TEST::STRING; } break;
+
+ case 'TEST::CISTRING':
+ case 'CISTRING': { $this->expect = TEST::CISTRING; } break;
+
+ case 'TEST::FORMAT':
+ case 'FORMAT': { $this->expect = TEST::FORMAT; } break;
+
+ default:
+ throw new TestConfigurationException(
+ $this->config, "unknown type of expectation (%s)", $chunks[1]);
+ }
+ }
+ } break;
+
+ default: {
+ $this->$chunks[0] = $chunks[1];
+ }
+ }
+ } else switch(substr($trim, 1, 1)) {
+ case '#': { /* do nothing */ } break;
+
+ default: {
+ $line = preg_replace(
+ "~(\r\n)~", "\n", substr($trim, 1));
+
+ $line = trim($line);
+
+ switch ($this->expect) {
+ case TEST::FORMAT:
+ $this->match[] = str_replace(
+ self::$format['search'],
+ self::$format['replace'], preg_quote($line));
+ break;
+
+ default: $this->match[] = $line;
+ }
+ }
+ }
+ } break;
+
+ default:
+ break 2;
+ }
+ }
+ fclose($handle);
+
+ $this->config = &$config;
+ $this->file = &$file;
+ }
+ }
+
+ /**
+ * Obvious!!
+ *
+ */
+ public function getResult() {
+ $options = sprintf(
+ '-i%s -qb', $this->file);
+
+ if ($this->options) {
+ $options = sprintf(
+ '%s %s %s',
+ $options,
+ $this->config['options'],
+ $this->options
+ );
+ } else {
+ $options = sprintf(
+ '%s %s', $options, $this->config['options']
+ );
+ }
+
+ $result = `{$this->config['phpdbg']} {$options}`;
+
+ if ($result) {
+ foreach (preg_split('~(\r|\n)~', $result) as $num => $line) {
+ if (!$line && !isset($this->match[$num]))
+ continue;
+
+ switch ($this->expect) {
+ case TEST::EXACT: {
+ if (strcmp($line, $this->match[$num]) !== 0) {
+ $this->diff['wants'][$num] = &$this->match[$num];
+ $this->diff['gets'][$num] = $line;
+ }
+ } continue 2;
+
+ case TEST::STRING: {
+ if (strpos($line, $this->match[$num]) === false) {
+ $this->diff['wants'][$num] = &$this->match[$num];
+ $this->diff['gets'][$num] = $line;
+ }
+ } continue 2;
+
+ case TEST::CISTRING: {
+ if (stripos($line, $this->match[$num]) === false) {
+ $this->diff['wants'][$num] = &$this->match[$num];
+ $this->diff['gets'][$num] = $line;
+ }
+ } continue 2;
+
+ case TEST::FORMAT: {
+ $line = trim($line);
+ if (!preg_match("/^{$this->match[$num]}\$/s", $line)) {
+ $this->diff['wants'][$num] = &$this->match[$num];
+ $this->diff['gets'][$num] = $line;
+ }
+ } continue 2;
+ }
+ }
+ }
+
+ $this->writeLog($result);
+ $this->writeDiff();
+
+ return (count($this->diff) == 0);
+ }
+
+ /**
+ * Write diff to disk if configuration allows it
+ *
+ */
+ protected function writeDiff() {
+ $diff = sprintf(
+ '%s/%s.diff',
+ dirname($this->file), basename($this->file));
+
+ if (count($this->diff['wants'])) {
+ if (!in_array('nodiff', $this->config['flags'])) {
+ if (($diff = fopen($diff, 'w+'))) {
+
+ foreach ($this->diff['wants'] as $line => $want) {
+ $got = $this->diff['gets'][$line];
+
+ fprintf(
+ $diff, '(%d) -%s%s', $line+1, $want, PHP_EOL);
+ fprintf(
+ $diff, '(%d) +%s%s', $line+1, $got, PHP_EOL);
+ }
+
+ fclose($diff);
+ }
+ }
+ } else unlink($diff);
+ }
+
+ /**
+ * Write log to disk if configuration allows it
+ *
+ */
+ protected function writeLog(&$result = null) {
+ $log = sprintf(
+ '%s/%s.log',
+ dirname($this->file), basename($this->file));
+
+ if (count($this->diff) && $result) {
+ if (!in_array('nolog', $this->config['flags'])) {
+ @file_put_contents(
+ $log, $result);
+ }
+ } else unlink($log);
+ }
+
+ public $name;
+ public $purpose;
+ public $file;
+ public $options;
+ public $expect;
+
+ protected $match;
+ protected $diff;
+ protected $stats;
+ protected $totals;
+ }
+}
+
+namespace {
+ use \phpdbg\Testing\Test;
+ use \phpdbg\Testing\Tests;
+ use \phpdbg\Testing\TestsConfiguration;
+
+ $cwd = dirname(__FILE__);
+ $cmd = $_SERVER['argv'];
+ {
+ $config = new TestsConfiguration(array(
+ 'exec' => realpath(array_shift($cmd)),
+ 'phpdbg' => realpath(sprintf(
+ '%s/../phpdbg', $cwd
+ )),
+ 'path' => array(
+ realpath(dirname(__FILE__))
+ ),
+ 'flags' => array(),
+ 'width' => 75
+ ), $cmd);
+
+ $tests = new Tests($config);
+
+ foreach ($tests->findPaths() as $path) {
+ $tests->logPath($path);
+
+ foreach ($tests->findTests($path) as $test) {
+ $tests->logTest($path, $test);
+ }
+
+ $tests->logPathStats($path);
+ }
+
+ $tests->logStats();
+ }
+}
+?>
diff --git a/sapi/phpdbg/travis/ci.sh b/sapi/phpdbg/travis/ci.sh
new file mode 100755
index 000000000..44d56a01f
--- /dev/null
+++ b/sapi/phpdbg/travis/ci.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env sh
+git clone https://github.com/php/php-src
+cd php-src/sapi
+git clone https://github.com/krakjoe/phpdbg.git
+cd ../
+./buildconf --force
+./configure --disable-all --enable-phpdbg --enable-maintainer-zts
+make
+make test-phpdbg
diff --git a/sapi/phpdbg/web-bootstrap.php b/sapi/phpdbg/web-bootstrap.php
new file mode 100644
index 000000000..7b8c5d30d
--- /dev/null
+++ b/sapi/phpdbg/web-bootstrap.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * The following file shows how to bootstrap phpdbg so that you can mock specific server environments
+ *
+ * eval include("web-bootstrap.php")
+ * exec index.php
+ * compile
+ * break ...
+ * run
+ */
+if (!defined('PHPDBG_BOOTSTRAPPED'))
+{
+ /* define these once */
+ define("PHPDBG_BOOTPATH", "/opt/php-zts/htdocs");
+ define("PHPDBG_BOOTSTRAP", "index.php");
+ define("PHPDBG_BOOTSTRAPPED", sprintf("/%s", PHPDBG_BOOTSTRAP));
+}
+
+/*
+ * Superglobals are JIT, phpdbg will not over-write whatever you set during bootstrap
+ */
+
+$_SERVER = array
+(
+ 'HTTP_HOST' => 'localhost',
+ 'HTTP_CONNECTION' => 'keep-alive',
+ 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ 'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.65 Safari/537.36',
+ 'HTTP_ACCEPT_ENCODING' => 'gzip,deflate,sdch',
+ 'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
+ 'HTTP_COOKIE' => 'tz=Europe%2FLondon; __utma=1.347100075.1384196523.1384196523.1384196523.1; __utmc=1; __utmz=1.1384196523.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)',
+ 'PATH' => '/usr/local/bin:/usr/bin:/bin',
+ 'SERVER_SIGNATURE' => '<address>Apache/2.4.6 (Ubuntu) Server at phpdbg.com Port 80</address>',
+ 'SERVER_SOFTWARE' => 'Apache/2.4.6 (Ubuntu)',
+ 'SERVER_NAME' => 'localhost',
+ 'SERVER_ADDR' => '127.0.0.1',
+ 'SERVER_PORT' => '80',
+ 'REMOTE_ADDR' => '127.0.0.1',
+ 'DOCUMENT_ROOT' => PHPDBG_BOOTPATH,
+ 'REQUEST_SCHEME' => 'http',
+ 'CONTEXT_PREFIX' => '',
+ 'CONTEXT_DOCUMENT_ROOT' => PHPDBG_BOOTPATH,
+ 'SERVER_ADMIN' => '[no address given]',
+ 'SCRIPT_FILENAME' => sprintf(
+ '%s/%s', PHPDBG_BOOTPATH, PHPDBG_BOOTSTRAP
+ ),
+ 'REMOTE_PORT' => '47931',
+ 'GATEWAY_INTERFACE' => 'CGI/1.1',
+ 'SERVER_PROTOCOL' => 'HTTP/1.1',
+ 'REQUEST_METHOD' => 'GET',
+ 'QUERY_STRING' => '',
+ 'REQUEST_URI' => PHPDBG_BOOTSTRAPPED,
+ 'SCRIPT_NAME' => PHPDBG_BOOTSTRAPPED,
+ 'PHP_SELF' => PHPDBG_BOOTSTRAPPED,
+ 'REQUEST_TIME' => time(),
+);
+
+$_GET = array();
+$_REQUEST = array();
+$_POST = array();
+$_COOKIE = array();
+$_FILES = array();
+
+chdir(PHPDBG_BOOTPATH);
diff --git a/sapi/phttpd/php_phttpd.h b/sapi/phttpd/php_phttpd.h
index 49089cffb..92409ac90 100644
--- a/sapi/phttpd/php_phttpd.h
+++ b/sapi/phttpd/php_phttpd.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/phttpd/phttpd.c b/sapi/phttpd/phttpd.c
index c2e917202..60fc48ba3 100644
--- a/sapi/phttpd/phttpd.c
+++ b/sapi/phttpd/phttpd.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/pi3web/pi3web_sapi.c b/sapi/pi3web/pi3web_sapi.c
index 64eb2a6c9..4bc08e538 100644
--- a/sapi/pi3web/pi3web_sapi.c
+++ b/sapi/pi3web/pi3web_sapi.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/roxen/roxen.c b/sapi/roxen/roxen.c
index c897ef62b..b3a64345e 100644
--- a/sapi/roxen/roxen.c
+++ b/sapi/roxen/roxen.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/thttpd/php_thttpd.h b/sapi/thttpd/php_thttpd.h
index 40d63d27b..75e79b405 100644
--- a/sapi/thttpd/php_thttpd.h
+++ b/sapi/thttpd/php_thttpd.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/thttpd/thttpd.c b/sapi/thttpd/thttpd.c
index 548bcda17..843e4a62f 100644
--- a/sapi/thttpd/thttpd.c
+++ b/sapi/thttpd/thttpd.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/tux/php_tux.c b/sapi/tux/php_tux.c
index 968dd9eb9..55d911f8a 100644
--- a/sapi/tux/php_tux.c
+++ b/sapi/tux/php_tux.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/webjames/php_webjames.h b/sapi/webjames/php_webjames.h
index f9903d164..dcb6cdb91 100644
--- a/sapi/webjames/php_webjames.h
+++ b/sapi/webjames/php_webjames.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/sapi/webjames/webjames.c b/sapi/webjames/webjames.c
index 9237ac7dd..264f910af 100644
--- a/sapi/webjames/webjames.c
+++ b/sapi/webjames/webjames.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
+ | Copyright (c) 1997-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |