summaryrefslogtreecommitdiff
path: root/sapi/phpdbg
diff options
context:
space:
mode:
Diffstat (limited to 'sapi/phpdbg')
-rw-r--r--sapi/phpdbg/Makefile.frag2
-rw-r--r--sapi/phpdbg/config.m419
-rw-r--r--sapi/phpdbg/config.w323
-rw-r--r--sapi/phpdbg/create-test.php150
-rw-r--r--sapi/phpdbg/phpdbg.c1117
-rw-r--r--sapi/phpdbg/phpdbg.h53
-rw-r--r--sapi/phpdbg/phpdbg_bp.c183
-rw-r--r--sapi/phpdbg/phpdbg_bp.h3
-rw-r--r--sapi/phpdbg/phpdbg_break.c4
-rw-r--r--sapi/phpdbg/phpdbg_break.h2
-rw-r--r--sapi/phpdbg/phpdbg_btree.c92
-rw-r--r--sapi/phpdbg/phpdbg_btree.h4
-rw-r--r--sapi/phpdbg/phpdbg_cmd.c136
-rw-r--r--sapi/phpdbg/phpdbg_cmd.h5
-rw-r--r--sapi/phpdbg/phpdbg_eol.c4
-rw-r--r--sapi/phpdbg/phpdbg_eol.h2
-rw-r--r--sapi/phpdbg/phpdbg_frame.c137
-rw-r--r--sapi/phpdbg/phpdbg_frame.h4
-rw-r--r--sapi/phpdbg/phpdbg_help.c140
-rw-r--r--sapi/phpdbg/phpdbg_help.h4
-rw-r--r--sapi/phpdbg/phpdbg_info.c55
-rw-r--r--sapi/phpdbg/phpdbg_info.h2
-rw-r--r--sapi/phpdbg/phpdbg_io.c49
-rw-r--r--sapi/phpdbg/phpdbg_io.h7
-rw-r--r--sapi/phpdbg/phpdbg_lexer.c2521
-rw-r--r--sapi/phpdbg/phpdbg_lexer.h3
-rw-r--r--sapi/phpdbg/phpdbg_lexer.l75
-rw-r--r--sapi/phpdbg/phpdbg_list.c183
-rw-r--r--sapi/phpdbg/phpdbg_list.h5
-rw-r--r--sapi/phpdbg/phpdbg_opcode.c170
-rw-r--r--sapi/phpdbg/phpdbg_opcode.h8
-rw-r--r--sapi/phpdbg/phpdbg_out.c5
-rw-r--r--sapi/phpdbg/phpdbg_out.h17
-rw-r--r--sapi/phpdbg/phpdbg_parser.c1074
-rw-r--r--sapi/phpdbg/phpdbg_parser.h92
-rw-r--r--sapi/phpdbg/phpdbg_parser.y32
-rw-r--r--sapi/phpdbg/phpdbg_print.c53
-rw-r--r--sapi/phpdbg/phpdbg_print.h2
-rw-r--r--sapi/phpdbg/phpdbg_prompt.c725
-rw-r--r--sapi/phpdbg/phpdbg_prompt.h13
-rw-r--r--sapi/phpdbg/phpdbg_rinit_hook.c2
-rw-r--r--sapi/phpdbg/phpdbg_rinit_hook.h2
-rw-r--r--sapi/phpdbg/phpdbg_set.c42
-rw-r--r--sapi/phpdbg/phpdbg_set.h4
-rw-r--r--sapi/phpdbg/phpdbg_sigio_win32.c4
-rw-r--r--sapi/phpdbg/phpdbg_sigio_win32.h2
-rw-r--r--sapi/phpdbg/phpdbg_sigsafe.c10
-rw-r--r--sapi/phpdbg/phpdbg_sigsafe.h5
-rw-r--r--sapi/phpdbg/phpdbg_utils.c132
-rw-r--r--sapi/phpdbg/phpdbg_utils.h15
-rw-r--r--sapi/phpdbg/phpdbg_wait.c41
-rw-r--r--sapi/phpdbg/phpdbg_wait.h2
-rw-r--r--sapi/phpdbg/phpdbg_watch.c1901
-rw-r--r--sapi/phpdbg/phpdbg_watch.h68
-rw-r--r--sapi/phpdbg/phpdbg_webdata_transfer.c4
-rw-r--r--sapi/phpdbg/phpdbg_webdata_transfer.h2
-rw-r--r--sapi/phpdbg/phpdbg_win.c2
-rw-r--r--sapi/phpdbg/phpdbg_win.h2
-rw-r--r--sapi/phpdbg/tests/basic_run.phpt8
-rw-r--r--sapi/phpdbg/tests/breakpoints_001.phpt33
-rw-r--r--sapi/phpdbg/tests/breakpoints_002.phpt40
-rw-r--r--sapi/phpdbg/tests/breakpoints_003.phpt33
-rw-r--r--sapi/phpdbg/tests/breakpoints_004.phpt41
-rw-r--r--sapi/phpdbg/tests/breakpoints_005.phpt28
-rw-r--r--sapi/phpdbg/tests/breakpoints_006.phpt26
-rw-r--r--sapi/phpdbg/tests/breakpoints_007.phpt25
-rw-r--r--sapi/phpdbg/tests/breakpoints_008.phpt34
-rw-r--r--sapi/phpdbg/tests/bug73615.phpt18
-rw-r--r--sapi/phpdbg/tests/bug73615/.phpdbginit2
-rw-r--r--sapi/phpdbg/tests/bug73704.phpt27
-rw-r--r--sapi/phpdbg/tests/bug73794.phpt11
-rw-r--r--sapi/phpdbg/tests/clean_001.phpt60
-rw-r--r--sapi/phpdbg/tests/clear_001.phpt44
-rw-r--r--sapi/phpdbg/tests/commands/0001_basic.test8
-rw-r--r--sapi/phpdbg/tests/commands/0002_set.test21
-rw-r--r--sapi/phpdbg/tests/commands/0101_info.test19
-rw-r--r--sapi/phpdbg/tests/commands/0102_print.test27
-rw-r--r--sapi/phpdbg/tests/commands/0103_register.test28
-rw-r--r--sapi/phpdbg/tests/commands/0104_clean.test14
-rw-r--r--sapi/phpdbg/tests/commands/0105_clear.test18
-rw-r--r--sapi/phpdbg/tests/commands/0106_compile.test18
-rw-r--r--sapi/phpdbg/tests/commands/0107_compile.test17
-rw-r--r--sapi/phpdbg/tests/delimiter.phpt7
-rw-r--r--sapi/phpdbg/tests/exceptions_001.phpt48
-rw-r--r--sapi/phpdbg/tests/exceptions_002.phpt51
-rw-r--r--sapi/phpdbg/tests/exceptions_003.phpt54
-rw-r--r--sapi/phpdbg/tests/finish_leave_001.phpt43
-rw-r--r--sapi/phpdbg/tests/generator_run.phpt24
-rw-r--r--sapi/phpdbg/tests/include.inc3
-rw-r--r--sapi/phpdbg/tests/include_once.phpt16
-rw-r--r--sapi/phpdbg/tests/info_001.phpt80
-rw-r--r--sapi/phpdbg/tests/info_002.phpt31
-rw-r--r--sapi/phpdbg/tests/next_001.phpt37
-rw-r--r--sapi/phpdbg/tests/normal_exit.phpt15
-rw-r--r--sapi/phpdbg/tests/phpdbg_break_next.phpt22
-rw-r--r--sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.inc6
-rw-r--r--sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.phpt84
-rw-r--r--sapi/phpdbg/tests/phpdbg_oplog_001.phpt58
-rw-r--r--sapi/phpdbg/tests/phpdbg_oplog_002.phpt16
-rw-r--r--sapi/phpdbg/tests/print_001.phpt67
-rw-r--r--sapi/phpdbg/tests/print_002.phpt51
-rw-r--r--sapi/phpdbg/tests/run-tests.php597
-rw-r--r--sapi/phpdbg/tests/run_001.phpt56
-rw-r--r--sapi/phpdbg/tests/run_002.phpt50
-rw-r--r--sapi/phpdbg/tests/set_exception_handler.phpt19
-rw-r--r--sapi/phpdbg/tests/stdin_001.phpt25
-rw-r--r--sapi/phpdbg/tests/stepping_001.phpt67
-rw-r--r--sapi/phpdbg/tests/watch_001.phpt47
-rw-r--r--sapi/phpdbg/tests/watch_002.phpt32
-rw-r--r--sapi/phpdbg/tests/watch_003.phpt39
-rw-r--r--sapi/phpdbg/tests/watch_004.phpt38
-rw-r--r--sapi/phpdbg/tests/watch_005.phpt48
-rw-r--r--sapi/phpdbg/tests/watch_006.phpt71
-rw-r--r--sapi/phpdbg/zend_mm_structs.h102
114 files changed, 7561 insertions, 4338 deletions
diff --git a/sapi/phpdbg/Makefile.frag b/sapi/phpdbg/Makefile.frag
index 36c7512d69..e0cdfe25ef 100644
--- a/sapi/phpdbg/Makefile.frag
+++ b/sapi/phpdbg/Makefile.frag
@@ -14,7 +14,7 @@ $(BUILD_BINARY): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS)
$(builddir)/phpdbg_lexer.lo: $(srcdir)/phpdbg_parser.h
$(srcdir)/phpdbg_lexer.c: $(srcdir)/phpdbg_lexer.l
- @(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date -cbdFo $(srcdir)/phpdbg_lexer.c $(srcdir)/phpdbg_lexer.l)
+ @(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date -cbdFo sapi/phpdbg/phpdbg_lexer.c sapi/phpdbg/phpdbg_lexer.l)
$(srcdir)/phpdbg_parser.h: $(srcdir)/phpdbg_parser.c
$(srcdir)/phpdbg_parser.c: $(srcdir)/phpdbg_parser.y
diff --git a/sapi/phpdbg/config.m4 b/sapi/phpdbg/config.m4
index 87d38ea8c5..9fb4e62984 100644
--- a/sapi/phpdbg/config.m4
+++ b/sapi/phpdbg/config.m4
@@ -3,15 +3,15 @@ dnl $Id$
dnl
PHP_ARG_ENABLE(phpdbg, for phpdbg support,
-[ --enable-phpdbg Build phpdbg], no, no)
+[ --enable-phpdbg Build phpdbg], yes, yes)
PHP_ARG_ENABLE(phpdbg-webhelper, for phpdbg web SAPI support,
-[ --enable-phpdbg-webhelper Build phpdbg web SAPI support], yes, yes)
+[ --enable-phpdbg-webhelper Build phpdbg web SAPI support], no)
PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build,
[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no)
-if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then
+if test "$BUILD_PHPDBG" = "" && test "$PHP_PHPDBG" != "no"; then
AC_HEADER_TIOCGWINSZ
AC_DEFINE(HAVE_PHPDBG, 1, [ ])
@@ -21,14 +21,7 @@ if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then
AC_DEFINE(PHPDBG_DEBUG, 0, [ ])
fi
- if test "$PHP_PHPDBG_WEBHELPER" != "no"; then
- if ! test -d $abs_srcdir/ext/phpdbg_webhelper; then
- ln -s ../sapi/phpdbg $abs_srcdir/ext/phpdbg_webhelper
- fi
- PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared)
- fi
-
- PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
+ PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"
PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c phpdbg_eol.c phpdbg_out.c"
if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then
@@ -72,6 +65,10 @@ if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then
PHP_SUBST(BUILD_PHPDBG_SHARED)
fi
+if test "$PHP_PHPDBG_WEBHELPER" != "no"; then
+ PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared)
+fi
+
dnl ## Local Variables:
dnl ## tab-width: 4
dnl ## End:
diff --git a/sapi/phpdbg/config.w32 b/sapi/phpdbg/config.w32
index 8a685d3347..2d907ee697 100644
--- a/sapi/phpdbg/config.w32
+++ b/sapi/phpdbg/config.w32
@@ -9,9 +9,10 @@ PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.
'phpdbg_sigio_win32.c phpdbg_eol.c phpdbg_out.c';
PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll';
PHPDBG_EXE='phpdbg.exe';
+PHPDBG_CFLAGS='/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1';
if (PHP_PHPDBG == "yes") {
- SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE);
+ SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE, PHPDBG_CFLAGS);
ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib");
ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H");
ADD_FLAG("LDFLAGS_PHPDBG", "/stack:8388608");
diff --git a/sapi/phpdbg/create-test.php b/sapi/phpdbg/create-test.php
new file mode 100644
index 0000000000..0d79fad5dd
--- /dev/null
+++ b/sapi/phpdbg/create-test.php
@@ -0,0 +1,150 @@
+#!/usr/bin/env php
+<?php
+
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 7 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2016 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: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#####
+## This is just a helper for intercepting stdin/stdout and the file and create a half-finished test.
+## The output still may need adapting to match file names etc.
+#####
+
+error_reporting(-1);
+
+$phpdbg = getenv('TEST_PHPDBG_EXECUTABLE') ?: null;
+$pass_options = ' -qbI -n -d "error_reporting=32767" -d "display_errors=1" -d "display_startup_errors=1" -d "log_errors=0"';
+$file = "";
+$cmdargv = "";
+
+if (isset($argc) && $argc > 1) {
+ $post_ddash = false;
+ for ($i = 1; $i < $argc; $i++) {
+ if ($argv[$i][0] == "-" && !$post_ddash) {
+ switch (substr($argv[$i], 1)) {
+ case "p":
+ $phpdbg = $argv[++$i];
+ break;
+ case "n":
+ $pass_options .= " -n";
+ break;
+ case "d":
+ $pass_options .= " -d ".escapeshellarg($argv[++$i]);
+ $ini[] = $argv[$i];
+ break;
+ case "-":
+ $post_ddash = true;
+ break;
+ }
+ } else {
+ $real_argv[] = $argv[$i];
+ }
+ }
+ if (isset($real_argv[0])) {
+ $file = realpath($real_argv[0]);
+ $cmdargv = implode(" ", array_map("escapeshellarg", array_slice($real_argv, 1)));
+ }
+}
+
+$proc = proc_open("$phpdbg $pass_options $file -- $cmdargv", [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]], $pipes);
+if (!$proc) {
+ die("Couldn't start phpdbg\n");
+}
+
+$input = $output = "";
+
+stream_set_blocking(STDIN, false);
+
+do {
+ $r = [$pipes[1], STDIN];
+ $w = $e = null;
+ $n = @stream_select($r, $w, $e, null);
+
+ if ($n > 0) {
+ if ("" != $in = fread(STDIN, 1024)) {
+ $input .= $in;
+ fwrite($pipes[0], $in);
+ continue;
+ }
+
+ if (feof(STDIN)) {
+ die("stdin closed?!\n");
+ }
+
+ if (feof($pipes[1])) {
+ $n = false;
+ } else {
+ $output .= $c = fgetc($pipes[1]);
+ echo $c;
+ }
+ }
+} while ($n !== false);
+
+stream_set_blocking(STDIN, true);
+
+print "\n";
+if (!isset($name)) {
+ print "Specify the test description: ";
+ $desc = trim(fgets(STDIN));
+}
+while (!isset($testfile)) {
+ print "Specify the test file name (leave empty to write to stderr): ";
+ $testfile = trim(fgets(STDIN));
+ if ($testfile != "" && file_exists($testfile)) {
+ print "That file already exists. Type y or yes to overwrite: ";
+ $y = trim(fgets(STDIN));
+ if ($y !== "y" && $y !== "yes") {
+ unset($testfile);
+ }
+ }
+}
+
+$output = str_replace("string(".strlen($file).") \"$file\"", 'string(%d) "%s"', $output);
+$output = str_replace($file, "%s", $output);
+$input = trim($input);
+
+$testdata = <<<TEST
+--TEST--
+$desc
+--PHPDBG--
+$input
+--EXPECTF--
+$output
+TEST;
+
+if (!empty($ini)) {
+ $testdata .= "\n--INI--\n".implode("\n", $ini);
+}
+if ($cmdargv != "") {
+ $testdata .= "\n--ARGS--\n$cmdargv";
+}
+if ($file != "") {
+ $testdata .= "\n--FILE--\n".file_get_contents($file);
+}
+
+if ($testfile == "") {
+ print "\n";
+} elseif (file_put_contents($testfile, $testdata)) {
+ print "Test saved to $testfile\n";
+} else {
+ print "The test could not be saved to $testfile; outputting on stderr now\n";
+ $testfile = "";
+}
+
+if ($testfile == "") {
+ fwrite(STDERR, $testdata);
+}
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c
index 3ee0bde97f..96f1613a59 100644
--- a/sapi/phpdbg/phpdbg.c
+++ b/sapi/phpdbg/phpdbg.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -18,10 +18,6 @@
+----------------------------------------------------------------------+
*/
-#if !defined(ZEND_SIGNALS) || defined(_WIN32)
-# include <signal.h>
-#endif
-
#include "phpdbg.h"
#include "phpdbg_prompt.h"
#include "phpdbg_bp.h"
@@ -33,6 +29,7 @@
#include "zend_alloc.h"
#include "phpdbg_eol.h"
#include "phpdbg_print.h"
+#include "phpdbg_help.h"
#include "ext/standard/basic_functions.h"
@@ -52,6 +49,10 @@
# include "openssl/applink.c"
#endif
+#if defined(PHP_WIN32) && defined(ZTS)
+ZEND_TSRMLS_CACHE_DEFINE()
+#endif
+
ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
int phpdbg_startup_run = 0;
@@ -71,12 +72,64 @@ PHP_INI_END()
static zend_bool phpdbg_booted = 0;
static zend_bool phpdbg_fully_started = 0;
+zend_bool use_mm_wrappers = 1;
-#if PHP_VERSION_ID >= 50500
-void (*zend_execute_old)(zend_execute_data *execute_data);
-#else
-void (*zend_execute_old)(zend_op_array *op_array);
-#endif
+static void php_phpdbg_destroy_bp_file(zval *brake) /* {{{ */
+{
+ zend_hash_destroy(Z_ARRVAL_P(brake));
+ efree(Z_ARRVAL_P(brake));
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_symbol(zval *brake) /* {{{ */
+{
+ efree((char *) ((phpdbg_breaksymbol_t *) Z_PTR_P(brake))->symbol);
+ efree(Z_PTR_P(brake));
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_opcode(zval *brake) /* {{{ */
+{
+ efree((char *) ((phpdbg_breakop_t *) Z_PTR_P(brake))->name);
+ efree(Z_PTR_P(brake));
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_opline(zval *brake) /* {{{ */
+{
+ efree(Z_PTR_P(brake));
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_methods(zval *brake) /* {{{ */
+{
+ zend_hash_destroy(Z_ARRVAL_P(brake));
+ efree(Z_ARRVAL_P(brake));
+} /* }}} */
+
+static void php_phpdbg_destroy_bp_condition(zval *data) /* {{{ */
+{
+ phpdbg_breakcond_t *brake = (phpdbg_breakcond_t *) Z_PTR_P(data);
+
+ if (brake->ops) {
+ destroy_op_array(brake->ops);
+ efree(brake->ops);
+ }
+ efree((char*) brake->code);
+ efree(brake);
+} /* }}} */
+
+static void php_phpdbg_destroy_registered(zval *data) /* {{{ */
+{
+ zend_function *function = (zend_function *) Z_PTR_P(data);
+ destroy_zend_function(function);
+} /* }}} */
+
+static void php_phpdbg_destroy_file_source(zval *data) /* {{{ */
+{
+ phpdbg_file_source *source = (phpdbg_file_source *) Z_PTR_P(data);
+ destroy_op_array(&source->op_array);
+ if (source->buf) {
+ efree(source->buf);
+ }
+ efree(source);
+} /* }}} */
static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
{
@@ -87,6 +140,7 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
pg->colors[1] = NULL;
pg->colors[2] = NULL;
+ pg->lines = phpdbg_get_terminal_height();
pg->exec = NULL;
pg->exec_len = 0;
pg->buffer = NULL;
@@ -102,6 +156,7 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
pg->sapi_name_ptr = NULL;
pg->socket_fd = -1;
pg->socket_server_fd = -1;
+ pg->unclean_eval = 0;
pg->req_id = 0;
pg->err_buf.active = 0;
@@ -111,86 +166,21 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
pg->sigsafe_mem.mem = NULL;
pg->sigsegv_bailout = NULL;
+ pg->oplog_list = NULL;
+
#ifdef PHP_WIN32
pg->sigio_watcher_thread = INVALID_HANDLE_VALUE;
memset(&pg->swd, 0, sizeof(struct win32_sigio_watcher_data));
#endif
pg->eol = PHPDBG_EOL_LF;
-} /* }}} */
-
-static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
-{
- ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
- REGISTER_INI_ENTRIES();
-
-#if PHP_VERSION_ID >= 50500
- zend_execute_old = zend_execute_ex;
- zend_execute_ex = phpdbg_execute_ex;
-#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(zval *brake) /* {{{ */
-{
- zend_hash_destroy(Z_ARRVAL_P(brake));
-} /* }}} */
+ pg->stdin_file = NULL;
-static void php_phpdbg_destroy_bp_symbol(zval *brake) /* {{{ */
-{
- efree((char *) ((phpdbg_breaksymbol_t *) Z_PTR_P(brake))->symbol);
+ pg->cur_command = NULL;
} /* }}} */
-static void php_phpdbg_destroy_bp_opcode(zval *brake) /* {{{ */
-{
- efree((char *) ((phpdbg_breakop_t *) Z_PTR_P(brake))->name);
-} /* }}} */
-
-
-static void php_phpdbg_destroy_bp_methods(zval *brake) /* {{{ */
-{
- zend_hash_destroy(Z_ARRVAL_P(brake));
-} /* }}} */
-
-static void php_phpdbg_destroy_bp_condition(zval *data) /* {{{ */
-{
- phpdbg_breakcond_t *brake = (phpdbg_breakcond_t *) Z_PTR_P(data);
-
- if (brake) {
- if (brake->ops) {
-
- destroy_op_array(brake->ops);
- efree(brake->ops);
- }
- efree((char*) brake->code);
- }
-} /* }}} */
-
-static void php_phpdbg_destroy_registered(zval *data) /* {{{ */
-{
- zend_function *function = (zend_function *) Z_PTR_P(data);
-
-
- destroy_zend_function(function);
-} /* }}} */
-
-
-static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
+static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
{
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], 8, NULL, php_phpdbg_destroy_bp_file, 0);
@@ -198,7 +188,7 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
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_OPLINE], 8, NULL, php_phpdbg_destroy_bp_opline, 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);
@@ -207,12 +197,31 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
+ zend_hash_init(&PHPDBG_G(file_sources), 0, NULL, php_phpdbg_destroy_file_source, 0);
+ phpdbg_setup_watchpoints();
+
+ REGISTER_INI_ENTRIES();
+
+ zend_execute_ex = phpdbg_execute_ex;
+
+ 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 PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
+static PHP_MSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
{
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
+ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]);
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]);
@@ -222,14 +231,23 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
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(file_sources));
+ zend_hash_destroy(&PHPDBG_G(seek));
zend_hash_destroy(&PHPDBG_G(registered));
- zend_hash_destroy(&PHPDBG_G(watchpoints));
- zend_llist_destroy(&PHPDBG_G(watchlist_mem));
+ phpdbg_destroy_watchpoints();
+
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ phpdbg_notice("stop", "type=\"normal\"", "Script ended normally");
+ }
+
+ /* hack to restore mm_heap->use_custom_heap in order to receive memory leak info */
+ if (use_mm_wrappers) {
+ /* ASSUMING that mm_heap->use_custom_heap is the first element of the struct ... */
+ *(int *) zend_mm_get_heap() = 0;
+ }
if (PHPDBG_G(buffer)) {
- efree(PHPDBG_G(buffer));
+ free(PHPDBG_G(buffer));
PHPDBG_G(buffer) = NULL;
}
@@ -238,16 +256,6 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
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;
@@ -271,6 +279,31 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
PHPDBG_G(oplog_list) = NULL;
}
+ fflush(stdout);
+ if (SG(request_info).argv0) {
+ free(SG(request_info).argv0);
+ SG(request_info).argv0 = NULL;
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
+{
+ /* deactivate symbol table caching to have these properly destroyed upon stack leaving (especially important for watchpoints) */
+ EG(symtable_cache_limit) = EG(symtable_cache) - 1;
+
+ return SUCCESS;
+} /* }}} */
+
+static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
+{
+ if (PHPDBG_G(stdin_file)) {
+ fclose(PHPDBG_G(stdin_file));
+ PHPDBG_G(stdin_file) = NULL;
+ }
+
return SUCCESS;
} /* }}} */
@@ -306,11 +339,11 @@ static PHP_FUNCTION(phpdbg_exec)
ZVAL_TRUE(return_value);
}
} else {
- zend_error(E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec);
+ zend_error(E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", ZSTR_VAL(exec));
ZVAL_FALSE(return_value);
}
} else {
- zend_error(E_WARNING, "Failed to set execution context (%s) the file does not exist", exec);
+ zend_error(E_WARNING, "Failed to set execution context (%s) the file does not exist", ZSTR_VAL(exec));
ZVAL_FALSE(return_value);
}
@@ -321,19 +354,25 @@ static PHP_FUNCTION(phpdbg_exec)
instructs phpdbg to insert a breakpoint at the next opcode */
static PHP_FUNCTION(phpdbg_break_next)
{
- if (zend_parse_parameters_none() == FAILURE && EG(current_execute_data)) {
+ zend_execute_data *ex = EG(current_execute_data);
+
+ while (ex && ex->func && !ZEND_USER_CODE(ex->func->type)) {
+ ex = ex->prev_execute_data;
+ }
+
+ if (zend_parse_parameters_none() == FAILURE || !ex) {
return;
}
- phpdbg_set_breakpoint_opline_ex((phpdbg_opline_ptr_t) EG(current_execute_data)->opline + 1);
+ phpdbg_set_breakpoint_opline_ex((phpdbg_opline_ptr_t) ex->opline + 1);
} /* }}} */
/* {{{ proto void phpdbg_break_file(string file, integer line) */
static PHP_FUNCTION(phpdbg_break_file)
{
- char *file = NULL;
- size_t flen = 0;
- long line;
+ char *file;
+ size_t flen;
+ zend_long line;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &file, &flen, &line) == FAILURE) {
return;
@@ -386,9 +425,9 @@ static PHP_FUNCTION(phpdbg_clear)
/* {{{ proto void phpdbg_color(integer element, string color) */
static PHP_FUNCTION(phpdbg_color)
{
- long element = 0L;
- char *color = NULL;
- size_t color_len = 0;
+ zend_long element;
+ char *color;
+ size_t color_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &element, &color, &color_len) == FAILURE) {
return;
@@ -441,11 +480,165 @@ static PHP_FUNCTION(phpdbg_start_oplog)
PHPDBG_G(oplog_list)->start = PHPDBG_G(oplog_cur);
}
+static zend_always_inline zend_bool phpdbg_is_ignored_opcode(zend_uchar opcode) {
+ return
+ opcode == ZEND_NOP || opcode == ZEND_OP_DATA || opcode == ZEND_FE_FREE || opcode == ZEND_FREE || opcode == ZEND_ASSERT_CHECK || opcode == ZEND_VERIFY_RETURN_TYPE
+ || opcode == ZEND_DECLARE_CONST || opcode == ZEND_DECLARE_CLASS || opcode == ZEND_DECLARE_INHERITED_CLASS || opcode == ZEND_DECLARE_FUNCTION
+ || opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED || opcode == ZEND_VERIFY_ABSTRACT_CLASS || opcode == ZEND_ADD_TRAIT || opcode == ZEND_BIND_TRAITS
+ || opcode == ZEND_DECLARE_ANON_CLASS || opcode == ZEND_DECLARE_ANON_INHERITED_CLASS || opcode == ZEND_FAST_RET || opcode == ZEND_TICKS
+ || opcode == ZEND_EXT_STMT || opcode == ZEND_EXT_FCALL_BEGIN || opcode == ZEND_EXT_FCALL_END || opcode == ZEND_EXT_NOP || opcode == ZEND_BIND_GLOBAL
+ ;
+}
+
+static void phpdbg_oplog_fill_executable(zend_op_array *op_array, HashTable *insert_ht, zend_bool by_opcode) {
+ /* ignore RECV_* opcodes */
+ zend_op *cur = op_array->opcodes + op_array->num_args + !!(op_array->fn_flags & ZEND_ACC_VARIADIC);
+ zend_op *end = op_array->opcodes + op_array->last;
+
+ zend_long insert_idx;
+ zval zero;
+ ZVAL_LONG(&zero, 0);
+
+ /* ignore autogenerated return (well, not too precise with finally branches, but that's okay) */
+ if (op_array->last >= 1 && (((end - 1)->opcode == ZEND_RETURN || (end - 1)->opcode == ZEND_RETURN_BY_REF || (end - 1)->opcode == ZEND_GENERATOR_RETURN)
+ && ((op_array->last > 1 && ((end - 2)->opcode == ZEND_RETURN || (end - 2)->opcode == ZEND_RETURN_BY_REF || (end - 2)->opcode == ZEND_GENERATOR_RETURN || (end - 2)->opcode == ZEND_THROW))
+ || op_array->function_name == NULL || (end - 1)->extended_value == -1))) {
+ end--;
+ }
+
+ for (; cur < end; cur++) {
+ zend_uchar opcode = cur->opcode;
+ if (phpdbg_is_ignored_opcode(opcode)) {
+ continue;
+ }
+
+ if (by_opcode) {
+ insert_idx = cur - op_array->opcodes;
+ } else {
+ insert_idx = cur->lineno;
+ }
+
+ if (opcode == ZEND_NEW && cur[1].opcode == ZEND_DO_FCALL) {
+ cur++;
+ }
+
+ zend_hash_index_update(insert_ht, insert_idx, &zero);
+ }
+}
+
+static inline HashTable* phpdbg_add_empty_array(HashTable *ht, zend_string *name) {
+ zval *ht_zv = zend_hash_find(ht, name);
+ if (!ht_zv) {
+ zval zv;
+ array_init(&zv);
+ ht_zv = zend_hash_add_new(ht, name, &zv);
+ }
+ return Z_ARR_P(ht_zv);
+}
+
+/* {{{ proto void phpdbg_get_executable() */
+static PHP_FUNCTION(phpdbg_get_executable)
+{
+ HashTable *options = NULL;
+ zval *option_buffer;
+ zend_bool by_function = 0;
+ zend_bool by_opcode = 0;
+ HashTable *insert_ht;
+
+ zend_function *func;
+ zend_class_entry *ce;
+ zend_string *name;
+ HashTable *files = &PHPDBG_G(file_sources);
+ HashTable files_tmp;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) {
+ return;
+ }
+
+ if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("functions")))) {
+ by_function = zend_is_true(option_buffer);
+ }
+
+ if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("opcodes")))) {
+ if (by_function) {
+ by_opcode = zend_is_true(option_buffer);
+ }
+ }
+
+ if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("files")))) {
+ ZVAL_DEREF(option_buffer);
+ if (Z_TYPE_P(option_buffer) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(option_buffer)) > 0) {
+ zval *filename;
+
+ files = &files_tmp;
+ zend_hash_init(files, 0, NULL, NULL, 0);
+
+ ZEND_HASH_FOREACH_VAL(Z_ARR_P(option_buffer), filename) {
+ zend_hash_add_empty_element(files, zval_get_string(filename));
+ } ZEND_HASH_FOREACH_END();
+ } else {
+ GC_REFCOUNT(files)++;
+ }
+ } else {
+ GC_REFCOUNT(files)++;
+ }
+
+ array_init(return_value);
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), name, func) {
+ if (func->type == ZEND_USER_FUNCTION) {
+ if (zend_hash_exists(files, func->op_array.filename)) {
+ insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), func->op_array.filename);
+
+ if (by_function) {
+ insert_ht = phpdbg_add_empty_array(insert_ht, name);
+ }
+
+ phpdbg_oplog_fill_executable(&func->op_array, insert_ht, by_opcode);
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), name, ce) {
+ if (ce->type == ZEND_USER_CLASS) {
+ if (zend_hash_exists(files, ce->info.user.filename)) {
+ ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
+ if (func->type == ZEND_USER_FUNCTION && zend_hash_exists(files, func->op_array.filename)) {
+ insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), func->op_array.filename);
+
+ if (by_function) {
+ zend_string *fn_name = strpprintf(ZSTR_LEN(name) + ZSTR_LEN(func->op_array.function_name) + 2, "%.*s::%.*s", (int) ZSTR_LEN(name), ZSTR_VAL(name), (int) ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name));
+ insert_ht = phpdbg_add_empty_array(insert_ht, fn_name);
+ zend_string_release(fn_name);
+ }
+
+ phpdbg_oplog_fill_executable(&func->op_array, insert_ht, by_opcode);
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ ZEND_HASH_FOREACH_STR_KEY(files, name) {
+ phpdbg_file_source *source = zend_hash_find_ptr(&PHPDBG_G(file_sources), name);
+ if (source) {
+ phpdbg_oplog_fill_executable(
+ &source->op_array,
+ phpdbg_add_empty_array(Z_ARR_P(return_value), source->op_array.filename),
+ by_opcode);
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ if (!--GC_REFCOUNT(files)) {
+ zend_hash_destroy(files);
+ }
+}
+
/* {{{ proto void phpdbg_end_oplog() */
static PHP_FUNCTION(phpdbg_end_oplog)
{
- phpdbg_oplog_entry *cur = PHPDBG_G(oplog_list)->start;
- phpdbg_oplog_list *prev = PHPDBG_G(oplog_list)->prev;
+ phpdbg_oplog_entry *cur;
+ phpdbg_oplog_list *prev;
HashTable *options = NULL;
zval *option_buffer;
@@ -461,6 +654,9 @@ static PHP_FUNCTION(phpdbg_end_oplog)
return;
}
+ cur = PHPDBG_G(oplog_list)->start;
+ prev = PHPDBG_G(oplog_list)->prev;
+
efree(PHPDBG_G(oplog_list));
PHPDBG_G(oplog_list) = prev;
@@ -478,65 +674,61 @@ static PHP_FUNCTION(phpdbg_end_oplog)
{
zend_string *last_file = NULL;
- zval *file_buf;
+ HashTable *file_ht;
zend_string *last_function = (void *)~(uintptr_t)0;
zend_class_entry *last_scope = NULL;
- zval *fn_buf;
HashTable *insert_ht;
zend_long insert_idx;
do {
- zend_op_array *op_array = cur->op_array;
- if (op_array->filename != last_file) {
- last_file = op_array->filename;
- file_buf = zend_hash_find(Z_ARR_P(return_value), last_file);
- if (!file_buf) {
- zval ht;
- array_init(&ht);
- file_buf = zend_hash_add_new(Z_ARR_P(return_value), last_file, &ht);
- }
+ zval zero;
+ ZVAL_LONG(&zero, 0);
+
+ if (cur->filename != last_file) {
+ last_file = cur->filename;
+ file_ht = insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), last_file);
}
- insert_ht = Z_ARR_P(file_buf);
if (by_function) {
- if (op_array->function_name != last_function || op_array->scope != last_scope) {
+ if (cur->function_name == NULL) {
+ if (last_function != NULL) {
+ insert_ht = file_ht;
+ }
+ last_function = NULL;
+ } else if (cur->function_name != last_function || cur->scope != last_scope) {
zend_string *fn_name;
- last_function = op_array->function_name;
- last_scope = op_array->scope;
+ last_function = cur->function_name;
+ last_scope = cur->scope;
if (last_scope == NULL) {
fn_name = zend_string_copy(last_function);
} else {
- fn_name = strpprintf(ZSTR_LEN(last_function) + ZSTR_LEN(last_scope->name) + 2, "%.*s::%.*s", ZSTR_LEN(last_function), ZSTR_VAL(last_function), ZSTR_LEN(last_scope->name), ZSTR_VAL(last_scope->name));
- }
- fn_buf = zend_hash_find(Z_ARR_P(return_value), fn_name);
- if (!fn_buf) {
- zval ht;
- array_init(&ht);
- fn_buf = zend_hash_add_new(Z_ARR_P(return_value), fn_name, &ht);
+ fn_name = strpprintf(ZSTR_LEN(last_function) + ZSTR_LEN(last_scope->name) + 2, "%.*s::%.*s", (int) ZSTR_LEN(last_scope->name), ZSTR_VAL(last_scope->name), (int) ZSTR_LEN(last_function), ZSTR_VAL(last_function));
}
+ insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), fn_name);
+ zend_string_release(fn_name);
}
- insert_ht = Z_ARR_P(fn_buf);
}
if (by_opcode) {
- insert_idx = cur->op - op_array->opcodes;
+ insert_idx = cur->op - cur->opcodes;
} else {
+ if (phpdbg_is_ignored_opcode(cur->op->opcode)) {
+ continue;
+ }
+
insert_idx = cur->op->lineno;
}
{
zval *num = zend_hash_index_find(insert_ht, insert_idx);
if (!num) {
- zval zv;
- ZVAL_LONG(&zv, 0);
- num = zend_hash_index_add_new(insert_ht, insert_idx, &zv);
+ num = zend_hash_index_add_new(insert_ht, insert_idx, &zero);
}
Z_LVAL_P(num)++;
}
- cur = cur->next;
- } while (cur != NULL);
+ } while ((cur = cur->next));
}
if (!prev) {
@@ -581,6 +773,11 @@ ZEND_BEGIN_ARG_INFO_EX(phpdbg_start_oplog_arginfo, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(phpdbg_end_oplog_arginfo, 0, 0, 0)
+ ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(phpdbg_get_executable_arginfo, 0, 0, 0)
+ ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
zend_function_entry phpdbg_user_functions[] = {
@@ -594,6 +791,7 @@ zend_function_entry phpdbg_user_functions[] = {
PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
PHP_FE(phpdbg_start_oplog, phpdbg_start_oplog_arginfo)
PHP_FE(phpdbg_end_oplog, phpdbg_end_oplog_arginfo)
+ PHP_FE(phpdbg_get_executable, phpdbg_get_executable_arginfo)
#ifdef PHP_FE_END
PHP_FE_END
#else
@@ -606,7 +804,7 @@ static zend_module_entry sapi_phpdbg_module_entry = {
PHPDBG_NAME,
phpdbg_user_functions,
PHP_MINIT(phpdbg),
- NULL,
+ PHP_MSHUTDOWN(phpdbg),
PHP_RINIT(phpdbg),
PHP_RSHUTDOWN(phpdbg),
NULL,
@@ -614,13 +812,17 @@ static zend_module_entry sapi_phpdbg_module_entry = {
STANDARD_MODULE_PROPERTIES
};
+static void phpdbg_interned_strings_nothing(void) { }
+
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;
}
+ /* prevent zend_interned_strings_restore from invalidating our string pointers too early (in phpdbg allocated memory only gets freed after module shutdown) */
+ zend_interned_strings_restore = phpdbg_interned_strings_nothing;
- phpdbg_booted=1;
+ phpdbg_booted = 1;
return SUCCESS;
} /* }}} */
@@ -649,10 +851,10 @@ static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *s
}
/* }}} */
-static void php_sapi_phpdbg_log_message(char *message) /* {{{ */
+static void php_sapi_phpdbg_log_message(char *message, int syslog_type_int) /* {{{ */
{
/*
- * We must not request TSRM before being boot
+ * We must not request TSRM before being booted
*/
if (phpdbg_booted) {
if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) {
@@ -662,6 +864,10 @@ static void php_sapi_phpdbg_log_message(char *message) /* {{{ */
phpdbg_error("php", "msg=\"%s\"", "%s", message);
+ if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
+ return;
+ }
+
switch (PG(last_error_type)) {
case E_ERROR:
case E_CORE_ERROR:
@@ -672,14 +878,14 @@ static void php_sapi_phpdbg_log_message(char *message) /* {{{ */
const char *file_char = zend_get_executed_filename();
zend_string *file = zend_string_init(file_char, strlen(file_char), 0);
phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
- efree(file);
+ zend_string_release(file);
if (!phpdbg_fully_started) {
return;
}
do {
- switch (phpdbg_interactive(1)) {
+ switch (phpdbg_interactive(1, NULL)) {
case PHPDBG_LEAVE:
case PHPDBG_FINISH:
case PHPDBG_UNTIL:
@@ -695,32 +901,15 @@ static void php_sapi_phpdbg_log_message(char *message) /* {{{ */
}
/* }}} */
-static int php_sapi_phpdbg_deactivate(void) /* {{{ */
+static int php_sapi_phpdbg_activate(void) /* {{{ */
{
- if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) == PHPDBG_IS_CLEANING) {
- zend_phpdbg_globals *pg = PHPDBG_G(backup) = calloc(1, sizeof(zend_phpdbg_globals));
-
- php_phpdbg_globals_ctor(pg);
-
- pg->exec = zend_strndup(PHPDBG_G(exec), PHPDBG_G(exec_len));
- pg->exec_len = PHPDBG_G(exec_len);
- pg->oplog = PHPDBG_G(oplog);
- pg->prompt[0] = PHPDBG_G(prompt)[0];
- pg->prompt[1] = PHPDBG_G(prompt)[1];
- memcpy(pg->colors, PHPDBG_G(colors), sizeof(pg->colors));
- pg->eol = PHPDBG_G(eol);
- pg->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK;
- }
-
- fflush(stdout);
- if(SG(request_info).argv0) {
- free(SG(request_info).argv0);
- SG(request_info).argv0 = NULL;
- }
+ return SUCCESS;
+}
+static int php_sapi_phpdbg_deactivate(void) /* {{{ */
+{
return SUCCESS;
}
-/* }}} */
static void php_sapi_phpdbg_register_vars(zval *track_vars_array) /* {{{ */
{
@@ -761,7 +950,7 @@ static inline size_t php_sapi_phpdbg_ub_write(const char *message, size_t length
if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
send(PHPDBG_G(socket_fd), message, length, 0);
}
- return phpdbg_script(P_STDOUT, "%.*s", length, message);
+ return phpdbg_script(P_STDOUT, "%.*s", (int) length, message);
} /* }}} */
/* beginning of struct, see main/streams/plain_wrapper.c line 111 */
@@ -785,7 +974,7 @@ static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t co
return count;
}
if (stat[2].st_dev == stat[1].st_dev && stat[2].st_ino == stat[1].st_ino) {
- phpdbg_script(P_STDERR, "%.*s", (int) count, buf);
+ phpdbg_script_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd, P_STDERR, "%.*s", (int) count, buf);
return count;
}
break;
@@ -794,21 +983,15 @@ static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t co
return PHPDBG_G(php_stdiop_write)(stream, buf, count);
}
-#if PHP_VERSION_ID >= 50700
static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
{
-#else
-static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
-{
-#endif
-
if (!phpdbg_active_sigsafe_mem()) {
fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
}
} /* }}} */
/* copied from sapi/cli/php_cli.c cli_register_file_handles */
-static void phpdbg_register_file_handles(void) /* {{{ */
+void phpdbg_register_file_handles(void) /* {{{ */
{
zval zin, zout, zerr;
php_stream *s_in, *s_out, *s_err;
@@ -840,18 +1023,21 @@ static void phpdbg_register_file_handles(void) /* {{{ */
ic.flags = CONST_CS;
ic.name = zend_string_init(ZEND_STRL("STDIN"), 0);
ic.module_number = 0;
+ zend_hash_del(EG(zend_constants), ic.name);
zend_register_constant(&ic);
oc.value = zout;
oc.flags = CONST_CS;
oc.name = zend_string_init(ZEND_STRL("STDOUT"), 0);
oc.module_number = 0;
+ zend_hash_del(EG(zend_constants), oc.name);
zend_register_constant(&oc);
ec.value = zerr;
ec.flags = CONST_CS;
ec.name = zend_string_init(ZEND_STRL("STDERR"), 0);
ec.module_number = 0;
+ zend_hash_del(EG(zend_constants), ec.name);
zend_register_constant(&ec);
}
/* }}} */
@@ -865,7 +1051,7 @@ static sapi_module_struct phpdbg_sapi_module = {
php_sapi_phpdbg_module_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
- NULL, /* activate */
+ php_sapi_phpdbg_activate, /* activate */
php_sapi_phpdbg_deactivate, /* deactivate */
php_sapi_phpdbg_ub_write, /* unbuffered write */
@@ -903,7 +1089,9 @@ const opt_struct OPTIONS[] = { /* {{{ */
{'I', 0, "ignore init"},
{'O', 1, "opline log"},
{'r', 0, "run"},
+ {'e', 0, "generate ext_stmt opcodes"},
{'E', 0, "step-through-eval"},
+ {'s', 1, "script from stdin"},
{'S', 1, "sapi-name"},
#ifndef _WIN32
{'l', 1, "listen"},
@@ -930,7 +1118,6 @@ const char phpdbg_ini_hardcoded[] =
/* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
#define INI_DEFAULT(name, value) \
ZVAL_STRINGL(&tmp, value, sizeof(value) - 1); \
- Z_SET_REFCOUNT(tmp, 0); \
zend_hash_str_update(configuration_hash, name, sizeof(name) - 1, &tmp);
void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */
@@ -976,18 +1163,26 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */
}
} else {
/* set signalled only when not interactive */
- if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
- if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
- char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
-
- phpdbg_set_sigsafe_mem(mem);
- zend_try {
- phpdbg_force_interruption();
- } zend_end_try()
- phpdbg_clear_sigsafe_mem();
- return;
+ if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
+ char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
+
+ phpdbg_set_sigsafe_mem(mem);
+ zend_try {
+ phpdbg_force_interruption();
+ } zend_end_try()
+ phpdbg_clear_sigsafe_mem();
+
+ PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
+
+ if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
+ zend_bailout();
}
+ } else {
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
+ if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
+ PHPDBG_G(flags) |= PHPDBG_HAS_PAGINATION;
+ PHPDBG_G(flags) &= ~PHPDBG_PREVENT_INTERACTIVE;
+ }
}
}
} /* }}} */
@@ -1073,9 +1268,13 @@ void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */
phpdbg_force_interruption();
} zend_end_try();
phpdbg_clear_sigsafe_mem();
- break;
- }
- if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
+
+ PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
+
+ if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
+ zend_bailout();
+ }
+ } else if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
}
break;
@@ -1099,16 +1298,12 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
switch (sig) {
case SIGBUS:
case SIGSEGV:
- if (PHPDBG_G(sigsegv_bailout)) {
- LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE);
- }
is_handled = phpdbg_watchpoint_segfault_handler(info, context);
if (is_handled == FAILURE) {
-#ifdef ZEND_SIGNALS
+ if (PHPDBG_G(sigsegv_bailout)) {
+ LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE);
+ }
zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
-#else
- sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
-#endif
}
break;
}
@@ -1116,37 +1311,53 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
} /* }}} */
#endif
-static inline zend_mm_heap *phpdbg_mm_get_heap() /* {{{ */
+void phpdbg_sighup_handler(int sig) /* {{{ */
{
- zend_mm_heap *mm_heap;
-
-
- mm_heap = zend_mm_set_heap(NULL);
- zend_mm_set_heap(mm_heap);
-
- return mm_heap;
+ exit(0);
} /* }}} */
-void *phpdbg_malloc_wrapper(size_t size) /* {{{ */
+void *phpdbg_malloc_wrapper(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
{
- return zend_mm_alloc(phpdbg_mm_get_heap(), size);
+ return _zend_mm_alloc(zend_mm_get_heap(), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
} /* }}} */
-void phpdbg_free_wrapper(void *p) /* {{{ */
+void phpdbg_free_wrapper(void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
{
- zend_mm_heap *heap = phpdbg_mm_get_heap();
+ zend_mm_heap *heap = zend_mm_get_heap();
if (UNEXPECTED(heap == p)) {
/* TODO: heap maybe allocated by mmap(zend_mm_init) or malloc(USE_ZEND_ALLOC=0)
* let's prevent it from segfault for now
*/
} else {
- zend_mm_free(heap, p);
+ phpdbg_watch_efree(p);
+ _zend_mm_free(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
} /* }}} */
-void *phpdbg_realloc_wrapper(void *ptr, size_t size) /* {{{ */
+void *phpdbg_realloc_wrapper(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
{
- return zend_mm_realloc(phpdbg_mm_get_heap(), ptr, size);
+ return _zend_mm_realloc(zend_mm_get_heap(), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
+} /* }}} */
+
+php_stream *phpdbg_stream_url_wrap_php(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC) /* {{{ */
+{
+ if (!strncasecmp(path, "php://", 6)) {
+ path += 6;
+ }
+
+ if (!strncasecmp(path, "stdin", 6) && PHPDBG_G(stdin_file)) {
+ php_stream *stream = php_stream_fopen_from_fd(dup(fileno(PHPDBG_G(stdin_file))), "r", NULL);
+#ifdef PHP_WIN32
+ zval *blocking_pipes = php_stream_context_get_option(context, "pipe", "blocking");
+ if (blocking_pipes) {
+ convert_to_long(blocking_pipes);
+ php_stream_set_option(stream, PHP_STREAM_OPTION_PIPE_BLOCKING, Z_LVAL_P(blocking_pipes), NULL);
+ }
+#endif
+ return stream;
+ }
+
+ return PHPDBG_G(orig_url_wrap_php)(wrapper, path, mode, options, opened_path, context STREAMS_CC);
} /* }}} */
int main(int argc, char **argv) /* {{{ */
@@ -1160,12 +1371,13 @@ int main(int argc, char **argv) /* {{{ */
zend_bool ini_ignore;
char *ini_override;
char *exec = NULL;
+ char *first_command = NULL;
char *init_file;
size_t init_file_len;
zend_bool init_file_default;
char *oplog_file;
size_t oplog_file_len;
- zend_ulong flags;
+ uint64_t flags;
char *php_optarg;
int php_optind, opt, show_banner = 1;
long cleaning = -1;
@@ -1179,19 +1391,26 @@ int main(int argc, char **argv) /* {{{ */
int socket = -1;
FILE* stream = NULL;
char *print_opline_func;
+ zend_bool ext_stmt = 0;
+ zend_bool is_exit;
+ int exit_status;
+ char *read_from_stdin = NULL;
+ zend_string *backup_phpdbg_compile = NULL;
+ zend_bool show_help = 0, show_version = 0;
+ void* (*_malloc)(size_t);
+ void (*_free)(void*);
+ void* (*_realloc)(void*, size_t);
-#ifdef ZTS
- void ***tsrm_ls;
-#endif
#ifndef _WIN32
struct sigaction sigio_struct;
struct sigaction signal_struct;
signal_struct.sa_sigaction = phpdbg_signal_handler;
signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
+ sigemptyset(&signal_struct.sa_mask);
sigio_struct.sa_sigaction = phpdbg_sigio_handler;
sigio_struct.sa_flags = SA_SIGINFO;
-
+ sigemptyset(&sigio_struct.sa_mask);
address = strdup("127.0.0.1");
#endif
@@ -1203,13 +1422,15 @@ int main(int argc, char **argv) /* {{{ */
setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
#endif
+phpdbg_main:
#ifdef ZTS
tsrm_startup(1, 1, 0, NULL);
-
- tsrm_ls = ts_resource(0);
+ (void)ts_resource(0);
+ ZEND_TSRMLS_CACHE_UPDATE();
#endif
-phpdbg_main:
+ zend_signal_startup();
+
ini_entries = NULL;
ini_entries_len = 0;
ini_ignore = 0;
@@ -1222,10 +1443,12 @@ phpdbg_main:
oplog_file = NULL;
oplog_file_len = 0;
flags = PHPDBG_DEFAULT_FLAGS;
+ is_exit = 0;
php_optarg = NULL;
php_optind = 1;
opt = 0;
sapi_name = NULL;
+ exit_status = 0;
if (settings) {
exec = settings->exec;
}
@@ -1286,10 +1509,13 @@ phpdbg_main:
/* begin phpdbg options */
- case 'S': { /* set SAPI name */
- if (sapi_name) {
- free(sapi_name);
+ case 's': { /* read script from stdin */
+ if (settings == NULL) {
+ read_from_stdin = strdup(php_optarg);
}
+ } break;
+
+ case 'S': { /* set SAPI name */
sapi_name = strdup(php_optarg);
} break;
@@ -1300,6 +1526,7 @@ phpdbg_main:
case 'i': { /* set init file */
if (init_file) {
free(init_file);
+ init_file = NULL;
}
init_file_len = strlen(php_optarg);
@@ -1319,6 +1546,10 @@ phpdbg_main:
flags &= ~PHPDBG_IS_QUIET;
break;
+ case 'e':
+ ext_stmt = 1;
+ break;
+
case 'E': /* stepping through eval on */
flags |= PHPDBG_IS_STEPONEVAL;
break;
@@ -1359,42 +1590,22 @@ phpdbg_main:
} break;
case 'h': {
- sapi_startup(phpdbg);
- phpdbg->startup(phpdbg);
- PHPDBG_G(flags) = 0;
- phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT);
- phpdbg_do_help(NULL);
- sapi_deactivate();
- sapi_shutdown();
- return 0;
+ show_help = 1;
} break;
case 'V': {
- sapi_startup(phpdbg);
- phpdbg->startup(phpdbg);
- printf(
- "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2015 The PHP Group\n%s",
- PHPDBG_VERSION,
- __DATE__,
- __TIME__,
- PHP_VERSION,
- get_zend_version()
- );
- sapi_deactivate();
- sapi_shutdown();
- return 0;
+ show_version = 1;
} break;
}
php_optarg = NULL;
}
+ quit_immediately = phpdbg_startup_run > 1;
+
/* set exec if present on command line */
- if (!exec && (argc > php_optind) && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
- if (strlen(argv[php_optind])) {
- if (exec) {
- free(exec);
- }
+ if (!read_from_stdin && argc > php_optind) {
+ if (!exec && strlen(argv[php_optind])) {
exec = strdup(argv[php_optind]);
}
php_optind++;
@@ -1449,88 +1660,140 @@ phpdbg_main:
phpdbg->ini_entries = ini_entries;
+ ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
+
+ /* set default colors */
+ phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold"));
+ phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold"));
+ phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green"));
+
+ /* set default prompt */
+ phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT);
+
+ if (settings > (zend_phpdbg_globals *) 0x2) {
+#ifdef ZTS
+ *((zend_phpdbg_globals *) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings;
+#else
+ phpdbg_globals = *settings;
+#endif
+ free(settings);
+ }
+
+ /* set flags from command line */
+ PHPDBG_G(flags) = flags;
+
if (phpdbg->startup(phpdbg) == SUCCESS) {
+ zend_mm_heap *mm_heap;
#ifdef _WIN32
EXCEPTION_POINTERS *xp;
__try {
#endif
- zend_mm_heap *mm_heap;
- void* (*_malloc)(size_t);
- void (*_free)(void*);
- void* (*_realloc)(void*, size_t);
-
- /* set flags from command line */
- PHPDBG_G(flags) = flags;
- if (settings > (zend_phpdbg_globals *) 0x2) {
-#ifdef ZTS
- *((zend_phpdbg_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings;
-#else
- phpdbg_globals = *settings;
-#endif
+ if (show_version || show_help) {
+ /* It ain't gonna proceed to real execution anyway,
+ but the correct descriptor is needed already. */
+ PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
+ PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
+ if (show_help) {
+ phpdbg_do_help_cmd(exec);
+ } else if (show_version) {
+ phpdbg_out(
+ "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2016 The PHP Group\n%s",
+ PHPDBG_VERSION,
+ __DATE__,
+ __TIME__,
+ PHP_VERSION,
+ get_zend_version()
+ );
+ }
+ sapi_deactivate();
+ sapi_shutdown();
+ if (ini_entries) {
+ free(ini_entries);
+ }
+ if (ini_override) {
+ free(ini_override);
+ }
+ if (exec) {
+ free(exec);
+ }
+ if (oplog_file) {
+ free(oplog_file);
+ }
+ if (init_file) {
+ free(init_file);
+ }
+ goto free_and_return;
}
+ zend_try {
+ zend_signal_activate();
+ } zend_end_try();
+
/* setup remote server if necessary */
if (cleaning <= 0 && listen > 0) {
server = phpdbg_open_socket(address, listen);
- if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream) == FAILURE) {
+ if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream) == FAILURE) {
exit(0);
}
#ifndef _WIN32
- sigaction(SIGIO, &sigio_struct, NULL);
+ zend_sigaction(SIGIO, &sigio_struct, NULL);
#endif
/* set remote flag to stop service shutting down upon quit */
remote = 1;
- }
-
- mm_heap = phpdbg_mm_get_heap();
- zend_mm_get_custom_handlers(mm_heap, &_malloc, &_free, &_realloc);
+#ifndef _WIN32
+ } else {
- if (!_malloc) {
- _malloc = phpdbg_malloc_wrapper;
- }
- if (!_realloc) {
- _realloc = phpdbg_realloc_wrapper;
- }
- if (!_free) {
- _free = phpdbg_free_wrapper;
+ zend_signal(SIGHUP, phpdbg_sighup_handler);
+#endif
}
- zend_activate();
+ mm_heap = zend_mm_get_heap();
+ zend_mm_get_custom_handlers(mm_heap, &_malloc, &_free, &_realloc);
- phpdbg_init_list();
+ use_mm_wrappers = !_malloc && !_realloc && !_free;
PHPDBG_G(original_free_function) = _free;
_free = phpdbg_watch_efree;
- zend_mm_set_custom_handlers(mm_heap, _malloc, _free, _realloc);
+ if (use_mm_wrappers) {
+#if ZEND_DEBUG
+ zend_mm_set_custom_debug_handlers(mm_heap, phpdbg_malloc_wrapper, phpdbg_free_wrapper, phpdbg_realloc_wrapper);
+#else
+ zend_mm_set_custom_handlers(mm_heap, phpdbg_malloc_wrapper, phpdbg_free_wrapper, phpdbg_realloc_wrapper);
+#endif
+ } else {
+ zend_mm_set_custom_handlers(mm_heap, _malloc, _free, _realloc);
+ }
- phpdbg_setup_watchpoints();
+ _free = PHPDBG_G(original_free_function);
-#if defined(ZEND_SIGNALS) && !defined(_WIN32)
- zend_try {
- zend_signal_activate();
- } zend_end_try();
-#endif
-#if defined(ZEND_SIGNALS) && !defined(_WIN32)
- zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
- zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
-#elif !defined(_WIN32)
- sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
- sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
-#endif
+ phpdbg_init_list();
PHPDBG_G(sapi_name_ptr) = sapi_name;
+ if (exec) { /* set execution context */
+ PHPDBG_G(exec) = phpdbg_resolve_path(exec);
+ PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0;
+
+ free(exec);
+ exec = NULL;
+ }
+
php_output_activate();
php_output_deactivate();
+ if (SG(sapi_headers).mimetype) {
+ efree(SG(sapi_headers).mimetype);
+ SG(sapi_headers).mimetype = NULL;
+ }
+
php_output_activate();
- if (php_request_startup() == SUCCESS) {
+ {
int i;
SG(request_info).argc = argc - php_optind + 1;
@@ -1538,37 +1801,33 @@ phpdbg_main:
for (i = SG(request_info).argc; --i;) {
SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
}
- SG(request_info).argv[i] = exec ? estrdup(exec) : estrdup("");
+ SG(request_info).argv[0] = PHPDBG_G(exec) ? estrdup(PHPDBG_G(exec)) : estrdup("");
+ }
- php_hash_environment();
+ if (php_request_startup() == FAILURE) {
+ PUTS("Could not startup");
+ return 1;
}
+#ifndef _WIN32
+ zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
+ zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
+#endif
+
/* do not install sigint handlers for remote consoles */
/* sending SIGINT then provides a decent way of shutting down the server */
#ifndef _WIN32
if (listen < 0) {
#endif
-#if defined(ZEND_SIGNALS) && !defined(_WIN32)
zend_try { zend_signal(SIGINT, phpdbg_sigint_handler); } zend_end_try();
-#else
- signal(SIGINT, phpdbg_sigint_handler);
-#endif
#ifndef _WIN32
}
-#endif
- PG(modules_activated) = 0;
-
-#ifndef _WIN32
/* setup io here */
if (remote) {
PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
-
- signal(SIGPIPE, SIG_IGN);
+ zend_signal(SIGPIPE, SIG_IGN);
}
-#endif
-
-#ifndef _WIN32
PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin);
PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
@@ -1599,33 +1858,26 @@ phpdbg_main:
php_stream_stdio_ops.write = phpdbg_stdiop_write;
#endif
- if (exec) { /* set execution context */
- PHPDBG_G(exec) = phpdbg_resolve_path(exec);
- PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0;
-
- free(exec);
- exec = NULL;
- }
-
if (oplog_file) { /* open oplog */
PHPDBG_G(oplog) = fopen(oplog_file, "w+");
if (!PHPDBG_G(oplog)) {
phpdbg_error("oplog", "path=\"%s\"", "Failed to open oplog %s", oplog_file);
}
free(oplog_file);
+ oplog_file = NULL;
}
- /* set default colors */
- phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold"));
- phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold"));
- phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green"));
-
- /* set default prompt */
- phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT);
+ {
+ php_stream_wrapper *wrapper = zend_hash_str_find_ptr(php_stream_get_url_stream_wrappers_hash(), ZEND_STRL("php"));
+ PHPDBG_G(orig_url_wrap_php) = wrapper->wops->stream_opener;
+ wrapper->wops->stream_opener = phpdbg_stream_url_wrap_php;
+ }
/* Make stdin, stdout and stderr accessible from PHP scripts */
phpdbg_register_file_handles();
+ phpdbg_list_update();
+
if (show_banner && cleaning < 2) {
/* print blurb */
phpdbg_welcome(cleaning == 1);
@@ -1633,17 +1885,14 @@ phpdbg_main:
cleaning = -1;
+ if (ext_stmt) {
+ CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
+ }
+
/* initialize from file */
PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
zend_try {
phpdbg_init(init_file, init_file_len, init_file_default);
- if (bp_tmp) {
- PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
- phpdbg_string_init(bp_tmp);
- free(bp_tmp);
- bp_tmp = NULL;
- PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
- }
} zend_end_try();
PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
@@ -1653,49 +1902,99 @@ phpdbg_main:
}
/* auto compile */
- if (PHPDBG_G(exec)) {
- if (settings) {
+ if (read_from_stdin) {
+ if (!read_from_stdin[0]) {
+ if (!quit_immediately) {
+ phpdbg_error("error", "", "Impossible to not specify a stdin delimiter without -rr");
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+ goto phpdbg_out;
+ }
+ }
+ if (show_banner || read_from_stdin[0]) {
+ phpdbg_notice("stdin", "delimiter=\"%s\"", "Reading input from stdin; put '%s' followed by a newline on an own line after code to end input", read_from_stdin);
+ }
+
+ if (phpdbg_startup_run > 0) {
PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
}
zend_try {
- phpdbg_compile();
+ phpdbg_param_t cmd;
+ cmd.str = read_from_stdin;
+ cmd.len = strlen(read_from_stdin);
+ PHPDBG_COMMAND_HANDLER(stdin)(&cmd);
} zend_end_try();
PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
+ } else if (PHPDBG_G(exec)) {
+ if (settings || phpdbg_startup_run > 0) {
+ PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
+ }
+
+ zend_try {
+ if (backup_phpdbg_compile) {
+ phpdbg_compile_stdin(backup_phpdbg_compile);
+ } else {
+ phpdbg_compile();
+ }
+ } zend_end_try();
+ backup_phpdbg_compile = NULL;
+
+ PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
+ }
+
+ if (bp_tmp) {
+ PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT | PHPDBG_IS_INITIALIZING;
+ phpdbg_string_init(bp_tmp);
+ free(bp_tmp);
+ bp_tmp = NULL;
+ PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT & ~PHPDBG_IS_INITIALIZING;
}
if (settings == (void *) 0x1) {
if (PHPDBG_G(ops)) {
phpdbg_print_opcodes(print_opline_func);
} else {
- write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("No opcodes could be compiled | No file specified or compilation failed?\n"));
+ zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("No opcodes could be compiled | No file specified or compilation failed?\n"));
}
goto phpdbg_out;
}
+ PG(during_request_startup) = 0;
+
phpdbg_fully_started = 1;
/* #ifndef for making compiler shutting up */
#ifndef _WIN32
phpdbg_interact:
#endif
-
/* phpdbg main() */
do {
zend_try {
if (phpdbg_startup_run) {
- quit_immediately = phpdbg_startup_run > 1;
phpdbg_startup_run = 0;
- PHPDBG_COMMAND_HANDLER(run)(NULL);
+ if (quit_immediately) {
+ PHPDBG_G(flags) = (PHPDBG_G(flags) & ~PHPDBG_HAS_PAGINATION) | PHPDBG_IS_INTERACTIVE | PHPDBG_PREVENT_INTERACTIVE;
+ } else {
+ PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
+ }
+ zend_try {
+ if (first_command) {
+ phpdbg_interactive(1, estrdup(first_command));
+ } else {
+ PHPDBG_COMMAND_HANDLER(run)(NULL);
+ }
+ } zend_end_try();
if (quit_immediately) {
/* if -r is on the command line more than once just quit */
EG(bailout) = __orig_bailout; /* reset zend_try */
+ exit_status = EG(exit_status);
break;
}
}
- phpdbg_interactive(1);
+ CG(unclean_shutdown) = 0;
+ phpdbg_interactive(1, NULL);
} zend_catch {
if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
char *bp_tmp_str;
@@ -1738,16 +2037,6 @@ phpdbg_interact:
} while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
- if (PHPDBG_G(exec) && (PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
- exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */
- }
-
- /* this must be forced */
- CG(unclean_shutdown) = 0;
-
- /* this is just helpful */
- PG(report_memleaks) = 0;
-
#ifndef _WIN32
phpdbg_out:
if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
@@ -1763,6 +2052,11 @@ phpdbg_out:
phpdbg_out:
#endif
+ if (first_command) {
+ free(first_command);
+ first_command = NULL;
+ }
+
if (cleaning <= 0) {
PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING;
cleaning = -1;
@@ -1771,22 +2065,12 @@ phpdbg_out:
{
int i;
/* free argv */
- for (i = SG(request_info).argc; --i;) {
+ for (i = SG(request_info).argc; i--;) {
efree(SG(request_info).argv[i]);
}
efree(SG(request_info).argv);
}
-#ifndef _WIN32
- /* reset it... else we risk a stack overflow upon next run (when clean'ing) */
- php_stream_stdio_ops.write = PHPDBG_G(php_stdiop_write);
-#endif
-
-#ifndef ZTS
- /* force cleanup of auto and core globals */
- zend_hash_clean(CG(auto_globals));
- memset( &core_globals, 0, sizeof(php_core_globals));
-#endif
if (ini_entries) {
free(ini_entries);
}
@@ -1795,60 +2079,133 @@ phpdbg_out:
free(ini_override);
}
- /* this must be forced */
- CG(unclean_shutdown) = 0;
-
- /* this is just helpful */
- PG(report_memleaks) = 0;
+ /* In case we aborted during script execution, we may not reset CG(unclean_shutdown) */
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_RUNNING)) {
+ is_exit = !PHPDBG_G(in_execution);
+ CG(unclean_shutdown) = is_exit || PHPDBG_G(unclean_eval);
+ }
if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) {
php_free_shutdown_functions();
zend_objects_store_mark_destructed(&EG(objects_store));
}
- /* sapi_module.deactivate is where to backup things, last chance before mm_shutdown... */
-
zend_try {
php_request_shutdown(NULL);
} zend_end_try();
- if ((PHPDBG_G(flags) & (PHPDBG_IS_QUITTING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_RUNNING) {
- phpdbg_notice("stop", "type=\"normal\"", "Script ended normally");
- cleaning++;
+ if (PHPDBG_G(exec) && !memcmp("-", PHPDBG_G(exec), 2)) { /* i.e. execution context has been read from stdin - back it up */
+ phpdbg_file_source *data = zend_hash_str_find_ptr(&PHPDBG_G(file_sources), PHPDBG_G(exec), PHPDBG_G(exec_len));
+ backup_phpdbg_compile = zend_string_alloc(data->len + 2, 1);
+ sprintf(ZSTR_VAL(backup_phpdbg_compile), "?>%.*s", (int) data->len, data->buf);
+ }
+
+ /* backup globals when cleaning */
+ if ((cleaning > 0 || remote) && !quit_immediately) {
+ settings = calloc(1, sizeof(zend_phpdbg_globals));
+
+ php_phpdbg_globals_ctor(settings);
+
+ if (PHPDBG_G(exec)) {
+ settings->exec = zend_strndup(PHPDBG_G(exec), PHPDBG_G(exec_len));
+ settings->exec_len = PHPDBG_G(exec_len);
+ }
+ settings->oplog = PHPDBG_G(oplog);
+ settings->prompt[0] = PHPDBG_G(prompt)[0];
+ settings->prompt[1] = PHPDBG_G(prompt)[1];
+ memcpy(settings->colors, PHPDBG_G(colors), sizeof(settings->colors));
+ settings->eol = PHPDBG_G(eol);
+ settings->input_buflen = PHPDBG_G(input_buflen);
+ memcpy(settings->input_buffer, PHPDBG_G(input_buffer), settings->input_buflen);
+ settings->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK;
+ first_command = PHPDBG_G(cur_command);
+ } else {
+ if (PHPDBG_G(prompt)[0]) {
+ free(PHPDBG_G(prompt)[0]);
+ }
+ if (PHPDBG_G(prompt)[1]) {
+ free(PHPDBG_G(prompt)[1]);
+ }
+ if (PHPDBG_G(cur_command)) {
+ free(PHPDBG_G(cur_command));
+ }
}
- if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) == PHPDBG_IS_CLEANING) {
- settings = PHPDBG_G(backup);
+ if (exit_status == 0) {
+ exit_status = EG(exit_status);
}
php_output_deactivate();
+ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+ if (PHPDBG_G(in_execution) || is_exit) {
+ if (!quit_immediately && !phpdbg_startup_run) {
+ PHPDBG_G(flags) -= PHPDBG_IS_QUITTING;
+ cleaning++;
+ }
+ }
+ }
+
+ {
+ php_stream_wrapper *wrapper = zend_hash_str_find_ptr(php_stream_get_url_stream_wrappers_hash(), ZEND_STRL("php"));
+ wrapper->wops->stream_opener = PHPDBG_G(orig_url_wrap_php);
+ }
+
zend_try {
php_module_shutdown();
} zend_end_try();
- sapi_shutdown();
+#ifndef _WIN32
+ /* force override (no zend_signals) to prevent crashes due to signal recursion in SIGSEGV/SIGBUS handlers */
+ signal(SIGSEGV, SIG_DFL);
+ signal(SIGBUS, SIG_DFL);
+ /* reset it... else we risk a stack overflow upon next run (when clean'ing) */
+ php_stream_stdio_ops.write = PHPDBG_G(php_stdiop_write);
+#endif
}
- if ((cleaning > 0 || remote) && !quit_immediately) {
- goto phpdbg_main;
+ sapi_shutdown();
+
+ if (sapi_name) {
+ free(sapi_name);
+ }
+
+free_and_return:
+ if (read_from_stdin) {
+ free(read_from_stdin);
+ read_from_stdin = NULL;
}
#ifdef ZTS
- /* bugggy */
- /* tsrm_shutdown(); */
+ /* reset to original handlers - otherwise PHPDBG_G() in phpdbg_watch_efree will be segfaulty (with e.g. USE_ZEND_ALLOC=0) */
+ if (!use_mm_wrappers) {
+ zend_mm_set_custom_handlers(zend_mm_get_heap(), _malloc, _free, _realloc);
+ }
+
+ ts_free_id(phpdbg_globals_id);
+
+ tsrm_shutdown();
#endif
+ if ((cleaning > 0 || remote) && !quit_immediately) {
+ /* reset internal php_getopt state */
+ php_getopt(-1, argv, OPTIONS, NULL, &php_optind, 0, 0);
+
+ goto phpdbg_main;
+ }
+
+ if (backup_phpdbg_compile) {
+ zend_string_free(backup_phpdbg_compile);
+ }
+
#ifndef _WIN32
if (address) {
free(address);
}
#endif
- if (PHPDBG_G(sapi_name_ptr)) {
- free(PHPDBG_G(sapi_name_ptr));
- }
-
- return 0;
+ /* usually 0; just for -rr */
+ return exit_status;
} /* }}} */
diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h
index f900866211..cf591a8a4e 100644
--- a/sapi/phpdbg/phpdbg.h
+++ b/sapi/phpdbg/phpdbg.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -45,8 +45,11 @@
#include "zend_globals.h"
#include "zend_ini_scanner.h"
#include "zend_stream.h"
-#ifndef _WIN32
-# include "zend_signal.h"
+#include "zend_signal.h"
+#if !defined(_WIN32) && !defined(ZEND_SIGNALS) && defined(HAVE_SIGNAL_H)
+# include <signal.h>
+#elif PHP_WIN32
+# include "win32/signal.h"
#endif
#include "SAPI.h"
#include <fcntl.h>
@@ -181,28 +184,31 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input);
#define PHPDBG_IS_INITIALIZING (1ULL<<25)
#define PHPDBG_IS_SIGNALED (1ULL<<26)
#define PHPDBG_IS_INTERACTIVE (1ULL<<27)
-#define PHPDBG_IS_BP_ENABLED (1ULL<<28)
-#define PHPDBG_IS_REMOTE (1ULL<<29)
-#define PHPDBG_IS_DISCONNECTED (1ULL<<30)
-#define PHPDBG_WRITE_XML (1ULL<<31)
+#define PHPDBG_PREVENT_INTERACTIVE (1ULL<<28)
+#define PHPDBG_IS_BP_ENABLED (1ULL<<29)
+#define PHPDBG_IS_REMOTE (1ULL<<30)
+#define PHPDBG_IS_DISCONNECTED (1ULL<<31)
+#define PHPDBG_WRITE_XML (1ULL<<32)
+
+#define PHPDBG_SHOW_REFCOUNTS (1ULL<<33)
-#define PHPDBG_SHOW_REFCOUNTS (1ULL<<32)
+#define PHPDBG_IN_SIGNAL_HANDLER (1ULL<<34)
-#define PHPDBG_IN_SIGNAL_HANDLER (1ULL<<33)
+#define PHPDBG_DISCARD_OUTPUT (1ULL<<35)
-#define PHPDBG_DISCARD_OUTPUT (1ULL<<34)
+#define PHPDBG_HAS_PAGINATION (1ULL<<36)
#define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL | PHPDBG_IN_FINISH | PHPDBG_IN_LEAVE)
#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP | PHPDBG_HAS_SYM_BP | PHPDBG_HAS_METHOD_BP | PHPDBG_HAS_OPLINE_BP | PHPDBG_HAS_COND_BP | PHPDBG_HAS_OPCODE_BP | PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
#define PHPDBG_IS_STOPPING (PHPDBG_IS_QUITTING | PHPDBG_IS_CLEANING)
-#define PHPDBG_PRESERVE_FLAGS_MASK (PHPDBG_SHOW_REFCOUNTS | PHPDBG_IS_STEPONEVAL | PHPDBG_IS_BP_ENABLED | PHPDBG_STEP_OPCODE | PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_REMOTE | PHPDBG_WRITE_XML | PHPDBG_IS_DISCONNECTED)
+#define PHPDBG_PRESERVE_FLAGS_MASK (PHPDBG_SHOW_REFCOUNTS | PHPDBG_IS_STEPONEVAL | PHPDBG_IS_BP_ENABLED | PHPDBG_STEP_OPCODE | PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_REMOTE | PHPDBG_WRITE_XML | PHPDBG_IS_DISCONNECTED | PHPDBG_HAS_PAGINATION)
#ifndef _WIN32
-# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED)
+# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED | PHPDBG_HAS_PAGINATION)
#else
-# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_BP_ENABLED)
+# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_BP_ENABLED | PHPDBG_HAS_PAGINATION)
#endif /* }}} */
/* {{{ output descriptors */
@@ -227,6 +233,8 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input);
}
+void phpdbg_register_file_handles(void);
+
/* {{{ structs */
ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */
@@ -237,6 +245,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
phpdbg_frame_t frame; /* frame */
uint32_t last_line; /* last executed line */
+ char *cur_command; /* current command */
phpdbg_lexer_data lexer; /* lexer data */
phpdbg_param_t *parser_stack; /* param stack during lexer / parser phase */
@@ -245,12 +254,15 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
#endif
phpdbg_btree watchpoint_tree; /* tree with watchpoints */
phpdbg_btree watch_HashTables; /* tree with original dtors of watchpoints */
- HashTable watchpoints; /* watchpoints */
+ HashTable watch_elements; /* user defined watch elements */
HashTable watch_collisions; /* collision table to check if multiple watches share the same recursive watchpoint */
- zend_llist watchlist_mem; /* triggered watchpoints */
+ HashTable watch_recreation; /* watch elements pending recreation of their respective watchpoints */
+ HashTable watch_free; /* pointers to watch for being freed */
+ HashTable *watchlist_mem; /* triggered watchpoints */
+ HashTable *watchlist_mem_backup; /* triggered watchpoints backup table while iterating over it */
zend_bool watchpoint_hit; /* a watchpoint was hit */
void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */
- phpdbg_watchpoint_t *watch_tmp; /* temporary pointer for a watchpoint */
+ phpdbg_watch_element *watch_tmp; /* temporary pointer for a watch element */
char *exec; /* file to execute */
size_t exec_len; /* size of exec */
@@ -259,8 +271,11 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
int bp_count; /* breakpoint count */
int vmret; /* return from last opcode handler execution */
zend_bool in_execution; /* in execution? */
+ zend_bool unclean_eval; /* do not check for memory leaks when we needed to bail out during eval */
zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type);
+ zend_op_array *(*init_compile_file)(zend_file_handle *file_handle, int type);
+ zend_op_array *(*compile_string)(zval *source_string, char *filename);
HashTable file_sources;
FILE *oplog; /* opline log */
@@ -292,6 +307,9 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
char *buffer; /* buffer */
zend_bool last_was_newline; /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */
+ FILE *stdin_file; /* FILE pointer to stdin source file */
+ php_stream *(*orig_url_wrap_php)(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC);
+
char input_buffer[PHPDBG_MAX_CMD]; /* stdin input buffer */
int input_buflen; /* length of stdin input buffer */
phpdbg_signal_safe_mem sigsafe_mem; /* memory to use in async safe environment (only once!) */
@@ -308,8 +326,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
HANDLE sigio_watcher_thread; /* sigio watcher thread handle */
struct win32_sigio_watcher_data swd;
#endif
-
- struct _zend_phpdbg_globals *backup; /* backup of data to store */
+ long lines; /* max number of lines to display */
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
#endif
diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c
index 1c06646f0e..49f74b87a9 100644
--- a/sapi/phpdbg/phpdbg_bp.c
+++ b/sapi/phpdbg/phpdbg_bp.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,8 +25,9 @@
#include "phpdbg_utils.h"
#include "phpdbg_opcode.h"
#include "zend_globals.h"
+#include "ext/standard/php_string.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
/* {{{ private api functions */
static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array*);
@@ -63,6 +64,7 @@ static void phpdbg_file_breaks_dtor(zval *data) /* {{{ */
phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) Z_PTR_P(data);
efree((char*)bp->filename);
+ efree(bp);
} /* }}} */
static void phpdbg_class_breaks_dtor(zval *data) /* {{{ */
@@ -71,11 +73,13 @@ static void phpdbg_class_breaks_dtor(zval *data) /* {{{ */
efree((char*)bp->class_name);
efree((char*)bp->func_name);
+ efree(bp);
} /* }}} */
static void phpdbg_opline_class_breaks_dtor(zval *data) /* {{{ */
{
- zend_hash_destroy((HashTable *) Z_PTR_P(data));
+ zend_hash_destroy(Z_ARRVAL_P(data));
+ efree(Z_ARRVAL_P(data));
} /* }}} */
static void phpdbg_opline_breaks_dtor(zval *data) /* {{{ */
@@ -88,6 +92,7 @@ static void phpdbg_opline_breaks_dtor(zval *data) /* {{{ */
if (bp->func_name) {
efree((char*)bp->func_name);
}
+ efree(bp);
} /* }}} */
PHPDBG_API void phpdbg_reset_breakpoints(void) /* {{{ */
@@ -131,10 +136,12 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */
switch (brake->type) {
case PHPDBG_BREAK_FILE: {
+ zend_string *filename = php_addcslashes(zend_string_init(((phpdbg_breakfile_t*)brake)->filename, strlen(((phpdbg_breakfile_t*)brake)->filename), 0), 1, "\\\"\n", 3);
phpdbg_asprintf(&new_str,
- "%sbreak %s:%lu\n", *str,
- ((phpdbg_breakfile_t*)brake)->filename,
+ "%sbreak \"%s\":%lu\n", *str,
+ ZSTR_VAL(filename),
((phpdbg_breakfile_t*)brake)->line);
+ zend_string_release(filename);
} break;
case PHPDBG_BREAK_SYM: {
@@ -166,10 +173,12 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */
} break;
case PHPDBG_BREAK_FILE_OPLINE: {
+ zend_string *filename = php_addcslashes(zend_string_init(((phpdbg_breakopline_t*)brake)->class_name, strlen(((phpdbg_breakopline_t*)brake)->class_name), 0), 1, "\\\"\n", 3);
phpdbg_asprintf(&new_str,
- "%sbreak %s:#%llu\n", *str,
- ((phpdbg_breakopline_t*)brake)->class_name,
+ "%sbreak \"%s\":#%llu\n", *str,
+ ZSTR_VAL(filename),
((phpdbg_breakopline_t*)brake)->opline_num);
+ zend_string_release(filename);
} break;
case PHPDBG_BREAK_OPCODE: {
@@ -195,12 +204,14 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */
conditional->code);
break;
- case FILE_PARAM:
+ case FILE_PARAM: {
+ zend_string *filename = php_addcslashes(zend_string_init(conditional->param.file.name, strlen(conditional->param.file.name), 0), 1, "\\\"\n", 3);
phpdbg_asprintf(&new_str,
- "%sbreak at %s:%lu if %s\n", *str,
- conditional->param.file.name, conditional->param.file.line,
+ "%sbreak at \"%s\":%lu if %s\n", *str,
+ ZSTR_VAL(filename), conditional->param.file.line,
conditional->code);
- break;
+ zend_string_release(filename);
+ } break;
default: { /* do nothing */ } break;
}
@@ -208,6 +219,8 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */
phpdbg_asprintf(&new_str, "%sbreak if %s\n", str, conditional->code);
}
} break;
+
+ default: continue;
}
if ((*str)[0]) {
@@ -226,17 +239,24 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */
PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* {{{ */
{
+ phpdbg_set_breakpoint_file_ex(path, 0, line_num);
+} /* }}} */
+
+PHPDBG_API void phpdbg_set_breakpoint_file_ex(const char *path, size_t path_len, long line_num) /* {{{ */
+{
php_stream_statbuf ssb;
char realpath[MAXPATHLEN];
const char *original_path = path;
zend_bool pending = 0;
+ zend_string *path_str;
- HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE];
+ HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE];
phpdbg_breakfile_t new_break;
- size_t path_len = 0L;
- if (VCWD_REALPATH(path, realpath)) {
- path = realpath;
+ if (!path_len) {
+ if (VCWD_REALPATH(path, realpath)) {
+ path = realpath;
+ }
}
path_len = strlen(path);
@@ -261,11 +281,13 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* {
}
}
- if (!(broken = zend_hash_str_find_ptr(file_breaks, path, path_len))) {
+ path_str = zend_string_init(path, path_len, 0);
+
+ if (!(broken = zend_hash_find_ptr(file_breaks, path_str))) {
HashTable breaks;
zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0);
- broken = zend_hash_str_add_mem(file_breaks, path, path_len, &breaks, sizeof(HashTable));
+ broken = zend_hash_add_mem(file_breaks, path_str, &breaks, sizeof(HashTable));
}
if (!zend_hash_index_exists(broken, line_num)) {
@@ -278,18 +300,17 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* {
PHPDBG_BREAK_MAPPING(new_break.id, broken);
if (pending) {
- zend_string *file, *path_str = zend_string_init(path, path_len, 0);
+ zend_string *file;
ZEND_HASH_FOREACH_STR_KEY(&PHPDBG_G(file_sources), file) {
HashTable *fileht;
phpdbg_debug("Compare against loaded %s\n", file);
if (!(pending = ((fileht = phpdbg_resolve_pending_file_break_ex(ZSTR_VAL(file), ZSTR_LEN(file), path_str, broken)) == NULL))) {
- new_break = *(phpdbg_breakfile_t *) zend_hash_index_find_ptr(broken, line_num);
+ new_break = *(phpdbg_breakfile_t *) zend_hash_index_find_ptr(fileht, line_num);
break;
}
} ZEND_HASH_FOREACH_END();
- zend_string_release(path_str);
}
if (pending) {
@@ -304,13 +325,21 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num) /* {
} else {
phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num);
}
+
+ zend_string_release(path_str);
} /* }}} */
PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, zend_string *cur, HashTable *fileht) /* {{{ */
{
phpdbg_debug("file: %s, filelen: %u, cur: %s, curlen %u, pos: %c, memcmp: %d\n", file, filelen, ZSTR_VAL(cur), ZSTR_LEN(cur), filelen > ZSTR_LEN(cur) ? file[filelen - ZSTR_LEN(cur) - 1] : '?', filelen > ZSTR_LEN(cur) ? memcmp(file + filelen - ZSTR_LEN(cur), ZSTR_VAL(cur), ZSTR_LEN(cur)) : 0);
- if (((ZSTR_LEN(cur) < filelen && file[filelen - ZSTR_LEN(cur) - 1] == '/') || filelen == ZSTR_LEN(cur)) && !memcmp(file + filelen - ZSTR_LEN(cur), ZSTR_VAL(cur), ZSTR_LEN(cur))) {
+#ifdef _WIN32
+# define WIN32_PATH_CHECK file[filelen - ZSTR_LEN(cur) - 1] == '\\'
+#else
+# define WIN32_PATH_CHECK 0
+#endif
+
+ if (((ZSTR_LEN(cur) < filelen && (file[filelen - ZSTR_LEN(cur) - 1] == '/' || WIN32_PATH_CHECK)) || filelen == ZSTR_LEN(cur)) && !memcmp(file + filelen - ZSTR_LEN(cur), ZSTR_VAL(cur), ZSTR_LEN(cur))) {
phpdbg_breakfile_t *brake, new_brake;
HashTable *master;
@@ -327,8 +356,7 @@ PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uin
new_brake.filename = estrndup(file, filelen);
PHPDBG_BREAK_UNMAPPING(brake->id);
- if (master) {
- zend_hash_index_update_mem(master, brake->line, &new_brake, sizeof(phpdbg_breakfile_t));
+ if (zend_hash_index_add_mem(master, brake->line, &new_brake, sizeof(phpdbg_breakfile_t))) {
PHPDBG_BREAK_MAPPING(brake->id, master);
}
} ZEND_HASH_FOREACH_END();
@@ -364,6 +392,15 @@ PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file) /* {{{ */
PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len) /* {{{ */
{
+ char *lcname;
+
+ if (*name == '\\') {
+ name++;
+ name_len--;
+ }
+
+ lcname = zend_str_tolower_dup(name, name_len);
+
if (!zend_hash_str_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) {
phpdbg_breaksymbol_t new_break;
@@ -372,7 +409,7 @@ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len)
PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_SYM);
new_break.symbol = estrndup(name, name_len);
- zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol, name_len, &new_break, sizeof(phpdbg_breaksymbol_t));
+ zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], lcname, name_len, &new_break, sizeof(phpdbg_breaksymbol_t));
phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" function=\"%s\"", "Breakpoint #%d added at %s", new_break.id, new_break.symbol);
@@ -380,6 +417,8 @@ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len)
} else {
phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" function=\"%s\"", "Breakpoint exists at %s", name);
}
+
+ efree(lcname);
} /* }}} */
PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char *func_name) /* {{{ */
@@ -387,14 +426,22 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char
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);
+ char *func_lcname, *class_lcname;
+
+ if (*class_name == '\\') {
+ class_name++;
+ class_len--;
+ }
+
+ func_lcname = zend_str_tolower_dup(func_name, func_len);
+ class_lcname = zend_str_tolower_dup(class_name, class_len);
- if (!(class_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, class_len))) {
+ if (!(class_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_lcname, class_len))) {
zend_hash_init(&class_breaks, 8, NULL, phpdbg_class_breaks_dtor, 0);
- class_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, class_len, &class_breaks, sizeof(HashTable));
+ class_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_lcname, class_len, &class_breaks, sizeof(HashTable));
}
- if (!zend_hash_str_exists(class_table, lcname, func_len)) {
+ if (!zend_hash_str_exists(class_table, func_lcname, func_len)) {
phpdbg_breakmethod_t new_break;
PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_BP;
@@ -405,7 +452,7 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char
new_break.func_name = estrndup(func_name, func_len);
new_break.func_len = func_len;
- zend_hash_str_update_mem(class_table, lcname, func_len, &new_break, sizeof(phpdbg_breakmethod_t));
+ zend_hash_str_update_mem(class_table, func_lcname, func_len, &new_break, sizeof(phpdbg_breakmethod_t));
phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" method=\"%s::%s\"", "Breakpoint #%d added at %s::%s", new_break.id, class_name, func_name);
@@ -414,7 +461,8 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char
phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" method=\"%s::%s\"", "Breakpoint exists at %s::%s", class_name, func_name);
}
- efree(lcname);
+ efree(func_lcname);
+ efree(class_lcname);
} /* }}} */
PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline) /* {{{ */
@@ -500,12 +548,12 @@ PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array) /* {{{ *
opline_break = zend_hash_get_current_data_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" symbol=\"%s\" num=\"%ld\" opline=\"%#lx\"", "Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)",
- brake->id,
+ opline_break->id,
brake->class_name ? brake->class_name : "",
brake->class_name && brake->func_name ? "::" : "",
brake->func_name ? brake->func_name : "",
brake->opline_num,
- brake->opline);
+ opline_break->opline);
}
} ZEND_HASH_FOREACH_END();
} /* }}} */
@@ -528,12 +576,14 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break) /* {
} else {
zend_execute_data *execute_data = EG(current_execute_data);
do {
- zend_op_array *op_array = &execute_data->func->op_array;
- if (op_array->function_name == NULL && op_array->scope == NULL && new_break->class_len == ZSTR_LEN(op_array->filename) && !memcmp(ZSTR_VAL(op_array->filename), new_break->class_name, new_break->class_len)) {
- if (phpdbg_resolve_op_array_break(new_break, op_array) == SUCCESS) {
- return SUCCESS;
- } else {
- return 2;
+ if (ZEND_USER_CODE(execute_data->func->common.type)) {
+ zend_op_array *op_array = &execute_data->func->op_array;
+ if (op_array->function_name == NULL && op_array->scope == NULL && new_break->class_len == ZSTR_LEN(op_array->filename) && !memcmp(ZSTR_VAL(op_array->filename), new_break->class_name, new_break->class_len)) {
+ if (phpdbg_resolve_op_array_break(new_break, op_array) == SUCCESS) {
+ return SUCCESS;
+ } else {
+ return 2;
+ }
}
}
} while ((execute_data = execute_data->prev_execute_data) != NULL);
@@ -573,6 +623,8 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break) /* {
return SUCCESS;
} /* }}} */
+/* TODO ... method/function oplines need to be normalized (leading backslash, lowercase) and file oplines need to be resolved properly */
+
PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline) /* {{{ */
{
phpdbg_breakopline_t new_break;
@@ -749,6 +801,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline) /* {
PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE);
new_break.opline = (zend_ulong) opline;
+ new_break.base = NULL;
zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t));
@@ -846,21 +899,13 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_
{
HashTable *breaks;
phpdbg_breakbase_t *brake;
- size_t path_len;
- char realpath[MAXPATHLEN];
- const char *path = ZSTR_VAL(op_array->filename);
-
- if (VCWD_REALPATH(path, realpath)) {
- path = realpath;
- }
-
- path_len = strlen(path);
#if 0
- phpdbg_debug("Op at: %.*s %d\n", path_len, path, (*EG(opline_ptr))->lineno);
+ phpdbg_debug("Op at: %.*s %d\n", ZSTR_LEN(op_array->filename), ZSTR_VAL(op_array->filename), (*EG(opline_ptr))->lineno);
#endif
- if (!(breaks = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len))) {
+ /* NOTE: realpath resolution should have happened at compile time - no reason to do it here again */
+ if (!(breaks = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename))) {
return NULL;
}
@@ -873,8 +918,6 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_
static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *fbc) /* {{{ */
{
- const char *fname;
- size_t flen;
zend_op_array *ops;
if (fbc->type != ZEND_USER_FUNCTION) {
@@ -889,30 +932,33 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *f
}
if (ops->function_name) {
- fname = ZSTR_VAL(ops->function_name);
- flen = ZSTR_LEN(ops->function_name);
+ phpdbg_breakbase_t *brake;
+ zend_string *fname = zend_string_tolower(ops->function_name);
+
+ brake = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname);
+
+ zend_string_release(fname);
+ return brake;
} else {
- fname = "main";
- flen = 4;
+ return zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], ZEND_STRL("main"));
}
-
- return zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname, flen);
} /* }}} */
static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array *ops) /* {{{ */
{
HashTable *class_table;
phpdbg_breakbase_t *brake = NULL;
+ zend_string *class_lcname = zend_string_tolower(ops->scope->name);
- if ((class_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name))) {
- size_t lcname_len = ZSTR_LEN(ops->function_name);
- char *lcname = zend_str_tolower_dup(ZSTR_VAL(ops->function_name), lcname_len);
+ if ((class_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_lcname))) {
+ zend_string *lcname = zend_string_tolower(ops->function_name);
- brake = zend_hash_str_find_ptr(class_table, lcname, lcname_len);
+ brake = zend_hash_find_ptr(class_table, lcname);
- efree(lcname);
+ zend_string_release(lcname);
}
+ zend_string_release(class_lcname);
return brake;
} /* }}} */
@@ -929,9 +975,9 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_pt
static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode) /* {{{ */
{
- const char *opname = phpdbg_decode_opcode(opcode);
+ const char *opname = zend_get_opcode_name(opcode);
- if (memcmp(opname, PHPDBG_STRL("UNKNOWN")) == 0) {
+ if (!opname) {
return NULL;
}
@@ -1038,11 +1084,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut
zend_try {
PHPDBG_G(flags) |= PHPDBG_IN_COND_BP;
zend_execute(bp->ops, &retval);
-#if PHP_VERSION_ID >= 50700
- if (zend_is_true(&retval)) {
-#else
if (zend_is_true(&retval)) {
-#endif
breakpoint = SUCCESS;
}
} zend_end_try();
@@ -1081,8 +1123,9 @@ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data *execute
}
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 == execute_data->func->op_array.opcodes) {
+ zend_op_array *op_array = &execute_data->func->op_array;
+ /* check we are at the beginning of the stack, but after argument RECV */
+ if (execute_data->opline == op_array->opcodes + op_array->num_args + !!(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
if ((base = phpdbg_find_breakpoint_symbol(execute_data->func))) {
goto result;
}
diff --git a/sapi/phpdbg/phpdbg_bp.h b/sapi/phpdbg/phpdbg_bp.h
index 5cf3f5631d..b44d5ec74e 100644
--- a/sapi/phpdbg/phpdbg_bp.h
+++ b/sapi/phpdbg/phpdbg_bp.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -126,6 +126,7 @@ PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file); /* }}} */
/* {{{ Breakpoint Creation API */
PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno);
+PHPDBG_API void phpdbg_set_breakpoint_file_ex(const char* filename, size_t path_len, long lineno);
PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len);
PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name);
PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len);
diff --git a/sapi/phpdbg/phpdbg_break.c b/sapi/phpdbg/phpdbg_break.c
index c0465ff417..0640d96fd8 100644
--- a/sapi/phpdbg/phpdbg_break.c
+++ b/sapi/phpdbg/phpdbg_break.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -26,7 +26,7 @@
#include "phpdbg_bp.h"
#include "phpdbg_prompt.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s, flags) \
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9], flags)
diff --git a/sapi/phpdbg/phpdbg_break.h b/sapi/phpdbg/phpdbg_break.h
index deb5031a12..4a74028c0e 100644
--- a/sapi/phpdbg/phpdbg_break.h
+++ b/sapi/phpdbg/phpdbg_break.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_btree.c b/sapi/phpdbg/phpdbg_btree.c
index 2311f05126..7e1937fc73 100644
--- a/sapi/phpdbg/phpdbg_btree.c
+++ b/sapi/phpdbg/phpdbg_btree.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,14 +25,17 @@
branch = branch->branches[!!(n)];
#ifdef _Win32
-# define emalloc malloc
-# define efree free
+# undef pemalloc
+# undef pefree
+# define pemalloc(size, persistent) malloc(size)
+# define pefree(ptr, persistent) free(ptr)
#endif
/* depth in bits */
void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth) {
tree->depth = depth;
tree->branch = NULL;
+ tree->persistent = 0;
tree->count = 0;
}
@@ -66,7 +69,6 @@ phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx) {
phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong idx) {
phpdbg_btree_branch *branch = tree->branch;
int i = tree->depth - 1, last_superior_i = -1;
- zend_bool had_alternative_branch = 0;
if (branch == NULL) {
return NULL;
@@ -74,30 +76,33 @@ phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong id
/* find nearest watchpoint */
do {
- /* an impossible branch was found if: */
- if (!had_alternative_branch && (idx >> i) % 2 == 0 && !branch->branches[0]) {
- /* there's no lower branch than idx */
- if (last_superior_i == -1) {
- /* failure */
- return NULL;
- }
- /* reset state */
- branch = tree->branch;
- i = tree->depth - 1;
- /* follow branch according to bits in idx until the last lower branch before the impossible branch */
- do {
- CHOOSE_BRANCH((idx >> i) % 2 == 1 && branch->branches[1]);
- } while (--i > last_superior_i);
- /* use now the lower branch of which we can be sure that it contains only branches lower than idx */
- CHOOSE_BRANCH(0);
- /* and choose the highest possible branch in the branch containing only branches lower than idx */
- while (i--) {
- CHOOSE_BRANCH(branch->branches[1]);
+ if ((idx >> i) % 2 == 0) {
+ if (branch->branches[0]) {
+ CHOOSE_BRANCH(0);
+ /* an impossible branch was found if: */
+ } else {
+ /* there's no lower branch than idx */
+ if (last_superior_i == -1) {
+ /* failure */
+ return NULL;
+ }
+ /* reset state */
+ branch = tree->branch;
+ i = tree->depth - 1;
+ /* follow branch according to bits in idx until the last lower branch before the impossible branch */
+ do {
+ CHOOSE_BRANCH((idx >> i) % 2 == 1 && branch->branches[1]);
+ } while (--i > last_superior_i);
+ /* use now the lower branch of which we can be sure that it contains only branches lower than idx */
+ CHOOSE_BRANCH(0);
+ /* and choose the highest possible branch in the branch containing only branches lower than idx */
+ while (i--) {
+ CHOOSE_BRANCH(branch->branches[1]);
+ }
+ break;
}
- break;
- }
/* follow branch according to bits in idx until having found an impossible branch */
- if (had_alternative_branch || (idx >> i) % 2 == 1) {
+ } else {
if (branch->branches[1]) {
if (branch->branches[0]) {
last_superior_i = i;
@@ -105,10 +110,11 @@ phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong id
CHOOSE_BRANCH(1);
} else {
CHOOSE_BRANCH(0);
- had_alternative_branch = 1;
+ while (i--) {
+ CHOOSE_BRANCH(branch->branches[1]);
+ }
+ break;
}
- } else {
- CHOOSE_BRANCH(0);
}
} while (i--);
@@ -154,7 +160,7 @@ int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr,
}
{
- phpdbg_btree_branch *memory = *branch = emalloc((i + 2) * sizeof(phpdbg_btree_branch));
+ phpdbg_btree_branch *memory = *branch = pemalloc((i + 2) * sizeof(phpdbg_btree_branch), tree->persistent);
do {
(*branch)->branches[!((idx >> i) % 2)] = NULL;
branch = &(*branch)->branches[(idx >> i) % 2];
@@ -196,14 +202,14 @@ check_branch_existence:
tree->count--;
if (i_last_dual_branch == -1) {
- efree(tree->branch);
+ pefree(tree->branch, tree->persistent);
tree->branch = NULL;
} else {
if (last_dual_branch->branches[last_dual_branch_branch] == last_dual_branch + 1) {
phpdbg_btree_branch *original_branch = last_dual_branch->branches[!last_dual_branch_branch];
memcpy(last_dual_branch + 1, last_dual_branch->branches[!last_dual_branch_branch], (i_last_dual_branch + 1) * sizeof(phpdbg_btree_branch));
- efree(last_dual_branch->branches[!last_dual_branch_branch]);
+ pefree(last_dual_branch->branches[!last_dual_branch_branch], tree->persistent);
last_dual_branch->branches[!last_dual_branch_branch] = last_dual_branch + 1;
branch = last_dual_branch->branches[!last_dual_branch_branch];
@@ -211,7 +217,7 @@ check_branch_existence:
branch = (branch->branches[branch->branches[1] == ++original_branch] = last_dual_branch + i_last_dual_branch - i + 1);
}
} else {
- efree(last_dual_branch->branches[last_dual_branch_branch]);
+ pefree(last_dual_branch->branches[last_dual_branch_branch], tree->persistent);
}
last_dual_branch->branches[last_dual_branch_branch] = NULL;
@@ -220,6 +226,26 @@ check_branch_existence:
return SUCCESS;
}
+void phpdbg_btree_clean_recursive(phpdbg_btree_branch *branch, zend_ulong depth, zend_bool persistent) {
+ phpdbg_btree_branch *start = branch;
+ while (depth--) {
+ zend_bool use_branch = branch + 1 == branch->branches[0];
+ if (branch->branches[use_branch]) {
+ phpdbg_btree_clean_recursive(branch->branches[use_branch], depth, persistent);
+ }
+ }
+
+ pefree(start, persistent);
+}
+
+void phpdbg_btree_clean(phpdbg_btree *tree) {
+ if (tree->branch) {
+ phpdbg_btree_clean_recursive(tree->branch, tree->depth, tree->persistent);
+ tree->branch = NULL;
+ tree->count = 0;
+ }
+}
+
void phpdbg_btree_branch_dump(phpdbg_btree_branch *branch, zend_ulong depth) {
if (branch) {
if (depth--) {
diff --git a/sapi/phpdbg/phpdbg_btree.h b/sapi/phpdbg/phpdbg_btree.h
index 08b645ede4..3eae81b997 100644
--- a/sapi/phpdbg/phpdbg_btree.h
+++ b/sapi/phpdbg/phpdbg_btree.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -37,6 +37,7 @@ union _phpdbg_btree_branch {
typedef struct {
zend_ulong count;
zend_ulong depth;
+ zend_bool persistent;
phpdbg_btree_branch *branch;
} phpdbg_btree;
@@ -47,6 +48,7 @@ typedef struct {
} phpdbg_btree_position;
void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth);
+void phpdbg_btree_clean(phpdbg_btree *tree);
phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx);
phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong idx);
phpdbg_btree_position phpdbg_btree_find_between(phpdbg_btree *tree, zend_ulong lower_idx, zend_ulong higher_idx);
diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c
index 04da78098b..f89e58a13c 100644
--- a/sapi/phpdbg/phpdbg_cmd.c
+++ b/sapi/phpdbg/phpdbg_cmd.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,7 +25,7 @@
#include "phpdbg_prompt.h"
#include "phpdbg_io.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
static inline const char *phpdbg_command_name(const phpdbg_command_t *command, char *buffer) {
size_t pos = 0;
@@ -95,35 +95,35 @@ PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **point
{
switch (param->type) {
case STR_PARAM:
- asprintf(pointer, "%s", param->str);
+ ZEND_IGNORE_VALUE(asprintf(pointer, "%s", param->str));
break;
case ADDR_PARAM:
- asprintf(pointer, ZEND_ULONG_FMT, param->addr);
+ ZEND_IGNORE_VALUE(asprintf(pointer, ZEND_ULONG_FMT, param->addr));
break;
case NUMERIC_PARAM:
- asprintf(pointer, "%li", param->num);
+ ZEND_IGNORE_VALUE(asprintf(pointer, "%li", param->num));
break;
case METHOD_PARAM:
- asprintf(pointer, "%s::%s", param->method.class, param->method.name);
+ ZEND_IGNORE_VALUE(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);
+ ZEND_IGNORE_VALUE(asprintf(pointer, "%s:%lu#%lu", param->file.name, param->file.line, param->num));
} else {
- asprintf(pointer, "%s:%lu", param->file.name, param->file.line);
+ ZEND_IGNORE_VALUE(asprintf(pointer, "%s:%lu", param->file.name, param->file.line));
}
break;
case NUMERIC_FUNCTION_PARAM:
- asprintf(pointer, "%s#%lu", param->str, param->num);
+ ZEND_IGNORE_VALUE(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);
+ ZEND_IGNORE_VALUE(asprintf(pointer, "%s::%s#%lu", param->method.class, param->method.name, param->num));
break;
default:
@@ -325,7 +325,7 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)
if (param && param->type) {
switch (param->type) {
case STR_PARAM:
- fprintf(stderr, "%s STR_PARAM(%s=%lu)\n", msg, param->str, param->len);
+ fprintf(stderr, "%s STR_PARAM(%s=%zu)\n", msg, param->str, param->len);
break;
case ADDR_PARAM:
@@ -357,11 +357,11 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)
break;
case COND_PARAM:
- fprintf(stderr, "%s COND_PARAM(%s=%lu)\n", msg, param->str, param->len);
+ fprintf(stderr, "%s COND_PARAM(%s=%zu)\n", msg, param->str, param->len);
break;
case OP_PARAM:
- fprintf(stderr, "%s OP_PARAM(%s=%lu)\n", msg, param->str, param->len);
+ fprintf(stderr, "%s OP_PARAM(%s=%zu)\n", msg, param->str, param->len);
break;
default: {
@@ -385,23 +385,31 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) {
switch (remove->type) {
case NUMERIC_METHOD_PARAM:
case METHOD_PARAM:
- if (remove->method.class)
- free(remove->method.class);
- if (remove->method.name)
- free(remove->method.name);
+ if (remove->method.class) {
+ efree(remove->method.class);
+ }
+ if (remove->method.name) {
+ efree(remove->method.name);
+ }
break;
case NUMERIC_FUNCTION_PARAM:
case STR_PARAM:
case OP_PARAM:
- if (remove->str)
- free(remove->str);
+ case EVAL_PARAM:
+ case SHELL_PARAM:
+ case COND_PARAM:
+ case RUN_PARAM:
+ if (remove->str) {
+ efree(remove->str);
+ }
break;
case NUMERIC_FILE_PARAM:
case FILE_PARAM:
- if (remove->file.name)
- free(remove->file.name);
+ if (remove->file.name) {
+ efree(remove->file.name);
+ }
break;
default: {
@@ -426,8 +434,9 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) {
PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param) {
phpdbg_param_t *next = calloc(1, sizeof(phpdbg_param_t));
- if (!next)
+ if (!next) {
return;
+ }
*(next) = *(param);
@@ -446,6 +455,16 @@ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param)
stack->len++;
} /* }}} */
+/* {{{ */
+PHPDBG_API void phpdbg_stack_separate(phpdbg_param_t *param) {
+ phpdbg_param_t *stack = calloc(1, sizeof(phpdbg_param_t));
+
+ stack->type = STACK_PARAM;
+ stack->next = param->next;
+ param->next = stack;
+ stack->top = param->top;
+} /* }}} */
+
PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack) {
if (command) {
char buffer[128] = {0,};
@@ -458,7 +477,7 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
/* check for arg spec */
if (!(arg) || !(*arg)) {
- if (!top) {
+ if (!top || top->type == STACK_PARAM) {
return SUCCESS;
}
@@ -498,6 +517,10 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
}
while (arg && *arg) {
+ if (top && top->type == STACK_PARAM) {
+ break;
+ }
+
current++;
switch (*arg) {
@@ -520,9 +543,11 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
case '*': { /* do nothing */ } break;
}
- if (top ) {
+ if (top) {
top = top->next;
- } else break;
+ } else {
+ break;
+ }
received++;
arg++;
@@ -636,22 +661,9 @@ PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *
return NULL;
} /* }}} */
-/* {{{ */
-PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe) {
- phpdbg_param_t *top = NULL;
+static int phpdbg_internal_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe) {
const phpdbg_command_t *handler = NULL;
-
- if (stack->type != STACK_PARAM) {
- phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !");
- return FAILURE;
- }
-
- if (!stack->len) {
- phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !");
- return FAILURE;
- }
-
- top = (phpdbg_param_t *) stack->next;
+ phpdbg_param_t *top = (phpdbg_param_t *) stack->next;
switch (top->type) {
case EVAL_PARAM:
@@ -701,6 +713,32 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async
return SUCCESS;
} /* }}} */
+/* {{{ */
+PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe) {
+ phpdbg_param_t *top = stack;
+
+ if (stack->type != STACK_PARAM) {
+ phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !");
+ return FAILURE;
+ }
+
+ if (!stack->len) {
+ phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !");
+ return FAILURE;
+ }
+
+ do {
+ if (top->type == STACK_PARAM) {
+ int result;
+ if ((result = phpdbg_internal_stack_execute(top, allow_async_unsafe)) != SUCCESS) {
+ return result;
+ }
+ }
+ } while ((top = top->next));
+
+ return SUCCESS;
+} /* }}} */
+
PHPDBG_API char *phpdbg_read_input(char *buffered) /* {{{ */
{
char buf[PHPDBG_MAX_CMD];
@@ -716,8 +754,7 @@ PHPDBG_API char *phpdbg_read_input(char *buffered) /* {{{ */
#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT))
/* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */
#if USE_LIB_STAR
-readline:
- if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE)
+ if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) || !isatty(PHPDBG_G(io)[PHPDBG_STDIN].fd))
#endif
{
phpdbg_write("prompt", "", "%s", phpdbg_get_prompt());
@@ -727,9 +764,7 @@ readline:
else {
cmd = readline(phpdbg_get_prompt());
PHPDBG_G(last_was_newline) = 1;
- }
- if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
if (!cmd) {
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED;
zend_bailout();
@@ -745,7 +780,7 @@ readline:
buffer = estrdup(cmd);
#if USE_LIB_STAR
- if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
+ if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && isatty(PHPDBG_G(io)[PHPDBG_STDIN].fd)) {
free(cmd);
}
#endif
@@ -763,13 +798,14 @@ readline:
if (buffer && strlen(buffer)) {
if (PHPDBG_G(buffer)) {
- efree(PHPDBG_G(buffer));
+ free(PHPDBG_G(buffer));
}
- PHPDBG_G(buffer) = estrdup(buffer);
- } else {
- if (PHPDBG_G(buffer)) {
- buffer = estrdup(PHPDBG_G(buffer));
+ PHPDBG_G(buffer) = strdup(buffer);
+ } else if (PHPDBG_G(buffer)) {
+ if (buffer) {
+ efree(buffer);
}
+ buffer = estrdup(PHPDBG_G(buffer));
}
return buffer;
diff --git a/sapi/phpdbg/phpdbg_cmd.h b/sapi/phpdbg/phpdbg_cmd.h
index 957297600b..1ecfd62705 100644
--- a/sapi/phpdbg/phpdbg_cmd.h
+++ b/sapi/phpdbg/phpdbg_cmd.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -22,6 +22,7 @@
#define PHPDBG_CMD_H
#include "TSRM.h"
+#include "zend_generators.h"
/* {{{ Command and Parameter */
enum {
@@ -113,6 +114,7 @@ struct _phpdbg_command_t {
typedef struct {
int num;
+ zend_generator *generator;
zend_execute_data *execute_data;
} phpdbg_frame_t;
/* }}} */
@@ -137,6 +139,7 @@ PHPDBG_API int phpdbg_ask_user_permission(const char *question);
* Stack Management
*/
PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param);
+PHPDBG_API void phpdbg_stack_separate(phpdbg_param_t *param);
PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top);
PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack);
PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe);
diff --git a/sapi/phpdbg/phpdbg_eol.c b/sapi/phpdbg/phpdbg_eol.c
index 4cc6ef1679..eaf9997fb4 100644
--- a/sapi/phpdbg/phpdbg_eol.c
+++ b/sapi/phpdbg/phpdbg_eol.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -23,7 +23,7 @@
#include "phpdbg.h"
#include "phpdbg_eol.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define EOL_LIST_LEN 4
struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = {
diff --git a/sapi/phpdbg/phpdbg_eol.h b/sapi/phpdbg/phpdbg_eol.h
index e8dd27c971..29fd74f888 100644
--- a/sapi/phpdbg/phpdbg_eol.h
+++ b/sapi/phpdbg/phpdbg_eol.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c
index 189b3b20fa..85f3341e17 100644
--- a/sapi/phpdbg/phpdbg_frame.c
+++ b/sapi/phpdbg/phpdbg_frame.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -23,8 +23,81 @@
#include "phpdbg_utils.h"
#include "phpdbg_frame.h"
#include "phpdbg_list.h"
+#include "zend_smart_str.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
+
+static inline void phpdbg_append_individual_arg(smart_str *s, uint32_t i, zend_function *func, zval *arg) {
+ const zend_arg_info *arginfo = func->common.arg_info;
+ char *arg_name = NULL;
+
+ if (i) {
+ smart_str_appends(s, ", ");
+ }
+ if (i < func->common.num_args) {
+ if (arginfo) {
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
+ arg_name = (char *) ((zend_internal_arg_info *) &arginfo[i])->name;
+ } else {
+ arg_name = ZSTR_VAL(arginfo[i].name);
+ }
+ }
+ smart_str_appends(s, arg_name ? arg_name : "?");
+ smart_str_appendc(s, '=');
+ }
+ {
+ char *arg_print = phpdbg_short_zval_print(arg, 40);
+ smart_str_appends(s, arg_print);
+ efree(arg_print);
+ }
+}
+
+zend_string *phpdbg_compile_stackframe(zend_execute_data *ex) {
+ smart_str s = {0};
+ zend_op_array *op_array = &ex->func->op_array;
+ uint32_t i = 0, first_extra_arg = op_array->num_args, num_args = ZEND_CALL_NUM_ARGS(ex);
+ zval *p = ZEND_CALL_ARG(ex, 1);
+
+ if (op_array->scope) {
+ smart_str_append(&s, op_array->scope->name);
+ smart_str_appends(&s, "::");
+ }
+ smart_str_append(&s, op_array->function_name);
+ smart_str_appendc(&s, '(');
+ if (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg) {
+ while (i < first_extra_arg) {
+ phpdbg_append_individual_arg(&s, i, ex->func, p);
+ p++;
+ i++;
+ }
+ p = ZEND_CALL_VAR_NUM(ex, op_array->last_var + op_array->T);
+ }
+ while (i < num_args) {
+ phpdbg_append_individual_arg(&s, i, ex->func, p);
+ p++;
+ i++;
+ }
+ smart_str_appendc(&s, ')');
+
+ if (ex->func->type == ZEND_USER_FUNCTION) {
+ smart_str_appends(&s, " at ");
+ smart_str_append(&s, op_array->filename);
+ smart_str_appendc(&s, ':');
+ smart_str_append_unsigned(&s, ex->opline->lineno);
+ } else {
+ smart_str_appends(&s, " [internal function]");
+ }
+
+ return s.s;
+}
+
+void phpdbg_print_cur_frame_info() {
+ const char *file_chr = zend_get_executed_filename();
+ zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
+
+ phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
+ efree(file);
+}
void phpdbg_restore_frame(void) /* {{{ */
{
@@ -32,17 +105,22 @@ void phpdbg_restore_frame(void) /* {{{ */
return;
}
+ if (PHPDBG_FRAME(generator)) {
+ if (PHPDBG_FRAME(generator)->execute_data->call) {
+ PHPDBG_FRAME(generator)->frozen_call_stack = zend_generator_freeze_call_stack(PHPDBG_FRAME(generator)->execute_data);
+ }
+ PHPDBG_FRAME(generator) = NULL;
+ }
+
PHPDBG_FRAME(num) = 0;
/* move things back */
EG(current_execute_data) = PHPDBG_FRAME(execute_data);
-
- EG(scope) = PHPDBG_EX(func)->op_array.scope;
} /* }}} */
void phpdbg_switch_frame(int frame) /* {{{ */
{
- zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data);
+ zend_execute_data *execute_data = PHPDBG_FRAME(num) ? PHPDBG_FRAME(execute_data) : EG(current_execute_data);
int i = 0;
if (PHPDBG_FRAME(num) == frame) {
@@ -78,18 +156,17 @@ void phpdbg_switch_frame(int frame) /* {{{ */
/* backup things and jump back */
PHPDBG_FRAME(execute_data) = EG(current_execute_data);
EG(current_execute_data) = execute_data;
-
- EG(scope) = PHPDBG_EX(func)->op_array.scope;
}
- phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame);
+ phpdbg_try_access {
+ zend_string *s = phpdbg_compile_stackframe(EG(current_execute_data));
+ phpdbg_notice("frame", "id=\"%d\" frameinfo=\"%.*s\"", "Switched to frame #%d: %.*s", frame, (int) ZSTR_LEN(s), ZSTR_VAL(s));
+ zend_string_release(s);
+ } phpdbg_catch_access {
+ phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame);
+ } phpdbg_end_try_access();
- {
- const char *file_chr = zend_get_executed_filename();
- zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
- phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
- efree(file);
- }
+ phpdbg_print_cur_frame_info();
} /* }}} */
static void phpdbg_dump_prototype(zval *tmp) /* {{{ */
@@ -164,7 +241,11 @@ static void phpdbg_dump_prototype(zval *tmp) /* {{{ */
}
++j;
- php_printf("%s", phpdbg_short_zval_print(argstmp, 40));
+ {
+ char *arg_print = phpdbg_short_zval_print(argstmp, 40);
+ php_printf("%s", arg_print);
+ efree(arg_print);
+ }
phpdbg_xml("</arg>");
} ZEND_HASH_FOREACH_END();
@@ -214,7 +295,7 @@ void phpdbg_dump_backtrace(size_t num) /* {{{ */
while ((tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) {
if (file) { /* userland */
phpdbg_out("frame #%d: ", i);
- phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"%d\"", i, Z_STRVAL_P(file), Z_LVAL_P(line));
+ phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"", i, Z_STRVAL_P(file), Z_LVAL_P(line));
phpdbg_dump_prototype(tmp);
phpdbg_out(" at %s:%ld\n", Z_STRVAL_P(file), Z_LVAL_P(line));
i++;
@@ -238,3 +319,27 @@ void phpdbg_dump_backtrace(size_t num) /* {{{ */
PHPDBG_OUTPUT_BACKUP_RESTORE();
} /* }}} */
+
+void phpdbg_open_generator_frame(zend_generator *gen) {
+ zend_string *s;
+
+ if (EG(current_execute_data) == gen->execute_data) {
+ return;
+ }
+
+ phpdbg_restore_frame();
+
+ PHPDBG_FRAME(num) = -1;
+ PHPDBG_FRAME(generator) = gen;
+
+ EG(current_execute_data) = gen->execute_data;
+ if (gen->frozen_call_stack) {
+ zend_generator_restore_call_stack(gen);
+ }
+ gen->execute_data->prev_execute_data = NULL;
+
+ s = phpdbg_compile_stackframe(EG(current_execute_data));
+ phpdbg_notice("frame", "handle=\"%d\" frameinfo=\"%.*s\"", "Switched to generator with handle #%d: %.*s", gen->std.handle, (int) ZSTR_LEN(s), ZSTR_VAL(s));
+ zend_string_release(s);
+ phpdbg_print_cur_frame_info();
+}
diff --git a/sapi/phpdbg/phpdbg_frame.h b/sapi/phpdbg/phpdbg_frame.h
index 04d636ba4e..d0baf4b2e0 100644
--- a/sapi/phpdbg/phpdbg_frame.h
+++ b/sapi/phpdbg/phpdbg_frame.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -23,8 +23,10 @@
#include "TSRM.h"
+zend_string *phpdbg_compile_stackframe(zend_execute_data *);
void phpdbg_restore_frame(void);
void phpdbg_switch_frame(int);
void phpdbg_dump_backtrace(size_t);
+void phpdbg_open_generator_frame(zend_generator *);
#endif /* PHPDBG_FRAME_H */
diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c
index c2744b9b68..eb62d76d2e 100644
--- a/sapi/phpdbg/phpdbg_help.c
+++ b/sapi/phpdbg/phpdbg_help.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,7 +25,7 @@
#include "phpdbg_eol.h"
#include "zend.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
/* {{{ Commands Table */
#define PHPDBG_COMMAND_HELP_D(name, tip, alias, action) \
@@ -209,6 +209,26 @@ static int get_command(
} /* }}} */
+void phpdbg_do_help_cmd(char *type) { /* {{{ */
+ char *help;
+
+ if (!type) {
+ pretty_print(get_help("overview!"));
+ return;
+ }
+
+ help = get_help(type);
+
+ if (!help || memcmp(help, "", sizeof("")) == SUCCESS) {
+ pretty_print(get_help("overview!"));
+ pretty_print(
+ "\nrequested help page could not be found");
+ return;
+ }
+
+ pretty_print(help);
+} /* }}} */
+
PHPDBG_COMMAND(help) /* {{{ */
{
phpdbg_command_t const *cmd;
@@ -329,34 +349,36 @@ phpdbg_help_text_t phpdbg_help_text[] = {
"It supports the following commands:" CR CR
"**Information**" CR
-" **list** list PHP source" CR
-" **info** displays information on the debug session" CR
-" **print** show opcodes" CR
-" **frame** select a stack frame and print a stack frame summary" CR
-" **back** shows the current backtrace" CR
-" **help** provide help on a topic" CR CR
+" **list** list PHP source" CR
+" **info** displays information on the debug session" CR
+" **print** show opcodes" CR
+" **frame** select a stack frame and print a stack frame summary" CR
+" **generator** show active generators or select a generator frame" CR
+" **back** shows the current backtrace" CR
+" **help** provide help on a topic" CR CR
"**Starting and Stopping Execution**" CR
-" **exec** set execution context" CR
-" **run** attempt execution" CR
-" **step** continue execution until other line is reached" CR
-" **continue** continue execution" CR
-" **until** continue execution up to the given location" CR
-" **next** continue execution up to the given location and halt on the first line after it" CR
-" **finish** continue up to end of the current execution frame" CR
-" **leave** continue up to end of the current execution frame and halt after the calling instruction" CR
-" **break** set a breakpoint at the specified target" CR
-" **watch** set a watchpoint on $variable" CR
-" **clear** clear one or all breakpoints" CR
-" **clean** clean the execution environment" CR CR
+" **exec** set execution context" CR
+" **stdin** set executing script from stdin" CR
+" **run** attempt execution" CR
+" **step** continue execution until other line is reached" CR
+" **continue** continue execution" CR
+" **until** continue execution up to the given location" CR
+" **next** continue execution up to the given location and halt on the first line after it" CR
+" **finish** continue up to end of the current execution frame" CR
+" **leave** continue up to end of the current execution frame and halt after the calling instruction" CR
+" **break** set a breakpoint at the specified target" CR
+" **watch** set a watchpoint on $variable" CR
+" **clear** clear one or all breakpoints" CR
+" **clean** clean the execution environment" CR CR
"**Miscellaneous**" CR
-" **set** set the phpdbg configuration" CR
-" **source** execute a phpdbginit script" CR
-" **register** register a phpdbginit function as a command alias" CR
-" **sh** shell a command" CR
-" **ev** evaluate some code" CR
-" **quit** exit phpdbg" CR CR
+" **set** set the phpdbg configuration" CR
+" **source** execute a phpdbginit script" CR
+" **register** register a phpdbginit function as a command alias" CR
+" **sh** shell a command" CR
+" **ev** evaluate some code" CR
+" **quit** exit phpdbg" CR CR
"Type **help <command>** or (**help alias**) to get detailed help on any of the above commands, "
"for example **help list** or **h l**. Note that help will also match partial commands if unique "
@@ -383,8 +405,10 @@ phpdbg_help_text_t phpdbg_help_text[] = {
" **-I** Ignore default .phpdbginit" CR
" **-O** **-O**my.oplog Sets oplog output file" CR
" **-r** Run execution context" CR
-" **-rr** Run execution context and quit after execution" CR
+" **-rr** Run execution context and quit after execution (not respecting breakpoints)" CR
+" **-e** Generate extended information for debugger/profiler" CR
" **-E** Enable step through eval, careful!" CR
+" **-s** **-s=**, **-s**=foo Read code to execute from stdin with an optional delimiter" CR
" **-S** **-S**cli Override SAPI name, careful!" CR
" **-l** **-l**4000 Setup remote console ports" CR
" **-a** **-a**192.168.0.3 Setup remote console bind address" CR
@@ -395,6 +419,13 @@ phpdbg_help_text_t phpdbg_help_text[] = {
" **--** **--** arg1 arg2 Use to delimit phpdbg arguments and php $argv; append any $argv "
"argument after it" CR CR
+"**Reading from stdin**" CR CR
+
+"The **-s** option allows inputting a script to execute directly from stdin. The given delimiter "
+"(\"foo\" in the example) needs to be specified at the end of the input on its own line, followed by "
+"a line break. If **-rr** has been specified, it is allowed to omit the delimiter (**-s=**) and "
+"it will read until EOF. See also the help entry for the **stdin** command." CR CR
+
"**Remote Console Mode**" CR CR
"This mode is enabled by specifying the **-a** option. Phpdbg will bind only to the loopback "
@@ -633,6 +664,21 @@ phpdbg_help_text_t phpdbg_help_text[] = {
" Set the execution context to **/tmp/script.php**"
},
+{"stdin",
+"The **stdin** command takes a string serving as delimiter. It will then read all the input from "
+"stdin until encountering the given delimiter on a standalone line. It can also be passed at "
+"startup using the **-s=** command line option (the delimiter then is optional if **-rr** is "
+"also passed - in that case it will just read until EOF)." CR
+"This input will be then compiled as PHP code and set as execution context." CR CR
+
+"**Example**" CR CR
+
+" $P stdin foo" CR
+" <?php" CR
+" echo \"Hello, world!\\n\";" CR
+" foo"
+},
+
//*********** Does F skip any breakpoints lower stack frames or only the current??
{"finish",
"The **finish** command causes control to be passed back to the vm, continuing execution. Any "
@@ -647,8 +693,8 @@ phpdbg_help_text_t phpdbg_help_text[] = {
},
{"frame",
-"The **frame** takes an optional integer argument. If omitted, then the current frame is displayed "
-"If specified then the current scope is set to the corresponding frame listed in a **back** trace. "
+"The **frame** takes an optional integer argument. If omitted, then the current frame is displayed. "
+"If specified, then the current scope is set to the corresponding frame listed in a **back** trace. "
"This can be used to allowing access to the variables in a higher stack frame than that currently being executed." CR CR
"**Examples**" CR CR
@@ -657,7 +703,25 @@ phpdbg_help_text_t phpdbg_help_text[] = {
" Go to frame 2 and print out variable **$count** in that frame" CR CR
"Note that this frame scope is discarded when execution continues, with the execution frame "
-"then reset to the lowest executiong frame."
+"then reset to the lowest executing frame."
+},
+
+{"generator",
+"The **generator** command takes an optional integer argument. If omitted, then a list of the "
+"currently active generators is displayed. If specified then the current scope is set to the frame "
+"of the generator with the corresponding object handle. This can be used to inspect any generators "
+"not in the current **back** trace." CR CR
+
+"**Examples**" CR CR
+" $P generator" CR
+" List of generators, with the #id being the object handle, e.g.:" CR
+" #3: my_generator(argument=\"value\") at test.php:5" CR
+" $P g 3" CR
+" $P ev $i" CR
+" Go to frame of generator with object handle 3 and print out variable **$i** in that frame" CR CR
+
+"Note that this frame scope is discarded when execution continues, with the execution frame "
+"then reset to the lowest executing frame."
},
{"info",
@@ -808,20 +872,20 @@ phpdbg_help_text_t phpdbg_help_text[] = {
},
{"run",
-"Enter the vm, startinging execution. Execution will then continue until the next breakpoint "
-"or completion of the script. Add parameters you want to use as $argv"
+"Enter the vm, starting execution. Execution will then continue until the next breakpoint "
+"or completion of the script. Add parameters you want to use as $argv. Add a trailing "
+"**< filename** for reading STDIN from a file." CR CR
+
"**Examples**" CR CR
+
" $P run" CR
" $P r" CR
" Will cause execution of the context, if it is set" CR CR
-" $P r test" CR
-" Will execute with $argv[1] == \"test\"" CR CR
+" $P r test < foo.txt" CR
+" Will execute with $argv[1] == \"test\" and read from the foo.txt file for STDIN" CR CR
"Note that the execution context must be set. If not previously compiled, then the script will "
-"be compiled before execution." CR CR
-
-"Note that attempting to run a script that is already executing will result in an \"execution "
-"in progress\" error."
+"be compiled before execution."
},
{"set",
diff --git a/sapi/phpdbg/phpdbg_help.h b/sapi/phpdbg/phpdbg_help.h
index a2db10880e..d44eca15ee 100644
--- a/sapi/phpdbg/phpdbg_help.h
+++ b/sapi/phpdbg/phpdbg_help.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -45,4 +45,6 @@ typedef struct _phpdbg_help_text_t {
} phpdbg_help_text_t;
extern phpdbg_help_text_t phpdbg_help_text[];
+
+extern void phpdbg_do_help_cmd(char *type);
#endif /* PHPDBG_HELP_H */
diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c
index 1f78ac9173..ddd8229c08 100644
--- a/sapi/phpdbg/phpdbg_info.c
+++ b/sapi/phpdbg/phpdbg_info.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,7 +25,7 @@
#include "phpdbg_bp.h"
#include "phpdbg_prompt.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s, flags) \
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13], flags)
@@ -72,7 +72,7 @@ PHPDBG_INFO(files) /* {{{ */
phpdbg_try_access {
ZEND_HASH_FOREACH_STR_KEY(&EG(included_files), fname) {
- phpdbg_writeln("includedfile", "name=\"%s\"", "File: %s", fname);
+ phpdbg_writeln("includedfile", "name=\"%s\"", "File: %s", ZSTR_VAL(fname));
} ZEND_HASH_FOREACH_END();
} phpdbg_catch_access {
phpdbg_error("signalsegv", "", "Could not fetch file name, invalid data source, aborting included file listing");
@@ -120,12 +120,18 @@ PHPDBG_INFO(constants) /* {{{ */
phpdbg_out("Address Refs Type Constant\n");
ZEND_HASH_FOREACH_PTR(&consts, data) {
-#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("constant", "address=\"%p\" refcount=\"%d\" type=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %.*s" msg, &data->value, Z_REFCOUNTED(data->value) ? Z_REFCOUNT(data->value) : 1, zend_zval_type_name(&data->value), ZSTR_LEN(data->name), ZSTR_VAL(data->name), ##__VA_ARGS__)
+#define VARIABLEINFO(attrs, msg, ...) \
+ phpdbg_writeln("constant", \
+ "address=\"%p\" refcount=\"%d\" type=\"%s\" name=\"%.*s\" " attrs, \
+ "%-18p %-7d %-9s %.*s" msg, &data->value, \
+ Z_REFCOUNTED(data->value) ? Z_REFCOUNT(data->value) : 1, \
+ zend_zval_type_name(&data->value), \
+ (int) ZSTR_LEN(data->name), ZSTR_VAL(data->name), ##__VA_ARGS__)
switch (Z_TYPE(data->value)) {
case IS_STRING:
phpdbg_try_access {
- VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN(data->value), Z_STRLEN(data->value) < 255 ? Z_STRLEN(data->value) : 255, Z_STRVAL(data->value), Z_STRLEN(data->value) > 255 ? "..." : "");
+ VARIABLEINFO("length=\"%zd\" value=\"%.*s\"", "\nstring (%zd) \"%.*s%s\"", Z_STRLEN(data->value), Z_STRLEN(data->value) < 255 ? (int) Z_STRLEN(data->value) : 255, Z_STRVAL(data->value), Z_STRLEN(data->value) > 255 ? "..." : "");
} phpdbg_catch_access {
VARIABLEINFO("", "");
} phpdbg_end_try_access();
@@ -153,10 +159,12 @@ PHPDBG_INFO(constants) /* {{{ */
return SUCCESS;
} /* }}} */
-static int phpdbg_arm_auto_global(zend_auto_global *auto_global) {
+static int phpdbg_arm_auto_global(zval *ptrzv) {
+ zend_auto_global *auto_global = Z_PTR_P(ptrzv);
+
if (auto_global->armed) {
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
- phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", ZSTR_LEN(auto_global->name), ZSTR_VAL(auto_global->name));
+ phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", (int) ZSTR_LEN(auto_global->name), ZSTR_VAL(auto_global->name));
} else {
auto_global->armed = auto_global->auto_global_callback(auto_global->name);
}
@@ -204,9 +212,9 @@ static int phpdbg_print_symbols(zend_bool show_globals) {
if (ops->function_name) {
if (ops->scope) {
- phpdbg_notice("variableinfo", "method=\"%s::%s\" num=\"%d\"", "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars));
+ phpdbg_notice("variableinfo", "method=\"%s::%s\" num=\"%d\"", "Variables in %s::%s() (%d)", ops->scope->name->val, ops->function_name->val, zend_hash_num_elements(&vars));
} else {
- phpdbg_notice("variableinfo", "function=\"%s\" num=\"%d\"", "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars));
+ phpdbg_notice("variableinfo", "function=\"%s\" num=\"%d\"", "Variables in %s() (%d)", ZSTR_VAL(ops->function_name), zend_hash_num_elements(&vars));
}
} else {
if (ops->filename) {
@@ -221,8 +229,12 @@ static int phpdbg_print_symbols(zend_bool show_globals) {
phpdbg_out("Address Refs Type Variable\n");
ZEND_HASH_FOREACH_STR_KEY_VAL(&vars, var, data) {
phpdbg_try_access {
-#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("variable", "address=\"%p\" refcount=\"%d\" type=\"%s\" refstatus=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %s$%.*s" msg, data, Z_REFCOUNT_P(data), zend_zval_type_name(data), Z_ISREF_P(data) ? "&": "", ZSTR_LEN(var), ZSTR_VAL(var), ##__VA_ARGS__)
-
+ const char *isref = "";
+#define VARIABLEINFO(attrs, msg, ...) \
+ phpdbg_writeln("variable", \
+ "address=\"%p\" refcount=\"%d\" type=\"%s\" refstatus=\"%s\" name=\"%.*s\" " attrs, \
+ "%-18p %-7d %-9s %s$%.*s" msg, data, Z_REFCOUNTED_P(data) ? Z_REFCOUNT_P(data) : 1, zend_zval_type_name(data), isref, (int) ZSTR_LEN(var), ZSTR_VAL(var), ##__VA_ARGS__)
+retry_switch:
switch (Z_TYPE_P(data)) {
case IS_RESOURCE:
phpdbg_try_access {
@@ -234,14 +246,14 @@ static int phpdbg_print_symbols(zend_bool show_globals) {
break;
case IS_OBJECT:
phpdbg_try_access {
- VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (%s)\n", Z_OBJCE_P(data)->name);
+ VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (%s)\n", ZSTR_VAL(Z_OBJCE_P(data)->name));
} phpdbg_catch_access {
VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (unknown)\n");
} phpdbg_end_try_access();
break;
case IS_STRING:
phpdbg_try_access {
- VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN_P(data), Z_STRLEN_P(data) < 255 ? Z_STRLEN_P(data) : 255, Z_STRVAL_P(data), Z_STRLEN_P(data) > 255 ? "..." : "");
+ VARIABLEINFO("length=\"%zd\" value=\"%.*s\"", "\nstring (%zd) \"%.*s%s\"", Z_STRLEN_P(data), Z_STRLEN_P(data) < 255 ? (int) Z_STRLEN_P(data) : 255, Z_STRVAL_P(data), Z_STRLEN_P(data) > 255 ? "..." : "");
} phpdbg_catch_access {
VARIABLEINFO("", "");
} phpdbg_end_try_access();
@@ -258,13 +270,20 @@ static int phpdbg_print_symbols(zend_bool show_globals) {
case IS_DOUBLE:
VARIABLEINFO("value=\"%lf\"", "\ndouble (%lf)", Z_DVAL_P(data));
break;
+ case IS_REFERENCE:
+ isref = "&";
+ data = Z_REFVAL_P(data);
+ goto retry_switch;
+ case IS_INDIRECT:
+ data = Z_INDIRECT_P(data);
+ goto retry_switch;
default:
VARIABLEINFO("", "");
}
#undef VARIABLEINFO
} phpdbg_catch_access {
- phpdbg_writeln("variable", "address=\"%p\" name=\"%s\"", "%p\tn/a\tn/a\t$%s", data, var);
+ phpdbg_writeln("variable", "address=\"%p\" name=\"%s\"", "%p\tn/a\tn/a\t$%s", data, ZSTR_VAL(var));
} phpdbg_end_try_access();
} ZEND_HASH_FOREACH_END();
}
@@ -290,13 +309,13 @@ PHPDBG_INFO(literal) /* {{{ */
zend_bool in_executor = PHPDBG_G(in_execution) && EG(current_execute_data) && EG(current_execute_data)->func;
if (in_executor || PHPDBG_G(ops)) {
zend_op_array *ops = in_executor ? &EG(current_execute_data)->func->op_array : PHPDBG_G(ops);
- int literal = 0, count = ops->last_literal-1;
+ int literal = 0, count = ops->last_literal - 1;
if (ops->function_name) {
if (ops->scope) {
- phpdbg_notice("literalinfo", "method=\"%s::%s\" num=\"%d\"", "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count);
+ phpdbg_notice("literalinfo", "method=\"%s::%s\" num=\"%d\"", "Literal Constants in %s::%s() (%d)", ops->scope->name->val, ops->function_name->val, count);
} else {
- phpdbg_notice("literalinfo", "function=\"%s\" num=\"%d\"", "Literal Constants in %s() (%d)", ops->function_name, count);
+ phpdbg_notice("literalinfo", "function=\"%s\" num=\"%d\"", "Literal Constants in %s() (%d)", ops->function_name->val, count);
}
} else {
if (ops->filename) {
@@ -359,7 +378,7 @@ static inline void phpdbg_print_class_name(zend_class_entry *ce) /* {{{ */
const char *visibility = ce->type == ZEND_USER_CLASS ? "User" : "Internal";
const char *type = (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : (ce->ce_flags & ZEND_ACC_ABSTRACT) ? "Abstract Class" : "Class";
- phpdbg_writeln("class", "type=\"%s\" flags=\"%s\" name=\"%.*s\" methodcount=\"%d\"", "%s %s %.*s (%d)", visibility, type, ZSTR_LEN(ce->name), ZSTR_VAL(ce->name), zend_hash_num_elements(&ce->function_table));
+ phpdbg_writeln("class", "type=\"%s\" flags=\"%s\" name=\"%.*s\" methodcount=\"%d\"", "%s %s %.*s (%d)", visibility, type, (int) ZSTR_LEN(ce->name), ZSTR_VAL(ce->name), zend_hash_num_elements(&ce->function_table));
} /* }}} */
PHPDBG_INFO(classes) /* {{{ */
diff --git a/sapi/phpdbg/phpdbg_info.h b/sapi/phpdbg/phpdbg_info.h
index cc0d624755..3e7d585576 100644
--- a/sapi/phpdbg/phpdbg_info.h
+++ b/sapi/phpdbg/phpdbg_info.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_io.c b/sapi/phpdbg/phpdbg_io.c
index 246431ff2d..65a14d0ccb 100644
--- a/sapi/phpdbg/phpdbg_io.c
+++ b/sapi/phpdbg/phpdbg_io.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -45,7 +45,7 @@
#include <poll.h>
#endif
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
/* is easy to generalize ... but not needed for now */
PHPDBG_API int phpdbg_consume_stdin_line(char *buf) {
@@ -149,7 +149,7 @@ recv_once:
#endif
if (got_now == -1) {
- write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Read operation timed out!\n"));
+ zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Read operation timed out!\n"));
return -1;
}
i -= got_now;
@@ -190,16 +190,51 @@ PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo) {
return ret;
}
+static int phpdbg_output_pager(int sock, const char *ptr, int len) {
+ int count = 0, bytes = 0;
+ const char *p = ptr, *endp = ptr + len;
+
+ while ((p = memchr(p, '\n', endp - p))) {
+ count++;
+ p++;
+
+ if (count % PHPDBG_G(lines) == 0) {
+ bytes += write(sock, ptr + bytes, (p - ptr) - bytes);
+
+ if (memchr(p, '\n', endp - p)) {
+ char buf[PHPDBG_MAX_CMD];
+ zend_quiet_write(sock, ZEND_STRL("\r---Type <return> to continue or q <return> to quit---"));
+ phpdbg_consume_stdin_line(buf);
+ if (*buf == 'q') {
+ break;
+ }
+ write(sock, "\r", 1);
+ } else break;
+ }
+ }
+ if (bytes && count % PHPDBG_G(lines) != 0) {
+ bytes += write(sock, ptr + bytes, len - bytes);
+ } else if (!bytes) {
+ bytes += write(sock, ptr, len);
+ }
+ return bytes;
+}
PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len) {
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
return phpdbg_send_bytes(sock, ptr, len);
}
+
+ if ((PHPDBG_G(flags) & PHPDBG_HAS_PAGINATION)
+ && !(PHPDBG_G(flags) & PHPDBG_WRITE_XML)
+ && PHPDBG_G(io)[PHPDBG_STDOUT].fd == sock
+ && PHPDBG_G(lines) > 0) {
+ return phpdbg_output_pager(sock, ptr, len);
+ }
return write(sock, ptr, len);
}
-
PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port) {
struct addrinfo res;
int fd = phpdbg_create_listenable_socket(interface, port, &res);
@@ -270,7 +305,7 @@ PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short
wrote = snprintf(buf, 128, "Could not translate address '%s'", addr);
buf[wrote] = '\0';
- write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
+ zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
return sock;
} else {
@@ -280,7 +315,7 @@ PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short
wrote = snprintf(buf, 256, "Host '%s' not found. %s", addr, estrdup(gai_strerror(rc)));
buf[wrote] = '\0';
- write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
+ zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
return sock;
#ifndef PHP_WIN32
@@ -295,7 +330,7 @@ PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short
wrote = sprintf(buf, "Unable to create socket");
buf[wrote] = '\0';
- write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
+ zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
return sock;
}
diff --git a/sapi/phpdbg/phpdbg_io.h b/sapi/phpdbg/phpdbg_io.h
index 3e25fc5eeb..8bafc0c999 100644
--- a/sapi/phpdbg/phpdbg_io.h
+++ b/sapi/phpdbg/phpdbg_io.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -21,6 +21,11 @@
#include "phpdbg.h"
+/* Older versions of glibc <= 2.3.0 and <= OS X 10.5 do not have this constant defined */
+#ifndef AI_NUMERICSERV
+#define AI_NUMERICSERV 0
+#endif
+
PHPDBG_API int phpdbg_consume_stdin_line(char *buf);
PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo);
diff --git a/sapi/phpdbg/phpdbg_lexer.c b/sapi/phpdbg/phpdbg_lexer.c
index d1474dc252..74cad5b8f2 100644
--- a/sapi/phpdbg/phpdbg_lexer.c
+++ b/sapi/phpdbg/phpdbg_lexer.c
@@ -1,5 +1,5 @@
-/* Generated by re2c 0.13.5 */
-#line 1 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+/* Generated by re2c 0.14.3 */
+#line 1 "sapi/phpdbg/phpdbg_lexer.l"
/*
* phpdbg_lexer.l
*/
@@ -16,6 +16,7 @@
#define YYGETCONDITION() LEX(state)
#define YYCURSOR LEX(cursor)
#define YYMARKER LEX(marker)
+#define YYCTXMARKER LEX(ctxmarker)
#define yyleng LEX(len)
#define yytext ((char*) LEX(text))
#undef YYDEBUG
@@ -27,7 +28,7 @@
#define RAW 2
#define INITIAL 3
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
void phpdbg_init_lexer (phpdbg_param_t *stack, char *input) {
PHPDBG_G(parser_stack) = stack;
@@ -38,13 +39,32 @@ void phpdbg_init_lexer (phpdbg_param_t *stack, char *input) {
LEX(len) = strlen(input);
}
+static int unescape_string(char *s) {
+ switch (*s) {
+ case '\'':
+ case '\"': {
+ char start = *s;
+ size_t off = 1;
+ do {
+ if (s[off] == '\\') {
+ off++;
+ }
+ *s = s[off];
+ } while ((++s)[off] != start);
+ return off + 1;
+ }
+ }
+
+ return 0;
+}
+
int phpdbg_lex (phpdbg_param_t* yylval) {
restart:
LEX(text) = YYCURSOR;
-#line 49 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 68 "sapi/phpdbg/phpdbg_lexer.c"
{
YYCTYPE yych;
unsigned int yyaccept = 0;
@@ -65,1454 +85,2059 @@ restart:
yyc_INITIAL:
{
static const unsigned char yybm[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 192, 96, 0, 0, 192, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 192, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 128, 0, 0, 0, 128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
-
- YYDEBUG(0, *YYCURSOR);
+ YYDEBUG(1, *YYCURSOR);
YYFILL(4);
yych = *YYCURSOR;
- if (yybm[0+yych] & 32) {
- goto yy4;
- }
- if (yych <= 'E') {
+ if (yych <= '#') {
if (yych <= '\f') {
- if (yych <= 0x00) goto yy7;
- if (yych != '\t') goto yy12;
+ if (yych <= 0x08) {
+ if (yych <= 0x00) goto yy9;
+ goto yy14;
+ } else {
+ if (yych <= '\t') goto yy3;
+ if (yych <= '\n') goto yy9;
+ goto yy14;
+ }
} else {
if (yych <= 0x1F) {
- if (yych >= 0x0E) goto yy12;
+ if (yych >= 0x0E) goto yy14;
} else {
- if (yych <= ' ') goto yy2;
- if (yych <= 'D') goto yy12;
+ if (yych <= ' ') goto yy5;
+ if (yych <= '"') goto yy14;
goto yy8;
}
}
} else {
- if (yych <= 'd') {
- if (yych <= 'Q') goto yy12;
- if (yych <= 'R') goto yy11;
- if (yych <= 'S') goto yy9;
- goto yy12;
+ if (yych <= 'S') {
+ if (yych <= 'E') {
+ if (yych <= 'D') goto yy14;
+ goto yy10;
+ } else {
+ if (yych <= 'Q') goto yy14;
+ if (yych <= 'R') goto yy13;
+ goto yy11;
+ }
} else {
if (yych <= 'q') {
- if (yych <= 'e') goto yy8;
- goto yy12;
+ if (yych == 'e') goto yy10;
+ goto yy14;
} else {
- if (yych <= 'r') goto yy10;
- if (yych <= 's') goto yy9;
- goto yy12;
+ if (yych <= 'r') goto yy12;
+ if (yych <= 's') goto yy11;
+ goto yy14;
}
}
}
-yy2:
- YYDEBUG(2, *YYCURSOR);
- ++YYCURSOR;
- if ((yych = *YYCURSOR) <= '\f') {
- if (yych <= 0x00) goto yy29;
- if (yych <= 0x08) goto yy3;
- if (yych <= '\n') goto yy29;
- } else {
- if (yych <= '\r') goto yy29;
- if (yych == ' ') goto yy29;
- }
yy3:
YYDEBUG(3, *YYCURSOR);
+ ++YYCURSOR;
+ if (yybm[0+(yych = *YYCURSOR)] & 128) {
+ goto yy5;
+ }
+yy4:
+ YYDEBUG(4, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 176 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 206 "sapi/phpdbg/phpdbg_lexer.l"
{
YYSETCONDITION(NORMAL);
YYCURSOR = LEX(text);
goto restart;
}
-#line 161 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy4:
- YYDEBUG(4, *YYCURSOR);
+#line 181 "sapi/phpdbg/phpdbg_lexer.c"
+yy5:
+ YYDEBUG(5, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(5, *YYCURSOR);
+ YYDEBUG(6, *YYCURSOR);
if (yybm[0+yych] & 128) {
- goto yy28;
+ goto yy5;
}
- if (yych <= 0x00) goto yy27;
- if (yych == '\n') goto yy4;
-yy6:
- YYDEBUG(6, *YYCURSOR);
+ YYDEBUG(7, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 175 "sapi/phpdbg/phpdbg_lexer.l"
{
- return 0;
+ /* ignore whitespace */
+
+ goto restart;
}
-#line 180 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy7:
- YYDEBUG(7, *YYCURSOR);
- yych = *++YYCURSOR;
- goto yy3;
+#line 199 "sapi/phpdbg/phpdbg_lexer.c"
yy8:
YYDEBUG(8, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'V') goto yy23;
- if (yych == 'v') goto yy23;
- goto yy3;
+ yych = *++YYCURSOR;
+ goto yy4;
yy9:
YYDEBUG(9, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'H') goto yy19;
- if (yych == 'h') goto yy19;
- goto yy3;
+ yych = *++YYCURSOR;
+ goto yy4;
yy10:
YYDEBUG(10, *YYCURSOR);
yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
- if (yybm[0+yych] & 64) {
- goto yy16;
- }
- if (yych == 'U') goto yy13;
- if (yych == 'u') goto yy13;
- goto yy3;
+ if (yych == 'V') goto yy25;
+ if (yych == 'v') goto yy25;
+ goto yy4;
yy11:
YYDEBUG(11, *YYCURSOR);
yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'U') goto yy13;
- if (yych == 'u') goto yy13;
- goto yy3;
+ if (yych == 'H') goto yy21;
+ if (yych == 'h') goto yy21;
+ goto yy4;
yy12:
YYDEBUG(12, *YYCURSOR);
- yych = *++YYCURSOR;
- goto yy3;
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= 0x1F) {
+ if (yych <= '\t') {
+ if (yych <= 0x08) goto yy4;
+ goto yy18;
+ } else {
+ if (yych == '\r') goto yy18;
+ goto yy4;
+ }
+ } else {
+ if (yych <= 'U') {
+ if (yych <= ' ') goto yy18;
+ if (yych <= 'T') goto yy4;
+ goto yy15;
+ } else {
+ if (yych == 'u') goto yy15;
+ goto yy4;
+ }
+ }
yy13:
YYDEBUG(13, *YYCURSOR);
- yych = *++YYCURSOR;
- if (yych == 'N') goto yy15;
- if (yych == 'n') goto yy15;
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych == 'U') goto yy15;
+ if (yych == 'u') goto yy15;
+ goto yy4;
yy14:
YYDEBUG(14, *YYCURSOR);
- YYCURSOR = YYMARKER;
- goto yy3;
+ yych = *++YYCURSOR;
+ goto yy4;
yy15:
YYDEBUG(15, *YYCURSOR);
yych = *++YYCURSOR;
- if (yybm[0+yych] & 64) {
- goto yy16;
- }
- goto yy14;
+ if (yych == 'N') goto yy17;
+ if (yych == 'n') goto yy17;
yy16:
YYDEBUG(16, *YYCURSOR);
+ YYCURSOR = YYMARKER;
+ goto yy4;
+yy17:
+ YYDEBUG(17, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '\f') {
+ if (yych != '\t') goto yy16;
+ } else {
+ if (yych <= '\r') goto yy18;
+ if (yych != ' ') goto yy16;
+ }
+yy18:
+ YYDEBUG(18, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(17, *YYCURSOR);
- if (yybm[0+yych] & 64) {
- goto yy16;
+ YYDEBUG(19, *YYCURSOR);
+ if (yych <= '\f') {
+ if (yych == '\t') goto yy18;
+ } else {
+ if (yych <= '\r') goto yy18;
+ if (yych == ' ') goto yy18;
}
- YYDEBUG(18, *YYCURSOR);
+ YYDEBUG(20, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 163 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 193 "sapi/phpdbg/phpdbg_lexer.l"
{
YYSETCONDITION(PRE_RAW);
phpdbg_init_param(yylval, EMPTY_PARAM);
return T_RUN;
}
-#line 253 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy19:
- YYDEBUG(19, *YYCURSOR);
+#line 293 "sapi/phpdbg/phpdbg_lexer.c"
+yy21:
+ YYDEBUG(21, *YYCURSOR);
yych = *++YYCURSOR;
if (yych <= '\f') {
- if (yych <= 0x08) goto yy14;
- if (yych >= '\v') goto yy14;
+ if (yych != '\t') goto yy16;
} else {
- if (yych <= '\r') goto yy20;
- if (yych != ' ') goto yy14;
+ if (yych <= '\r') goto yy22;
+ if (yych != ' ') goto yy16;
}
-yy20:
- YYDEBUG(20, *YYCURSOR);
+yy22:
+ YYDEBUG(22, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(21, *YYCURSOR);
+ YYDEBUG(23, *YYCURSOR);
if (yych <= '\f') {
- if (yych <= 0x08) goto yy22;
- if (yych <= '\n') goto yy20;
+ if (yych == '\t') goto yy22;
} else {
- if (yych <= '\r') goto yy20;
- if (yych == ' ') goto yy20;
+ if (yych <= '\r') goto yy22;
+ if (yych == ' ') goto yy22;
}
-yy22:
- YYDEBUG(22, *YYCURSOR);
+ YYDEBUG(24, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 158 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 187 "sapi/phpdbg/phpdbg_lexer.l"
{
YYSETCONDITION(PRE_RAW);
phpdbg_init_param(yylval, EMPTY_PARAM);
return T_SHELL;
}
-#line 286 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy23:
- YYDEBUG(23, *YYCURSOR);
+#line 323 "sapi/phpdbg/phpdbg_lexer.c"
+yy25:
+ YYDEBUG(25, *YYCURSOR);
yych = *++YYCURSOR;
if (yych <= '\f') {
- if (yych <= 0x08) goto yy14;
- if (yych >= '\v') goto yy14;
+ if (yych != '\t') goto yy16;
} else {
- if (yych <= '\r') goto yy24;
- if (yych != ' ') goto yy14;
+ if (yych <= '\r') goto yy26;
+ if (yych != ' ') goto yy16;
}
-yy24:
- YYDEBUG(24, *YYCURSOR);
+yy26:
+ YYDEBUG(26, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(25, *YYCURSOR);
+ YYDEBUG(27, *YYCURSOR);
if (yych <= '\f') {
- if (yych <= 0x08) goto yy26;
- if (yych <= '\n') goto yy24;
+ if (yych == '\t') goto yy26;
} else {
- if (yych <= '\r') goto yy24;
- if (yych == ' ') goto yy24;
+ if (yych <= '\r') goto yy26;
+ if (yych == ' ') goto yy26;
}
-yy26:
- YYDEBUG(26, *YYCURSOR);
+ YYDEBUG(28, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 153 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 181 "sapi/phpdbg/phpdbg_lexer.l"
{
YYSETCONDITION(PRE_RAW);
phpdbg_init_param(yylval, EMPTY_PARAM);
return T_EVAL;
}
-#line 319 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy27:
- YYDEBUG(27, *YYCURSOR);
- yych = *++YYCURSOR;
- goto yy6;
-yy28:
- YYDEBUG(28, *YYCURSOR);
- ++YYCURSOR;
- YYFILL(1);
- yych = *YYCURSOR;
-yy29:
- YYDEBUG(29, *YYCURSOR);
- if (yybm[0+yych] & 128) {
- goto yy28;
- }
- if (yych <= 0x00) goto yy27;
- if (yych == '\n') goto yy4;
- YYDEBUG(30, *YYCURSOR);
- yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
- {
- /* ignore whitespace */
-
- goto restart;
-}
-#line 344 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 353 "sapi/phpdbg/phpdbg_lexer.c"
}
/* *********************************** */
yyc_NORMAL:
{
static const unsigned char yybm[] = {
- 0, 8, 8, 8, 8, 8, 8, 8,
- 8, 66, 68, 8, 8, 66, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 66, 8, 8, 0, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 24, 8,
- 152, 152, 152, 152, 152, 152, 152, 152,
- 152, 152, 0, 8, 8, 8, 8, 8,
- 8, 168, 168, 168, 168, 168, 168, 40,
- 40, 40, 40, 40, 40, 40, 40, 40,
- 40, 40, 40, 40, 40, 40, 40, 40,
- 40, 40, 40, 8, 8, 8, 8, 8,
- 8, 168, 168, 168, 168, 168, 168, 40,
- 40, 40, 40, 40, 40, 40, 40, 40,
- 40, 40, 40, 40, 40, 40, 40, 40,
- 40, 40, 40, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
+ /* table 1 .. 8: 0 */
+ 0, 242, 242, 242, 242, 242, 242, 242,
+ 242, 160, 0, 242, 242, 160, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 160, 242, 50, 160, 242, 242, 242, 194,
+ 242, 242, 242, 242, 242, 242, 243, 242,
+ 251, 251, 251, 251, 251, 251, 251, 251,
+ 251, 251, 160, 242, 242, 242, 242, 242,
+ 242, 254, 254, 254, 254, 254, 254, 246,
+ 246, 246, 246, 246, 246, 246, 246, 246,
+ 246, 246, 246, 246, 246, 246, 246, 246,
+ 246, 246, 246, 242, 2, 242, 242, 242,
+ 242, 254, 254, 254, 254, 254, 254, 246,
+ 246, 246, 246, 246, 246, 246, 246, 246,
+ 246, 246, 246, 246, 246, 246, 246, 246,
+ 246, 246, 246, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242,
+ /* table 9 .. 10: 256 */
+ 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 64, 0, 128, 128, 64, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 64, 128, 0, 0, 128, 128, 128, 0,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 0, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
};
- YYDEBUG(31, *YYCURSOR);
+ YYDEBUG(29, *YYCURSOR);
YYFILL(11);
yych = *YYCURSOR;
- if (yybm[0+yych] & 2) {
- goto yy33;
+ if (yybm[256+yych] & 64) {
+ goto yy31;
}
- if (yych <= 'N') {
- if (yych <= '0') {
- if (yych <= '#') {
- if (yych <= '\t') {
- if (yych <= 0x00) goto yy39;
- goto yy43;
- } else {
- if (yych <= '\n') goto yy36;
- if (yych <= '"') goto yy43;
- goto yy58;
- }
- } else {
- if (yych <= '-') {
- if (yych <= ',') goto yy43;
- goto yy40;
- } else {
- if (yych <= '.') goto yy45;
- if (yych <= '/') goto yy43;
- goto yy48;
- }
- }
- } else {
- if (yych <= 'E') {
- if (yych <= ':') {
- if (yych <= '9') goto yy45;
- goto yy60;
- } else {
- if (yych <= 'C') goto yy43;
- if (yych <= 'D') goto yy49;
- goto yy50;
- }
- } else {
- if (yych <= 'H') {
- if (yych <= 'F') goto yy51;
- goto yy43;
- } else {
- if (yych <= 'I') goto yy42;
- if (yych <= 'M') goto yy43;
- goto yy52;
- }
- }
- }
- } else {
- if (yych <= 'f') {
- if (yych <= 'Y') {
- if (yych <= 'S') {
- if (yych <= 'O') goto yy53;
- goto yy43;
- } else {
- if (yych <= 'T') goto yy54;
- if (yych <= 'X') goto yy43;
- goto yy55;
- }
- } else {
- if (yych <= 'c') {
- if (yych <= 'Z') goto yy56;
- goto yy43;
- } else {
- if (yych <= 'd') goto yy49;
- if (yych <= 'e') goto yy50;
- goto yy51;
- }
- }
- } else {
- if (yych <= 'o') {
- if (yych <= 'i') {
- if (yych <= 'h') goto yy43;
- goto yy42;
- } else {
- if (yych <= 'm') goto yy43;
- if (yych <= 'n') goto yy52;
- goto yy53;
- }
- } else {
- if (yych <= 'x') {
- if (yych == 't') goto yy54;
- goto yy43;
- } else {
- if (yych <= 'y') goto yy55;
- if (yych <= 'z') goto yy57;
- goto yy43;
- }
- }
- }
+ YYDEBUG(-1, yych);
+ switch (yych) {
+ case 0x00:
+ case '\t':
+ case '\n': goto yy36;
+ case '"': goto yy44;
+ case '#': goto yy34;
+ case '\'': goto yy46;
+ case '-': goto yy38;
+ case '.':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy47;
+ case '0': goto yy50;
+ case ':': goto yy41;
+ case 'D':
+ case 'd': goto yy51;
+ case 'E':
+ case 'e': goto yy52;
+ case 'F':
+ case 'f': goto yy53;
+ case 'I':
+ case 'i': goto yy40;
+ case 'N':
+ case 'n': goto yy54;
+ case 'O':
+ case 'o': goto yy55;
+ case 'T':
+ case 't': goto yy56;
+ case 'Y':
+ case 'y': goto yy57;
+ case 'Z': goto yy58;
+ case 'z': goto yy59;
+ default: goto yy42;
}
-yy33:
- YYDEBUG(33, *YYCURSOR);
+yy31:
+ YYDEBUG(31, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(34, *YYCURSOR);
- if (yybm[0+yych] & 2) {
- goto yy33;
+ YYDEBUG(32, *YYCURSOR);
+ if (yybm[256+yych] & 64) {
+ goto yy31;
}
- if (yych <= 0x00) goto yy39;
- if (yych == '\n') goto yy36;
- YYDEBUG(35, *YYCURSOR);
+ YYDEBUG(33, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 175 "sapi/phpdbg/phpdbg_lexer.l"
{
/* ignore whitespace */
goto restart;
}
-#line 493 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 490 "sapi/phpdbg/phpdbg_lexer.c"
+yy34:
+ YYDEBUG(34, *YYCURSOR);
+ YYCTXMARKER = YYCURSOR + 1;
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '.') {
+ if (yych <= ',') goto yy35;
+ if (yych <= '-') goto yy146;
+ goto yy147;
+ } else {
+ if (yych <= '/') goto yy35;
+ if (yych <= '9') goto yy147;
+ }
+yy35:
+ YYDEBUG(35, *YYCURSOR);
+ yyleng = (size_t) YYCURSOR - (size_t) yytext;
+#line 110 "sapi/phpdbg/phpdbg_lexer.l"
+ {
+ YYSETCONDITION(INITIAL);
+ return T_SEPARATOR;
+}
+#line 512 "sapi/phpdbg/phpdbg_lexer.c"
yy36:
YYDEBUG(36, *YYCURSOR);
++YYCURSOR;
- YYFILL(1);
- yych = *YYCURSOR;
YYDEBUG(37, *YYCURSOR);
- if (yybm[0+yych] & 2) {
- goto yy33;
- }
- if (yych <= 0x00) goto yy39;
- if (yych == '\n') goto yy36;
-yy38:
- YYDEBUG(38, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 89 "sapi/phpdbg/phpdbg_lexer.l"
{
return 0;
}
-#line 512 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy39:
- YYDEBUG(39, *YYCURSOR);
- yych = *++YYCURSOR;
- goto yy38;
-yy40:
- YYDEBUG(40, *YYCURSOR);
- yyaccept = 0;
+#line 522 "sapi/phpdbg/phpdbg_lexer.c"
+yy38:
+ YYDEBUG(38, *YYCURSOR);
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yybm[0+yych] & 16) {
- goto yy45;
+ if (yybm[0+yych] & 1) {
+ goto yy47;
}
- if (yych == 'r') goto yy113;
- goto yy44;
-yy41:
- YYDEBUG(41, *YYCURSOR);
+ if (yych == 'r') goto yy136;
+ goto yy43;
+yy39:
+ YYDEBUG(39, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 133 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 161 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, STR_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
+ yylval->str = estrndup(yytext, yyleng - unescape_string(yytext));
yylval->len = yyleng;
return T_ID;
}
-#line 536 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 542 "sapi/phpdbg/phpdbg_lexer.c"
+yy40:
+ YYDEBUG(40, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych == 'F') goto yy132;
+ if (yych == 'f') goto yy132;
+ goto yy43;
+yy41:
+ YYDEBUG(41, *YYCURSOR);
+ YYCTXMARKER = YYCURSOR + 1;
+ yych = *++YYCURSOR;
+ if (yych == ':') goto yy130;
+ if (yych == '\\') goto yy68;
+ goto yy128;
yy42:
YYDEBUG(42, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'F') goto yy109;
- if (yych == 'f') goto yy109;
- goto yy44;
-yy43:
- YYDEBUG(43, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
YYMARKER = ++YYCURSOR;
YYFILL(3);
yych = *YYCURSOR;
+yy43:
+ YYDEBUG(43, *YYCURSOR);
+ if (yybm[256+yych] & 128) {
+ goto yy42;
+ }
+ if (yych <= ' ') goto yy39;
+ if (yych == '#') goto yy39;
+ if (yych <= '\'') goto yy62;
+ goto yy61;
yy44:
YYDEBUG(44, *YYCURSOR);
- if (yybm[0+yych] & 8) {
- goto yy43;
- }
- if (yych <= '9') goto yy41;
- goto yy65;
+ yych = *++YYCURSOR;
+ if (yych == '"') goto yy62;
+ goto yy120;
yy45:
YYDEBUG(45, *YYCURSOR);
- yyaccept = 1;
+ YYCURSOR = YYMARKER;
+ if (yyaccept <= 3) {
+ if (yyaccept <= 1) {
+ if (yyaccept == 0) {
+ goto yy35;
+ } else {
+ goto yy39;
+ }
+ } else {
+ if (yyaccept == 2) {
+ goto yy49;
+ } else {
+ goto yy76;
+ }
+ }
+ } else {
+ if (yyaccept <= 5) {
+ if (yyaccept == 4) {
+ goto yy107;
+ } else {
+ goto yy67;
+ }
+ } else {
+ goto yy142;
+ }
+ }
+yy46:
+ YYDEBUG(46, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == '\'') goto yy62;
+ goto yy109;
+yy47:
+ YYDEBUG(47, *YYCURSOR);
+ yyaccept = 2;
YYMARKER = ++YYCURSOR;
YYFILL(3);
yych = *YYCURSOR;
- YYDEBUG(46, *YYCURSOR);
- if (yybm[0+yych] & 16) {
- goto yy45;
+ YYDEBUG(48, *YYCURSOR);
+ if (yybm[0+yych] & 1) {
+ goto yy47;
}
- if (yych <= 0x1F) {
+ if (yych <= ' ') {
if (yych <= '\n') {
- if (yych <= 0x00) goto yy47;
- if (yych <= 0x08) goto yy43;
+ if (yych <= 0x00) goto yy49;
+ if (yych <= 0x08) goto yy42;
} else {
- if (yych != '\r') goto yy43;
+ if (yych == '\r') goto yy49;
+ if (yych <= 0x1F) goto yy42;
}
} else {
- if (yych <= '#') {
- if (yych <= ' ') goto yy47;
- if (yych <= '"') goto yy43;
+ if (yych <= '&') {
+ if (yych <= '!') goto yy42;
+ if (yych <= '"') goto yy62;
+ if (yych >= '$') goto yy42;
} else {
- if (yych == ':') goto yy65;
- goto yy43;
+ if (yych <= '\'') goto yy62;
+ if (yych <= '/') goto yy42;
+ if (yych <= ':') goto yy61;
+ goto yy42;
}
}
-yy47:
- YYDEBUG(47, *YYCURSOR);
+yy49:
+ YYDEBUG(49, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 114 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 142 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, NUMERIC_PARAM);
yylval->num = atoi(yytext);
return T_DIGITS;
}
-#line 592 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy48:
- YYDEBUG(48, *YYCURSOR);
- yyaccept = 1;
+#line 649 "sapi/phpdbg/phpdbg_lexer.c"
+yy50:
+ YYDEBUG(50, *YYCURSOR);
+ yyaccept = 2;
yych = *(YYMARKER = ++YYCURSOR);
- if (yybm[0+yych] & 16) {
- goto yy45;
+ if (yybm[0+yych] & 1) {
+ goto yy47;
}
if (yych <= 0x1F) {
if (yych <= '\n') {
- if (yych <= 0x00) goto yy47;
- if (yych <= 0x08) goto yy44;
- goto yy47;
+ if (yych <= 0x00) goto yy49;
+ if (yych <= 0x08) goto yy43;
+ goto yy49;
} else {
- if (yych == '\r') goto yy47;
- goto yy44;
+ if (yych == '\r') goto yy49;
+ goto yy43;
}
} else {
if (yych <= '#') {
- if (yych <= ' ') goto yy47;
- if (yych <= '"') goto yy44;
- goto yy47;
+ if (yych <= ' ') goto yy49;
+ if (yych <= '"') goto yy43;
+ goto yy49;
} else {
- if (yych == 'x') goto yy105;
- goto yy44;
+ if (yych == 'x') goto yy104;
+ goto yy43;
}
}
-yy49:
- YYDEBUG(49, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'I') goto yy99;
- if (yych == 'i') goto yy99;
- goto yy44;
-yy50:
- YYDEBUG(50, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'N') goto yy94;
- if (yych == 'n') goto yy94;
- goto yy44;
yy51:
YYDEBUG(51, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'A') goto yy91;
- if (yych == 'a') goto yy91;
- goto yy44;
+ if (yych == 'I') goto yy98;
+ if (yych == 'i') goto yy98;
+ goto yy43;
yy52:
YYDEBUG(52, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'O') goto yy87;
- if (yych == 'o') goto yy87;
- goto yy44;
+ if (yych == 'N') goto yy93;
+ if (yych == 'n') goto yy93;
+ goto yy43;
yy53:
YYDEBUG(53, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych == 'A') goto yy90;
+ if (yych == 'a') goto yy90;
+ goto yy43;
+yy54:
+ YYDEBUG(54, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych == 'O') goto yy87;
+ if (yych == 'o') goto yy87;
+ goto yy43;
+yy55:
+ YYDEBUG(55, *YYCURSOR);
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych <= 'N') {
if (yych == 'F') goto yy86;
- if (yych <= 'M') goto yy44;
- goto yy80;
+ if (yych <= 'M') goto yy43;
+ goto yy81;
} else {
if (yych <= 'f') {
- if (yych <= 'e') goto yy44;
+ if (yych <= 'e') goto yy43;
goto yy86;
} else {
- if (yych == 'n') goto yy80;
- goto yy44;
+ if (yych == 'n') goto yy81;
+ goto yy43;
}
}
-yy54:
- YYDEBUG(54, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'R') goto yy84;
- if (yych == 'r') goto yy84;
- goto yy44;
-yy55:
- YYDEBUG(55, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'E') goto yy79;
- if (yych == 'e') goto yy79;
- goto yy44;
yy56:
YYDEBUG(56, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'E') goto yy76;
- goto yy44;
+ if (yych == 'R') goto yy84;
+ if (yych == 'r') goto yy84;
+ goto yy43;
yy57:
YYDEBUG(57, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'e') goto yy64;
- goto yy44;
+ if (yych == 'E') goto yy80;
+ if (yych == 'e') goto yy80;
+ goto yy43;
yy58:
YYDEBUG(58, *YYCURSOR);
- ++YYCURSOR;
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych == 'E') goto yy77;
+ goto yy43;
+yy59:
YYDEBUG(59, *YYCURSOR);
- yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 92 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
- {
- return T_POUND;
-}
-#line 699 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy60:
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych != 'e') goto yy43;
YYDEBUG(60, *YYCURSOR);
- ++YYCURSOR;
- if ((yych = *YYCURSOR) == ':') goto yy62;
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych == 'n') goto yy71;
+ goto yy43;
+yy61:
YYDEBUG(61, *YYCURSOR);
- yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 98 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
- {
- return T_COLON;
-}
-#line 710 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+ yych = *++YYCURSOR;
+ if (yych == '/') goto yy65;
+ if (yych == '\\') goto yy68;
+ goto yy45;
yy62:
YYDEBUG(62, *YYCURSOR);
++YYCURSOR;
+ YYFILL(3);
+ yych = *YYCURSOR;
+yy63:
YYDEBUG(63, *YYCURSOR);
- yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 95 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
- {
- return T_DCOLON;
-}
-#line 720 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+ if (yybm[0+yych] & 2) {
+ goto yy62;
+ }
+ if (yych <= '#') goto yy45;
yy64:
YYDEBUG(64, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'n') goto yy70;
- goto yy44;
+ yych = *++YYCURSOR;
+ if (yych != '/') goto yy45;
yy65:
YYDEBUG(65, *YYCURSOR);
yych = *++YYCURSOR;
- if (yych == '/') goto yy67;
-yy66:
+ if (yych != '/') goto yy45;
YYDEBUG(66, *YYCURSOR);
- YYCURSOR = YYMARKER;
- if (yyaccept <= 2) {
- if (yyaccept <= 1) {
- if (yyaccept <= 0) {
- goto yy41;
- } else {
- goto yy47;
- }
- } else {
- goto yy75;
- }
- } else {
- if (yyaccept <= 3) {
- goto yy108;
- } else {
- goto yy119;
- }
- }
+ ++YYCURSOR;
yy67:
YYDEBUG(67, *YYCURSOR);
- yych = *++YYCURSOR;
- if (yych != '/') goto yy66;
- YYDEBUG(68, *YYCURSOR);
- ++YYCURSOR;
- YYDEBUG(69, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 86 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 123 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, STR_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
+ yylval->str = estrndup(yytext, yyleng);
yylval->len = yyleng;
return T_PROTO;
}
-#line 766 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy70:
+#line 788 "sapi/phpdbg/phpdbg_lexer.c"
+yy68:
+ YYDEBUG(68, *YYCURSOR);
+ yyaccept = 1;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(69, *YYCURSOR);
+ if (yych <= ' ') {
+ if (yych <= '\n') {
+ if (yych <= 0x00) goto yy39;
+ if (yych <= 0x08) goto yy68;
+ goto yy39;
+ } else {
+ if (yych == '\r') goto yy39;
+ if (yych <= 0x1F) goto yy68;
+ goto yy39;
+ }
+ } else {
+ if (yych <= '&') {
+ if (yych <= '!') goto yy68;
+ if (yych <= '#') goto yy39;
+ goto yy68;
+ } else {
+ if (yych <= '\'') goto yy39;
+ if (yych != ':') goto yy68;
+ }
+ }
YYDEBUG(70, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych != 'd') goto yy44;
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yych == '\\') goto yy68;
+ goto yy45;
+yy71:
YYDEBUG(71, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych != '_') goto yy44;
-yy72:
+ if (yych != 'd') goto yy43;
YYDEBUG(72, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yybm[0+yych] & 32) {
- goto yy73;
- }
- goto yy44;
+ if (yych != '_') goto yy43;
yy73:
YYDEBUG(73, *YYCURSOR);
- yyaccept = 2;
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yybm[0+yych] & 4) {
+ goto yy74;
+ }
+ goto yy43;
+yy74:
+ YYDEBUG(74, *YYCURSOR);
+ yyaccept = 3;
YYMARKER = ++YYCURSOR;
YYFILL(3);
yych = *YYCURSOR;
- YYDEBUG(74, *YYCURSOR);
- if (yybm[0+yych] & 32) {
- goto yy73;
+ YYDEBUG(75, *YYCURSOR);
+ if (yybm[0+yych] & 4) {
+ goto yy74;
}
- if (yych <= 0x1F) {
+ if (yych <= ' ') {
if (yych <= '\n') {
- if (yych <= 0x00) goto yy75;
- if (yych <= 0x08) goto yy43;
+ if (yych <= 0x00) goto yy76;
+ if (yych <= 0x08) goto yy42;
} else {
- if (yych != '\r') goto yy43;
+ if (yych == '\r') goto yy76;
+ if (yych <= 0x1F) goto yy42;
}
} else {
- if (yych <= '#') {
- if (yych <= ' ') goto yy75;
- if (yych <= '"') goto yy43;
+ if (yych <= '&') {
+ if (yych <= '!') goto yy42;
+ if (yych <= '"') goto yy62;
+ if (yych >= '$') goto yy42;
} else {
- if (yych == ':') goto yy65;
- goto yy43;
+ if (yych <= '\'') goto yy62;
+ if (yych == ':') goto yy61;
+ goto yy42;
}
}
-yy75:
- YYDEBUG(75, *YYCURSOR);
+yy76:
+ YYDEBUG(76, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 126 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 154 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, OP_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
+ yylval->str = estrndup(yytext, yyleng);
yylval->len = yyleng;
return T_OPCODE;
}
-#line 820 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy76:
- YYDEBUG(76, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych != 'N') goto yy44;
+#line 878 "sapi/phpdbg/phpdbg_lexer.c"
+yy77:
YYDEBUG(77, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych != 'D') goto yy44;
+ if (yych != 'N') goto yy43;
YYDEBUG(78, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == '_') goto yy72;
- goto yy44;
-yy79:
+ if (yych != 'D') goto yy43;
YYDEBUG(79, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'S') goto yy80;
- if (yych != 's') goto yy44;
+ if (yych == '_') goto yy73;
+ goto yy43;
yy80:
YYDEBUG(80, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yybm[0+yych] & 64) {
- goto yy81;
- }
- goto yy44;
+ if (yych == 'S') goto yy81;
+ if (yych != 's') goto yy43;
yy81:
YYDEBUG(81, *YYCURSOR);
- ++YYCURSOR;
- YYFILL(1);
- yych = *YYCURSOR;
- YYDEBUG(82, *YYCURSOR);
- if (yybm[0+yych] & 64) {
- goto yy81;
+ YYCTXMARKER = YYCURSOR + 1;
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '\f') {
+ if (yych <= 0x00) goto yy82;
+ if (yych <= 0x08) goto yy43;
+ if (yych >= '\v') goto yy43;
+ } else {
+ if (yych <= '\r') goto yy82;
+ if (yych != ' ') goto yy43;
}
+yy82:
+ YYDEBUG(82, *YYCURSOR);
+ ++YYCURSOR;
YYDEBUG(83, *YYCURSOR);
+ YYCURSOR = YYCTXMARKER;
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 102 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 130 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, NUMERIC_PARAM);
yylval->num = 1;
return T_TRUTHY;
}
-#line 866 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 924 "sapi/phpdbg/phpdbg_lexer.c"
yy84:
YYDEBUG(84, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'U') goto yy85;
- if (yych != 'u') goto yy44;
+ if (yych != 'u') goto yy43;
yy85:
YYDEBUG(85, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'E') goto yy80;
- if (yych == 'e') goto yy80;
- goto yy44;
+ if (yych == 'E') goto yy81;
+ if (yych == 'e') goto yy81;
+ goto yy43;
yy86:
YYDEBUG(86, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'F') goto yy87;
- if (yych != 'f') goto yy44;
+ if (yych != 'f') goto yy43;
yy87:
YYDEBUG(87, *YYCURSOR);
- yyaccept = 0;
+ YYCTXMARKER = YYCURSOR + 1;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych <= '\f') {
- if (yych <= 0x08) goto yy44;
- if (yych >= '\v') goto yy44;
+ if (yych <= 0x00) goto yy88;
+ if (yych <= 0x08) goto yy43;
+ if (yych >= '\v') goto yy43;
} else {
if (yych <= '\r') goto yy88;
- if (yych != ' ') goto yy44;
+ if (yych != ' ') goto yy43;
}
yy88:
YYDEBUG(88, *YYCURSOR);
++YYCURSOR;
- YYFILL(1);
- yych = *YYCURSOR;
YYDEBUG(89, *YYCURSOR);
- if (yych <= '\f') {
- if (yych <= 0x08) goto yy90;
- if (yych <= '\n') goto yy88;
- } else {
- if (yych <= '\r') goto yy88;
- if (yych == ' ') goto yy88;
- }
-yy90:
- YYDEBUG(90, *YYCURSOR);
+ YYCURSOR = YYCTXMARKER;
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 108 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 136 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, NUMERIC_PARAM);
yylval->num = 0;
return T_FALSY;
}
-#line 919 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 969 "sapi/phpdbg/phpdbg_lexer.c"
+yy90:
+ YYDEBUG(90, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych == 'L') goto yy91;
+ if (yych != 'l') goto yy43;
yy91:
YYDEBUG(91, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'L') goto yy92;
- if (yych != 'l') goto yy44;
+ if (yych == 'S') goto yy92;
+ if (yych != 's') goto yy43;
yy92:
YYDEBUG(92, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'S') goto yy93;
- if (yych != 's') goto yy44;
+ if (yych == 'E') goto yy87;
+ if (yych == 'e') goto yy87;
+ goto yy43;
yy93:
YYDEBUG(93, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'E') goto yy87;
- if (yych == 'e') goto yy87;
- goto yy44;
+ if (yych == 'A') goto yy94;
+ if (yych != 'a') goto yy43;
yy94:
YYDEBUG(94, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'A') goto yy95;
- if (yych != 'a') goto yy44;
+ if (yych == 'B') goto yy95;
+ if (yych != 'b') goto yy43;
yy95:
YYDEBUG(95, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'B') goto yy96;
- if (yych != 'b') goto yy44;
+ if (yych == 'L') goto yy96;
+ if (yych != 'l') goto yy43;
yy96:
YYDEBUG(96, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'L') goto yy97;
- if (yych != 'l') goto yy44;
+ if (yych == 'E') goto yy97;
+ if (yych != 'e') goto yy43;
yy97:
YYDEBUG(97, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'E') goto yy98;
- if (yych != 'e') goto yy44;
+ if (yych == 'D') goto yy81;
+ if (yych == 'd') goto yy81;
+ goto yy43;
yy98:
YYDEBUG(98, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'D') goto yy80;
- if (yych == 'd') goto yy80;
- goto yy44;
+ if (yych == 'S') goto yy99;
+ if (yych != 's') goto yy43;
yy99:
YYDEBUG(99, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'S') goto yy100;
- if (yych != 's') goto yy44;
+ if (yych == 'A') goto yy100;
+ if (yych != 'a') goto yy43;
yy100:
YYDEBUG(100, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'A') goto yy101;
- if (yych != 'a') goto yy44;
+ if (yych == 'B') goto yy101;
+ if (yych != 'b') goto yy43;
yy101:
YYDEBUG(101, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'B') goto yy102;
- if (yych != 'b') goto yy44;
+ if (yych == 'L') goto yy102;
+ if (yych != 'l') goto yy43;
yy102:
YYDEBUG(102, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'L') goto yy103;
- if (yych != 'l') goto yy44;
+ if (yych == 'E') goto yy103;
+ if (yych != 'e') goto yy43;
yy103:
YYDEBUG(103, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'E') goto yy104;
- if (yych != 'e') goto yy44;
+ if (yych == 'D') goto yy87;
+ if (yych == 'd') goto yy87;
+ goto yy43;
yy104:
YYDEBUG(104, *YYCURSOR);
- yyaccept = 0;
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'D') goto yy87;
- if (yych == 'd') goto yy87;
- goto yy44;
+ if (yybm[0+yych] & 8) {
+ goto yy105;
+ }
+ goto yy43;
yy105:
YYDEBUG(105, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yybm[0+yych] & 128) {
- goto yy106;
- }
- goto yy44;
-yy106:
- YYDEBUG(106, *YYCURSOR);
- yyaccept = 3;
+ yyaccept = 4;
YYMARKER = ++YYCURSOR;
YYFILL(3);
yych = *YYCURSOR;
- YYDEBUG(107, *YYCURSOR);
- if (yybm[0+yych] & 128) {
- goto yy106;
+ YYDEBUG(106, *YYCURSOR);
+ if (yybm[0+yych] & 8) {
+ goto yy105;
}
- if (yych <= 0x1F) {
+ if (yych <= ' ') {
if (yych <= '\n') {
- if (yych <= 0x00) goto yy108;
- if (yych <= 0x08) goto yy43;
+ if (yych <= 0x00) goto yy107;
+ if (yych <= 0x08) goto yy42;
} else {
- if (yych != '\r') goto yy43;
+ if (yych == '\r') goto yy107;
+ if (yych <= 0x1F) goto yy42;
}
} else {
- if (yych <= '#') {
- if (yych <= ' ') goto yy108;
- if (yych <= '"') goto yy43;
+ if (yych <= '&') {
+ if (yych <= '!') goto yy42;
+ if (yych <= '"') goto yy62;
+ if (yych >= '$') goto yy42;
} else {
- if (yych == ':') goto yy65;
- goto yy43;
+ if (yych <= '\'') goto yy62;
+ if (yych <= '/') goto yy42;
+ if (yych <= ':') goto yy61;
+ goto yy42;
}
}
-yy108:
- YYDEBUG(108, *YYCURSOR);
+yy107:
+ YYDEBUG(107, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 120 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 148 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, ADDR_PARAM);
yylval->addr = strtoul(yytext, 0, 16);
return T_ADDR;
}
-#line 1050 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 1104 "sapi/phpdbg/phpdbg_lexer.c"
+yy108:
+ YYDEBUG(108, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(4);
+ yych = *YYCURSOR;
yy109:
YYDEBUG(109, *YYCURSOR);
- yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- if (yych <= '\f') {
- if (yych <= 0x08) goto yy44;
- if (yych >= '\v') goto yy44;
+ if (yybm[0+yych] & 16) {
+ goto yy108;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00) goto yy45;
+ if (yych >= '\n') goto yy45;
} else {
- if (yych <= '\r') goto yy110;
- if (yych != ' ') goto yy44;
+ if (yych <= '#') goto yy110;
+ if (yych <= '\'') goto yy118;
+ if (yych <= ':') goto yy112;
+ goto yy113;
}
yy110:
YYDEBUG(110, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
+yy111:
YYDEBUG(111, *YYCURSOR);
- if (yych <= '\f') {
- if (yych <= 0x08) goto yy112;
- if (yych <= '\n') goto yy110;
- } else {
- if (yych <= '\r') goto yy110;
- if (yych == ' ') goto yy110;
+ if (yybm[0+yych] & 32) {
+ goto yy110;
}
+ if (yych <= '\n') goto yy45;
+ if (yych <= '\'') goto yy115;
+ goto yy116;
yy112:
YYDEBUG(112, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == '/') goto yy114;
+ goto yy111;
+yy113:
+ YYDEBUG(113, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(3);
+ yych = *YYCURSOR;
+ if (yych <= '"') {
+ if (yych <= '\f') {
+ if (yych <= 0x00) goto yy45;
+ if (yych <= 0x08) goto yy62;
+ if (yych <= '\n') goto yy45;
+ goto yy62;
+ } else {
+ if (yych <= '\r') goto yy45;
+ if (yych == ' ') goto yy45;
+ goto yy62;
+ }
+ } else {
+ if (yych <= '9') {
+ if (yych <= '#') goto yy45;
+ if (yych == '\'') goto yy108;
+ goto yy62;
+ } else {
+ if (yych <= ':') goto yy64;
+ if (yych == '\\') goto yy108;
+ goto yy62;
+ }
+ }
+yy114:
+ YYDEBUG(114, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == '/') goto yy117;
+ goto yy111;
+yy115:
+ YYDEBUG(115, *YYCURSOR);
+ yych = *++YYCURSOR;
+ goto yy39;
+yy116:
+ YYDEBUG(116, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yych == '\'') goto yy110;
+ if (yych == '\\') goto yy110;
+ goto yy45;
+yy117:
+ YYDEBUG(117, *YYCURSOR);
+ yyaccept = 5;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= 0x00) goto yy67;
+ if (yych == '\n') goto yy67;
+ goto yy111;
+yy118:
+ YYDEBUG(118, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '\r') {
+ if (yych <= 0x08) {
+ if (yych <= 0x00) goto yy39;
+ goto yy63;
+ } else {
+ if (yych <= '\n') goto yy39;
+ if (yych <= '\f') goto yy63;
+ goto yy39;
+ }
+ } else {
+ if (yych <= ' ') {
+ if (yych <= 0x1F) goto yy63;
+ goto yy39;
+ } else {
+ if (yych == '#') goto yy39;
+ goto yy63;
+ }
+ }
+yy119:
+ YYDEBUG(119, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(4);
+ yych = *YYCURSOR;
+yy120:
+ YYDEBUG(120, *YYCURSOR);
+ if (yybm[0+yych] & 64) {
+ goto yy119;
+ }
+ if (yych <= ' ') {
+ if (yych <= 0x00) goto yy45;
+ if (yych == '\n') goto yy45;
+ } else {
+ if (yych <= '"') goto yy118;
+ if (yych <= '#') goto yy121;
+ if (yych <= ':') goto yy123;
+ goto yy124;
+ }
+yy121:
+ YYDEBUG(121, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+yy122:
+ YYDEBUG(122, *YYCURSOR);
+ if (yybm[0+yych] & 128) {
+ goto yy121;
+ }
+ if (yych <= '\n') goto yy45;
+ if (yych <= '"') goto yy115;
+ goto yy126;
+yy123:
+ YYDEBUG(123, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == '/') goto yy125;
+ goto yy122;
+yy124:
+ YYDEBUG(124, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(3);
+ yych = *YYCURSOR;
+ if (yych <= ' ') {
+ if (yych <= '\n') {
+ if (yych <= 0x00) goto yy45;
+ if (yych <= 0x08) goto yy62;
+ goto yy45;
+ } else {
+ if (yych == '\r') goto yy45;
+ if (yych <= 0x1F) goto yy62;
+ goto yy45;
+ }
+ } else {
+ if (yych <= '9') {
+ if (yych <= '!') goto yy62;
+ if (yych <= '"') goto yy119;
+ if (yych <= '#') goto yy45;
+ goto yy62;
+ } else {
+ if (yych <= ':') goto yy64;
+ if (yych == '\\') goto yy119;
+ goto yy62;
+ }
+ }
+yy125:
+ YYDEBUG(125, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == '/') goto yy127;
+ goto yy122;
+yy126:
+ YYDEBUG(126, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yych == '"') goto yy121;
+ if (yych == '\\') goto yy121;
+ goto yy45;
+yy127:
+ YYDEBUG(127, *YYCURSOR);
+ yyaccept = 5;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= 0x00) goto yy67;
+ if (yych == '\n') goto yy67;
+ goto yy122;
+yy128:
+ YYDEBUG(128, *YYCURSOR);
+ ++YYCURSOR;
+ YYDEBUG(129, *YYCURSOR);
+ YYCURSOR = YYCTXMARKER;
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 80 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 119 "sapi/phpdbg/phpdbg_lexer.l"
+ {
+ return T_COLON;
+}
+#line 1309 "sapi/phpdbg/phpdbg_lexer.c"
+yy130:
+ YYDEBUG(130, *YYCURSOR);
+ ++YYCURSOR;
+ YYDEBUG(131, *YYCURSOR);
+ yyleng = (size_t) YYCURSOR - (size_t) yytext;
+#line 115 "sapi/phpdbg/phpdbg_lexer.l"
+ {
+ return T_DCOLON;
+}
+#line 1319 "sapi/phpdbg/phpdbg_lexer.c"
+yy132:
+ YYDEBUG(132, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '\f') {
+ if (yych != '\t') goto yy43;
+ } else {
+ if (yych <= '\r') goto yy133;
+ if (yych != ' ') goto yy43;
+ }
+yy133:
+ YYDEBUG(133, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(134, *YYCURSOR);
+ if (yych <= '\f') {
+ if (yych == '\t') goto yy133;
+ } else {
+ if (yych <= '\r') goto yy133;
+ if (yych == ' ') goto yy133;
+ }
+ YYDEBUG(135, *YYCURSOR);
+ yyleng = (size_t) YYCURSOR - (size_t) yytext;
+#line 100 "sapi/phpdbg/phpdbg_lexer.l"
{
YYSETCONDITION(RAW);
phpdbg_init_param(yylval, EMPTY_PARAM);
return T_IF;
}
-#line 1084 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy113:
- YYDEBUG(113, *YYCURSOR);
- yyaccept = 0;
+#line 1350 "sapi/phpdbg/phpdbg_lexer.c"
+yy136:
+ YYDEBUG(136, *YYCURSOR);
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych <= ' ') {
if (yych <= '\f') {
- if (yych <= 0x08) goto yy44;
- if (yych >= '\v') goto yy44;
+ if (yych != '\t') goto yy43;
} else {
- if (yych <= '\r') goto yy114;
- if (yych <= 0x1F) goto yy44;
+ if (yych <= '\r') goto yy137;
+ if (yych <= 0x1F) goto yy43;
}
} else {
if (yych <= '.') {
- if (yych <= ',') goto yy44;
- if (yych <= '-') goto yy116;
- goto yy117;
+ if (yych <= ',') goto yy43;
+ if (yych <= '-') goto yy139;
+ goto yy140;
} else {
- if (yych <= '/') goto yy44;
- if (yych <= '9') goto yy117;
- goto yy44;
+ if (yych <= '/') goto yy43;
+ if (yych <= '9') goto yy140;
+ goto yy43;
}
}
-yy114:
- YYDEBUG(114, *YYCURSOR);
+yy137:
+ YYDEBUG(137, *YYCURSOR);
++YYCURSOR;
YYFILL(2);
yych = *YYCURSOR;
- YYDEBUG(115, *YYCURSOR);
+ YYDEBUG(138, *YYCURSOR);
if (yych <= ' ') {
if (yych <= '\f') {
- if (yych <= 0x08) goto yy66;
- if (yych <= '\n') goto yy114;
- goto yy66;
+ if (yych == '\t') goto yy137;
+ goto yy45;
} else {
- if (yych <= '\r') goto yy114;
- if (yych <= 0x1F) goto yy66;
- goto yy114;
+ if (yych <= '\r') goto yy137;
+ if (yych <= 0x1F) goto yy45;
+ goto yy137;
}
} else {
if (yych <= '.') {
- if (yych <= ',') goto yy66;
- if (yych <= '-') goto yy120;
- goto yy121;
+ if (yych <= ',') goto yy45;
+ if (yych <= '-') goto yy143;
+ goto yy144;
} else {
- if (yych <= '/') goto yy66;
- if (yych <= '9') goto yy121;
- goto yy66;
+ if (yych <= '/') goto yy45;
+ if (yych <= '9') goto yy144;
+ goto yy45;
}
}
-yy116:
- YYDEBUG(116, *YYCURSOR);
- yyaccept = 0;
+yy139:
+ YYDEBUG(139, *YYCURSOR);
+ yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == '.') goto yy117;
- if (yych <= '/') goto yy44;
- if (yych >= ':') goto yy44;
-yy117:
- YYDEBUG(117, *YYCURSOR);
- yyaccept = 4;
+ if (yych == '.') goto yy140;
+ if (yych <= '/') goto yy43;
+ if (yych >= ':') goto yy43;
+yy140:
+ YYDEBUG(140, *YYCURSOR);
+ yyaccept = 6;
YYMARKER = ++YYCURSOR;
YYFILL(3);
yych = *YYCURSOR;
- YYDEBUG(118, *YYCURSOR);
- if (yych <= ' ') {
- if (yych <= '\n') {
- if (yych <= 0x00) goto yy119;
- if (yych <= 0x08) goto yy43;
+ YYDEBUG(141, *YYCURSOR);
+ if (yych <= '"') {
+ if (yych <= '\f') {
+ if (yych <= 0x00) goto yy142;
+ if (yych <= 0x08) goto yy42;
+ if (yych >= '\v') goto yy42;
} else {
- if (yych == '\r') goto yy119;
- if (yych <= 0x1F) goto yy43;
+ if (yych <= 0x1F) {
+ if (yych >= 0x0E) goto yy42;
+ } else {
+ if (yych <= ' ') goto yy142;
+ if (yych <= '!') goto yy42;
+ goto yy62;
+ }
}
} else {
- if (yych <= '.') {
- if (yych == '#') goto yy119;
- if (yych <= '-') goto yy43;
- goto yy117;
+ if (yych <= '-') {
+ if (yych <= '#') goto yy142;
+ if (yych == '\'') goto yy62;
+ goto yy42;
} else {
- if (yych <= '/') goto yy43;
- if (yych <= '9') goto yy117;
- if (yych <= ':') goto yy65;
- goto yy43;
+ if (yych <= '/') {
+ if (yych <= '.') goto yy140;
+ goto yy42;
+ } else {
+ if (yych <= '9') goto yy140;
+ if (yych <= ':') goto yy61;
+ goto yy42;
+ }
}
}
-yy119:
- YYDEBUG(119, *YYCURSOR);
+yy142:
+ YYDEBUG(142, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 73 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 93 "sapi/phpdbg/phpdbg_lexer.l"
{
char *text = yytext + 2;
while (*++text < '0');
yylval->num = atoi(text);
return T_REQ_ID;
}
-#line 1179 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy120:
- YYDEBUG(120, *YYCURSOR);
+#line 1453 "sapi/phpdbg/phpdbg_lexer.c"
+yy143:
+ YYDEBUG(143, *YYCURSOR);
yych = *++YYCURSOR;
- if (yych == '.') goto yy121;
- if (yych <= '/') goto yy66;
- if (yych >= ':') goto yy66;
-yy121:
- YYDEBUG(121, *YYCURSOR);
+ if (yych == '.') goto yy144;
+ if (yych <= '/') goto yy45;
+ if (yych >= ':') goto yy45;
+yy144:
+ YYDEBUG(144, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(122, *YYCURSOR);
- if (yych == '.') goto yy121;
- if (yych <= '/') goto yy119;
- if (yych <= '9') goto yy121;
- goto yy119;
+ YYDEBUG(145, *YYCURSOR);
+ if (yych == '.') goto yy144;
+ if (yych <= '/') goto yy142;
+ if (yych <= '9') goto yy144;
+ goto yy142;
+yy146:
+ YYDEBUG(146, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == '.') goto yy147;
+ if (yych <= '/') goto yy45;
+ if (yych >= ':') goto yy45;
+yy147:
+ YYDEBUG(147, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(148, *YYCURSOR);
+ if (yych == '.') goto yy147;
+ if (yych <= '/') goto yy149;
+ if (yych <= '9') goto yy147;
+yy149:
+ YYDEBUG(149, *YYCURSOR);
+ YYCURSOR = YYCTXMARKER;
+ yyleng = (size_t) YYCURSOR - (size_t) yytext;
+#line 106 "sapi/phpdbg/phpdbg_lexer.l"
+ {
+ return T_POUND;
+}
+#line 1493 "sapi/phpdbg/phpdbg_lexer.c"
}
/* *********************************** */
yyc_PRE_RAW:
{
static const unsigned char yybm[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 160, 48, 0, 0, 160, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 160, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 64, 0,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 64, 0, 0, 0, 64, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 64, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 128, 0,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
- YYDEBUG(123, *YYCURSOR);
+ YYDEBUG(150, *YYCURSOR);
YYFILL(2);
yych = *YYCURSOR;
- if (yybm[0+yych] & 16) {
- goto yy127;
- }
if (yych <= '\r') {
- if (yych <= 0x08) {
- if (yych <= 0x00) goto yy130;
- goto yy132;
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy158;
+ if (yych <= 0x08) goto yy160;
} else {
- if (yych <= '\t') goto yy125;
- if (yych <= '\f') goto yy132;
+ if (yych <= '\n') goto yy158;
+ if (yych <= '\f') goto yy160;
}
} else {
- if (yych <= ' ') {
- if (yych <= 0x1F) goto yy132;
+ if (yych <= '"') {
+ if (yych == ' ') goto yy154;
+ goto yy160;
} else {
- if (yych == '-') goto yy131;
- goto yy132;
+ if (yych <= '#') goto yy157;
+ if (yych == '-') goto yy159;
+ goto yy160;
}
}
-yy125:
- YYDEBUG(125, *YYCURSOR);
+ YYDEBUG(152, *YYCURSOR);
++YYCURSOR;
- if ((yych = *YYCURSOR) <= '\f') {
- if (yych <= 0x00) goto yy142;
- if (yych <= 0x08) goto yy126;
- if (yych <= '\n') goto yy142;
- } else {
- if (yych <= '\r') goto yy142;
- if (yych == ' ') goto yy142;
+ if (yybm[0+(yych = *YYCURSOR)] & 64) {
+ goto yy154;
}
-yy126:
- YYDEBUG(126, *YYCURSOR);
+yy153:
+ YYDEBUG(153, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 169 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 199 "sapi/phpdbg/phpdbg_lexer.l"
{
YYSETCONDITION(RAW);
YYCURSOR = LEX(text);
goto restart;
}
-#line 1277 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy127:
- YYDEBUG(127, *YYCURSOR);
+#line 1568 "sapi/phpdbg/phpdbg_lexer.c"
+yy154:
+ YYDEBUG(154, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(128, *YYCURSOR);
- if (yybm[0+yych] & 128) {
- goto yy141;
+ YYDEBUG(155, *YYCURSOR);
+ if (yybm[0+yych] & 64) {
+ goto yy154;
}
- if (yych <= 0x00) goto yy140;
- if (yych == '\n') goto yy127;
-yy129:
- YYDEBUG(129, *YYCURSOR);
+ YYDEBUG(156, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 175 "sapi/phpdbg/phpdbg_lexer.l"
{
- return 0;
+ /* ignore whitespace */
+
+ goto restart;
}
-#line 1296 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy130:
- YYDEBUG(130, *YYCURSOR);
+#line 1586 "sapi/phpdbg/phpdbg_lexer.c"
+yy157:
+ YYDEBUG(157, *YYCURSOR);
yych = *++YYCURSOR;
- goto yy126;
-yy131:
- YYDEBUG(131, *YYCURSOR);
+ goto yy153;
+yy158:
+ YYDEBUG(158, *YYCURSOR);
+ yych = *++YYCURSOR;
+ goto yy153;
+yy159:
+ YYDEBUG(159, *YYCURSOR);
yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == 'r') goto yy133;
- goto yy126;
-yy132:
- YYDEBUG(132, *YYCURSOR);
+ if (yych == 'r') goto yy161;
+ goto yy153;
+yy160:
+ YYDEBUG(160, *YYCURSOR);
yych = *++YYCURSOR;
- goto yy126;
-yy133:
- YYDEBUG(133, *YYCURSOR);
+ goto yy153;
+yy161:
+ YYDEBUG(161, *YYCURSOR);
++YYCURSOR;
YYFILL(2);
yych = *YYCURSOR;
- YYDEBUG(134, *YYCURSOR);
- if (yybm[0+yych] & 32) {
- goto yy133;
+ YYDEBUG(162, *YYCURSOR);
+ if (yybm[0+yych] & 128) {
+ goto yy165;
}
- if (yych <= '.') {
- if (yych <= ',') goto yy135;
- if (yych <= '-') goto yy136;
- goto yy137;
+ if (yych <= '\r') {
+ if (yych == '\t') goto yy161;
+ if (yych >= '\r') goto yy161;
} else {
- if (yych <= '/') goto yy135;
- if (yych <= '9') goto yy137;
+ if (yych <= ' ') {
+ if (yych >= ' ') goto yy161;
+ } else {
+ if (yych == '-') goto yy164;
+ }
}
-yy135:
- YYDEBUG(135, *YYCURSOR);
+yy163:
+ YYDEBUG(163, *YYCURSOR);
YYCURSOR = YYMARKER;
- goto yy126;
-yy136:
- YYDEBUG(136, *YYCURSOR);
+ goto yy153;
+yy164:
+ YYDEBUG(164, *YYCURSOR);
yych = *++YYCURSOR;
- if (yybm[0+yych] & 64) {
- goto yy137;
+ if (yybm[0+yych] & 128) {
+ goto yy165;
}
- goto yy135;
-yy137:
- YYDEBUG(137, *YYCURSOR);
+ goto yy163;
+yy165:
+ YYDEBUG(165, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(138, *YYCURSOR);
- if (yybm[0+yych] & 64) {
- goto yy137;
+ YYDEBUG(166, *YYCURSOR);
+ if (yybm[0+yych] & 128) {
+ goto yy165;
}
- YYDEBUG(139, *YYCURSOR);
+ YYDEBUG(167, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 73 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 93 "sapi/phpdbg/phpdbg_lexer.l"
{
char *text = yytext + 2;
while (*++text < '0');
yylval->num = atoi(text);
return T_REQ_ID;
}
-#line 1357 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy140:
- YYDEBUG(140, *YYCURSOR);
- yych = *++YYCURSOR;
- goto yy129;
-yy141:
- YYDEBUG(141, *YYCURSOR);
- ++YYCURSOR;
- YYFILL(1);
- yych = *YYCURSOR;
-yy142:
- YYDEBUG(142, *YYCURSOR);
- if (yybm[0+yych] & 128) {
- goto yy141;
- }
- if (yych <= 0x00) goto yy140;
- if (yych == '\n') goto yy127;
- YYDEBUG(143, *YYCURSOR);
- yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
- {
- /* ignore whitespace */
-
- goto restart;
-}
-#line 1382 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
+#line 1653 "sapi/phpdbg/phpdbg_lexer.c"
}
/* *********************************** */
yyc_RAW:
{
static const unsigned char yybm[] = {
- 0, 128, 128, 128, 128, 128, 128, 128,
- 128, 160, 64, 128, 128, 160, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 160, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
+ 0, 232, 232, 232, 232, 232, 232, 232,
+ 232, 236, 0, 232, 232, 236, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 236, 232, 32, 224, 232, 232, 232, 128,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 16, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232,
};
- YYDEBUG(144, *YYCURSOR);
+ YYDEBUG(168, *YYCURSOR);
YYFILL(1);
yych = *YYCURSOR;
- if (yybm[0+yych] & 32) {
- goto yy146;
+ if (yybm[0+yych] & 4) {
+ goto yy170;
}
- if (yych <= 0x00) goto yy152;
- if (yych == '\n') goto yy149;
- goto yy153;
-yy146:
- YYDEBUG(146, *YYCURSOR);
- ++YYCURSOR;
+ if (yych <= '"') {
+ if (yych <= 0x08) {
+ if (yych <= 0x00) goto yy175;
+ goto yy177;
+ } else {
+ if (yych <= '\n') goto yy175;
+ if (yych <= '!') goto yy177;
+ goto yy181;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy173;
+ if (yych <= '&') goto yy177;
+ goto yy183;
+ } else {
+ if (yych == '\\') goto yy179;
+ goto yy177;
+ }
+ }
+yy170:
+ YYDEBUG(170, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(147, *YYCURSOR);
- if (yybm[0+yych] & 32) {
- goto yy146;
+ YYDEBUG(171, *YYCURSOR);
+ if (yybm[0+yych] & 4) {
+ goto yy170;
}
- if (yych <= 0x00) goto yy152;
- if (yych == '\n') goto yy149;
- goto yy153;
-yy148:
- YYDEBUG(148, *YYCURSOR);
+ if (yych <= '"') {
+ if (yych <= 0x08) {
+ if (yych >= 0x01) goto yy177;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy177;
+ goto yy181;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy172;
+ if (yych <= '&') goto yy177;
+ goto yy183;
+ } else {
+ if (yych == '\\') goto yy179;
+ goto yy177;
+ }
+ }
+yy172:
+ YYDEBUG(172, *YYCURSOR);
yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 140 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 168 "sapi/phpdbg/phpdbg_lexer.l"
{
phpdbg_init_param(yylval, STR_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
+ yylval->str = estrdup(yytext);
yylval->len = yyleng;
return T_INPUT;
}
-#line 1452 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy149:
- YYDEBUG(149, *YYCURSOR);
+#line 1755 "sapi/phpdbg/phpdbg_lexer.c"
+yy173:
+ YYDEBUG(173, *YYCURSOR);
++YYCURSOR;
+ YYDEBUG(174, *YYCURSOR);
+ yyleng = (size_t) YYCURSOR - (size_t) yytext;
+#line 110 "sapi/phpdbg/phpdbg_lexer.l"
+ {
+ YYSETCONDITION(INITIAL);
+ return T_SEPARATOR;
+}
+#line 1766 "sapi/phpdbg/phpdbg_lexer.c"
+yy175:
+ YYDEBUG(175, *YYCURSOR);
+ ++YYCURSOR;
+ YYDEBUG(176, *YYCURSOR);
+ yyleng = (size_t) YYCURSOR - (size_t) yytext;
+#line 89 "sapi/phpdbg/phpdbg_lexer.l"
+ {
+ return 0;
+}
+#line 1776 "sapi/phpdbg/phpdbg_lexer.c"
+yy177:
+ YYDEBUG(177, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(150, *YYCURSOR);
- if (yybm[0+yych] & 64) {
- goto yy149;
+ YYDEBUG(178, *YYCURSOR);
+ if (yybm[0+yych] & 8) {
+ goto yy177;
}
- if (yych <= '\f') {
- if (yych <= 0x00) goto yy152;
- if (yych == '\t') goto yy155;
+ if (yych <= '\n') goto yy172;
+ if (yych <= '"') goto yy181;
+ if (yych <= '#') goto yy172;
+ if (yych <= '\'') goto yy183;
+yy179:
+ YYDEBUG(179, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(180, *YYCURSOR);
+ if (yybm[0+yych] & 16) {
+ goto yy179;
+ }
+ if (yych <= '!') {
+ if (yych <= 0x00) goto yy172;
+ if (yych == '\n') goto yy172;
+ goto yy177;
} else {
- if (yych <= '\r') goto yy155;
- if (yych == ' ') goto yy155;
+ if (yych <= '"') goto yy211;
+ if (yych == '\'') goto yy193;
+ goto yy177;
}
-yy151:
- YYDEBUG(151, *YYCURSOR);
- yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
- {
- return 0;
-}
-#line 1476 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
-yy152:
- YYDEBUG(152, *YYCURSOR);
- yych = *++YYCURSOR;
- goto yy151;
-yy153:
- YYDEBUG(153, *YYCURSOR);
+yy181:
+ YYDEBUG(181, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(154, *YYCURSOR);
if (yybm[0+yych] & 128) {
- goto yy153;
+ goto yy207;
}
- goto yy148;
-yy155:
- YYDEBUG(155, *YYCURSOR);
+ if (yych >= '#') goto yy209;
+yy182:
+ YYDEBUG(182, *YYCURSOR);
+ YYCURSOR = YYMARKER;
+ goto yy172;
+yy183:
+ YYDEBUG(183, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yybm[0+yych] & 32) {
+ goto yy184;
+ }
+ if (yych <= '\'') goto yy182;
+ goto yy186;
+yy184:
+ YYDEBUG(184, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(185, *YYCURSOR);
+ if (yybm[0+yych] & 32) {
+ goto yy184;
+ }
+ if (yych <= '\n') goto yy182;
+ if (yych <= '\'') goto yy177;
+yy186:
+ YYDEBUG(186, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(187, *YYCURSOR);
+ if (yybm[0+yych] & 32) {
+ goto yy184;
+ }
+ if (yych <= '\n') goto yy182;
+ if (yych >= '(') goto yy186;
+yy188:
+ YYDEBUG(188, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(189, *YYCURSOR);
+ if (yych <= '"') {
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy172;
+ goto yy188;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy188;
+ goto yy192;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy184;
+ if (yych <= '&') goto yy188;
+ goto yy193;
+ } else {
+ if (yych != '\\') goto yy188;
+ }
+ }
+yy190:
+ YYDEBUG(190, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(191, *YYCURSOR);
+ if (yych <= '!') {
+ if (yych <= 0x00) goto yy172;
+ if (yych == '\n') goto yy172;
+ goto yy188;
+ } else {
+ if (yych <= '"') goto yy203;
+ if (yych == '\\') goto yy190;
+ goto yy188;
+ }
+yy192:
+ YYDEBUG(192, *YYCURSOR);
++YYCURSOR;
YYFILL(1);
yych = *YYCURSOR;
- YYDEBUG(156, *YYCURSOR);
if (yybm[0+yych] & 64) {
- goto yy149;
+ goto yy196;
}
- if (yych <= '\f') {
- if (yych <= 0x00) goto yy152;
- if (yych == '\t') goto yy155;
+ if (yych <= '\n') goto yy182;
+ if (yych <= '"') goto yy184;
+ if (yych <= '\'') goto yy194;
+ goto yy198;
+yy193:
+ YYDEBUG(193, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yych <= '"') {
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy172;
+ goto yy188;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy188;
+ goto yy192;
+ }
} else {
- if (yych <= '\r') goto yy155;
- if (yych == ' ') goto yy155;
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy184;
+ if (yych <= '&') goto yy188;
+ goto yy183;
+ } else {
+ if (yych == '\\') goto yy190;
+ goto yy188;
+ }
+ }
+yy194:
+ YYDEBUG(194, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(195, *YYCURSOR);
+ if (yych <= '"') {
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy172;
+ goto yy194;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy194;
+ goto yy211;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy207;
+ if (yych <= '&') goto yy194;
+ goto yy206;
+ } else {
+ if (yych == '\\') goto yy212;
+ goto yy194;
+ }
+ }
+yy196:
+ YYDEBUG(196, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(197, *YYCURSOR);
+ if (yybm[0+yych] & 64) {
+ goto yy196;
+ }
+ if (yych <= '\n') goto yy182;
+ if (yych <= '"') goto yy188;
+ if (yych <= '\'') goto yy194;
+yy198:
+ YYDEBUG(198, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(199, *YYCURSOR);
+ if (yybm[0+yych] & 64) {
+ goto yy196;
+ }
+ if (yych <= '\n') goto yy182;
+ if (yych >= '(') goto yy198;
+yy200:
+ YYDEBUG(200, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(201, *YYCURSOR);
+ if (yych <= '"') {
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy172;
+ goto yy200;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy200;
+ goto yy203;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy196;
+ if (yych <= '&') goto yy200;
+ } else {
+ if (yych == '\\') goto yy204;
+ goto yy200;
+ }
+ }
+yy202:
+ YYDEBUG(202, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yych <= '"') {
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy172;
+ goto yy200;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy200;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy196;
+ if (yych <= '&') goto yy200;
+ goto yy206;
+ } else {
+ if (yych == '\\') goto yy204;
+ goto yy200;
+ }
+ }
+yy203:
+ YYDEBUG(203, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yych <= '"') {
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy172;
+ goto yy200;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy200;
+ goto yy192;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy196;
+ if (yych <= '&') goto yy200;
+ goto yy202;
+ } else {
+ if (yych != '\\') goto yy200;
+ }
+ }
+yy204:
+ YYDEBUG(204, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(205, *YYCURSOR);
+ if (yych <= '\n') {
+ if (yych <= 0x00) goto yy172;
+ if (yych <= '\t') goto yy200;
+ goto yy172;
+ } else {
+ if (yych == '\\') goto yy204;
+ goto yy200;
+ }
+yy206:
+ YYDEBUG(206, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yybm[0+yych] & 64) {
+ goto yy196;
+ }
+ if (yych <= '\n') goto yy182;
+ if (yych <= '"') goto yy188;
+ if (yych >= '(') goto yy198;
+yy207:
+ YYDEBUG(207, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(208, *YYCURSOR);
+ if (yybm[0+yych] & 128) {
+ goto yy207;
+ }
+ if (yych <= '\n') goto yy182;
+ if (yych <= '"') goto yy177;
+yy209:
+ YYDEBUG(209, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(210, *YYCURSOR);
+ if (yybm[0+yych] & 128) {
+ goto yy207;
+ }
+ if (yych <= '\n') goto yy182;
+ if (yych <= '"') goto yy194;
+ goto yy209;
+yy211:
+ YYDEBUG(211, *YYCURSOR);
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ if (yych <= '"') {
+ if (yych <= '\t') {
+ if (yych <= 0x00) goto yy172;
+ goto yy194;
+ } else {
+ if (yych <= '\n') goto yy172;
+ if (yych <= '!') goto yy194;
+ goto yy181;
+ }
+ } else {
+ if (yych <= '\'') {
+ if (yych <= '#') goto yy207;
+ if (yych <= '&') goto yy194;
+ goto yy206;
+ } else {
+ if (yych != '\\') goto yy194;
+ }
+ }
+yy212:
+ YYDEBUG(212, *YYCURSOR);
+ ++YYCURSOR;
+ YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(213, *YYCURSOR);
+ if (yych <= '&') {
+ if (yych <= 0x00) goto yy172;
+ if (yych == '\n') goto yy172;
+ goto yy194;
+ } else {
+ if (yych <= '\'') goto yy202;
+ if (yych == '\\') goto yy212;
+ goto yy194;
}
- YYDEBUG(157, *YYCURSOR);
- yyleng = (size_t) YYCURSOR - (size_t) yytext;
-#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
- {
- /* ignore whitespace */
-
- goto restart;
-}
-#line 1515 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c"
}
}
-#line 183 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l"
+#line 213 "sapi/phpdbg/phpdbg_lexer.l"
}
diff --git a/sapi/phpdbg/phpdbg_lexer.h b/sapi/phpdbg/phpdbg_lexer.h
index 89ef7668e5..355ce4ece0 100644
--- a/sapi/phpdbg/phpdbg_lexer.h
+++ b/sapi/phpdbg/phpdbg_lexer.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -28,6 +28,7 @@ typedef struct {
unsigned char *text;
unsigned char *cursor;
unsigned char *marker;
+ unsigned char *ctxmarker;
int state;
} phpdbg_lexer_data;
diff --git a/sapi/phpdbg/phpdbg_lexer.l b/sapi/phpdbg/phpdbg_lexer.l
index b9cdc65d22..422cda4f2c 100644
--- a/sapi/phpdbg/phpdbg_lexer.l
+++ b/sapi/phpdbg/phpdbg_lexer.l
@@ -14,6 +14,7 @@
#define YYGETCONDITION() LEX(state)
#define YYCURSOR LEX(cursor)
#define YYMARKER LEX(marker)
+#define YYCTXMARKER LEX(ctxmarker)
#define yyleng LEX(len)
#define yytext ((char*) LEX(text))
#undef YYDEBUG
@@ -25,7 +26,7 @@
#define RAW 2
#define INITIAL 3
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
void phpdbg_init_lexer (phpdbg_param_t *stack, char *input) {
PHPDBG_G(parser_stack) = stack;
@@ -36,6 +37,25 @@ void phpdbg_init_lexer (phpdbg_param_t *stack, char *input) {
LEX(len) = strlen(input);
}
+static int unescape_string(char *s) {
+ switch (*s) {
+ case '\'':
+ case '\"': {
+ char start = *s;
+ size_t off = 1;
+ do {
+ if (s[off] == '\\') {
+ off++;
+ }
+ *s = s[off];
+ } while ((++s)[off] != start);
+ return off + 1;
+ }
+ }
+
+ return 0;
+}
+
int phpdbg_lex (phpdbg_param_t* yylval) {
restart:
@@ -56,20 +76,21 @@ T_SHELL 'sh'
T_IF 'if'
T_RUN 'run'
T_RUN_SHORT "r"
-WS [ \r\n\t]+
+WS [ \r\t]+
DIGITS [-]?[0-9\.]+
ID [^ \r\n\t:#\000]+
+GENERIC_ID ([^ \r\n\t:#\000"']|":\\")+|["]([^\n\000"\\]|"\\\\"|"\\"["])+["]|[']([^\n\000'\\]|"\\\\"|"\\"['])+[']
ADDR [0][x][a-fA-F0-9]+
OPCODE (ZEND_|zend_)([A-Za-z])+
-INPUT [^\n\000]+
+INPUT ("\\"[#"']|["]("\\\\"|"\\"["]|[^\n\000"])+["]|[']("\\"[']|"\\\\"|[^\n\000'])+[']|[^\n\000#"'])+
<!*> := yyleng = (size_t) YYCURSOR - (size_t) yytext;
-<*>{WS}?[\n\000] {
+<*>[\n\000] {
return 0;
}
-<PRE_RAW, NORMAL>[-][r]{WS}?{DIGITS} {
+<PRE_RAW, NORMAL>"-r"{WS}?{DIGITS} {
char *text = yytext + 2;
while (*++text < '0');
yylval->num = atoi(text);
@@ -82,29 +103,37 @@ INPUT [^\n\000]+
return T_IF;
}
-<NORMAL>{ID}[:]{1}[//]{2} {
- phpdbg_init_param(yylval, STR_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
- yylval->len = yyleng;
- return T_PROTO;
-}
-<NORMAL>[#]{1} {
+<NORMAL>"#"/{DIGITS} {
return T_POUND;
}
-<NORMAL>[:]{2} {
+
+<*>"#" {
+ YYSETCONDITION(INITIAL);
+ return T_SEPARATOR;
+}
+
+<NORMAL>"::" {
return T_DCOLON;
}
-<NORMAL>[:]{1} {
+
+<NORMAL>":"/[^\\] {
return T_COLON;
}
-<NORMAL>({T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE}){WS} {
+<NORMAL>{ID}"://" {
+ phpdbg_init_param(yylval, STR_PARAM);
+ yylval->str = estrndup(yytext, yyleng);
+ yylval->len = yyleng;
+ return T_PROTO;
+}
+
+<NORMAL>({T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE})/[ \r\t\n\000] {
phpdbg_init_param(yylval, NUMERIC_PARAM);
yylval->num = 1;
return T_TRUTHY;
}
-<NORMAL>({T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE}){WS} {
+<NORMAL>({T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE})/[ \r\t\n\000] {
phpdbg_init_param(yylval, NUMERIC_PARAM);
yylval->num = 0;
return T_FALSY;
@@ -124,21 +153,21 @@ INPUT [^\n\000]+
<NORMAL>{OPCODE} {
phpdbg_init_param(yylval, OP_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
+ yylval->str = estrndup(yytext, yyleng);
yylval->len = yyleng;
return T_OPCODE;
}
-<NORMAL>{ID} {
+<NORMAL>{GENERIC_ID} {
phpdbg_init_param(yylval, STR_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
+ yylval->str = estrndup(yytext, yyleng - unescape_string(yytext));
yylval->len = yyleng;
return T_ID;
}
<RAW>{INPUT} {
phpdbg_init_param(yylval, STR_PARAM);
- yylval->str = zend_strndup(yytext, yyleng);
+ yylval->str = estrdup(yytext);
yylval->len = yyleng;
return T_INPUT;
}
@@ -154,25 +183,27 @@ INPUT [^\n\000]+
phpdbg_init_param(yylval, EMPTY_PARAM);
return T_EVAL;
}
+
<INITIAL>{T_SHELL}{WS} {
YYSETCONDITION(PRE_RAW);
phpdbg_init_param(yylval, EMPTY_PARAM);
return T_SHELL;
}
+
<INITIAL>({T_RUN}|{T_RUN_SHORT}){WS} {
YYSETCONDITION(PRE_RAW);
phpdbg_init_param(yylval, EMPTY_PARAM);
return T_RUN;
}
-<PRE_RAW>. {
+<PRE_RAW>[^ ] {
YYSETCONDITION(RAW);
YYCURSOR = LEX(text);
goto restart;
}
-<INITIAL>. {
+<INITIAL>[^ ] {
YYSETCONDITION(NORMAL);
YYCURSOR = LEX(text);
diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c
index 38804d551e..a1138b4517 100644
--- a/sapi/phpdbg/phpdbg_list.c
+++ b/sapi/phpdbg/phpdbg_list.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -31,8 +31,9 @@
#include "phpdbg_utils.h"
#include "phpdbg_prompt.h"
#include "php_streams.h"
+#include "zend_exceptions.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s, flags) \
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[12], flags)
@@ -61,9 +62,15 @@ PHPDBG_LIST(lines) /* {{{ */
} break;
case FILE_PARAM: {
- zend_string *file = zend_string_init(param->file.name, strlen(param->file.name), 0);
+ zend_string *file;
+ char resolved_path_buf[MAXPATHLEN];
+ const char *abspath = param->file.name;
+ if (VCWD_REALPATH(abspath, resolved_path_buf)) {
+ abspath = resolved_path_buf;
+ }
+ file = zend_string_init(abspath, strlen(abspath), 0);
phpdbg_list_file(file, param->file.line, 0, 0);
- efree(file);
+ zend_string_release(file);
} break;
phpdbg_default_switch_case();
@@ -110,10 +117,10 @@ PHPDBG_LIST(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);
} else {
- phpdbg_error("list", "type=\"nosource\" class=\"%s\"", "The source of the requested class (%s) cannot be found", ce->name);
+ phpdbg_error("list", "type=\"nosource\" class=\"%s\"", "The source of the requested class (%s) cannot be found", ZSTR_VAL(ce->name));
}
} else {
- phpdbg_error("list", "type=\"internalclass\" class=\"%s\"", "The class requested (%s) is not user defined", ce->name);
+ phpdbg_error("list", "type=\"internalclass\" class=\"%s\"", "The class requested (%s) is not user defined", ZSTR_VAL(ce->name));
}
} else {
phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "The requested class (%s) could not be found", param->str);
@@ -126,16 +133,8 @@ void phpdbg_list_file(zend_string *filename, uint count, int offset, uint highli
{
uint line, lastline;
phpdbg_file_source *data;
- char resolved_path_buf[MAXPATHLEN];
- const char *abspath;
- if (VCWD_REALPATH(ZSTR_VAL(filename), resolved_path_buf)) {
- abspath = resolved_path_buf;
- } else {
- abspath = ZSTR_VAL(filename);
- }
-
- if (!(data = zend_hash_str_find_ptr(&PHPDBG_G(file_sources), abspath, strlen(abspath)))) {
+ if (!(data = zend_hash_find_ptr(&PHPDBG_G(file_sources), filename))) {
phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file...");
return;
}
@@ -151,7 +150,7 @@ void phpdbg_list_file(zend_string *filename, uint count, int offset, uint highli
lastline = data->lines;
}
- phpdbg_xml("<list %r file=\"%s\">", filename);
+ phpdbg_xml("<list %r file=\"%s\">", ZSTR_VAL(filename));
for (line = offset; line < lastline;) {
uint linestart = data->line[line++];
@@ -199,11 +198,12 @@ void phpdbg_list_function_byname(const char *str, size_t len) /* {{{ */
/* search active scope if begins with period */
if (func_name[0] == '.') {
- if (EG(scope)) {
+ zend_class_entry *scope = zend_get_executed_scope();
+ if (scope) {
func_name++;
func_name_len--;
- func_table = &EG(scope)->function_table;
+ func_table = &scope->function_table;
} else {
phpdbg_error("inactive", "type=\"noclasses\"", "No active class");
return;
@@ -231,43 +231,37 @@ void phpdbg_list_function_byname(const char *str, size_t len) /* {{{ */
efree(func_name);
} /* }}} */
+/* Note: do not free the original file handler, let original compile_file() or caller do that. Caller may rely on its value to check success */
zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type) {
phpdbg_file_source data, *dataptr;
- zend_file_handle fake = {{0}};
+ zend_file_handle fake;
zend_op_array *ret;
- char *filename = (char *)(file->opened_path ? ZSTR_VAL(file->opened_path) : file->filename);
+ char *filename;
uint line;
char *bufptr, *endptr;
- char resolved_path_buf[MAXPATHLEN];
-
- zend_stream_fixup(file, &data.buf, &data.len);
- data.filename = filename;
- data.line[0] = 0;
-
- if (file->handle.stream.mmap.old_closer) {
- /* do not unmap */
- file->handle.stream.closer = file->handle.stream.mmap.old_closer;
+ if (zend_stream_fixup(file, &bufptr, &data.len) == FAILURE) {
+ return PHPDBG_G(compile_file)(file, type);
}
-#if HAVE_MMAP
- if (file->handle.stream.mmap.map) {
- data.map = file->handle.stream.mmap.map;
+ filename = (char *)(file->opened_path ? ZSTR_VAL(file->opened_path) : file->filename);
+
+ data.buf = emalloc(data.len + ZEND_MMAP_AHEAD + 1);
+ if (data.len > 0) {
+ memcpy(data.buf, bufptr, data.len);
}
-#endif
+ memset(data.buf + data.len, 0, ZEND_MMAP_AHEAD + 1);
+ data.line[0] = 0;
+ memset(&fake, 0, sizeof(fake));
fake.type = ZEND_HANDLE_MAPPED;
fake.handle.stream.mmap.buf = data.buf;
fake.handle.stream.mmap.len = data.len;
fake.free_filename = 0;
- fake.opened_path = file->opened_path;
fake.filename = filename;
fake.opened_path = file->opened_path;
*(dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * data.len)) = data;
- if (VCWD_REALPATH(filename, resolved_path_buf)) {
- filename = resolved_path_buf;
- }
for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) {
if (*bufptr == '\n') {
@@ -276,34 +270,121 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type) {
}
dataptr->lines = ++line;
dataptr->line[line] = endptr - data.buf;
- dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
-
- zend_hash_str_add_ptr(&PHPDBG_G(file_sources), filename, strlen(filename), dataptr);
- phpdbg_resolve_pending_file_break(filename);
ret = PHPDBG_G(compile_file)(&fake, type);
+ if (ret == NULL) {
+ efree(data.buf);
+ efree(dataptr);
+
+ fake.opened_path = NULL;
+ zend_file_handle_dtor(&fake);
+
+ return NULL;
+ }
+
+ dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
+ zend_hash_add_ptr(&PHPDBG_G(file_sources), ret->filename, dataptr);
+ phpdbg_resolve_pending_file_break(ZSTR_VAL(ret->filename));
+
fake.opened_path = NULL;
zend_file_handle_dtor(&fake);
return ret;
}
-void phpdbg_free_file_source(phpdbg_file_source *data) {
-#if HAVE_MMAP
- if (data->map) {
- munmap(data->map, data->len + ZEND_MMAP_AHEAD);
- } else
-#endif
- if (data->buf) {
- efree(data->buf);
+zend_op_array *phpdbg_init_compile_file(zend_file_handle *file, int type) {
+ char *filename = (char *)(file->opened_path ? ZSTR_VAL(file->opened_path) : file->filename);
+ char resolved_path_buf[MAXPATHLEN];
+ zend_op_array *op_array;
+ phpdbg_file_source *dataptr;
+
+ if (VCWD_REALPATH(filename, resolved_path_buf)) {
+ filename = resolved_path_buf;
+
+ if (file->opened_path) {
+ zend_string_release(file->opened_path);
+ file->opened_path = zend_string_init(filename, strlen(filename), 0);
+ } else {
+ if (file->free_filename) {
+ efree((char *) file->filename);
+ }
+ file->free_filename = 0;
+ file->filename = filename;
+ }
+ }
+
+ op_array = PHPDBG_G(init_compile_file)(file, type);
+
+ if (op_array == NULL) {
+ return NULL;
+ }
+
+ dataptr = zend_hash_find_ptr(&PHPDBG_G(file_sources), op_array->filename);
+ ZEND_ASSERT(dataptr != NULL);
+
+ dataptr->op_array = *op_array;
+ if (dataptr->op_array.refcount) {
+ ++*dataptr->op_array.refcount;
+ }
+
+ return op_array;
+}
+
+zend_op_array *phpdbg_compile_string(zval *source_string, char *filename) {
+ zend_string *fake_name;
+ zend_op_array *op_array;
+ phpdbg_file_source *dataptr;
+ uint line;
+ char *bufptr, *endptr;
+
+ if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) {
+ return PHPDBG_G(compile_string)(source_string, filename);
}
- efree(data);
+ dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * Z_STRLEN_P(source_string));
+ dataptr->buf = estrndup(Z_STRVAL_P(source_string), Z_STRLEN_P(source_string));
+ dataptr->len = Z_STRLEN_P(source_string);
+ dataptr->line[0] = 0;
+ for (line = 0, bufptr = dataptr->buf - 1, endptr = dataptr->buf + dataptr->len; ++bufptr < endptr;) {
+ if (*bufptr == '\n') {
+ dataptr->line[++line] = (uint)(bufptr - dataptr->buf) + 1;
+ }
+ }
+ dataptr->lines = ++line;
+ dataptr->line[line] = endptr - dataptr->buf;
+
+ op_array = PHPDBG_G(compile_string)(source_string, filename);
+
+ if (op_array == NULL) {
+ efree(dataptr->buf);
+ efree(dataptr);
+ return NULL;
+ }
+
+ fake_name = strpprintf(0, "%s%c%p", filename, 0, op_array->opcodes);
+
+ dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
+ zend_hash_add_ptr(&PHPDBG_G(file_sources), fake_name, dataptr);
+
+ zend_string_release(fake_name);
+
+ dataptr->op_array = *op_array;
+ if (dataptr->op_array.refcount) {
+ ++*dataptr->op_array.refcount;
+ }
+
+ return op_array;
}
void phpdbg_init_list(void) {
PHPDBG_G(compile_file) = zend_compile_file;
- zend_hash_init(&PHPDBG_G(file_sources), 1, NULL, (dtor_func_t) phpdbg_free_file_source, 0);
+ PHPDBG_G(compile_string) = zend_compile_string;
zend_compile_file = phpdbg_compile_file;
+ zend_compile_string = phpdbg_compile_string;
+}
+
+void phpdbg_list_update(void) {
+ PHPDBG_G(init_compile_file) = zend_compile_file;
+ zend_compile_file = phpdbg_init_compile_file;
}
diff --git a/sapi/phpdbg/phpdbg_list.h b/sapi/phpdbg/phpdbg_list.h
index 3436ddd8fb..9adb69b6c9 100644
--- a/sapi/phpdbg/phpdbg_list.h
+++ b/sapi/phpdbg/phpdbg_list.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -39,14 +39,15 @@ void phpdbg_list_file(zend_string *, uint, int, uint);
extern const phpdbg_command_t phpdbg_list_commands[];
void phpdbg_init_list(void);
+void phpdbg_list_update(void);
typedef struct {
- char *filename;
char *buf;
size_t len;
#if HAVE_MMAP
void *map;
#endif
+ zend_op_array op_array;
uint lines;
uint line[1];
} phpdbg_file_source;
diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c
index b64fa5c491..44119c9e51 100644
--- a/sapi/phpdbg/phpdbg_opcode.c
+++ b/sapi/phpdbg/phpdbg_opcode.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,22 +25,36 @@
#include "phpdbg_utils.h"
#include "ext/standard/php_string.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
-static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, uint32_t type) /* {{{ */
+static inline const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
+{
+ const char *ret = zend_get_opcode_name(opcode);
+ if (ret) {
+ return ret + 5; /* Skip ZEND_ prefix */
+ }
+ return "UNKNOWN";
+} /* }}} */
+
+static inline char *phpdbg_decode_op(
+ zend_op_array *ops, const znode_op *op, uint32_t type) /* {{{ */
{
char *decode = NULL;
switch (type) {
case IS_CV: {
zend_string *var = ops->vars[EX_VAR_TO_NUM(op->var)];
- asprintf(&decode, "$%.*s%c", ZSTR_LEN(var) <= 19 ? (int) ZSTR_LEN(var) : 18, ZSTR_VAL(var), ZSTR_LEN(var) <= 19 ? 0 : '+');
+ spprintf(&decode, 0, "$%.*s%c",
+ ZSTR_LEN(var) <= 19 ? (int) ZSTR_LEN(var) : 18,
+ ZSTR_VAL(var), ZSTR_LEN(var) <= 19 ? 0 : '+');
} break;
case IS_VAR:
- case IS_TMP_VAR: {
- asprintf(&decode, "@%" PRIu32, EX_VAR_TO_NUM(op->var) - ops->last_var);
- } break;
+ spprintf(&decode, 0, "@%u", EX_VAR_TO_NUM(op->var) - ops->last_var);
+ break;
+ case IS_TMP_VAR:
+ spprintf(&decode, 0, "~%u", EX_VAR_TO_NUM(op->var) - ops->last_var);
+ break;
case IS_CONST: {
zval *literal = RT_CONSTANT(ops, *op);
decode = phpdbg_short_zval_print(literal, 20);
@@ -49,94 +63,61 @@ static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, uint32_t
return decode;
} /* }}} */
-char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */
-{
- const char *opcode_name = phpdbg_decode_opcode(op->opcode);
- char *result, *decode[4] = {NULL, NULL, NULL, NULL};
-
- /* EX */
- switch (op->opcode) {
- case ZEND_FAST_CALL:
- if (op->extended_value != 0) {
- asprintf(&decode[0], "FAST_CALL<%s>",
- op->extended_value == ZEND_FAST_CALL_FROM_CATCH ? "FROM_CATCH" : "FROM_FINALLY");
+char *phpdbg_decode_input_op(
+ zend_op_array *ops, const zend_op *opline, znode_op op, zend_uchar op_type,
+ uint32_t flags) {
+ char *result = NULL;
+ if (op_type != IS_UNUSED) {
+ result = phpdbg_decode_op(ops, &op, op_type);
+ } else if (ZEND_VM_OP_JMP_ADDR == (flags & ZEND_VM_OP_MASK)) {
+ spprintf(&result, 0, "J%td", OP_JMP_ADDR(opline, op) - ops->opcodes);
+ } else if (ZEND_VM_OP_NUM == (flags & ZEND_VM_OP_MASK)) {
+ spprintf(&result, 0, "%" PRIu32, op.num);
+ } else if (ZEND_VM_OP_TRY_CATCH == (flags & ZEND_VM_OP_MASK)) {
+ if (op.num != (uint32_t)-1) {
+ spprintf(&result, 0, "try-catch(%" PRIu32 ")", op.num);
}
- break;
- case ZEND_FAST_RET:
- if (op->extended_value != 0) {
- asprintf(&decode[0], "FAST_RET<%s>",
- op->extended_value == ZEND_FAST_RET_TO_CATCH ? "TO_CATCH" : "TO_FINALLY");
+ } else if (ZEND_VM_OP_LIVE_RANGE == (flags & ZEND_VM_OP_MASK)) {
+ if (opline->extended_value & ZEND_FREE_ON_RETURN) {
+ spprintf(&result, 0, "live-range(%" PRIu32 ")", op.num);
}
- break;
+ } else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) {
+ result = estrdup("THIS");
+ } else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) {
+ result = estrdup("NEXT");
+ } else if (ZEND_VM_OP_CLASS_FETCH == (flags & ZEND_VM_OP_MASK)) {
+ //zend_dump_class_fetch_type(op.num);
+ } else if (ZEND_VM_OP_CONSTRUCTOR == (flags & ZEND_VM_OP_MASK)) {
+ result = estrdup("CONSTRUCTOR");
}
+ return result;
+}
- /* OP1 */
- switch (op->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- asprintf(&decode[1], "J%ld", OP_JMP_ADDR(op, op->op1) - ops->opcodes);
- break;
-
- case ZEND_INIT_FCALL:
- case ZEND_RECV:
- case ZEND_RECV_INIT:
- case ZEND_RECV_VARIADIC:
- asprintf(&decode[1], "%" PRIu32, op->op1.num);
- break;
+char *phpdbg_decode_opline(zend_op_array *ops, zend_op *opline) /*{{{ */
+{
+ const char *opcode_name = phpdbg_decode_opcode(opline->opcode);
+ uint32_t flags = zend_get_opcode_flags(opline->opcode);
+ char *result, *decode[4] = {NULL, NULL, NULL, NULL};
- default:
- decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type);
- break;
- }
+ /* OP1 */
+ decode[1] = phpdbg_decode_input_op(
+ ops, opline, opline->op1, opline->op1_type, ZEND_VM_OP1_FLAGS(flags));
/* OP2 */
- switch (op->opcode) {
- case ZEND_JMPZNZ:
- asprintf(&decode[2], "J%ld or J%ld", OP_JMP_ADDR(op, op->op2) - ops->opcodes, ZEND_OFFSET_TO_OPLINE(op, op->extended_value) - ops->opcodes);
- break;
-
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_ASSERT_CHECK:
- asprintf(&decode[2], "J%ld", OP_JMP_ADDR(op, op->op2) - ops->opcodes);
- break;
-
- case ZEND_FAST_CALL:
- case ZEND_FAST_RET:
- if (op->extended_value != 0) {
- asprintf(&decode[2], "J%" PRIu32, op->op2.opline_num);
- }
- break;
-
- case ZEND_SEND_VAL:
- case ZEND_SEND_VAL_EX:
- case ZEND_SEND_VAR:
- case ZEND_SEND_VAR_NO_REF:
- case ZEND_SEND_REF:
- case ZEND_SEND_VAR_EX:
- case ZEND_SEND_USER:
- asprintf(&decode[2], "%" PRIu32, op->op2.num);
- break;
-
- default:
- decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type);
- break;
- }
+ decode[2] = phpdbg_decode_input_op(
+ ops, opline, opline->op2, opline->op2_type, ZEND_VM_OP2_FLAGS(flags));
/* RESULT */
- switch (op->opcode) {
+ switch (opline->opcode) {
case ZEND_CATCH:
- asprintf(&decode[2], "%" PRIu32, op->result.num);
+ spprintf(&decode[3], 0, "%" PRIu32, opline->result.num);
break;
default:
- decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type);
+ decode[3] = phpdbg_decode_op(ops, &opline->result, opline->result_type);
break;
}
- asprintf(&result,
+ spprintf(&result, 0,
"%-23s %-20s %-20s %-20s",
decode[0] ? decode[0] : opcode_name,
decode[1] ? decode[1] : "",
@@ -144,13 +125,13 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */
decode[3] ? decode[3] : "");
if (decode[0])
- free(decode[0]);
+ efree(decode[0]);
if (decode[1])
- free(decode[1]);
+ efree(decode[1]);
if (decode[2])
- free(decode[2]);
+ efree(decode[2]);
if (decode[3])
- free(decode[3]);
+ efree(decode[3]);
return result;
} /* }}} */
@@ -176,22 +157,24 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, zend_bool ignore_fl
}
if (!ignore_flags && PHPDBG_G(oplog)) {
- phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %s %s",
+ phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %s %s\n",
opline->lineno,
opline,
decode,
execute_data->func->op_array.filename ? ZSTR_VAL(execute_data->func->op_array.filename) : "unknown");
}
- if (decode) {
- free(decode);
- }
+ efree(decode);
}
if (PHPDBG_G(oplog_list)) {
phpdbg_oplog_entry *cur = zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry));
+ zend_op_array *op_array = &execute_data->func->op_array;
cur->op = (zend_op *) execute_data->opline;
- cur->op_array = &execute_data->func->op_array;
+ cur->opcodes = op_array->opcodes;
+ cur->filename = op_array->filename;
+ cur->scope = op_array->scope;
+ cur->function_name = op_array->function_name;
cur->next = NULL;
PHPDBG_G(oplog_cur)->next = cur;
PHPDBG_G(oplog_cur) = cur;
@@ -202,12 +185,3 @@ void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags
{
phpdbg_print_opline_ex(execute_data, ignore_flags);
} /* }}} */
-
-const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
-{
- const char *ret = zend_get_opcode_name(opcode);
- if (ret) {
- return ret + 5; /* Skip ZEND_ prefix */
- }
- return "UNKNOWN";
-} /* }}} */
diff --git a/sapi/phpdbg/phpdbg_opcode.h b/sapi/phpdbg/phpdbg_opcode.h
index ab7e9e261d..2831748236 100644
--- a/sapi/phpdbg/phpdbg_opcode.h
+++ b/sapi/phpdbg/phpdbg_opcode.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -23,7 +23,6 @@
#include "zend_types.h"
-const char *phpdbg_decode_opcode(zend_uchar);
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op);
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags);
void phpdbg_print_opline_ex(zend_execute_data *execute_data, zend_bool ignore_flags);
@@ -31,7 +30,10 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, zend_bool ignore_fl
typedef struct _phpdbg_oplog_entry phpdbg_oplog_entry;
struct _phpdbg_oplog_entry {
phpdbg_oplog_entry *next;
- zend_op_array *op_array;
+ zend_string *function_name;
+ zend_class_entry *scope;
+ zend_string *filename;
+ zend_op *opcodes;
zend_op *op;
};
diff --git a/sapi/phpdbg/phpdbg_out.c b/sapi/phpdbg/phpdbg_out.c
index cd9a4acaa0..90940ca68c 100644
--- a/sapi/phpdbg/phpdbg_out.c
+++ b/sapi/phpdbg/phpdbg_out.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -30,7 +30,7 @@
# include "win32/time.h"
#endif
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
/* copied from php-src/main/snprintf.c and slightly modified */
/*
@@ -1281,6 +1281,7 @@ PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) {
len = phpdbg_mixed_write(fd, buffer, buflen);
}
+ efree(buffer);
return len;
}
diff --git a/sapi/phpdbg/phpdbg_out.h b/sapi/phpdbg/phpdbg_out.h
index 74bbbad980..a6f28da14d 100644
--- a/sapi/phpdbg/phpdbg_out.h
+++ b/sapi/phpdbg/phpdbg_out.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -34,20 +34,11 @@ enum {
P_LOG
};
-#ifdef ZTS
-PHPDBG_API int phpdbg_print(int severity, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 6, 7);
-PHPDBG_API int phpdbg_xml_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
-PHPDBG_API int phpdbg_log_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
-PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
-PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
-#else
PHPDBG_API int phpdbg_print(int severity, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6);
PHPDBG_API int phpdbg_xml_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
PHPDBG_API int phpdbg_log_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
-#endif
-
#define phpdbg_error(tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR , PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__)
#define phpdbg_notice(tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE , PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__)
@@ -63,9 +54,9 @@ PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_
#define phpdbg_writeln_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN, out, tag, xmlfmt, strfmt, ##__VA_ARGS__)
#define phpdbg_write_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE , out, tag, xmlfmt, strfmt, ##__VA_ARGS__)
#define phpdbg_script_ex(out, type, fmt, ...) phpdbg_print(type , out, NULL, NULL, fmt, ##__VA_ARGS__)
-#define phpdbg_log_ex(out, fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
-#define phpdbg_xml_ex(out, fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
-#define phpdbg_out_ex(out, fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd, fmt, ##__VA_ARGS__)
+#define phpdbg_log_ex(out, fmt, ...) phpdbg_log_internal(out, fmt, ##__VA_ARGS__)
+#define phpdbg_xml_ex(out, fmt, ...) phpdbg_xml_internal(out, fmt, ##__VA_ARGS__)
+#define phpdbg_out_ex(out, fmt, ...) phpdbg_out_internal(out, fmt, ##__VA_ARGS__)
#define phpdbg_rlog(fd, fmt, ...) phpdbg_rlog_internal(fd, fmt, ##__VA_ARGS__)
diff --git a/sapi/phpdbg/phpdbg_parser.c b/sapi/phpdbg/phpdbg_parser.c
index ed976f0b3f..da08df2199 100644
--- a/sapi/phpdbg/phpdbg_parser.c
+++ b/sapi/phpdbg/phpdbg_parser.c
@@ -1,21 +1,19 @@
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
-/* A Bison parser, made by GNU Bison 2.4.1. */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@@ -28,7 +26,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -46,7 +44,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.4.1"
+#define YYBISON_VERSION "2.7.12-4996"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -60,8 +58,6 @@
/* Pull parsers. */
#define YYPULL 1
-/* Using locations. */
-#define YYLSP_NEEDED 0
/* Substitute the variable and function names. */
#define yyparse phpdbg_parse
@@ -72,10 +68,8 @@
#define yydebug phpdbg_debug
#define yynerrs phpdbg_nerrs
-
/* Copy the first part of user declarations. */
-
-/* Line 189 of yacc.c */
+/* Line 371 of yacc.c */
#line 1 "sapi/phpdbg/phpdbg_parser.y"
@@ -100,17 +94,24 @@
#undef yyerror
static int yyerror(const char *msg);
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
+#ifdef _MSC_VER
+#define YYMALLOC malloc
+#define YYFREE free
+#endif
-/* Line 189 of yacc.c */
-#line 109 "sapi/phpdbg/phpdbg_parser.c"
+/* Line 371 of yacc.c */
+#line 107 "sapi/phpdbg/phpdbg_parser.c"
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
/* Enabling verbose error messages. */
#ifdef YYERROR_VERBOSE
@@ -120,15 +121,20 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
# define YYERROR_VERBOSE 1
#endif
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+ by #include "phpdbg_parser.h". */
+#ifndef YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
+# define YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int phpdbg_debug;
#endif
-
/* "%code requires" blocks. */
-
-/* Line 209 of yacc.c */
-#line 31 "sapi/phpdbg/phpdbg_parser.y"
+/* Line 387 of yacc.c */
+#line 36 "sapi/phpdbg/phpdbg_parser.y"
#include "phpdbg.h"
#ifndef YY_TYPEDEF_YY_SCANNER_T
@@ -137,9 +143,8 @@ typedef void* yyscan_t;
#endif
-
-/* Line 209 of yacc.c */
-#line 143 "sapi/phpdbg/phpdbg_parser.c"
+/* Line 387 of yacc.c */
+#line 148 "sapi/phpdbg/phpdbg_parser.c"
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -157,17 +162,39 @@ typedef void* yyscan_t;
T_COLON = 265,
T_DCOLON = 266,
T_POUND = 267,
- T_PROTO = 268,
- T_DIGITS = 269,
- T_LITERAL = 270,
- T_ADDR = 271,
- T_OPCODE = 272,
- T_ID = 273,
- T_INPUT = 274,
- T_UNEXPECTED = 275,
- T_REQ_ID = 276
+ T_SEPARATOR = 268,
+ T_PROTO = 269,
+ T_DIGITS = 270,
+ T_LITERAL = 271,
+ T_ADDR = 272,
+ T_OPCODE = 273,
+ T_ID = 274,
+ T_INPUT = 275,
+ T_UNEXPECTED = 276,
+ T_REQ_ID = 277
};
#endif
+/* Tokens. */
+#define T_EVAL 258
+#define T_RUN 259
+#define T_SHELL 260
+#define T_IF 261
+#define T_TRUTHY 262
+#define T_FALSY 263
+#define T_STRING 264
+#define T_COLON 265
+#define T_DCOLON 266
+#define T_POUND 267
+#define T_SEPARATOR 268
+#define T_PROTO 269
+#define T_DIGITS 270
+#define T_LITERAL 271
+#define T_ADDR 272
+#define T_OPCODE 273
+#define T_ID 274
+#define T_INPUT 275
+#define T_UNEXPECTED 276
+#define T_REQ_ID 277
@@ -179,11 +206,26 @@ typedef int YYSTYPE;
#endif
-/* Copy the second part of user declarations. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int phpdbg_parse (void *YYPARSE_PARAM);
+#else
+int phpdbg_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int phpdbg_parse (void);
+#else
+int phpdbg_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+#endif /* !YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */
-/* Line 264 of yacc.c */
-#line 187 "sapi/phpdbg/phpdbg_parser.c"
+/* Copy the second part of user declarations. */
+
+/* Line 390 of yacc.c */
+#line 229 "sapi/phpdbg/phpdbg_parser.c"
#ifdef short
# undef short
@@ -233,27 +275,36 @@ typedef short int yytype_int16;
#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
#ifndef YY_
-# if YYENABLE_NLS
+# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
# endif
# endif
# ifndef YY_
-# define YY_(msgid) msgid
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+# define __attribute__(Spec) /* empty */
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
#else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
#endif
+
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
@@ -286,11 +337,12 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
# endif
# endif
# endif
@@ -313,24 +365,24 @@ YYID (yyi)
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
-# if (defined __cplusplus && ! defined _STDLIB_H \
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef _STDLIB_H
-# define _STDLIB_H 1
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
@@ -359,23 +411,7 @@ union yyalloc
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
+# define YYCOPY_NEEDED 1
/* Relocate STACK from its old location to the new one. The
local variables YYSIZE and YYSTACKSIZE give the old and new number of
@@ -395,23 +431,43 @@ union yyalloc
#endif
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
/* YYFINAL -- State number of the termination state. */
-#define YYFINAL 26
+#define YYFINAL 27
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 48
+#define YYLAST 50
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 22
+#define YYNTOKENS 23
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 6
+#define YYNNTS 7
/* YYNRULES -- Number of rules. */
-#define YYNRULES 28
+#define YYNRULES 30
/* YYNRULES -- Number of states. */
-#define YYNSTATES 43
+#define YYNSTATES 46
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 276
+#define YYMAXUTOK 277
#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -446,7 +502,7 @@ static const yytype_uint8 yytranslate[] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21
+ 15, 16, 17, 18, 19, 20, 21, 22
};
#if YYDEBUG
@@ -454,35 +510,38 @@ static const yytype_uint8 yytranslate[] =
YYRHS. */
static const yytype_uint8 yyprhs[] =
{
- 0, 0, 3, 5, 7, 8, 10, 13, 16, 20,
- 25, 30, 36, 40, 46, 50, 53, 55, 57, 59,
- 61, 63, 65, 67, 69, 70, 74, 78, 81
+ 0, 0, 3, 5, 9, 10, 12, 14, 16, 19,
+ 22, 26, 31, 36, 42, 46, 52, 56, 59, 61,
+ 63, 65, 67, 69, 71, 73, 75, 76, 80, 84,
+ 87
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
- 23, 0, -1, 24, -1, 27, -1, -1, 25, -1,
- 24, 25, -1, 24, 26, -1, 18, 10, 14, -1,
- 18, 10, 12, 14, -1, 13, 18, 10, 14, -1,
- 13, 18, 10, 12, 14, -1, 18, 11, 18, -1,
- 18, 11, 18, 12, 14, -1, 18, 12, 14, -1,
- 6, 19, -1, 17, -1, 16, -1, 15, -1, 7,
- -1, 8, -1, 14, -1, 18, -1, 21, -1, -1,
- 3, 26, 19, -1, 5, 26, 19, -1, 4, 26,
- -1, 4, 26, 19, -1
+ 24, 0, -1, 25, -1, 24, 13, 25, -1, -1,
+ 26, -1, 29, -1, 27, -1, 26, 27, -1, 26,
+ 28, -1, 19, 10, 15, -1, 19, 10, 12, 15,
+ -1, 14, 19, 10, 15, -1, 14, 19, 10, 12,
+ 15, -1, 19, 11, 19, -1, 19, 11, 19, 12,
+ 15, -1, 19, 12, 15, -1, 6, 20, -1, 18,
+ -1, 17, -1, 16, -1, 7, -1, 8, -1, 15,
+ -1, 19, -1, 22, -1, -1, 3, 28, 20, -1,
+ 5, 28, 20, -1, 4, 28, -1, 4, 28, 20,
+ -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint8 yyrline[] =
{
- 0, 65, 65, 66, 67, 71, 72, 73, 77, 82,
- 87, 97, 107, 112, 118, 124, 129, 130, 131, 132,
- 133, 134, 135, 139, 140, 144, 149, 154, 158
+ 0, 71, 71, 72, 73, 77, 78, 82, 83, 84,
+ 88, 93, 98, 108, 118, 123, 129, 135, 140, 141,
+ 142, 143, 144, 145, 146, 150, 151, 155, 160, 165,
+ 169
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 1
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
@@ -491,12 +550,13 @@ static const char *const yytname[] =
"\"if (condition)\"", "\"truthy (true, on, yes or enabled)\"",
"\"falsy (false, off, no or disabled)\"",
"\"string (some input, perhaps)\"", "\": (colon)\"",
- "\":: (double colon)\"", "\"# (pound sign)\"", "\"protocol (file://)\"",
- "\"digits (numbers)\"", "\"literal (string)\"", "\"address\"",
- "\"opcode\"", "\"identifier (command or function name)\"",
+ "\":: (double colon)\"", "\"# (pound sign followed by digits)\"",
+ "\"# (pound sign)\"", "\"protocol (file://)\"", "\"digits (numbers)\"",
+ "\"literal (string)\"", "\"address\"", "\"opcode\"",
+ "\"identifier (command or function name)\"",
"\"input (input string or data)\"", "\"input\"",
- "\"request id (-r %d)\"", "$accept", "input", "parameters", "parameter",
- "req_id", "full_expression", 0
+ "\"request id (-r %d)\"", "$accept", "input", "command", "parameters",
+ "parameter", "req_id", "full_expression", YY_NULL
};
#endif
@@ -507,94 +567,103 @@ static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
- 275, 276
+ 275, 276, 277
};
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 22, 23, 23, 23, 24, 24, 24, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 26, 26, 27, 27, 27, 27
+ 0, 23, 24, 24, 24, 25, 25, 26, 26, 26,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 28, 28, 29, 29, 29,
+ 29
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
static const yytype_uint8 yyr2[] =
{
- 0, 2, 1, 1, 0, 1, 2, 2, 3, 4,
- 4, 5, 3, 5, 3, 2, 1, 1, 1, 1,
- 1, 1, 1, 1, 0, 3, 3, 2, 3
+ 0, 2, 1, 3, 0, 1, 1, 1, 2, 2,
+ 3, 4, 4, 5, 3, 5, 3, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 0, 3, 3, 2,
+ 3
};
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
- STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 4, 24, 24, 24, 0, 19, 20, 0, 21, 18,
- 17, 16, 22, 0, 2, 5, 3, 23, 0, 27,
- 0, 15, 0, 0, 0, 0, 1, 6, 7, 25,
- 28, 26, 0, 0, 8, 12, 14, 0, 10, 9,
- 0, 11, 13
+ 4, 26, 26, 26, 0, 21, 22, 0, 23, 20,
+ 19, 18, 24, 0, 2, 5, 7, 6, 25, 0,
+ 29, 0, 17, 0, 0, 0, 0, 1, 0, 8,
+ 9, 27, 30, 28, 0, 0, 10, 14, 16, 3,
+ 0, 12, 11, 0, 13, 15
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] =
{
- -1, 13, 14, 15, 18, 16
+ -1, 13, 14, 15, 16, 19, 17
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -16
+#define YYPACT_NINF -17
static const yytype_int8 yypact[] =
{
- -3, -15, -15, -15, -10, -16, -16, 3, -16, -16,
- -16, -16, 22, 29, 10, -16, -16, -16, 11, 17,
- 19, -16, 30, 8, 21, 27, -16, -16, -16, -16,
- -16, -16, 23, 28, -16, 31, -16, 32, -16, -16,
- 33, -16, -16
+ -3, -16, -16, -16, -10, -17, -17, 2, -17, -17,
+ -17, -17, 26, 9, -17, 11, -17, -17, -17, 3,
+ 4, 21, -17, 29, 19, 23, 25, -17, -3, -17,
+ -17, -17, -17, -17, 20, 28, -17, 32, -17, -17,
+ 30, -17, -17, 31, -17, -17
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] =
{
- -16, -16, -16, 34, 5, -16
+ -17, -17, 22, -17, 33, 5, -17
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
- number is the opposite. If zero, do what YYDEFACT says.
- If YYTABLE_NINF, syntax error. */
+ number is the opposite. If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -1
static const yytype_uint8 yytable[] =
{
- 1, 2, 3, 4, 5, 6, 17, 19, 20, 21,
- 7, 8, 9, 10, 11, 12, 4, 5, 6, 28,
- 33, 22, 34, 7, 8, 9, 10, 11, 12, 26,
- 29, 17, 23, 24, 25, 37, 30, 38, 31, 35,
- 32, 36, 39, 40, 0, 0, 41, 42, 27
+ 1, 2, 3, 4, 5, 6, 18, 20, 21, 27,
+ 22, 7, 8, 9, 10, 11, 12, 4, 5, 6,
+ 30, 23, 28, 31, 32, 7, 8, 9, 10, 11,
+ 12, 35, 40, 18, 36, 41, 24, 25, 26, 34,
+ 38, 33, 37, 42, 43, 44, 45, 0, 29, 0,
+ 39
};
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-17)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
static const yytype_int8 yycheck[] =
{
- 3, 4, 5, 6, 7, 8, 21, 2, 3, 19,
- 13, 14, 15, 16, 17, 18, 6, 7, 8, 14,
- 12, 18, 14, 13, 14, 15, 16, 17, 18, 0,
- 19, 21, 10, 11, 12, 12, 19, 14, 19, 18,
- 10, 14, 14, 12, -1, -1, 14, 14, 14
+ 3, 4, 5, 6, 7, 8, 22, 2, 3, 0,
+ 20, 14, 15, 16, 17, 18, 19, 6, 7, 8,
+ 15, 19, 13, 20, 20, 14, 15, 16, 17, 18,
+ 19, 12, 12, 22, 15, 15, 10, 11, 12, 10,
+ 15, 20, 19, 15, 12, 15, 15, -1, 15, -1,
+ 28
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
- 0, 3, 4, 5, 6, 7, 8, 13, 14, 15,
- 16, 17, 18, 23, 24, 25, 27, 21, 26, 26,
- 26, 19, 18, 10, 11, 12, 0, 25, 26, 19,
- 19, 19, 10, 12, 14, 18, 14, 12, 14, 14,
- 12, 14, 14
+ 0, 3, 4, 5, 6, 7, 8, 14, 15, 16,
+ 17, 18, 19, 24, 25, 26, 27, 29, 22, 28,
+ 28, 28, 20, 19, 10, 11, 12, 0, 13, 27,
+ 28, 20, 20, 20, 10, 12, 15, 19, 15, 25,
+ 12, 15, 15, 12, 15, 15
};
#define yyerrok (yyerrstatus = 0)
@@ -609,78 +678,50 @@ static const yytype_uint8 yystos[] =
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (YYID (0))
-
+/* Error token number */
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
- This macro was not mandated originally: define only if we know
- we won't break user code: when these are the locations we know. */
-
+/* This macro is provided for backward compatibility. */
#ifndef YY_LOCATION_PRINT
-# if YYLTYPE_IS_TRIVIAL
-# define YY_LOCATION_PRINT(File, Loc) \
- fprintf (File, "%d.%d-%d.%d", \
- (Loc).first_line, (Loc).first_column, \
- (Loc).last_line, (Loc).last_column)
-# else
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
-
#ifdef YYLEX_PARAM
# define YYLEX yylex (&yylval, YYLEX_PARAM)
#else
@@ -730,6 +771,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
YYSTYPE const * const yyvaluep;
#endif
{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
if (!yyvaluep)
return;
# ifdef YYPRINT
@@ -738,11 +781,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
# else
YYUSE (yyoutput);
# endif
- switch (yytype)
- {
- default:
- break;
- }
+ YYUSE (yytype);
}
@@ -868,7 +907,6 @@ int yydebug;
#endif
-
#if YYERROR_VERBOSE
# ifndef yystrlen
@@ -970,116 +1008,146 @@ yytnamerr (char *yyres, const char *yystr)
}
# endif
-/* Copy into YYRESULT an error message about the unexpected token
- YYCHAR while in state YYSTATE. Return the number of bytes copied,
- including the terminating null byte. If YYRESULT is null, do not
- copy anything; just return the number of bytes that would be
- copied. As a special case, return 0 if an ordinary "syntax error"
- message will do. Return YYSIZE_MAXIMUM if overflow occurs during
- size calculation. */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
- int yyn = yypact[yystate];
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
- if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
- return 0;
- else
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
{
- int yytype = YYTRANSLATE (yychar);
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- int yysize_overflow = 0;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- int yyx;
-
-# if 0
- /* This is so xgettext sees the translatable formats that are
- constructed on the fly. */
- YY_("syntax error, unexpected %s");
- YY_("syntax error, unexpected %s, expecting %s");
- YY_("syntax error, unexpected %s, expecting %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s");
- YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
- char *yyfmt;
- char const *yyf;
- static char const yyunexpected[] = "syntax error, unexpected %s";
- static char const yyexpecting[] = ", expecting %s";
- static char const yyor[] = " or %s";
- char yyformat[sizeof yyunexpected
- + sizeof yyexpecting - 1
- + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
- * (sizeof yyor - 1))];
- char const *yyprefix = yyexpecting;
-
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
-
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yycount = 1;
-
- yyarg[0] = yytname[yytype];
- yyfmt = yystpcpy (yyformat, yyunexpected);
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- yyformat[sizeof yyunexpected - 1] = '\0';
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
- yyfmt = yystpcpy (yyfmt, yyprefix);
- yyprefix = yyor;
- }
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
- yyf = YY_(yyformat);
- yysize1 = yysize + yystrlen (yyf);
- yysize_overflow |= (yysize1 < yysize);
- yysize = yysize1;
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
- if (yysize_overflow)
- return YYSIZE_MAXIMUM;
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
- if (yyresult)
- {
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- char *yyp = yyresult;
- int yyi = 0;
- while ((*yyp = *yyf) != '\0')
- {
- if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyf += 2;
- }
- else
- {
- yyp++;
- yyf++;
- }
- }
- }
- return yysize;
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
}
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
}
#endif /* YYERROR_VERBOSE */
-
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
@@ -1103,36 +1171,15 @@ yydestruct (yymsg, yytype, yyvaluep)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
- switch (yytype)
- {
-
- default:
- break;
- }
+ YYUSE (yytype);
}
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-/*-------------------------.
-| yyparse or yypush_parse. |
-`-------------------------*/
+/*----------.
+| yyparse. |
+`----------*/
#ifdef YYPARSE_PARAM
#if (defined __STDC__ || defined __C99__FUNC__ \
@@ -1159,8 +1206,31 @@ yyparse ()
/* The lookahead symbol. */
int yychar;
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+static YYSTYPE yyval_default;
+# define YY_INITIAL_VALUE(Value) = Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
/* Number of syntax errors so far. */
int yynerrs;
@@ -1173,7 +1243,7 @@ YYSTYPE yylval;
`yyss': related to states.
`yyvs': related to semantic values.
- Refer to the stacks thru separate pointers, to allow yyoverflow
+ Refer to the stacks through separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
/* The state stack. */
@@ -1191,7 +1261,7 @@ YYSTYPE yylval;
int yyn;
int yyresult;
/* Lookahead token as an internal (translated) token number. */
- int yytoken;
+ int yytoken = 0;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
@@ -1209,9 +1279,8 @@ YYSTYPE yylval;
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1220,14 +1289,6 @@ YYSTYPE yylval;
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
-
goto yysetstate;
/*------------------------------------------------------------.
@@ -1319,7 +1380,7 @@ yybackup:
/* First try to decide what to do without reference to lookahead token. */
yyn = yypact[yystate];
- if (yyn == YYPACT_NINF)
+ if (yypact_value_is_default (yyn))
goto yydefault;
/* Not known => get a lookahead token if don't already have one. */
@@ -1350,8 +1411,8 @@ yybackup:
yyn = yytable[yyn];
if (yyn <= 0)
{
- if (yyn == 0 || yyn == YYTABLE_NINF)
- goto yyerrlab;
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
@@ -1368,7 +1429,9 @@ yybackup:
yychar = YYEMPTY;
yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1404,60 +1467,71 @@ yyreduce:
YY_REDUCE_PRINT (yyn);
switch (yyn)
{
- case 3:
+ case 2:
+/* Line 1802 of yacc.c */
+#line 71 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
+ break;
-/* Line 1455 of yacc.c */
-#line 66 "sapi/phpdbg/phpdbg_parser.y"
- { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); ;}
+ case 3:
+/* Line 1802 of yacc.c */
+#line 72 "sapi/phpdbg/phpdbg_parser.y"
+ { phpdbg_stack_separate((yyvsp[(1) - (3)]).top); (yyval) = (yyvsp[(3) - (3)]); }
break;
case 5:
-
-/* Line 1455 of yacc.c */
-#line 71 "sapi/phpdbg/phpdbg_parser.y"
- { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); ;}
+/* Line 1802 of yacc.c */
+#line 77 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval).top = PHPDBG_G(parser_stack)->top; }
break;
case 6:
-
-/* Line 1455 of yacc.c */
-#line 72 "sapi/phpdbg/phpdbg_parser.y"
- { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); ;}
+/* Line 1802 of yacc.c */
+#line 78 "sapi/phpdbg/phpdbg_parser.y"
+ { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); (yyval).top = PHPDBG_G(parser_stack)->top; }
break;
case 7:
-
-/* Line 1455 of yacc.c */
-#line 73 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (2)]); ;}
+/* Line 1802 of yacc.c */
+#line 82 "sapi/phpdbg/phpdbg_parser.y"
+ { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); (yyval).top = PHPDBG_G(parser_stack)->top; }
break;
case 8:
+/* Line 1802 of yacc.c */
+#line 83 "sapi/phpdbg/phpdbg_parser.y"
+ { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); (yyval).top = PHPDBG_G(parser_stack)->top; }
+ break;
-/* Line 1455 of yacc.c */
-#line 77 "sapi/phpdbg/phpdbg_parser.y"
+ case 9:
+/* Line 1802 of yacc.c */
+#line 84 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (2)]); }
+ break;
+
+ case 10:
+/* Line 1802 of yacc.c */
+#line 88 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = FILE_PARAM;
(yyval).file.name = (yyvsp[(2) - (3)]).str;
(yyval).file.line = (yyvsp[(3) - (3)]).num;
- ;}
+ }
break;
- case 9:
-
-/* Line 1455 of yacc.c */
-#line 82 "sapi/phpdbg/phpdbg_parser.y"
+ case 11:
+/* Line 1802 of yacc.c */
+#line 93 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_FILE_PARAM;
(yyval).file.name = (yyvsp[(1) - (4)]).str;
(yyval).file.line = (yyvsp[(4) - (4)]).num;
- ;}
+ }
break;
- case 10:
-
-/* Line 1455 of yacc.c */
-#line 87 "sapi/phpdbg/phpdbg_parser.y"
+ case 12:
+/* Line 1802 of yacc.c */
+#line 98 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = FILE_PARAM;
(yyval).file.name = malloc((yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len + 1);
@@ -1467,13 +1541,12 @@ yyreduce:
(yyval).file.name[(yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len] = '\0';
}
(yyval).file.line = (yyvsp[(4) - (4)]).num;
- ;}
+ }
break;
- case 11:
-
-/* Line 1455 of yacc.c */
-#line 97 "sapi/phpdbg/phpdbg_parser.y"
+ case 13:
+/* Line 1802 of yacc.c */
+#line 108 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_FILE_PARAM;
(yyval).file.name = malloc((yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len + 1);
@@ -1483,160 +1556,154 @@ yyreduce:
(yyval).file.name[(yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len] = '\0';
}
(yyval).file.line = (yyvsp[(5) - (5)]).num;
- ;}
+ }
break;
- case 12:
-
-/* Line 1455 of yacc.c */
-#line 107 "sapi/phpdbg/phpdbg_parser.y"
+ case 14:
+/* Line 1802 of yacc.c */
+#line 118 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = METHOD_PARAM;
(yyval).method.class = (yyvsp[(1) - (3)]).str;
(yyval).method.name = (yyvsp[(3) - (3)]).str;
- ;}
+ }
break;
- case 13:
-
-/* Line 1455 of yacc.c */
-#line 112 "sapi/phpdbg/phpdbg_parser.y"
+ case 15:
+/* Line 1802 of yacc.c */
+#line 123 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_METHOD_PARAM;
(yyval).method.class = (yyvsp[(1) - (5)]).str;
(yyval).method.name = (yyvsp[(3) - (5)]).str;
(yyval).num = (yyvsp[(5) - (5)]).num;
- ;}
+ }
break;
- case 14:
-
-/* Line 1455 of yacc.c */
-#line 118 "sapi/phpdbg/phpdbg_parser.y"
+ case 16:
+/* Line 1802 of yacc.c */
+#line 129 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = NUMERIC_FUNCTION_PARAM;
(yyval).str = (yyvsp[(1) - (3)]).str;
(yyval).len = (yyvsp[(1) - (3)]).len;
(yyval).num = (yyvsp[(3) - (3)]).num;
- ;}
+ }
break;
- case 15:
-
-/* Line 1455 of yacc.c */
-#line 124 "sapi/phpdbg/phpdbg_parser.y"
+ case 17:
+/* Line 1802 of yacc.c */
+#line 135 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = COND_PARAM;
(yyval).str = (yyvsp[(2) - (2)]).str;
(yyval).len = (yyvsp[(2) - (2)]).len;
- ;}
- break;
-
- case 16:
-
-/* Line 1455 of yacc.c */
-#line 129 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (1)]); ;}
- break;
-
- case 17:
-
-/* Line 1455 of yacc.c */
-#line 130 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (1)]); ;}
+ }
break;
case 18:
-
-/* Line 1455 of yacc.c */
-#line 131 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (1)]); ;}
+/* Line 1802 of yacc.c */
+#line 140 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
break;
case 19:
-
-/* Line 1455 of yacc.c */
-#line 132 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (1)]); ;}
+/* Line 1802 of yacc.c */
+#line 141 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
break;
case 20:
-
-/* Line 1455 of yacc.c */
-#line 133 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (1)]); ;}
+/* Line 1802 of yacc.c */
+#line 142 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
break;
case 21:
-
-/* Line 1455 of yacc.c */
-#line 134 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (1)]); ;}
+/* Line 1802 of yacc.c */
+#line 143 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
break;
case 22:
-
-/* Line 1455 of yacc.c */
-#line 135 "sapi/phpdbg/phpdbg_parser.y"
- { (yyval) = (yyvsp[(1) - (1)]); ;}
+/* Line 1802 of yacc.c */
+#line 144 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
break;
case 23:
+/* Line 1802 of yacc.c */
+#line 145 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
+ break;
-/* Line 1455 of yacc.c */
-#line 139 "sapi/phpdbg/phpdbg_parser.y"
- { PHPDBG_G(req_id) = (yyvsp[(1) - (1)]).num; ;}
+ case 24:
+/* Line 1802 of yacc.c */
+#line 146 "sapi/phpdbg/phpdbg_parser.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
break;
case 25:
+/* Line 1802 of yacc.c */
+#line 150 "sapi/phpdbg/phpdbg_parser.y"
+ { PHPDBG_G(req_id) = (yyvsp[(1) - (1)]).num; }
+ break;
-/* Line 1455 of yacc.c */
-#line 144 "sapi/phpdbg/phpdbg_parser.y"
+ case 27:
+/* Line 1802 of yacc.c */
+#line 155 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = EVAL_PARAM;
(yyval).str = (yyvsp[(3) - (3)]).str;
(yyval).len = (yyvsp[(3) - (3)]).len;
- ;}
+ }
break;
- case 26:
-
-/* Line 1455 of yacc.c */
-#line 149 "sapi/phpdbg/phpdbg_parser.y"
+ case 28:
+/* Line 1802 of yacc.c */
+#line 160 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = SHELL_PARAM;
(yyval).str = (yyvsp[(3) - (3)]).str;
(yyval).len = (yyvsp[(3) - (3)]).len;
- ;}
+ }
break;
- case 27:
-
-/* Line 1455 of yacc.c */
-#line 154 "sapi/phpdbg/phpdbg_parser.y"
+ case 29:
+/* Line 1802 of yacc.c */
+#line 165 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = RUN_PARAM;
(yyval).len = 0;
- ;}
+ }
break;
- case 28:
-
-/* Line 1455 of yacc.c */
-#line 158 "sapi/phpdbg/phpdbg_parser.y"
+ case 30:
+/* Line 1802 of yacc.c */
+#line 169 "sapi/phpdbg/phpdbg_parser.y"
{
(yyval).type = RUN_PARAM;
(yyval).str = (yyvsp[(3) - (3)]).str;
(yyval).len = (yyvsp[(3) - (3)]).len;
- ;}
+ }
break;
-
-/* Line 1455 of yacc.c */
-#line 1638 "sapi/phpdbg/phpdbg_parser.c"
+/* Line 1802 of yacc.c */
+#line 1694 "sapi/phpdbg/phpdbg_parser.c"
default: break;
}
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
YYPOPSTACK (yylen);
@@ -1664,6 +1731,10 @@ yyreduce:
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
@@ -1671,37 +1742,36 @@ yyerrlab:
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
{
- YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
- if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
- {
- YYSIZE_T yyalloc = 2 * yysize;
- if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
- yyalloc = YYSTACK_ALLOC_MAXIMUM;
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yyalloc);
- if (yymsg)
- yymsg_alloc = yyalloc;
- else
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- }
- }
-
- if (0 < yysize && yysize <= yymsg_alloc)
- {
- (void) yysyntax_error (yymsg, yystate, yychar);
- yyerror (yymsg);
- }
- else
- {
- yyerror (YY_("syntax error"));
- if (yysize != 0)
- goto yyexhaustedlab;
- }
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
}
+# undef YYSYNTAX_ERROR
#endif
}
@@ -1760,7 +1830,7 @@ yyerrlab1:
for (;;)
{
yyn = yypact[yystate];
- if (yyn != YYPACT_NINF)
+ if (!yypact_value_is_default (yyn))
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -1783,7 +1853,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -1807,7 +1879,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if !defined yyoverflow || YYERROR_VERBOSE
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -1819,8 +1891,13 @@ yyexhaustedlab:
yyreturn:
if (yychar != YYEMPTY)
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
@@ -1844,9 +1921,8 @@ yyreturn:
}
-
-/* Line 1675 of yacc.c */
-#line 165 "sapi/phpdbg/phpdbg_parser.y"
+/* Line 2050 of yacc.c */
+#line 176 "sapi/phpdbg/phpdbg_parser.y"
static int yyerror(const char *msg) {
@@ -1864,8 +1940,16 @@ static int yyerror(const char *msg) {
}
int phpdbg_do_parse(phpdbg_param_t *stack, char *input) {
+ if (!*input) {
+ return 0;
+ }
+
+ if (PHPDBG_G(cur_command)) {
+ free(PHPDBG_G(cur_command));
+ }
+ PHPDBG_G(cur_command) = strdup(input);
+
phpdbg_init_lexer(stack, input);
return yyparse();
}
-
diff --git a/sapi/phpdbg/phpdbg_parser.h b/sapi/phpdbg/phpdbg_parser.h
index 0c66b27dc0..d13cfbc0a5 100644
--- a/sapi/phpdbg/phpdbg_parser.h
+++ b/sapi/phpdbg/phpdbg_parser.h
@@ -1,21 +1,19 @@
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
-/* A Bison parser, made by GNU Bison 2.4.1. */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
-
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@@ -28,14 +26,22 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
+#ifndef YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
+# define YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int phpdbg_debug;
+#endif
/* "%code requires" blocks. */
-
-/* Line 1676 of yacc.c */
-#line 31 "sapi/phpdbg/phpdbg_parser.y"
+/* Line 2060 of yacc.c */
+#line 36 "sapi/phpdbg/phpdbg_parser.y"
#include "phpdbg.h"
#ifndef YY_TYPEDEF_YY_SCANNER_T
@@ -44,9 +50,8 @@ typedef void* yyscan_t;
#endif
-
-/* Line 1676 of yacc.c */
-#line 50 "sapi/phpdbg/phpdbg_parser.h"
+/* Line 2060 of yacc.c */
+#line 55 "sapi/phpdbg/phpdbg_parser.h"
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -64,17 +69,39 @@ typedef void* yyscan_t;
T_COLON = 265,
T_DCOLON = 266,
T_POUND = 267,
- T_PROTO = 268,
- T_DIGITS = 269,
- T_LITERAL = 270,
- T_ADDR = 271,
- T_OPCODE = 272,
- T_ID = 273,
- T_INPUT = 274,
- T_UNEXPECTED = 275,
- T_REQ_ID = 276
+ T_SEPARATOR = 268,
+ T_PROTO = 269,
+ T_DIGITS = 270,
+ T_LITERAL = 271,
+ T_ADDR = 272,
+ T_OPCODE = 273,
+ T_ID = 274,
+ T_INPUT = 275,
+ T_UNEXPECTED = 276,
+ T_REQ_ID = 277
};
#endif
+/* Tokens. */
+#define T_EVAL 258
+#define T_RUN 259
+#define T_SHELL 260
+#define T_IF 261
+#define T_TRUTHY 262
+#define T_FALSY 263
+#define T_STRING 264
+#define T_COLON 265
+#define T_DCOLON 266
+#define T_POUND 267
+#define T_SEPARATOR 268
+#define T_PROTO 269
+#define T_DIGITS 270
+#define T_LITERAL 271
+#define T_ADDR 272
+#define T_OPCODE 273
+#define T_ID 274
+#define T_INPUT 275
+#define T_UNEXPECTED 276
+#define T_REQ_ID 277
@@ -86,5 +113,18 @@ typedef int YYSTYPE;
#endif
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int phpdbg_parse (void *YYPARSE_PARAM);
+#else
+int phpdbg_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int phpdbg_parse (void);
+#else
+int phpdbg_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
-
+#endif /* !YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */
diff --git a/sapi/phpdbg/phpdbg_parser.y b/sapi/phpdbg/phpdbg_parser.y
index 8b3ab27f85..527c321f4c 100644
--- a/sapi/phpdbg/phpdbg_parser.y
+++ b/sapi/phpdbg/phpdbg_parser.y
@@ -21,7 +21,12 @@
#undef yyerror
static int yyerror(const char *msg);
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
+
+#ifdef _MSC_VER
+#define YYMALLOC malloc
+#define YYFREE free
+#endif
%}
@@ -48,7 +53,8 @@ typedef void* yyscan_t;
%token T_STRING "string (some input, perhaps)"
%token T_COLON ": (colon)"
%token T_DCOLON ":: (double colon)"
-%token T_POUND "# (pound sign)"
+%token T_POUND "# (pound sign followed by digits)"
+%token T_SEPARATOR "# (pound sign)"
%token T_PROTO "protocol (file://)"
%token T_DIGITS "digits (numbers)"
%token T_LITERAL "literal (string)"
@@ -62,14 +68,19 @@ typedef void* yyscan_t;
%% /* Rules */
input
- : parameters
- | full_expression { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); }
+ : command { $$ = $1; }
+ | input T_SEPARATOR command { phpdbg_stack_separate($1.top); $$ = $3; }
| /* nothing */
;
+command
+ : parameters { $$.top = PHPDBG_G(parser_stack)->top; }
+ | full_expression { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); $$.top = PHPDBG_G(parser_stack)->top; }
+ ;
+
parameters
- : parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); }
- | parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); }
+ : parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); $$.top = PHPDBG_G(parser_stack)->top; }
+ | parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); $$.top = PHPDBG_G(parser_stack)->top; }
| parameters req_id { $$ = $1; }
;
@@ -179,6 +190,15 @@ static int yyerror(const char *msg) {
}
int phpdbg_do_parse(phpdbg_param_t *stack, char *input) {
+ if (!*input) {
+ return 0;
+ }
+
+ if (PHPDBG_G(cur_command)) {
+ free(PHPDBG_G(cur_command));
+ }
+ PHPDBG_G(cur_command) = strdup(input);
+
phpdbg_init_lexer(stack, input);
return yyparse();
diff --git a/sapi/phpdbg/phpdbg_print.c b/sapi/phpdbg/phpdbg_print.c
index b7bb9e688a..034354a9e7 100644
--- a/sapi/phpdbg/phpdbg_print.c
+++ b/sapi/phpdbg/phpdbg_print.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -24,7 +24,7 @@
#include "phpdbg_opcode.h"
#include "phpdbg_prompt.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s, flags) \
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[8], flags)
@@ -42,7 +42,7 @@ const phpdbg_command_t phpdbg_print_commands[] = {
PHPDBG_PRINT(opline) /* {{{ */
{
if (PHPDBG_G(in_execution) && EG(current_execute_data)) {
- phpdbg_print_opline(EG(current_execute_data), 1);
+ phpdbg_print_opline(phpdbg_user_execute_data(EG(current_execute_data)), 1);
} else {
phpdbg_error("inactive", "type=\"execution\"", "Not Executing!");
}
@@ -82,15 +82,11 @@ static inline void phpdbg_print_function_helper(zend_function *method) /* {{{ */
do {
char *decode = phpdbg_decode_opline(op_array, opline);
- if (decode != NULL) {
- phpdbg_writeln("print", "line=\"%u\" opnum=\"%u\" op=\"%s\"", " L%-4u #%-5u %s",
- opline->lineno,
- opcode,
- decode);
- free(decode);
- } else {
- phpdbg_error("print", "type=\"decodefailure\" opline=\"%16p\"", "Failed to decode opline %16p", opline);
- }
+ phpdbg_writeln("print", "line=\"%u\" opnum=\"%u\" op=\"%s\"", " L%-4u #%-5u %s",
+ opline->lineno,
+ opcode,
+ decode);
+ efree(decode);
opline++;
} while (opcode++ < end);
}
@@ -128,7 +124,7 @@ return SUCCESS;
PHPDBG_PRINT(stack) /* {{{ */
{
if (PHPDBG_G(in_execution) && EG(current_execute_data)) {
- zend_op_array *ops = &EG(current_execute_data)->func->op_array;
+ zend_op_array *ops = &phpdbg_user_execute_data(EG(current_execute_data))->func->op_array;
if (ops->function_name) {
if (ops->scope) {
phpdbg_notice("printinfo", "method=\"%s::%s\" num=\"%d\"", "Stack in %s::%s() (%d ops)", ZSTR_VAL(ops->scope->name), ZSTR_VAL(ops->function_name), ops->last);
@@ -221,11 +217,13 @@ PHPDBG_PRINT(func) /* {{{ */
zend_string *lcname;
/* search active scope if begins with period */
if (func_name[0] == '.') {
- if (EG(scope)) {
+ zend_class_entry *scope = zend_get_executed_scope();
+
+ if (scope) {
func_name++;
func_name_len--;
- func_table = &EG(scope)->function_table;
+ func_table = &scope->function_table;
} else {
phpdbg_error("inactive", "type=\"noclasses\"", "No active class");
return SUCCESS;
@@ -282,7 +280,7 @@ void phpdbg_print_opcodes_function(const char *function, size_t len) {
return;
}
- phpdbg_out("function name: %.*s\n", ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name));
+ phpdbg_out("function name: %.*s\n", (int) ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name));
phpdbg_print_function_helper(func);
}
@@ -355,7 +353,7 @@ static void phpdbg_print_opcodes_ce(zend_class_entry *ce) {
phpdbg_out("\n");
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, method_name, method) {
- phpdbg_out("\nfunction name: %s\n", method_name);
+ phpdbg_out("\nfunction name: %s\n", ZSTR_VAL(method_name));
phpdbg_print_function_helper(method);
} ZEND_HASH_FOREACH_END();
}
@@ -381,8 +379,6 @@ void phpdbg_print_opcodes_class(const char *class) {
PHPDBG_API void phpdbg_print_opcodes(char *function)
{
- char *method_name = strtok(function, ":");
-
if (function == NULL) {
phpdbg_print_opcodes_main();
} else if (function[0] == '*' && function[1] == 0) {
@@ -406,11 +402,20 @@ PHPDBG_API void phpdbg_print_opcodes(char *function)
phpdbg_print_opcodes_ce(ce);
}
} ZEND_HASH_FOREACH_END();
- } else if (method_name == NULL) {
- phpdbg_print_opcodes_function(function, strlen(function));
- } else if ((method_name = strtok(NULL, ":")) == NULL) {
- phpdbg_print_opcodes_class(function);
} else {
- phpdbg_print_opcodes_method(function, method_name);
+ function = zend_str_tolower_dup(function, strlen(function));
+
+ if (strstr(function, "::") == NULL) {
+ phpdbg_print_opcodes_function(function, strlen(function));
+ } else {
+ char *method_name, *class_name = strtok(function, "::");
+ if ((method_name = strtok(NULL, "::")) == NULL) {
+ phpdbg_print_opcodes_class(class_name);
+ } else {
+ phpdbg_print_opcodes_method(class_name, method_name);
+ }
+ }
+
+ efree(function);
}
}
diff --git a/sapi/phpdbg/phpdbg_print.h b/sapi/phpdbg/phpdbg_print.h
index 029c15946f..b8e18fedaf 100644
--- a/sapi/phpdbg/phpdbg_print.h
+++ b/sapi/phpdbg/phpdbg_print.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
index 540706eae1..4655702fa8 100644
--- a/sapi/phpdbg/phpdbg_prompt.c
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,7 +25,10 @@
#include "zend_exceptions.h"
#include "zend_vm.h"
#include "zend_generators.h"
+#include "zend_interfaces.h"
+#include "zend_smart_str.h"
#include "phpdbg.h"
+#include "phpdbg_io.h"
#include "phpdbg_help.h"
#include "phpdbg_print.h"
@@ -47,7 +50,7 @@
#error "phpdbg can only be built with CALL zend vm kind"
#endif
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
extern int phpdbg_startup_run;
#ifdef HAVE_LIBDL
@@ -66,33 +69,35 @@ extern int phpdbg_startup_run;
/* {{{ command declarations */
const phpdbg_command_t phpdbg_prompt_commands[] = {
- PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s", 0),
- PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s", 0),
- PHPDBG_COMMAND_D(ev, "evaluate some code", 0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */
- PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0, 0),
- PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0, 0),
- PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0, 0),
- PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, "|*c", 0),
- PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c", 0),
- PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "|s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0, 0),
- PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0, 0),
- PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s", 0),
- PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s", 0),
- PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(sh, "shell a command", 0 , NULL, "i", 0),
- PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(wait, "wait for other process", 'W', NULL, 0, 0),
- PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss", 0),
- PHPDBG_COMMAND_D(next, "step over next line", 'n', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(eol, "set EOL", 'E', NULL, "|s", 0),
+ PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s", 0),
+ PHPDBG_COMMAND_D(stdin, "read script from stdin", 0 , NULL, "s", 0),
+ PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(continue, "continue execution", 'c', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s", 0),
+ PHPDBG_COMMAND_D(ev, "evaluate some code", 0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */
+ PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0, 0),
+ PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0, 0),
+ PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0, 0),
+ PHPDBG_COMMAND_D(generator, "inspect or switch to a generator", 'g', NULL, "|n", 0),
+ PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, "|*c", 0),
+ PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c", 0),
+ PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "|s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0, 0),
+ PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0, 0),
+ PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(register, "register a function", 'R', NULL, "s", 0),
+ PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s", 0),
+ PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(sh, "shell a command", 0 , NULL, "i", 0),
+ PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(wait, "wait for other process", 'W', NULL, 0, 0),
+ PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss", 0),
+ PHPDBG_COMMAND_D(next, "step over next line", 'n', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(eol, "set EOL", 'E', NULL, "|s", 0),
PHPDBG_END_COMMAND
}; /* }}} */
@@ -119,8 +124,7 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack) /* {{{ */
ZVAL_STRINGL(&fci.function_name, lc_name, name->len);
fci.size = sizeof(zend_fcall_info);
- fci.function_table = &PHPDBG_G(registered);
- fci.symbol_table = zend_rebuild_symbol_table();
+ //???fci.symbol_table = zend_rebuild_symbol_table();
fci.object = NULL;
fci.retval = &fretval;
fci.no_separation = 1;
@@ -344,12 +348,14 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_
void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default) /* {{{ */
{
- if (!init_file && use_default) {
+ if (init_file) {
+ phpdbg_try_file_init(init_file, init_file_len, 1);
+ } else if (use_default) {
char *scan_dir = getenv("PHP_INI_SCAN_DIR");
char *sys_ini;
int i;
- asprintf(&sys_ini, "%s/" PHPDBG_INIT_FILENAME, PHP_CONFIG_FILE_PATH);
+ ZEND_IGNORE_VALUE(asprintf(&sys_ini, "%s/" PHPDBG_INIT_FILENAME, PHP_CONFIG_FILE_PATH));
phpdbg_try_file_init(sys_ini, strlen(sys_ini), 0);
free(sys_ini);
@@ -368,7 +374,7 @@ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default) /
scan_dir[i] = 0;
}
- asprintf(&init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME);
+ ZEND_IGNORE_VALUE(asprintf(&init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME));
phpdbg_try_file_init(init_file, strlen(init_file), 1);
if (i == -1) {
break;
@@ -377,12 +383,29 @@ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default) /
}
phpdbg_try_file_init(PHPDBG_STRL(PHPDBG_INIT_FILENAME), 0);
- } else {
- phpdbg_try_file_init(init_file, init_file_len, 1);
}
}
/* }}} */
+void phpdbg_clean(zend_bool full, zend_bool resubmit) /* {{{ */
+{
+ /* this is implicitly required */
+ if (PHPDBG_G(ops)) {
+ destroy_op_array(PHPDBG_G(ops));
+ efree(PHPDBG_G(ops));
+ PHPDBG_G(ops) = NULL;
+ }
+
+ if (!resubmit && PHPDBG_G(cur_command)) {
+ free(PHPDBG_G(cur_command));
+ PHPDBG_G(cur_command) = NULL;
+ }
+
+ if (full) {
+ PHPDBG_G(flags) |= PHPDBG_IS_CLEANING;
+ }
+} /* }}} */
+
PHPDBG_COMMAND(exec) /* {{{ */
{
zend_stat_t sb;
@@ -408,7 +431,7 @@ PHPDBG_COMMAND(exec) /* {{{ */
if (PHPDBG_G(ops)) {
phpdbg_notice("exec", "type=\"unsetops\"", "Destroying compiled opcodes");
- phpdbg_clean(0);
+ phpdbg_clean(0, 0);
}
PHPDBG_G(exec) = res;
@@ -417,12 +440,13 @@ PHPDBG_COMMAND(exec) /* {{{ */
VCWD_CHDIR_FILE(res);
*SG(request_info).argv = PHPDBG_G(exec);
- php_hash_environment();
+ php_build_argv(NULL, &PG(http_globals)[TRACK_VARS_SERVER]);
phpdbg_notice("exec", "type=\"set\" context=\"%s\"", "Set execution context: %s", PHPDBG_G(exec));
if (PHPDBG_G(in_execution)) {
- phpdbg_clean(1);
+ phpdbg_clean(1, 0);
+ return SUCCESS;
}
phpdbg_compile();
@@ -438,17 +462,171 @@ PHPDBG_COMMAND(exec) /* {{{ */
return SUCCESS;
} /* }}} */
+PHPDBG_COMMAND(stdin)
+{
+ smart_str code = {0};
+ char *buf;
+ char *sep = param->str;
+ int seplen = param->len;
+ int bytes = 0;
+
+ smart_str_appends(&code, "?>");
+
+ do {
+ PHPDBG_G(input_buflen) += bytes;
+ if (PHPDBG_G(input_buflen) <= 0) {
+ continue;
+ }
+
+ if (sep && seplen) {
+ char *nl = buf = PHPDBG_G(input_buffer);
+ do {
+ if (buf == nl + seplen) {
+ if (!memcmp(sep, nl, seplen) && (*buf == '\n' || (*buf == '\r' && buf[1] == '\n'))) {
+ smart_str_appendl(&code, PHPDBG_G(input_buffer), nl - PHPDBG_G(input_buffer));
+ memmove(PHPDBG_G(input_buffer), ++buf, --PHPDBG_G(input_buflen));
+ goto exec_code;
+ }
+ }
+ if (*buf == '\n') {
+ nl = buf + 1;
+ }
+ buf++;
+ } while (--PHPDBG_G(input_buflen));
+ if (buf != nl && buf <= nl + seplen) {
+ smart_str_appendl(&code, PHPDBG_G(input_buffer), nl - PHPDBG_G(input_buffer));
+ PHPDBG_G(input_buflen) = buf - nl;
+ memmove(PHPDBG_G(input_buffer), nl, PHPDBG_G(input_buflen));
+ } else {
+ PHPDBG_G(input_buflen) = 0;
+ smart_str_appendl(&code, PHPDBG_G(input_buffer), buf - PHPDBG_G(input_buffer));
+ }
+ } else {
+ smart_str_appendl(&code, PHPDBG_G(input_buffer), PHPDBG_G(input_buflen));
+ PHPDBG_G(input_buflen) = 0;
+ }
+ } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, PHPDBG_G(input_buffer) + PHPDBG_G(input_buflen), PHPDBG_MAX_CMD - PHPDBG_G(input_buflen), -1)) > 0);
+
+ if (bytes < 0) {
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED;
+ zend_bailout();
+ }
+
+exec_code:
+ smart_str_0(&code);
+
+ if (phpdbg_compile_stdin(code.s) == FAILURE) {
+ zend_exception_error(EG(exception), E_ERROR);
+ zend_bailout();
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+int phpdbg_compile_stdin(zend_string *code) {
+ zval zv;
+
+ ZVAL_STR(&zv, code);
+
+ PHPDBG_G(ops) = zend_compile_string(&zv, "-");
+
+ zend_string_release(code);
+
+ if (EG(exception)) {
+ return FAILURE;
+ }
+
+ if (PHPDBG_G(exec)) {
+ efree(PHPDBG_G(exec));
+ }
+ PHPDBG_G(exec) = estrdup("-");
+ PHPDBG_G(exec_len) = 1;
+ { /* remove leading ?> from source */
+ int i;
+ /* remove trailing data after zero byte, used for avoiding conflicts in eval()'ed code snippets */
+ zend_string *source_path = strpprintf(0, "-%c%p", 0, PHPDBG_G(ops)->opcodes);
+ phpdbg_file_source *data = zend_hash_find_ptr(&PHPDBG_G(file_sources), source_path);
+ dtor_func_t dtor = PHPDBG_G(file_sources).pDestructor;
+ PHPDBG_G(file_sources).pDestructor = NULL;
+ zend_hash_del(&PHPDBG_G(file_sources), source_path);
+ PHPDBG_G(file_sources).pDestructor = dtor;
+ zend_hash_str_update_ptr(&PHPDBG_G(file_sources), "-", 1, data);
+ zend_string_release(source_path);
+
+ for (i = 1; i <= data->lines; i++) {
+ data->line[i] -= 2;
+ }
+ data->len -= 2;
+ memmove(data->buf, data->buf + 2, data->len);
+ }
+
+ phpdbg_notice("compile", "context=\"-\"", "Successful compilation of stdin input");
+
+ return SUCCESS;
+}
+
int phpdbg_compile(void) /* {{{ */
{
zend_file_handle fh;
+ char *buf;
+ char *start_line = NULL;
+ size_t len;
+ size_t start_line_len;
+ int i;
if (!PHPDBG_G(exec)) {
phpdbg_error("inactive", "type=\"nocontext\"", "No execution context");
return FAILURE;
}
- if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, USE_PATH|STREAM_OPEN_FOR_INCLUDE) == SUCCESS) {
+ if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, USE_PATH|STREAM_OPEN_FOR_INCLUDE) == SUCCESS && zend_stream_fixup(&fh, &buf, &len) == SUCCESS) {
+ /* Skip #! line */
+ if (len >= 3 && buf[0] == '#' && buf[1] == '!') {
+ char *end = buf + len;
+ do {
+ switch (fh.handle.stream.mmap.buf++[0]) {
+ case '\r':
+ if (fh.handle.stream.mmap.buf[0] == '\n') {
+ fh.handle.stream.mmap.buf++;
+ }
+ case '\n':
+ CG(start_lineno) = 2;
+ start_line_len = fh.handle.stream.mmap.buf - buf;
+ start_line = emalloc(start_line_len);
+ memcpy(start_line, buf, start_line_len);
+ fh.handle.stream.mmap.len -= start_line_len;
+ end = fh.handle.stream.mmap.buf;
+ }
+ } while (fh.handle.stream.mmap.buf + 1 < end);
+ }
+
PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE);
+
+ /* prepend shebang line to file_source */
+ if (start_line) {
+ phpdbg_file_source *data = zend_hash_find_ptr(&PHPDBG_G(file_sources), PHPDBG_G(ops)->filename);
+
+ dtor_func_t dtor = PHPDBG_G(file_sources).pDestructor;
+ PHPDBG_G(file_sources).pDestructor = NULL;
+ zend_hash_del(&PHPDBG_G(file_sources), PHPDBG_G(ops)->filename);
+ PHPDBG_G(file_sources).pDestructor = dtor;
+
+ data = erealloc(data, sizeof(phpdbg_file_source) + sizeof(uint) * ++data->lines);
+ memmove(data->line + 1, data->line, sizeof(uint) * data->lines);
+ data->line[0] = 0;
+ data->buf = erealloc(data->buf, data->len + start_line_len);
+ memmove(data->buf + start_line_len, data->buf, data->len * sizeof(uint));
+ memcpy(data->buf, start_line, start_line_len);
+ efree(start_line);
+ data->len += start_line_len;
+ for (i = 1; i <= data->lines; i++) {
+ data->line[i] += start_line_len;
+ }
+ zend_hash_update_ptr(&PHPDBG_G(file_sources), PHPDBG_G(ops)->filename, data);
+ }
+
+ fh.handle.stream.mmap.buf = buf;
+ fh.handle.stream.mmap.len = len;
zend_destroy_file_handle(&fh);
if (EG(exception)) {
zend_exception_error(EG(exception), E_ERROR);
@@ -480,26 +658,24 @@ PHPDBG_COMMAND(continue) /* {{{ */
} /* }}} */
int phpdbg_skip_line_helper() /* {{{ */ {
+ zend_execute_data *ex = phpdbg_user_execute_data(EG(current_execute_data));
+ const zend_op_array *op_array = &ex->func->op_array;
+ const zend_op *opline = op_array->opcodes;
+
PHPDBG_G(flags) |= PHPDBG_IN_UNTIL;
- PHPDBG_G(seek_ex) = EG(current_execute_data);
- {
- const zend_op *opline = EG(current_execute_data)->opline;
- const zend_op_array *op_array = &EG(current_execute_data)->func->op_array;
-
- while (++opline < op_array->opcodes + op_array->last) {
- if (opline->lineno != EG(current_execute_data)->opline->lineno
- || opline->opcode == ZEND_RETURN
- || opline->opcode == ZEND_FAST_RET
- || opline->opcode == ZEND_GENERATOR_RETURN
- || opline->opcode == ZEND_EXIT
- || opline->opcode == ZEND_YIELD
- || opline->opcode == ZEND_YIELD_FROM
- ) {
- zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline);
- break;
- }
+ PHPDBG_G(seek_ex) = ex;
+ do {
+ if (opline->lineno != ex->opline->lineno
+ || opline->opcode == ZEND_RETURN
+ || opline->opcode == ZEND_FAST_RET
+ || opline->opcode == ZEND_GENERATOR_RETURN
+ || opline->opcode == ZEND_EXIT
+ || opline->opcode == ZEND_YIELD
+ || opline->opcode == ZEND_YIELD_FROM
+ ) {
+ zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline);
}
- }
+ } while (++opline < op_array->opcodes + op_array->last);
return PHPDBG_UNTIL;
}
@@ -527,11 +703,12 @@ PHPDBG_COMMAND(next) /* {{{ */
} /* }}} */
static void phpdbg_seek_to_end(void) /* {{{ */ {
- const zend_op *opline = EG(current_execute_data)->opline;
- const zend_op_array *op_array = &EG(current_execute_data)->func->op_array - 1;
+ zend_execute_data *ex = phpdbg_user_execute_data(EG(current_execute_data));
+ const zend_op_array *op_array = &ex->func->op_array;
+ const zend_op *opline = op_array->opcodes;
- PHPDBG_G(seek_ex) = EG(current_execute_data);
- while (++opline < op_array->opcodes + op_array->last) {
+ PHPDBG_G(seek_ex) = ex;
+ do {
switch (opline->opcode) {
case ZEND_RETURN:
case ZEND_FAST_RET:
@@ -540,9 +717,8 @@ static void phpdbg_seek_to_end(void) /* {{{ */ {
case ZEND_YIELD:
case ZEND_YIELD_FROM:
zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline);
- return;
}
- }
+ } while (++opline < op_array->opcodes + op_array->last);
}
/* }}} */
@@ -553,8 +729,12 @@ PHPDBG_COMMAND(finish) /* {{{ */
return SUCCESS;
}
- PHPDBG_G(flags) |= PHPDBG_IN_FINISH;
phpdbg_seek_to_end();
+ if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) phpdbg_user_execute_data(EG(current_execute_data))->opline)) {
+ zend_hash_clean(&PHPDBG_G(seek));
+ } else {
+ PHPDBG_G(flags) |= PHPDBG_IN_FINISH;
+ }
return PHPDBG_FINISH;
} /* }}} */
@@ -566,10 +746,15 @@ PHPDBG_COMMAND(leave) /* {{{ */
return SUCCESS;
}
- PHPDBG_G(flags) |= PHPDBG_IN_LEAVE;
phpdbg_seek_to_end();
-
- return PHPDBG_LEAVE;
+ if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) phpdbg_user_execute_data(EG(current_execute_data))->opline)) {
+ zend_hash_clean(&PHPDBG_G(seek));
+ phpdbg_notice("leave", "type=\"end\"", "Already at the end of the function");
+ return SUCCESS;
+ } else {
+ PHPDBG_G(flags) |= PHPDBG_IN_LEAVE;
+ return PHPDBG_LEAVE;
+ }
} /* }}} */
PHPDBG_COMMAND(frame) /* {{{ */
@@ -585,47 +770,40 @@ PHPDBG_COMMAND(frame) /* {{{ */
static inline void phpdbg_handle_exception(void) /* {{{ */
{
- zend_fcall_info fci;
- zval trace;
zend_object *ex = EG(exception);
-
- /* get filename and linenumber before unsetting exception */
- /* not really useful??? see blow
- const char *filename = zend_get_executed_filename();
- uint32_t lineno = zend_get_executed_lineno();
- */
+ zend_string *msg, *file;
+ zend_long line;
+ zval zv, rv, tmp;
EG(exception) = NULL;
- /* call __toString */
- ZVAL_STRINGL(&fci.function_name, "__tostring", sizeof("__tostring") - 1);
- fci.size = sizeof(fci);
- fci.function_table = &ex->ce->function_table;
- fci.symbol_table = NULL;
- fci.object = ex;
- fci.retval = &trace;
- fci.param_count = 0;
- fci.params = NULL;
- fci.no_separation = 1;
- if (zend_call_function(&fci, NULL) == SUCCESS) {
- phpdbg_writeln("exception", "name=\"%s\" trace=\"%.*s\"", "Uncaught %s!\n%.*s", ZSTR_VAL(ex->ce->name), Z_STRLEN(trace), Z_STRVAL(trace));
-
- zval_ptr_dtor(&trace);
+ ZVAL_OBJ(&zv, ex);
+ zend_call_method_with_0_params(&zv, ex->ce, NULL, "__tostring", &tmp);
+ file = zval_get_string(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("file"), 1, &rv));
+ line = zval_get_long(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("line"), 1, &rv));
+
+ if (EG(exception)) {
+ EG(exception) = NULL;
+ msg = ZSTR_EMPTY_ALLOC();
} else {
- phpdbg_error("exception", "name=\"%s\"", "Uncaught %s!", ZSTR_VAL(ex->ce->name));
+ zend_update_property_string(zend_get_exception_base(&zv), &zv, ZEND_STRL("string"), Z_STRVAL(tmp));
+ zval_ptr_dtor(&tmp);
+ msg = zval_get_string(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("string"), 1, &rv));
}
- /* output useful information about address */
-/* not really useful ???
- phpdbg_writeln("exception", "opline=\"%p\" file=\"%s\" line=\"%u\"", "Stack entered at %p in %s on line %u", PHPDBG_G(ops)->opcodes, filename, lineno); */
+ phpdbg_error("exception", "name=\"%s\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"", "Uncaught %s in %s on line " ZEND_LONG_FMT, ZSTR_VAL(ex->ce->name), ZSTR_VAL(file), line);
+ zend_string_release(file);
+ phpdbg_writeln("exceptionmsg", "msg=\"%s\"", "%s", ZSTR_VAL(msg));
+ zend_string_release(msg);
- zval_dtor(&fci.function_name);
if (EG(prev_exception)) {
OBJ_RELEASE(EG(prev_exception));
EG(prev_exception) = 0;
}
OBJ_RELEASE(ex);
EG(opline_before_exception) = NULL;
+
+ EG(exit_status) = 255;
} /* }}} */
PHPDBG_COMMAND(run) /* {{{ */
@@ -637,7 +815,7 @@ PHPDBG_COMMAND(run) /* {{{ */
if (PHPDBG_G(in_execution)) {
if (phpdbg_ask_user_permission("Do you really want to restart execution?") == SUCCESS) {
phpdbg_startup_run++;
- phpdbg_clean(1);
+ phpdbg_clean(1, 1);
}
return SUCCESS;
}
@@ -649,35 +827,92 @@ PHPDBG_COMMAND(run) /* {{{ */
}
}
- /* clean up from last execution */
- if (ex && ex->symbol_table) {
- zend_hash_clean(ex->symbol_table);
- } else {
- zend_rebuild_symbol_table();
- }
- PHPDBG_G(handled_exception) = NULL;
-
- /* clean seek state */
- PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK;
- zend_hash_clean(&PHPDBG_G(seek));
-
- /* reset hit counters */
- phpdbg_reset_breakpoints();
-
if (param && param->type != EMPTY_PARAM && param->len != 0) {
char **argv = emalloc(5 * sizeof(char *));
+ char *end = param->str + param->len, *p = param->str;
+ char last_byte;
int argc = 0;
int i;
- char *argv_str = strtok(param->str, " ");
- while (argv_str) {
+ while (*end == '\r' || *end == '\n') *(end--) = 0;
+ last_byte = end[1];
+ end[1] = 0;
+
+ while (*p == ' ') p++;
+ while (*p) {
+ char sep = ' ';
+ char *buf = emalloc(end - p + 1), *q = buf;
+
+ if (*p == '<') {
+ /* use as STDIN */
+ do p++; while (*p == ' ');
+
+ if (*p == '\'' || *p == '"') {
+ sep = *(p++);
+ }
+ while (*p && *p != sep) {
+ if (*p == '\\' && (p[1] == sep || p[1] == '\\')) {
+ p++;
+ }
+ *(q++) = *(p++);
+ }
+ *(q++) = 0;
+ if (*p) {
+ do p++; while (*p == ' ');
+ }
+
+ if (*p) {
+ phpdbg_error("cmd", "", "Invalid run command, cannot put further arguments after stdin");
+ goto free_cmd;
+ }
+
+ PHPDBG_G(stdin_file) = fopen(buf, "r");
+ if (PHPDBG_G(stdin_file) == NULL) {
+ phpdbg_error("stdin", "path=\"%s\"", "Could not open '%s' for reading from stdin", buf);
+ goto free_cmd;
+ }
+ efree(buf);
+ phpdbg_register_file_handles();
+ break;
+ }
+
if (argc >= 4 && argc == (argc & -argc)) {
argv = erealloc(argv, (argc * 2 + 1) * sizeof(char *));
}
- argv[++argc] = argv_str;
- argv_str = strtok(0, " ");
- argv[argc] = estrdup(argv[argc]);
+
+ if (*p == '\'' || *p == '"') {
+ sep = *(p++);
+ }
+ if (*p == '\\' && (p[1] == '<' || p[1] == '\'' || p[1] == '"')) {
+ p++;
+ }
+ while (*p && *p != sep) {
+ if (*p == '\\' && (p[1] == sep || p[1] == '\\' || (p[1] == '#' && sep == ' '))) {
+ p++;
+ }
+ *(q++) = *(p++);
+ }
+ if (!*p && sep != ' ') {
+ phpdbg_error("cmd", "", "Invalid run command, unterminated escape sequence");
+free_cmd:
+ efree(buf);
+ for (i = 0; i < argc; i++) {
+ efree(argv[i]);
+ }
+ efree(argv);
+ end[1] = last_byte;
+ return SUCCESS;
+ }
+
+ *(q++) = 0;
+ argv[++argc] = erealloc(buf, q - buf);
+
+ if (*p) {
+ do p++; while (*p == ' ');
+ }
}
+ end[1] = last_byte;
+
argv[0] = SG(request_info).argv[0];
for (i = SG(request_info).argc; --i;) {
efree(SG(request_info).argv[i]);
@@ -686,9 +921,24 @@ PHPDBG_COMMAND(run) /* {{{ */
SG(request_info).argv = erealloc(argv, ++argc * sizeof(char *));
SG(request_info).argc = argc;
- php_hash_environment();
+ php_build_argv(NULL, &PG(http_globals)[TRACK_VARS_SERVER]);
}
+ /* clean up from last execution */
+ if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
+ zend_hash_clean(ex->symbol_table);
+ } else {
+ zend_rebuild_symbol_table();
+ }
+ PHPDBG_G(handled_exception) = NULL;
+
+ /* clean seek state */
+ PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK;
+ zend_hash_clean(&PHPDBG_G(seek));
+
+ /* reset hit counters */
+ phpdbg_reset_breakpoints();
+
zend_try {
PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
PHPDBG_G(flags) |= PHPDBG_IS_RUNNING;
@@ -697,13 +947,10 @@ PHPDBG_COMMAND(run) /* {{{ */
} zend_catch {
PHPDBG_G(in_execution) = 0;
- if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
- zend_bailout();
- }
-
if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
- phpdbg_error("stop", "type=\"bailout\"", "Caught exit/error from VM");
restore = 0;
+ } else {
+ zend_bailout();
}
} zend_end_try();
@@ -713,14 +960,26 @@ PHPDBG_COMMAND(run) /* {{{ */
}
if (restore) {
+ zend_exception_restore();
+ zend_try {
+ zend_try_exception_handler();
+ PHPDBG_G(in_execution) = 1;
+ } zend_catch {
+ PHPDBG_G(in_execution) = 0;
+
+ if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
+ zend_bailout();
+ }
+ } zend_end_try();
+
if (EG(exception)) {
phpdbg_handle_exception();
}
}
- phpdbg_clean(1);
-
PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING;
+
+ phpdbg_clean(1, 0);
} else {
phpdbg_error("inactive", "type=\"nocontext\"", "Nothing to execute!");
}
@@ -750,8 +1009,8 @@ PHPDBG_COMMAND(ev) /* {{{ */
zval retval;
zend_execute_data *original_execute_data = EG(current_execute_data);
- zend_class_entry *original_scope = EG(scope);
zend_vm_stack original_stack = EG(vm_stack);
+ zend_object *ex = NULL;
PHPDBG_OUTPUT_BACKUP();
@@ -776,23 +1035,33 @@ PHPDBG_COMMAND(ev) /* {{{ */
PHPDBG_G(flags) |= PHPDBG_IN_EVAL;
zend_try {
if (zend_eval_stringl(param->str, param->len, &retval, "eval()'d code") == SUCCESS) {
- phpdbg_xml("<eval %r>");
- if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
- zval *zvp = &retval;
- phpdbg_xml_var_dump(zvp);
+ if (EG(exception)) {
+ ex = EG(exception);
+ zend_exception_error(EG(exception), E_ERROR);
+ } else {
+ phpdbg_xml("<eval %r>");
+ if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
+ zval *zvp = &retval;
+ phpdbg_xml_var_dump(zvp);
+ }
+ zend_print_zval_r(&retval, 0);
+ phpdbg_xml("</eval>");
+ phpdbg_out("\n");
+ zval_ptr_dtor(&retval);
}
- zend_print_zval_r(&retval, 0);
- phpdbg_xml("</eval>");
- phpdbg_out("\n");
- zval_ptr_dtor(&retval);
}
} zend_catch {
+ PHPDBG_G(unclean_eval) = 1;
+ if (ex) {
+ OBJ_RELEASE(ex);
+ }
EG(current_execute_data) = original_execute_data;
- EG(scope) = original_scope;
EG(vm_stack_top) = original_stack->top;
EG(vm_stack_end) = original_stack->end;
EG(vm_stack) = original_stack;
+ EG(exit_status) = 0;
} zend_end_try();
+
PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL;
/* switch stepping back on */
@@ -823,6 +1092,56 @@ PHPDBG_COMMAND(back) /* {{{ */
return SUCCESS;
} /* }}} */
+PHPDBG_COMMAND(generator) /* {{{ */
+{
+ int i;
+
+ if (!PHPDBG_G(in_execution)) {
+ phpdbg_error("inactive", "type=\"noexec\"", "Not executing!");
+ return SUCCESS;
+ }
+
+ if (param) {
+ i = param->num;
+ zend_object **obj = EG(objects_store).object_buckets + i;
+ if (i < EG(objects_store).top && *obj && IS_OBJ_VALID(*obj) && (*obj)->ce == zend_ce_generator) {
+ zend_generator *gen = (zend_generator *) *obj;
+ if (gen->execute_data) {
+ if (zend_generator_get_current(gen)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
+ phpdbg_error("generator", "type=\"running\"", "Generator currently running");
+ } else {
+ phpdbg_open_generator_frame(gen);
+ }
+ } else {
+ phpdbg_error("generator", "type=\"closed\"", "Generator already closed");
+ }
+ } else {
+ phpdbg_error("invalidarg", "", "Invalid object handle");
+ }
+ } else {
+ for (i = 0; i < EG(objects_store).top; i++) {
+ zend_object *obj = EG(objects_store).object_buckets[i];
+ if (obj && IS_OBJ_VALID(obj) && obj->ce == zend_ce_generator) {
+ zend_generator *gen = (zend_generator *) obj, *current = zend_generator_get_current(gen);
+ if (gen->execute_data) {
+ zend_string *s = phpdbg_compile_stackframe(gen->execute_data);
+ phpdbg_out("#%d: %.*s", i, (int) ZSTR_LEN(s), ZSTR_VAL(s));
+ zend_string_release(s);
+ if (gen != current) {
+ if (gen->node.parent != current) {
+ phpdbg_out(" with direct parent #%d and", gen->node.parent->std.handle);
+ }
+ phpdbg_out(" executing #%d currently", current->std.handle);
+ }
+ phpdbg_out("\n");
+ }
+ }
+ }
+ }
+
+ return SUCCESS;
+} /* }}} */
+
PHPDBG_COMMAND(print) /* {{{ */
{
if (!param || param->type == EMPTY_PARAM) {
@@ -888,16 +1207,21 @@ PHPDBG_COMMAND(set) /* {{{ */
PHPDBG_COMMAND(break) /* {{{ */
{
if (!param) {
- phpdbg_set_breakpoint_file(
- zend_get_executed_filename(),
- zend_get_executed_lineno());
+ if (PHPDBG_G(exec)) {
+ phpdbg_set_breakpoint_file_ex(
+ zend_get_executed_filename(),
+ strlen(zend_get_executed_filename()),
+ zend_get_executed_lineno());
+ } else {
+ phpdbg_error("inactive", "type=\"noexec\"", "Execution context not set!");
+ }
} else switch (param->type) {
case ADDR_PARAM:
phpdbg_set_breakpoint_opline(param->addr);
break;
case NUMERIC_PARAM:
if (PHPDBG_G(exec)) {
- phpdbg_set_breakpoint_file(phpdbg_current_file(), param->num);
+ phpdbg_set_breakpoint_file_ex(phpdbg_current_file(), strlen(phpdbg_current_file()), param->num);
} else {
phpdbg_error("inactive", "type=\"noexec\"", "Execution context not set!");
}
@@ -958,6 +1282,7 @@ static int add_zendext_info(zend_extension *ext) /* {{{ */ {
}
/* }}} */
+#ifdef HAVE_LIBDL
PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, char **name) /* {{{ */ {
DL_HANDLE handle;
char *extension_dir;
@@ -987,7 +1312,7 @@ PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, char **name)
if (!handle) {
#if PHP_WIN32
char *err = GET_DL_ERROR();
- if (err && *err != "") {
+ if (err && err[0]) {
phpdbg_error("dl", "type=\"unknown\"", "%s", err);
LocalFree(err);
} else {
@@ -1098,6 +1423,7 @@ quit:
return NULL;
}
/* }}} */
+#endif
PHPDBG_COMMAND(dl) /* {{{ */
{
@@ -1188,14 +1514,10 @@ PHPDBG_COMMAND(register) /* {{{ */
PHPDBG_COMMAND(quit) /* {{{ */
{
- /* don't allow this to loop, ever ... */
- if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
- PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
- PHPDBG_G(flags) &= ~(PHPDBG_IS_RUNNING | PHPDBG_IS_CLEANING);
- zend_bailout();
- }
+ PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
+ PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING;
- return PHPDBG_NEXT;
+ return SUCCESS;
} /* }}} */
PHPDBG_COMMAND(clean) /* {{{ */
@@ -1214,9 +1536,7 @@ PHPDBG_COMMAND(clean) /* {{{ */
phpdbg_writeln("clean", "constants=\"%d\"", "Constants %d", zend_hash_num_elements(EG(zend_constants)));
phpdbg_writeln("clean", "includes=\"%d\"", "Includes %d", zend_hash_num_elements(&EG(included_files)));
- PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING;
-
- phpdbg_clean(1);
+ phpdbg_clean(1, 0);
phpdbg_xml("</cleaninfo>");
@@ -1274,9 +1594,7 @@ PHPDBG_COMMAND(watch) /* {{{ */
phpdbg_list_watchpoints();
} else switch (param->type) {
case STR_PARAM:
- if (phpdbg_create_var_watchpoint(param->str, param->len) != FAILURE) {
- phpdbg_notice("watch", "variable=\"%.*s\"", "Set watchpoint on %.*s", (int) param->len, param->str);
- }
+ phpdbg_create_var_watchpoint(param->str, param->len);
break;
phpdbg_default_switch_case();
@@ -1285,20 +1603,19 @@ PHPDBG_COMMAND(watch) /* {{{ */
return SUCCESS;
} /* }}} */
-int phpdbg_interactive(zend_bool allow_async_unsafe) /* {{{ */
+int phpdbg_interactive(zend_bool allow_async_unsafe, char *input) /* {{{ */
{
int ret = SUCCESS;
- char *input = NULL;
phpdbg_param_t stack;
PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
while (ret == SUCCESS || ret == FAILURE) {
- if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_STOPPING) {
+ if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
zend_bailout();
}
- if (!(input = phpdbg_read_input(NULL))) {
+ if (!input && !(input = phpdbg_read_input(NULL))) {
break;
}
@@ -1369,25 +1686,15 @@ int phpdbg_interactive(zend_bool allow_async_unsafe) /* {{{ */
return ret;
} /* }}} */
-void phpdbg_clean(zend_bool full) /* {{{ */
-{
- /* this is implicitly required */
- if (PHPDBG_G(ops)) {
- destroy_op_array(PHPDBG_G(ops));
- efree(PHPDBG_G(ops));
- PHPDBG_G(ops) = NULL;
- }
-
- if (full) {
- PHPDBG_G(flags) |= PHPDBG_IS_CLEANING;
-
- zend_bailout();
- }
-} /* }}} */
-
-/* code may behave weirdly if EG(exception) is set */
+/* code may behave weirdly if EG(exception) is set; thus backup it */
#define DO_INTERACTIVE(allow_async_unsafe) do { \
+ const zend_op *backup_opline; \
+ const zend_op *before_ex; \
if (exception) { \
+ if (EG(current_execute_data) && EG(current_execute_data)->func && ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) { \
+ backup_opline = EG(current_execute_data)->opline; \
+ } \
+ before_ex = EG(opline_before_exception); \
++GC_REFCOUNT(exception); \
zend_clear_exception(); \
} \
@@ -1398,20 +1705,26 @@ void phpdbg_clean(zend_bool full) /* {{{ */
efree(file); \
} \
\
- switch (phpdbg_interactive(allow_async_unsafe)) { \
+ switch (phpdbg_interactive(allow_async_unsafe, NULL)) { \
zval zv; \
- default: \
- if (exception) { \
- Z_OBJ(zv) = exception; \
- zend_throw_exception_internal(&zv); \
- } \
- /* fallthrough */ \
case PHPDBG_LEAVE: \
case PHPDBG_FINISH: \
case PHPDBG_UNTIL: \
- case PHPDBG_NEXT:{ \
+ case PHPDBG_NEXT: \
+ if (exception) { \
+ if (EG(current_execute_data) && EG(current_execute_data)->func && ZEND_USER_CODE(EG(current_execute_data)->func->common.type) \
+ && (backup_opline->opcode == ZEND_HANDLE_EXCEPTION || backup_opline->opcode == ZEND_CATCH)) { \
+ EG(current_execute_data)->opline = backup_opline; \
+ EG(exception) = exception; \
+ } else { \
+ Z_OBJ(zv) = exception; \
+ zend_throw_exception_internal(&zv); \
+ } \
+ EG(opline_before_exception) = before_ex; \
+ } \
+ /* fallthrough */ \
+ default: \
goto next; \
- } \
} \
} while (0)
@@ -1439,11 +1752,16 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */
}
#endif
+ if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
+ phpdbg_print_opline_ex(execute_data, 0);
+ goto next;
+ }
+
/* check for uncaught exceptions */
- if (exception && PHPDBG_G(handled_exception) != exception) {
+ if (exception && PHPDBG_G(handled_exception) != exception && !(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
zend_execute_data *prev_ex = execute_data;
zval zv, rv;
- zend_string *file;
+ zend_string *file, *msg;
zend_long line;
do {
@@ -1463,27 +1781,38 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */
ZVAL_OBJ(&zv, exception);
file = zval_get_string(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("file"), 1, &rv));
line = zval_get_long(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("line"), 1, &rv));
-
- phpdbg_error("exception", "name=\"%s\" file=\"%s\" line=\"%lld\"", "Uncaught exception %s in %s on line %lld", ZSTR_VAL(exception->ce->name), ZSTR_VAL(file), line);
+ msg = zval_get_string(zend_read_property(zend_get_exception_base(&zv), &zv, ZEND_STRL("message"), 1, &rv));
+
+ phpdbg_error("exception",
+ "name=\"%s\" file=\"%s\" line=\"" ZEND_LONG_FMT "\"",
+ "Uncaught %s in %s on line " ZEND_LONG_FMT ": %.*s",
+ ZSTR_VAL(exception->ce->name), ZSTR_VAL(file), line,
+ ZSTR_LEN(msg) < 80 ? (int) ZSTR_LEN(msg) : 80, ZSTR_VAL(msg));
+ zend_string_release(msg);
zend_string_release(file);
+
DO_INTERACTIVE(1);
}
ex_is_caught:
- /* allow conditional breakpoints and
- initialization to access the vm uninterrupted */
- if ((PHPDBG_G(flags) & PHPDBG_IN_COND_BP) ||
- (PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) {
+ /* allow conditional breakpoints and initialization to access the vm uninterrupted */
+ if (PHPDBG_G(flags) & (PHPDBG_IN_COND_BP | PHPDBG_IS_INITIALIZING)) {
/* skip possible breakpoints */
goto next;
}
+ /* not while in conditionals */
+ phpdbg_print_opline_ex(execute_data, 0);
+
/* perform seek operation */
- if (PHPDBG_G(flags) & PHPDBG_SEEK_MASK) {
+ if ((PHPDBG_G(flags) & PHPDBG_SEEK_MASK) && !(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
/* current address */
zend_ulong address = (zend_ulong) execute_data->opline;
if (PHPDBG_G(seek_ex) != execute_data) {
+ if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) {
+ goto stepping;
+ }
goto next;
}
@@ -1527,10 +1856,8 @@ ex_is_caught:
}
}
- /* not while in conditionals */
- phpdbg_print_opline_ex(execute_data, 0);
-
if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING && (PHPDBG_G(flags) & PHPDBG_STEP_OPCODE || execute_data->opline->lineno != PHPDBG_G(last_line))) {
+stepping:
PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING;
DO_INTERACTIVE(1);
}
@@ -1573,7 +1900,7 @@ next:
execute_data->call->func->type == ZEND_USER_FUNCTION) {
zend_execute_ex = execute_ex;
}
- PHPDBG_G(vmret) = zend_vm_call_opcode_handler(execute_data);
+ PHPDBG_G(vmret) = zend_vm_call_opcode_handler(execute_data);
zend_execute_ex = phpdbg_execute_ex;
if (PHPDBG_G(vmret) != 0) {
@@ -1597,7 +1924,13 @@ void phpdbg_force_interruption(void) /* {{{ */ {
if (data) {
if (data->func) {
- phpdbg_notice("hardinterrupt", "opline=\"%p\" num=\"%lu\" file=\"%s\" line=\"%u\"", "Current opline: %p (op #%lu) in %s:%u", data->opline, (data->opline - data->func->op_array.opcodes) / sizeof(data->opline), data->func->op_array.filename, data->opline->lineno);
+ if (ZEND_USER_CODE(data->func->type)) {
+ phpdbg_notice("hardinterrupt", "opline=\"%p\" num=\"%lu\" file=\"%s\" line=\"%u\"", "Current opline: %p (op #%lu) in %s:%u", data->opline, (data->opline - data->func->op_array.opcodes) / sizeof(data->opline), data->func->op_array.filename->val, data->opline->lineno);
+ } else if (data->func->internal_function.function_name) {
+ phpdbg_notice("hardinterrupt", "func=\"%s\"", "Current opline: in internal function %s", data->func->internal_function.function_name->val);
+ } else {
+ phpdbg_notice("hardinterrupt", "", "Current opline: executing internal code");
+ }
} else {
phpdbg_notice("hardinterrupt", "opline=\"%p\"", "Current opline: %p (op_array information unavailable)", data->opline);
}
diff --git a/sapi/phpdbg/phpdbg_prompt.h b/sapi/phpdbg/phpdbg_prompt.h
index 25c0b4f71f..e9df703715 100644
--- a/sapi/phpdbg/phpdbg_prompt.h
+++ b/sapi/phpdbg/phpdbg_prompt.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,14 +25,15 @@
void phpdbg_string_init(char *buffer);
void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default);
void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init);
-int phpdbg_interactive(zend_bool allow_async_unsafe);
+int phpdbg_interactive(zend_bool allow_async_unsafe, char *input);
int phpdbg_compile(void);
-void phpdbg_clean(zend_bool full);
+int phpdbg_compile_stdin(zend_string *code);
void phpdbg_force_interruption(void);
/* }}} */
/* {{{ phpdbg command handlers */
PHPDBG_COMMAND(exec);
+PHPDBG_COMMAND(stdin);
PHPDBG_COMMAND(step);
PHPDBG_COMMAND(continue);
PHPDBG_COMMAND(run);
@@ -51,6 +52,7 @@ PHPDBG_COMMAND(clear);
PHPDBG_COMMAND(help);
PHPDBG_COMMAND(sh);
PHPDBG_COMMAND(dl);
+PHPDBG_COMMAND(generator);
PHPDBG_COMMAND(set);
PHPDBG_COMMAND(source);
PHPDBG_COMMAND(export);
@@ -64,11 +66,6 @@ PHPDBG_COMMAND(wait); /* }}} */
/* {{{ prompt commands */
extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */
-/* {{{ */
-#if PHP_VERSION_ID >= 50500
void phpdbg_execute_ex(zend_execute_data *execute_data);
-#else
-void phpdbg_execute_ex(zend_op_array *op_array);
-#endif /* }}} */
#endif /* PHPDBG_PROMPT_H */
diff --git a/sapi/phpdbg/phpdbg_rinit_hook.c b/sapi/phpdbg/phpdbg_rinit_hook.c
index 248b8a323e..e0693acbbf 100644
--- a/sapi/phpdbg/phpdbg_rinit_hook.c
+++ b/sapi/phpdbg/phpdbg_rinit_hook.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_rinit_hook.h b/sapi/phpdbg/phpdbg_rinit_hook.h
index 69d4f61285..2e56df17a9 100644
--- a/sapi/phpdbg/phpdbg_rinit_hook.h
+++ b/sapi/phpdbg/phpdbg_rinit_hook.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_set.c b/sapi/phpdbg/phpdbg_set.c
index f91156a452..47ecbd08b6 100644
--- a/sapi/phpdbg/phpdbg_set.c
+++ b/sapi/phpdbg/phpdbg_set.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -25,13 +25,14 @@
#include "phpdbg_bp.h"
#include "phpdbg_prompt.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s, flags) \
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[17], flags)
const phpdbg_command_t phpdbg_set_commands[] = {
PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt [<string>]", 'p', set_prompt, NULL, "|s", 0),
+ PHPDBG_SET_COMMAND_D(pagination, "usage: set pagination [<on|off>]", 'P', set_pagination, NULL, "|b", PHPDBG_ASYNC_SAFE),
#ifndef _WIN32
PHPDBG_SET_COMMAND_D(color, "usage: set color <element> <color>", 'c', set_color, NULL, "ss", PHPDBG_ASYNC_SAFE),
PHPDBG_SET_COMMAND_D(colors, "usage: set colors [<on|off>]", 'C', set_colors, NULL, "|b", PHPDBG_ASYNC_SAFE),
@@ -42,6 +43,7 @@ const phpdbg_command_t phpdbg_set_commands[] = {
PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet [<on|off>]", 'q', set_quiet, NULL, "|b", PHPDBG_ASYNC_SAFE),
PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping [<line|op>]", 's', set_stepping, NULL, "|s", PHPDBG_ASYNC_SAFE),
PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount [<on|off>]", 'r', set_refcount, NULL, "|b", PHPDBG_ASYNC_SAFE),
+ PHPDBG_SET_COMMAND_D(lines, "usage: set lines [<number>]", 'l', set_lines, NULL, "|l", PHPDBG_ASYNC_SAFE),
PHPDBG_END_COMMAND
};
@@ -56,6 +58,42 @@ PHPDBG_SET(prompt) /* {{{ */
return SUCCESS;
} /* }}} */
+PHPDBG_SET(pagination) /* {{{ */
+{
+ if (!param || param->type == EMPTY_PARAM) {
+ phpdbg_writeln("setpagination", "active=\"%s\"", "Pagination %s", PHPDBG_G(flags) & PHPDBG_HAS_PAGINATION ? "on" : "off");
+ } else switch (param->type) {
+ case NUMERIC_PARAM: {
+ if (param->num) {
+ PHPDBG_G(flags) |= PHPDBG_HAS_PAGINATION;
+ } else {
+ PHPDBG_G(flags) &= ~PHPDBG_HAS_PAGINATION;
+ }
+ } break;
+
+ default:
+ phpdbg_error("setpagination", "type=\"wrongargs\"", "set pagination used incorrectly: set pagination <on|off>");
+ }
+
+ return SUCCESS;
+} /* }}} */
+
+PHPDBG_SET(lines) /* {{{ */
+{
+ if (!param || param->type == EMPTY_PARAM) {
+ phpdbg_writeln("setlines", "active=\"%s\"", "Lines %ld", PHPDBG_G(lines));
+ } else switch (param->type) {
+ case NUMERIC_PARAM: {
+ PHPDBG_G(lines) = param->num;
+ } break;
+
+ default:
+ phpdbg_error("setlines", "type=\"wrongargs\"", "set lines used incorrectly: set lines <number>");
+ }
+
+ return SUCCESS;
+} /* }}} */
+
PHPDBG_SET(break) /* {{{ */
{
switch (param->type) {
diff --git a/sapi/phpdbg/phpdbg_set.h b/sapi/phpdbg/phpdbg_set.h
index 9b2e1ce14e..e1c0105e40 100644
--- a/sapi/phpdbg/phpdbg_set.h
+++ b/sapi/phpdbg/phpdbg_set.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -36,6 +36,8 @@ PHPDBG_SET(breaks);
PHPDBG_SET(quiet);
PHPDBG_SET(stepping);
PHPDBG_SET(refcount);
+PHPDBG_SET(pagination);
+PHPDBG_SET(lines);
extern const phpdbg_command_t phpdbg_set_commands[];
diff --git a/sapi/phpdbg/phpdbg_sigio_win32.c b/sapi/phpdbg/phpdbg_sigio_win32.c
index 8dde7c3cad..db334a0dc5 100644
--- a/sapi/phpdbg/phpdbg_sigio_win32.c
+++ b/sapi/phpdbg/phpdbg_sigio_win32.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 2014-2015 The PHP Group |
+ | Copyright (c) 2014-2016 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 |
@@ -23,7 +23,7 @@
#include "phpdbg_sigio_win32.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
VOID
diff --git a/sapi/phpdbg/phpdbg_sigio_win32.h b/sapi/phpdbg/phpdbg_sigio_win32.h
index c0b190ba58..83b07d64b7 100644
--- a/sapi/phpdbg/phpdbg_sigio_win32.h
+++ b/sapi/phpdbg/phpdbg_sigio_win32.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 2014-2015 The PHP Group |
+ | Copyright (c) 2014-2016 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/phpdbg_sigsafe.c b/sapi/phpdbg/phpdbg_sigsafe.c
index 319c9a5e75..081d864c5c 100644
--- a/sapi/phpdbg/phpdbg_sigsafe.c
+++ b/sapi/phpdbg/phpdbg_sigsafe.c
@@ -1,25 +1,25 @@
#include "phpdbg_sigsafe.h"
#include "phpdbg.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define STR(x) #x
#define EXP_STR(x) STR(x)
static void* zend_mm_mem_alloc(zend_mm_storage *storage, size_t size, size_t alignment) {
- if (EXPECTED(size == PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) {
+ if (EXPECTED(size <= PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) {
PHPDBG_G(sigsafe_mem).allocated = 1;
- return PHPDBG_G(sigsafe_mem).mem;
+ return (void *) (((size_t) PHPDBG_G(sigsafe_mem).mem & ~(alignment - 1)) + alignment);
}
- write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Tried to allocate more than " EXP_STR(PHPDBG_SIGSAFE_MEM_SIZE) " bytes from stack memory in signal handler ... bailing out of signal handler\n"));
+ zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Tried to allocate more than " EXP_STR(PHPDBG_SIGSAFE_MEM_SIZE) " bytes from stack memory in signal handler ... bailing out of signal handler\n"));
if (*EG(bailout)) {
LONGJMP(*EG(bailout), FAILURE);
}
- write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n"));
+ zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n"));
return NULL;
}
diff --git a/sapi/phpdbg/phpdbg_sigsafe.h b/sapi/phpdbg/phpdbg_sigsafe.h
index e5d0f34b43..ab689a38d8 100644
--- a/sapi/phpdbg/phpdbg_sigsafe.h
+++ b/sapi/phpdbg/phpdbg_sigsafe.h
@@ -1,10 +1,7 @@
#ifndef PHPDBG_SIGSAFE_H
#define PHPDBG_SIGSAFE_H
-//#include "zend_mm_structs.h"
-
-#define PHPDBG_SIGSAFE_MEM_SIZE ZEND_MM_CHUNK_SIZE
-//(1 << 20)
+#define PHPDBG_SIGSAFE_MEM_SIZE (ZEND_MM_CHUNK_SIZE * 2)
#include "zend.h"
diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c
index 112f340d6b..684a5a37b5 100644
--- a/sapi/phpdbg/phpdbg_utils.c
+++ b/sapi/phpdbg/phpdbg_utils.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -26,14 +26,19 @@
#include "phpdbg_utils.h"
#include "ext/standard/php_string.h"
-#if defined(HAVE_SYS_IOCTL_H)
-# include "sys/ioctl.h"
-# ifndef GWINSZ_IN_SYS_IOCTL
-# include <termios.h>
-# endif
+/* FASYNC under Solaris */
+#ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
#endif
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+#ifdef HAVE_SYS_IOCTL_H
+# include "sys/ioctl.h"
+# ifndef GWINSZ_IN_SYS_IOCTL
+# include <termios.h>
+# endif
+#endif
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
/* {{{ color structures */
const static phpdbg_color_t colors[] = {
@@ -166,16 +171,20 @@ PHPDBG_API const char *phpdbg_current_file(void) /* {{{ */
PHPDBG_API const zend_function *phpdbg_get_function(const char *fname, const char *cname) /* {{{ */
{
zend_function *func = NULL;
- zend_string *lfname = zend_string_alloc(strlen(fname), 0);
- memcpy(ZSTR_VAL(lfname), zend_str_tolower_dup(fname, ZSTR_LEN(lfname)), ZSTR_LEN(lfname) + 1);
+ zend_string *lfname = zend_string_init(fname, strlen(fname), 0);
+ zend_string *tmp = zend_string_tolower(lfname);
+ zend_string_release(lfname);
+ lfname = tmp;
if (cname) {
zend_class_entry *ce;
- zend_string *lcname = zend_string_alloc(strlen(cname), 0);
- memcpy(ZSTR_VAL(lcname), zend_str_tolower_dup(cname, ZSTR_LEN(lcname)), ZSTR_LEN(lcname) + 1);
+ zend_string *lcname = zend_string_init(cname, strlen(cname), 0);
+ tmp = zend_string_tolower(lcname);
+ zend_string_release(lcname);
+ lcname = tmp;
ce = zend_lookup_class(lcname);
- efree(lcname);
+ zend_string_release(lcname);
if (ce) {
func = zend_hash_find_ptr(&ce->function_table, lfname);
@@ -184,7 +193,7 @@ PHPDBG_API const zend_function *phpdbg_get_function(const char *fname, const cha
func = zend_hash_find_ptr(EG(function_table), lfname);
}
- efree(lfname);
+ zend_string_release(lfname);
return func;
} /* }}} */
@@ -298,16 +307,13 @@ PHPDBG_API const char *phpdbg_get_prompt(void) /* {{{ */
#ifndef HAVE_LIBEDIT
/* TODO: libedit doesn't seems to support coloured prompt */
if ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED)) {
- asprintf(
- &PHPDBG_G(prompt)[1], "\033[%sm%s\033[0m ",
+ ZEND_IGNORE_VALUE(asprintf(&PHPDBG_G(prompt)[1], "\033[%sm%s\033[0m ",
PHPDBG_G(colors)[PHPDBG_COLOR_PROMPT]->code,
- PHPDBG_G(prompt)[0]);
+ PHPDBG_G(prompt)[0]));
} else
#endif
{
- asprintf(
- &PHPDBG_G(prompt)[1], "%s ",
- PHPDBG_G(prompt)[0]);
+ ZEND_IGNORE_VALUE(asprintf(&PHPDBG_G(prompt)[1], "%s ", PHPDBG_G(prompt)[0]));
}
return PHPDBG_G(prompt)[1];
@@ -345,8 +351,26 @@ PHPDBG_API int phpdbg_get_terminal_width(void) /* {{{ */
return columns;
} /* }}} */
+PHPDBG_API int phpdbg_get_terminal_height(void) /* {{{ */
+{
+ int lines;
+#ifdef _WIN32
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+ lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+#elif defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ)
+ struct winsize w;
+
+ lines = ioctl(fileno(stdout), TIOCGWINSZ, &w) == 0 ? w.ws_row : 40;
+#else
+ lines = 40;
+#endif
+ return lines;
+} /* }}} */
+
PHPDBG_API void phpdbg_set_async_io(int fd) {
-#ifndef _WIN32
+#if !defined(_WIN32) && defined(FASYNC)
int flags;
fcntl(STDIN_FILENO, F_SETOWN, getpid());
flags = fcntl(STDIN_FILENO, F_GETFL);
@@ -460,11 +484,11 @@ PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable
key = ZSTR_VAL(strkey);
keylen = ZSTR_LEN(strkey);
} else {
- keylen = spprintf(&key, 0, "%llu", numkey);
+ keylen = spprintf(&key, 0, ZEND_ULONG_FMT, numkey);
}
propkey = phpdbg_get_property_key(key);
name = emalloc(i + keylen + 2);
- namelen = sprintf(name, "%.*s%.*s%s", (int) i, input, keylen - (propkey - key), propkey, input[len - 1] == ']'?"]":"");
+ namelen = sprintf(name, "%.*s%.*s%s", (int) i, input, (int) (keylen - (propkey - key)), propkey, input[len - 1] == ']'?"]":"");
if (!strkey) {
efree(key);
}
@@ -508,7 +532,7 @@ PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable
last_index[index_len] = 0;
if (!(zv = zend_symtable_str_find(parent, last_index, index_len))) {
if (!silent) {
- phpdbg_error("variable", "type=\"undefined\" variable=\"%.*s\"", "%.*s is undefined", (int) i, input);
+ phpdbg_error("variable", "type=\"undefined\" variable=\"%.*s\"", "%.*s is undefined", (int) input[i] == ']' ? i + 1 : i, input);
}
return FAILURE;
}
@@ -573,7 +597,7 @@ static int phpdbg_xml_array_element_dump(zval *zv, zend_string *key, zend_ulong
phpdbg_try_access {
if (key) { /* string key */
- phpdbg_xml(" name=\"%.*s\"", ZSTR_LEN(key), ZSTR_VAL(key));
+ phpdbg_xml(" name=\"%.*s\"", (int) ZSTR_LEN(key), ZSTR_VAL(key));
} else { /* numeric key */
phpdbg_xml(" name=\"%ld\"", num);
}
@@ -607,7 +631,7 @@ static int phpdbg_xml_object_property_dump(zval *zv, zend_string *key, zend_ulon
phpdbg_xml(" class=\"%s\" protection=\"private\"", class_name);
}
} else {
- phpdbg_xml(" name=\"%.*s\" protection=\"public\"", ZSTR_LEN(key), ZSTR_VAL(key));
+ phpdbg_xml(" name=\"%.*s\" protection=\"public\"", (int) ZSTR_LEN(key), ZSTR_VAL(key));
}
} else { /* numeric key */
phpdbg_xml(" name=\"%ld\" protection=\"public\"", num);
@@ -659,7 +683,7 @@ PHPDBG_API void phpdbg_xml_var_dump(zval *zv) {
phpdbg_xml("<float refstatus=\"%s\" value=\"%.*G\" />", COMMON, (int) EG(precision), Z_DVAL_P(zv));
break;
case IS_STRING:
- phpdbg_xml("<string refstatus=\"%s\" length=\"%d\" value=\"%.*s\" />", COMMON, Z_STRLEN_P(zv), Z_STRLEN_P(zv), Z_STRVAL_P(zv));
+ phpdbg_xml("<string refstatus=\"%s\" length=\"%zd\" value=\"%.*s\" />", COMMON, Z_STRLEN_P(zv), (int) Z_STRLEN_P(zv), Z_STRVAL_P(zv));
break;
case IS_ARRAY:
myht = Z_ARRVAL_P(zv);
@@ -681,7 +705,7 @@ PHPDBG_API void phpdbg_xml_var_dump(zval *zv) {
}
class_name = Z_OBJ_HANDLER_P(zv, get_class_name)(Z_OBJ_P(zv));
- phpdbg_xml("<object refstatus=\"%s\" class=\"%.*s\" id=\"%d\" num=\"%d\">", COMMON, ZSTR_LEN(class_name), ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(zv), myht ? zend_hash_num_elements(myht) : 0);
+ phpdbg_xml("<object refstatus=\"%s\" class=\"%.*s\" id=\"%d\" num=\"%d\">", COMMON, (int) ZSTR_LEN(class_name), ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(zv), myht ? zend_hash_num_elements(myht) : 0);
zend_string_release(class_name);
element_dump_func = phpdbg_xml_object_property_dump;
@@ -705,7 +729,7 @@ head_done:
break;
case IS_RESOURCE: {
const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(zv));
- phpdbg_xml("<resource refstatus=\"%s\" id=\"%pd\" type=\"%ld\" />", COMMON, Z_RES_P(zv)->handle, type_name ? type_name : "unknown");
+ phpdbg_xml("<resource refstatus=\"%s\" id=\"%pd\" type=\"%s\" />", COMMON, Z_RES_P(zv)->handle, type_name ? type_name : "unknown");
break;
}
default:
@@ -728,11 +752,11 @@ PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *execute_data, zen
op_num = op - op_array->opcodes;
- for (i = 0; i < op_array->last_try_catch && op_array->try_catch_array[i].try_op < op_num; i++) {
+ for (i = 0; i < op_array->last_try_catch && op_array->try_catch_array[i].try_op <= op_num; i++) {
uint32_t catch = op_array->try_catch_array[i].catch_op, finally = op_array->try_catch_array[i].finally_op;
if (op_num <= catch || op_num <= finally) {
- if (finally && finally < catch) {
- return 0;
+ if (finally) {
+ return 1;
}
do {
@@ -748,7 +772,7 @@ PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *execute_data, zen
return 1;
}
- catch = cur->extended_value;
+ catch += cur->extended_value / sizeof(zend_op);
} while (!cur->result.num);
return 0;
@@ -764,53 +788,69 @@ char *phpdbg_short_zval_print(zval *zv, int maxlen) /* {{{ */
switch (Z_TYPE_P(zv)) {
case IS_UNDEF:
- decode = zend_strndup("", 0);
+ decode = estrdup("");
break;
case IS_NULL:
- decode = zend_strndup(ZEND_STRL("null"));
+ decode = estrdup("null");
break;
case IS_FALSE:
- decode = zend_strndup(ZEND_STRL("false"));
+ decode = estrdup("false");
break;
case IS_TRUE:
- decode = zend_strndup(ZEND_STRL("true"));
+ decode = estrdup("true");
break;
case IS_LONG:
- asprintf(&decode, ZEND_ULONG_FMT, Z_LVAL_P(zv));
+ spprintf(&decode, 0, ZEND_LONG_FMT, Z_LVAL_P(zv));
break;
case IS_DOUBLE:
- asprintf(&decode, "%.*G", 14, Z_DVAL_P(zv));
+ spprintf(&decode, 0, "%.*G", 14, Z_DVAL_P(zv));
+
+ /* Make sure it looks like a float */
+ if (zend_finite(Z_DVAL_P(zv)) && !strchr(decode, '.')) {
+ size_t len = strlen(decode);
+ char *decode2 = emalloc(len + strlen(".0") + 1);
+ memcpy(decode2, decode, len);
+ decode2[len] = '.';
+ decode2[len+1] = '0';
+ decode2[len+2] = '\0';
+ efree(decode);
+ decode = decode2;
+ }
break;
case IS_STRING: {
int i;
- zend_string *str = php_addcslashes(Z_STR_P(zv), 0, "\\\"", 2);
+ zend_string *str = php_addcslashes(Z_STR_P(zv), 0, "\\\"\n\t\0", 5);
for (i = 0; i < ZSTR_LEN(str); i++) {
if (ZSTR_VAL(str)[i] < 32) {
ZSTR_VAL(str)[i] = ' ';
}
}
- asprintf(&decode, "\"%.*s\"%c", ZSTR_LEN(str) <= maxlen - 2 ? (int) ZSTR_LEN(str) : (maxlen - 3), ZSTR_VAL(str), ZSTR_LEN(str) <= maxlen - 2 ? 0 : '+');
+ spprintf(&decode, 0, "\"%.*s\"%c",
+ ZSTR_LEN(str) <= maxlen - 2 ? (int) ZSTR_LEN(str) : (maxlen - 3),
+ ZSTR_VAL(str), ZSTR_LEN(str) <= maxlen - 2 ? 0 : '+');
zend_string_release(str);
} break;
case IS_RESOURCE:
- asprintf(&decode, "Rsrc #%d", Z_RES_HANDLE_P(zv));
+ spprintf(&decode, 0, "Rsrc #%d", Z_RES_HANDLE_P(zv));
break;
case IS_ARRAY:
- asprintf(&decode, "array(%d)", zend_hash_num_elements(Z_ARR_P(zv)));
+ spprintf(&decode, 0, "array(%d)", zend_hash_num_elements(Z_ARR_P(zv)));
break;
case IS_OBJECT: {
zend_string *str = Z_OBJCE_P(zv)->name;
- asprintf(&decode, "%.*s%c", ZSTR_LEN(str) <= maxlen ? (int) ZSTR_LEN(str) : maxlen - 1, ZSTR_VAL(str), ZSTR_LEN(str) <= maxlen ? 0 : '+');
+ spprintf(&decode, 0, "%.*s%c",
+ ZSTR_LEN(str) <= maxlen ? (int) ZSTR_LEN(str) : maxlen - 1,
+ ZSTR_VAL(str), ZSTR_LEN(str) <= maxlen ? 0 : '+');
break;
}
case IS_CONSTANT:
- decode = zend_strndup(ZEND_STRL("<constant>"));
+ decode = estrdup("<constant>");
break;
case IS_CONSTANT_AST:
- decode = zend_strndup(ZEND_STRL("<ast>"));
+ decode = estrdup("<ast>");
break;
default:
- asprintf(&decode, "unknown type: %d", Z_TYPE_P(zv));
+ spprintf(&decode, 0, "unknown type: %d", Z_TYPE_P(zv));
break;
}
diff --git a/sapi/phpdbg/phpdbg_utils.h b/sapi/phpdbg/phpdbg_utils.h
index d4fd352cd4..4ba756139b 100644
--- a/sapi/phpdbg/phpdbg_utils.h
+++ b/sapi/phpdbg/phpdbg_utils.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -73,8 +73,9 @@ PHPDBG_API int phpdbg_get_element(const char *name, size_t len); /* }}} */
PHPDBG_API void phpdbg_set_prompt(const char*);
PHPDBG_API const char *phpdbg_get_prompt(void); /* }}} */
-/* {{{ Console Width */
-PHPDBG_API int phpdbg_get_terminal_width(void); /* }}} */
+/* {{{ Console size */
+PHPDBG_API int phpdbg_get_terminal_width(void);
+PHPDBG_API int phpdbg_get_terminal_height(void); /* }}} */
PHPDBG_API void phpdbg_set_async_io(int fd);
@@ -98,6 +99,14 @@ char *phpdbg_short_zval_print(zval *zv, int maxlen);
PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *ex, zend_object *exception);
+static zend_always_inline zend_execute_data *phpdbg_user_execute_data(zend_execute_data *ex) {
+ while (!ex->func || !ZEND_USER_CODE(ex->func->common.type)) {
+ ex = ex->prev_execute_data;
+ ZEND_ASSERT(ex);
+ }
+ return ex;
+}
+
#ifdef ZTS
#define PHPDBG_OUTPUT_BACKUP_DEFINES() \
zend_output_globals *output_globals_ptr; \
diff --git a/sapi/phpdbg/phpdbg_wait.c b/sapi/phpdbg/phpdbg_wait.c
index 856f6e2b3e..5ef29e895e 100644
--- a/sapi/phpdbg/phpdbg_wait.c
+++ b/sapi/phpdbg/phpdbg_wait.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -21,7 +21,7 @@
#include "ext/standard/php_var.h"
#include "ext/standard/basic_functions.h"
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
static void phpdbg_rebuild_http_globals_array(int type, const char *name) {
zval *zvp;
@@ -50,7 +50,7 @@ typedef struct {
static int phpdbg_array_data_compare(const void *a, const void *b) {
Bucket *f, *s;
- zval result;
+ int result;
zval *first, *second;
f = *((Bucket **) a);
@@ -59,13 +59,11 @@ static int phpdbg_array_data_compare(const void *a, const void *b) {
first = &f->val;
second = &s->val;
- if (string_compare_function(&result, first, second) == FAILURE) {
- return 0;
- }
+ result = string_compare_function(first, second);
- if (Z_LVAL(result) < 0) {
+ if (result < 0) {
return -1;
- } else if (Z_LVAL(result) > 0) {
+ } else if (result > 0) {
return 1;
}
@@ -233,7 +231,7 @@ void phpdbg_webdata_decompress(char *msg, int len) {
} else if (mode > 0) {
// not loaded module
if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_P(module))) {
- phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", Z_STRLEN_P(module), Z_STRVAL_P(module), Z_STRLEN_P(module), Z_STRVAL_P(module));
+ phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", (int) Z_STRLEN_P(module), Z_STRVAL_P(module), (int) Z_STRLEN_P(module), Z_STRVAL_P(module));
}
}
} while (module);
@@ -250,8 +248,10 @@ void phpdbg_webdata_decompress(char *msg, int len) {
extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
while (extension) {
extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
+ if (extension == NULL){
+ break;
+ }
- /* php_serach_array() body should be in some ZEND_API function... */
ZEND_HASH_FOREACH_STR_KEY_PTR(Z_ARRVAL_P(zvp), strkey, name) {
if (Z_TYPE_P(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_P(name), Z_STRLEN_P(name))) {
break;
@@ -283,18 +283,13 @@ void phpdbg_webdata_decompress(char *msg, int len) {
pefree(elm, zend_extensions.persistent);
zend_extensions.count--;
} else {
-/* zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &hpos);
- if (Z_TYPE(key) == IS_LONG) {
- zend_hash_index_del(Z_ARRVAL_PP(zvpp), Z_LVAL(key));
- }
-*/
zend_hash_del(Z_ARRVAL_P(zvp), strkey);
}
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zvp), name) {
if (Z_TYPE_P(name) == IS_STRING) {
- phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", Z_STRLEN_P(name), Z_STRVAL_P(name));
+ phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", (int) Z_STRLEN_P(name), Z_STRVAL_P(name));
}
} ZEND_HASH_FOREACH_END();
}
@@ -351,9 +346,16 @@ PHPDBG_COMMAND(wait) /* {{{ */
if (PHPDBG_G(socket_server_fd) == -1) {
int len;
PHPDBG_G(socket_server_fd) = sl = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sl == -1) {
+ phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Unable to open a socket to UNIX domain socket at %s defined by phpdbg.path ini setting", PHPDBG_G(socket_path));
+ return FAILURE;
+ }
local.sun_family = AF_UNIX;
- strcpy(local.sun_path, PHPDBG_G(socket_path));
+ if (strlcpy(local.sun_path, PHPDBG_G(socket_path), sizeof(local.sun_path)) > sizeof(local.sun_path)) {
+ phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Socket at %s defined by phpdbg.path ini setting is too long", PHPDBG_G(socket_path));
+ return FAILURE;
+ }
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(sl, (struct sockaddr *)&local, len) == -1) {
phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting", PHPDBG_G(socket_path));
@@ -369,6 +371,11 @@ PHPDBG_COMMAND(wait) /* {{{ */
rlen = sizeof(remote);
sr = accept(sl, (struct sockaddr *) &remote, (socklen_t *) &rlen);
+ if (sr == -1) {
+ phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Unable to create a connection to UNIX domain socket at %s defined by phpdbg.path ini setting", PHPDBG_G(socket_path));
+ close(PHPDBG_G(socket_server_fd));
+ return FAILURE;
+ }
char msglen[5];
int recvd = 4;
diff --git a/sapi/phpdbg/phpdbg_wait.h b/sapi/phpdbg/phpdbg_wait.h
index 569e54b5a7..090b10ba61 100644
--- a/sapi/phpdbg/phpdbg_wait.h
+++ b/sapi/phpdbg/phpdbg_wait.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_watch.c b/sapi/phpdbg/phpdbg_watch.c
index 7452771cf2..63af56793b 100644
--- a/sapi/phpdbg/phpdbg_watch.c
+++ b/sapi/phpdbg/phpdbg_watch.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -20,53 +20,86 @@
/* Some information for the reader...
*
- * Watchpoints are either simple, recursive or implicit (PHPDBG_WATCH_* flags)
+ * The main structure managing the direct observations is the watchpoint (phpdbg_watchpoint_t). There are several types of watchpoints currently:
+ * WATCH_ON_BUCKET: a watchpoint on a Bucket element, used to monitor values inside HashTables (largely handled equivalently to WATCH_ON_ZVAL, it just monitors also for IS_UNDEF and key changes)
+ * WATCH_ON_ZVAL: a watchpoint on a bare zval (&zend_reference.val, zval.value.indirect)
+ * WATCH_ON_STR: a watchpoint on a zend_string (put on &ZSTR_LEN() in order to not watch refcount/hash)
+ * WATCH_ON_HASHTABLE: a watchpoint on a HashTable (currently only used to observe size changes, put after flags in order to not watch refcount)
+ * WATCH_ON_REFCOUNTED: a watchpoint on a zend_refcounted, observes the refcount and serves as reference pointer in the custom efree handler
+ * WATCH_ON_HASHDATA: special watchpoint to watch for HT_GET_DATA_ADDR(ht) being efree()'d to be able to properly relocate Bucket watches
+ *
+ * Watch elements are either simple, recursive or implicit (PHPDBG_WATCH_* flags)
* Simple means that a particular watchpoint was explicitely defined
- * Recursive watchpoints are created recursively and substitute simple watchpoints
- * Implicit watchpoints are implicitely created on all ancestors of simple or recursive watchpoints
- * Recursive and (simple or implicit) watchpoints are mutually exclusive
+ * Recursive watch elements are created recursively (recursive root flag is to distinguish the root element easily from its children recursive elements)
+ * Implicit watch elements are implicitely created on all ancestors of simple or recursive watch elements
+ * Recursive and (simple or implicit) watch elements are mutually exclusive
+ * Array/Object to distinguish watch elements on arrays
+ *
+ * Watch elements all contain a reference to a watchpoint (except if scheduled for recreation); a "watch" is a watch element created by the user with a specific id
+ * Each watch has its independent structure of watch elements, watchpoints are responsible for managing collisions and preventing pointers being watched multiple times
*
* PHPDBG_G(watchpoint_tree) contains all watchpoints identified by the watch target address
- * PHPDBG_G(watch_HashTables) contains the dtors of the HashTables to call in our custom dtor (we substitute the dtor of HashTables containing watched zvals by our own dtor)
- * PHPDBG_G(watchpoints) contains all watchpoints (except the ones managed by watch collision)
- * PHPDBG_G(watch_collisions) is indexed by a zend_reference * pointer. It stores information about collisions (everything which contains a zend_reference * may be referenced by multiple watches)
+ * PHPDBG_G(watch_HashTables) contains the addresses of parent_containers of watch elements
+ * PHPDBG_G(watch_elements) contains all directly defined watch elements (i.e. those which have an individual id)
+ * PHPDBG_G(watch_collisions) is indexed by a zend_refcounted * pointer (phpdbg_watchpoint_t.ref). It stores information about collisions (everything which contains a zend_refcounted * may be referenced by multiple watches)
+ * PHPDBG_G(watch_free) is a set of pointers to watch for being freed (like HashTables referenced by phpdbg_watch_element.parent_container)
+ * PHPDBG_G(watch_recreation) is the list of watch elements whose watchpoint has been removed (via efree() for example) and needs to be recreated
+ * PHPDBG_G(watchlist_mem) is the list of unprotected memory pages; used to watch which pages need their PROT_WRITE attribute removed after checking
*
- * Creating a watchpoint:
- * * Create watchpoints with PHPDBG_WATCH_IMPLICIT set on each zval and HashTable in hierarchy except the last zval or HashTable fetch. (if already existing PHPDBG_WATCH_IMPLICIT flag is added)
- * * Create a PHPDBG_WATCH_SIMPLE watch for simple watches or a PHPDBG_WATCH_RECURSIVE watch for recursive watches
- * * When the target zval is an IS_REFERENCE, create a watchpoint on it too
- * * Each time a watchpoints parent is a zval and it is Z_REFCOUNTED(), put a watchpoint (WATCH_ON_REFCOUNTED) on it and add a watchpoint collision
- * * When in recursive mode and encountering a not-refcounted PHPDBG_WATCH_SIMPLE, remove it and recreate it with a PHPDBG_WATCH_RECURSIVE (handled via watch collision)
- * * Make attention to not add something twice or iterate over it twice
+ * Watching on addresses:
+ * * Address and size are transformed into memory page aligned address and size
+ * * mprotect() enables or disables them (depending on flags) - Windows has a transparent compatibility layer in phpdbg_win.c
+ * * segfault handler stores the address of the page and marks it again as writable
+ * * later watchpoints pointing inside these pages are compared against their current value and eventually reactivated (or deleted)
*
- * Deleting a watchpoint:
- * * Only allow deletion of recursive watches at their root and simple watches
- * * Go to referenced variable. And remove watch collision on *parent* (if there is a parent)
- * * If it is Z_REFCOUNTED(), remove that watch collision
+ * Creating a watch:
+ * * Implicit watch elements for each element in the hierarchy (starting from base, which typically is current symbol table) except the last one
+ * * Create a watch element with either simple flag or recursive [+ root] flags
+ * * If the element has recursive flag, create elements recursively for every referenced HashTable and zval
+ *
+ * Creating a watch element:
+ * * For each watch element a related watchpoint is created, if there's none yet; add itself then into the list of parents of that watchpoint
+ * * If the watch has a parent_container, add itself also into a phpdbg_watch_ht_info (inside PHPDBG_G(watch_HashTables)) [and creates it if not yet existing]
+ *
+ * Creation of watchpoints:
+ * * Watchpoints create a watch collision for each refcounted or indirect on the zval (if type is WATCH_ON_BUCKET or WATCH_ON_ZVAL)
+ * * Backs the current value of the watched pointer up
+ * * Installs the watchpoint in PHPDBG_G(watchpoint_tree) and activates it (activation of a watchpoint = remove PROT_WRITE from the pages the watched pointer resides on)
*
* Watch collisions:
- * * hold a counter for recursive, if it is incremented from 0 to 1, create recursive watchpoint
- * * holds a HashTable for normal (not implicit) watchpoints ... it is used to get the fetch type of the HashTable (depending on whether it is empty or not)
- * * holds a HashTable for implicit watchpoints ... (some sort of a refcounter, but ensure that there are no duplicates)
- * * if normal and implicit watchpoints are empty, drop that watch collision and remove WATCH_ON_REFCOUNT alongside with watchpoint on an eventual reference
+ * * Manages a watchpoint on the refcount (WATCH_ON_REFCOUNTED) or indirect zval (WATCH_ON_ZVAL)
+ * * Guarantees that every pointer is watched at most once (by having a pointer to collision mapping in PHPDBG_G(watch_collisions), which have the unique watchpoints for the respective collision)
+ * * Contains a list of parents, i.e. which watchpoints reference it (via watch->ref)
+ * * If no watchpoint is referencing it anymore, the watch collision and its associated watchpoints (phpdbg_watch_collision.ref/reference) are removed
*
- * Watching on addresses:
- * * Address and size are transformed into memory page aligned address and size
- * * mprotect() enables or disables them (depending on flags) - Windows has a transparent compatibility layer in phpdbg_win.c
- * * segfault handler dumps watched memory segment and deactivates watchpoint
- * * later watches inside these memory segments are compared against their current value and eventually reactivated (or deleted)
+ * Deleting a watch:
+ * * Watches are stored by an id in PHPDBG_G(watch_elements); the associated watch element is then deleted
+ * * Deletes all parent and children implicit watch elements
+ *
+ * Deleting a watch element:
+ * * Removes itself from the parent list of the associated watchpoints; if that parent list is empty, also delete the watchpoint
+ * * Removes itself from the related phpdbg_watch_ht_info if it has a parent_container
+ *
+ * Deleting a watchpoint:
+ * * Remove itself from watch collisions this watchpoint participates in
+ * * Removes the watchpoint from PHPDBG_G(watchpoint_tree) and deactivates it (deactivation of a watchpoint = add PROT_WRITE to the pages the watched pointer resides on)
+ *
+ * A watched pointer is efree()'d:
+ * * Needs immediate action as we else may run into dereferencing a pointer into freed memory
+ * * Deletes the associated watchpoint, and for each watch element, if recursive, all its children elements
+ * * If the its watch elements are implicit, recursive roots or simple, they and all their children are dissociated from their watchpoints (i.e. removed from the watchpoint, if no other element is referencing it, it is deleted); adds these elements to PHPDBG_G(watch_recreation)
*
- * A watched zval was removed:
- * * trigger a memory copy (in segv handler) and an automatic deactivation
- * * change a type flag _zval_struct.u1.v.type_flags (add PHPDBG_DESTRUCTED_ZVAL flag) in memory dump
+ * Recreating watchpoints:
+ * * Upon each opcode, PHPDBG_G(watch_recreation) is checked and all its elements are searched for whether the watch is still reachable via the tree given by its implicits
+ * * In case they are not reachable, the watch is deleted (and thus all the related watch elements), else a new watchpoint is created for all the watch elements
+ * * The old and new values of the watches are compared and shown if changed
*
- * A watched zval was changed:
- * * check if parent container has a different reference for referenced zval - recursively update all watches and drop them if necessary
- * * if _zval_struct.u1.v.type_flags & PHPDBG_DESTRUCTED_ZVAL, add it to a list of zvals to be handled at the end (if location was not changed, remove it finally)
- * * display changes if watch->flags & PHPDBG_WATCH_NORMAL (means: not implicit)
- * * handle case where Z_RECOUNTED() or Z_PTR() changed (remove/add collison(s))
- * * if necessary ... on zvals: handle references, if recursive also objects and arrays ... on arrays: if recursive, add new elements
- * * drop destructed zval watchpoints which were not updated
+ * Comparing watchpoints:
+ * * The old and new values of the watches are compared and shown if changed
+ * * If changed, it is checked whether the refcounted/indirect changed and watch collisions removed or created accordingly
+ * * If a zval/bucket watchpoint is recursive, watch elements are added or removed accordingly
+ * * If an array watchpoint is recursive, new array watchpoints are added if there are new ones in the array
+ * * If the watch (element with an id) is not reachable anymore due to changes in implicits, the watch is removed
*/
#include "zend.h"
@@ -80,36 +113,115 @@
# include <sys/mman.h>
#endif
-ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
const phpdbg_command_t phpdbg_watch_commands[] = {
PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, &phpdbg_prompt_commands[24], "s", 0),
- PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, &phpdbg_prompt_commands[24], "s", 0),
+ PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, &phpdbg_prompt_commands[24], "n", 0),
PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, &phpdbg_prompt_commands[24], "s", 0),
PHPDBG_END_COMMAND
};
-//#define HT_FROM_WATCH(watch) (watch->type == WATCH_ON_OBJECT ? watch->addr.obj->handlers->get_properties(watch->parent_container.zv) : watch->type == WATCH_ON_ARRAY ? &watch->addr.arr->ht : NULL)
#define HT_FROM_ZVP(zvp) (Z_TYPE_P(zvp) == IS_OBJECT ? Z_OBJPROP_P(zvp) : Z_TYPE_P(zvp) == IS_ARRAY ? Z_ARRVAL_P(zvp) : NULL)
#define HT_WATCH_OFFSET (sizeof(zend_refcounted *) + sizeof(uint32_t)) /* we are not interested in gc and flags */
#define HT_PTR_HT(ptr) ((HashTable *) (((char *) (ptr)) - HT_WATCH_OFFSET))
#define HT_WATCH_HT(watch) HT_PTR_HT((watch)->addr.ptr)
-typedef struct {
- void *page;
- size_t size;
- char reenable_writing;
- /* data must be last element */
- void *data;
-} phpdbg_watch_memdump;
+/* ### PRINTING POINTER DIFFERENCES ### */
+zend_bool phpdbg_check_watch_diff(phpdbg_watchtype type, void *oldPtr, void *newPtr) {
+ switch (type) {
+ case WATCH_ON_BUCKET:
+ if (memcmp(&((Bucket *) oldPtr)->h, &((Bucket *) newPtr)->h, sizeof(Bucket) - sizeof(zval) /* key/val comparison */) != 0) {
+ return 2;
+ }
+ case WATCH_ON_ZVAL:
+ return memcmp(oldPtr, newPtr, sizeof(zend_value) + sizeof(uint32_t) /* value + typeinfo */) != 0;
+ case WATCH_ON_HASHTABLE:
+ return zend_hash_num_elements(HT_PTR_HT(oldPtr)) != zend_hash_num_elements(HT_PTR_HT(newPtr));
+ case WATCH_ON_REFCOUNTED:
+ return memcmp(oldPtr, newPtr, sizeof(uint32_t) /* no zend_refcounted metadata info */) != 0;
+ case WATCH_ON_STR:
+ return memcmp(oldPtr, newPtr, *(size_t *) oldPtr + XtOffsetOf(zend_string, val) - XtOffsetOf(zend_string, len)) != 0;
+ case WATCH_ON_HASHDATA:
+ ZEND_ASSERT(0);
+ }
+ return 0;
+}
+
+void phpdbg_print_watch_diff(phpdbg_watchtype type, zend_string *name, void *oldPtr, void *newPtr) {
+ int32_t elementDiff;
+
+ PHPDBG_G(watchpoint_hit) = 1;
+
+ phpdbg_notice("watchhit", "variable=\"%s\"", "Breaking on watchpoint %.*s", (int) ZSTR_LEN(name), ZSTR_VAL(name));
+ phpdbg_xml("<watchdata %r>");
+
+ switch (type) {
+ case WATCH_ON_BUCKET:
+ case WATCH_ON_ZVAL:
+ if (Z_REFCOUNTED_P((zval *) oldPtr)) {
+ phpdbg_writeln("watchvalue", "type=\"old\" inaccessible=\"inaccessible\"", "Old value inaccessible or destroyed");
+ } else if (Z_TYPE_P((zval *) oldPtr) == IS_INDIRECT) {
+ phpdbg_writeln("watchvalue", "type=\"old\" inaccessible=\"inaccessible\"", "Old value inaccessible or destroyed (was indirect)");
+ } else {
+ phpdbg_out("Old value: ");
+ phpdbg_xml("<watchvalue %r type=\"old\">");
+ zend_print_flat_zval_r((zval *) oldPtr);
+ phpdbg_xml("</watchvalue>");
+ phpdbg_out("\n");
+ }
+
+ while (Z_TYPE_P((zval *) newPtr) == IS_INDIRECT) {
+ newPtr = Z_INDIRECT_P((zval *) newPtr);
+ }
+
+ phpdbg_out("New value%s: ", Z_ISREF_P((zval *) newPtr) ? " (reference)" : "");
+ phpdbg_xml("<watchvalue %r%s type=\"new\">", Z_ISREF_P((zval *) newPtr) ? " reference=\"reference\"" : "");
+ zend_print_flat_zval_r((zval *) newPtr);
+ phpdbg_xml("</watchvalue>");
+ phpdbg_out("\n");
+ break;
+
+ case WATCH_ON_HASHTABLE:
+ elementDiff = zend_hash_num_elements(HT_PTR_HT(oldPtr)) - zend_hash_num_elements(HT_PTR_HT(newPtr));
+ if (elementDiff > 0) {
+ phpdbg_writeln("watchsize", "removed=\"%d\"", "%d elements were removed from the array", (int) elementDiff);
+ } else if (elementDiff < 0) {
+ phpdbg_writeln("watchsize", "added=\"%d\"", "%d elements were added to the array", (int) -elementDiff);
+ }
+ break;
+
+ case WATCH_ON_REFCOUNTED:
+ phpdbg_writeln("watchrefcount", "type=\"old\" refcount=\"%d\"", "Old refcount: %d", GC_REFCOUNT((zend_refcounted *) oldPtr));
+ phpdbg_writeln("watchrefcount", "type=\"new\" refcount=\"%d\"", "New refcount: %d", GC_REFCOUNT((zend_refcounted *) newPtr));
+ break;
+
+ case WATCH_ON_STR:
+ phpdbg_out("Old value: ");
+ phpdbg_xml("<watchvalue %r type=\"old\">");
+ zend_write((char *) oldPtr + XtOffsetOf(zend_string, val) - XtOffsetOf(zend_string, len), *(size_t *) oldPtr);
+ phpdbg_xml("</watchvalue>");
+ phpdbg_out("\n");
+
+ phpdbg_out("New value: ");
+ phpdbg_xml("<watchvalue %r type=\"new\">");
+ zend_write((char *) newPtr + XtOffsetOf(zend_string, val) - XtOffsetOf(zend_string, len), *(size_t *) newPtr);
+ phpdbg_xml("</watchvalue>");
+ phpdbg_out("\n");
+ break;
-#define MEMDUMP_SIZE(size) (sizeof(phpdbg_watch_memdump) - sizeof(void *) + (size))
+ case WATCH_ON_HASHDATA:
+ ZEND_ASSERT(0);
+ }
+ phpdbg_xml("</watchdata>");
+}
+/* ### LOW LEVEL WATCHPOINT HANDLING ### */
static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr) {
phpdbg_watchpoint_t *watch;
- phpdbg_btree_result *result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong)phpdbg_get_page_boundary(addr) + phpdbg_pagesize - 1);
+ phpdbg_btree_result *result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong) phpdbg_get_page_boundary(addr) + phpdbg_pagesize - 1);
if (result == NULL) {
return NULL;
@@ -139,510 +251,1007 @@ static inline void phpdbg_deactivate_watchpoint(phpdbg_watchpoint_t *watch) {
phpdbg_change_watchpoint_access(watch, PROT_READ | PROT_WRITE);
}
-static inline void phpdbg_store_watchpoint(phpdbg_watchpoint_t *watch) {
+/* Note that consecutive pages need to be merged in order to avoid watchpoints spanning page boundaries to have part of their data in the one page, part in the other page */
+#ifdef _WIN32
+int phpdbg_watchpoint_segfault_handler(void *addr) {
+#else
+int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context) {
+#endif
+
+ void *page = phpdbg_get_page_boundary(
+#ifdef _WIN32
+ addr
+#else
+ info->si_addr
+#endif
+ );
+
+ /* perhaps unnecessary, but check to be sure to not conflict with other segfault handlers */
+ if (phpdbg_check_for_watchpoint(page) == NULL) {
+ return FAILURE;
+ }
+
+ /* re-enable writing */
+ mprotect(page, phpdbg_pagesize, PROT_READ | PROT_WRITE);
+
+ zend_hash_index_add_empty_element(PHPDBG_G(watchlist_mem), (zend_ulong) page);
+
+ return SUCCESS;
+}
+
+/* ### REGISTER WATCHPOINT ### To be used only by watch element and collision managers ### */
+static inline void phpdbg_store_watchpoint_btree(phpdbg_watchpoint_t *watch) {
+ phpdbg_btree_result *res;
+ ZEND_ASSERT((res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr)) == NULL || res->ptr == watch);
phpdbg_btree_insert(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr, watch);
}
-static inline void phpdbg_remove_watchpoint(phpdbg_watchpoint_t *watch) {
+static inline void phpdbg_remove_watchpoint_btree(phpdbg_watchpoint_t *watch) {
phpdbg_btree_delete(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr);
}
-void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch) {
+/* ### SET WATCHPOINT ADDR ### To be used only by watch element and collision managers ### */
+void phpdbg_set_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch) {
watch->addr.ptr = addr;
watch->size = size;
+ watch->ref = NULL;
+ watch->coll = NULL;
+ zend_hash_init(&watch->elements, 8, brml, NULL, 0);
}
-void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch) {
- phpdbg_create_addr_watchpoint(zv, sizeof(zval), watch);
+void phpdbg_set_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch) {
+ phpdbg_set_addr_watchpoint(zv, sizeof(zval) - sizeof(uint32_t), watch);
watch->type = WATCH_ON_ZVAL;
}
-void phpdbg_create_ht_watchpoint(HashTable *ht, phpdbg_watchpoint_t *watch) {
- phpdbg_create_addr_watchpoint(((char *) ht) + HT_WATCH_OFFSET, sizeof(HashTable) - HT_WATCH_OFFSET, watch);
- watch->type = WATCH_ON_HASHTABLE;
- watch->implicit_ht_count = 0;
+void phpdbg_set_bucket_watchpoint(Bucket *bucket, phpdbg_watchpoint_t *watch) {
+ phpdbg_set_addr_watchpoint(bucket, sizeof(Bucket), watch);
+ watch->type = WATCH_ON_BUCKET;
}
-static int phpdbg_create_recursive_ht_watch(phpdbg_watchpoint_t *watch);
-static int phpdbg_create_recursive_zval_watch(phpdbg_watchpoint_t *watch);
-
-void phpdbg_watch_HashTable_dtor(zval *ptr);
+void phpdbg_set_ht_watchpoint(HashTable *ht, phpdbg_watchpoint_t *watch) {
+ phpdbg_set_addr_watchpoint(((char *) ht) + HT_WATCH_OFFSET, sizeof(HashTable) - HT_WATCH_OFFSET, watch);
+ watch->type = WATCH_ON_HASHTABLE;
+}
-static void phpdbg_free_watch(phpdbg_watchpoint_t *watch) {
- zend_string_release(watch->str);
- zend_string_release(watch->name_in_parent);
+void phpdbg_watch_backup_data(phpdbg_watchpoint_t *watch) {
+ switch (watch->type) {
+ case WATCH_ON_BUCKET:
+ case WATCH_ON_ZVAL:
+ case WATCH_ON_REFCOUNTED:
+ memcpy(&watch->backup, watch->addr.ptr, watch->size);
+ break;
+ case WATCH_ON_STR:
+ if (watch->backup.str) {
+ zend_string_release(watch->backup.str);
+ }
+ watch->backup.str = zend_string_init((char *) watch->addr.ptr + XtOffsetOf(zend_string, val) - XtOffsetOf(zend_string, len), *(size_t *) watch->addr.ptr, 1);
+ break;
+ case WATCH_ON_HASHTABLE:
+ memcpy((char *) &watch->backup + HT_WATCH_OFFSET, watch->addr.ptr, watch->size);
+ case WATCH_ON_HASHDATA:
+ break;
+ }
}
-static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch);
-static void phpdbg_delete_ht_watchpoints_recursive(phpdbg_watchpoint_t *watch);
-static void phpdbg_delete_zval_watchpoints_recursive(phpdbg_watchpoint_t *watch);
-static void phpdbg_delete_watchpoints_recursive(phpdbg_watchpoint_t *watch);
-
-/* Store all the possible watches the refcounted may refer to (for displaying & deleting by identifier) [collision] */
-static phpdbg_watchpoint_t *phpdbg_create_refcounted_watchpoint(phpdbg_watchpoint_t *parent, zend_refcounted *ref) {
- phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
- watch->flags = parent->flags;
- watch->parent = parent;
- watch->str = parent->str;
- ++GC_REFCOUNT(parent->str);
- phpdbg_create_addr_watchpoint(&ref->refcount, sizeof(uint32_t), watch);
- watch->type = WATCH_ON_REFCOUNTED;
+/* ### MANAGE WATCH COLLISIONS ### To be used only by watch element manager and memory differ ### */
+/* watch collisions are responsible for having only one watcher on a given refcounted/refval and having a mapping back to the parent zvals */
+void phpdbg_delete_watch_collision(phpdbg_watchpoint_t *watch) {
+ phpdbg_watch_collision *coll;
+ if ((coll = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->ref))) {
+ zend_hash_index_del(&coll->parents, (zend_ulong) watch);
+ if (zend_hash_num_elements(&coll->parents) == 0) {
+ phpdbg_deactivate_watchpoint(&coll->ref);
+ phpdbg_remove_watchpoint_btree(&coll->ref);
+
+ if (coll->ref.type == WATCH_ON_ZVAL) {
+ phpdbg_delete_watch_collision(&coll->ref);
+ } else if (coll->reference.addr.ptr) {
+ phpdbg_deactivate_watchpoint(&coll->reference);
+ phpdbg_remove_watchpoint_btree(&coll->reference);
+ phpdbg_delete_watch_collision(&coll->reference);
+ if (coll->reference.type == WATCH_ON_STR) {
+ zend_string_release(coll->reference.backup.str);
+ }
+ }
- return watch;
+ zend_hash_index_del(&PHPDBG_G(watch_collisions), (zend_ulong) watch->ref);
+ zend_hash_destroy(&coll->parents);
+ efree(coll);
+ }
+ }
}
-/* Must prevent duplicates ... if there are duplicates, replace new by old! */
-static void phpdbg_add_watch_collision(phpdbg_watchpoint_t *watch) {
- phpdbg_watch_collision *cur;
+void phpdbg_update_watch_ref(phpdbg_watchpoint_t *watch) {
+ phpdbg_watch_collision *coll;
- /* Check for either recursive or (simple and/or implicit) */
- ZEND_ASSERT(((watch->flags & PHPDBG_WATCH_RECURSIVE) == 0) ^ ((watch->flags & (PHPDBG_WATCH_IMPLICIT | PHPDBG_WATCH_SIMPLE)) == 0));
+ ZEND_ASSERT(watch->type == WATCH_ON_ZVAL || watch->type == WATCH_ON_BUCKET);
+ if (Z_REFCOUNTED_P(watch->addr.zv)) {
+ if (Z_COUNTED_P(watch->addr.zv) == watch->ref) {
+ return;
+ }
- if ((cur = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->addr.ref))) {
- phpdbg_watchpoint_t *old;
- int flags = 0;
- if ((old = zend_hash_find_ptr(&cur->watches, watch->str)) || (old = zend_hash_find_ptr(&cur->implicit_watches, watch->str))) {
- if (((old->flags ^ watch->flags) & (PHPDBG_WATCH_NORMAL|PHPDBG_WATCH_IMPLICIT)) == 0) {
- return; /* there was no change ... */
+ if (watch->ref != NULL) {
+ phpdbg_delete_watch_collision(watch);
+ }
+
+ watch->ref = Z_COUNTED_P(watch->addr.zv);
+
+ if (!(coll = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->ref))) {
+ coll = emalloc(sizeof(*coll));
+ coll->ref.type = WATCH_ON_REFCOUNTED;
+ phpdbg_set_addr_watchpoint(Z_COUNTED_P(watch->addr.zv), sizeof(uint32_t), &coll->ref);
+ coll->ref.coll = coll;
+ phpdbg_store_watchpoint_btree(&coll->ref);
+ phpdbg_activate_watchpoint(&coll->ref);
+ phpdbg_watch_backup_data(&coll->ref);
+
+ if (Z_ISREF_P(watch->addr.zv)) {
+ phpdbg_set_zval_watchpoint(Z_REFVAL_P(watch->addr.zv), &coll->reference);
+ coll->reference.coll = coll;
+ phpdbg_update_watch_ref(&coll->reference);
+ phpdbg_store_watchpoint_btree(&coll->reference);
+ phpdbg_activate_watchpoint(&coll->reference);
+ phpdbg_watch_backup_data(&coll->reference);
+ } else if (Z_TYPE_P(watch->addr.zv) == IS_STRING) {
+ coll->reference.type = WATCH_ON_STR;
+ phpdbg_set_addr_watchpoint(&Z_STRLEN_P(watch->addr.zv), XtOffsetOf(zend_string, val) - XtOffsetOf(zend_string, len) + Z_STRLEN_P(watch->addr.zv) + 1, &coll->reference);
+ coll->reference.coll = coll;
+ phpdbg_store_watchpoint_btree(&coll->reference);
+ phpdbg_activate_watchpoint(&coll->reference);
+ coll->reference.backup.str = NULL;
+ phpdbg_watch_backup_data(&coll->reference);
+ } else {
+ coll->reference.addr.ptr = NULL;
}
- flags = old->flags;
+ zend_hash_init(&coll->parents, 8, shitty stupid parameter, NULL, 0);
+ zend_hash_index_add_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->ref, coll);
+ }
+ zend_hash_index_add_ptr(&coll->parents, (zend_long) watch, watch);
+ } else if (Z_TYPE_P(watch->addr.zv) == IS_INDIRECT) {
+ if ((zend_refcounted *) Z_INDIRECT_P(watch->addr.zv) == watch->ref) {
+ return;
+ }
- if (flags & PHPDBG_WATCH_RECURSIVE) {
- if (!(watch->flags & PHPDBG_WATCH_RECURSIVE) && !--cur->refs) {
- phpdbg_delete_watchpoints_recursive(watch);
- }
- }
- if (flags & PHPDBG_WATCH_NORMAL) {
- zend_hash_del(&cur->watches, watch->str);
- if (zend_hash_num_elements(&cur->watches) > 0) {
- cur->watch = Z_PTR_P(zend_hash_get_current_data_ex(&cur->watches, NULL));
- } else {
- cur->watch = Z_PTR_P(zend_hash_get_current_data_ex(&cur->implicit_watches, NULL));
- }
- }
- if (flags & PHPDBG_WATCH_IMPLICIT) {
- zend_hash_del(&cur->implicit_watches, watch->str);
- }
+ if (watch->ref != NULL) {
+ phpdbg_delete_watch_collision(watch);
+ }
+
+ watch->ref = (zend_refcounted *) Z_INDIRECT_P(watch->addr.zv);
+
+ if (!(coll = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->ref))) {
+ coll = emalloc(sizeof(*coll));
+ phpdbg_set_zval_watchpoint(Z_INDIRECT_P(watch->addr.zv), &coll->ref);
+ coll->ref.coll = coll;
+ phpdbg_update_watch_ref(&coll->ref);
+ phpdbg_store_watchpoint_btree(&coll->ref);
+ phpdbg_activate_watchpoint(&coll->ref);
+ phpdbg_watch_backup_data(&coll->ref);
- old->flags = watch->flags;
- phpdbg_free_watch(watch);
- efree(watch);
- watch = old;
+ zend_hash_init(&coll->parents, 8, shitty stupid parameter, NULL, 0);
+ zend_hash_index_add_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->ref, coll);
}
- if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
- if (!(flags & PHPDBG_WATCH_RECURSIVE) && !cur->refs++) {
- phpdbg_create_recursive_zval_watch(watch->parent);
- }
+ zend_hash_index_add_ptr(&coll->parents, (zend_long) watch, watch);
+ } else if (watch->ref) {
+ phpdbg_delete_watch_collision(watch);
+ watch->ref = NULL;
+ }
+}
+
+/* ### MANAGE WATCH ELEMENTS ### */
+/* watchpoints must be unique per element. Only one watchpoint may point to one element. But many elements may point to one watchpoint. */
+void phpdbg_recurse_watch_element(phpdbg_watch_element *element);
+void phpdbg_remove_watch_element_recursively(phpdbg_watch_element *element);
+void phpdbg_free_watch_element(phpdbg_watch_element *element);
+void phpdbg_remove_watchpoint(phpdbg_watchpoint_t *watch);
+void phpdbg_watch_parent_ht(phpdbg_watch_element *element);
+
+phpdbg_watch_element *phpdbg_add_watch_element(phpdbg_watchpoint_t *watch, phpdbg_watch_element *element) {
+ phpdbg_btree_result *res;
+ if ((res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr)) == NULL) {
+ phpdbg_watchpoint_t *mem = emalloc(sizeof(*mem));
+ *mem = *watch;
+ watch = mem;
+ phpdbg_store_watchpoint_btree(watch);
+ if (watch->type == WATCH_ON_ZVAL || watch->type == WATCH_ON_BUCKET) {
+ phpdbg_update_watch_ref(watch);
}
+ phpdbg_activate_watchpoint(watch);
+ phpdbg_watch_backup_data(watch);
} else {
- phpdbg_watch_collision coll;
- coll.refs = (watch->flags & PHPDBG_WATCH_RECURSIVE) != 0;
- coll.watch = watch;
- zend_hash_init(&coll.watches, 8, arghs, NULL, 0);
- zend_hash_init(&coll.implicit_watches, 8, ..., NULL, 0);
- cur = zend_hash_index_add_mem(&PHPDBG_G(watch_collisions), (zend_ulong) watch->addr.ref, &coll, sizeof(phpdbg_watch_collision));
- phpdbg_store_watchpoint(cur->watch);
- phpdbg_activate_watchpoint(cur->watch);
- if (coll.refs) {
- phpdbg_create_recursive_zval_watch(watch->parent);
+ phpdbg_watch_element *old_element;
+ watch = res->ptr;
+ if ((old_element = zend_hash_find_ptr(&watch->elements, element->str))) {
+ phpdbg_free_watch_element(element);
+ return old_element;
}
}
- if (watch->flags & PHPDBG_WATCH_NORMAL) {
- cur->watch = watch;
- zend_hash_add_ptr(&cur->watches, watch->str, watch->parent);
- }
- if (watch->flags & PHPDBG_WATCH_IMPLICIT) {
- zend_hash_add_ptr(&cur->implicit_watches, watch->str, watch->parent);
+ element->watch = watch;
+ zend_hash_add_ptr(&watch->elements, element->str, element);
+
+ if (element->flags & PHPDBG_WATCH_RECURSIVE) {
+ phpdbg_recurse_watch_element(element);
}
-}
-static void phpdbg_remove_watch_collision(phpdbg_watchpoint_t *watch) {
- phpdbg_watch_collision *cur;
- if ((cur = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) Z_COUNTED_P(watch->addr.zv)))) {
- if (cur->refs && !--cur->refs) {
- phpdbg_delete_watchpoints_recursive(watch);
- }
+ return element;
+}
- zend_hash_del(&cur->watches, watch->str);
- zend_hash_del(&cur->implicit_watches, watch->str);
+phpdbg_watch_element *phpdbg_add_bucket_watch_element(Bucket *bucket, phpdbg_watch_element *element) {
+ phpdbg_watchpoint_t watch;
+ phpdbg_set_bucket_watchpoint(bucket, &watch);
+ element = phpdbg_add_watch_element(&watch, element);
+ phpdbg_watch_parent_ht(element);
+ return element;
+}
- if (zend_hash_num_elements(&cur->watches) > 0) {
- cur->watch = Z_PTR_P(zend_hash_get_current_data_ex(&cur->watches, NULL));
- } else if (zend_hash_num_elements(&cur->implicit_watches) > 0) {
- cur->watch = Z_PTR_P(zend_hash_get_current_data_ex(&cur->implicit_watches, NULL));
- } else {
- phpdbg_deactivate_watchpoint(cur->watch);
- phpdbg_remove_watchpoint(cur->watch);
+phpdbg_watch_element *phpdbg_add_ht_watch_element(zval *zv, phpdbg_watch_element *element) {
+ phpdbg_watchpoint_t watch;
+ HashTable *ht = HT_FROM_ZVP(zv);
- zend_hash_index_del(&PHPDBG_G(watch_collisions), (zend_ulong) Z_COUNTED_P(watch->addr.zv));
- }
+ if (!ht) {
+ return NULL;
}
+
+ element->flags |= Z_TYPE_P(zv) == IS_ARRAY ? PHPDBG_WATCH_ARRAY : PHPDBG_WATCH_OBJECT;
+ phpdbg_set_ht_watchpoint(ht, &watch);
+ return phpdbg_add_watch_element(&watch, element);
}
-static phpdbg_watchpoint_t *phpdbg_create_watchpoint(phpdbg_watchpoint_t *watch);
+zend_bool phpdbg_is_recursively_watched(void *ptr, phpdbg_watch_element *element) {
+ phpdbg_watch_element *next = element;
+ do {
+ element = next;
+ if (element->watch->addr.ptr == ptr) {
+ return 1;
+ }
+ next = element->parent;
+ } while (!(element->flags & PHPDBG_WATCH_RECURSIVE_ROOT));
-static phpdbg_watchpoint_t *phpdbg_create_reference_watch(phpdbg_watchpoint_t *watch) {
- phpdbg_watchpoint_t *ref = emalloc(sizeof(phpdbg_watchpoint_t));
- watch->reference = ref;
- ref->flags = watch->flags;
- ref->str = watch->str;
- ++GC_REFCOUNT(ref->str);
- ref->parent = watch;
- ref->parent_container = NULL;
- phpdbg_create_zval_watchpoint(Z_REFVAL_P(watch->addr.zv), ref);
+ return 0;
+}
- phpdbg_create_watchpoint(ref);
+void phpdbg_add_recursive_watch_from_ht(phpdbg_watch_element *element, zend_long idx, zend_string *str, zval *zv) {
+ phpdbg_watch_element *child;
+ if (phpdbg_is_recursively_watched(zv, element)) {
+ return;
+ }
- return ref;
+ child = emalloc(sizeof(*child));
+ child->flags = PHPDBG_WATCH_RECURSIVE;
+ if (str) {
+ child->str = strpprintf(0, (element->flags & PHPDBG_WATCH_ARRAY) ? "%.*s[%s]" : "%.*s->%s", (int) ZSTR_LEN(element->str) - 2, ZSTR_VAL(element->str), phpdbg_get_property_key(ZSTR_VAL(str)));
+ } else {
+ child->str = strpprintf(0, (element->flags & PHPDBG_WATCH_ARRAY) ? "%.*s[" ZEND_LONG_FMT "]" : "%.*s->" ZEND_LONG_FMT, (int) ZSTR_LEN(element->str) - 2, ZSTR_VAL(element->str), idx);
+ }
+ if (!str) {
+ str = zend_long_to_str(idx); // TODO: hack, use proper int handling for name in parent
+ } else { str = zend_string_copy(str); }
+ child->name_in_parent = str;
+ child->parent = element;
+ child->child = NULL;
+ child->parent_container = HT_WATCH_HT(element->watch);
+ zend_hash_add_ptr(&element->child_container, child->str, child);
+ phpdbg_add_bucket_watch_element((Bucket *) zv, child);
}
-static phpdbg_watchpoint_t *phpdbg_get_refcount_watch(phpdbg_watchpoint_t *parent) {
- zend_refcounted *ref;
- phpdbg_btree_result *res;
+void phpdbg_recurse_watch_element(phpdbg_watch_element *element) {
+ phpdbg_watch_element *child;
+ zval *zv;
- if (parent->type == WATCH_ON_HASHTABLE) {
- parent = parent->parent;
- if (!parent) {
- return NULL;
+ if (element->watch->type == WATCH_ON_ZVAL || element->watch->type == WATCH_ON_BUCKET) {
+ zv = element->watch->addr.zv;
+ while (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ ZVAL_DEREF(zv);
+
+ if (element->child) {
+ phpdbg_remove_watch_element_recursively(element->child);
}
- }
- ZEND_ASSERT(parent->type == WATCH_ON_ZVAL);
- ref = Z_COUNTED_P(parent->addr.zv);
+ if ((Z_TYPE_P(zv) != IS_ARRAY && Z_TYPE_P(zv) != IS_OBJECT)
+ || phpdbg_is_recursively_watched(HT_WATCH_OFFSET + (char *) HT_FROM_ZVP(zv), element)) {
+ if (element->child) {
+ phpdbg_free_watch_element(element->child);
+ element->child = NULL;
+ }
+ return;
+ }
- res = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) ref);
- if (res) {
- return res->ptr;
+ if (element->child) {
+ child = element->child;
+ } else {
+ child = emalloc(sizeof(*child));
+ child->flags = PHPDBG_WATCH_RECURSIVE;
+ child->str = strpprintf(0, "%.*s[]", (int) ZSTR_LEN(element->str), ZSTR_VAL(element->str));
+ child->name_in_parent = NULL;
+ child->parent = element;
+ child->child = NULL;
+ element->child = child;
+ }
+ zend_hash_init(&child->child_container, 8, NULL, NULL, 0);
+ phpdbg_add_ht_watch_element(zv, child);
+ } else if (zend_hash_num_elements(&element->child_container) == 0) {
+ zend_string *str;
+ zend_long idx;
+
+ ZEND_ASSERT(element->watch->type == WATCH_ON_HASHTABLE);
+ ZEND_HASH_FOREACH_KEY_VAL(HT_WATCH_HT(element->watch), idx, str, zv) {
+ phpdbg_add_recursive_watch_from_ht(element, idx, str, zv);
+ } ZEND_HASH_FOREACH_END();
}
- return NULL;
}
-static phpdbg_watchpoint_t *phpdbg_create_watchpoint(phpdbg_watchpoint_t *watch) {
- phpdbg_watchpoint_t *ret = watch;
-
- /* exclude references & refcounted */
- if (!watch->parent || watch->parent->type != WATCH_ON_ZVAL || watch->type == WATCH_ON_HASHTABLE) {
- phpdbg_watchpoint_t *old_watch = zend_hash_find_ptr(&PHPDBG_G(watchpoints), watch->str);
-
- if (old_watch) {
-#define return_and_free_watch(x) { \
- phpdbg_watchpoint_t *ref = phpdbg_get_refcount_watch(old_watch); \
- if (ref) { \
- phpdbg_add_watch_collision(ref); \
- } \
- phpdbg_free_watch(watch); \
- efree(watch); \
- return (x); \
-}
- if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
- if (old_watch->flags & PHPDBG_WATCH_RECURSIVE) {
- return_and_free_watch(NULL);
- } else {
- old_watch->flags &= ~(PHPDBG_WATCH_SIMPLE | PHPDBG_WATCH_IMPLICIT);
- old_watch->flags |= PHPDBG_WATCH_RECURSIVE;
- return_and_free_watch(old_watch);
- }
- } else {
- if (!(old_watch->flags & PHPDBG_WATCH_RECURSIVE)) {
- old_watch->flags |= watch->flags & (PHPDBG_WATCH_IMPLICIT | PHPDBG_WATCH_SIMPLE);
- }
- return_and_free_watch(NULL);
- }
+void phpdbg_watch_parent_ht(phpdbg_watch_element *element) {
+ if (element->watch->type == WATCH_ON_BUCKET) {
+ phpdbg_btree_result *res;
+ HashPosition pos;
+ phpdbg_watch_ht_info *hti;
+ ZEND_ASSERT(element->parent_container);
+ if (!(res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) element->parent_container))) {
+ hti = emalloc(sizeof(*hti));
+ hti->ht = element->parent_container;
+
+ zend_hash_init(&hti->watches, 0, grrrrr, ZVAL_PTR_DTOR, 0);
+ phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong) hti->ht, hti);
+
+ phpdbg_set_addr_watchpoint(HT_GET_DATA_ADDR(hti->ht), HT_HASH_SIZE(hti->ht->nTableMask), &hti->hash_watch);
+ hti->hash_watch.type = WATCH_ON_HASHDATA;
+ phpdbg_store_watchpoint_btree(&hti->hash_watch);
+ phpdbg_activate_watchpoint(&hti->hash_watch);
} else {
- if (watch->parent && watch->parent->type == WATCH_ON_HASHTABLE) {
- watch->parent->implicit_ht_count++;
- }
- zend_hash_add_ptr(&PHPDBG_G(watchpoints), watch->str, watch);
+ hti = (phpdbg_watch_ht_info *) res->ptr;
}
- }
- phpdbg_store_watchpoint(watch);
+ zend_hash_internal_pointer_end_ex(hti->ht, &pos);
+ hti->last = hti->ht->arData + pos;
+ hti->last_str = hti->last->key;
+ hti->last_idx = hti->last->h;
- if (watch->parent && watch->parent->type == WATCH_ON_ZVAL && Z_REFCOUNTED_P(watch->parent->addr.zv)) {
- phpdbg_add_watch_collision(phpdbg_create_refcounted_watchpoint(watch, Z_COUNTED_P(watch->parent->addr.zv)));
+ zend_hash_add_ptr(&hti->watches, element->name_in_parent, element);
}
+}
+
+void phpdbg_unwatch_parent_ht(phpdbg_watch_element *element) {
+ if (element->watch->type == WATCH_ON_BUCKET) {
+ phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) element->parent_container);
+ ZEND_ASSERT(element->parent_container);
+ if (res) {
+ phpdbg_watch_ht_info *hti = res->ptr;
- if (watch->type == WATCH_ON_ZVAL) {
- if (watch->parent_container) {
- HashTable *ht_watches;
- phpdbg_btree_result *find;
- if (!(find = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) watch->parent_container))) {
- phpdbg_watch_ht_info *hti = emalloc(sizeof(*hti));
- hti->dtor = watch->parent_container->pDestructor;
- ht_watches = &hti->watches;
- zend_hash_init(ht_watches, 0, grrrrr, ZVAL_PTR_DTOR, 0);
- phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong) watch->parent_container, hti);
- watch->parent_container->pDestructor = (dtor_func_t) phpdbg_watch_HashTable_dtor;
+ if (zend_hash_num_elements(&hti->watches) == 1) {
+ zend_hash_destroy(&hti->watches);
+ phpdbg_btree_delete(&PHPDBG_G(watch_HashTables), (zend_ulong) hti->ht);
+ phpdbg_deactivate_watchpoint(&hti->hash_watch);
+ phpdbg_remove_watchpoint_btree(&hti->hash_watch);
+ efree(hti);
} else {
- ht_watches = &((phpdbg_watch_ht_info *) find->ptr)->watches;
+ zend_hash_del(&hti->watches, element->name_in_parent);
}
- zend_hash_add_ptr(ht_watches, watch->name_in_parent, watch);
- }
-
- if (Z_ISREF_P(watch->addr.zv)) {
- ret = phpdbg_create_reference_watch(watch);
}
}
+}
- phpdbg_activate_watchpoint(watch);
+/* ### DE/QUEUE WATCH ELEMENTS ### to be used by watch element manager only */
+/* implicit watchpoints may change (especially because of separation); elements updated by remove & re-add etc.; thus we need to wait a little bit (until next opcode) and then compare whether the watchpoint still exists and if not, remove it */
- return ret;
-}
+void phpdbg_dissociate_watch_element(phpdbg_watch_element *element, phpdbg_watch_element *until);
+void phpdbg_free_watch_element_tree(phpdbg_watch_element *element);
-static int phpdbg_create_simple_watchpoint(phpdbg_watchpoint_t *watch) {
- watch->flags |= PHPDBG_WATCH_SIMPLE;
+void phpdbg_queue_element_for_recreation(phpdbg_watch_element *element) {
+ /* store lowermost element */
+ phpdbg_watch_element *prev;
- phpdbg_create_watchpoint(watch);
+ if ((prev = zend_hash_find_ptr(&PHPDBG_G(watch_recreation), element->str))) {
+ phpdbg_watch_element *child = prev;
+ do {
+ if (child == element) {
+ return;
+ }
+ child = child->child;
+ } while (child);
+ }
+ zend_hash_update_ptr(&PHPDBG_G(watch_recreation), element->str, element);
- return SUCCESS;
-}
+ /* dissociate from watchpoint to avoid dangling memory watches */
+ phpdbg_dissociate_watch_element(element, prev);
-static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *zv_watch) {
- zval *zv = zv_watch->addr.zv;
- phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
- HashTable *ht = HT_FROM_ZVP(zv);
+ if (!element->parent) {
+ /* HERE BE DRAGONS; i.e. we assume HashTable is directly allocated via emalloc() ... (which *should be* the case for every user-accessible array and symbol tables) */
+ zend_hash_index_add_empty_element(&PHPDBG_G(watch_free), (zend_ulong) element->parent_container);
+ }
+}
- watch->parent = zv_watch;
+zend_bool phpdbg_try_readding_watch_element(zval *parent, phpdbg_watch_element *element) {
+ zval *zv;
+ HashTable *ht = HT_FROM_ZVP(parent);
if (!ht) {
- return FAILURE;
- }
+ return 0;
+ } else if (element->flags & (PHPDBG_WATCH_ARRAY | PHPDBG_WATCH_OBJECT)) {
+ char *htPtr = ((char *) ht) + HT_WATCH_OFFSET;
+ char *oldPtr = ((char *) &element->backup.ht) + HT_WATCH_OFFSET;
+ if (phpdbg_check_watch_diff(WATCH_ON_HASHTABLE, oldPtr, htPtr)) {
+ phpdbg_print_watch_diff(WATCH_ON_HASHTABLE, element->str, oldPtr, htPtr);
+ }
- phpdbg_create_ht_watchpoint(ht, watch);
+ phpdbg_add_ht_watch_element(parent, element);
+ } else if ((zv = zend_symtable_find(ht, element->name_in_parent))) {
+ if (element->flags & PHPDBG_WATCH_IMPLICIT) {
+ zval *next = zv;
- if (phpdbg_create_watchpoint(watch) == NULL) {
- return SUCCESS;
- }
+ while (Z_TYPE_P(next) == IS_INDIRECT) {
+ next = Z_INDIRECT_P(next);
+ }
+ if (Z_ISREF_P(next)) {
+ next = Z_REFVAL_P(next);
+ }
+
+ if (!phpdbg_try_readding_watch_element(next, element->child)) {
+ return 0;
+ }
+ } else if (phpdbg_check_watch_diff(WATCH_ON_ZVAL, &element->backup.zv, zv)) {
+ phpdbg_print_watch_diff(WATCH_ON_ZVAL, element->str, &element->backup.zv, zv);
+ }
- if (Z_TYPE_P(zv) == IS_ARRAY) {
- watch->flags |= PHPDBG_WATCH_ARRAY;
+ element->parent_container = ht;
+ phpdbg_add_bucket_watch_element((Bucket *) zv, element);
+ phpdbg_watch_parent_ht(element);
} else {
- watch->flags |= PHPDBG_WATCH_OBJECT;
+ return 0;
}
- phpdbg_add_watch_collision(phpdbg_create_refcounted_watchpoint(watch, Z_COUNTED_P(zv)));
-
- return SUCCESS;
+ return 1;
}
-static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch) {
- if (watch->type != WATCH_ON_ZVAL) {
- return FAILURE;
+void phpdbg_automatic_dequeue_free(phpdbg_watch_element *element) {
+ phpdbg_watch_element *child = element;
+ while (child->child && !(child->flags & PHPDBG_WATCH_RECURSIVE_ROOT)) {
+ child = child->child;
}
+ PHPDBG_G(watchpoint_hit) = 1;
+ phpdbg_notice("watchdelete", "variable=\"%.*s\" recursive=\"%s\"", "%.*s has been removed, removing watchpoint%s", (int) ZSTR_LEN(child->str), ZSTR_VAL(child->str), (child->flags & PHPDBG_WATCH_RECURSIVE_ROOT) ? " recursively" : "");
+ zend_hash_index_del(&PHPDBG_G(watch_elements), child->id);
+ phpdbg_free_watch_element_tree(element);
+}
- watch->flags |= PHPDBG_WATCH_RECURSIVE;
- watch = phpdbg_create_watchpoint(watch);
+void phpdbg_dequeue_elements_for_recreation() {
+ phpdbg_watch_element *element;
+
+ ZEND_HASH_FOREACH_PTR(&PHPDBG_G(watch_recreation), element) {
+ ZEND_ASSERT(element->flags & (PHPDBG_WATCH_IMPLICIT | PHPDBG_WATCH_RECURSIVE_ROOT | PHPDBG_WATCH_SIMPLE));
+ if (element->parent || zend_hash_index_find(&PHPDBG_G(watch_free), (zend_ulong) element->parent_container)) {
+ zval _zv, *zv = &_zv;
+ if (element->parent) {
+ ZEND_ASSERT(element->parent->watch->type == WATCH_ON_ZVAL || element->parent->watch->type == WATCH_ON_BUCKET);
+ zv = element->parent->watch->addr.zv;
+ while (Z_TYPE_P(zv) == IS_INDIRECT) {
+ zv = Z_INDIRECT_P(zv);
+ }
+ ZVAL_DEREF(zv);
+ } else {
+ ZVAL_ARR(zv, element->parent_container);
+ }
+ if (!phpdbg_try_readding_watch_element(zv, element)) {
+ phpdbg_automatic_dequeue_free(element);
+ }
+ } else {
+ phpdbg_automatic_dequeue_free(element);
+ }
+ } ZEND_HASH_FOREACH_END();
- return SUCCESS;
+ zend_hash_clean(&PHPDBG_G(watch_recreation));
+ zend_hash_clean(&PHPDBG_G(watch_free));
}
-static int phpdbg_create_recursive_ht_watch(phpdbg_watchpoint_t *watch) {
- zval *zv;
- zend_string *key;
- zend_long h;
- size_t str_len;
+/* ### WATCH ELEMENT DELETION ### only use phpdbg_remove_watch_element from the exterior */
+void phpdbg_clean_watch_element(phpdbg_watch_element *element);
- ZEND_ASSERT(watch->type == WATCH_ON_HASHTABLE);
+void phpdbg_free_watch_element(phpdbg_watch_element *element) {
+ zend_string_release(element->str);
+ if (element->name_in_parent) {
+ zend_string_release(element->name_in_parent);
+ }
+ efree(element);
+}
- ZEND_HASH_FOREACH_KEY_VAL(HT_WATCH_HT(watch), h, key, zv) {
- char *str = NULL;
- phpdbg_watchpoint_t *new_watch = emalloc(sizeof(phpdbg_watchpoint_t));
+/* note: does *not* free the passed element, only clean */
+void phpdbg_remove_watch_element_recursively(phpdbg_watch_element *element) {
+ if (element->child) {
+ phpdbg_remove_watch_element_recursively(element->child);
+ phpdbg_free_watch_element(element->child);
+ element->child = NULL;
+ } else if (element->flags & (PHPDBG_WATCH_ARRAY | PHPDBG_WATCH_OBJECT)) {
+ phpdbg_watch_element *child;
+ ZEND_HASH_FOREACH_PTR(&element->child_container, child) {
+ phpdbg_remove_watch_element_recursively(child);
+ phpdbg_free_watch_element(child);
+ } ZEND_HASH_FOREACH_END();
+ zend_hash_destroy(&element->child_container);
+ }
- new_watch->flags = PHPDBG_WATCH_RECURSIVE;
- new_watch->parent = watch;
- new_watch->parent_container = HT_WATCH_HT(watch);
+ phpdbg_clean_watch_element(element);
+}
- if (key) {
- new_watch->name_in_parent = key;
- ++GC_REFCOUNT(key);
+/* remove single watch (i.e. manual unset) or implicit removed */
+void phpdbg_remove_watch_element(phpdbg_watch_element *element) {
+ phpdbg_watch_element *parent = element->parent, *child = element->child;
+ while (parent) {
+ phpdbg_watch_element *cur = parent;
+ parent = parent->parent;
+ phpdbg_clean_watch_element(cur);
+ phpdbg_free_watch_element(cur);
+ }
+ while (child) {
+ phpdbg_watch_element *cur = child;
+ child = child->child;
+ if (cur->flags & PHPDBG_WATCH_RECURSIVE_ROOT) {
+ phpdbg_remove_watch_element_recursively(cur);
+ child = NULL;
} else {
- str_len = spprintf(&str, 0, "%lld", h);
- new_watch->name_in_parent = zend_string_init(str, str_len, 0);
- efree(str);
+ phpdbg_clean_watch_element(cur);
}
+ phpdbg_free_watch_element(cur);
+ }
+ if (element->flags & PHPDBG_WATCH_RECURSIVE_ROOT) {
+ phpdbg_remove_watch_element_recursively(element);
+ } else {
+ phpdbg_clean_watch_element(element);
+ }
+ zend_hash_index_del(&PHPDBG_G(watch_elements), element->id);
+ phpdbg_free_watch_element(element);
+}
- str_len = spprintf(&str, 0, "%.*s%s%s%s", (int) ZSTR_LEN(watch->str) - 2, ZSTR_VAL(watch->str), (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", phpdbg_get_property_key(ZSTR_VAL(new_watch->name_in_parent)), (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : "");
- new_watch->str = zend_string_init(str, str_len, 0);
- efree(str);
+void phpdbg_backup_watch_element(phpdbg_watch_element *element) {
+ memcpy(&element->backup, &element->watch->backup, /* element->watch->size */ sizeof(element->backup));
+}
- while (Z_TYPE_P(zv) == IS_INDIRECT) {
- zv = Z_INDIRECT_P(zv);
- }
+/* until argument to prevent double remove of children elements */
+void phpdbg_dissociate_watch_element(phpdbg_watch_element *element, phpdbg_watch_element *until) {
+ phpdbg_watch_element *child = element;
+ ZEND_ASSERT((element->flags & (PHPDBG_WATCH_RECURSIVE_ROOT | PHPDBG_WATCH_RECURSIVE)) != PHPDBG_WATCH_RECURSIVE);
- phpdbg_create_zval_watchpoint(zv, new_watch);
- new_watch = phpdbg_create_watchpoint(new_watch);
- phpdbg_create_recursive_zval_watch(new_watch);
- } ZEND_HASH_FOREACH_END();
+ if (element->flags & PHPDBG_WATCH_RECURSIVE_ROOT) {
+ phpdbg_backup_watch_element(element);
+ phpdbg_remove_watch_element_recursively(element);
+ return;
+ }
- return SUCCESS;
+ while (child->child != until) {
+ child = child->child;
+ if (child->flags & PHPDBG_WATCH_RECURSIVE_ROOT) {
+ phpdbg_backup_watch_element(child);
+ phpdbg_remove_watch_element_recursively(child);
+ child->child = NULL;
+ break;
+ }
+ if (child->child == NULL || (child->flags & PHPDBG_WATCH_RECURSIVE_ROOT)) {
+ phpdbg_backup_watch_element(child);
+ }
+ phpdbg_clean_watch_element(child);
+ }
+ /* element needs to be removed last! */
+ if (element->child == NULL) {
+ phpdbg_backup_watch_element(element);
+ }
+ phpdbg_clean_watch_element(element);
}
-static int phpdbg_create_recursive_zval_watch(phpdbg_watchpoint_t *watch) {
- size_t str_len;
- HashTable *ht;
- zval *zvp;
-
- ZEND_ASSERT(watch->type == WATCH_ON_ZVAL);
+/* unlike phpdbg_remove_watch_element this *only* frees and does not clean up element + children! Only use after previous cleanup (e.g. phpdbg_dissociate_watch_element) */
+void phpdbg_free_watch_element_tree(phpdbg_watch_element *element) {
+ phpdbg_watch_element *parent = element->parent, *child = element->child;
+ while (parent) {
+ phpdbg_watch_element *cur = parent;
+ parent = parent->parent;
+ phpdbg_clean_watch_element(cur);
+ phpdbg_free_watch_element(cur);
+ }
+ while (child) {
+ phpdbg_watch_element *cur = child;
+ child = child->child;
+ phpdbg_free_watch_element(cur);
+ }
+ phpdbg_free_watch_element(element);
+}
- zvp = watch->addr.zv;
- ZVAL_DEREF(zvp);
+void phpdbg_update_watch_element_watch(phpdbg_watch_element *element) {
+ if (element->flags & PHPDBG_WATCH_IMPLICIT) {
+ phpdbg_watch_element *child = element->child;
+ while (child->flags & PHPDBG_WATCH_IMPLICIT) {
+ child = child->child;
+ }
- if ((ht = HT_FROM_ZVP(zvp))) {
- char *str = NULL;
- phpdbg_watchpoint_t *new_watch = emalloc(sizeof(phpdbg_watchpoint_t));
+ ZEND_ASSERT(element->watch->type == WATCH_ON_ZVAL || element->watch->type == WATCH_ON_BUCKET);
+ phpdbg_queue_element_for_recreation(element);
+ } else if (element->flags & (PHPDBG_WATCH_RECURSIVE_ROOT | PHPDBG_WATCH_SIMPLE)) {
+ phpdbg_queue_element_for_recreation(element);
+ } else if (element->flags & PHPDBG_WATCH_RECURSIVE) {
+ phpdbg_remove_watch_element_recursively(element);
+ if (element->parent->flags & (PHPDBG_WATCH_OBJECT | PHPDBG_WATCH_ARRAY)) {
+ zend_hash_del(&element->parent->child_container, element->str);
+ } else {
+ element->parent->child = NULL;
+ }
+ phpdbg_free_watch_element(element);
+ }
+}
- new_watch->flags = PHPDBG_WATCH_RECURSIVE;
- new_watch->parent = watch;
- new_watch->parent_container = watch->parent_container;
- new_watch->name_in_parent = watch->name_in_parent;
- ++GC_REFCOUNT(new_watch->name_in_parent);
- str_len = spprintf(&str, 0, "%.*s[]", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str));
- new_watch->str = zend_string_init(str, str_len, 0);
- efree(str);
+void phpdbg_update_watch_collision_elements(phpdbg_watchpoint_t *watch) {
+ phpdbg_watchpoint_t *parent;
+ phpdbg_watch_element *element;
- if (Z_TYPE_P(zvp) == IS_ARRAY) {
- new_watch->flags |= PHPDBG_WATCH_ARRAY;
+ ZEND_HASH_FOREACH_PTR(&watch->coll->parents, parent) {
+ if (parent->coll) {
+ phpdbg_update_watch_collision_elements(parent);
} else {
- new_watch->flags |= PHPDBG_WATCH_OBJECT;
+ ZEND_HASH_FOREACH_PTR(&parent->elements, element) {
+ phpdbg_update_watch_element_watch(element);
+ } ZEND_HASH_FOREACH_END();
}
+ } ZEND_HASH_FOREACH_END();
+}
+
+void phpdbg_remove_watchpoint(phpdbg_watchpoint_t *watch) {
+ phpdbg_watch_element *element;
+
+ phpdbg_deactivate_watchpoint(watch);
+ phpdbg_remove_watchpoint_btree(watch);
+ phpdbg_delete_watch_collision(watch);
- phpdbg_create_ht_watchpoint(ht, new_watch);
+ if (watch->coll) {
+ phpdbg_update_watch_collision_elements(watch);
+ return;
+ }
- phpdbg_create_recursive_ht_watch(new_watch);
+ watch->elements.nNumOfElements++; /* dirty hack to avoid double free */
+ ZEND_HASH_FOREACH_PTR(&watch->elements, element) {
+ phpdbg_update_watch_element_watch(element);
+ } ZEND_HASH_FOREACH_END();
+ zend_hash_destroy(&watch->elements);
- phpdbg_create_watchpoint(new_watch);
+ efree(watch);
+}
+void phpdbg_clean_watch_element(phpdbg_watch_element *element) {
+ HashTable *elements = &element->watch->elements;
+ phpdbg_unwatch_parent_ht(element);
+ zend_hash_del(elements, element->str);
+ if (zend_hash_num_elements(elements) == 0) {
+ phpdbg_remove_watchpoint(element->watch);
}
+}
- return SUCCESS;
+/* TODO: compile a name of all hit watchpoints (ids ??) */
+zend_string *phpdbg_watchpoint_change_collision_name(phpdbg_watchpoint_t *watch) {
+ phpdbg_watchpoint_t *parent;
+ phpdbg_watch_element *element;
+ zend_string *name = NULL;
+ if (watch->coll) {
+ ZEND_HASH_FOREACH_PTR(&watch->coll->parents, parent) {
+ if (name) {
+ zend_string_release(name);
+ }
+ name = phpdbg_watchpoint_change_collision_name(parent);
+ } ZEND_HASH_FOREACH_END();
+ return name;
+ }
+ ZEND_HASH_FOREACH_PTR(&watch->elements, element) {
+ if (element->flags & PHPDBG_WATCH_IMPLICIT) {
+ if ((watch->type == WATCH_ON_ZVAL || watch->type == WATCH_ON_BUCKET) && Z_TYPE(watch->backup.zv) > IS_STRING) {
+ phpdbg_update_watch_element_watch(element->child);
+ }
+ continue;
+ }
+ name = element->str;
+ } ZEND_HASH_FOREACH_END();
+
+ return name ? zend_string_copy(name) : NULL;
}
-static void phpdbg_delete_implicit_parents(phpdbg_watchpoint_t *watch) {
- phpdbg_watchpoint_t *parent = watch->parent;
- if (!parent) {
+/* ### WATCHING FOR CHANGES ### */
+/* TODO: enforce order: first parents, then children, in order to avoid false positives */
+void phpdbg_check_watchpoint(phpdbg_watchpoint_t *watch) {
+ zend_string *name = NULL;
+ void *comparePtr;
+
+ if (watch->type == WATCH_ON_HASHTABLE) {
+ phpdbg_watch_element *element;
+ zend_string *str;
+ zend_long idx;
+ zval *zv;
+ ZEND_HASH_FOREACH_PTR(&watch->elements, element) {
+ if (element->flags & PHPDBG_WATCH_RECURSIVE) {
+ phpdbg_btree_result *res = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) HT_WATCH_HT(watch));
+ phpdbg_watch_ht_info *hti = res ? res->ptr : NULL;
+
+ ZEND_HASH_REVERSE_FOREACH_KEY_VAL(HT_WATCH_HT(watch), idx, str, zv) {
+ if (!str) {
+ str = zend_long_to_str(idx); // TODO: hack, use proper int handling for name in parent
+ } else {
+ str = zend_string_copy(str);
+ }
+ if (hti && zend_hash_find(&hti->watches, str)) {
+ zend_string_release(str);
+ break;
+ }
+ ZEND_HASH_FOREACH_PTR(&watch->elements, element) {
+ if (element->flags & PHPDBG_WATCH_RECURSIVE) {
+ phpdbg_add_recursive_watch_from_ht(element, idx, str, zv);
+ }
+ } ZEND_HASH_FOREACH_END();
+ phpdbg_notice("watchadd", "element=\"%.*s\"", "Element %.*s has been added to watchpoint", (int) ZSTR_LEN(str), ZSTR_VAL(str));
+ zend_string_release(str);
+ PHPDBG_G(watchpoint_hit) = 1;
+ } ZEND_HASH_FOREACH_END();
+
+ break;
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+ if (watch->type == WATCH_ON_HASHDATA) {
return;
}
- ZEND_ASSERT(!(parent->flags & PHPDBG_WATCH_RECURSIVE));
- ZEND_ASSERT(parent->flags & PHPDBG_WATCH_IMPLICIT);
-
- if (parent->type == WATCH_ON_HASHTABLE && --parent->implicit_ht_count) {
+ switch (watch->type) {
+ case WATCH_ON_STR:
+ comparePtr = &ZSTR_LEN(watch->backup.str);
+ break;
+ case WATCH_ON_HASHTABLE:
+ comparePtr = (char *) &watch->backup.ht + HT_WATCH_OFFSET;
+ break;
+ default:
+ comparePtr = &watch->backup;
+ }
+ if (!phpdbg_check_watch_diff(watch->type, comparePtr, watch->addr.ptr)) {
+ return;
+ }
+ if (watch->type == WATCH_ON_REFCOUNTED && !(PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS)) {
+ phpdbg_watch_backup_data(watch);
return;
}
+ if (watch->type == WATCH_ON_BUCKET) {
+ if (watch->backup.bucket.key != watch->addr.bucket->key || (watch->backup.bucket.key != NULL && watch->backup.bucket.h != watch->addr.bucket->h)) {
+ phpdbg_watch_element *element;
+ zval *new;
- parent->flags &= ~PHPDBG_WATCH_IMPLICIT;
- if (!(parent->flags & PHPDBG_WATCH_SIMPLE)) {
- if (parent->type == WATCH_ON_ZVAL && Z_REFCOUNTED_P(watch->addr.zv)) {
- phpdbg_remove_watch_collision(parent);
+ ZEND_HASH_FOREACH_PTR(&watch->elements, element) {
+ break;
+ } ZEND_HASH_FOREACH_END();
+
+ new = zend_symtable_find(element->parent_container, element->name_in_parent);
+
+ if (!new) {
+ /* dequeuing will take care of appropriate notification about removal */
+ phpdbg_remove_watchpoint(watch);
+ return;
+ }
+
+ phpdbg_deactivate_watchpoint(watch);
+ phpdbg_remove_watchpoint_btree(watch);
+ watch->addr.zv = new;
+ phpdbg_store_watchpoint_btree(watch);
+ phpdbg_activate_watchpoint(watch);
+
+ if (!phpdbg_check_watch_diff(WATCH_ON_ZVAL, &watch->backup.bucket.val, watch->addr.ptr)) {
+ phpdbg_watch_backup_data(watch);
+ return;
+ }
+ } else if (Z_TYPE_P(watch->addr.zv) == IS_UNDEF) {
+ /* dequeuing will take care of appropriate notification about removal */
+ phpdbg_remove_watchpoint(watch);
+ return;
}
- zend_hash_del(&PHPDBG_G(watchpoints), parent->str);
}
-}
-/* delete watchpoint, recursively (and inclusively) */
-static int phpdbg_delete_watchpoint_recursive(phpdbg_watchpoint_t *watch, zend_bool user_request) {
- if (watch->type == WATCH_ON_HASHTABLE) {
- if (user_request) {
- phpdbg_delete_ht_watchpoints_recursive(watch);
- } else {
- HashTable *ht;
- phpdbg_btree_result *result;
+ name = phpdbg_watchpoint_change_collision_name(watch);
- ht = HT_FROM_ZVP(watch->addr.zv);
+ if (name) {
+ phpdbg_print_watch_diff(watch->type, name, comparePtr, watch->addr.ptr);
+ zend_string_release(name);
+ }
- if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) ht))) {
- phpdbg_delete_watchpoint_recursive((phpdbg_watchpoint_t *) result->ptr, user_request);
+ if (watch->type == WATCH_ON_ZVAL || watch->type == WATCH_ON_BUCKET) {
+ phpdbg_watch_element *element;
+ phpdbg_update_watch_ref(watch);
+ ZEND_HASH_FOREACH_PTR(&watch->elements, element) {
+ if (element->flags & PHPDBG_WATCH_RECURSIVE) {
+ phpdbg_recurse_watch_element(element);
}
- }
- } else if (watch->type == WATCH_ON_ZVAL) {
- phpdbg_delete_zval_watchpoints_recursive(watch);
+ } ZEND_HASH_FOREACH_END();
}
- return zend_hash_del(&PHPDBG_G(watchpoints), watch->str);
+ phpdbg_watch_backup_data(watch);
}
-static void phpdbg_delete_ht_watchpoints_recursive(phpdbg_watchpoint_t *watch) {
- zend_string *strkey;
- zend_long numkey;
- char *str;
- size_t str_len;
- phpdbg_watchpoint_t *watchpoint;
-
- ZEND_HASH_FOREACH_KEY(HT_WATCH_HT(watch), numkey, strkey) {
- if (strkey) {
- str_len = spprintf(&str, 0, "%.*s%s%s%s", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str), (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", phpdbg_get_property_key(ZSTR_VAL(strkey)), (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : "");
- } else {
- str_len = spprintf(&str, 0, "%.*s%s" ZEND_LONG_FMT "%s", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str), (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", numkey, (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : "");
- }
+void phpdbg_reenable_memory_watches(void) {
+ zend_ulong page;
+ phpdbg_btree_result *res;
+ phpdbg_watchpoint_t *watch;
- if ((watchpoint = zend_hash_str_find_ptr(&PHPDBG_G(watchpoints), str, str_len))) {
- phpdbg_delete_watchpoint_recursive(watchpoint, 1);
+ ZEND_HASH_FOREACH_NUM_KEY(PHPDBG_G(watchlist_mem), page) {
+ /* Disble writing again if there are any watchers on that page */
+ res = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), page + phpdbg_pagesize - 1);
+ if (res) {
+ watch = res->ptr;
+ if ((char *) page < (char *) watch->addr.ptr + watch->size) {
+ mprotect((void *) page, phpdbg_pagesize, PROT_READ);
+ }
}
-
- efree(str);
} ZEND_HASH_FOREACH_END();
+ zend_hash_clean(PHPDBG_G(watchlist_mem));
}
-static void phpdbg_delete_zval_watchpoints_recursive(phpdbg_watchpoint_t *watch) {
- if (Z_REFCOUNTED_P(watch->addr.zv)) {
- phpdbg_remove_watch_collision(watch);
+int phpdbg_print_changed_zvals(void) {
+ int ret;
+ zend_ulong page;
+ phpdbg_watchpoint_t *watch;
+ phpdbg_btree_result *res;
+ HashTable *mem_list = NULL;
+
+ if (zend_hash_num_elements(&PHPDBG_G(watch_elements)) == 0) {
+ return FAILURE;
}
-}
-/* delete watchpoints recusively (exclusively!) */
-static void phpdbg_delete_watchpoints_recursive(phpdbg_watchpoint_t *watch) {
- if (watch->type == WATCH_ON_ZVAL) {
- phpdbg_delete_zval_watchpoints_recursive(watch);
- } else if (watch->type == WATCH_ON_HASHTABLE) {
- phpdbg_delete_ht_watchpoints_recursive(watch);
+ if (zend_hash_num_elements(PHPDBG_G(watchlist_mem)) > 0) {
+ /* we must not add elements to the hashtable while iterating over it (resize => read into freed memory) */
+ mem_list = PHPDBG_G(watchlist_mem);
+ PHPDBG_G(watchlist_mem) = PHPDBG_G(watchlist_mem_backup);
+
+ ZEND_HASH_FOREACH_NUM_KEY(mem_list, page) {
+ phpdbg_btree_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), page, page + phpdbg_pagesize);
+
+ while ((res = phpdbg_btree_next(&pos))) {
+ watch = res->ptr;
+ phpdbg_check_watchpoint(watch);
+ }
+ if ((res = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), page - 1))) {
+ watch = res->ptr;
+ if ((char *) page < (char *) watch->addr.ptr + watch->size) {
+ phpdbg_check_watchpoint(watch);
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
}
+
+ phpdbg_dequeue_elements_for_recreation();
+
+ phpdbg_reenable_memory_watches();
+
+ if (mem_list) {
+ PHPDBG_G(watchlist_mem) = mem_list;
+ phpdbg_reenable_memory_watches();
+ }
+
+ ret = PHPDBG_G(watchpoint_hit) ? SUCCESS : FAILURE;
+ PHPDBG_G(watchpoint_hit) = 0;
+
+ return ret;
}
-static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch) {
- int ret;
- phpdbg_watchpoint_t *watch;
+void phpdbg_watch_efree(void *ptr) {
phpdbg_btree_result *result;
- if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) tmp_watch->addr.ptr)) == NULL) {
- return FAILURE;
- }
+ /* only do expensive checks if there are any watches at all */
+ if (zend_hash_num_elements(&PHPDBG_G(watch_elements))) {
+ if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) ptr))) {
+ phpdbg_watchpoint_t *watch = result->ptr;
+ if (watch->type != WATCH_ON_HASHDATA) {
+ phpdbg_remove_watchpoint(watch);
+ } else {
+ /* remove all linked watchpoints, they will be dissociated from their elements */
+ phpdbg_watch_element *element;
+ phpdbg_watch_ht_info *hti = (phpdbg_watch_ht_info *) watch;
+
+ ZEND_HASH_FOREACH_PTR(&hti->watches, element) {
+ zend_ulong num = zend_hash_num_elements(&hti->watches);
+ phpdbg_remove_watchpoint(element->watch);
+ if (num == 1) { /* prevent access into freed memory */
+ break;
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+ }
- watch = result->ptr;
+ /* special case watchpoints as they aren't on ptr but on ptr + HT_WATCH_OFFSET */
+ if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), HT_WATCH_OFFSET + (zend_ulong) ptr))) {
+ phpdbg_watchpoint_t *watch = result->ptr;
+ if (watch->type == WATCH_ON_HASHTABLE) {
+ phpdbg_remove_watchpoint(watch);
+ }
+ }
- if (!(watch->flags & PHPDBG_WATCH_NORMAL) || (watch->parent && (watch->parent->flags & PHPDBG_WATCH_RECURSIVE))) {
- return FAILURE; /* TODO: better error message for recursive (??) */
+ zend_hash_index_del(&PHPDBG_G(watch_free), (zend_ulong) ptr);
}
- if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
- ret = phpdbg_delete_watchpoint_recursive(watch, 1);
- } else {
- ret = zend_hash_del(&PHPDBG_G(watchpoints), watch->str);
+ if (PHPDBG_G(original_free_function)) {
+ PHPDBG_G(original_free_function)(ptr);
}
+}
- phpdbg_free_watch(tmp_watch);
- efree(tmp_watch);
+/* ### USER API ### */
+void phpdbg_list_watchpoints(void) {
+ phpdbg_watch_element *element;
- return ret;
+ phpdbg_xml("<watchlist %r>");
+
+ ZEND_HASH_FOREACH_PTR(&PHPDBG_G(watch_elements), element) {
+ phpdbg_writeln("watchvariable", "variable=\"%.*s\" on=\"%s\" type=\"%s\"", "%.*s (%s, %s)", (int) ZSTR_LEN(element->str), ZSTR_VAL(element->str), (element->flags & (PHPDBG_WATCH_ARRAY|PHPDBG_WATCH_OBJECT)) ? "array" : "variable", (element->flags & PHPDBG_WATCH_RECURSIVE) ? "recursive" : "simple");
+ } ZEND_HASH_FOREACH_END();
+
+ phpdbg_xml("</watchlist>");
}
-static int phpdbg_watchpoint_parse_wrapper(char *name, size_t namelen, char *key, size_t keylen, HashTable *parent, zval *zv, int (*callback)(phpdbg_watchpoint_t *)) {
+static int phpdbg_create_simple_watchpoint(zval *zv, phpdbg_watch_element *element) {
+ element->flags = PHPDBG_WATCH_SIMPLE;
+ phpdbg_add_bucket_watch_element((Bucket *) zv, element);
+ return SUCCESS;
+}
+
+static int phpdbg_create_array_watchpoint(zval *zv, phpdbg_watch_element *element) {
+ phpdbg_watch_element *new;
+ zend_string *str;
+ zval *orig_zv = zv;
+
+ ZVAL_DEREF(zv);
+ if (Z_TYPE_P(zv) != IS_ARRAY && Z_TYPE_P(zv) != IS_OBJECT) {
+ return FAILURE;
+ }
+
+ new = ecalloc(1, sizeof(phpdbg_watch_element));
+
+ str = strpprintf(0, "%.*s[]", (int) ZSTR_LEN(element->str), ZSTR_VAL(element->str));
+ zend_string_release(element->str);
+ element->str = str;
+ element->flags = PHPDBG_WATCH_IMPLICIT;
+ phpdbg_add_bucket_watch_element((Bucket *) orig_zv, element);
+ element->child = new;
+
+ new->flags = PHPDBG_WATCH_SIMPLE;
+ new->str = zend_string_copy(str);
+ new->parent = element;
+ phpdbg_add_ht_watch_element(zv, new);
+ return SUCCESS;
+}
+
+static int phpdbg_create_recursive_watchpoint(zval *zv, phpdbg_watch_element *element) {
+ element->flags = PHPDBG_WATCH_RECURSIVE | PHPDBG_WATCH_RECURSIVE_ROOT;
+ element->child = NULL;
+ phpdbg_add_bucket_watch_element((Bucket *) zv, element);
+ return SUCCESS;
+}
+
+typedef struct { int (*callback)(zval *zv, phpdbg_watch_element *); zend_string *str; } phpdbg_watch_parse_struct;
+
+static int phpdbg_watchpoint_parse_wrapper(char *name, size_t namelen, char *key, size_t keylen, HashTable *parent, zval *zv, phpdbg_watch_parse_struct *info) {
int ret;
- phpdbg_watchpoint_t *watch = ecalloc(1, sizeof(phpdbg_watchpoint_t));
- watch->str = zend_string_init(name, namelen, 0);
- watch->name_in_parent = zend_string_init(key, keylen, 0);
- watch->parent_container = parent;
- phpdbg_create_zval_watchpoint(zv, watch);
+ phpdbg_watch_element *element = ecalloc(1, sizeof(phpdbg_watch_element));
+ element->str = zend_string_init(name, namelen, 0);
+ element->name_in_parent = zend_string_init(key, keylen, 0);
+ element->parent_container = parent;
+ element->parent = PHPDBG_G(watch_tmp);
+ element->child = NULL;
- ret = callback(watch);
+ ret = info->callback(zv, element);
efree(name);
efree(key);
if (ret != SUCCESS) {
- phpdbg_free_watch(watch);
- efree(watch);
+ phpdbg_remove_watch_element(element);
+ } else {
+ if (PHPDBG_G(watch_tmp)) {
+ PHPDBG_G(watch_tmp)->child = element;
+ }
+
+ if (element->child) {
+ element = element->child;
+ }
+ element->id = PHPDBG_G(watch_elements).nNextFreeElement;
+ zend_hash_index_add_ptr(&PHPDBG_G(watch_elements), element->id, element);
+
+ phpdbg_notice("watchadd", "index=\"%d\" variable=\"%.*s\"", "Added%s watchpoint #%d for %.*s", (element->flags & PHPDBG_WATCH_RECURSIVE_ROOT) ? " recursive" : "", element->id, (int) ZSTR_LEN(element->str), ZSTR_VAL(element->str));
}
PHPDBG_G(watch_tmp) = NULL;
@@ -650,56 +1259,76 @@ static int phpdbg_watchpoint_parse_wrapper(char *name, size_t namelen, char *key
return ret;
}
-PHPDBG_API int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t *), zend_bool silent) {
- return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, NULL, 0, callback);
+PHPDBG_API int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, phpdbg_watch_parse_struct *info, zend_bool silent) {
+ return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, NULL, 0, info);
}
-static int phpdbg_watchpoint_parse_step(char *name, size_t namelen, char *key, size_t keylen, HashTable *parent, zval *zv, int (*callback)(phpdbg_watchpoint_t *)) {
- phpdbg_watchpoint_t *watch;
+static int phpdbg_watchpoint_parse_step(char *name, size_t namelen, char *key, size_t keylen, HashTable *parent, zval *zv, phpdbg_watch_parse_struct *info) {
+ phpdbg_watch_element *element;
- if ((watch = zend_hash_str_find_ptr(&PHPDBG_G(watchpoints), name, namelen))) {
- watch->flags |= PHPDBG_WATCH_IMPLICIT;
- PHPDBG_G(watch_tmp) = watch;
+ /* do not install watch elements for references */
+ if (PHPDBG_G(watch_tmp) && Z_ISREF_P(PHPDBG_G(watch_tmp)->watch->addr.zv) && Z_REFVAL_P(PHPDBG_G(watch_tmp)->watch->addr.zv) == zv) {
+ efree(name);
+ efree(key);
return SUCCESS;
}
- watch = ecalloc(1, sizeof(phpdbg_watchpoint_t));
- watch->flags = PHPDBG_WATCH_IMPLICIT;
- watch->str = zend_string_init(name, namelen, 0);
- watch->name_in_parent = zend_string_init(key, keylen, 0);
- watch->parent_container = parent;
- watch->parent = PHPDBG_G(watch_tmp);
- phpdbg_create_zval_watchpoint(zv, watch);
-
- phpdbg_create_watchpoint(watch);
+ element = ecalloc(1, sizeof(phpdbg_watch_element));
+ element->flags = PHPDBG_WATCH_IMPLICIT;
+ element->str = zend_string_copy(info->str);
+ element->name_in_parent = zend_string_init(key, keylen, 0);
+ element->parent_container = parent;
+ element->parent = PHPDBG_G(watch_tmp);
+ element = phpdbg_add_bucket_watch_element((Bucket *) zv, element);
efree(name);
efree(key);
- PHPDBG_G(watch_tmp) = watch;
+ if (PHPDBG_G(watch_tmp)) {
+ PHPDBG_G(watch_tmp)->child = element;
+ }
+ PHPDBG_G(watch_tmp) = element;
+
return SUCCESS;
}
-static int phpdbg_watchpoint_parse_symtables(char *input, size_t len, int (*callback)(phpdbg_watchpoint_t *)) {
- if (EG(scope) && len >= 5 && !memcmp("$this", input, 5)) {
+static int phpdbg_watchpoint_parse_symtables(char *input, size_t len, int (*callback)(zval *, phpdbg_watch_element *)) {
+ zend_class_entry *scope = zend_get_executed_scope();
+ phpdbg_watch_parse_struct info;
+ int ret;
+
+ if (scope && len >= 5 && !memcmp("$this", input, 5)) {
zend_hash_str_add(EG(current_execute_data)->symbol_table, ZEND_STRL("this"), &EG(current_execute_data)->This);
}
- if (phpdbg_is_auto_global(input, len) && phpdbg_watchpoint_parse_input(input, len, &EG(symbol_table), 0, callback, 1) != FAILURE) {
+ if (callback == phpdbg_create_array_watchpoint) {
+ info.str = strpprintf(0, "%.*s[]", (int) len, input);
+ } else {
+ info.str = zend_string_init(input, len, 0);
+ }
+ info.callback = callback;
+
+ if (phpdbg_is_auto_global(input, len) && phpdbg_watchpoint_parse_input(input, len, &EG(symbol_table), 0, &info, 1) != FAILURE) {
+ zend_string_release(info.str);
return SUCCESS;
}
- return phpdbg_parse_variable_with_arg(input, len, EG(current_execute_data)->symbol_table, 0, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_step, 0, callback);
+ ret = phpdbg_parse_variable_with_arg(input, len, EG(current_execute_data)->symbol_table, 0, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_step, 0, &info);
+
+ zend_string_release(info.str);
+ return ret;
}
PHPDBG_WATCH(delete) /* {{{ */
{
+ phpdbg_watch_element *element;
switch (param->type) {
- case STR_PARAM:
- if (phpdbg_delete_var_watchpoint(param->str, param->len) == FAILURE) {
- phpdbg_error("watchdelete", "type=\"nowatch\"", "Nothing was deleted, no corresponding watchpoint found");
+ case NUMERIC_PARAM:
+ if ((element = zend_hash_index_find_ptr(&PHPDBG_G(watch_elements), param->num))) {
+ phpdbg_remove_watch_element(element);
+ phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Removed watchpoint %d", (int) param->num);
} else {
- phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Removed watchpoint %.*s", (int) param->len, param->str);
+ phpdbg_error("watchdelete", "type=\"nowatch\"", "Nothing was deleted, no corresponding watchpoint found");
}
break;
@@ -709,6 +1338,14 @@ PHPDBG_WATCH(delete) /* {{{ */
return SUCCESS;
} /* }}} */
+int phpdbg_create_var_watchpoint(char *input, size_t len) {
+ if (phpdbg_rebuild_symtable() == FAILURE) {
+ return FAILURE;
+ }
+
+ return phpdbg_watchpoint_parse_symtables(input, len, phpdbg_create_simple_watchpoint);
+}
+
PHPDBG_WATCH(recursive) /* {{{ */
{
if (phpdbg_rebuild_symtable() == FAILURE) {
@@ -717,9 +1354,7 @@ PHPDBG_WATCH(recursive) /* {{{ */
switch (param->type) {
case STR_PARAM:
- if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_recursive_watchpoint) != FAILURE) {
- phpdbg_notice("watchrecursive", "variable=\"%.*s\"", "Set recursive watchpoint on %.*s", (int)param->len, param->str);
- }
+ phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_recursive_watchpoint);
break;
phpdbg_default_switch_case();
@@ -736,9 +1371,7 @@ PHPDBG_WATCH(array) /* {{{ */
switch (param->type) {
case STR_PARAM:
- if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_array_watchpoint) != FAILURE) {
- phpdbg_notice("watcharray", "variable=\"%.*s\"", "Set array watchpoint on %.*s", (int)param->len, param->str);
- }
+ phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_array_watchpoint);
break;
phpdbg_default_switch_case();
@@ -747,145 +1380,6 @@ PHPDBG_WATCH(array) /* {{{ */
return SUCCESS;
} /* }}} */
-void phpdbg_watch_HashTable_dtor(zval *zv) {
- phpdbg_btree_result *result;
- zval *orig_zv = zv;
-
- while (Z_TYPE_P(zv) == IS_INDIRECT) {
- zv = Z_INDIRECT_P(zv);
- }
-
- if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) zv))) {
- phpdbg_watchpoint_t *watch = result->ptr;
-
- if (watch->flags & PHPDBG_WATCH_NORMAL) {
- PHPDBG_G(watchpoint_hit) = 1;
-
- phpdbg_notice("watchdelete", "variable=\"%.*s\" recursive=\"%s\"", "%.*s was removed, removing watchpoint%s", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str), (watch->flags & PHPDBG_WATCH_RECURSIVE) ? " recursively" : "");
- }
-
- if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
- phpdbg_delete_watchpoint_recursive(watch, 0);
- } else {
- zend_hash_del(&PHPDBG_G(watchpoints), watch->str);
- }
-
- if ((result = phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) watch->parent_container))) {
- phpdbg_watch_ht_info *hti = result->ptr;
- hti->dtor(orig_zv);
- zend_hash_del(&hti->watches, watch->name_in_parent);
- if (zend_hash_num_elements(&hti->watches) == 0) {
- watch->parent_container->pDestructor = hti->dtor;
- zend_hash_destroy(&hti->watches);
- efree(hti);
- }
- } else {
- zval_ptr_dtor_wrapper(orig_zv);
- }
- }
-}
-
-int phpdbg_create_var_watchpoint(char *input, size_t len) {
- if (phpdbg_rebuild_symtable() == FAILURE) {
- return FAILURE;
- }
-
- return phpdbg_watchpoint_parse_symtables(input, len, phpdbg_create_simple_watchpoint);
-}
-
-int phpdbg_delete_var_watchpoint(char *input, size_t len) {
- if (phpdbg_rebuild_symtable() == FAILURE) {
- return FAILURE;
- }
-
- return phpdbg_watchpoint_parse_input(input, len, EG(current_execute_data)->symbol_table, 0, phpdbg_delete_watchpoint, 0);
-}
-
-#ifdef _WIN32
-int phpdbg_watchpoint_segfault_handler(void *addr) {
-#else
-int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context) {
-#endif
- void *page;
- phpdbg_watch_memdump *dump;
- phpdbg_watchpoint_t *watch;
- size_t size;
-
- watch = phpdbg_check_for_watchpoint(
-#ifdef _WIN32
- addr
-#else
- info->si_addr
-#endif
- );
-
- if (watch == NULL) {
- return FAILURE;
- }
-
- page = phpdbg_get_page_boundary(watch->addr.ptr);
- size = phpdbg_get_total_page_size(watch->addr.ptr, watch->size);
-
- /* re-enable writing */
- mprotect(page, size, PROT_READ | PROT_WRITE);
-
- dump = malloc(MEMDUMP_SIZE(size));
- dump->page = page;
- dump->size = size;
-
- memcpy(&dump->data, page, size);
-
- zend_llist_add_element(&PHPDBG_G(watchlist_mem), &dump);
-
- return SUCCESS;
-}
-
-void phpdbg_watchpoints_clean(void) {
- zend_hash_clean(&PHPDBG_G(watchpoints));
-}
-
-/* due to implicit delete... MUST BE DESTROYED MANUALLY */
-static void phpdbg_watch_dtor(zval *pDest) {
- phpdbg_watchpoint_t *watch = (phpdbg_watchpoint_t *) Z_PTR_P(pDest);
-
- if (watch->flags & PHPDBG_WATCH_IMPLICIT) {
- watch->flags = PHPDBG_WATCH_SIMPLE; // tiny hack for delete_implicit_parents
-
- if (watch->type == WATCH_ON_ZVAL) {
- phpdbg_delete_zval_watchpoints_recursive(watch);
- } else if (watch->type == WATCH_ON_HASHTABLE) {
- phpdbg_watchpoint_t *watchpoint;
-
- watch->implicit_ht_count++;
-
- ZEND_HASH_FOREACH_PTR(&((phpdbg_watch_ht_info *) phpdbg_btree_find(&PHPDBG_G(watch_HashTables), (zend_ulong) HT_WATCH_HT(watch))->ptr)->watches, watchpoint) {
- phpdbg_delete_watchpoint_recursive(watchpoint, 1);
- } ZEND_HASH_FOREACH_END();
- }
- }
-
- phpdbg_delete_implicit_parents(watch);
-
- phpdbg_deactivate_watchpoint(watch);
- phpdbg_remove_watchpoint(watch);
-
- phpdbg_free_watch(watch);
-}
-
-static void phpdbg_watch_mem_dtor(void *llist_data) {
- phpdbg_watch_memdump *dump = *(phpdbg_watch_memdump **) llist_data;
-
- /* Disble writing again */
- if (dump->reenable_writing) {
- mprotect(dump->page, dump->size, PROT_READ);
- }
-
- free(dump);
-}
-
-static void phpdbg_watch_free_ptr_dtor(zval *ptr) {
- efree(Z_PTR_P(ptr));
-}
void phpdbg_setup_watchpoints(void) {
#if _SC_PAGE_SIZE
@@ -898,253 +1392,42 @@ void phpdbg_setup_watchpoints(void) {
phpdbg_pagesize = 4096; /* common pagesize */
#endif
- zend_llist_init(&PHPDBG_G(watchlist_mem), sizeof(void *), phpdbg_watch_mem_dtor, 1);
phpdbg_btree_init(&PHPDBG_G(watchpoint_tree), sizeof(void *) * 8);
phpdbg_btree_init(&PHPDBG_G(watch_HashTables), sizeof(void *) * 8);
- zend_hash_init(&PHPDBG_G(watchpoints), 8, NULL, phpdbg_watch_dtor, 0);
- zend_hash_init(&PHPDBG_G(watch_collisions), 8, NULL, phpdbg_watch_free_ptr_dtor, 0);
-}
-
-static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump) {
- /* fetch all changes between dump->page and dump->page + dump->size */
- phpdbg_btree_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), (zend_ulong) dump->page, (zend_ulong) dump->page + dump->size);
- phpdbg_btree_result *result;
- int elementDiff;
- void *curTest;
-
- dump->reenable_writing = 0;
-
- while ((result = phpdbg_btree_next(&pos))) {
- phpdbg_watchpoint_t *watch = result->ptr;
- void *oldPtr = (char *) &dump->data + ((size_t) watch->addr.ptr - (size_t) dump->page);
- char reenable = 1;
- int removed = 0;
-
- if ((size_t) watch->addr.ptr < (size_t) dump->page || (size_t) watch->addr.ptr + watch->size > (size_t) dump->page + dump->size) {
- continue;
- }
-
- /* Test if the zval was separated or replaced and if necessary move the watchpoint */
- if ((watch->type == WATCH_ON_HASHTABLE || watch->type == WATCH_ON_ZVAL) && watch->parent_container) {
- if ((curTest = zend_symtable_find(watch->parent_container, watch->name_in_parent))) {
- while (Z_TYPE_P((zval *) curTest) == IS_INDIRECT) {
- curTest = Z_INDIRECT_P((zval *) curTest);
- }
-
- if (watch->type == WATCH_ON_HASHTABLE) {
- switch (Z_TYPE_P((zval *) curTest)) {
- case IS_ARRAY:
- curTest = (void *) Z_ARRVAL_P((zval *) curTest);
- break;
- case IS_OBJECT:
- curTest = (void *) Z_OBJPROP_P((zval *) curTest);
- break;
- }
- }
-
- if (curTest != watch->addr.ptr) {
- phpdbg_deactivate_watchpoint(watch);
- phpdbg_remove_watchpoint(watch);
- watch->addr.ptr = curTest;
- phpdbg_store_watchpoint(watch);
- phpdbg_activate_watchpoint(watch);
-
- reenable = 0;
- }
- } else {
- removed = 1;
- }
- }
-
- /* Show to the user what changed and delete watchpoint upon removal */
- if (memcmp(oldPtr, watch->addr.ptr, watch->size) != SUCCESS) {
- zend_bool do_break = 0;
-
- if (watch->flags & PHPDBG_WATCH_NORMAL) {
- switch (watch->type) {
- case WATCH_ON_ZVAL:
- do_break = memcmp(oldPtr, watch->addr.zv, sizeof(zend_value) + sizeof(uint32_t) /* value + typeinfo */);
- break;
- case WATCH_ON_HASHTABLE:
- do_break = zend_hash_num_elements(HT_PTR_HT(oldPtr)) != zend_hash_num_elements(HT_WATCH_HT(watch));
- break;
- case WATCH_ON_REFCOUNTED:
- if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS) {
- do_break = memcmp(oldPtr, watch->addr.ref, sizeof(uint32_t) /* no zend_refcounted metadata info */);
- }
- break;
- }
- }
-
- if (do_break) {
- PHPDBG_G(watchpoint_hit) = 1;
-
- phpdbg_notice("watchhit", "variable=\"%s\"", "Breaking on watchpoint %.*s", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str));
- phpdbg_xml("<watchdata %r>");
- }
-
- switch (watch->type) {
- case WATCH_ON_ZVAL: {
- int show_value = memcmp(oldPtr, watch->addr.zv, sizeof(zend_value) + sizeof(uint32_t) /* no metadata info */);
-
- if ((watch->flags & PHPDBG_WATCH_NORMAL) && (removed || show_value)) {
-/* TODO: Merge with refcounting watches, store if watched ref value is to be dropped etc. [for example: manually increment refcount transparently for displaying and drop it if it decrements to 1] */
- if (Z_REFCOUNTED_P((zval *) oldPtr)) {
- phpdbg_writeln("watchvalue", "type=\"old\" inaccessible=\"inaccessible\"", "Old value inaccessible or destroyed");
- } else {
- phpdbg_out("Old value: ");
- phpdbg_xml("<watchvalue %r type=\"old\">");
- zend_print_flat_zval_r((zval *) oldPtr);
- phpdbg_xml("</watchvalue>");
- phpdbg_out("\n");
- }
- }
-
- /* check if zval was removed */
- if (removed) {
- if (watch->flags & PHPDBG_WATCH_NORMAL) {
- phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Watchpoint %.*s was unset, removing watchpoint", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str));
- }
- zend_hash_del(&PHPDBG_G(watchpoints), watch->str);
-
- reenable = 0;
-
- if (Z_REFCOUNTED_P((zval *) oldPtr)) {
- phpdbg_remove_watch_collision(watch);
- }
- break;
- }
-
- if ((watch->flags & PHPDBG_WATCH_NORMAL) && show_value) {
- phpdbg_out("New value%s: ", Z_ISREF_P(watch->addr.zv) ? " (reference)" : "");
- phpdbg_xml("<watchvalue %r%s type=\"new\">", Z_ISREF_P(watch->addr.zv) ? " reference=\"reference\"" : "");
- zend_print_flat_zval_r(watch->addr.zv);
- phpdbg_xml("</watchvalue>");
- phpdbg_out("\n");
- }
-
- /* add new watchpoints if necessary */
- if (Z_PTR_P(watch->addr.zv) != Z_PTR_P((zval *) oldPtr) || Z_TYPE_P(watch->addr.zv) != Z_TYPE_P((zval *) oldPtr)) {
- if (Z_REFCOUNTED_P((zval *) oldPtr)) {
- zval *new_zv = watch->addr.zv;
- watch->addr.ptr = oldPtr;
- phpdbg_remove_watch_collision(watch);
- watch->addr.zv = new_zv;
- }
- if (Z_REFCOUNTED_P(watch->addr.zv)) {
- if ((watch->flags & PHPDBG_WATCH_NORMAL) && (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS)) {
- phpdbg_writeln("watchrefcount", "type=\"new\" refcount=\"%d\"", "New refcount: %d", Z_COUNTED_P(watch->addr.zv)->refcount);
- }
- if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
- phpdbg_create_recursive_watchpoint(watch);
- } else if (Z_ISREF_P(watch->addr.zv)) {
- phpdbg_create_reference_watch(watch);
- }
- }
- }
-
- break;
- }
- case WATCH_ON_HASHTABLE:
- /* We should be safely able to assume the HashTable to be consistent (inconsistent HashTables should have been caught by phpdbg_watch_efree() */
- elementDiff = zend_hash_num_elements(HT_PTR_HT(oldPtr)) - zend_hash_num_elements(HT_WATCH_HT(watch));
- if ((watch->flags & PHPDBG_WATCH_NORMAL) && elementDiff) {
- if (elementDiff > 0) {
- phpdbg_writeln("watchsize", "removed=\"%d\"", "%d elements were removed from the array", elementDiff);
- } else {
- phpdbg_writeln("watchsize", "added=\"%d\"", "%d elements were added to the array", -elementDiff);
- }
- }
- /* add new watchpoints if necessary */
- if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
- phpdbg_create_recursive_ht_watch(watch);
- }
- if ((watch->flags & PHPDBG_WATCH_NORMAL) && HT_WATCH_HT(watch)->nInternalPointer != HT_PTR_HT(oldPtr)->nInternalPointer) {
- phpdbg_writeln("watcharrayptr", "", "Internal pointer of array was changed");
- }
- break;
- case WATCH_ON_REFCOUNTED: {
- if ((watch->flags & PHPDBG_WATCH_NORMAL) && (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS)) {
- phpdbg_writeln("watchrefcount", "type=\"old\" refcount=\"%d\"", "Old refcount: %d", ((zend_refcounted *) oldPtr)->refcount);
- phpdbg_writeln("watchrefcount", "type=\"new\" refcount=\"%d\"", "New refcount: %d", watch->addr.ref->refcount);
- }
- break;
- }
- }
-
- if (do_break) {
- phpdbg_xml("</watchdata>");
- }
- }
-
- dump->reenable_writing = dump->reenable_writing | reenable;
- }
-}
-
-int phpdbg_print_changed_zvals(void) {
- zend_llist_position pos;
- phpdbg_watch_memdump **dump;
- int ret;
-
- if (zend_llist_count(&PHPDBG_G(watchlist_mem)) == 0) {
- return FAILURE;
- }
-
- dump = (phpdbg_watch_memdump **) zend_llist_get_last_ex(&PHPDBG_G(watchlist_mem), &pos);
-
- do {
- phpdbg_print_changed_zval(*dump);
- } while ((dump = (phpdbg_watch_memdump **) zend_llist_get_prev_ex(&PHPDBG_G(watchlist_mem), &pos)));
-
- zend_llist_clean(&PHPDBG_G(watchlist_mem));
-
- ret = PHPDBG_G(watchpoint_hit) ? SUCCESS : FAILURE;
- PHPDBG_G(watchpoint_hit) = 0;
-
- return ret;
+ zend_hash_init(&PHPDBG_G(watch_elements), 8, NULL, NULL, 0);
+ zend_hash_init(&PHPDBG_G(watch_collisions), 8, NULL, NULL, 0);
+ zend_hash_init(&PHPDBG_G(watch_recreation), 8, NULL, NULL, 0);
+ zend_hash_init(&PHPDBG_G(watch_free), 8, NULL, NULL, 0);
+
+ /* put these on a separate page, to avoid conflicts with other memory */
+ PHPDBG_G(watchlist_mem) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
+ zend_hash_init(PHPDBG_G(watchlist_mem), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1);
+ PHPDBG_G(watchlist_mem_backup) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable));
+ zend_hash_init(PHPDBG_G(watchlist_mem_backup), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1);
}
-void phpdbg_list_watchpoints(void) {
- phpdbg_watchpoint_t *watch;
-
- phpdbg_xml("<watchlist %r>");
+void phpdbg_destroy_watchpoints(void) {
+ phpdbg_watch_element *element;
+ phpdbg_btree_position pos;
+ phpdbg_btree_result *res;
- ZEND_HASH_FOREACH_PTR(&PHPDBG_G(watchpoints), watch) {
- if (watch->flags & PHPDBG_WATCH_NORMAL) {
- phpdbg_writeln("watchvariable", "variable=\"%.*s\" on=\"%s\" type=\"%s\"", "%.*s (%s, %s)", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str), watch->type == WATCH_ON_HASHTABLE ? "array" : watch->type == WATCH_ON_REFCOUNTED ? "refcount" : "variable", watch->flags == PHPDBG_WATCH_RECURSIVE ? "recursive" : "simple");
- }
+ /* unconditionally free all remaining elements to avoid memory leaks */
+ ZEND_HASH_FOREACH_PTR(&PHPDBG_G(watch_recreation), element) {
+ phpdbg_automatic_dequeue_free(element);
} ZEND_HASH_FOREACH_END();
- phpdbg_xml("</watchlist>");
-}
-
-void phpdbg_watch_efree(void *ptr) {
- phpdbg_btree_result *result;
-
- result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong) ptr);
-
- if (result) {
- phpdbg_watchpoint_t *watch = result->ptr;
-
- if ((size_t) watch->addr.ptr + watch->size > (size_t) ptr) {
- if (watch->type == WATCH_ON_REFCOUNTED) {
- /* remove watchpoint here from btree, zval watchpoint will remove it via remove_watch_collison */
- phpdbg_deactivate_watchpoint(watch);
- phpdbg_remove_watchpoint(watch);
- } else {
- if (watch->type == WATCH_ON_ZVAL) {
- phpdbg_remove_watch_collision(watch);
- }
- if (watch->type == WATCH_ON_HASHTABLE && (watch->flags & PHPDBG_WATCH_SIMPLE)) {
- /* when a HashTable is freed, we can safely assume the other zvals all were dtor'ed */
- phpdbg_notice("watchdelete", "variable=\"%.*s\" recursive=\"%s\"", "Array %.*s was removed, removing watchpoint%s", (int) ZSTR_LEN(watch->str), ZSTR_VAL(watch->str), (watch->flags & PHPDBG_WATCH_RECURSIVE) ? " recursively" : "");
- }
- if (watch->type == WATCH_ON_HASHTABLE || watch->parent == NULL || watch->parent->type != WATCH_ON_ZVAL) { /* no references */
- zend_hash_del(&PHPDBG_G(watchpoints), watch->str);
- }
- }
- }
+ /* upon fatal errors etc. (i.e. CG(unclean_shutdown) == 1), some watchpoints may still be active. Ensure memory is not watched anymore for next run. Do not care about memory freeing here, shutdown is unclean and near anyway. */
+ pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), 0, -1);
+ while ((res = phpdbg_btree_next(&pos))) {
+ phpdbg_deactivate_watchpoint(res->ptr);
}
- PHPDBG_G(original_free_function)(ptr);
+ zend_hash_destroy(&PHPDBG_G(watch_elements)); PHPDBG_G(watch_elements).nNumOfElements = 0; /* phpdbg_watch_efree() is checking against this arrays size */
+ zend_hash_destroy(&PHPDBG_G(watch_recreation));
+ zend_hash_destroy(&PHPDBG_G(watch_free));
+ zend_hash_destroy(&PHPDBG_G(watch_collisions));
+ zend_hash_destroy(PHPDBG_G(watchlist_mem));
+ free(PHPDBG_G(watchlist_mem));
+ zend_hash_destroy(PHPDBG_G(watchlist_mem_backup));
+ free(PHPDBG_G(watchlist_mem_backup));
}
diff --git a/sapi/phpdbg/phpdbg_watch.h b/sapi/phpdbg/phpdbg_watch.h
index ca56af8c3e..4f19e5c4d6 100644
--- a/sapi/phpdbg/phpdbg_watch.h
+++ b/sapi/phpdbg/phpdbg_watch.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -45,6 +45,9 @@ typedef enum {
WATCH_ON_ZVAL,
WATCH_ON_HASHTABLE,
WATCH_ON_REFCOUNTED,
+ WATCH_ON_STR,
+ WATCH_ON_HASHDATA,
+ WATCH_ON_BUCKET,
} phpdbg_watchtype;
@@ -54,41 +57,68 @@ typedef enum {
#define PHPDBG_WATCH_OBJECT 0x08
#define PHPDBG_WATCH_NORMAL (PHPDBG_WATCH_SIMPLE | PHPDBG_WATCH_RECURSIVE)
#define PHPDBG_WATCH_IMPLICIT 0x10
+#define PHPDBG_WATCH_RECURSIVE_ROOT 0x20
-#define PHPDBG_DESTRUCTED_ZVAL 0x80
+typedef struct _phpdbg_watch_collision phpdbg_watch_collision;
-typedef struct _phpdbg_watchpoint_t phpdbg_watchpoint_t;
-
-struct _phpdbg_watchpoint_t {
+typedef struct _phpdbg_watchpoint_t {
union {
zval *zv;
zend_refcounted *ref;
+ Bucket *bucket;
void *ptr;
} addr;
size_t size;
phpdbg_watchtype type;
- char flags;
- unsigned int implicit_ht_count;
- phpdbg_watchpoint_t *parent;
- phpdbg_watchpoint_t *reference;
- HashTable *parent_container;
- zend_string *name_in_parent;
- zend_string *str;
+ zend_refcounted *ref; /* key to fetch the collision on parents */
+ HashTable elements;
+ phpdbg_watch_collision *coll; /* only present on *children* */
+ union {
+ zval zv;
+ Bucket bucket;
+ zend_refcounted ref;
+ HashTable ht;
+ zend_string *str;
+ } backup;
+} phpdbg_watchpoint_t;
+
+struct _phpdbg_watch_collision {
+ phpdbg_watchpoint_t ref;
+ phpdbg_watchpoint_t reference;
+ HashTable parents;
};
-typedef struct {
+typedef struct _phpdbg_watch_element {
+ uint32_t id;
phpdbg_watchpoint_t *watch;
- unsigned int refs;
- HashTable watches;
- HashTable implicit_watches;
-} phpdbg_watch_collision;
+ char flags;
+ struct _phpdbg_watch_element *child; /* always set for implicit watches */
+ struct _phpdbg_watch_element *parent;
+ HashTable child_container; /* children of this watch element for recursive array elements */
+ HashTable *parent_container; /* container of the value */
+ zend_string *name_in_parent;
+ zend_string *str;
+ union {
+ zval zv;
+ zend_refcounted ref;
+ HashTable ht;
+ } backup; /* backup for when watchpoint gets dissociated */
+} phpdbg_watch_element;
typedef struct {
- dtor_func_t dtor;
- HashTable watches;
+ /* to watch rehashes (yes, this is not *perfect*, but good enough for everything in PHP...) */
+ phpdbg_watchpoint_t hash_watch; /* must be first element */
+ Bucket *last;
+ zend_string *last_str;
+ zend_ulong last_idx;
+
+ HashTable *ht;
+ size_t data_size;
+ HashTable watches; /* contains phpdbg_watch_element */
} phpdbg_watch_ht_info;
void phpdbg_setup_watchpoints(void);
+void phpdbg_destroy_watchpoints(void);
#ifndef _WIN32
int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context);
diff --git a/sapi/phpdbg/phpdbg_webdata_transfer.c b/sapi/phpdbg/phpdbg_webdata_transfer.c
index ddcf2deec2..2deb1607c5 100644
--- a/sapi/phpdbg/phpdbg_webdata_transfer.c
+++ b/sapi/phpdbg/phpdbg_webdata_transfer.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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 |
@@ -23,7 +23,7 @@ static int phpdbg_is_auto_global(char *name, int len) {
int ret;
zend_string *str = zend_string_init(name, len, 0);
ret = zend_is_auto_global(str);
- efree(str);
+ zend_string_free(str);
return ret;
}
diff --git a/sapi/phpdbg/phpdbg_webdata_transfer.h b/sapi/phpdbg/phpdbg_webdata_transfer.h
index 28810a2741..df205251a6 100644
--- a/sapi/phpdbg/phpdbg_webdata_transfer.h
+++ b/sapi/phpdbg/phpdbg_webdata_transfer.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_win.c b/sapi/phpdbg/phpdbg_win.c
index 132eb05b1e..4b4511b7a6 100644
--- a/sapi/phpdbg/phpdbg_win.c
+++ b/sapi/phpdbg/phpdbg_win.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/phpdbg_win.h b/sapi/phpdbg/phpdbg_win.h
index 9e1501b263..56892bab28 100644
--- a/sapi/phpdbg/phpdbg_win.h
+++ b/sapi/phpdbg/phpdbg_win.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 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/tests/basic_run.phpt b/sapi/phpdbg/tests/basic_run.phpt
new file mode 100644
index 0000000000..beb19b535a
--- /dev/null
+++ b/sapi/phpdbg/tests/basic_run.phpt
@@ -0,0 +1,8 @@
+--TEST--
+Basic run
+--PHPDBG--
+r
+q
+--EXPECTF--
+prompt> [Nothing to execute!]
+prompt>
diff --git a/sapi/phpdbg/tests/breakpoints_001.phpt b/sapi/phpdbg/tests/breakpoints_001.phpt
new file mode 100644
index 0000000000..17e7c65cbf
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_001.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Fundamental breakpoints functionality
+--PHPDBG--
+b 3
+r
+b 4
+c
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:3]
+prompt> [Breakpoint #0 at %s:3, hits: 1]
+>00003: echo $i++;
+ 00004: echo $i++;
+ 00005: echo $i++;
+prompt> [Breakpoint #1 added at %s:4]
+prompt> 1
+[Breakpoint #1 at %s:4, hits: 1]
+>00004: echo $i++;
+ 00005: echo $i++;
+ 00006: echo $i++;
+prompt> 234
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+$i = 1;
+echo $i++;
+echo $i++;
+echo $i++;
+echo $i++;
+
diff --git a/sapi/phpdbg/tests/breakpoints_002.phpt b/sapi/phpdbg/tests/breakpoints_002.phpt
new file mode 100644
index 0000000000..96c98194b1
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_002.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Preserve breakpoints on restart
+--PHPDBG--
+b breakpoints_002.php:4
+r
+b 3
+r
+y
+c
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:4]
+prompt> 1
+[Breakpoint #0 at %s:4, hits: 1]
+>00004: echo $i++;
+ 00005: echo $i++;
+ 00006: echo $i++;
+prompt> [Breakpoint #1 added at %s:3]
+prompt> Do you really want to restart execution? (type y or n): [Breakpoint #1 at %s:3, hits: 1]
+>00003: echo $i++;
+ 00004: echo $i++;
+ 00005: echo $i++;
+prompt> 1
+[Breakpoint #0 at %s:4, hits: 1]
+>00004: echo $i++;
+ 00005: echo $i++;
+ 00006: echo $i++;
+prompt> 234
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+$i = 1;
+echo $i++;
+echo $i++;
+echo $i++;
+echo $i++;
+
diff --git a/sapi/phpdbg/tests/breakpoints_003.phpt b/sapi/phpdbg/tests/breakpoints_003.phpt
new file mode 100644
index 0000000000..12b2504487
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_003.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Test deleting breakpoints
+--PHPDBG--
+b 4
+b del 0
+b 5
+r
+b del 1
+r
+y
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Deleted breakpoint #0]
+prompt> [Breakpoint #1 added at %s:5]
+prompt> 12
+[Breakpoint #1 at %s:5, hits: 1]
+>00005: echo $i++;
+ 00006: echo $i++;
+ 00007:
+prompt> [Deleted breakpoint #1]
+prompt> Do you really want to restart execution? (type y or n): 1234
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+$i = 1;
+echo $i++;
+echo $i++;
+echo $i++;
+echo $i++;
+
diff --git a/sapi/phpdbg/tests/breakpoints_004.phpt b/sapi/phpdbg/tests/breakpoints_004.phpt
new file mode 100644
index 0000000000..917e908efb
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_004.phpt
@@ -0,0 +1,41 @@
+--TEST--
+Test opcode breakpoints
+--PHPDBG--
+b ZEND_ECHO
+r
+c
+
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at ZEND_ECHO]
+prompt> [Breakpoint #0 in ZEND_ECHO at %s:3, hits: 1]
+>00003: echo $i++;
+ 00004: echo $i++;
+ 00005: echo $i++;
+prompt> 1
+[Breakpoint #0 in ZEND_ECHO at %s:4, hits: 2]
+>00004: echo $i++;
+ 00005: echo $i++;
+ 00006: echo $i++;
+prompt> 2
+[Breakpoint #0 in ZEND_ECHO at %s:5, hits: 3]
+>00005: echo $i++;
+ 00006: echo $i++;
+ 00007:
+prompt> 3
+[Breakpoint #0 in ZEND_ECHO at %s:6, hits: 4]
+>00006: echo $i++;
+ 00007:
+prompt> 4
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+$i = 1;
+echo $i++;
+echo $i++;
+echo $i++;
+echo $i++;
diff --git a/sapi/phpdbg/tests/breakpoints_005.phpt b/sapi/phpdbg/tests/breakpoints_005.phpt
new file mode 100644
index 0000000000..653dab9fcc
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_005.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Test breakpoint into function context
+--PHPDBG--
+b breakpoints_005.php:4
+r
+ev $bar
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Breakpoint #0 at %s:4, hits: 1]
+>00004: var_dump($bar);
+ 00005: }
+ 00006:
+prompt> test
+prompt> string(4) "test"
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+function foo($bar) {
+ var_dump($bar);
+}
+
+foo("test");
+
diff --git a/sapi/phpdbg/tests/breakpoints_006.phpt b/sapi/phpdbg/tests/breakpoints_006.phpt
new file mode 100644
index 0000000000..fa6f0cdc5b
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_006.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Basic function breakpoints
+--PHPDBG--
+b foo
+r
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at foo]
+prompt> [Breakpoint #0 in foo() at %s:4, hits: 1]
+>00004: var_dump($bar);
+ 00005: }
+ 00006:
+prompt> string(4) "test"
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+function foo($bar) {
+ var_dump($bar);
+}
+
+foo("test");
+
diff --git a/sapi/phpdbg/tests/breakpoints_007.phpt b/sapi/phpdbg/tests/breakpoints_007.phpt
new file mode 100644
index 0000000000..f921c257c5
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_007.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Basic method breakpoints
+--PHPDBG--
+b bar::foo
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at bar::foo]
+prompt> [Breakpoint #0 in bar::foo() at %s:5, hits: 1]
+>00005: var_dump($bar);
+ 00006: }
+ 00007: }
+prompt>
+--FILE--
+<?php
+
+class bar {
+ function foo($bar) {
+ var_dump($bar);
+ }
+}
+
+(new bar)->foo("test");
+
diff --git a/sapi/phpdbg/tests/breakpoints_008.phpt b/sapi/phpdbg/tests/breakpoints_008.phpt
new file mode 100644
index 0000000000..cbe5042c2b
--- /dev/null
+++ b/sapi/phpdbg/tests/breakpoints_008.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Test namespaced and non-lowercase breakpoint names
+--PHPDBG--
+b foo\bar::foo
+b \Foo\Bar::Foo
+r
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at foo\bar::foo]
+prompt> [Breakpoint exists at Foo\Bar::Foo]
+prompt> [Breakpoint #0 in foo\bar::foo() at %s:6, hits: 1]
+>00006: var_dump($bar);
+ 00007: }
+ 00008: }
+prompt> string(4) "test"
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+namespace Foo {
+ class Bar {
+ function Foo($bar) {
+ var_dump($bar);
+ }
+ }
+}
+
+namespace {
+ (new \Foo\Bar)->Foo("test");
+}
+
diff --git a/sapi/phpdbg/tests/bug73615.phpt b/sapi/phpdbg/tests/bug73615.phpt
new file mode 100644
index 0000000000..e5fccef0a8
--- /dev/null
+++ b/sapi/phpdbg/tests/bug73615.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #73615 (phpdbg without option never load .phpdbginit at startup)
+--SKIPIF--
+<?php
+if (!getenv('TEST_PHPDBG_EXECUTABLE')) die("SKIP: No TEST_PHPDBG_EXECUTABLE specified");
+?>
+--FILE--
+<?php
+
+$phpdbg = getenv('TEST_PHPDBG_EXECUTABLE');
+
+chdir(__DIR__."/bug73615");
+
+print `$phpdbg -qn`;
+
+?>
+--EXPECT--
+Executed .phpdbginit
diff --git a/sapi/phpdbg/tests/bug73615/.phpdbginit b/sapi/phpdbg/tests/bug73615/.phpdbginit
new file mode 100644
index 0000000000..29184ddf7c
--- /dev/null
+++ b/sapi/phpdbg/tests/bug73615/.phpdbginit
@@ -0,0 +1,2 @@
+ev "Executed .phpdbginit"
+q
diff --git a/sapi/phpdbg/tests/bug73704.phpt b/sapi/phpdbg/tests/bug73704.phpt
new file mode 100644
index 0000000000..a3ee92b126
--- /dev/null
+++ b/sapi/phpdbg/tests/bug73704.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #73704 (phpdbg shows the wrong line in files with shebang)
+--PHPDBG--
+list 6
+b 4
+r
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> 00001: #!/usr/bin/env php
+ 00002: <?php
+ 00003:
+ 00004: echo 1;
+ 00005:
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Breakpoint #0 at %s:4, hits: 1]
+>00004: echo 1;
+ 00005:
+prompt> 1
+[Script ended normally]
+prompt>
+--FILE--
+#!/usr/bin/env php
+<?php
+
+echo 1;
diff --git a/sapi/phpdbg/tests/bug73794.phpt b/sapi/phpdbg/tests/bug73794.phpt
new file mode 100644
index 0000000000..8d5ba234c7
--- /dev/null
+++ b/sapi/phpdbg/tests/bug73794.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Bug #73794 (Crash (out of memory) when using run and # command separator)
+--PHPDBG--
+r echo # quit
+--EXPECTF--
+[Successful compilation of %s]
+prompt> echo
+--FILE--
+<?php
+echo $argv[1];
+?>
diff --git a/sapi/phpdbg/tests/clean_001.phpt b/sapi/phpdbg/tests/clean_001.phpt
new file mode 100644
index 0000000000..0500850448
--- /dev/null
+++ b/sapi/phpdbg/tests/clean_001.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Cleaning must preserve breakpoints
+--INI--
+opcache.enable_cli=0
+--PHPDBG--
+b 4
+b foo
+r
+c
+clean
+y
+c
+r
+c
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Breakpoint #1 added at foo]
+prompt> 1
+[Breakpoint #0 at %s:4, hits: 1]
+>00004: echo 2;
+ 00005: echo 3;
+ 00006: foo();
+prompt> 23
+[Breakpoint #1 in foo() at %s:9, hits: 1]
+>00009: echo 4;
+ 00010: }
+ 00011:
+prompt> Do you really want to clean your current environment? (type y or n): Cleaning Execution Environment
+Classes %d
+Functions %d
+Constants %d
+Includes 0
+prompt> [Not running]
+prompt> 1
+[Breakpoint #0 at %s:4, hits: 1]
+>00004: echo 2;
+ 00005: echo 3;
+ 00006: foo();
+prompt> 23
+[Breakpoint #1 in foo() at %s:9, hits: 1]
+>00009: echo 4;
+ 00010: }
+ 00011:
+prompt> 4
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+echo 1;
+echo 2;
+echo 3;
+foo();
+
+function foo() {
+ echo 4;
+}
diff --git a/sapi/phpdbg/tests/clear_001.phpt b/sapi/phpdbg/tests/clear_001.phpt
new file mode 100644
index 0000000000..96d73990eb
--- /dev/null
+++ b/sapi/phpdbg/tests/clear_001.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Test clearing breakpoints
+--INI--
+opcache.enable_cli=0
+--PHPDBG--
+b 4
+b foo
+r
+clear
+c
+i b
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Breakpoint #1 added at foo]
+prompt> 1
+[Breakpoint #0 at %s:4, hits: 1]
+>00004: echo 2;
+ 00005: echo 3;
+ 00006: foo();
+prompt> Clearing Breakpoints
+File 1
+Functions 1
+Methods 0
+Oplines 0
+File oplines 0
+Function oplines 0
+Method oplines 0
+Conditionals 0
+prompt> 234
+[Script ended normally]
+prompt> prompt>
+--FILE--
+<?php
+
+echo 1;
+echo 2;
+echo 3;
+foo();
+
+function foo() {
+ echo 4;
+}
diff --git a/sapi/phpdbg/tests/commands/0001_basic.test b/sapi/phpdbg/tests/commands/0001_basic.test
deleted file mode 100644
index 08aa9ab664..0000000000
--- a/sapi/phpdbg/tests/commands/0001_basic.test
+++ /dev/null
@@ -1,8 +0,0 @@
-#######################################################
-# 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
deleted file mode 100644
index 6a14a15adc..0000000000
--- a/sapi/phpdbg/tests/commands/0002_set.test
+++ /dev/null
@@ -1,21 +0,0 @@
-#################################################
-# 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 off]
-# 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 test.log
diff --git a/sapi/phpdbg/tests/commands/0101_info.test b/sapi/phpdbg/tests/commands/0101_info.test
deleted file mode 100644
index 397a45c992..0000000000
--- a/sapi/phpdbg/tests/commands/0101_info.test
+++ /dev/null
@@ -1,19 +0,0 @@
-#################################################
-# 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
deleted file mode 100644
index 7078b13ea2..0000000000
--- a/sapi/phpdbg/tests/commands/0102_print.test
+++ /dev/null
@@ -1,27 +0,0 @@
-#################################################
-# name: print
-# purpose: test print commands
-# expect: TEST::FORMAT
-# options: -rr
-#################################################
-#[User Class: test (3 methods)]
-#L%d-%d test::testMethod() %s - 0x%s + 1 ops
-# L%d #0 RETURN null
-#L%d-%d test::testPrivateMethod() %s - 0x%s + 1 ops
-# L%d #0 RETURN null
-#L%d-%d test::testProtectedMethod() %s - 0x%s + 1 ops
-# L%d #0 RETURN null
-#[User Method testMethod (1 ops)]
-#L%d-%d test::testMethod() %s - 0x%s + 1 ops
-# L%d #0 RETURN null
-#################################################
-<:
-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
deleted file mode 100644
index 703a12f771..0000000000
--- a/sapi/phpdbg/tests/commands/0103_register.test
+++ /dev/null
@@ -1,28 +0,0 @@
-#################################################
-# name: register
-# purpose: test registration functions
-# expect: TEST::FORMAT
-# options: -rr
-#################################################
-#[Registered test_function]
-#array(5) {
-# [0]=>
-# int(1)
-# [1]=>
-# int(2)
-# [2]=>
-# int(3)
-# [3]=>
-# int(4)
-# [4]=>
-# int(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
deleted file mode 100644
index 2c7660ad60..0000000000
--- a/sapi/phpdbg/tests/commands/0104_clean.test
+++ /dev/null
@@ -1,14 +0,0 @@
-#################################################
-# name: clean
-# purpose: test cleaning environment
-# expect: TEST::FORMAT
-# options: -rr
-#################################################
-#Cleaning Execution Environment
-#Classes %d
-#Functions %d
-#Constants %d
-#Includes %d
-#################################################
-clean
-quit
diff --git a/sapi/phpdbg/tests/commands/0105_clear.test b/sapi/phpdbg/tests/commands/0105_clear.test
deleted file mode 100644
index 8ce1002491..0000000000
--- a/sapi/phpdbg/tests/commands/0105_clear.test
+++ /dev/null
@@ -1,18 +0,0 @@
-#################################################
-# 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
deleted file mode 100644
index b4d801670b..0000000000
--- a/sapi/phpdbg/tests/commands/0106_compile.test
+++ /dev/null
@@ -1,18 +0,0 @@
-#################################################
-# name: compile
-# purpose: test compiling code
-# expect: TEST::FORMAT
-# options: -rr
-#################################################
-#[Successful compilation of %s]
-#Hello World
-#[Script ended normally]
-#################################################
-<:
-define('OUT',
- tempnam(null, "phpdbg"));
-file_put_contents(OUT, "<?php echo \"Hello World\"; ?>");
-phpdbg_exec(OUT);
-:>
-run
-quit
diff --git a/sapi/phpdbg/tests/commands/0107_compile.test b/sapi/phpdbg/tests/commands/0107_compile.test
deleted file mode 100644
index 4842cb74f1..0000000000
--- a/sapi/phpdbg/tests/commands/0107_compile.test
+++ /dev/null
@@ -1,17 +0,0 @@
-#################################################
-# name: compile
-# purpose: test compiling error code
-# expect: TEST::FORMAT
-# options: -rr
-#################################################
-#[PHP Parse error: syntax error, unexpected 'echo' (T_ECHO) in %s on line %s]
-#[Could not find information about included file...]
-#################################################
-<:
-define('OUT',
- tempnam(null, "phpdbg"));
-file_put_contents(OUT, "<?error echo \"Hello World\"; ?>");
-phpdbg_exec(OUT);
-:>
-run
-quit
diff --git a/sapi/phpdbg/tests/delimiter.phpt b/sapi/phpdbg/tests/delimiter.phpt
new file mode 100644
index 0000000000..da5f681783
--- /dev/null
+++ b/sapi/phpdbg/tests/delimiter.phpt
@@ -0,0 +1,7 @@
+--TEST--
+Test # delimiter parsing and execution
+--PHPDBG--
+ev 1 + 3 # ev 2 ** 3#q
+--EXPECTF--
+prompt> 4
+8
diff --git a/sapi/phpdbg/tests/exceptions_001.phpt b/sapi/phpdbg/tests/exceptions_001.phpt
new file mode 100644
index 0000000000..99989654cf
--- /dev/null
+++ b/sapi/phpdbg/tests/exceptions_001.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Properly handle exceptions going to be uncaught
+--PHPDBG--
+r
+t
+ev 1 + 2
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> handle first
+[Uncaught Error in %s on line 16: Call to undefined function foo()]
+>00016: foo(); // Error
+ 00017: } catch (\Exception $e) {
+ 00018: var_dump($e);
+prompt> frame #0: {closure}() at %s:16
+frame #1: {main} at %s:22
+prompt> 3
+prompt> [Uncaught Error in %s on line 16]
+Error: Call to undefined function foo() in %s:16
+Stack trace:
+#0 %s(22): {closure}()
+#1 {main}
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+(function() {
+ try {
+ foo(); // Error
+ } catch (\Exception $e) {
+ var_dump($e);
+ } finally {
+ print "handle first\n";
+ return "ok";
+ }
+})();
+
+(function() {
+ try {
+ foo(); // Error
+ } catch (\Exception $e) {
+ var_dump($e);
+ } catch (\ParseError $e) {
+ var_dump($e);
+ }
+})();
diff --git a/sapi/phpdbg/tests/exceptions_002.phpt b/sapi/phpdbg/tests/exceptions_002.phpt
new file mode 100644
index 0000000000..f304cc25db
--- /dev/null
+++ b/sapi/phpdbg/tests/exceptions_002.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Test exceptions in eval during exception
+--PHPDBG--
+r
+ev next_error()
+c
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> handle first
+[Uncaught Error in %s on line 16: Call to undefined function foo()]
+>00016: foo(); // Error
+ 00017: } catch (\Exception $e) {
+ 00018: var_dump($e);
+prompt>
+Fatal error: Uncaught Error: Call to undefined function next_error() in eval()'d code:1
+Stack trace:
+#0 %s(16): unknown()
+#1 %s(20): {closure}()
+#2 {main}
+ thrown in eval()'d code on line 1
+prompt> [Uncaught Error in %s on line 16]
+Error: Call to undefined function foo() in %s:16
+Stack trace:
+#0 %s(20): {closure}()
+#1 {main}
+[Script ended normally]
+prompt> [The stack contains nothing !]
+prompt>
+--FILE--
+<?php
+
+(function() {
+ try {
+ foo(); // Error
+ } catch (\Exception $e) {
+ var_dump($e);
+ } finally {
+ print "handle first\n";
+ return "ok";
+ }
+})();
+
+(function() {
+ try {
+ foo(); // Error
+ } catch (\Exception $e) {
+ var_dump($e);
+ }
+})();
diff --git a/sapi/phpdbg/tests/exceptions_003.phpt b/sapi/phpdbg/tests/exceptions_003.phpt
new file mode 100644
index 0000000000..51090c081a
--- /dev/null
+++ b/sapi/phpdbg/tests/exceptions_003.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Test breaks on HANDLE_EXCEPTION
+--PHPDBG--
+b 5
+r
+s
+
+s
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:5]
+prompt> [Breakpoint #0 at %s:5, hits: 1]
+>00005: x();
+ 00006: } finally {
+ 00007: print "ok\n";
+prompt> [L0 %s HANDLE_EXCEPTION %s]
+>00005: x();
+ 00006: } finally {
+ 00007: print "ok\n";
+prompt> [L7 %s ECHO "ok\n" %s]
+>00007: print "ok\n";
+ 00008: }
+ 00009: } catch (Error $e) {
+prompt> ok
+[L7 %s FAST_RET ~%d try-catch(0) %s]
+[L9 %s CATCH "Error" $e 1 %s]
+>00005: x();
+ 00006: } finally {
+ 00007: print "ok\n";
+prompt> [L10 %s ECHO "caught\n" %s]
+>00010: print "caught\n";
+ 00011: }
+ 00012:
+prompt> caught
+[L14 %s RETURN 1 %s]
+>00014:
+prompt>
+--FILE--
+<?php
+
+try {
+ try {
+ x();
+ } finally {
+ print "ok\n";
+ }
+} catch (Error $e) {
+ print "caught\n";
+}
+
+?>
diff --git a/sapi/phpdbg/tests/finish_leave_001.phpt b/sapi/phpdbg/tests/finish_leave_001.phpt
new file mode 100644
index 0000000000..e345752b00
--- /dev/null
+++ b/sapi/phpdbg/tests/finish_leave_001.phpt
@@ -0,0 +1,43 @@
+--TEST--
+test finish and leave commands
+--INI--
+opcache.optimization_level=0
+--PHPDBG--
+b bar
+b 5
+r
+finish
+leave
+leave
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at bar]
+prompt> [Breakpoint #1 added at %s:5]
+prompt> [Breakpoint #0 in bar() at %s:9, hits: 1]
+>00009: return "world";
+ 00010: }
+ 00011:
+prompt> [Breakpoint #1 at %s:5, hits: 1]
+>00005: return ["hello", $other];
+ 00006: }
+ 00007:
+prompt> [Breaking for leave at %s:5]
+>00005: return ["hello", $other];
+ 00006: }
+ 00007:
+prompt> [Already at the end of the function]
+prompt>
+--FILE--
+<?php
+function foo() {
+ $other = bar();
+
+ return ["hello", $other];
+}
+
+function bar() {
+ return "world";
+}
+
+foo();
diff --git a/sapi/phpdbg/tests/generator_run.phpt b/sapi/phpdbg/tests/generator_run.phpt
new file mode 100644
index 0000000000..798d77051e
--- /dev/null
+++ b/sapi/phpdbg/tests/generator_run.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Ensure proper saving of EX(opline)
+--PHPDBG--
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> caught Generator exception
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+function gen() {
+ try {
+ throw new Exception;
+ } catch(Exception $e) {
+ yield "caught Generator exception";
+ }
+}
+
+foreach (gen() as $v) {
+ print $v;
+}
diff --git a/sapi/phpdbg/tests/include.inc b/sapi/phpdbg/tests/include.inc
new file mode 100644
index 0000000000..fb1b7ca841
--- /dev/null
+++ b/sapi/phpdbg/tests/include.inc
@@ -0,0 +1,3 @@
+<?php
+
+echo 1;
diff --git a/sapi/phpdbg/tests/include_once.phpt b/sapi/phpdbg/tests/include_once.phpt
new file mode 100644
index 0000000000..0a00e04cde
--- /dev/null
+++ b/sapi/phpdbg/tests/include_once.phpt
@@ -0,0 +1,16 @@
+--TEST--
+include_once must include only once
+--PHPDBG--
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> 1
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+include_once __DIR__.'/include.inc';
+include_once __DIR__.'/include.inc';
+
diff --git a/sapi/phpdbg/tests/info_001.phpt b/sapi/phpdbg/tests/info_001.phpt
new file mode 100644
index 0000000000..2f38fd36af
--- /dev/null
+++ b/sapi/phpdbg/tests/info_001.phpt
@@ -0,0 +1,80 @@
+--TEST--
+Test basic info functionality
+--INI--
+auto_globals_jit=0
+--PHPDBG--
+i classes
+i funcs
+b foo
+r
+i v
+i g
+i b
+i d
+i F
+i e
+i l
+c
+i v
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [User Classes (1)]
+User Class Foo\Bar (2)
+|---- in %s on line 4
+prompt> [User Functions (1)]
+|-------- foo in %s on line 14
+prompt> [Breakpoint #0 added at foo]
+prompt> string(4) "test"
+[Breakpoint #0 in foo() at %s:15, hits: 1]
+>00015: var_dump(strrev($baz));
+ 00016: }
+ 00017:
+prompt> [Variables in foo() (1)]
+Address Refs Type Variable
+%s %d string $baz
+string (4) "test"
+prompt> [Superglobal variables (8)]
+Address Refs Type Variable
+%s 2 array $_GET
+%s 2 array $_POST
+%s 2 array $_COOKIE
+%s 2 array $_SERVER
+%s 2 array $_ENV
+%s 1 array $_REQUEST
+%s 2 array $_FILES
+%s 1 array &$GLOBALS
+prompt> ------------------------------------------------
+Function Breakpoints:
+#0 foo
+prompt> [User-defined constants (0)]
+prompt> [Included files: 0]
+prompt> [No error found!]
+prompt> [Literal Constants in foo() (2)]
+|-------- C0 -------> [var_dump]
+|-------- C1 -------> [strrev]
+prompt> string(4) "tset"
+[Script ended normally]
+prompt> [No active op array!]
+prompt>
+--FILE--
+<?php
+
+namespace Foo {
+ class Bar {
+ function Foo($bar) {
+ var_dump($bar);
+ }
+
+ function baz() { }
+ }
+}
+
+namespace {
+ function foo($baz) {
+ var_dump(strrev($baz));
+ }
+
+ (new \Foo\Bar)->Foo("test");
+ foo("test");
+}
diff --git a/sapi/phpdbg/tests/info_002.phpt b/sapi/phpdbg/tests/info_002.phpt
new file mode 100644
index 0000000000..faeca0e430
--- /dev/null
+++ b/sapi/phpdbg/tests/info_002.phpt
@@ -0,0 +1,31 @@
+--TEST--
+info constants test
+--PHPDBG--
+b 10
+r
+i d
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:10]
+prompt> [Breakpoint #0 at %s:10, hits: 1]
+>00010: print B;
+ 00011:
+prompt> [User-defined constants (2)]
+Address Refs Type Constant
+%s 1 integer A
+int (10)
+%s 1 integer B
+int (100)
+prompt>
+--FILE--
+<?php
+
+const A = 10;
+const B = C::D * A;
+
+class C {
+ const D = 10;
+}
+
+print B;
diff --git a/sapi/phpdbg/tests/next_001.phpt b/sapi/phpdbg/tests/next_001.phpt
new file mode 100644
index 0000000000..b07d954303
--- /dev/null
+++ b/sapi/phpdbg/tests/next_001.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Test next command on function boundaries
+--PHPDBG--
+b 4
+r
+n
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Breakpoint #0 at %s:4, hits: 1]
+>00004: echo 0;
+ 00005: }
+ 00006:
+prompt> 0
+[L5 %s RETURN null %s]
+>00005: }
+ 00006:
+ 00007: foo();
+prompt> [L8 %s ECHO 1 %s]
+>00008: echo 1;
+ 00009:
+prompt> 1
+[L9 %s RETURN 1 %s]
+>00009:
+prompt>
+--FILE--
+<?php
+
+function foo() {
+ echo 0;
+}
+
+foo();
+echo 1;
diff --git a/sapi/phpdbg/tests/normal_exit.phpt b/sapi/phpdbg/tests/normal_exit.phpt
new file mode 100644
index 0000000000..692614e98f
--- /dev/null
+++ b/sapi/phpdbg/tests/normal_exit.phpt
@@ -0,0 +1,15 @@
+--TEST--
+A script with die() must end "normally"
+--PHPDBG--
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Script ended normally]
+prompt>
+--FILE--
+<?php
+
+(function($argv) {
+ die();
+})($argv);
diff --git a/sapi/phpdbg/tests/phpdbg_break_next.phpt b/sapi/phpdbg/tests/phpdbg_break_next.phpt
new file mode 100644
index 0000000000..37ee2e8282
--- /dev/null
+++ b/sapi/phpdbg/tests/phpdbg_break_next.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Test phpdbg_break_next() function
+--PHPDBG--
+r
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> A
+[Breakpoint #0 added at %s]
+[Breakpoint #0 in %s at %s:5, hits: 1]
+>00005: echo 'B';
+ 00006:
+prompt> B
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+echo 'A';
+phpdbg_break_next();
+echo 'B';
diff --git a/sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.inc b/sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.inc
new file mode 100644
index 0000000000..4f4155715d
--- /dev/null
+++ b/sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.inc
@@ -0,0 +1,6 @@
+<?php
+
+function foo()
+{
+ return '<result>'; // line 5 is executable
+}
diff --git a/sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.phpt b/sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.phpt
new file mode 100644
index 0000000000..0ddbd6f527
--- /dev/null
+++ b/sapi/phpdbg/tests/phpdbg_get_executable_stream_wrapper.phpt
@@ -0,0 +1,84 @@
+--TEST--
+Getting executable lines from custom wrappers
+--PHPDBG--
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> array(1) {
+ [5]=>
+ int(0)
+}
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+/**
+ * This example demonstrates how phpdbg_get_executable() behaves differently
+ * when passed the 'files' option vs without, in the face of some mild abuse
+ * of stream wrappers.
+ */
+
+/**
+ * First, we define a stream wrapper that simply maps to a real file on disk.
+ */
+final class StreamWrapper
+{
+ public function stream_open(
+ string $path,
+ string $mode,
+ int $options = 0,
+ string &$openedPath = null
+ ) : bool {
+ if ($mode[0] !== 'r') {
+ return false;
+ }
+
+ list($scheme, $path) = explode('://', $path, 2);
+
+ $stream = \fopen($path, $mode);
+
+ if ($stream === false) {
+ return false;
+ }
+
+ $this->stream = $stream;
+
+ /**
+ * The $openedPath reference variable is assigned, indicating the
+ * *actual* path that was opened. This affects the behaviour of
+ * constants like __FILE__.
+ */
+ $openedPath = \realpath($path);
+
+ return true;
+ }
+
+ public function stream_read(int $count) : string { return \fread($this->stream, $count); }
+ public function stream_close() : bool { return \fclose($this->stream); }
+ public function stream_eof() : bool { return \feof($this->stream); }
+ public function stream_stat() { return \fstat($this->stream); }
+
+ private $stream = false;
+}
+
+stream_wrapper_register('wrapper', StreamWrapper::class);
+
+/**
+ * Next, we include a PHP file that contains executable lines, via the stream
+ * wrapper.
+ */
+$filename = __DIR__ . '/phpdbg_get_executable_stream_wrapper.inc';
+require 'wrapper://' . $filename;
+
+/**
+ * If we call phpdbg_get_executable() and pass no options, the realpath of the
+ * included file is present in the array, but indicates no executable lines.
+ */
+$x = phpdbg_get_executable();
+
+// We expect [5 => 0], but got an empty array ...
+var_dump($x[$filename]);
+
+?>
diff --git a/sapi/phpdbg/tests/phpdbg_oplog_001.phpt b/sapi/phpdbg/tests/phpdbg_oplog_001.phpt
new file mode 100644
index 0000000000..e4e558b9fa
--- /dev/null
+++ b/sapi/phpdbg/tests/phpdbg_oplog_001.phpt
@@ -0,0 +1,58 @@
+--TEST--
+Test phpdbg_*_oplog() functions
+--INI--
+opcache.enable_cli=0
+--PHPDBG--
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> halloarray(2) {
+ ["%s"]=>
+ array(5) {
+ [13]=>
+ int(1)
+ [17]=>
+ int(2)
+ [18]=>
+ int(2)
+ [19]=>
+ int(3)
+ [21]=>
+ int(4)
+ }
+ ["A::b"]=>
+ array(3) {
+ [4]=>
+ int(1)
+ [5]=>
+ int(3)
+ [8]=>
+ int(2)
+ }
+}
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+class A {
+ public function b($c = 1) {
+ if ($c == 1) {
+ // comment
+ }
+ }
+}
+
+phpdbg_start_oplog();
+
+echo "hallo";
+
+// fcalls
+
+$a = new A();
+$a->b();
+$a->b('ha');
+
+var_dump(phpdbg_end_oplog(["functions" => true]));
+
diff --git a/sapi/phpdbg/tests/phpdbg_oplog_002.phpt b/sapi/phpdbg/tests/phpdbg_oplog_002.phpt
new file mode 100644
index 0000000000..b9ba905caa
--- /dev/null
+++ b/sapi/phpdbg/tests/phpdbg_oplog_002.phpt
@@ -0,0 +1,16 @@
+--TEST--
+phpdbg_end_oplog() alone must not crash
+--PHPDBG--
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt>
+Warning: Can not end an oplog without starting it in %s on line 3
+NULL
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+var_dump(phpdbg_end_oplog());
diff --git a/sapi/phpdbg/tests/print_001.phpt b/sapi/phpdbg/tests/print_001.phpt
new file mode 100644
index 0000000000..94ccedc3cf
--- /dev/null
+++ b/sapi/phpdbg/tests/print_001.phpt
@@ -0,0 +1,67 @@
+--TEST--
+Basic print functionality
+--INI--
+opcache.enable_cli=0
+--PHPDBG--
+p foo
+p class \Foo\bar
+p
+p e
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [User Function foo (8 ops)]
+L14-16 foo() %s - %s + 8 ops
+ L14 #0 RECV 1 $baz
+ L15 #1 INIT_FCALL%s %d %s "var_dump"
+ L15 #2 INIT_FCALL%s %d %s "strrev"
+ L15 #3 SEND_VAR $baz 1
+ L15 #4 DO_%cCALL @0
+ L15 #5 SEND_VAR @0 1
+ L15 #6 DO_%cCALL
+ L16 #7 RETURN null
+prompt> [User Class: Foo\Bar (2 methods)]
+L5-7 Foo\Bar::Foo() %s - %s + 5 ops
+ L5 #0 RECV 1 $bar
+ L6 #1 INIT_NS_FCALL_BY_NAME "Foo\\var_dump"
+ L6 #2 SEND_VAR_EX $bar 1
+ L6 #3 DO_FCALL
+ L7 #4 RETURN null
+L9-9 Foo\Bar::baz() %s - %s + 1 ops
+ L9 #0 RETURN null
+prompt> [Not Executing!]
+prompt> [Context %s (11 ops)]
+L1-21 {main}() %s - %s + 11 ops
+ L4 #0 NOP
+ L14 #1 NOP
+ L18 #2 NEW "Foo\\Bar" @1
+ L18 #3 DO_FCALL
+ L18 #4 INIT_METHOD_CALL @1 "Foo"
+ L18 #5 SEND_VAL_EX "test" 1
+ L18 #6 DO_FCALL
+ L19 #7 INIT_FCALL%s %d %s "foo"
+ L19 #8 SEND_VAL "test" 1
+ L19 #9 DO_FCALL
+ L21 #10 RETURN 1
+prompt>
+--FILE--
+<?php
+
+namespace Foo {
+ class Bar {
+ function Foo($bar) {
+ var_dump($bar);
+ }
+
+ function baz() { }
+ }
+}
+
+namespace {
+ function foo($baz) {
+ var_dump(strrev($baz));
+ }
+
+ (new \Foo\Bar)->Foo("test");
+ foo("test");
+}
diff --git a/sapi/phpdbg/tests/print_002.phpt b/sapi/phpdbg/tests/print_002.phpt
new file mode 100644
index 0000000000..3a824986c1
--- /dev/null
+++ b/sapi/phpdbg/tests/print_002.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Relative print commands
+--INI--
+opcache.enable_cli=0
+--PHPDBG--
+b foo
+r
+p
+p o
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at foo]
+prompt> string(4) "test"
+[Breakpoint #0 in foo() at %s:15, hits: 1]
+>00015: var_dump(strrev($baz));
+ 00016: }
+ 00017:
+prompt> [Stack in foo() (8 ops)]
+L14-16 foo() %s - %s + 8 ops
+ L14 #0 RECV 1 $baz
+ L15 #1 INIT_FCALL%s %d %s "var_dump"
+ L15 #2 INIT_FCALL%s %d %s "strrev"
+ L15 #3 SEND_VAR $baz 1
+ L15 #4 DO_%cCALL @0
+ L15 #5 SEND_VAR @0 1
+ L15 #6 DO_%cCALL
+ L16 #7 RETURN null
+prompt> [L15 %s INIT_FCALL%s %d %s "var_dump" %s]
+prompt>
+--FILE--
+<?php
+
+namespace Foo {
+ class Bar {
+ function Foo($bar) {
+ var_dump($bar);
+ }
+
+ function baz() { }
+ }
+}
+
+namespace {
+ function foo($baz) {
+ var_dump(strrev($baz));
+ }
+
+ (new \Foo\Bar)->Foo("test");
+ foo("test");
+}
diff --git a/sapi/phpdbg/tests/run-tests.php b/sapi/phpdbg/tests/run-tests.php
deleted file mode 100644
index 4afb64561c..0000000000
--- a/sapi/phpdbg/tests/run-tests.php
+++ /dev/null
@@ -1,597 +0,0 @@
-<?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-diff2stdout\t\twrite diff to stdout instead of files%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)) {
- $tests[] = new Test($this->config, $test);
- }
- }
-
- return $tests;
- }
-
- /**
- *
- * @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);
-
- return $result;
- }
-
- 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 -nqb', $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() {
- if (count($this->diff['wants'])) {
- if (!$this->config->hasFlag('nodiff')) {
- if ($this->config->hasFlag('diff2stdout')) {
- $difffile = "php://stdout";
- file_put_contents($difffile, "====DIFF====\n");
- } else {
- $difffile = sprintf(
- '%s/%s.diff',
- dirname($this->file), basename($this->file));
- }
-
- if (($diff = fopen($difffile, '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'];
-
- $retval = 0;
-
- {
- $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) {
- $retval |= !$tests->logTest($path, $test);
- }
-
- $tests->logPathStats($path);
- }
-
- $tests->logStats();
- }
-
- die($retval);
-}
-?>
diff --git a/sapi/phpdbg/tests/run_001.phpt b/sapi/phpdbg/tests/run_001.phpt
new file mode 100644
index 0000000000..30aab1f17a
--- /dev/null
+++ b/sapi/phpdbg/tests/run_001.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Test argv passing
+--PHPDBG--
+r
+r 1 2 3
+r
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> int(5)
+array(5) {
+ [0]=>
+ string(%d) "%s"
+ [1]=>
+ string(2) "--"
+ [2]=>
+ string(1) "1"
+ [3]=>
+ string(1) "2"
+ [4]=>
+ string(1) "3"
+}
+[Script ended normally]
+prompt> int(5)
+array(4) {
+ [0]=>
+ string(%d) "%s"
+ [1]=>
+ string(1) "1"
+ [2]=>
+ string(1) "2"
+ [3]=>
+ string(1) "3"
+}
+[Script ended normally]
+prompt> int(5)
+array(5) {
+ [0]=>
+ string(%d) "%s"
+ [1]=>
+ string(2) "--"
+ [2]=>
+ string(1) "1"
+ [3]=>
+ string(1) "2"
+ [4]=>
+ string(1) "3"
+}
+[Script ended normally]
+prompt>
+--ARGS--
+1 2 3
+--FILE--
+<?php
+
+var_dump($argc, $argv);
diff --git a/sapi/phpdbg/tests/run_002.phpt b/sapi/phpdbg/tests/run_002.phpt
new file mode 100644
index 0000000000..02f6889d6d
--- /dev/null
+++ b/sapi/phpdbg/tests/run_002.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Stdin and escaped args being passed to run command
+--CLEAN--
+<?php
+@unlink("run_002_tmp.fixture");
+?>
+--PHPDBG--
+ev file_put_contents("run_002_tmp.fixture", "stdin\ndata")
+b 6
+r <run_002_tmp.fixture
+r arg1 '_ \' arg2 "' < run_002_tmp.fixture
+y
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> 10
+prompt> [Breakpoint #0 added at %s:6]
+prompt> array(1) {
+ [0]=>
+ string(%d) "%s"
+}
+string(10) "stdin
+data"
+[Breakpoint #0 at %s:6, hits: 1]
+>00006: echo "ok\n";
+ 00007:
+prompt> Do you really want to restart execution? (type y or n): array(3) {
+ [0]=>
+ string(%d) "%s"
+ [1]=>
+ string(4) "arg1"
+ [2]=>
+ string(10) "_ ' arg2 ""
+}
+string(10) "stdin
+data"
+[Breakpoint #0 at %s:6, hits: 1]
+>00006: echo "ok\n";
+ 00007:
+prompt> ok
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+var_dump($argv);
+var_dump(stream_get_contents(STDIN));
+
+echo "ok\n";
diff --git a/sapi/phpdbg/tests/set_exception_handler.phpt b/sapi/phpdbg/tests/set_exception_handler.phpt
new file mode 100644
index 0000000000..7d4d4faca0
--- /dev/null
+++ b/sapi/phpdbg/tests/set_exception_handler.phpt
@@ -0,0 +1,19 @@
+--TEST--
+set_exception_handler() in phpdbg
+--PHPDBG--
+r
+c
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Uncaught Exception in %s on line 4: test]
+>00004: throw new Exception("test");
+ 00005:
+prompt> EX
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+set_exception_handler(function () { print "EX\n"; });
+throw new Exception("test");
diff --git a/sapi/phpdbg/tests/stdin_001.phpt b/sapi/phpdbg/tests/stdin_001.phpt
new file mode 100644
index 0000000000..0bc940caef
--- /dev/null
+++ b/sapi/phpdbg/tests/stdin_001.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Test stdin input with breakpoints
+--PHPDBG--
+stdin foo
+<?php
+
+echo "Hello, world!\n";
+foo
+b 3
+r
+c
+r
+q
+--EXPECTF--
+prompt> [Successful compilation of stdin input]
+prompt> [Breakpoint #0 added at -:3]
+prompt> [Breakpoint #0 at -:3, hits: 1]
+>00003: echo "Hello, world!\n";
+ 00004:
+prompt> Hello, world!
+[Script ended normally]
+prompt> [Breakpoint #0 at -:3, hits: 1]
+>00003: echo "Hello, world!\n";
+ 00004:
+prompt> \ No newline at end of file
diff --git a/sapi/phpdbg/tests/stepping_001.phpt b/sapi/phpdbg/tests/stepping_001.phpt
new file mode 100644
index 0000000000..76577b2767
--- /dev/null
+++ b/sapi/phpdbg/tests/stepping_001.phpt
@@ -0,0 +1,67 @@
+--TEST--
+Stepping with exceptions must not be stuck at CATCH
+--INI--
+opcache.enable=0
+--PHPDBG--
+b ZEND_THROW
+r
+s
+
+
+
+
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at ZEND_THROW]
+prompt> [Breakpoint #0 in ZEND_THROW at %s:4, hits: 1]
+>00004: throw new Exception;
+ 00005: }
+ 00006:
+prompt> [L0 %s HANDLE_EXCEPTION %s]
+>00004: throw new Exception;
+ 00005: }
+ 00006:
+prompt> [L0 %s HANDLE_EXCEPTION %s]
+[L9 %s CATCH "Exception" $e 1 %s]
+>00008: foo();
+ 00009: } catch (Exception $e) {
+ 00010: echo "ok";
+prompt> [L10 %s ECHO "ok" %s]
+>00010: echo "ok";
+ 00011: } finally {
+ 00012: echo " ... ok";
+prompt> ok
+[L11 %s FAST_CALL J8 ~%d %s]
+>00011: } finally {
+ 00012: echo " ... ok";
+ 00013: }
+prompt> [L12 %s ECHO " ... ok" %s]
+>00012: echo " ... ok";
+ 00013: }
+ 00014:
+prompt> ... ok
+[L12 %s FAST_RET ~%d %s]
+[L11 %s JMP J10 %s]
+>00011: } finally {
+ 00012: echo " ... ok";
+ 00013: }
+prompt> [L14 %s RETURN 1 %s]
+>00014:
+prompt>
+--FILE--
+<?php
+
+function foo() {
+ throw new Exception;
+}
+
+try {
+ foo();
+} catch (Exception $e) {
+ echo "ok";
+} finally {
+ echo " ... ok";
+}
diff --git a/sapi/phpdbg/tests/watch_001.phpt b/sapi/phpdbg/tests/watch_001.phpt
new file mode 100644
index 0000000000..e16681bf7c
--- /dev/null
+++ b/sapi/phpdbg/tests/watch_001.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Test simple recursive watchpoint
+--INI--
+opcache.optimization_level=0
+--PHPDBG--
+b 3
+r
+w r $b
+c
+
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:3]
+prompt> [Breakpoint #0 at %s:3, hits: 1]
+>00003: $a = 1;
+ 00004: $b = [$a];
+ 00005:
+prompt> [Added recursive watchpoint #0 for $b]
+prompt> [Breaking on watchpoint $b]
+Old value:
+New value: Array ([0] => 1)
+>00006: unset($b);
+ 00007: $b = 2;
+ 00008:
+prompt> [Breaking on watchpoint $b]
+Old value inaccessible or destroyed
+New value:
+>00007: $b = 2;
+ 00008:
+prompt> [Breaking on watchpoint $b]
+Old value:
+New value: 2
+>00008:
+prompt> [$b has been removed, removing watchpoint recursively]
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+$a = 1;
+$b = [$a];
+
+unset($b);
+$b = 2;
diff --git a/sapi/phpdbg/tests/watch_002.phpt b/sapi/phpdbg/tests/watch_002.phpt
new file mode 100644
index 0000000000..b57ca0a1d4
--- /dev/null
+++ b/sapi/phpdbg/tests/watch_002.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Test simple array watchpoint with replace
+--PHPDBG--
+b 6
+r
+w a $a
+c
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:6]
+prompt> [Breakpoint #0 at %s:6, hits: 1]
+>00006: $a[0] = 2;
+ 00007:
+ 00008: $a = [0 => 3, 1 => 4];
+prompt> [Added watchpoint #0 for $a[]]
+prompt> [Breaking on watchpoint $a[]]
+1 elements were added to the array
+>00009:
+prompt> [$a[] has been removed, removing watchpoint]
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+$a = [];
+
+$a[0] = 1;
+$a[0] = 2;
+
+$a = [0 => 3, 1 => 4];
diff --git a/sapi/phpdbg/tests/watch_003.phpt b/sapi/phpdbg/tests/watch_003.phpt
new file mode 100644
index 0000000000..08868aedc3
--- /dev/null
+++ b/sapi/phpdbg/tests/watch_003.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Test simple watchpoint with replace
+--PHPDBG--
+b 6
+r
+w $a[0]
+c
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:6]
+prompt> [Breakpoint #0 at %s:6, hits: 1]
+>00006: $a[0] = 2;
+ 00007:
+ 00008: $a = [0 => 3, 1 => 4];
+prompt> [Added watchpoint #0 for $a[0]]
+prompt> [Breaking on watchpoint $a[0]]
+Old value: 1
+New value: 2
+>00008: $a = [0 => 3, 1 => 4];
+ 00009:
+prompt> [Breaking on watchpoint $a[0]]
+Old value: 2
+New value: 3
+>00009:
+prompt> [$a[0] has been removed, removing watchpoint]
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+$a = [];
+
+$a[0] = 1;
+$a[0] = 2;
+
+$a = [0 => 3, 1 => 4];
diff --git a/sapi/phpdbg/tests/watch_004.phpt b/sapi/phpdbg/tests/watch_004.phpt
new file mode 100644
index 0000000000..878542937b
--- /dev/null
+++ b/sapi/phpdbg/tests/watch_004.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Test detection of inline string manipulations on zval watch
+--INI--
+opcache.optimization_level=0
+--PHPDBG--
+b 3
+r
+w $a
+c
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:3]
+prompt> [Breakpoint #0 at %s:3, hits: 1]
+>00003: $b = "a";
+ 00004: $a = $b.$b;
+ 00005: $a[1] = "b";
+prompt> [Added watchpoint #0 for $a]
+prompt> [Breaking on watchpoint $a]
+Old value:
+New value: aa
+>00005: $a[1] = "b";
+ 00006:
+prompt> [Breaking on watchpoint $a]
+Old value: aa
+New value: ab
+>00006:
+prompt> [$a has been removed, removing watchpoint]
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+$b = "a";
+$a = $b.$b;
+$a[1] = "b";
diff --git a/sapi/phpdbg/tests/watch_005.phpt b/sapi/phpdbg/tests/watch_005.phpt
new file mode 100644
index 0000000000..d6bae9d3f3
--- /dev/null
+++ b/sapi/phpdbg/tests/watch_005.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Test proper watch comparisons when having multiple levels of indirection from a zval to its value
+--PHPDBG--
+b 3
+r
+w r $a
+c
+
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:3]
+prompt> [Breakpoint #0 at %s:3, hits: 1]
+>00003: $b = "a";
+ 00004: $a = $b.$b;
+ 00005: $c = &$a;
+prompt> [Added recursive watchpoint #0 for $a]
+prompt> [Breaking on watchpoint $a]
+Old value:
+New value: aa
+>00005: $c = &$a;
+ 00006: $a[1] = "b";
+ 00007:
+prompt> [Breaking on watchpoint $a]
+Old value inaccessible or destroyed
+New value (reference): aa
+>00006: $a[1] = "b";
+ 00007:
+ 00008: exit;
+prompt> [Breaking on watchpoint $a]
+Old value: aa
+New value: ab
+>00008: exit;
+ 00009:
+prompt> [$a has been removed, removing watchpoint recursively]
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+$b = "a";
+$a = $b.$b;
+$c = &$a;
+$a[1] = "b";
+
+exit;
diff --git a/sapi/phpdbg/tests/watch_006.phpt b/sapi/phpdbg/tests/watch_006.phpt
new file mode 100644
index 0000000000..bf38b8eff1
--- /dev/null
+++ b/sapi/phpdbg/tests/watch_006.phpt
@@ -0,0 +1,71 @@
+--TEST--
+Test multiple watch elements pointing to the same watchpoint
+--PHPDBG--
+b 4
+r
+w $a[0]
+w r $b
+c
+
+
+
+
+
+
+q
+--EXPECTF--
+[Successful compilation of %s]
+prompt> [Breakpoint #0 added at %s:4]
+prompt> [Breakpoint #0 at %s:4, hits: 1]
+>00004: $a[0] = 1;
+ 00005: $b = &$a;
+ 00006: $a[0] = 2;
+prompt> [Added watchpoint #0 for $a[0]]
+prompt> [Added recursive watchpoint #1 for $b]
+prompt> [Breaking on watchpoint $a[0]]
+Old value: 0
+New value: 1
+>00005: $b = &$a;
+ 00006: $a[0] = 2;
+ 00007: $a[1] = 3;
+prompt> [Breaking on watchpoint $b]
+Old value:
+New value (reference): Array ([0] => 1)
+>00006: $a[0] = 2;
+ 00007: $a[1] = 3;
+ 00008: $c = [1];
+prompt> [Breaking on watchpoint $a[0]]
+Old value: 1
+New value: 2
+>00007: $a[1] = 3;
+ 00008: $c = [1];
+ 00009: $b = &$c;
+prompt> [Element 1 has been added to watchpoint]
+[Breaking on watchpoint $b[]]
+1 elements were added to the array
+>00008: $c = [1];
+ 00009: $b = &$c;
+ 00010:
+prompt> [Breaking on watchpoint $b]
+Old value inaccessible or destroyed
+New value (reference): Array ([0] => 2,[1] => 3)
+>00009: $b = &$c;
+ 00010:
+prompt> [Breaking on watchpoint $b]
+Old value inaccessible or destroyed
+New value (reference): Array ([0] => 1)
+>00010:
+prompt> [$b has been removed, removing watchpoint recursively]
+[$a[0] has been removed, removing watchpoint]
+[Script ended normally]
+prompt>
+--FILE--
+<?php
+
+$a = [0];
+$a[0] = 1;
+$b = &$a;
+$a[0] = 2;
+$a[1] = 3;
+$c = [1];
+$b = &$c;
diff --git a/sapi/phpdbg/zend_mm_structs.h b/sapi/phpdbg/zend_mm_structs.h
deleted file mode 100644
index ca64069e0f..0000000000
--- a/sapi/phpdbg/zend_mm_structs.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef ZEND_MM_STRUCTS_H
-#define ZEND_MM_STRUCTS_H
-
-/* structs and macros defined in Zend/zend_alloc.c
- Needed for realizing watchpoints and sigsafe memory */
-
-#include "zend.h"
-
-#ifndef ZEND_MM_COOKIES
-# define ZEND_MM_COOKIES ZEND_DEBUG
-#endif
-
-#define ZEND_MM_CACHE 1
-#ifndef ZEND_MM_CACHE_STAT
-# define ZEND_MM_CACHE_STAT 0
-#endif
-
-typedef struct _zend_mm_block_info {
-#if ZEND_MM_COOKIES
- size_t _cookie;
-#endif
- size_t _size;
- size_t _prev;
-} zend_mm_block_info;
-
-typedef struct _zend_mm_small_free_block {
- zend_mm_block_info info;
-#if ZEND_DEBUG
- unsigned int magic;
-#ifdef ZTS
- THREAD_T thread_id;
-#endif
-#endif
- struct _zend_mm_free_block *prev_free_block;
- struct _zend_mm_free_block *next_free_block;
-} zend_mm_small_free_block;
-
-typedef struct _zend_mm_free_block {
- zend_mm_block_info info;
-#if ZEND_DEBUG
- unsigned int magic;
-#ifdef ZTS
- THREAD_T thread_id;
-#endif
-#endif
- struct _zend_mm_free_block *prev_free_block;
- struct _zend_mm_free_block *next_free_block;
-
- struct _zend_mm_free_block **parent;
- struct _zend_mm_free_block *child[2];
-} zend_mm_free_block;
-
-#define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
- (zend_mm_free_block *) ((char *)&heap->free_buckets[index * 2] + \
- sizeof(zend_mm_free_block *) * 2 - \
- sizeof(zend_mm_small_free_block))
-
-#define ZEND_MM_REST_BUCKET(heap) \
- (zend_mm_free_block *)((char *)&heap->rest_buckets[0] + \
- sizeof(zend_mm_free_block *) * 2 - \
- sizeof(zend_mm_small_free_block))
-
-#define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
-struct _zend_mm_heap {
- int use_zend_alloc;
- void *(*_malloc)(size_t);
- void (*_free)(void *);
- void *(*_realloc)(void *, size_t);
- size_t free_bitmap;
- size_t large_free_bitmap;
- size_t block_size;
- size_t compact_size;
- zend_mm_segment *segments_list;
- zend_mm_storage *storage;
- size_t real_size;
- size_t real_peak;
- size_t limit;
- size_t size;
- size_t peak;
- size_t reserve_size;
- void *reserve;
- int overflow;
- int internal;
-#if ZEND_MM_CACHE
- unsigned int cached;
- zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
-#endif
- zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
- zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
- zend_mm_free_block *rest_buckets[2];
- int rest_count;
-#if ZEND_MM_CACHE_STAT
- struct {
- int count;
- int max_count;
- int hit;
- int miss;
- } cache_stat[ZEND_MM_NUM_BUCKETS+1];
-#endif
-};
-
-#endif