From 43509370272898f7a346de7e2f4c8a012d00f621 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Fri, 20 Dec 2013 14:27:51 +0100 Subject: Merge branch 'master' of sapi/phpdbg into PHP-5.6 Including phpdbg. --- .gdbinit | 10 + .gitignore | 5 + .phpdbginit | 105 +++ .travis.yml | 3 + Changelog.md | 52 ++ Makefile.frag | 28 + README.md | 83 ++ config.m4 | 61 ++ config.w32 | 19 + phpdbg.c | 1308 +++++++++++++++++++++++++++++ phpdbg.h | 187 +++++ phpdbg.init.d | 122 +++ phpdbg_bp.c | 1661 +++++++++++++++++++++++++++++++++++++ phpdbg_bp.h | 146 ++++ phpdbg_break.c | 155 ++++ phpdbg_break.h | 58 ++ phpdbg_cmd.c | 669 +++++++++++++++ phpdbg_cmd.h | 169 ++++ phpdbg_frame.c | 206 +++++ phpdbg_frame.h | 30 + phpdbg_help.c | 603 ++++++++++++++ phpdbg_help.h | 92 ++ phpdbg_info.c | 355 ++++++++ phpdbg_info.h | 49 ++ phpdbg_list.c | 279 +++++++ phpdbg_list.h | 47 ++ phpdbg_opcode.c | 361 ++++++++ phpdbg_opcode.h | 31 + phpdbg_print.c | 258 ++++++ phpdbg_print.h | 51 ++ phpdbg_prompt.c | 1328 +++++++++++++++++++++++++++++ phpdbg_prompt.h | 68 ++ phpdbg_set.c | 208 +++++ phpdbg_set.h | 47 ++ phpdbg_utils.c | 386 +++++++++ phpdbg_utils.h | 110 +++ test.php | 51 ++ tests/commands/0001_basic.test | 8 + tests/commands/0002_set.test | 23 + tests/commands/0101_info.test | 19 + tests/commands/0102_print.test | 28 + tests/commands/0103_register.test | 28 + tests/commands/0104_clean.test | 15 + tests/commands/0105_clear.test | 18 + tests/commands/0106_compile.test | 19 + tests/run-tests.php | 583 +++++++++++++ travis/ci.sh | 9 + web-bootstrap.php | 64 ++ 48 files changed, 10215 insertions(+) create mode 100644 .gdbinit create mode 100644 .gitignore create mode 100644 .phpdbginit create mode 100644 .travis.yml create mode 100644 Changelog.md create mode 100644 Makefile.frag create mode 100644 README.md create mode 100644 config.m4 create mode 100644 config.w32 create mode 100644 phpdbg.c create mode 100644 phpdbg.h create mode 100755 phpdbg.init.d create mode 100644 phpdbg_bp.c create mode 100644 phpdbg_bp.h create mode 100644 phpdbg_break.c create mode 100644 phpdbg_break.h create mode 100644 phpdbg_cmd.c create mode 100644 phpdbg_cmd.h create mode 100644 phpdbg_frame.c create mode 100644 phpdbg_frame.h create mode 100644 phpdbg_help.c create mode 100644 phpdbg_help.h create mode 100644 phpdbg_info.c create mode 100644 phpdbg_info.h create mode 100644 phpdbg_list.c create mode 100644 phpdbg_list.h create mode 100644 phpdbg_opcode.c create mode 100644 phpdbg_opcode.h create mode 100644 phpdbg_print.c create mode 100644 phpdbg_print.h create mode 100644 phpdbg_prompt.c create mode 100644 phpdbg_prompt.h create mode 100644 phpdbg_set.c create mode 100644 phpdbg_set.h create mode 100644 phpdbg_utils.c create mode 100644 phpdbg_utils.h create mode 100644 test.php create mode 100644 tests/commands/0001_basic.test create mode 100644 tests/commands/0002_set.test create mode 100644 tests/commands/0101_info.test create mode 100644 tests/commands/0102_print.test create mode 100644 tests/commands/0103_register.test create mode 100644 tests/commands/0104_clean.test create mode 100644 tests/commands/0105_clear.test create mode 100644 tests/commands/0106_compile.test create mode 100644 tests/run-tests.php create mode 100755 travis/ci.sh create mode 100644 web-bootstrap.php diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000000..401a4bb88c --- /dev/null +++ b/.gdbinit @@ -0,0 +1,10 @@ +define ____phpdbg_globals + if basic_functions_module.zts + if !$tsrm_ls + set $tsrm_ls = ts_resource_ex(0, 0) + end + set $phpdbg = ((zend_phpdbg_globals*) (*((void ***) $tsrm_ls))[phpdbg_globals_id-1]) + else + set $phpdbg = phpdbg_globals + end +end diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..297efcbc42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.libs/ +./phpdbg +*.lo +*.o +build diff --git a/.phpdbginit b/.phpdbginit new file mode 100644 index 0000000000..1ad35218ed --- /dev/null +++ b/.phpdbginit @@ -0,0 +1,105 @@ +########################################################## +# .phpdbginit +# +# Lines starting with # are ignored +# Code must start and end with <: and :> respectively +########################################################## +# Place initialization commands one per line +########################################################## +# exec sapi/phpdbg/test.php +# set color prompt white-bold +# set color notice green +# set color error red + +########################################################## +# Embedding code in .phpdbginit +########################################################## +<: +/* +* This embedded PHP is executed at init time +*/ + +/* +* Functions defined and registered by init +* will persist across cleans +*/ + +/* +function my_debugging_function() +{ + var_dump(func_get_args()); +} +*/ + +/* phpdbg_break(PHPDBG_METHOD, "phpdbg::method"); */ +/* phpdbg_break(PHPDBG_FUNC, "my_global_function"); */ +/* phpdbg_break(PHPDBG_FILE, "/path/to/file.php:10"); */ + +/* + If readline is loaded, you might want to setup completion: +*/ +if (function_exists('readline_completion_function')) { + readline_completion_function(function(){ + return array_merge( + get_defined_functions()['user'], + array_keys(get_defined_constants()) + ); + }); +} + +/* + Setting argv made trivial ... + + argv 1 2 3 4 + ^ set argv for next execution + + argv + ^ unset argv for next execution + +*/ +function argv() +{ + $argv = func_get_args(); + + if (!$argv) { + $_SERVER['argv'] = array(); + $_SERVER['argc'] = 0; + return; + } + + $_SERVER['argv'] = array_merge + ( + array("phpdbg"), + $argv + ); + $_SERVER['argc'] = count($_SERVER['argv']); + + return $_SERVER['argv']; +} +:> +########################################################## +# Now carry on initializing phpdbg ... +########################################################## +# R my_debugging_function +# R argv + +########################################################## +# PHP has many functions that might be useful +# ... you choose ... +########################################################## +# R touch +# R unlink +# R scandir +# R glob + +########################################################## +# Remember: *you have access to the shell* +########################################################## +# The output of registered function calls is not, +# by default, very pretty (unless you implement +# and register a new implementation for phpdbg) +# The output of shell commands will usually be more +# readable on the console +########################################################## +# TLDR; if you have a good shell, use it ... +########################################################## diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..353402858e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: c + +script: ./travis/ci.sh diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000000..c5d8b51514 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,52 @@ +ChangeLog for phpdbg +==================== + +Version 0.3.0 2013-00-00 +------------------------ + +1. Added ability to disable an enable a single breakpoint +2. Added ability to override SAPI name +3. Added extended conditional breakpoint support "break at" +4. Fix loading of zend extnsions with -z +5. Fix crash when loading .phpdbginit with command line switch +6. Fix crash on startup errors +7. Added init.d for remote console (redhat) +8. Added phpdbg_exec userland function +9. Added testing facilities +10. Added break on n-th opline support +11. Improved trace output + +Version 0.2.0 2013-11-31 +------------------------ + +1. Added "break delete " command +2. Added "break opcode " command +3. Added "set" command - control prompt and console colors +4. .phpdbginit now searched in (additional) ini dirs +5. Added source command - load additional .phpdbginit script during session +6. Added remote console mode +7. Added info memory command + +Version 0.1.0 2013-11-23 +------------------------ + +1. New commands: + - until (continue until the current line is executed) + - frame (switch to a frame in the current stack for inspection) + - info (quick access to useful information on the console) + - finish (continue until the current function has returned) + - leave (continue until the current function is returning) + - shell (shell a command) + - register (register a function for use as a command) +2. Added printers for class and method +3. Make uniform commands and aliases where possible +4. Include all alias information and sub-command information in help +5. Added signal handling to break execution (ctrl-c) +6. Fixed #13 (Output Buffering Control seems fail) +7. Fixed #14 (Fixed typo in Makefile.frag) + + +Version 0.0.1 2013-11-15 +------------------------ + +1. Initial features diff --git a/Makefile.frag b/Makefile.frag new file mode 100644 index 0000000000..5be6d5b00f --- /dev/null +++ b/Makefile.frag @@ -0,0 +1,28 @@ +phpdbg: $(BUILD_BINARY) + +phpdbg-shared: $(BUILD_SHARED) + +$(BUILD_SHARED): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) + $(BUILD_PHPDBG_SHARED) + +$(BUILD_BINARY): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) + $(BUILD_PHPDBG) + +install-phpdbg: $(BUILD_BINARY) + @echo "Installing phpdbg binary: $(INSTALL_ROOT)$(bindir)/" + @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir) + @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log + @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run + @$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT) + +clean-phpdbg: + @echo "Cleaning phpdbg object files ..." + find sapi/phpdbg/ -name *.lo -o -name *.o | xargs rm -f + +test-phpdbg: + @echo "Running phpdbg tests ..." + @$(top_builddir)/sapi/cli/php sapi/phpdbg/tests/run-tests.php --phpdbg sapi/phpdbg/phpdbg + +.PHONY: clean-phpdbg test-phpdbg + + diff --git a/README.md b/README.md new file mode 100644 index 0000000000..e7e5c731a8 --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +The interactive PHP debugger +============================ + +Implemented as a SAPI module, phpdbg can excert complete control over the environment without impacting the functionality or performance of your code. + +phpdbg aims to be a lightweight, powerful, easy to use debugging platform for PHP 5.4+ + +[![phpdbg on travis-ci](https://travis-ci.org/krakjoe/phpdbg.png?branch=master)](https://travis-ci.org/krakjoe/phpdbg) + +Features +======== + + - Stepthrough Debugging + - Flexible Breakpoints (Class Method, Function, File:Line, Address, Opcode) + - Easy Access to PHP with built-in eval() + - Easy Access to Currently Executing Code + - Userland API + - SAPI Agnostic - Easily Integrated + - PHP Configuration File Support + - JIT Super Globals - Set Your Own!! + - Optional readline Support - Comfortable Terminal Operation + - Remote Debugging Support - Bundled Java GUI + - Easy Operation - See Help :) + +Planned +======= + + - Improve Everything :) + +Installation +============ + +To install **phpdbg**, you must compile the source against your PHP installation sources, and enable the SAPI with the configure command. + +``` +cd /usr/src/php-src/sapi +git clone https://github.com/krakjoe/phpdbg +cd ../ +./buildconf --force +./configure --enable-phpdbg +make -j8 +make install-phpdbg +``` + +Where the source directory has been used previously to build PHP, there exists a file named *config.nice* which can be used to invoke configure with the same +parameters as were used by the last execution of *configure*. + +**Note:** PHP must be configured with the switch --with-readline for phpdbg to support history, autocompletion, tab-listing etc. + +Command Line Options +==================== + +The following switches are implemented (just like cli SAPI): + + - -n ignore php ini + - -c search for php ini in path + - -z load zend extension + - -d define php ini entry + +The following switches change the default behaviour of phpdbg: + + - -v disables quietness + - -s enabled stepping + - -e sets execution context + - -b boring - disables use of colour on the console + - -I ignore .phpdbginit (default init file) + - -i override .phpgdbinit location (implies -I) + - -O set oplog output file + - -q do not print banner on startup + - -r jump straight to run + - -E enable step through eval() + - -l listen ports for remote mode + - -a listen address for remote mode + - -S override SAPI name + +**Note:** Passing -rr will cause phpdbg to quit after execution, rather than returning to the console. + +Getting Started +=============== + +See the website for tutorials/documentation + +http://phpdbg.com diff --git a/config.m4 b/config.m4 new file mode 100644 index 0000000000..274e6409d0 --- /dev/null +++ b/config.m4 @@ -0,0 +1,61 @@ +dnl +dnl $Id$ +dnl + +PHP_ARG_ENABLE(phpdbg, for phpdbg support, +[ --enable-phpdbg Build phpdbg], yes, yes) + +PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build, +[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) + +if test "$PHP_PHPDBG" != "no"; then + AC_DEFINE(HAVE_PHPDBG, 1, [ ]) + + if test "$PHP_PHPDBG_DEBUG" != "no"; then + AC_DEFINE(PHPDBG_DEBUG, 1, [ ]) + else + AC_DEFINE(PHPDBG_DEBUG, 0, [ ]) + fi + + PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE" + PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c" + + PHP_SUBST(PHP_PHPDBG_CFLAGS) + PHP_SUBST(PHP_PHPDBG_FILES) + + PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/phpdbg/Makefile.frag]) + PHP_SELECT_SAPI(phpdbg, program, $PHP_PHPDBG_FILES, $PHP_PHPDBG_CFLAGS, [$(SAPI_PHPDBG_PATH)]) + + BUILD_BINARY="sapi/phpdbg/phpdbg" + BUILD_SHARED="sapi/phpdbg/libphpdbg.la" + + BUILD_PHPDBG="\$(LIBTOOL) --mode=link \ + \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \ + \$(PHP_GLOBAL_OBJS) \ + \$(PHP_BINARY_OBJS) \ + \$(PHP_PHPDBG_OBJS) \ + \$(EXTRA_LIBS) \ + \$(PHPDBG_EXTRA_LIBS) \ + \$(ZEND_EXTRA_LIBS) \ + -o \$(BUILD_BINARY)" + + BUILD_PHPDBG_SHARED="\$(LIBTOOL) --mode=link \ + \$(CC) -shared -Wl,-soname,libphpdbg.so -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \ + \$(PHP_GLOBAL_OBJS) \ + \$(PHP_BINARY_OBJS) \ + \$(PHP_PHPDBG_OBJS) \ + \$(EXTRA_LIBS) \ + \$(PHPDBG_EXTRA_LIBS) \ + \$(ZEND_EXTRA_LIBS) \ + \-DPHPDBG_SHARED \ + -o \$(BUILD_SHARED)" + + PHP_SUBST(BUILD_BINARY) + PHP_SUBST(BUILD_SHARED) + PHP_SUBST(BUILD_PHPDBG) + PHP_SUBST(BUILD_PHPDBG_SHARED) +fi + +dnl ## Local Variables: +dnl ## tab-width: 4 +dnl ## End: diff --git a/config.w32 b/config.w32 new file mode 100644 index 0000000000..29031507b3 --- /dev/null +++ b/config.w32 @@ -0,0 +1,19 @@ +ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes'); +ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); + +PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c'; +PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; +PHPDBG_EXE='phpdbg.exe'; + +if (PHP_PHPDBG == "yes") { + /* build phpdbg binary */ + SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); + ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); +} + +if (PHP_PHPDBGS == "yes") { + SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32'); + ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib"); +} + + diff --git a/phpdbg.c b/phpdbg.c new file mode 100644 index 0000000000..17193ed244 --- /dev/null +++ b/phpdbg.c @@ -0,0 +1,1308 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_SIGNALS +# include +#endif +#include "phpdbg.h" +#include "phpdbg_prompt.h" +#include "phpdbg_bp.h" +#include "phpdbg_break.h" +#include "phpdbg_utils.h" +#include "phpdbg_set.h" + +/* {{{ remote console headers */ +#ifndef _WIN32 +# include +# include +# include +# include +# include +# include +#endif /* }}} */ + +ZEND_DECLARE_MODULE_GLOBALS(phpdbg); + +static zend_bool phpdbg_booted = 0; + +#if PHP_VERSION_ID >= 50500 +void (*zend_execute_old)(zend_execute_data *execute_data TSRMLS_DC); +#else +void (*zend_execute_old)(zend_op_array *op_array TSRMLS_DC); +#endif + +static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */ +{ + pg->prompt[0] = NULL; + pg->prompt[1] = NULL; + + pg->colors[0] = NULL; + pg->colors[1] = NULL; + pg->colors[2] = NULL; + + pg->exec = NULL; + pg->exec_len = 0; + pg->ops = NULL; + pg->vmret = 0; + pg->bp_count = 0; + pg->lcmd = NULL; + pg->flags = PHPDBG_DEFAULT_FLAGS; + pg->oplog = NULL; + pg->io[PHPDBG_STDIN] = NULL; + pg->io[PHPDBG_STDOUT] = NULL; + pg->io[PHPDBG_STDERR] = NULL; + memset(&pg->lparam, 0, sizeof(phpdbg_param_t)); + pg->frame.num = 0; +} /* }}} */ + +static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ +{ + ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL); +#if PHP_VERSION_ID >= 50500 + zend_execute_old = zend_execute_ex; + zend_execute_ex = phpdbg_execute_ex; +#else + zend_execute_old = zend_execute; + zend_execute = phpdbg_execute_ex; +#endif + + REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHPDBG_FUNC", STR_PARAM, CONST_CS|CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("PHPDBG_COLOR_PROMPT", PHPDBG_COLOR_PROMPT, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHPDBG_COLOR_NOTICE", PHPDBG_COLOR_NOTICE, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHPDBG_COLOR_ERROR", PHPDBG_COLOR_ERROR, CONST_CS|CONST_PERSISTENT); + + return SUCCESS; +} /* }}} */ + +static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */ +{ + zend_hash_destroy((HashTable*)brake); +} /* }}} */ + +static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */ +{ + efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol); +} /* }}} */ + +static void php_phpdbg_destroy_bp_opcode(void *brake) /* {{{ */ +{ + efree((char*)((phpdbg_breakop_t*)brake)->name); +} /* }}} */ + + +static void php_phpdbg_destroy_bp_methods(void *brake) /* {{{ */ +{ + zend_hash_destroy((HashTable*)brake); +} /* }}} */ + +static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */ +{ + phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data; + + if (brake) { + if (brake->ops) { + TSRMLS_FETCH(); + + destroy_op_array( + brake->ops TSRMLS_CC); + efree(brake->ops); + } + efree((char*)brake->code); + } +} /* }}} */ + +static void php_phpdbg_destroy_registered(void *data) /* {{{ */ +{ + TSRMLS_FETCH(); + + zend_function *function = (zend_function*) data; + + destroy_zend_function( + function TSRMLS_CC); +} /* }}} */ + +static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */ +{ + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0); + + zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0); + zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0); + + return SUCCESS; +} /* }}} */ + +static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ +{ + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]); + zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]); + zend_hash_destroy(&PHPDBG_G(seek)); + zend_hash_destroy(&PHPDBG_G(registered)); + + if (PHPDBG_G(exec)) { + efree(PHPDBG_G(exec)); + PHPDBG_G(exec) = NULL; + } + + if (PHPDBG_G(prompt)[0]) { + free(PHPDBG_G(prompt)[0]); + } + if (PHPDBG_G(prompt)[1]) { + free(PHPDBG_G(prompt)[1]); + } + + PHPDBG_G(prompt)[0] = NULL; + PHPDBG_G(prompt)[1] = NULL; + + if (PHPDBG_G(oplog)) { + fclose( + PHPDBG_G(oplog)); + PHPDBG_G(oplog) = NULL; + } + + if (PHPDBG_G(ops)) { + destroy_op_array(PHPDBG_G(ops) TSRMLS_CC); + efree(PHPDBG_G(ops)); + PHPDBG_G(ops) = NULL; + } + + return SUCCESS; +} /* }}} */ + +/* {{{ proto mixed phpdbg_exec(string context) + Attempt to set the execution context for phpdbg + If the execution context was set previously it is returned + If the execution context was not set previously boolean true is returned + If the request to set the context fails, boolean false is returned, and an E_WARNING raised */ +static PHP_FUNCTION(phpdbg_exec) +{ + char *exec = NULL; + zend_ulong exec_len = 0L; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) { + return; + } + + { + struct stat sb; + zend_bool result = 1; + + if (VCWD_STAT(exec, &sb) != FAILURE) { + if (sb.st_mode & (S_IFREG|S_IFLNK)) { + if (PHPDBG_G(exec)) { + ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1); + efree(PHPDBG_G(exec)); + result = 0; + } + + PHPDBG_G(exec) = estrndup(exec, exec_len); + PHPDBG_G(exec_len) = exec_len; + + if (result) + ZVAL_BOOL(return_value, 1); + } else { + zend_error( + E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec); + ZVAL_BOOL(return_value, 0); + } + } else { + zend_error( + E_WARNING, "Failed to set execution context (%s) the file does not exist", exec); + + ZVAL_BOOL(return_value, 0); + } + } +} /* }}} */ + +/* {{{ proto void phpdbg_break([integer type, string expression]) + instructs phpdbg to insert a breakpoint at the next opcode */ +static PHP_FUNCTION(phpdbg_break) +{ + if (ZEND_NUM_ARGS() > 0) { + long type; + char *expr = NULL; + zend_uint expr_len = 0; + phpdbg_param_t param; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &type, &expr, &expr_len) == FAILURE) { + return; + } + + phpdbg_parse_param(expr, expr_len, ¶m TSRMLS_CC); + + switch (type) { + case METHOD_PARAM: + phpdbg_do_break_method(¶m, NULL TSRMLS_CC); + break; + + case FILE_PARAM: + phpdbg_do_break_file(¶m, NULL TSRMLS_CC); + break; + + case NUMERIC_PARAM: + phpdbg_do_break_lineno(¶m, NULL TSRMLS_CC); + break; + + case STR_PARAM: + phpdbg_do_break_func(¶m, NULL TSRMLS_CC); + break; + + default: zend_error( + E_WARNING, "unrecognized parameter type %ld", type); + } + + phpdbg_clear_param(¶m TSRMLS_CC); + + } else if (EG(current_execute_data) && EG(active_op_array)) { + zend_ulong opline_num = (EG(current_execute_data)->opline - + EG(active_op_array)->opcodes); + + phpdbg_set_breakpoint_opline_ex( + &EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC); + } +} /* }}} */ + +/* {{{ proto void phpdbg_clear(void) + instructs phpdbg to clear breakpoints */ +static PHP_FUNCTION(phpdbg_clear) +{ + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]); +} /* }}} */ + +/* {{{ proto void phpdbg_color(integer element, string color) */ +static PHP_FUNCTION(phpdbg_color) +{ + long element; + char *color; + zend_uint color_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) { + return; + } + + switch (element) { + case PHPDBG_COLOR_NOTICE: + case PHPDBG_COLOR_ERROR: + case PHPDBG_COLOR_PROMPT: + phpdbg_set_color_ex(element, color, color_len TSRMLS_CC); + break; + + default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant"); + } +} /* }}} */ + +/* {{{ proto void phpdbg_prompt(string prompt) */ +static PHP_FUNCTION(phpdbg_prompt) +{ + char *prompt; + zend_uint prompt_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) { + return; + } + + phpdbg_set_prompt(prompt TSRMLS_CC); +} /* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_arginfo, 0, 0, 0) + ZEND_ARG_INFO(0, type) + ZEND_ARG_INFO(0, expression) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0) + ZEND_ARG_INFO(0, element) + ZEND_ARG_INFO(0, color) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_prompt_arginfo, 0, 0, 0) + ZEND_ARG_INFO(0, string) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_exec_arginfo, 0, 0, 0) + ZEND_ARG_INFO(0, context) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0) +ZEND_END_ARG_INFO() + +zend_function_entry phpdbg_user_functions[] = { + PHP_FE(phpdbg_clear, phpdbg_clear_arginfo) + PHP_FE(phpdbg_break, phpdbg_break_arginfo) + PHP_FE(phpdbg_exec, phpdbg_exec_arginfo) + PHP_FE(phpdbg_color, phpdbg_color_arginfo) + PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo) +#ifdef PHP_FE_END + PHP_FE_END +#else + {NULL,NULL,NULL} +#endif +}; + +static zend_module_entry sapi_phpdbg_module_entry = { + STANDARD_MODULE_HEADER, + PHPDBG_NAME, + phpdbg_user_functions, + PHP_MINIT(phpdbg), + NULL, + PHP_RINIT(phpdbg), + PHP_RSHUTDOWN(phpdbg), + NULL, + PHPDBG_VERSION, + STANDARD_MODULE_PROPERTIES +}; + +static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */ +{ + if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) { + return FAILURE; + } + + phpdbg_booted=1; + + return SUCCESS; +} /* }}} */ + +static char* php_sapi_phpdbg_read_cookies(TSRMLS_D) /* {{{ */ +{ + return NULL; +} /* }}} */ + +static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */ +{ + return 0; +} +/* }}} */ + +static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */ +{ + /* We do nothing here, this function is needed to prevent that the fallback + * header handling is called. */ + return SAPI_HEADER_SENT_SUCCESSFULLY; +} +/* }}} */ + +static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /* {{{ */ +{ +} +/* }}} */ + +static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ +{ + /* + * We must not request TSRM before being boot + */ + if (phpdbg_booted) { + phpdbg_error("%s", message); + } else fprintf(stdout, "%s\n", message); +} +/* }}} */ + +static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */ +{ + fflush(stdout); + if(SG(request_info).argv0) { + free(SG(request_info).argv0); + SG(request_info).argv0 = NULL; + } + return SUCCESS; +} +/* }}} */ + +static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {{{ */ +{ + unsigned int len; + char *docroot = ""; + + /* In phpdbg mode, we consider the environment to be a part of the server variables + */ + php_import_environment_variables(track_vars_array TSRMLS_CC); + + if (PHPDBG_G(exec)) { + len = PHPDBG_G(exec_len); + if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", + &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("PHP_SELF", PHPDBG_G(exec), + track_vars_array TSRMLS_CC); + } + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", + &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("SCRIPT_NAME", PHPDBG_G(exec), + track_vars_array TSRMLS_CC); + } + + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", + &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec), + track_vars_array TSRMLS_CC); + } + if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", + &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec), + track_vars_array TSRMLS_CC); + } + } + + /* any old docroot will doo */ + len = 0U; + if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", + &docroot, len, &len TSRMLS_CC)) { + php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC); + } +} +/* }}} */ + +static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */ +{ + return phpdbg_write("%s", message); +} /* }}} */ + +#if PHP_VERSION_ID >= 50700 +static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC) /* {{{ */ +{ +#else +static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */ +{ + TSRMLS_FETCH(); +#endif + + fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); +} /* }}} */ + +/* {{{ sapi_module_struct phpdbg_sapi_module +*/ +static sapi_module_struct phpdbg_sapi_module = { + "phpdbg", /* name */ + "phpdbg", /* pretty name */ + + php_sapi_phpdbg_module_startup, /* startup */ + php_module_shutdown_wrapper, /* shutdown */ + + NULL, /* activate */ + php_sapi_phpdbg_deactivate, /* deactivate */ + + php_sapi_phpdbg_ub_write, /* unbuffered write */ + php_sapi_phpdbg_flush, /* flush */ + NULL, /* get uid */ + NULL, /* getenv */ + + php_error, /* error handler */ + + php_sapi_phpdbg_header_handler, /* header handler */ + php_sapi_phpdbg_send_headers, /* send headers handler */ + php_sapi_phpdbg_send_header, /* send header handler */ + + NULL, /* read POST data */ + php_sapi_phpdbg_read_cookies, /* read Cookies */ + + php_sapi_phpdbg_register_vars, /* register server variables */ + php_sapi_phpdbg_log_message, /* Log message */ + NULL, /* Get request time */ + NULL, /* Child terminate */ + STANDARD_SAPI_MODULE_PROPERTIES +}; +/* }}} */ + +const opt_struct OPTIONS[] = { /* {{{ */ + {'c', 1, "ini path override"}, + {'d', 1, "define ini entry on command line"}, + {'n', 0, "no php.ini"}, + {'z', 1, "load zend_extension"}, + /* phpdbg options */ + {'q', 0, "no banner"}, + {'e', 1, "exec"}, + {'v', 0, "disable quietness"}, + {'s', 0, "enable stepping"}, + {'b', 0, "boring colours"}, + {'i', 1, "specify init"}, + {'I', 0, "ignore init"}, + {'O', 1, "opline log"}, + {'r', 0, "run"}, + {'E', 0, "step-through-eval"}, + {'S', 1, "sapi-name"}, +#ifndef _WIN32 + {'l', 1, "listen"}, + {'a', 1, "address-or-any"}, +#endif + {'V', 0, "version"}, + {'-', 0, NULL} +}; /* }}} */ + +const char phpdbg_ini_hardcoded[] = +"html_errors=Off\n" +"register_argc_argv=On\n" +"implicit_flush=On\n" +"display_errors=Off\n" +"log_errors=On\n" +"max_execution_time=0\n" +"max_input_time=-1\n\0"; + +/* overwriteable ini defaults must be set in phpdbg_ini_defaults() */ +#define INI_DEFAULT(name, value) \ + Z_SET_REFCOUNT(tmp, 0); \ + Z_UNSET_ISREF(tmp); \ + ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \ + zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL); + +void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */ +{ + zval tmp; + INI_DEFAULT("report_zend_debug", "0"); +} /* }}} */ + +static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */ +{ + /* print blurb */ + if (!cleaning) { + phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", + PHPDBG_VERSION); + phpdbg_writeln("To get help using phpdbg type \"help\" and press enter"); + phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); + } else { + phpdbg_notice("Clean Execution Environment"); + + phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files))); + } +} /* }}} */ + +static inline void phpdbg_sigint_handler(int signo) /* {{{ */ +{ + TSRMLS_FETCH(); + + if (EG(in_execution)) { + /* set signalled only when not interactive */ + if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { + PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; + } + } else { + PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; + zend_bailout(); + } +} /* }}} */ + +#ifndef _WIN32 +int phpdbg_open_socket(const char *interface, short port) /* {{{ */ +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + + switch (fd) { + case -1: + return -1; + + default: { + int reuse = 1; + + switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) { + case -1: + close(fd); + return -2; + + default: { + struct sockaddr_in address; + + memset(&address, 0, sizeof(address)); + + address.sin_port = htons(port); + address.sin_family = AF_INET; + + if ((*interface == '*')) { + address.sin_addr.s_addr = htonl(INADDR_ANY); + } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) { + close(fd); + return -3; + } + + switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) { + case -1: + close(fd); + return -4; + + default: { + listen(fd, 5); + } + } + } + } + } + } + + return fd; +} /* }}} */ + +static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */ +{ + if ((*socket)[0] >= 0) { + shutdown( + (*socket)[0], SHUT_RDWR); + close((*socket)[0]); + } + + if (streams[0]) { + fclose(streams[0]); + } + + if ((*socket)[1] >= 0) { + shutdown( + (*socket)[1], SHUT_RDWR); + close((*socket)[1]); + } + + if (streams[1]) { + fclose(streams[1]); + } +} /* }}} */ + +/* don't inline this, want to debug it easily, will inline when done */ + +int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */ +{ + if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) { + ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]); + ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]); + } + + streams[0] = NULL; + streams[1] = NULL; + + if ((*listen)[0] < 0 || (*listen)[1] < 0) { + if ((*listen)[0] < 0) { + phpdbg_rlog(stderr, + "console failed to initialize (stdin) on %s:%d", address, port[0]); + } + + if ((*listen)[1] < 0) { + phpdbg_rlog(stderr, + "console failed to initialize (stdout) on %s:%d", address, port[1]); + } + + if ((*listen)[0] >= 0) { + close((*listen)[0]); + } + + if ((*listen)[1] >= 0) { + close((*listen)[1]); + } + + return FAILURE; + } + + phpdbg_close_sockets(socket, streams); + + phpdbg_rlog(stderr, + "accepting connections on %s:%d/%d", address, port[0], port[1]); + { + struct sockaddr_in address; + socklen_t size = sizeof(address); + char buffer[20] = {0}; + + { + memset(&address, 0, size); + (*socket)[0] = accept( + (*listen)[0], (struct sockaddr *) &address, &size); + inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); + + phpdbg_rlog(stderr, "connection (stdin) from %s", buffer); + } + + { + memset(&address, 0, size); + (*socket)[1] = accept( + (*listen)[1], (struct sockaddr *) &address, &size); + inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); + + phpdbg_rlog(stderr, "connection (stdout) from %s", buffer); + } + } + + dup2((*socket)[0], fileno(stdin)); + dup2((*socket)[1], fileno(stdout)); + + setbuf(stdout, NULL); + + streams[0] = fdopen((*socket)[0], "r"); + streams[1] = fdopen((*socket)[1], "w"); + + return SUCCESS; +} /* }}} */ +#endif + +int main(int argc, char **argv) /* {{{ */ +{ + sapi_module_struct *phpdbg = &phpdbg_sapi_module; + char *sapi_name; + char *ini_entries; + int ini_entries_len; + char **zend_extensions = NULL; + zend_ulong zend_extensions_len = 0L; + zend_bool ini_ignore; + char *ini_override; + char *exec; + size_t exec_len; + char *init_file; + size_t init_file_len; + zend_bool init_file_default; + char *oplog_file; + size_t oplog_file_len; + zend_ulong flags; + char *php_optarg; + int php_optind, opt, show_banner = 1; + long cleaning = 0; + zend_bool remote = 0; + int run = 0; + int step = 0; + char *bp_tmp_file; +#ifndef _WIN32 + char *address; + int listen[2]; + int server[2]; + int socket[2]; + FILE* streams[2] = {NULL, NULL}; +#endif + +#ifdef ZTS + void ***tsrm_ls; +#endif + +#ifndef _WIN32 + address = strdup("127.0.0.1"); + socket[0] = -1; + socket[1] = -1; + listen[0] = -1; + listen[1] = -1; + server[0] = -1; + server[1] = -1; + streams[0] = NULL; + streams[1] = NULL; +#endif + +#ifdef PHP_WIN32 + _fmode = _O_BINARY; /* sets default for file streams to binary */ + setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */ + setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */ + setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */ +#endif + +#ifdef ZTS + tsrm_startup(1, 1, 0, NULL); + + tsrm_ls = ts_resource(0); +#endif + +phpdbg_main: + if (!cleaning) { + bp_tmp_file = malloc(L_tmpnam); + tmpnam(bp_tmp_file); + if (bp_tmp_file == NULL) { + phpdbg_error("Unable to create temporary file"); + } + } + ini_entries = NULL; + ini_entries_len = 0; + ini_ignore = 0; + ini_override = NULL; + zend_extensions = NULL; + zend_extensions_len = 0L; + exec = NULL; + exec_len = 0; + init_file = NULL; + init_file_len = 0; + init_file_default = 1; + oplog_file = NULL; + oplog_file_len = 0; + flags = PHPDBG_DEFAULT_FLAGS; + php_optarg = NULL; + php_optind = 1; + opt = 0; + run = 0; + step = 0; + sapi_name = NULL; + + + while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) { + switch (opt) { + case 'r': + run++; + break; + case 'n': + ini_ignore = 1; + break; + case 'c': + if (ini_override) { + free(ini_override); + } + ini_override = strdup(php_optarg); + break; + case 'd': { + int len = strlen(php_optarg); + char *val; + + if ((val = strchr(php_optarg, '='))) { + val++; + if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') { + ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0")); + memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg)); + ini_entries_len += (val - php_optarg); + memcpy(ini_entries + ini_entries_len, "\"", 1); + ini_entries_len++; + memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg)); + ini_entries_len += len - (val - php_optarg); + memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0")); + ini_entries_len += sizeof("\n\0\"") - 2; + } else { + ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0")); + memcpy(ini_entries + ini_entries_len, php_optarg, len); + memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0")); + ini_entries_len += len + sizeof("\n\0") - 2; + } + } else { + ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0")); + memcpy(ini_entries + ini_entries_len, php_optarg, len); + memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0")); + ini_entries_len += len + sizeof("=1\n\0") - 2; + } + } break; + + case 'z': + zend_extensions_len++; + if (zend_extensions) { + zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len); + } else zend_extensions = malloc(sizeof(char*) * zend_extensions_len); + zend_extensions[zend_extensions_len-1] = strdup(php_optarg); + break; + + /* begin phpdbg options */ + + case 'e': { /* set execution context */ + exec_len = strlen(php_optarg); + if (exec_len) { + if (exec) { + free(exec); + } + exec = strdup(php_optarg); + } + } break; + + case 'S': { /* set SAPI name */ + if (sapi_name) { + free(sapi_name); + } + sapi_name = strdup(php_optarg); + } break; + + case 'I': { /* ignore .phpdbginit */ + init_file_default = 0; + } break; + + case 'i': { /* set init file */ + if (init_file) { + free(init_file); + } + + init_file_len = strlen(php_optarg); + if (init_file_len) { + init_file = strdup(php_optarg); + } + } break; + + case 'O': { /* set oplog output */ + oplog_file_len = strlen(php_optarg); + if (oplog_file_len) { + oplog_file = strdup(php_optarg); + } + } break; + + case 'v': /* set quietness off */ + flags &= ~PHPDBG_IS_QUIET; + break; + + case 's': /* set stepping on */ + step = 1; + break; + + case 'E': /* stepping through eval on */ + flags |= PHPDBG_IS_STEPONEVAL; + break; + + case 'b': /* set colours off */ + flags &= ~PHPDBG_IS_COLOURED; + break; + + case 'q': /* hide banner */ + show_banner = 0; + break; + +#ifndef _WIN32 + /* if you pass a listen port, we will accept input on listen port */ + /* and write output to listen port * 2 */ + + case 'l': { /* set listen ports */ + if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) { + if (sscanf(php_optarg, "%d", &listen[0]) != 1) { + /* default to hardcoded ports */ + listen[0] = 4000; + listen[1] = 8000; + } else { + listen[1] = (listen[0] * 2); + } + } + } break; + + case 'a': { /* set bind address */ + free(address); + if (!php_optarg) { + address = strdup("*"); + } else address = strdup(php_optarg); + } break; +#endif + + case 'V': { + sapi_startup(phpdbg); + phpdbg->startup(phpdbg); + printf( + "phpdbg %s (built: %s %s)\nCopyright (c) 2013 %s\nPHP %s, Copyright (c) 1997-2013 The PHP Group\n%s", + PHPDBG_VERSION, + __DATE__, + __TIME__, + PHPDBG_AUTHORS, + PHP_VERSION, + get_zend_version() + ); + sapi_deactivate(TSRMLS_C); + sapi_shutdown(); + return 0; + } break; + } + } + +#ifndef _WIN32 + /* setup remote server if necessary */ + if (!cleaning && + (listen[0] > 0 && listen[1] > 0)) { + if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) { + remote = 0; + exit(0); + } + /* set remote flag to stop service shutting down upon quit */ + remote = 1; + } +#endif + + if (sapi_name) { + phpdbg->name = sapi_name; + } + + phpdbg->ini_defaults = phpdbg_ini_defaults; + phpdbg->phpinfo_as_text = 1; + phpdbg->php_ini_ignore_cwd = 1; + + sapi_startup(phpdbg); + + phpdbg->executable_location = argv[0]; + phpdbg->phpinfo_as_text = 1; + phpdbg->php_ini_ignore = ini_ignore; + phpdbg->php_ini_path_override = ini_override; + + if (ini_entries) { + ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded)); + memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1); + memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2); + } else { + ini_entries = malloc(sizeof(phpdbg_ini_hardcoded)); + memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded)); + } + ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2; + + if (zend_extensions_len) { + zend_ulong zend_extension = 0L; + + while (zend_extension < zend_extensions_len) { + const char *ze = zend_extensions[zend_extension]; + size_t ze_len = strlen(ze); + + ini_entries = realloc( + ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n")))); + memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1)); + ini_entries_len += (sizeof("zend_extension=")-1); + memcpy(&ini_entries[ini_entries_len], ze, ze_len); + ini_entries_len += ze_len; + memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1)); + + free(zend_extensions[zend_extension]); + zend_extension++; + } + + free(zend_extensions); + } + + phpdbg->ini_entries = ini_entries; + + if (phpdbg->startup(phpdbg) == SUCCESS) { + + zend_activate(TSRMLS_C); + + /* do not install sigint handlers for remote consoles */ + /* sending SIGINT then provides a decent way of shutting down the server */ +#ifdef ZEND_SIGNALS +# ifndef _WIN32 + if (listen[0] < 0) { +# endif + zend_try { + zend_signal_activate(TSRMLS_C); + zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); + } zend_end_try(); +# ifndef _WIN32 + } +# endif +#else +# ifndef _WIN32 + if (listen[0] < 0) { +# endif + signal(SIGINT, phpdbg_sigint_handler); +#ifndef _WIN32 + } +#endif +#endif + + PG(modules_activated) = 0; + + /* set flags from command line */ + PHPDBG_G(flags) = flags; + +#ifndef _WIN32 + /* setup io here */ + if (streams[0] && streams[1]) { + PHPDBG_G(flags) |= PHPDBG_IS_REMOTE; + + signal(SIGPIPE, SIG_IGN); + } +#endif + + PHPDBG_G(io)[PHPDBG_STDIN] = stdin; + PHPDBG_G(io)[PHPDBG_STDOUT] = stdout; + PHPDBG_G(io)[PHPDBG_STDERR] = stderr; + + if (exec) { /* set execution context */ + PHPDBG_G(exec) = phpdbg_resolve_path( + exec TSRMLS_CC); + PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec)); + + free(exec); + } + + if (oplog_file) { /* open oplog */ + PHPDBG_G(oplog) = fopen(oplog_file, "w+"); + if (!PHPDBG_G(oplog)) { + phpdbg_error( + "Failed to open oplog %s", oplog_file); + } + free(oplog_file); + } + + /* set default colors */ + phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold") TSRMLS_CC); + phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold") TSRMLS_CC); + phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC); + + /* set default prompt */ + phpdbg_set_prompt(PROMPT TSRMLS_CC); + + zend_try { + zend_activate_modules(TSRMLS_C); + } zend_end_try(); + + if (show_banner) { + /* print blurb */ + phpdbg_welcome((cleaning > 0) TSRMLS_CC); + } + + zend_try { + /* activate globals, they can be overwritten */ + zend_activate_auto_globals(TSRMLS_C); + } zend_end_try(); + + /* initialize from file */ + zend_try { + PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; + phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC); + phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC); + PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; + } zend_catch { + PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + goto phpdbg_out; + } + } zend_end_try(); + + /* step from here, not through init */ + if (step) { + PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; + } + + if (run) { + /* no need to try{}, run does it ... */ + PHPDBG_COMMAND_HANDLER(run)(NULL, NULL TSRMLS_CC); + if (run > 1) { + /* if -r is on the command line more than once just quit */ + goto phpdbg_out; + } + } + +phpdbg_interact: + /* phpdbg main() */ + do { + zend_try { + phpdbg_interactive(TSRMLS_C); + } zend_catch { + if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { + FILE *bp_tmp_fp = fopen(bp_tmp_file, "w"); + phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC); + fclose(bp_tmp_fp); + cleaning = 1; + goto phpdbg_out; + } else { + cleaning = 0; + } +#ifndef _WIN32 + /* remote client disconnected */ + if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { + + /* renegociate connections */ + phpdbg_open_sockets( + address, listen, &server, &socket, streams); + + /* set streams */ + if (streams[0] && streams[1]) { + PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING; + } + + /* this must be forced */ + CG(unclean_shutdown) = 0; + } +#endif + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + goto phpdbg_out; + } + } zend_end_try(); + } while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); + + /* this must be forced */ + CG(unclean_shutdown) = 0; + +phpdbg_out: +#ifndef _WIN32 + if (PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED) { + PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED; + goto phpdbg_interact; + } +#endif + +#ifndef ZTS + /* force cleanup of auto and core globals */ + zend_hash_clean(CG(auto_globals)); + memset( + &core_globals, 0, sizeof(php_core_globals)); +#endif + + if (ini_entries) { + free(ini_entries); + } + + if (ini_override) { + free(ini_override); + } + + if (PG(modules_activated)) { + zend_try { + zend_deactivate_modules(TSRMLS_C); + } zend_end_try(); + } + + zend_deactivate(TSRMLS_C); + + zend_try { + zend_post_deactivate_modules(TSRMLS_C); + } zend_end_try(); + +#ifdef ZEND_SIGNALS + zend_try { + zend_signal_deactivate(TSRMLS_C); + } zend_end_try(); +#endif + + zend_try { + php_module_shutdown(TSRMLS_C); + } zend_end_try(); + + sapi_shutdown(); + } + + if (cleaning || remote) { + goto phpdbg_main; + } + +#ifdef ZTS + /* bugggy */ + /* tsrm_shutdown(); */ +#endif + +#ifndef _WIN32 + if (address) { + free(address); + } +#endif + + if (sapi_name) { + free(sapi_name); + } + + free(bp_tmp_file); + + return 0; +} /* }}} */ diff --git a/phpdbg.h b/phpdbg.h new file mode 100644 index 0000000000..f0a59ce473 --- /dev/null +++ b/phpdbg.h @@ -0,0 +1,187 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_H +#define PHPDBG_H + +#ifdef PHP_WIN32 +# define PHPDBG_API __declspec(dllexport) +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define PHPDBG_API __attribute__ ((visibility("default"))) +#else +# define PHPDBG_API +#endif + +#include "php.h" +#include "php_globals.h" +#include "php_variables.h" +#include "php_getopt.h" +#include "zend_builtin_functions.h" +#include "zend_extensions.h" +#include "zend_modules.h" +#include "zend_globals.h" +#include "zend_ini_scanner.h" +#include "zend_stream.h" +#include "SAPI.h" +#include +#include +#if defined(_WIN32) && !defined(__MINGW32__) +# include +# include "config.w32.h" +# undef strcasecmp +# undef strncasecmp +# define strcasecmp _stricmp +# define strncasecmp _strnicmp +#else +# include "php_config.h" +#endif +#ifndef O_BINARY +# define O_BINARY 0 +#endif +#include "php_main.h" + +#ifdef ZTS +# include "TSRM.h" +#endif + +#ifdef HAVE_LIBREADLINE +# include +# include +#endif + +#include "phpdbg_cmd.h" +#include "phpdbg_utils.h" + +#ifdef ZTS +# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) +#else +# define PHPDBG_G(v) (phpdbg_globals.v) +#endif + +#define PHPDBG_NEXT 2 +#define PHPDBG_UNTIL 3 +#define PHPDBG_FINISH 4 +#define PHPDBG_LEAVE 5 + +/* + BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE +*/ + +/* {{{ tables */ +#define PHPDBG_BREAK_FILE 0 +#define PHPDBG_BREAK_SYM 1 +#define PHPDBG_BREAK_OPLINE 2 +#define PHPDBG_BREAK_METHOD 3 +#define PHPDBG_BREAK_COND 4 +#define PHPDBG_BREAK_OPCODE 5 +#define PHPDBG_BREAK_FUNCTION_OPLINE 6 +#define PHPDBG_BREAK_METHOD_OPLINE 7 +#define PHPDBG_BREAK_FILE_OPLINE 8 +#define PHPDBG_BREAK_MAP 9 +#define PHPDBG_BREAK_TABLES 10 /* }}} */ + +/* {{{ flags */ +#define PHPDBG_HAS_FILE_BP (1<<1) +#define PHPDBG_HAS_SYM_BP (1<<2) +#define PHPDBG_HAS_OPLINE_BP (1<<3) +#define PHPDBG_HAS_METHOD_BP (1<<4) +#define PHPDBG_HAS_COND_BP (1<<5) +#define PHPDBG_HAS_OPCODE_BP (1<<6) +#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1<<7) +#define PHPDBG_HAS_METHOD_OPLINE_BP (1<<8) +#define PHPDBG_HAS_FILE_OPLINE_BP (1<<9) /* }}} */ + +/* + END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE +*/ + +#define PHPDBG_IN_COND_BP (1<<10) +#define PHPDBG_IN_EVAL (1<<11) + +#define PHPDBG_IS_STEPPING (1<<12) +#define PHPDBG_IS_QUIET (1<<13) +#define PHPDBG_IS_QUITTING (1<<14) +#define PHPDBG_IS_COLOURED (1<<15) +#define PHPDBG_IS_CLEANING (1<<16) + +#define PHPDBG_IN_UNTIL (1<<17) +#define PHPDBG_IN_FINISH (1<<18) +#define PHPDBG_IN_LEAVE (1<<19) + +#define PHPDBG_IS_REGISTERED (1<<20) +#define PHPDBG_IS_STEPONEVAL (1<<21) +#define PHPDBG_IS_INITIALIZING (1<<22) +#define PHPDBG_IS_SIGNALED (1<<23) +#define PHPDBG_IS_INTERACTIVE (1<<24) +#define PHPDBG_IS_BP_ENABLED (1<<25) +#define PHPDBG_IS_REMOTE (1<<26) +#define PHPDBG_IS_DISCONNECTED (1<<27) + +#define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL|PHPDBG_IN_FINISH|PHPDBG_IN_LEAVE) +#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP) +#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP|PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP) + +#ifndef _WIN32 +# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED) +#else +# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED) +#endif /* }}} */ + +/* {{{ strings */ +#define PHPDBG_NAME "phpdbg" +#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ +#define PHPDBG_URL "http://phpdbg.com" +#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" +#define PHPDBG_VERSION "0.3.0" +#define PHPDBG_INIT_FILENAME ".phpdbginit" +/* }}} */ + +/* {{{ output descriptors */ +#define PHPDBG_STDIN 0 +#define PHPDBG_STDOUT 1 +#define PHPDBG_STDERR 2 +#define PHPDBG_IO_FDS 3 /* }}} */ + +/* {{{ structs */ +ZEND_BEGIN_MODULE_GLOBALS(phpdbg) + HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */ + HashTable registered; /* registered */ + HashTable seek; /* seek oplines */ + phpdbg_frame_t frame; /* frame */ + + char *exec; /* file to execute */ + size_t exec_len; /* size of exec */ + zend_op_array *ops; /* op_array */ + zval *retval; /* return value */ + int bp_count; /* breakpoint count */ + int vmret; /* return from last opcode handler execution */ + + FILE *oplog; /* opline log */ + FILE *io[PHPDBG_IO_FDS]; /* io */ + + char *prompt[2]; /* prompt */ + const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */ + + phpdbg_command_t *lcmd; /* last command */ + phpdbg_param_t lparam; /* last param */ + + zend_ulong flags; /* phpdbg flags */ +ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ + +#endif /* PHPDBG_H */ diff --git a/phpdbg.init.d b/phpdbg.init.d new file mode 100755 index 0000000000..99a1ab328b --- /dev/null +++ b/phpdbg.init.d @@ -0,0 +1,122 @@ +################################################################ +# File: /etc/init.d/phpdbg # +# Author: krakjoe # +# Purpose: Daemonize phpdbg automatically on boot # +# chkconfig: 2345 07 09 # +# description: Starts, stops and restarts phpdbg daemon # +################################################################ +LOCKFILE=/var/lock/subsys/phpdbg +PIDFILE=/var/run/phpdbg.pid +STDIN=4000 +STDOUT=8000 +################################################################ +# Either set path to phpdbg here or rely on phpdbg in ENV/PATH # +################################################################ +if [ "x${PHPDBG}" == "x" ]; then + PHPDBG=$(which phpdbg 2>/dev/null) +fi +################################################################ +# Options to pass to phpdbg upon boot # +################################################################ +OPTIONS= +LOGFILE=/var/log/phpdbg.log +################################################################ +# STOP EDITING STOP EDITING STOP EDITING STOP EDITING # +################################################################ +. /etc/rc.d/init.d/functions +RETVAL=1 +################################################################ +insanity() +{ + if [ "x${PHPDBG}" == "x" ]; then + PHPDBG=$(which phpdbg 2>>/dev/null) + if [ $? != 0 ]; then + echo -n $"Fatal: cannot find phpdbg ${PHPDBG}" + echo_failure + echo + return 1 + fi + else + if [ ! -x ${PHPDBG} ]; then + echo -n $"Fatal: cannot execute phpdbg ${PHPDBG}" + echo_failure + echo + return 1 + fi + fi + + return 0 +} + +start() +{ + insanity + + if [ $? -eq 1 ]; then + return $RETVAL + fi + + echo -n $"Starting: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} " + nohup ${PHPDBG} -l${STDIN}/${STDOUT} ${OPTIONS} 2>>${LOGFILE} 1>/dev/null $PIDFILE + echo_success + else + echo_failure + fi + echo + [ $RETVAL = 0 ] && touch ${LOCKFILE} + return $RETVAL +} + +stop() +{ + insanity + + if [ $? -eq 1 ]; then + return $RETVAL + fi + + if [ -f ${LOCKFILE} ] && [ -f ${PIDFILE} ] + then + echo -n $"Stopping: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} " + kill -s TERM $(cat $PIDFILE) + RETVAL=$? + if [ $RETVAL -eq 0 ]; then + echo_success + else + echo_failure + fi + echo + [ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE} + else + echo -n $"Error: phpdbg not running" + echo_failure + echo + [ $RETVAL = 1 ] + fi + return $RETVAL +} +################################################################## +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status $PHPDBG + ;; + restart) + $0 stop + $0 start + ;; + *) + echo "usage: $0 start|stop|restart|status" + ;; +esac +################################################################### +exit $RETVAL diff --git a/phpdbg_bp.c b/phpdbg_bp.c new file mode 100644 index 0000000000..69e0fa7086 --- /dev/null +++ b/phpdbg_bp.c @@ -0,0 +1,1661 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "zend_hash.h" +#include "phpdbg.h" +#include "phpdbg_bp.h" +#include "phpdbg_utils.h" +#include "phpdbg_opcode.h" +#include "zend_globals.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +/* {{{ private api functions */ +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array* TSRMLS_DC); +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function* TSRMLS_DC); +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array* TSRMLS_DC); +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t TSRMLS_DC); +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar TSRMLS_DC); +static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC); /* }}} */ + +/* +* Note: +* A break point must always set the correct id and type +* A set breakpoint function must always map new points +*/ +static inline void _phpdbg_break_mapping(int id, HashTable *table TSRMLS_DC) +{ + zend_hash_index_update( + &PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id), (void**) &table, sizeof(void*), NULL); +} + +#define PHPDBG_BREAK_MAPPING(id, table) _phpdbg_break_mapping(id, table TSRMLS_CC) +#define PHPDBG_BREAK_UNMAPPING(id) \ + zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id)) + +#define PHPDBG_BREAK_INIT(b, t) do {\ + b.id = PHPDBG_G(bp_count)++; \ + b.type = t; \ + b.disabled = 0;\ + b.hits = 0; \ +} while(0) + +static void phpdbg_file_breaks_dtor(void *data) /* {{{ */ +{ + phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) data; + + efree((char*)bp->filename); +} /* }}} */ + +static void phpdbg_class_breaks_dtor(void *data) /* {{{ */ +{ + phpdbg_breakmethod_t *bp = (phpdbg_breakmethod_t*) data; + + efree((char*)bp->class_name); + efree((char*)bp->func_name); +} /* }}} */ + +static void phpdbg_opline_class_breaks_dtor(void *data) /* {{{ */ +{ + zend_hash_destroy((HashTable *)data); +} /* }}} */ + +static void phpdbg_opline_breaks_dtor(void *data) /* {{{ */ +{ + phpdbg_breakopline_t *bp = (phpdbg_breakopline_t *) data; + + if (bp->class_name) { + efree((char*)bp->class_name); + } + if (bp->func_name) { + efree((char*)bp->func_name); + } +} /* }}} */ + +PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */ +{ + if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) { + HashPosition position[2]; + HashTable **table = NULL; + + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { + phpdbg_breakbase_t *brake; + + for (zend_hash_internal_pointer_reset_ex((*table), &position[1]); + zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex((*table), &position[1])) { + brake->hits = 0; + } + } + } +} /* }}} */ + +PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ +{ + HashPosition position[2]; + HashTable **table = NULL; + zend_ulong id = 0L; + + if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) { + phpdbg_notice( + "Exporting %d breakpoints", + zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])); + /* this only looks like magic, it isn't */ + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { + phpdbg_breakbase_t *brake; + + zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], NULL, NULL, &id, 0, &position[0]); + + for (zend_hash_internal_pointer_reset_ex((*table), &position[1]); + zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex((*table), &position[1])) { + if (brake->id == id) { + switch (brake->type) { + case PHPDBG_BREAK_FILE: { + fprintf(handle, + "break file %s:%lu\n", + ((phpdbg_breakfile_t*)brake)->filename, + ((phpdbg_breakfile_t*)brake)->line); + } break; + + case PHPDBG_BREAK_SYM: { + fprintf(handle, + "break func %s\n", + ((phpdbg_breaksymbol_t*)brake)->symbol); + } break; + + case PHPDBG_BREAK_METHOD: { + fprintf(handle, + "break method %s::%s\n", + ((phpdbg_breakmethod_t*)brake)->class_name, + ((phpdbg_breakmethod_t*)brake)->func_name); + } break; + + case PHPDBG_BREAK_METHOD_OPLINE: { + fprintf(handle, + "break address %s::%s#%ld\n", + ((phpdbg_breakopline_t*)brake)->class_name, + ((phpdbg_breakopline_t*)brake)->func_name, + ((phpdbg_breakopline_t*)brake)->opline_num); + } break; + + case PHPDBG_BREAK_FUNCTION_OPLINE: { + fprintf(handle, + "break address %s#%ld\n", + ((phpdbg_breakopline_t*)brake)->func_name, + ((phpdbg_breakopline_t*)brake)->opline_num); + } break; + + case PHPDBG_BREAK_FILE_OPLINE: { + fprintf(handle, + "break address %s:%ld\n", + ((phpdbg_breakopline_t*)brake)->class_name, + ((phpdbg_breakopline_t*)brake)->opline_num); + } break; + + case PHPDBG_BREAK_OPCODE: { + fprintf(handle, + "break op %s\n", + ((phpdbg_breakop_t*)brake)->name); + } break; + + case PHPDBG_BREAK_COND: { + phpdbg_breakcond_t *conditional = (phpdbg_breakcond_t*) brake; + + if (conditional->paramed) { + switch (conditional->param.type) { + case STR_PARAM: + fprintf(handle, + "break at %s if %s\n", conditional->param.str, conditional->code); + break; + + case METHOD_PARAM: + fprintf(handle, + "break at %s::%s if %s\n", + conditional->param.method.class, conditional->param.method.name, + conditional->code); + break; + + case FILE_PARAM: + fprintf(handle, + "break at %s:%lu if %s\n", + conditional->param.file.name, conditional->param.file.line, + conditional->code); + break; + + default: { /* do nothing */ } break; + } + } else { + fprintf( + handle, "break on %s\n", conditional->code); + } + } break; + } + } + } + } + } +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRMLS_DC) /* {{{ */ +{ + struct stat sb; + + if (VCWD_STAT(path, &sb) != FAILURE) { + if (sb.st_mode & (S_IFREG|S_IFLNK)) { + HashTable *broken; + phpdbg_breakfile_t new_break; + size_t path_len = strlen(path); + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], + path, path_len, (void**)&broken) == FAILURE) { + HashTable breaks; + + zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0); + + zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], + path, path_len, &breaks, sizeof(HashTable), + (void**)&broken); + } + + if (!zend_hash_index_exists(broken, line_num)) { + PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE); + new_break.filename = estrndup(path, path_len); + new_break.line = line_num; + + zend_hash_index_update( + broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL); + + phpdbg_notice("Breakpoint #%d added at %s:%ld", + new_break.id, new_break.filename, new_break.line); + + PHPDBG_BREAK_MAPPING(new_break.id, broken); + } else { + phpdbg_error("Breakpoint at %s:%ld exists", path, line_num); + } + + } else { + phpdbg_error("Cannot set breakpoint in %s, it is not a regular file", path); + } + } else { + phpdbg_error("Cannot stat %s, it does not exist", path); + } +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len TSRMLS_DC) /* {{{ */ +{ + if (!zend_hash_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) { + phpdbg_breaksymbol_t new_break; + + PHPDBG_G(flags) |= PHPDBG_HAS_SYM_BP; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_SYM); + new_break.symbol = estrndup(name, name_len); + + zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol, + name_len, &new_break, sizeof(phpdbg_breaksymbol_t), NULL); + + phpdbg_notice("Breakpoint #%d added at %s", + new_break.id, new_break.symbol); + + PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); + } else { + phpdbg_notice("Breakpoint exists at %s", name); + } +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char *func_name TSRMLS_DC) /* {{{ */ +{ + HashTable class_breaks, *class_table; + size_t class_len = strlen(class_name); + size_t func_len = strlen(func_name); + char *lcname = zend_str_tolower_dup(func_name, func_len); + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, + class_len, (void**)&class_table) != SUCCESS) { + zend_hash_init(&class_breaks, 8, NULL, phpdbg_class_breaks_dtor, 0); + zend_hash_update( + &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], + class_name, class_len, + (void**)&class_breaks, sizeof(HashTable), (void**)&class_table); + } + + if (!zend_hash_exists(class_table, lcname, func_len)) { + phpdbg_breakmethod_t new_break; + + PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_BP; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_METHOD); + new_break.class_name = estrndup(class_name, class_len); + new_break.class_len = class_len; + new_break.func_name = estrndup(func_name, func_len); + new_break.func_len = func_len; + + zend_hash_update(class_table, lcname, func_len, + &new_break, sizeof(phpdbg_breakmethod_t), NULL); + + phpdbg_notice("Breakpoint #%d added at %s::%s", + new_break.id, class_name, func_name); + + PHPDBG_BREAK_MAPPING(new_break.id, class_table); + } else { + phpdbg_notice("Breakpoint exists at %s::%s", class_name, func_name); + } + + efree(lcname); +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ */ +{ + if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline)) { + phpdbg_breakline_t new_break; + + PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE); + new_break.name = NULL; + new_break.opline = opline; + new_break.base = NULL; + + zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline, + &new_break, sizeof(phpdbg_breakline_t), NULL); + + phpdbg_notice("Breakpoint #%d added at %#lx", + new_break.id, new_break.opline); + PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + } else { + phpdbg_notice("Breakpoint exists at %#lx", opline); + } +} /* }}} */ + +PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakline_t opline_break; + if (op_array->last < brake->opline_num) { + if (brake->class_name == NULL) { + phpdbg_error("There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num); + } else if (brake->func_name == NULL) { + phpdbg_error("There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num); + } else { + phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num); + } + + return FAILURE; + } + + opline_break.disabled = 0; + opline_break.hits = 0; + opline_break.id = brake->id; + opline_break.opline = brake->opline = (zend_ulong)(op_array->opcodes + brake->opline_num); + opline_break.name = NULL; + opline_break.base = brake; + if (op_array->scope) { + opline_break.type = PHPDBG_BREAK_METHOD_OPLINE; + } else if (op_array->function_name) { + opline_break.type = PHPDBG_BREAK_FUNCTION_OPLINE; + } else { + opline_break.type = PHPDBG_BREAK_FILE_OPLINE; + } + + PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP; + + zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline_break.opline, &opline_break, sizeof(phpdbg_breakline_t), NULL); + + return SUCCESS; +} /* }}} */ + +PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC) /* {{{ */ +{ + HashTable *func_table = &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]; + HashTable *oplines_table; + HashPosition position; + phpdbg_breakopline_t *brake; + + if (op_array->scope != NULL && + zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], op_array->scope->name, op_array->scope->name_length, (void **)&func_table) == FAILURE) { + return; + } + + if (op_array->function_name == NULL) { + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], op_array->filename, strlen(op_array->filename), (void **)&oplines_table) == FAILURE) { + return; + } + } else if (zend_hash_find(func_table, op_array->function_name?op_array->function_name:"", op_array->function_name?strlen(op_array->function_name):0, (void **)&oplines_table) == FAILURE) { + return; + } + + for (zend_hash_internal_pointer_reset_ex(oplines_table, &position); + zend_hash_get_current_data_ex(oplines_table, (void**) &brake, &position) == SUCCESS; + zend_hash_move_forward_ex(oplines_table, &position)) { + if (phpdbg_resolve_op_array_break(brake, op_array TSRMLS_CC) == SUCCESS) { + phpdbg_breakline_t *opline_break; + + zend_hash_internal_pointer_end(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + zend_hash_get_current_data(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void **)&opline_break); + + phpdbg_notice("Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)", + brake->id, + brake->class_name?brake->class_name:"", + brake->class_name&&brake->func_name?"::":"", + brake->func_name?brake->func_name:"", + brake->opline_num, + brake->opline); + } + } +} /* }}} */ + +PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC) /* {{{ */ +{ + HashTable *func_table = EG(function_table); + zend_function *func; + + if (new_break->func_name == NULL) { + if (EG(current_execute_data) == NULL) { + if (PHPDBG_G(ops) != NULL && !memcmp(PHPDBG_G(ops)->filename, new_break->class_name, new_break->class_len)) { + if (phpdbg_resolve_op_array_break(new_break, PHPDBG_G(ops) TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } else { + return 2; + } + } + return FAILURE; + } else { + zend_execute_data *execute_data = EG(current_execute_data); + do { + if (execute_data->op_array->function_name == NULL && execute_data->op_array->scope == NULL && !memcmp(execute_data->op_array->filename, new_break->class_name, new_break->class_len)) { + if (phpdbg_resolve_op_array_break(new_break, execute_data->op_array TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } else { + return 2; + } + } + } while ((execute_data = execute_data->prev_execute_data) != NULL); + return FAILURE; + } + } + + if (new_break->class_name != NULL) { + zend_class_entry **ce; + if (zend_hash_find(EG(class_table), zend_str_tolower_dup(new_break->class_name, new_break->class_len), new_break->class_len + 1, (void **)&ce) == FAILURE) { + return FAILURE; + } + func_table = &(*ce)->function_table; + } + + if (zend_hash_find(func_table, zend_str_tolower_dup(new_break->func_name, new_break->func_len), new_break->func_len + 1, (void **)&func) == FAILURE) { + if (new_break->class_name != NULL && new_break->func_name != NULL) { + phpdbg_error("Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name); + return 2; + } + return FAILURE; + } + + if (func->type != ZEND_USER_FUNCTION) { + if (new_break->class_name == NULL) { + phpdbg_error("%s is not an user defined function, no oplines exist", new_break->func_name); + } else { + phpdbg_error("%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name); + } + return 2; + } + + if (phpdbg_resolve_op_array_break(new_break, &func->op_array TSRMLS_CC) == FAILURE) { + return 2; + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakopline_t new_break; + HashTable class_breaks, *class_table; + HashTable method_breaks, *method_table; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_METHOD_OPLINE); + new_break.func_len = strlen(method); + new_break.func_name = estrndup(method, new_break.func_len); + new_break.class_len = strlen(class); + new_break.class_name = estrndup(class, new_break.class_len); + new_break.opline_num = opline; + new_break.opline = 0; + + switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { + case FAILURE: + phpdbg_notice("Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); + break; + + case SUCCESS: + phpdbg_notice("Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); + break; + + case 2: + return; + } + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len, (void **)&class_table) == FAILURE) { + zend_hash_init(&class_breaks, 8, NULL, phpdbg_opline_class_breaks_dtor, 0); + zend_hash_update( + &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], + new_break.class_name, + new_break.class_len, + (void **)&class_breaks, sizeof(HashTable), (void **)&class_table); + } + + if (zend_hash_find(class_table, new_break.func_name, new_break.func_len, (void **)&method_table) == FAILURE) { + zend_hash_init(&method_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0); + zend_hash_update( + class_table, + new_break.func_name, + new_break.func_len, + (void **)&method_breaks, sizeof(HashTable), (void **)&method_table); + } + + if (zend_hash_index_exists(method_table, opline)) { + phpdbg_notice("Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline); + efree((char*)new_break.func_name); + efree((char*)new_break.class_name); + PHPDBG_G(bp_count)--; + return; + } + + PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_OPLINE_BP; + + PHPDBG_BREAK_MAPPING(new_break.id, method_table); + + zend_hash_index_update(method_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); +} + +PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakopline_t new_break; + HashTable func_breaks, *func_table; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FUNCTION_OPLINE); + new_break.func_len = strlen(function); + new_break.func_name = estrndup(function, new_break.func_len); + new_break.class_len = 0; + new_break.class_name = NULL; + new_break.opline_num = opline; + new_break.opline = 0; + + switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { + case FAILURE: + phpdbg_notice("Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline); + break; + + case SUCCESS: + phpdbg_notice("Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline); + break; + + case 2: + return; + } + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len, (void **)&func_table) == FAILURE) { + zend_hash_init(&func_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0); + zend_hash_update( + &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], + new_break.func_name, + new_break.func_len, + (void **)&func_breaks, sizeof(HashTable), (void **)&func_table); + } + + if (zend_hash_index_exists(func_table, opline)) { + phpdbg_notice("Breakpoint already exists for %s#%ld", new_break.func_name, opline); + efree((char*)new_break.func_name); + PHPDBG_G(bp_count)--; + return; + } + + PHPDBG_BREAK_MAPPING(new_break.id, func_table); + + PHPDBG_G(flags) |= PHPDBG_HAS_FUNCTION_OPLINE_BP; + + zend_hash_index_update(func_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); +} + +PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakopline_t new_break; + HashTable file_breaks, *file_table; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE_OPLINE); + new_break.func_len = 0; + new_break.func_name = NULL; + new_break.class_len = strlen(file); + new_break.class_name = estrndup(file, new_break.class_len); + new_break.opline_num = opline; + new_break.opline = 0; + + switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { + case FAILURE: + phpdbg_notice("Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline); + break; + + case SUCCESS: + phpdbg_notice("Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline); + break; + + case 2: + return; + } + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], new_break.class_name, new_break.class_len, (void **)&file_table) == FAILURE) { + zend_hash_init(&file_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0); + zend_hash_update( + &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], + new_break.class_name, + new_break.class_len, + (void **)&file_breaks, sizeof(HashTable), (void **)&file_table); + } + + if (zend_hash_index_exists(file_table, opline)) { + phpdbg_notice("Breakpoint already exists for %s:%ld", new_break.class_name, opline); + efree((char*)new_break.class_name); + PHPDBG_G(bp_count)--; + return; + } + + PHPDBG_BREAK_MAPPING(new_break.id, file_table); + + PHPDBG_G(flags) |= PHPDBG_HAS_FILE_OPLINE_BP; + + zend_hash_index_update(file_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); +} + +PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakop_t new_break; + zend_ulong hash = zend_hash_func(name, name_len); + + if (zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash)) { + phpdbg_notice( + "Breakpoint exists for %s", name); + return; + } + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPCODE); + new_break.hash = hash; + new_break.name = estrndup(name, name_len); + + zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash, + &new_break, sizeof(phpdbg_breakop_t), NULL); + + PHPDBG_G(flags) |= PHPDBG_HAS_OPCODE_BP; + + phpdbg_notice("Breakpoint #%d added at %s", new_break.id, name); + PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]); +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */ +{ + if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline)) { + phpdbg_breakline_t new_break; + + PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE); + new_break.opline = (zend_ulong) opline; + + zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], + (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t), NULL); + + phpdbg_notice("Breakpoint #%d added at %#lx", + new_break.id, new_break.opline); + PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + } +} /* }}} */ + +static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, const phpdbg_param_t *param, const char *expr, size_t expr_len, zend_ulong hash TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakcond_t new_break; + zend_uint cops = CG(compiler_options); + zval pv; + + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_COND); + new_break.hash = hash; + + if (param) { + new_break.paramed = 1; + phpdbg_copy_param( + param, &new_break.param TSRMLS_CC); + } else { + new_break.paramed = 0; + } + + cops = CG(compiler_options); + + CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL; + + new_break.code = estrndup(expr, expr_len); + new_break.code_len = expr_len; + + Z_STRLEN(pv) = expr_len + sizeof("return ;") - 1; + Z_STRVAL(pv) = emalloc(Z_STRLEN(pv) + 1); + memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1); + memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, expr, expr_len); + Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';'; + Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0'; + Z_TYPE(pv) = IS_STRING; + + new_break.ops = zend_compile_string( + &pv, "Conditional Breakpoint Code" TSRMLS_CC); + + zval_dtor(&pv); + + if (new_break.ops) { + zend_hash_index_update( + &PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash, &new_break, + sizeof(phpdbg_breakcond_t), (void**)&brake); + + phpdbg_notice("Conditional breakpoint #%d added %s/%p", + brake->id, brake->code, brake->ops); + + PHPDBG_G(flags) |= PHPDBG_HAS_COND_BP; + PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_COND]); + } else { + phpdbg_error( + "Failed to compile code for expression %s", expr); + efree((char*)new_break.code); + PHPDBG_G(bp_count)--; + } + CG(compiler_options) = cops; +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_expression(const char *expr, size_t expr_len TSRMLS_DC) /* {{{ */ +{ + zend_ulong expr_hash = zend_inline_hash_func(expr, expr_len); + phpdbg_breakcond_t new_break; + + if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], expr_hash)) { + phpdbg_create_conditional_break( + &new_break, NULL, expr, expr_len, expr_hash TSRMLS_CC); + } else { + phpdbg_notice("Conditional break %s exists", expr); + } +} /* }}} */ + +PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +{ + if (input->argc > 3 && phpdbg_argv_is(2, "if")) { + phpdbg_breakcond_t new_break; + phpdbg_param_t new_param; + + zend_ulong expr_hash = 0L; + size_t expr_len; + const char *join = strstr(input->string, "if"); + const char *expr = (join) + sizeof("if"); + + expr_len = strlen(expr); + expr = phpdbg_trim(expr, expr_len, &expr_len); + expr_hash = zend_inline_hash_func(expr, expr_len); + + { + /* get a clean parameter from input string */ + size_t sparam_len = 0L; + char *sparam = input->string; + + sparam[ + strstr(input->string, " ") - input->string] = 0; + sparam_len = strlen(sparam); + + switch (phpdbg_parse_param(sparam, sparam_len, &new_param TSRMLS_CC)) { + case EMPTY_PARAM: + case NUMERIC_PARAM: + phpdbg_clear_param( + &new_param TSRMLS_CC); + goto usage; + + default: { /* do nothing */ } break; + } + + expr_hash += phpdbg_hash_param(&new_param TSRMLS_CC); + } + + if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], expr_hash)) { + phpdbg_create_conditional_break( + &new_break, &new_param, expr, expr_len, expr_hash TSRMLS_CC); + } else { + phpdbg_notice( + "Conditional break %s exists at the specified location", expr); + } + + phpdbg_clear_param(&new_param TSRMLS_CC); + } else { +usage: + phpdbg_error("usage: break at if "); + } +} /* }}} */ + +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_array TSRMLS_DC) /* {{{ */ +{ + HashTable *breaks; + phpdbg_breakbase_t *brake; + size_t name_len = strlen(op_array->filename); + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename, + name_len, (void**)&breaks) == FAILURE) { + return NULL; + } + + if (zend_hash_index_find(breaks, (*EG(opline_ptr))->lineno, (void**)&brake) == SUCCESS) { + return brake; + } + + return NULL; +} /* }}} */ + +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *fbc TSRMLS_DC) /* {{{ */ +{ + const char *fname; + zend_op_array *ops; + phpdbg_breakbase_t *brake; + + if (fbc->type != ZEND_USER_FUNCTION) { + return NULL; + } + + ops = (zend_op_array*)fbc; + + if (ops->scope) { + /* find method breaks here */ + return phpdbg_find_breakpoint_method(ops TSRMLS_CC); + } + + fname = ops->function_name; + + if (!fname) { + fname = "main"; + } + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname, strlen(fname), (void**)&brake) == SUCCESS) { + return brake; + } + + return NULL; +} /* }}} */ + +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array *ops TSRMLS_DC) /* {{{ */ +{ + HashTable *class_table; + phpdbg_breakbase_t *brake; + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name, + ops->scope->name_length, (void**)&class_table) == SUCCESS) { + char *lcname = zend_str_tolower_dup(ops->function_name, strlen(ops->function_name)); + size_t lcname_len = strlen(lcname); + + if (zend_hash_find( + class_table, + lcname, + lcname_len, (void**)&brake) == SUCCESS) { + efree(lcname); + return brake; + } + + efree(lcname); + } + + return NULL; +} /* }}} */ + +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakline_t *brake; + + if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], + (zend_ulong) opline, (void**)&brake) == SUCCESS) { + return (brake->base?(phpdbg_breakbase_t *)brake->base:(phpdbg_breakbase_t *)brake); + } + + return NULL; +} /* }}} */ + +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakbase_t *brake; + const char *opname = phpdbg_decode_opcode(opcode); + + if (memcmp(opname, PHPDBG_STRL("UNKNOWN")) == 0) { + return NULL; + } + + if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], + zend_hash_func(opname, strlen(opname)), (void**)&brake) == SUCCESS) { + return brake; + } + return NULL; +} /* }}} */ + +static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ +{ + zend_function *function = (zend_function*) execute_data->function_state.function; + + switch (param->type) { + case NUMERIC_FUNCTION_PARAM: + case STR_PARAM: { + /* function breakpoint */ + + if (function->type != ZEND_USER_FUNCTION) { + return 0; + } + + { + const char *str = NULL; + size_t len = 0L; + zend_op_array *ops = (zend_op_array*)function; + str = ops->function_name ? ops->function_name : "main"; + len = strlen(str); + + if (len == param->len && memcmp(param->str, str, len) == SUCCESS) { + return param->type == STR_PARAM || execute_data->opline - ops->opcodes == param->num; + } + } + } break; + + case FILE_PARAM: { + if (param->file.line == zend_get_executed_lineno(TSRMLS_C)) { + const char *str = zend_get_executed_filename(TSRMLS_C); + size_t lengths[2] = {strlen(param->file.name), strlen(str)}; + + if (lengths[0] == lengths[1]) { + return (memcmp( + param->file.name, str, lengths[0]) == SUCCESS); + } + } + } break; + + case NUMERIC_METHOD_PARAM: + case METHOD_PARAM: { + if (function->type != ZEND_USER_FUNCTION) { + return 0; + } + + { + zend_op_array *ops = (zend_op_array*) function; + + if (ops->scope) { + size_t lengths[2] = {strlen(param->method.class), ops->scope->name_length}; + if (lengths[0] == lengths[1] && memcmp(param->method.class, ops->scope->name, lengths[0]) == SUCCESS) { + lengths[0] = strlen(param->method.name); + lengths[1] = strlen(ops->function_name); + + if (lengths[0] == lengths[1] && memcmp(param->method.name, ops->function_name, lengths[0]) == SUCCESS) { + return param->type == METHOD_PARAM || (execute_data->opline - ops->opcodes) == param->num; + } + } + } + } + } break; + + case ADDR_PARAM: { + return ((zend_ulong)(phpdbg_opline_ptr_t)execute_data->opline == param->addr); + } break; + + default: { + /* do nothing */ + } break; + } + return 0; +} /* }}} */ + +static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakcond_t *bp; + HashPosition position; + int breakpoint = FAILURE; + + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void*)&bp, &position) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { + zval *retval = NULL; + int orig_interactive = CG(interactive); + zval **orig_retval = EG(return_value_ptr_ptr); + zend_op_array *orig_ops = EG(active_op_array); + zend_op **orig_opline = EG(opline_ptr); + + if (((phpdbg_breakbase_t*)bp)->disabled) { + continue; + } + + if (bp->paramed) { + if (!phpdbg_find_breakpoint_param(&bp->param, execute_data TSRMLS_CC)) { + continue; + } + } + + ALLOC_INIT_ZVAL(retval); + + EG(return_value_ptr_ptr) = &retval; + EG(active_op_array) = bp->ops; + EG(no_extensions) = 1; + + if (!EG(active_symbol_table)) { + zend_rebuild_symbol_table(TSRMLS_C); + } + + CG(interactive) = 0; + + zend_try { + PHPDBG_G(flags) |= PHPDBG_IN_COND_BP; + zend_execute(EG(active_op_array) TSRMLS_CC); +#if PHP_VERSION_ID >= 50700 + if (zend_is_true(retval TSRMLS_CC)) { +#else + if (zend_is_true(retval)) { +#endif + breakpoint = SUCCESS; + } + } zend_catch { + CG(interactive) = orig_interactive; + + EG(no_extensions)=1; + EG(return_value_ptr_ptr) = orig_retval; + EG(active_op_array) = orig_ops; + EG(opline_ptr) = orig_opline; + PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP; + } zend_end_try(); + + CG(interactive) = orig_interactive; + + EG(no_extensions)=1; + EG(return_value_ptr_ptr) = orig_retval; + EG(active_op_array) = orig_ops; + EG(opline_ptr) = orig_opline; + PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP; + + if (breakpoint == SUCCESS) { + break; + } + } + + return (breakpoint == SUCCESS) ? ((phpdbg_breakbase_t*)bp) : NULL; +} /* }}} */ + +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data* execute_data TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakbase_t *base = NULL; + + if (!(PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED)) { + return NULL; + } + + /* conditions cannot be executed by eval()'d code */ + if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL) && + (PHPDBG_G(flags) & PHPDBG_HAS_COND_BP) && + (base = phpdbg_find_conditional_breakpoint(execute_data TSRMLS_CC))) { + goto result; + } + + if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP) && + (base = phpdbg_find_breakpoint_file(execute_data->op_array TSRMLS_CC))) { + goto result; + } + + if (PHPDBG_G(flags) & (PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_SYM_BP)) { + /* check we are at the beginning of the stack */ + if (execute_data->opline == EG(active_op_array)->opcodes) { + if ((base = phpdbg_find_breakpoint_symbol( + execute_data->function_state.function TSRMLS_CC))) { + goto result; + } + } + } + + if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP) && + (base = phpdbg_find_breakpoint_opline(execute_data->opline TSRMLS_CC))) { + goto result; + } + + if ((PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) && + (base = phpdbg_find_breakpoint_opcode(execute_data->opline->opcode TSRMLS_CC))) { + goto result; + } + + return NULL; + +result: + /* we return nothing for disable breakpoints */ + if (base->disabled) { + return NULL; + } + + return base; +} /* }}} */ + +PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ +{ + HashTable **table; + HashPosition position; + phpdbg_breakbase_t *brake; + + if ((brake = phpdbg_find_breakbase_ex(num, &table, &position TSRMLS_CC))) { + char *key; + zend_uint klen; + zend_ulong idx; + int type = brake->type; + char *name = NULL; + size_t name_len = 0L; + + switch (type) { + case PHPDBG_BREAK_FILE: + case PHPDBG_BREAK_METHOD: + if (zend_hash_num_elements((*table)) == 1) { + name = estrdup(brake->name); + name_len = strlen(name); + if (zend_hash_num_elements(&PHPDBG_G(bp)[type]) == 1) { + PHPDBG_G(flags) &= ~(1<<(brake->type+1)); + } + } + break; + + default: { + if (zend_hash_num_elements((*table)) == 1) { + PHPDBG_G(flags) &= ~(1<<(brake->type+1)); + } + } + } + + switch (type) { + case PHPDBG_BREAK_FILE_OPLINE: + case PHPDBG_BREAK_FUNCTION_OPLINE: + case PHPDBG_BREAK_METHOD_OPLINE: + if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]) == 1) { + PHPDBG_G(flags) &= PHPDBG_HAS_OPLINE_BP; + } + zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], ((phpdbg_breakopline_t*)brake)->opline); + } + + switch (zend_hash_get_current_key_ex( + (*table), &key, &klen, &idx, 0, &position)) { + + case HASH_KEY_IS_STRING: + zend_hash_del((*table), key, klen); + break; + + default: + zend_hash_index_del((*table), idx); + } + + switch (type) { + case PHPDBG_BREAK_FILE: + case PHPDBG_BREAK_METHOD: + if (name) { + zend_hash_del(&PHPDBG_G(bp)[type], name, name_len); + efree(name); + } + break; + } + + phpdbg_notice("Deleted breakpoint #%ld", num); + PHPDBG_BREAK_UNMAPPING(num); + } else { + phpdbg_error("Failed to find breakpoint #%ld", num); + } +} /* }}} */ + +PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D) /* {{{ */ +{ + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]); + + PHPDBG_G(flags) &= ~PHPDBG_BP_MASK; + + PHPDBG_G(bp_count) = 0; +} /* }}} */ + +PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t *brake, zend_bool output TSRMLS_DC) /* {{{ */ +{ + brake->hits++; + + if (output) { + phpdbg_print_breakpoint(brake TSRMLS_CC); + } +} /* }}} */ + +PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* {{{ */ +{ + if (!brake) + goto unknown; + + switch (brake->type) { + case PHPDBG_BREAK_FILE: { + phpdbg_notice("Breakpoint #%d at %s:%ld, hits: %lu", + ((phpdbg_breakfile_t*)brake)->id, + ((phpdbg_breakfile_t*)brake)->filename, + ((phpdbg_breakfile_t*)brake)->line, + ((phpdbg_breakfile_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_SYM: { + phpdbg_notice("Breakpoint #%d in %s() at %s:%u, hits: %lu", + ((phpdbg_breaksymbol_t*)brake)->id, + ((phpdbg_breaksymbol_t*)brake)->symbol, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakfile_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_OPLINE: { + phpdbg_notice("Breakpoint #%d in %#lx at %s:%u, hits: %lu", + ((phpdbg_breakline_t*)brake)->id, + ((phpdbg_breakline_t*)brake)->opline, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakline_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_METHOD_OPLINE: { + phpdbg_notice("Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu", + ((phpdbg_breakopline_t*)brake)->id, + ((phpdbg_breakopline_t*)brake)->class_name, + ((phpdbg_breakopline_t*)brake)->func_name, + ((phpdbg_breakopline_t*)brake)->opline_num, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakopline_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_FUNCTION_OPLINE: { + phpdbg_notice("Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu", + ((phpdbg_breakopline_t*)brake)->id, + ((phpdbg_breakopline_t*)brake)->func_name, + ((phpdbg_breakopline_t*)brake)->opline_num, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakopline_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_FILE_OPLINE: { + phpdbg_notice("Breakpoint #%d in %s:%lu at %s:%u, hits: %lu", + ((phpdbg_breakopline_t*)brake)->id, + ((phpdbg_breakopline_t*)brake)->class_name, + ((phpdbg_breakopline_t*)brake)->opline_num, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakopline_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_OPCODE: { + phpdbg_notice("Breakpoint #%d in %s at %s:%u, hits: %lu", + ((phpdbg_breakop_t*)brake)->id, + ((phpdbg_breakop_t*)brake)->name, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakop_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_METHOD: { + phpdbg_notice("Breakpoint #%d in %s::%s() at %s:%u, hits: %lu", + ((phpdbg_breakmethod_t*)brake)->id, + ((phpdbg_breakmethod_t*)brake)->class_name, + ((phpdbg_breakmethod_t*)brake)->func_name, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakmethod_t*)brake)->hits); + } break; + + case PHPDBG_BREAK_COND: { + if (((phpdbg_breakcond_t*)brake)->paramed) { + char *param; + phpdbg_notice("Conditional breakpoint #%d: at %s if %s %s:%u, hits: %lu", + ((phpdbg_breakcond_t*)brake)->id, + phpdbg_param_tostring(&((phpdbg_breakcond_t*)brake)->param, ¶m TSRMLS_CC), + ((phpdbg_breakcond_t*)brake)->code, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakcond_t*)brake)->hits); + if (param) + free(param); + } else { + phpdbg_notice("Conditional breakpoint #%d: on %s == true %s:%u, hits: %lu", + ((phpdbg_breakcond_t*)brake)->id, + ((phpdbg_breakcond_t*)brake)->code, + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C), + ((phpdbg_breakcond_t*)brake)->hits); + } + + } break; + + default: { +unknown: + phpdbg_notice("Unknown breakpoint at %s:%u", + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C)); + } + } +} /* }}} */ + +PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC); + + if (brake) { + brake->disabled = 0; + } +} /* }}} */ + +PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */ +{ + phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC); + + if (brake) { + brake->disabled = 1; + } +} /* }}} */ + +PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D) /* {{{ */ +{ + PHPDBG_G(flags) |= PHPDBG_IS_BP_ENABLED; +} /* }}} */ + +PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D) { /* {{{ */ + PHPDBG_G(flags) &= ~PHPDBG_IS_BP_ENABLED; +} /* }}} */ + +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC) /* {{{ */ +{ + HashTable **table; + HashPosition position; + + return phpdbg_find_breakbase_ex(id, &table, &position TSRMLS_CC); +} /* }}} */ + +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC) /* {{{ */ +{ + if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id, (void**)table) == SUCCESS) { + phpdbg_breakbase_t *brake; + + for (zend_hash_internal_pointer_reset_ex((**table), position); + zend_hash_get_current_data_ex((**table), (void**)&brake, position) == SUCCESS; + zend_hash_move_forward_ex((**table), position)) { + + if (brake->id == id) { + return brake; + } + } + } + return NULL; +} /* }}} */ + +PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ +{ + switch (type) { + case PHPDBG_BREAK_SYM: if ((PHPDBG_G(flags) & PHPDBG_HAS_SYM_BP)) { + HashPosition position; + phpdbg_breaksymbol_t *brake; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("Function Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], (void**) &brake, &position) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position)) { + phpdbg_writeln("#%d\t\t%s%s", + brake->id, brake->symbol, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } break; + + case PHPDBG_BREAK_METHOD: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_BP)) { + HashPosition position[2]; + HashTable *class_table; + char *class_name = NULL; + zend_uint class_len = 0; + zend_ulong class_idx = 0L; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("Method Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], (void**) &class_table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0])) { + + if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], + &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { + phpdbg_breakmethod_t *brake; + + for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]); + zend_hash_get_current_data_ex(class_table, (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex(class_table, &position[1])) { + phpdbg_writeln("#%d\t\t%s::%s%s", + brake->id, brake->class_name, brake->func_name, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } + + } + } break; + + case PHPDBG_BREAK_FILE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP)) { + HashPosition position[2]; + HashTable *points; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("File Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], (void**) &points, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0])) { + phpdbg_breakfile_t *brake; + + for (zend_hash_internal_pointer_reset_ex(points, &position[1]); + zend_hash_get_current_data_ex(points, (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex(points, &position[1])) { + phpdbg_writeln("#%d\t\t%s:%lu%s", + brake->id, brake->filename, brake->line, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } + + } break; + + case PHPDBG_BREAK_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)) { + HashPosition position; + phpdbg_breakline_t *brake; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("Opline Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void**) &brake, &position) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position)) { + switch (brake->type) { + case PHPDBG_BREAK_METHOD_OPLINE: + case PHPDBG_BREAK_FUNCTION_OPLINE: + case PHPDBG_BREAK_FILE_OPLINE: + phpdbg_writeln("#%d\t\t%#lx\t\t(%s breakpoint)%s", brake->id, brake->opline, + brake->type == PHPDBG_BREAK_METHOD_OPLINE?"method": + brake->type == PHPDBG_BREAK_FUNCTION_OPLINE?"function": + brake->type == PHPDBG_BREAK_FILE_OPLINE?"file": + "--- error ---", + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + break; + + default: + phpdbg_writeln("#%d\t\t%#lx", brake->id, brake->opline); + break; + } + } + } break; + + case PHPDBG_BREAK_METHOD_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_OPLINE_BP)) { + HashPosition position[3]; + HashTable *class_table, *method_table; + char *class_name = NULL, *method_name = NULL; + zend_uint class_len = 0, method_len = 0; + zend_ulong class_idx = 0L, method_idx = 0L; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("Method opline Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], (void**) &class_table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0])) { + + if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], + &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { + + for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]); + zend_hash_get_current_data_ex(class_table, (void**) &method_table, &position[1]) == SUCCESS; + zend_hash_move_forward_ex(class_table, &position[1])) { + + if (zend_hash_get_current_key_ex(class_table, + &method_name, &method_len, &method_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { + + phpdbg_breakopline_t *brake; + + for (zend_hash_internal_pointer_reset_ex(method_table, &position[2]); + zend_hash_get_current_data_ex(method_table, (void**)&brake, &position[2]) == SUCCESS; + zend_hash_move_forward_ex(method_table, &position[2])) { + phpdbg_writeln("#%d\t\t%s::%s opline %ld%s", + brake->id, brake->class_name, brake->func_name, brake->opline_num, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } + } + } + + } + } break; + + case PHPDBG_BREAK_FUNCTION_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FUNCTION_OPLINE_BP)) { + HashPosition position[2]; + HashTable *function_table; + char *function_name = NULL; + zend_uint function_len = 0; + zend_ulong function_idx = 0L; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("Function opline Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], (void**) &function_table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0])) { + + if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], + &function_name, &function_len, &function_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { + + phpdbg_breakopline_t *brake; + + for (zend_hash_internal_pointer_reset_ex(function_table, &position[1]); + zend_hash_get_current_data_ex(function_table, (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex(function_table, &position[1])) { + phpdbg_writeln("#%d\t\t%s opline %ld%s", + brake->id, brake->func_name, brake->opline_num, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } + + } + } break; + + case PHPDBG_BREAK_FILE_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_OPLINE_BP)) { + HashPosition position[2]; + HashTable *file_table; + char *file_name = NULL; + zend_uint file_len = 0; + zend_ulong file_idx = 0L; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("File opline Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], (void**) &file_table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0])) { + + if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], + &file_name, &file_len, &file_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { + + phpdbg_breakopline_t *brake; + + for (zend_hash_internal_pointer_reset_ex(file_table, &position[1]); + zend_hash_get_current_data_ex(file_table, (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex(file_table, &position[1])) { + phpdbg_writeln("#%d\t\t%s opline %ld%s", + brake->id, brake->class_name, brake->opline_num, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } + } + } break; + + case PHPDBG_BREAK_COND: if ((PHPDBG_G(flags) & PHPDBG_HAS_COND_BP)) { + HashPosition position; + phpdbg_breakcond_t *brake; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("Conditional Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void**) &brake, &position) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { + if (brake->paramed) { + switch (brake->param.type) { + case STR_PARAM: + phpdbg_writeln("#%d\t\tat %s if %s%s", + brake->id, + brake->param.str, + brake->code, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + break; + + case NUMERIC_FUNCTION_PARAM: + phpdbg_writeln("#%d\t\tat %s#%ld if %s%s", + brake->id, + brake->param.str, + brake->param.num, + brake->code, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + break; + + case METHOD_PARAM: + phpdbg_writeln("#%d\t\tat %s::%s if %s%s", + brake->id, + brake->param.method.class, + brake->param.method.name, + brake->code, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + break; + + case NUMERIC_METHOD_PARAM: + phpdbg_writeln("#%d\t\tat %s::%s#%ld if %s%s", + brake->id, + brake->param.method.class, + brake->param.method.name, + brake->param.num, + brake->code, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + break; + + case FILE_PARAM: + phpdbg_writeln("#%d\t\tat %s:%lu if %s%s", + brake->id, + brake->param.file.name, + brake->param.file.line, + brake->code, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + break; + + case ADDR_PARAM: + phpdbg_writeln("#%d\t\tat #%lx if %s%s", + brake->id, + brake->param.addr, + brake->code, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + break; + + default: + phpdbg_error("Invalid parameter type for conditional breakpoint"); + return; + } + } else { + phpdbg_writeln("#%d\t\tif %s%s", + brake->id, brake->code, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } + } break; + + case PHPDBG_BREAK_OPCODE: if (PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) { + HashPosition position; + phpdbg_breakop_t *brake; + + phpdbg_writeln(SEPARATE); + phpdbg_writeln("Opcode Breakpoints:"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], (void**) &brake, &position) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position)) { + phpdbg_writeln("#%d\t\t%s%s", + brake->id, brake->name, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } break; + } +} /* }}} */ diff --git a/phpdbg_bp.h b/phpdbg_bp.h new file mode 100644 index 0000000000..ed1b413f6d --- /dev/null +++ b/phpdbg_bp.h @@ -0,0 +1,146 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_BP_H +#define PHPDBG_BP_H + +/* {{{ */ +typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */ + +/* {{{ breakpoint base structure */ +#define phpdbg_breakbase(name) \ + int id; \ + zend_uchar type; \ + zend_ulong hits; \ + zend_bool disabled; \ + const char *name /* }}} */ + +/* {{{ breakpoint base */ +typedef struct _phpdbg_breakbase_t { + phpdbg_breakbase(name); +} phpdbg_breakbase_t; /* }}} */ + +/** + * Breakpoint file-based representation + */ +typedef struct _phpdbg_breakfile_t { + phpdbg_breakbase(filename); + long line; +} phpdbg_breakfile_t; + +/** + * Breakpoint symbol-based representation + */ +typedef struct _phpdbg_breaksymbol_t { + phpdbg_breakbase(symbol); +} phpdbg_breaksymbol_t; + +/** + * Breakpoint method based representation + */ +typedef struct _phpdbg_breakmethod_t { + phpdbg_breakbase(class_name); + size_t class_len; + const char *func_name; + size_t func_len; +} phpdbg_breakmethod_t; + +/** + * Breakpoint opline num based representation + */ +typedef struct _phpdbg_breakopline_t { + phpdbg_breakbase(func_name); + size_t func_len; + const char *class_name; + size_t class_len; + zend_ulong opline_num; + zend_ulong opline; +} phpdbg_breakopline_t; + +/** + * Breakpoint opline based representation + */ +typedef struct _phpdbg_breakline_t { + phpdbg_breakbase(name); + zend_ulong opline; + phpdbg_breakopline_t *base; +} phpdbg_breakline_t; + +/** + * Breakpoint opcode based representation + */ +typedef struct _phpdbg_breakop_t { + phpdbg_breakbase(name); + zend_ulong hash; +} phpdbg_breakop_t; + +/** + * Breakpoint condition based representation + */ +typedef struct _phpdbg_breakcond_t { + phpdbg_breakbase(code); + size_t code_len; + zend_bool paramed; + phpdbg_param_t param; + zend_ulong hash; + zend_op_array *ops; +} phpdbg_breakcond_t; + +/* {{{ Opline breaks API */ +PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC); +PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC); +PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */ + +/* {{{ Breakpoint Creation API */ +PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_expression(const char* expression, size_t expression_len TSRMLS_DC); +PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC); /* }}} */ + +/* {{{ Breakpoint Detection API */ +PHPDBG_API phpdbg_breakbase_t* phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC); /* }}} */ + +/* {{{ Misc Breakpoint API */ +PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t* brake, zend_bool output TSRMLS_DC); +PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC); +PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t* brake TSRMLS_DC); +PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D); +PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D); +PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC); +PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D); +PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC); +PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC); +PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D); /* }}} */ + +/* {{{ Breakbase API */ +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC); +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC); /* }}} */ + +/* {{{ Breakpoint Exportation API */ +PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */ + +#endif /* PHPDBG_BP_H */ diff --git a/phpdbg_break.c b/phpdbg_break.c new file mode 100644 index 0000000000..1423b960e6 --- /dev/null +++ b/phpdbg_break.c @@ -0,0 +1,155 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg.h" +#include "phpdbg_print.h" +#include "phpdbg_utils.h" +#include "phpdbg_opcode.h" +#include "phpdbg_break.h" +#include "phpdbg_bp.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_BREAK(file) /* {{{ */ +{ + switch (param->type) { + case FILE_PARAM: + phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(method) /* {{{ */ +{ + switch (param->type) { + case METHOD_PARAM: + phpdbg_set_breakpoint_method(param->method.class, param->method.name TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(address) /* {{{ */ +{ + switch (param->type) { + case ADDR_PARAM: + phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC); + break; + + case NUMERIC_METHOD_PARAM: + phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num TSRMLS_CC); + break; + + case NUMERIC_FUNCTION_PARAM: + phpdbg_set_breakpoint_function_opline(param->str, param->num TSRMLS_CC); + break; + + case FILE_PARAM: + phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(on) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: + phpdbg_set_breakpoint_expression(param->str, param->len TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(at) /* {{{ */ +{ + phpdbg_set_breakpoint_at(param, input TSRMLS_CC); + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(lineno) /* {{{ */ +{ + switch (param->type) { + case NUMERIC_PARAM: { + if (PHPDBG_G(exec)) { + phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC); + } else { + phpdbg_error("Execution context not set!"); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(func) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: + phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(op) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: + phpdbg_set_breakpoint_opcode(param->str, param->len TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_BREAK(del) /* {{{ */ +{ + switch (param->type) { + case NUMERIC_PARAM: { + phpdbg_delete_breakpoint(param->num TSRMLS_CC); + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ diff --git a/phpdbg_break.h b/phpdbg_break.h new file mode 100644 index 0000000000..04abeb6805 --- /dev/null +++ b/phpdbg_break.h @@ -0,0 +1,58 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_BREAK_H +#define PHPDBG_BREAK_H + +#include "TSRM.h" +#include "phpdbg_cmd.h" + +#define PHPDBG_BREAK(name) PHPDBG_COMMAND(break_##name) + +/** + * Printer Forward Declarations + */ +PHPDBG_BREAK(file); +PHPDBG_BREAK(func); +PHPDBG_BREAK(method); +PHPDBG_BREAK(address); +PHPDBG_BREAK(at); +PHPDBG_BREAK(op); +PHPDBG_BREAK(on); +PHPDBG_BREAK(lineno); +PHPDBG_BREAK(del); + +/** + * Commands + */ +static const phpdbg_command_t phpdbg_break_commands[] = { + PHPDBG_COMMAND_D_EX(file, "specify breakpoint by file:line", 'F', break_file, NULL, 1), + PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, 1), + PHPDBG_COMMAND_D_EX(method, "specify breakpoint by class::method", 'm', break_method, NULL, 1), + PHPDBG_COMMAND_D_EX(address, "specify breakpoint by address", 'a', break_address, NULL, 1), + PHPDBG_COMMAND_D_EX(op, "specify breakpoint by opcode", 'O', break_op, NULL, 1), + PHPDBG_COMMAND_D_EX(on, "specify breakpoint by condition", 'o', break_on, NULL, 1), + PHPDBG_COMMAND_D_EX(at, "specify breakpoint by location and condition", 'A', break_at, NULL, 1), + PHPDBG_COMMAND_D_EX(lineno, "specify breakpoint by line of currently executing file", 'l', break_lineno, NULL, 1), + PHPDBG_COMMAND_D_EX(del, "delete breakpoint by identifier number", 'd', break_del, NULL, 1), + PHPDBG_END_COMMAND +}; + +#endif /* PHPDBG_BREAK_H */ diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c new file mode 100644 index 0000000000..9f052d6f6f --- /dev/null +++ b/phpdbg_cmd.c @@ -0,0 +1,669 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg.h" +#include "phpdbg_cmd.h" +#include "phpdbg_utils.h" +#include "phpdbg_set.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: + return "empty"; + case ADDR_PARAM: + return "address"; + case NUMERIC_PARAM: + return "numeric"; + case METHOD_PARAM: + return "method"; + case NUMERIC_FUNCTION_PARAM: + return "function opline"; + case NUMERIC_METHOD_PARAM: + return "method opline"; + case FILE_PARAM: + return "file or file opline"; + case STR_PARAM: + return "string"; + default: /* this is bad */ + return "unknown"; + } +} + +PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char *str, size_t len, phpdbg_param_t *param TSRMLS_DC) /* {{{ */ +{ + char *class_name, *func_name; + + if (len == 0) { + param->type = EMPTY_PARAM; + goto parsed; + } + + if (phpdbg_is_addr(str)) { + param->addr = strtoul(str, 0, 16); + param->type = ADDR_PARAM; + goto parsed; + + } else if (phpdbg_is_numeric(str)) { + param->num = strtol(str, NULL, 0); + param->type = NUMERIC_PARAM; + goto parsed; + + } else if (phpdbg_is_class_method(str, len+1, &class_name, &func_name)) { + param->method.class = class_name; + param->method.name = func_name; + param->type = METHOD_PARAM; + goto parsed; + } else { + char *line_pos = strrchr(str, ':'); + + if (line_pos && phpdbg_is_numeric(line_pos+1)) { + if (strchr(str, ':') == line_pos) { + char path[MAXPATHLEN]; + + memcpy(path, str, line_pos - str); + path[line_pos - str] = 0; + *line_pos = 0; + param->file.name = phpdbg_resolve_path(path TSRMLS_CC); + param->file.line = strtol(line_pos+1, NULL, 0); + param->type = FILE_PARAM; + + goto parsed; + } + } + + line_pos = strrchr(str, '#'); + + if (line_pos && phpdbg_is_numeric(line_pos+1)) { + if (strchr(str, '#') == line_pos) { + param->num = strtol(line_pos + 1, NULL, 0); + + if (phpdbg_is_class_method(str, line_pos - str, &class_name, &func_name)) { + param->method.class = class_name; + param->method.name = func_name; + param->type = NUMERIC_METHOD_PARAM; + } else { + param->len = line_pos - str; + param->str = estrndup(str, param->len); + param->type = NUMERIC_FUNCTION_PARAM; + } + + goto parsed; + } + } + } + + param->str = estrndup(str, len); + param->len = len; + param->type = STR_PARAM; + +parsed: + phpdbg_debug("phpdbg_parse_param(\"%s\", %lu): %s", + str, len, phpdbg_get_param_type(param TSRMLS_CC)); + return param->type; +} /* }}} */ + +PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param TSRMLS_DC) /* {{{ */ +{ + if (param) { + switch (param->type) { + case FILE_PARAM: + efree(param->file.name); + break; + case METHOD_PARAM: + efree(param->method.class); + efree(param->method.name); + break; + case STR_PARAM: + efree(param->str); + break; + default: + break; + } + } + +} /* }}} */ + +PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: + asprintf(pointer, + "%s", param->str); + break; + + case ADDR_PARAM: + asprintf(pointer, + "%#lx", param->addr); + break; + + case NUMERIC_PARAM: + asprintf(pointer, + "%li", + param->num); + break; + + case METHOD_PARAM: + asprintf(pointer, + "%s::%s", + param->method.class, + param->method.name); + break; + + case FILE_PARAM: + if (param->num) { + asprintf(pointer, + "%s:%lu#%lu", + param->file.name, + param->file.line, + param->num); + } else { + asprintf(pointer, + "%s:%lu", + param->file.name, + param->file.line); + } + break; + + case NUMERIC_FUNCTION_PARAM: + asprintf(pointer, + "%s#%lu", param->str, param->num); + break; + + case NUMERIC_METHOD_PARAM: + asprintf(pointer, + "%s::%s#%lu", + param->method.class, + param->method.name, + param->num); + break; + + default: + asprintf(pointer, + "%s", "unknown"); + } + + return *pointer; +} /* }}} */ + +PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest TSRMLS_DC) /* {{{ */ +{ + switch ((dest->type = src->type)) { + case STR_PARAM: + dest->str = estrndup(src->str, src->len); + dest->len = src->len; + break; + + case ADDR_PARAM: + dest->addr = src->addr; + break; + + case NUMERIC_PARAM: + dest->num = src->num; + break; + + case METHOD_PARAM: + dest->method.class = estrdup(src->method.class); + dest->method.name = estrdup(src->method.name); + break; + + case FILE_PARAM: + dest->file.name = estrdup(src->file.name); + dest->file.line = src->file.line; + if (src->num) + dest->num = src->num; + break; + + case NUMERIC_FUNCTION_PARAM: + dest->str = estrndup(src->str, src->len); + dest->num = src->num; + dest->len = src->len; + break; + + case NUMERIC_METHOD_PARAM: + dest->method.class = estrdup(src->method.class); + dest->method.name = estrdup(src->method.name); + dest->num = src->num; + break; + + case EMPTY_PARAM: { /* do nothing */ } break; + } +} /* }}} */ + +PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */ +{ + zend_ulong hash = param->type; + + switch (param->type) { + case STR_PARAM: + hash += zend_inline_hash_func(param->str, param->len); + break; + + case METHOD_PARAM: + hash += zend_inline_hash_func(param->method.class, strlen(param->method.class)); + hash += zend_inline_hash_func(param->method.name, strlen(param->method.name)); + break; + + case FILE_PARAM: + hash += zend_inline_hash_func(param->file.name, strlen(param->file.name)); + hash += param->file.line; + if (param->num) + hash += param->num; + break; + + case ADDR_PARAM: + hash += param->addr; + break; + + case NUMERIC_PARAM: + hash += param->num; + break; + + case NUMERIC_FUNCTION_PARAM: + hash += zend_inline_hash_func(param->str, param->len); + hash += param->num; + break; + + case NUMERIC_METHOD_PARAM: + hash += zend_inline_hash_func(param->method.class, strlen(param->method.class)); + hash += zend_inline_hash_func(param->method.name, strlen(param->method.name)); + if (param->num) + hash+= param->num; + break; + + case EMPTY_PARAM: { /* do nothing */ } break; + } + + return hash; +} /* }}} */ + +PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_param_t *r TSRMLS_DC) /* {{{ */ +{ + if (l && r) { + if (l->type == r->type) { + switch (l->type) { + + case NUMERIC_FUNCTION_PARAM: + if (l->num != r->num) { + break; + } + /* break intentionally omitted */ + + case STR_PARAM: + return (l->len == r->len) && + (memcmp(l->str, r->str, l->len) == SUCCESS); + + case NUMERIC_PARAM: + return (l->num == r->num); + + case ADDR_PARAM: + return (l->addr == r->addr); + + case FILE_PARAM: { + if (l->file.line == r->file.line) { + size_t lengths[2] = { + strlen(l->file.name), strlen(r->file.name)}; + + if (lengths[0] == lengths[1]) { + if ((!l->num && !r->num) || (l->num == r->num)) { + return (memcmp( + l->file.name, r->file.name, lengths[0]) == SUCCESS); + } + } + } + } break; + + case NUMERIC_METHOD_PARAM: + if (l->num != r->num) { + break; + } + /* break intentionally omitted */ + + case METHOD_PARAM: { + size_t lengths[2] = { + strlen(l->method.class), strlen(r->method.class)}; + if (lengths[0] == lengths[1]) { + if (memcmp(l->method.class, r->method.class, lengths[0]) == SUCCESS) { + lengths[0] = strlen(l->method.name); + lengths[1] = strlen(r->method.name); + + if (lengths[0] == lengths[1]) { + return (memcmp( + l->method.name, r->method.name, lengths[0]) == SUCCESS); + } + } + } + } break; + + case EMPTY_PARAM: + return 1; + } + } + } + return 0; +} /* }}} */ + +PHPDBG_API phpdbg_input_t **phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC) /* {{{ */ +{ + char *p; + char b[PHPDBG_MAX_CMD]; + int l=0; + enum states { + IN_BETWEEN, + IN_WORD, + IN_STRING + } state = IN_BETWEEN; + phpdbg_input_t **argv = NULL; + + argv = (phpdbg_input_t**) emalloc(sizeof(phpdbg_input_t*)); + (*argc) = 0; + +#define RESET_STATE() do { \ + phpdbg_input_t *arg = emalloc(sizeof(phpdbg_input_t)); \ + if (arg) { \ + b[l]=0; \ + arg->length = l; \ + arg->string = estrndup(b, arg->length); \ + arg->argv = NULL; \ + arg->argc = 0; \ + argv = (phpdbg_input_t**) erealloc(argv, sizeof(phpdbg_input_t*) * ((*argc)+1)); \ + argv[(*argc)++] = arg; \ + l = 0; \ + } \ + state = IN_BETWEEN; \ +} while (0) + + for (p = buffer; *p != '\0'; p++) { + int c = (unsigned char) *p; + switch (state) { + case IN_BETWEEN: + if (isspace(c)) { + continue; + } + if (c == '"') { + state = IN_STRING; + continue; + } + state = IN_WORD; + b[l++]=c; + continue; + + case IN_STRING: + if (c == '"') { + if (buffer[(p - buffer)-1] == '\\') { + b[l-1]=c; + continue; + } + RESET_STATE(); + } else { + b[l++]=c; + } + continue; + + case IN_WORD: + if (isspace(c)) { + RESET_STATE(); + } else { + b[l++]=c; + } + continue; + } + } + + switch (state) { + case IN_WORD: { + RESET_STATE(); + } break; + + case IN_STRING: + phpdbg_error( + "Malformed command line (unclosed quote) @ %ld: %s!", + (p - buffer)-1, &buffer[(p - buffer)-1]); + break; + + case IN_BETWEEN: + break; + } + + if ((*argc) == 0) { + /* not needed */ + efree(argv); + + /* to be sure */ + return NULL; + } + + return argv; +} /* }}} */ + +PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ +{ + phpdbg_input_t *buffer = NULL; + char *cmd = NULL; + + if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && + (buffered == NULL)) { + fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); + } + + if (buffered == NULL) { +#ifndef HAVE_LIBREADLINE + char buf[PHPDBG_MAX_CMD]; + if ((!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && !phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) || + !fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { + /* the user has gone away */ + phpdbg_error("Failed to read console!"); + PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); + zend_bailout(); + return NULL; + } + + cmd = buf; +#else + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { + char buf[PHPDBG_MAX_CMD]; + if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { + cmd = buf; + } else cmd = NULL; + } else cmd = readline(phpdbg_get_prompt(TSRMLS_C)); + + if (!cmd) { + /* the user has gone away */ + phpdbg_error("Failed to read console!"); + PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); + zend_bailout(); + return NULL; + } + + if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { + add_history(cmd); + } +#endif + } else cmd = buffered; + + /* allocate and sanitize buffer */ + buffer = (phpdbg_input_t*) ecalloc(1, sizeof(phpdbg_input_t)); + if (!buffer) { + return NULL; + } + + buffer->string = phpdbg_trim(cmd, strlen(cmd), &buffer->length); + + /* store constant pointer to start of buffer */ + buffer->start = (char* const*) buffer->string; + + buffer->argv = phpdbg_read_argv( + buffer->string, &buffer->argc TSRMLS_CC); + +#ifdef PHPDBG_DEBUG + if (buffer->argc) { + int arg = 0; + + while (arg < buffer->argc) { + phpdbg_debug( + "argv %d=%s", arg, buffer->argv[arg]->string); + arg++; + } + } +#endif + +#ifdef HAVE_LIBREADLINE + if (!buffered && cmd && + !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { + free(cmd); + } +#endif + + return buffer; + } + + return NULL; +} /* }}} */ + +PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC) /* {{{ */ +{ + if (argv) { + if (argc) { + int arg; + for (arg=0; argstring) { + efree((*input)->string); + } + + phpdbg_destroy_argv( + (*input)->argv, (*input)->argc TSRMLS_CC); + + efree(*input); + } +} /* }}} */ + +PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +{ + int rc = FAILURE; + + if (input->argc > 0) { + while (command && command->name && command->handler) { + if (((command->name_len == input->argv[0]->length) && + (memcmp(command->name, input->argv[0]->string, command->name_len) == SUCCESS)) || + (command->alias && + (input->argv[0]->length == 1) && + (command->alias == *input->argv[0]->string))) { + + phpdbg_param_t param; + + param.type = EMPTY_PARAM; + + if (input->argc > 1) { + if (command->subs) { + phpdbg_input_t sub = *input; + + sub.string += input->argv[0]->length; + sub.length -= input->argv[0]->length; + + sub.string = phpdbg_trim( + sub.string, sub.length, &sub.length); + + sub.argc--; + sub.argv++; + + phpdbg_debug( + "trying sub commands in \"%s\" for \"%s\" with %d arguments", + command->name, sub.argv[0]->string, sub.argc-1); + + if (phpdbg_do_cmd(command->subs, &sub TSRMLS_CC) == SUCCESS) { + efree(sub.string); + return SUCCESS; + } + + efree(sub.string); + } + + /* no sub command found */ + { + char *store = input->string; + + input->string += input->argv[0]->length; + input->length -= input->argv[0]->length; + + input->string = phpdbg_trim( + input->string, input->length, &input->length); + + efree(store); + } + + /* pass parameter on */ + phpdbg_parse_param( + input->string, + input->length, + ¶m TSRMLS_CC); + } + + phpdbg_debug( + "found command %s for %s with %d arguments", + command->name, input->argv[0]->string, input->argc-1); + { + int arg; + for (arg=1; argargc; arg++) { + phpdbg_debug( + "\t#%d: [%s=%zu]", + arg, + input->argv[arg]->string, + input->argv[arg]->length); + } + } + + rc = command->handler(¶m, input TSRMLS_CC); + + /* only set last command when it is worth it! */ + if ((rc != FAILURE) && + !(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) { + PHPDBG_G(lcmd) = (phpdbg_command_t*) command; + phpdbg_clear_param( + &PHPDBG_G(lparam) TSRMLS_CC); + PHPDBG_G(lparam) = param; + } + break; + } + command++; + } + } else { + /* this should NEVER happen */ + phpdbg_error( + "No function executed!!"); + } + + return rc; +} /* }}} */ + diff --git a/phpdbg_cmd.h b/phpdbg_cmd.h new file mode 100644 index 0000000000..e779fd4b55 --- /dev/null +++ b/phpdbg_cmd.h @@ -0,0 +1,169 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_CMD_H +#define PHPDBG_CMD_H + +#include "TSRM.h" + +typedef struct _phpdbg_command_t phpdbg_command_t; + +/* {{{ Command and Parameter */ +enum { + NO_ARG = 0, + REQUIRED_ARG, + OPTIONAL_ARG +}; + +typedef enum { + EMPTY_PARAM = 0, + ADDR_PARAM, + FILE_PARAM, + METHOD_PARAM, + STR_PARAM, + NUMERIC_PARAM, + NUMERIC_FUNCTION_PARAM, + NUMERIC_METHOD_PARAM +} phpdbg_param_type; + +typedef struct _phpdbg_input_t phpdbg_input_t; + +struct _phpdbg_input_t { + char * const *start; + char *string; + size_t length; + phpdbg_input_t **argv; + int argc; +}; + +typedef struct _phpdbg_param { + phpdbg_param_type type; + long num; + zend_ulong addr; + struct { + char *name; + long line; + } file; + struct { + char *class; + char *name; + } method; + char *str; + size_t len; +} phpdbg_param_t; + +typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t*, const phpdbg_input_t* TSRMLS_DC); + +struct _phpdbg_command_t { + const char *name; /* Command name */ + size_t name_len; /* Command name length */ + const char *tip; /* Menu tip */ + size_t tip_len; /* Menu tip length */ + char alias; /* Alias */ + phpdbg_command_handler_t handler; /* Command handler */ + const phpdbg_command_t *subs; /* Sub Commands */ + char arg_type; /* Accept args? */ +}; +/* }}} */ + +/* {{{ misc */ +#define PHPDBG_STRL(s) s, sizeof(s)-1 +#define PHPDBG_MAX_CMD 500 +#define PHPDBG_FRAME(v) (PHPDBG_G(frame).v) +#define PHPDBG_EX(v) (EG(current_execute_data)->v) + +typedef struct { + int num; + zend_execute_data *execute_data; +} phpdbg_frame_t; +/* }}} */ + + + +/* +* Workflow: +* 1) read input +* input takes the line from console, creates argc/argv +* 2) parse parameters into suitable types based on arg_type +* takes input from 1) and arg_type and creates parameters +* 3) do command +* executes commands +* 4) destroy parameters +* cleans up what was allocated by creation of parameters +* 5) destroy input +* cleans up what was allocated by creation of input +*/ + +/* +* Input Management +*/ +PHPDBG_API phpdbg_input_t* phpdbg_read_input(char *buffered TSRMLS_DC); +PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t** TSRMLS_DC); + +/* +* Argument Management +*/ +PHPDBG_API phpdbg_input_t** phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC); +PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC); +#define phpdbg_argv_is(n, s) \ + (memcmp(input->argv[n]->string, s, input->argv[n]->length) == SUCCESS) + +/* +* Parameter Management +*/ +PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char*, size_t, phpdbg_param_t* TSRMLS_DC); +PHPDBG_API void phpdbg_clear_param(phpdbg_param_t* TSRMLS_DC); +PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t*, phpdbg_param_t* TSRMLS_DC); +PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *, const phpdbg_param_t * TSRMLS_DC); +PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t * TSRMLS_DC); +PHPDBG_API const char* phpdbg_get_param_type(const phpdbg_param_t* TSRMLS_DC); +PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC); + +/* +* Command Executor +*/ +PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t*, phpdbg_input_t* TSRMLS_DC); + +/** + * Command Declarators + */ +#define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name + +#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, has_args) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, has_args} + +#define PHPDBG_COMMAND_D(name, tip, alias, children, has_args) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, has_args} + +#define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC) + +#define PHPDBG_COMMAND_ARGS param, input TSRMLS_CC + +#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0'} + +/* +* Default Switch Case +*/ +#define phpdbg_default_switch_case() \ + default: \ + phpdbg_error("Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \ + break + +#endif /* PHPDBG_CMD_H */ diff --git a/phpdbg_frame.c b/phpdbg_frame.c new file mode 100644 index 0000000000..24aff59dd9 --- /dev/null +++ b/phpdbg_frame.c @@ -0,0 +1,206 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "phpdbg.h" +#include "phpdbg_utils.h" +#include "phpdbg_frame.h" +#include "phpdbg_list.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +void phpdbg_restore_frame(TSRMLS_D) /* {{{ */ +{ + if (PHPDBG_FRAME(num) == 0) { + return; + } + + PHPDBG_FRAME(num) = 0; + + /* move things back */ + EG(current_execute_data) = PHPDBG_FRAME(execute_data); + + EG(opline_ptr) = &PHPDBG_EX(opline); + EG(active_op_array) = PHPDBG_EX(op_array); + EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value); + EG(active_symbol_table) = PHPDBG_EX(symbol_table); + EG(This) = PHPDBG_EX(current_this); + EG(scope) = PHPDBG_EX(current_scope); + EG(called_scope) = PHPDBG_EX(current_called_scope); +} /* }}} */ + +void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ +{ + zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data); + int i = 0; + + if (PHPDBG_FRAME(num) == frame) { + phpdbg_notice("Already in frame #%d", frame); + return; + } + + while (execute_data) { + if (i++ == frame) { + break; + } + + do { + execute_data = execute_data->prev_execute_data; + } while (execute_data && execute_data->opline == NULL); + } + + if (execute_data == NULL) { + phpdbg_error("No frame #%d", frame); + return; + } + + phpdbg_restore_frame(TSRMLS_C); + + if (frame > 0) { + PHPDBG_FRAME(num) = frame; + + /* backup things and jump back */ + PHPDBG_FRAME(execute_data) = EG(current_execute_data); + EG(current_execute_data) = execute_data; + + EG(opline_ptr) = &PHPDBG_EX(opline); + EG(active_op_array) = PHPDBG_EX(op_array); + PHPDBG_FRAME(execute_data)->original_return_value = EG(return_value_ptr_ptr); + EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value); + EG(active_symbol_table) = PHPDBG_EX(symbol_table); + EG(This) = PHPDBG_EX(current_this); + EG(scope) = PHPDBG_EX(current_scope); + EG(called_scope) = PHPDBG_EX(current_called_scope); + } + + phpdbg_notice("Switched to frame #%d", frame); + phpdbg_list_file( + zend_get_executed_filename(TSRMLS_C), + 3, + zend_get_executed_lineno(TSRMLS_C)-1, + zend_get_executed_lineno(TSRMLS_C) + TSRMLS_CC + ); +} /* }}} */ + +static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */ +{ + zval **funcname, **class, **type, **args, **argstmp; + char is_class; + + zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"), + (void **)&funcname); + + if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp), + "object", sizeof("object"), (void **)&class)) == FAILURE) { + is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"), + (void **)&class); + } else { + zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class), + (zend_uint *)&Z_STRLEN_PP(class) TSRMLS_CC); + } + + if (is_class == SUCCESS) { + zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type); + } + + phpdbg_write("%s%s%s(", + is_class == FAILURE?"":Z_STRVAL_PP(class), + is_class == FAILURE?"":Z_STRVAL_PP(type), + Z_STRVAL_PP(funcname) + ); + + if (zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"), + (void **)&args) == SUCCESS) { + HashPosition iterator; + const zend_function *func = phpdbg_get_function( + Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC); + const zend_arg_info *arginfo = func ? func->common.arg_info : NULL; + int j = 0, m = func ? func->common.num_args : 0; + zend_bool is_variadic = 0; + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator); + while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args), + (void **) &argstmp, &iterator) == SUCCESS) { + if (j) { + phpdbg_write(", "); + } + if (m && j < m) { +#if PHP_VERSION_ID >= 50600 + is_variadic = arginfo[j].is_variadic; +#endif + phpdbg_write("%s=%s", + arginfo[j].name, is_variadic ? "[": ""); + } + ++j; + + zend_print_flat_zval_r(*argstmp TSRMLS_CC); + zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator); + } + if (is_variadic) { + phpdbg_write("]"); + } + } + phpdbg_write(")"); +} + +void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ +{ + zval zbacktrace; + zval **tmp; + zval **file, **line; + HashPosition position; + int i = 1, limit = num; + int user_defined; + + if (limit < 0) { + phpdbg_error("Invalid backtrace size %d", limit); + } + + zend_fetch_debug_backtrace( + &zbacktrace, 0, 0, limit TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position); + zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position); + while (1) { + user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file); + zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line); + zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position); + + if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), + (void**)&tmp, &position) == FAILURE) { + phpdbg_write("frame #0: {main} at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line)); + break; + } + + if (user_defined == SUCCESS) { + phpdbg_write("frame #%d: ", i++); + phpdbg_dump_prototype(tmp TSRMLS_CC); + phpdbg_writeln(" at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line)); + } else { + phpdbg_write(" => "); + phpdbg_dump_prototype(tmp TSRMLS_CC); + phpdbg_writeln(" (internal function)"); + } + } + + phpdbg_writeln(EMPTY); + zval_dtor(&zbacktrace); +} /* }}} */ diff --git a/phpdbg_frame.h b/phpdbg_frame.h new file mode 100644 index 0000000000..fbccd5404f --- /dev/null +++ b/phpdbg_frame.h @@ -0,0 +1,30 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_FRAME_H +#define PHPDBG_FRAME_H + +#include "TSRM.h" + +void phpdbg_restore_frame(TSRMLS_D); +void phpdbg_switch_frame(int TSRMLS_DC); +void phpdbg_dump_backtrace(size_t TSRMLS_DC); + +#endif /* PHPDBG_FRAME_H */ diff --git a/phpdbg_help.c b/phpdbg_help.c new file mode 100644 index 0000000000..edb1265955 --- /dev/null +++ b/phpdbg_help.c @@ -0,0 +1,603 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg.h" +#include "phpdbg_help.h" +#include "phpdbg_print.h" +#include "phpdbg_utils.h" +#include "phpdbg_break.h" +#include "phpdbg_list.h" +#include "phpdbg_info.h" +#include "phpdbg_set.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_HELP(exec) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("\tWill attempt execution, if compilation has not yet taken place, it occurs now"); + phpdbg_writeln("The execution context must be set before execution can take place"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(step) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("You can enable and disable stepping at any phpdbg prompt during execution"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sstepping 1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%ss 1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill enable stepping"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("While stepping is enabled you are presented with a prompt after the execution of each opcode"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(next) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_write("Step back into the vm and execute the next opcode"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%snext", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sn", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: is only useful while executing"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(until) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Step back into the vm, skipping breakpoints until the next source line"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%suntil", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%su", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: is only useful while executing"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(finish) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Step back into the vm, skipping breakpoints until past the end of the current stack"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sfinish", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sF", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: this allows all breakpoints that would otherwise break execution in the current scope to be skipped"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(leave) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Step back into the vm, skipping breakpoints until the current stack is returning"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sleave", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sL", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill cause a break when instructed to leave the current context"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: this allows inspection of the return value before it is returned"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(compile) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Pre-compilation of the execution context provides the opportunity to inspect opcodes before execution"); + phpdbg_writeln("The execution context must be set for compilation to succeed"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%scompile", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sc", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill compile the current execution context, populating class/function/constant/etc tables"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: It is a good idea to clean the environment between each compilation"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(print) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("By default, print will show information about the current execution context"); + phpdbg_writeln("Other printing commands give access to instruction information"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sprint class \\my\\class", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sp c \\my\\class", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the instructions for the methods in \\my\\class"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sprint method \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sp m \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the instructions for \\my\\class::method"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sprint func .getSomething", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sp f .getSomething", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the instructions for ::getSomething in the active scope"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sprint func my_function", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sp f my_function", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the instructions for the global function my_function"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sprint opline", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sp o", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the instruction for the current opline"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sprint exec", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sp e", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the instructions for the execution context"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sprint stack", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sp s", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the instructions for the current stack"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Specific printers loaded are show below:"); + phpdbg_notice("Commands"); + { + const phpdbg_command_t *print_command = phpdbg_print_commands; + + phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); + while (print_command && print_command->name) { + if (print_command->alias) { + phpdbg_writeln("\t[%c]\t%s\t\t%s", print_command->alias, print_command->name, print_command->tip); + } else { + phpdbg_writeln("\t[ ]\t%s\t\t%s", print_command->name, print_command->tip); + } + ++print_command; + } + } + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(run) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Execute the current context inside the phpdbg vm"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%srun", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sr", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill cause execution of the context, if it is set."); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: The execution context must be set, but not necessarily compiled before execution occurs"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(eval) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Access to eval() allows you to change the environment during execution, careful though!!"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%seval $variable", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sE $variable", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print_r($variable) on the console, if it is defined"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%seval $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sE $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill set $variable in the current scope"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: eval() will always show the result; do not prefix the code with \"return\""); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(break) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Setting a breakpoint stops execution at a specific stage"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sbreak [file] test.php:1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb [F] test.php:1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break execution on line 1 of test.php"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak [func] my_function", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb [f] my_function", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break execution on entry to my_function"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak [method] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb [m] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break execution on entry to \\my\\class::method"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak [address] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb [a] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break at the opline with the address provided"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak [address] my_function#1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb [a] my_function#1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break at the opline number 1 of the function my_function"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak [address] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb [a] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break at the opline number 2 of the method \\my\\class::method"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak address test.php:3", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb a test.php:3", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break at the opline number 3 of test.php"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak [lineno] 200", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb [l] 200", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break at line 200 of the currently executing file"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak on ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb on ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break when the condition evaluates to true"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak at phpdbg::isGreat if ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break at every opcode in phpdbg::isGreat when the condition evaluates to true"); + phpdbg_writeln("\t%sbreak at test.php:20 if ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break at every opcode on line 20 of test.php when the condition evaluates to true"); + phpdbg_write("\t"); + phpdbg_notice("The location can be anything accepted by file, func, method, or address break commands"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak op ZEND_ADD", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb O ZEND_ADD", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill break on every occurence of the opcode provided"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%sbreak del 1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sb d 1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill remove the breakpoint with the given identifier"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: An address is only valid for the current compilation"); + phpdbg_writeln(EMPTY); + phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Specific breakers loaded are show below:"); + phpdbg_notice("Commands"); + { + const phpdbg_command_t *break_command = phpdbg_break_commands; + + phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); + while (break_command && break_command->name) { + if (break_command->alias) { + phpdbg_writeln("\t[%c]\t%s\t\t%s", break_command->alias, break_command->name, break_command->tip); + } else { + phpdbg_writeln("\t[ ]\t%s\t\t%s", break_command->name, break_command->tip); + } + ++break_command; + } + } + phpdbg_writeln("Note: Conditional breaks are costly, use them sparingly!"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(clean) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("While debugging you may experience errors because of attempts to redeclare classes, constants or functions"); + phpdbg_writeln("Cleaning the environment cleans these tables, so that files can be recompiled without exiting phpdbg"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(clear) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Clearing breakpoints means you can once again run code without interruption"); + phpdbg_writeln("Note: all breakpoints are lost; be sure debugging is complete before clearing"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(info) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("info commands provide quick access to various types of information about the PHP environment"); + phpdbg_writeln("Specific info commands are show below:"); + phpdbg_notice("Commands"); + { + const phpdbg_command_t *info_command = phpdbg_info_commands; + + phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); + while (info_command && info_command->name) { + if (info_command->alias) { + phpdbg_writeln("\t[%c]\t%s\t\t%s", info_command->alias, info_command->name, info_command->tip); + } else { + phpdbg_writeln("\t[ ]\t%s\t\t%s", info_command->name, info_command->tip); + } + ++info_command; + } + } + + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(quiet) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Setting quietness on will stop the OPLINE output during execution"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%squiet 1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sQ 1", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill silence OPLINE output, while"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%squiet 0", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sQ 0", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill enable OPLINE output again"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: Quietness is disabled automatically while stepping"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(back) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("The backtrace is built with the default debug backtrace functionality"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sback 5", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%st 5", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill limit the number of frames to 5, the default is no limit"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: it is not necessary for an exception to be thrown to show a backtrace"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(frame) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("When viewing a backtrace, it is sometimes useful to jump to a frame in that trace"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sframe 2", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sf 2", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill go to frame 2, temporarily affecting scope and allowing access to the variables in that frame"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: the current frame is restored when execution continues"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(list) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("The list command displays source code for the given argument"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%slist [lines] 2", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sl [l] 2", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print next 2 lines from the current file"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%slist [func] my_function", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sl [f] my_function", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the source of the global function \"my_function\""); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%slist [func] .mine", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sl [f] .mine", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the source of the method \"mine\" from the active scope"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%slist [method] my::method", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sl [m] my::method", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the source of \"my::method\""); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%slist c myClass", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sl c myClass", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill print the source of \"myClass\""); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: before listing functions you must have a populated function table, try compile!!"); + phpdbg_writeln(EMPTY); + phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Specific listers loaded are show below:"); + phpdbg_notice("Commands"); + { + const phpdbg_command_t *list_command = phpdbg_list_commands; + + phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); + while (list_command && list_command->name) { + if (list_command->alias) { + phpdbg_writeln("\t[%c]\t%s\t\t%s", list_command->alias, list_command->name, list_command->tip); + } else { + phpdbg_writeln("\t[ ]\t%s\t\t%s", list_command->name, list_command->tip); + } + ++list_command; + } + } + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(oplog) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Even when quietness is enabled you may wish to save opline logs to a file"); + phpdbg_writeln("Setting a new oplog closes the previously open log"); + phpdbg_writeln("The log includes a high resolution timestamp on each entry"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%soplog /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sO /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill open the file /path/to/my.oplog for writing, creating it if it does not exist"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("\t%soplog 0", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sO 0", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill close the currently open log file, disabling oplog"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: upon failure to open a new oplog, the last oplog is held open"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(set) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Configure how phpdbg looks and behaves with the set command"); + phpdbg_writeln("Specific set commands are show below:"); + phpdbg_notice("Commands"); + { + const phpdbg_command_t *set_command = phpdbg_set_commands; + + phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); + while (set_command && set_command->name) { + if (set_command->alias) { + phpdbg_writeln("\t[%c]\t%s\t\t%s", set_command->alias, set_command->name, set_command->tip); + } else { + phpdbg_writeln("\t[ ]\t%s\t\t%s", set_command->name, set_command->tip); + } + ++set_command; + } + } +#ifndef _WIN32 + phpdbg_notice("Colors"); + { + const phpdbg_color_t *color = phpdbg_get_colors(TSRMLS_C); + + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + phpdbg_writeln("\t%-20s\t\tExample", "Name"); + } else { + phpdbg_writeln("\tName"); + } + + while (color && color->name) { + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + phpdbg_writeln( + "\t%-20s\t\t\033[%smphpdbg rocks :)\033[0m", color->name, color->code); + } else { + phpdbg_writeln("\t%s", color->name); + } + ++color; + } + } + phpdbg_writeln("The for set color can be \"prompt\", \"notice\", or \"error\""); +#endif + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(register) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Register any global function for use as a command in phpdbg console"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sregister scandir", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%sR scandir", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill register the scandir function for use in phpdbg"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: arguments passed as strings, return (if present) print_r'd on console"); + if (zend_hash_num_elements(&PHPDBG_G(registered))) { + HashPosition position; + char *name = NULL; + zend_uint name_len = 0; + + phpdbg_notice("Registered Functions (%d)", zend_hash_num_elements(&PHPDBG_G(registered))); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(registered), &position); + zend_hash_get_current_key_ex(&PHPDBG_G(registered), &name, &name_len, NULL, 1, &position) == HASH_KEY_IS_STRING; + zend_hash_move_forward_ex(&PHPDBG_G(registered), &position)) { + phpdbg_writeln("|-------> %s", name); + efree(name); + } + } + + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(source) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Sourcing a phpdbginit during your debugging session might save some time"); + phpdbg_writeln("The source command can also be used to export breakpoints to a phpdbginit file"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%ssource /my/init", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%s. /my/init", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill execute the phpdbginit file at /my/init"); + phpdbg_writeln("\t%ssource export /my/init", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%s. export /my/init", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill export breakpoints to /my/init in phpdbginit file format"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(shell) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Direct access to shell commands saves having to switch windows/consoles"); + phpdbg_writeln(EMPTY); + phpdbg_notice("Examples"); + phpdbg_writeln("\t%sshell ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\t%s- ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C)); + phpdbg_writeln("\tWill execute ls /usr/src/php-src, displaying the output in the console"); + phpdbg_writeln(EMPTY); + phpdbg_writeln("Note: read only commands please!"); + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ + +PHPDBG_HELP(options) /* {{{ */ +{ + phpdbg_help_header(); + phpdbg_writeln("Below are the command line options supported by phpdbg"); + phpdbg_notice("Command Line Options and Flags"); + phpdbg_writeln(" -c\t-c/my/php.ini\t\tSet php.ini file to load"); + phpdbg_writeln(" -d\t-dmemory_limit=4G\tSet a php.ini directive"); + phpdbg_writeln(" -n\tN/A\t\t\tDisable default php.ini"); + phpdbg_writeln(" -q\tN/A\t\t\tSupress welcome banner"); + phpdbg_writeln(" -e\t-emytest.php\t\tSet execution context"); + phpdbg_writeln(" -v\tN/A\t\t\tEnable oplog output"); + phpdbg_writeln(" -s\tN/A\t\t\tEnable stepping"); + phpdbg_writeln(" -b\tN/A\t\t\tDisable colour"); + phpdbg_writeln(" -i\t-imy.init\t\tSet .phpdbginit file"); + phpdbg_writeln(" -I\tN/A\t\t\tIgnore default .phpdbginit"); + phpdbg_writeln(" -O\t-Omy.oplog\t\tSets oplog output file"); + phpdbg_writeln(" -r\tN/A\t\t\tRun execution context"); + phpdbg_writeln(" -E\tN/A\t\t\tEnable step through eval, careful!"); + phpdbg_writeln(" -S\t-Scli\t\t\tOverride SAPI name, careful!"); +#ifndef _WIN32 + phpdbg_writeln(" -l\t-l4000\t\t\tSetup remote console ports"); + phpdbg_writeln(" -a\t-a192.168.0.3\t\tSetup remote console bind address"); +#endif + phpdbg_writeln(" -V\tN/A\t\t\tVersion number"); + phpdbg_notice("Passing -rr will quit automatically after execution"); +#ifndef _WIN32 + phpdbg_writeln("Remote Console Mode"); + phpdbg_notice("For security, phpdbg will bind only to the loopback interface by default"); + phpdbg_writeln("-a without an argument implies all; phpdbg will bind to all available interfaces."); + phpdbg_writeln("specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2."); + phpdbg_notice("Steps should be taken to secure this service if bound to a public interface/port"); +#endif + phpdbg_help_footer(); + return SUCCESS; +} /* }}} */ diff --git a/phpdbg_help.h b/phpdbg_help.h new file mode 100644 index 0000000000..012a1b49e7 --- /dev/null +++ b/phpdbg_help.h @@ -0,0 +1,92 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_HELP_H +#define PHPDBG_HELP_H + +#include "TSRM.h" +#include "phpdbg.h" +#include "phpdbg_cmd.h" + +#define PHPDBG_HELP(name) PHPDBG_COMMAND(help_##name) + +/** + * Helper Forward Declarations + */ +PHPDBG_HELP(exec); +PHPDBG_HELP(compile); +PHPDBG_HELP(step); +PHPDBG_HELP(next); +PHPDBG_HELP(run); +PHPDBG_HELP(eval); +PHPDBG_HELP(until); +PHPDBG_HELP(finish); +PHPDBG_HELP(leave); +PHPDBG_HELP(print); +PHPDBG_HELP(break); +PHPDBG_HELP(clean); +PHPDBG_HELP(clear); +PHPDBG_HELP(info); +PHPDBG_HELP(back); +PHPDBG_HELP(frame); +PHPDBG_HELP(quiet); +PHPDBG_HELP(list); +PHPDBG_HELP(set); +PHPDBG_HELP(register); +PHPDBG_HELP(options); +PHPDBG_HELP(source); +PHPDBG_HELP(shell); + +/** + * Commands + */ +static const phpdbg_command_t phpdbg_help_commands[] = { + PHPDBG_COMMAND_D_EX(exec, "the execution context should be a valid path", 'e', help_exec, NULL, 0), + PHPDBG_COMMAND_D_EX(compile, "allow inspection of code before execution", 'c', help_compile, NULL, 0), + PHPDBG_COMMAND_D_EX(step, "step through execution to break at every opcode", 's', help_step, NULL, 0), + PHPDBG_COMMAND_D_EX(next, "continue executing while stepping or after breaking", 'n', help_next, NULL, 0), + PHPDBG_COMMAND_D_EX(run, "execute inside the phpdbg vm", 'r', help_run, NULL, 0), + PHPDBG_COMMAND_D_EX(eval, "access to eval() allows affecting the environment", 'E', help_eval, NULL, 0), + PHPDBG_COMMAND_D_EX(until, "continue until the current line is executed", 'u', help_until, NULL, 0), + PHPDBG_COMMAND_D_EX(finish, "continue until the current function has returned", 'F', help_finish, NULL, 0), + PHPDBG_COMMAND_D_EX(leave, "continue until the current function is returning", 'L', help_leave, NULL, 0), + PHPDBG_COMMAND_D_EX(print, "print context information or instructions", 'p', help_print, NULL, 0), + PHPDBG_COMMAND_D_EX(break, "breakpoints allow execution interruption", 'b', help_break, NULL, 0), + PHPDBG_COMMAND_D_EX(clean, "resetting the environment is useful while debugging", 'X', help_clean, NULL, 0), + PHPDBG_COMMAND_D_EX(clear, "reset breakpoints to execute without interruption", 'c', help_clear, NULL, 0), + PHPDBG_COMMAND_D_EX(info, "quick access to useful information on the console", 'i', help_info, NULL, 0), + PHPDBG_COMMAND_D_EX(back, "show debug backtrace information during execution", 't', help_back, NULL, 0), + PHPDBG_COMMAND_D_EX(frame, "switch to a frame in the current stack for inspection", 'f', help_frame, NULL, 0), + PHPDBG_COMMAND_D_EX(quiet, "be quiet during execution", 'Q', help_quiet, NULL, 0), + PHPDBG_COMMAND_D_EX(list, "list code gives you quick access to code", 'l', help_list, NULL, 0), + PHPDBG_COMMAND_D_EX(set, "configure how phpdbg looks and behaves", 'S', help_set, NULL, 0), + PHPDBG_COMMAND_D_EX(register, "register a function for use as a command", 'R', help_register,NULL, 0), + PHPDBG_COMMAND_D_EX(options, "show information about command line options", 'o', help_options, NULL, 0), + PHPDBG_COMMAND_D_EX(source, "load a phpdbginit file at the console", '.', help_source, NULL, 0), + PHPDBG_COMMAND_D_EX(shell, "execute system commands with direct shell access", '-', help_shell, NULL, 0), + PHPDBG_END_COMMAND +}; + +#define phpdbg_help_header() \ + phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); +#define phpdbg_help_footer() \ + phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); + +#endif /* PHPDBG_HELP_H */ diff --git a/phpdbg_info.c b/phpdbg_info.c new file mode 100644 index 0000000000..1744f59215 --- /dev/null +++ b/phpdbg_info.c @@ -0,0 +1,355 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "phpdbg.h" +#include "phpdbg_utils.h" +#include "phpdbg_info.h" +#include "phpdbg_bp.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_INFO(break) /* {{{ */ +{ + phpdbg_print_breakpoints(PHPDBG_BREAK_FILE TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_SYM TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_OPLINE TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_FILE_OPLINE TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_FUNCTION_OPLINE TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD_OPLINE TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_COND TSRMLS_CC); + phpdbg_print_breakpoints(PHPDBG_BREAK_OPCODE TSRMLS_CC); + + return SUCCESS; +} /* }}} */ + +PHPDBG_INFO(files) /* {{{ */ +{ + HashPosition pos; + char *fname; + + phpdbg_notice("Included files: %d", + zend_hash_num_elements(&EG(included_files))); + + zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos); + while (zend_hash_get_current_key_ex(&EG(included_files), &fname, + NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { + phpdbg_writeln("File: %s", fname); + zend_hash_move_forward_ex(&EG(included_files), &pos); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_INFO(error) /* {{{ */ +{ + if (PG(last_error_message)) { + phpdbg_writeln("Last error: %s at %s line %d", + PG(last_error_message), PG(last_error_file), PG(last_error_lineno)); + } else { + phpdbg_notice("No error found!"); + } + return SUCCESS; +} /* }}} */ + +PHPDBG_INFO(vars) /* {{{ */ +{ + HashTable vars; + HashPosition pos; + char *var; + zval **data; + + if (!EG(active_op_array)) { + phpdbg_error("No active op array!"); + return SUCCESS; + } + + if (!EG(active_symbol_table)) { + zend_rebuild_symbol_table(TSRMLS_C); + + if (!EG(active_symbol_table)) { + phpdbg_error("No active symbol table!"); + return SUCCESS; + } + } + + zend_hash_init(&vars, 8, NULL, NULL, 0); + + zend_hash_internal_pointer_reset_ex(EG(active_symbol_table), &pos); + while (zend_hash_get_current_key_ex(EG(active_symbol_table), &var, + NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { + zend_hash_get_current_data_ex(EG(active_symbol_table), (void **)&data, &pos); + if (*var != '_') { + zend_hash_update( + &vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL); + } + zend_hash_move_forward_ex(EG(active_symbol_table), &pos); + } + + { + zend_op_array *ops = EG(active_op_array); + + if (ops->function_name) { + if (ops->scope) { + phpdbg_notice( + "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars)); + } else { + phpdbg_notice( + "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars)); + } + } else { + if (ops->filename) { + phpdbg_notice( + "Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars)); + } else { + phpdbg_notice( + "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars)); + } + } + } + + if (zend_hash_num_elements(&vars)) { + phpdbg_writeln("Address\t\tRefs\tType\t\tVariable"); + for (zend_hash_internal_pointer_reset_ex(&vars, &pos); + zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS; + zend_hash_move_forward_ex(&vars, &pos)) { + char *var; + + zend_hash_get_current_key_ex(&vars, &var, NULL, NULL, 0, &pos); + + if (*data) { + phpdbg_write( + "%p\t%d\t", + *data, + Z_REFCOUNT_PP(data)); + + switch (Z_TYPE_PP(data)) { + case IS_STRING: phpdbg_write("(string)\t"); break; + case IS_LONG: phpdbg_write("(integer)\t"); break; + case IS_DOUBLE: phpdbg_write("(float)\t"); break; + case IS_RESOURCE: phpdbg_write("(resource)\t"); break; + case IS_ARRAY: phpdbg_write("(array)\t"); break; + case IS_OBJECT: phpdbg_write("(object)\t"); break; + case IS_NULL: phpdbg_write("(null)\t"); break; + } + + if (Z_TYPE_PP(data) == IS_RESOURCE) { + int type; + + phpdbg_writeln( + "%s$%s", Z_ISREF_PP(data) ? "&": "", var); + if (zend_list_find(Z_RESVAL_PP(data), &type)) { + phpdbg_write( + "|-------(typeof)------> (%s)", + zend_rsrc_list_get_rsrc_type(type TSRMLS_CC)); + } else { + phpdbg_write( + "|-------(typeof)------> (unknown)"); + } + phpdbg_writeln(EMPTY); + } else if (Z_TYPE_PP(data) == IS_OBJECT) { + phpdbg_writeln( + "%s$%s", Z_ISREF_PP(data) ? "&": "", var); + phpdbg_write( + "|-----(instanceof)----> (%s)", Z_OBJCE_PP(data)->name); + phpdbg_writeln(EMPTY); + } else { + phpdbg_write( + "%s$%s", Z_ISREF_PP(data) ? "&": "", var); + } + } else { + phpdbg_write( + "n/a\tn/a\tn/a\t$%s", var); + } + phpdbg_writeln(EMPTY); + } + } + + zend_hash_destroy(&vars); + + return SUCCESS; +} /* }}} */ + +PHPDBG_INFO(literal) /* {{{ */ +{ + if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) { + zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops); + int literal = 0, count = ops->last_literal-1; + + if (ops->function_name) { + if (ops->scope) { + phpdbg_notice( + "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count); + } else { + phpdbg_notice( + "Literal Constants in %s() (%d)", ops->function_name, count); + } + } else { + if (ops->filename) { + phpdbg_notice( + "Literal Constants in %s (%d)", ops->filename, count); + } else { + phpdbg_notice( + "Literal Constants @ %p (%d)", ops, count); + } + } + + while (literal < ops->last_literal) { + if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) { + phpdbg_write("|-------- C%u -------> [", literal); + zend_print_zval( + &ops->literals[literal].constant, 0); + phpdbg_write("]"); + phpdbg_writeln(EMPTY); + } + literal++; + } + } else { + phpdbg_error("Not executing!"); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_INFO(memory) /* {{{ */ +{ + if (is_zend_mm(TSRMLS_C)) { + phpdbg_notice("Memory Manager Information"); + phpdbg_notice("Current"); + phpdbg_writeln("|-------> Used:\t%.3f kB", + (float) (zend_memory_usage(0 TSRMLS_CC)/1024)); + phpdbg_writeln("|-------> Real:\t%.3f kB", + (float) (zend_memory_usage(1 TSRMLS_CC)/1024)); + phpdbg_notice("Peak"); + phpdbg_writeln("|-------> Used:\t%.3f kB", + (float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024)); + phpdbg_writeln("|-------> Real:\t%.3f kB", + (float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024)); + } else { + phpdbg_error("Memory Manager Disabled!"); + } + return SUCCESS; +} /* }}} */ + +static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */ +{ + phpdbg_write( + "%s %s %s (%d)", + ((*ce)->type == ZEND_USER_CLASS) ? + "User" : "Internal", + ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? + "Interface" : + ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? + "Abstract Class" : + "Class", + (*ce)->name, zend_hash_num_elements(&(*ce)->function_table)); +} /* }}} */ + +PHPDBG_INFO(classes) /* {{{ */ +{ + HashPosition position; + zend_class_entry **ce; + HashTable classes; + + zend_hash_init(&classes, 8, NULL, NULL, 0); + + for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position); + zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS; + zend_hash_move_forward_ex(EG(class_table), &position)) { + + if ((*ce)->type == ZEND_USER_CLASS) { + zend_hash_next_index_insert( + &classes, ce, sizeof(ce), NULL); + } + } + + phpdbg_notice("User Classes (%d)", + zend_hash_num_elements(&classes)); + + for (zend_hash_internal_pointer_reset_ex(&classes, &position); + zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS; + zend_hash_move_forward_ex(&classes, &position)) { + + phpdbg_print_class_name(ce TSRMLS_CC); + phpdbg_writeln(EMPTY); + + if ((*ce)->parent) { + zend_class_entry *pce = (*ce)->parent; + do { + phpdbg_write("|-------- "); + phpdbg_print_class_name(&pce TSRMLS_CC); + phpdbg_writeln(EMPTY); + } while ((pce = pce->parent)); + } + + if ((*ce)->info.user.filename) { + phpdbg_writeln( + "|---- in %s on line %u", + (*ce)->info.user.filename, + (*ce)->info.user.line_start); + } else { + phpdbg_writeln("|---- no source code"); + } + phpdbg_writeln(EMPTY); + } + + zend_hash_destroy(&classes); + + return SUCCESS; +} /* }}} */ + +PHPDBG_INFO(funcs) /* {{{ */ +{ + HashPosition position; + zend_function *zf, **pzf; + HashTable functions; + + zend_hash_init(&functions, 8, NULL, NULL, 0); + + for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position); + zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS; + zend_hash_move_forward_ex(EG(function_table), &position)) { + + if (zf->type == ZEND_USER_FUNCTION) { + zend_hash_next_index_insert( + &functions, (void**) &zf, sizeof(zend_function), NULL); + } + } + + phpdbg_notice("User Functions (%d)", + zend_hash_num_elements(&functions)); + + for (zend_hash_internal_pointer_reset_ex(&functions, &position); + zend_hash_get_current_data_ex(&functions, (void**)&pzf, &position) == SUCCESS; + zend_hash_move_forward_ex(&functions, &position)) { + zend_op_array *op_array = &((*pzf)->op_array); + + phpdbg_writeln( + "|-------- %s in %s on line %d", + op_array->function_name ? op_array->function_name : "{main}", + op_array->filename ? op_array->filename : "(no source code)", + op_array->line_start); + } + + zend_hash_destroy(&functions); + + return SUCCESS; +} /* }}} */ diff --git a/phpdbg_info.h b/phpdbg_info.h new file mode 100644 index 0000000000..5d53812370 --- /dev/null +++ b/phpdbg_info.h @@ -0,0 +1,49 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_INFO_H +#define PHPDBG_INFO_H + +#include "phpdbg_cmd.h" + +#define PHPDBG_INFO(name) PHPDBG_COMMAND(info_##name) + +PHPDBG_INFO(files); +PHPDBG_INFO(break); +PHPDBG_INFO(classes); +PHPDBG_INFO(funcs); +PHPDBG_INFO(error); +PHPDBG_INFO(vars); +PHPDBG_INFO(literal); +PHPDBG_INFO(memory); + +static const phpdbg_command_t phpdbg_info_commands[] = { + PHPDBG_COMMAND_D_EX(break, "show breakpoints", 'b', info_break, NULL, 0), + PHPDBG_COMMAND_D_EX(files, "show included files", 'F', info_files, NULL, 0), + PHPDBG_COMMAND_D_EX(classes, "show loaded classes", 'c', info_classes, NULL, 0), + PHPDBG_COMMAND_D_EX(funcs, "show loaded classes", 'f', info_funcs, NULL, 0), + PHPDBG_COMMAND_D_EX(error, "show last error", 'e', info_error, NULL, 0), + PHPDBG_COMMAND_D_EX(vars, "show active variables", 'v', info_vars, NULL, 0), + PHPDBG_COMMAND_D_EX(literal, "show active literal constants", 'l', info_literal, NULL, 0), + PHPDBG_COMMAND_D_EX(memory, "show memory manager stats", 'm', info_memory, NULL, 0), + PHPDBG_END_COMMAND +}; + +#endif /* PHPDBG_INFO_H */ diff --git a/phpdbg_list.c b/phpdbg_list.c new file mode 100644 index 0000000000..b49be857ef --- /dev/null +++ b/phpdbg_list.c @@ -0,0 +1,279 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include +#include +#include +#ifndef _WIN32 +# include +# include +#endif +#include +#include "phpdbg.h" +#include "phpdbg_list.h" +#include "phpdbg_utils.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_LIST(lines) /* {{{ */ +{ + if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) { + phpdbg_error("Not executing, and execution context not set"); + return SUCCESS; + } + + switch (param->type) { + case NUMERIC_PARAM: + case EMPTY_PARAM: + phpdbg_list_file(phpdbg_current_file(TSRMLS_C), + param->type == EMPTY_PARAM ? 0 : (param->num < 0 ? 1 - param->num : param->num), + (param->type != EMPTY_PARAM && param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), + 0 TSRMLS_CC); + break; + case FILE_PARAM: + phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_LIST(func) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: + phpdbg_list_function_byname( + param->str, param->len TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_LIST(method) /* {{{ */ +{ + switch (param->type) { + case METHOD_PARAM: { + zend_class_entry **ce; + + if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + zend_function *function; + char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); + + if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) { + phpdbg_list_function(function TSRMLS_CC); + } else { + phpdbg_error("Could not find %s::%s", param->method.class, param->method.name); + } + + efree(lcname); + } else { + phpdbg_error("Could not find the class %s", param->method.class); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_LIST(class) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: { + zend_class_entry **ce; + + if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + if ((*ce)->type == ZEND_USER_CLASS) { + if ((*ce)->info.user.filename) { + phpdbg_list_file( + (*ce)->info.user.filename, + (*ce)->info.user.line_end - (*ce)->info.user.line_start + 1, + (*ce)->info.user.line_start, 0 TSRMLS_CC + ); + } else { + phpdbg_error("The source of the requested class (%s) cannot be found", (*ce)->name); + } + } else { + phpdbg_error("The class requested (%s) is not user defined", (*ce)->name); + } + } else { + phpdbg_error("The requested class (%s) could not be found", param->str); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */ +{ + unsigned char *mem, *pos, *last_pos, *end_pos; + struct stat st; +#ifndef _WIN32 + int fd; +#else + HANDLE fd, map; +#endif + int all_content = (count == 0); + int line = 0, displayed = 0; + + if (VCWD_STAT(filename, &st) == FAILURE) { + phpdbg_error("Failed to stat file %s", filename); + return; + } + +#ifndef _WIN32 + if ((fd = VCWD_OPEN(filename, O_RDONLY)) == FAILURE) { + phpdbg_error("Failed to open file %s to list", filename); + return; + } + + pos = last_pos = mem = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + end_pos = mem + st.st_size; +#else + + fd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd == INVALID_HANDLE_VALUE) { + phpdbg_error("Failed to open file!"); + return; + } + + map = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL); + if (map == NULL) { + phpdbg_error("Failed to map file!"); + CloseHandle(fd); + return; + } + + pos = last_pos = mem = (char*) MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); + if (mem == NULL) { + phpdbg_error("Failed to map file in memory"); + CloseHandle(map); + CloseHandle(fd); + return; + } + end_pos = mem + st.st_size; +#endif + while (1) { + if (pos == end_pos) { + break; + } + + pos = memchr(last_pos, '\n', end_pos - last_pos); + + if (!pos) { + /* No more line breaks */ + pos = end_pos; + } + + ++line; + + if (!offset || offset <= line) { + /* Without offset, or offset reached */ + if (!highlight) { + phpdbg_writeln("%05u: %.*s", line, (int)(pos - last_pos), last_pos); + } else { + if (highlight != line) { + phpdbg_writeln(" %05u: %.*s", line, (int)(pos - last_pos), last_pos); + } else { + phpdbg_writeln(">%05u: %.*s", line, (int)(pos - last_pos), last_pos); + } + } + ++displayed; + } + + last_pos = pos + 1; + + if (!all_content && displayed == count) { + /* Reached max line to display */ + break; + } + } + +#ifndef _WIN32 + munmap(mem, st.st_size); + close(fd); +#else + UnmapViewOfFile(mem); + CloseHandle(map); + CloseHandle(fd); +#endif +} /* }}} */ + +void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */ +{ + const zend_op_array *ops; + + if (fbc->type != ZEND_USER_FUNCTION) { + phpdbg_error("The function requested (%s) is not user defined", fbc->common.function_name); + return; + } + + ops = (zend_op_array*)fbc; + + phpdbg_list_file(ops->filename, + ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC); +} /* }}} */ + +void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */ +{ + HashTable *func_table = EG(function_table); + zend_function* fbc; + char *func_name = (char*) str; + size_t func_name_len = len; + + /* search active scope if begins with period */ + if (func_name[0] == '.') { + if (EG(scope)) { + func_name++; + func_name_len--; + + func_table = &EG(scope)->function_table; + } else { + phpdbg_error("No active class"); + return; + } + } else if (!EG(function_table)) { + phpdbg_error("No function table loaded"); + return; + } else { + func_table = EG(function_table); + } + + /* use lowercase names, case insensitive */ + func_name = zend_str_tolower_dup(func_name, func_name_len); + + if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) { + phpdbg_list_function(fbc TSRMLS_CC); + } else { + phpdbg_error("Function %s not found", func_name); + } + + efree(func_name); +} /* }}} */ + diff --git a/phpdbg_list.h b/phpdbg_list.h new file mode 100644 index 0000000000..d618027158 --- /dev/null +++ b/phpdbg_list.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_LIST_H +#define PHPDBG_LIST_H + +#include "TSRM.h" +#include "phpdbg_cmd.h" + +#define PHPDBG_LIST(name) PHPDBG_COMMAND(list_##name) +#define PHPDBG_LIST_HANDLER(name) PHPDBG_COMMAND_HANDLER(list_##name) + +PHPDBG_LIST(lines); +PHPDBG_LIST(class); +PHPDBG_LIST(method); +PHPDBG_LIST(func); + +void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC); +void phpdbg_list_function(const zend_function* TSRMLS_DC); +void phpdbg_list_file(const char*, long, long, int TSRMLS_DC); + +static const phpdbg_command_t phpdbg_list_commands[] = { + PHPDBG_COMMAND_D_EX(lines, "lists the specified lines", 'l', list_lines, NULL, 1), + PHPDBG_COMMAND_D_EX(class, "lists the specified class", 'c', list_class, NULL, 1), + PHPDBG_COMMAND_D_EX(method, "lists the specified method", 'm', list_method, NULL, 1), + PHPDBG_COMMAND_D_EX(func, "lists the specified function", 'f', list_func, NULL, 1), + PHPDBG_END_COMMAND +}; + +#endif /* PHPDBG_LIST_H */ diff --git a/phpdbg_opcode.c b/phpdbg_opcode.c new file mode 100644 index 0000000000..025d57a08d --- /dev/null +++ b/phpdbg_opcode.c @@ -0,0 +1,361 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg.h" +#include "zend_vm_opcodes.h" +#include "zend_compile.h" +#include "phpdbg_opcode.h" +#include "phpdbg_utils.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +static inline zend_uint phpdbg_decode_literal(zend_op_array *ops, zend_literal *literal TSRMLS_DC) /* {{{ */ +{ + int iter = 0; + + while (iter < ops->last_literal) { + if (literal == &ops->literals[iter]) { + return iter; + } + iter++; + } + + return 0; +} /* }}} */ + +static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint type, HashTable *vars TSRMLS_DC) /* {{{ */ +{ + char *decode = NULL; + + switch (type &~ EXT_TYPE_UNUSED) { + case IS_CV: + asprintf(&decode, "$%s", ops->vars[op->var].name); + break; + + case IS_VAR: + case IS_TMP_VAR: { + zend_ulong id = 0, *pid = NULL; + if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) { + id = zend_hash_num_elements(vars); + zend_hash_index_update( + vars, (zend_ulong) ops->vars - op->var, + (void**) &id, + sizeof(zend_ulong), NULL); + } else id = *pid; + asprintf(&decode, "@%lu", id); + } break; + + case IS_CONST: + asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->literal TSRMLS_CC)); + break; + + case IS_UNUSED: + asprintf(&decode, ""); + break; + } + return decode; +} /* }}} */ + +char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC) /*{{{ */ +{ + char *decode[4] = {NULL, NULL, NULL, NULL}; + + switch (op->opcode) { + case ZEND_JMP: +#ifdef ZEND_GOTO + case ZEND_GOTO: +#endif +#ifdef ZEND_FAST_CALL + case ZEND_FAST_CALL: +#endif + asprintf(&decode[1], "J%ld", op->op1.jmp_addr - ops->opcodes); + goto format; + + case ZEND_JMPZNZ: + decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); + asprintf( + &decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value); + goto result; + + case ZEND_JMPZ: + case ZEND_JMPNZ: + case ZEND_JMPZ_EX: + case ZEND_JMPNZ_EX: + +#ifdef ZEND_JMP_SET + case ZEND_JMP_SET: +#endif +#ifdef ZEND_JMP_SET_VAR + case ZEND_JMP_SET_VAR: +#endif + decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); + asprintf( + &decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes); + goto result; + + case ZEND_RECV_INIT: + goto result; + + default: { + decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); + decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars TSRMLS_CC); +result: + decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC); +format: + asprintf( + &decode[0], + "%-20s %-20s %-20s", + decode[1] ? decode[1] : "", + decode[2] ? decode[2] : "", + decode[3] ? decode[3] : ""); + } + } + + if (decode[1]) + free(decode[1]); + if (decode[2]) + free(decode[2]); + if (decode[3]) + free(decode[3]); + + return decode[0]; +} /* }}} */ + +void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC) /* {{{ */ +{ + /* force out a line while stepping so the user knows what is happening */ + if (ignore_flags || + (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || + (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) || + (PHPDBG_G(oplog)))) { + + zend_op *opline = execute_data->opline; + char *decode = phpdbg_decode_opline(execute_data->op_array, opline, vars TSRMLS_CC); + + if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) { + /* output line info */ + phpdbg_notice("L%-5u %16p %-30s %s %s", + opline->lineno, + opline, + phpdbg_decode_opcode(opline->opcode), + decode, + execute_data->op_array->filename ? execute_data->op_array->filename : "unknown"); + } + + if (!ignore_flags && PHPDBG_G(oplog)) { + phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s", + opline->lineno, + opline, + phpdbg_decode_opcode(opline->opcode), + decode, + execute_data->op_array->filename ? execute_data->op_array->filename : "unknown"); + } + + if (decode) { + free(decode); + } + } +} /* }}} */ + +void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC) /* {{{ */ +{ + phpdbg_print_opline_ex(execute_data, NULL, ignore_flags TSRMLS_CC); +} /* }}} */ + +const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */ +{ +#define CASE(s) case s: return #s + switch (opcode) { + CASE(ZEND_NOP); + CASE(ZEND_ADD); + CASE(ZEND_SUB); + CASE(ZEND_MUL); + CASE(ZEND_DIV); + CASE(ZEND_MOD); + CASE(ZEND_SL); + CASE(ZEND_SR); + CASE(ZEND_CONCAT); + CASE(ZEND_BW_OR); + CASE(ZEND_BW_AND); + CASE(ZEND_BW_XOR); + CASE(ZEND_BW_NOT); + CASE(ZEND_BOOL_NOT); + CASE(ZEND_BOOL_XOR); + CASE(ZEND_IS_IDENTICAL); + CASE(ZEND_IS_NOT_IDENTICAL); + CASE(ZEND_IS_EQUAL); + CASE(ZEND_IS_NOT_EQUAL); + CASE(ZEND_IS_SMALLER); + CASE(ZEND_IS_SMALLER_OR_EQUAL); + CASE(ZEND_CAST); + CASE(ZEND_QM_ASSIGN); + CASE(ZEND_ASSIGN_ADD); + CASE(ZEND_ASSIGN_SUB); + CASE(ZEND_ASSIGN_MUL); + CASE(ZEND_ASSIGN_DIV); + CASE(ZEND_ASSIGN_MOD); + CASE(ZEND_ASSIGN_SL); + CASE(ZEND_ASSIGN_SR); + CASE(ZEND_ASSIGN_CONCAT); + CASE(ZEND_ASSIGN_BW_OR); + CASE(ZEND_ASSIGN_BW_AND); + CASE(ZEND_ASSIGN_BW_XOR); + CASE(ZEND_PRE_INC); + CASE(ZEND_PRE_DEC); + CASE(ZEND_POST_INC); + CASE(ZEND_POST_DEC); + CASE(ZEND_ASSIGN); + CASE(ZEND_ASSIGN_REF); + CASE(ZEND_ECHO); + CASE(ZEND_PRINT); + CASE(ZEND_JMP); + CASE(ZEND_JMPZ); + CASE(ZEND_JMPNZ); + CASE(ZEND_JMPZNZ); + CASE(ZEND_JMPZ_EX); + CASE(ZEND_JMPNZ_EX); + CASE(ZEND_CASE); + CASE(ZEND_SWITCH_FREE); + CASE(ZEND_BRK); + CASE(ZEND_CONT); + CASE(ZEND_BOOL); + CASE(ZEND_INIT_STRING); + CASE(ZEND_ADD_CHAR); + CASE(ZEND_ADD_STRING); + CASE(ZEND_ADD_VAR); + CASE(ZEND_BEGIN_SILENCE); + CASE(ZEND_END_SILENCE); + CASE(ZEND_INIT_FCALL_BY_NAME); + CASE(ZEND_DO_FCALL); + CASE(ZEND_DO_FCALL_BY_NAME); + CASE(ZEND_RETURN); + CASE(ZEND_RECV); + CASE(ZEND_RECV_INIT); + CASE(ZEND_SEND_VAL); + CASE(ZEND_SEND_VAR); + CASE(ZEND_SEND_REF); + CASE(ZEND_NEW); + CASE(ZEND_INIT_NS_FCALL_BY_NAME); + CASE(ZEND_FREE); + CASE(ZEND_INIT_ARRAY); + CASE(ZEND_ADD_ARRAY_ELEMENT); + CASE(ZEND_INCLUDE_OR_EVAL); + CASE(ZEND_UNSET_VAR); + CASE(ZEND_UNSET_DIM); + CASE(ZEND_UNSET_OBJ); + CASE(ZEND_FE_RESET); + CASE(ZEND_FE_FETCH); + CASE(ZEND_EXIT); + CASE(ZEND_FETCH_R); + CASE(ZEND_FETCH_DIM_R); + CASE(ZEND_FETCH_OBJ_R); + CASE(ZEND_FETCH_W); + CASE(ZEND_FETCH_DIM_W); + CASE(ZEND_FETCH_OBJ_W); + CASE(ZEND_FETCH_RW); + CASE(ZEND_FETCH_DIM_RW); + CASE(ZEND_FETCH_OBJ_RW); + CASE(ZEND_FETCH_IS); + CASE(ZEND_FETCH_DIM_IS); + CASE(ZEND_FETCH_OBJ_IS); + CASE(ZEND_FETCH_FUNC_ARG); + CASE(ZEND_FETCH_DIM_FUNC_ARG); + CASE(ZEND_FETCH_OBJ_FUNC_ARG); + CASE(ZEND_FETCH_UNSET); + CASE(ZEND_FETCH_DIM_UNSET); + CASE(ZEND_FETCH_OBJ_UNSET); + CASE(ZEND_FETCH_DIM_TMP_VAR); + CASE(ZEND_FETCH_CONSTANT); + CASE(ZEND_GOTO); + CASE(ZEND_EXT_STMT); + CASE(ZEND_EXT_FCALL_BEGIN); + CASE(ZEND_EXT_FCALL_END); + CASE(ZEND_EXT_NOP); + CASE(ZEND_TICKS); + CASE(ZEND_SEND_VAR_NO_REF); + CASE(ZEND_CATCH); + CASE(ZEND_THROW); + CASE(ZEND_FETCH_CLASS); + CASE(ZEND_CLONE); + CASE(ZEND_RETURN_BY_REF); + CASE(ZEND_INIT_METHOD_CALL); + CASE(ZEND_INIT_STATIC_METHOD_CALL); + CASE(ZEND_ISSET_ISEMPTY_VAR); + CASE(ZEND_ISSET_ISEMPTY_DIM_OBJ); + CASE(ZEND_PRE_INC_OBJ); + CASE(ZEND_PRE_DEC_OBJ); + CASE(ZEND_POST_INC_OBJ); + CASE(ZEND_POST_DEC_OBJ); + CASE(ZEND_ASSIGN_OBJ); + CASE(ZEND_INSTANCEOF); + CASE(ZEND_DECLARE_CLASS); + CASE(ZEND_DECLARE_INHERITED_CLASS); + CASE(ZEND_DECLARE_FUNCTION); + CASE(ZEND_RAISE_ABSTRACT_ERROR); + CASE(ZEND_DECLARE_CONST); + CASE(ZEND_ADD_INTERFACE); + CASE(ZEND_DECLARE_INHERITED_CLASS_DELAYED); + CASE(ZEND_VERIFY_ABSTRACT_CLASS); + CASE(ZEND_ASSIGN_DIM); + CASE(ZEND_ISSET_ISEMPTY_PROP_OBJ); + CASE(ZEND_HANDLE_EXCEPTION); + CASE(ZEND_USER_OPCODE); +#ifdef ZEND_JMP_SET + CASE(ZEND_JMP_SET); +#endif + CASE(ZEND_DECLARE_LAMBDA_FUNCTION); +#ifdef ZEND_ADD_TRAIT + CASE(ZEND_ADD_TRAIT); +#endif +#ifdef ZEND_BIND_TRAITS + CASE(ZEND_BIND_TRAITS); +#endif +#ifdef ZEND_SEPARATE + CASE(ZEND_SEPARATE); +#endif +#ifdef ZEND_QM_ASSIGN_VAR + CASE(ZEND_QM_ASSIGN_VAR); +#endif +#ifdef ZEND_JMP_SET_VAR + CASE(ZEND_JMP_SET_VAR); +#endif +#ifdef ZEND_DISCARD_EXCEPTION + CASE(ZEND_DISCARD_EXCEPTION); +#endif +#ifdef ZEND_YIELD + CASE(ZEND_YIELD); +#endif +#ifdef ZEND_GENERATOR_RETURN + CASE(ZEND_GENERATOR_RETURN); +#endif +#ifdef ZEND_FAST_CALL + CASE(ZEND_FAST_CALL); +#endif +#ifdef ZEND_FAST_RET + CASE(ZEND_FAST_RET); +#endif +#ifdef ZEND_RECV_VARIADIC + CASE(ZEND_RECV_VARIADIC); +#endif + CASE(ZEND_OP_DATA); + default: + return "UNKNOWN"; + } +} /* }}} */ diff --git a/phpdbg_opcode.h b/phpdbg_opcode.h new file mode 100644 index 0000000000..5771488e70 --- /dev/null +++ b/phpdbg_opcode.h @@ -0,0 +1,31 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_OPCODE_H +#define PHPDBG_OPCODE_H + +#include "zend_types.h" + +const char *phpdbg_decode_opcode(zend_uchar); +char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC); +void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC); +void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC); + +#endif /* PHPDBG_OPCODE_H */ diff --git a/phpdbg_print.c b/phpdbg_print.c new file mode 100644 index 0000000000..51edcfbf8d --- /dev/null +++ b/phpdbg_print.c @@ -0,0 +1,258 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg.h" +#include "phpdbg_print.h" +#include "phpdbg_utils.h" +#include "phpdbg_opcode.h" +#include "phpdbg_prompt.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_PRINT(opline) /* {{{ */ +{ + if (EG(in_execution) && EG(current_execute_data)) { + phpdbg_print_opline(EG(current_execute_data), 1 TSRMLS_CC); + } else { + phpdbg_error("Not Executing!"); + } + + return SUCCESS; +} /* }}} */ + +static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) /* {{{ */ +{ + switch (method->type) { + case ZEND_USER_FUNCTION: { + zend_op_array* op_array = &(method->op_array); + HashTable vars; + + if (op_array) { + zend_op *opline = &(op_array->opcodes[0]); + zend_uint opcode = 0, + end = op_array->last-1; + + if (method->common.scope) { + phpdbg_writeln("\tL%d-%d %s::%s() %s", + op_array->line_start, op_array->line_end, + method->common.scope->name, + method->common.function_name, + op_array->filename ? op_array->filename : "unknown"); + } else { + phpdbg_writeln("\tL%d-%d %s() %s", + method->common.function_name ? op_array->line_start : 0, + method->common.function_name ? op_array->line_end : 0, + method->common.function_name ? method->common.function_name : "{main}", + op_array->filename ? op_array->filename : "unknown"); + } + + zend_hash_init(&vars, op_array->last, NULL, NULL, 0); + do { + char *decode = phpdbg_decode_opline(op_array, opline, &vars TSRMLS_CC); + if (decode != NULL) { + phpdbg_writeln("\t\tL%u\t%p %-30s %s", + opline->lineno, + opline, + phpdbg_decode_opcode(opline->opcode), + decode); + free(decode); + } else { + phpdbg_error("\tFailed to decode opline %16p", opline); + } + opline++; + } while (++opcode < end); + zend_hash_destroy(&vars); + } + } break; + + default: { + if (method->common.scope) { + phpdbg_writeln("\tInternal %s::%s()", method->common.scope->name, method->common.function_name); + } else { + phpdbg_writeln("\tInternal %s()", method->common.function_name); + } + } + } +} /* }}} */ + +PHPDBG_PRINT(exec) /* {{{ */ +{ + if (PHPDBG_G(exec)) { + if (!PHPDBG_G(ops)) { + phpdbg_compile(TSRMLS_C); + } + + if (PHPDBG_G(ops)) { + phpdbg_notice("Context %s", PHPDBG_G(exec)); + + phpdbg_print_function_helper((zend_function*) PHPDBG_G(ops) TSRMLS_CC); + } + } else { + phpdbg_error("No execution context set"); + } + +return SUCCESS; +} /* }}} */ + +PHPDBG_PRINT(stack) /* {{{ */ +{ + zend_op_array *ops = EG(active_op_array); + + if (EG(in_execution) && ops) { + if (ops->function_name) { + if (ops->scope) { + phpdbg_notice("Stack in %s::%s()", ops->scope->name, ops->function_name); + } else { + phpdbg_notice("Stack in %s()", ops->function_name); + } + } else { + if (ops->filename) { + phpdbg_notice("Stack in %s", ops->filename); + } else { + phpdbg_notice("Stack @ %p", ops); + } + } + phpdbg_print_function_helper((zend_function*) ops TSRMLS_CC); + } else { + phpdbg_error("Not Executing!"); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_PRINT(class) /* {{{ */ +{ + zend_class_entry **ce; + + switch (param->type) { + case STR_PARAM: { + if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + phpdbg_notice("%s %s: %s", + ((*ce)->type == ZEND_USER_CLASS) ? + "User" : "Internal", + ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? + "Interface" : + ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? + "Abstract Class" : + "Class", + (*ce)->name); + + phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table)); + if (zend_hash_num_elements(&(*ce)->function_table)) { + HashPosition position; + zend_function *method; + + for (zend_hash_internal_pointer_reset_ex(&(*ce)->function_table, &position); + zend_hash_get_current_data_ex(&(*ce)->function_table, (void**) &method, &position) == SUCCESS; + zend_hash_move_forward_ex(&(*ce)->function_table, &position)) { + phpdbg_print_function_helper(method TSRMLS_CC); + } + } + } else { + phpdbg_error("The class %s could not be found", param->str); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_PRINT(method) /* {{{ */ +{ + switch (param->type) { + case METHOD_PARAM: { + zend_class_entry **ce; + + if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + zend_function *fbc; + char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); + + if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { + phpdbg_notice("%s Method %s", + (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", + fbc->common.function_name); + + phpdbg_print_function_helper(fbc TSRMLS_CC); + } else { + phpdbg_error("The method %s could not be found", param->method.name); + } + + efree(lcname); + } else { + phpdbg_error("The class %s could not be found", param->method.class); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_PRINT(func) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: { + HashTable *func_table = EG(function_table); + zend_function* fbc; + const char *func_name = param->str; + size_t func_name_len = param->len; + char *lcname; + /* search active scope if begins with period */ + if (func_name[0] == '.') { + if (EG(scope)) { + func_name++; + func_name_len--; + + func_table = &EG(scope)->function_table; + } else { + phpdbg_error("No active class"); + return SUCCESS; + } + } else if (!EG(function_table)) { + phpdbg_error("No function table loaded"); + return SUCCESS; + } else { + func_table = EG(function_table); + } + + lcname = zend_str_tolower_dup(func_name, func_name_len); + + if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { + phpdbg_notice("%s %s %s", + (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", + (fbc->common.scope) ? "Method" : "Function", + fbc->common.function_name); + + phpdbg_print_function_helper(fbc TSRMLS_CC); + } else { + phpdbg_error("The function %s could not be found", func_name); + } + + efree(lcname); + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ diff --git a/phpdbg_print.h b/phpdbg_print.h new file mode 100644 index 0000000000..1232f544d2 --- /dev/null +++ b/phpdbg_print.h @@ -0,0 +1,51 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_PRINT_H +#define PHPDBG_PRINT_H + +#include "phpdbg_cmd.h" + +#define PHPDBG_PRINT(name) PHPDBG_COMMAND(print_##name) + +/** + * Printer Forward Declarations + */ +PHPDBG_PRINT(exec); +PHPDBG_PRINT(opline); +PHPDBG_PRINT(class); +PHPDBG_PRINT(method); +PHPDBG_PRINT(func); +PHPDBG_PRINT(stack); + +/** + * Commands + */ +static const phpdbg_command_t phpdbg_print_commands[] = { + PHPDBG_COMMAND_D_EX(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0), + PHPDBG_COMMAND_D_EX(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0), + PHPDBG_COMMAND_D_EX(class, "print out the instructions in the specified class", 'c', print_class, NULL, 1), + PHPDBG_COMMAND_D_EX(method, "print out the instructions in the specified method", 'm', print_method, NULL, 1), + PHPDBG_COMMAND_D_EX(func, "print out the instructions in the specified function", 'f', print_func, NULL, 1), + PHPDBG_COMMAND_D_EX(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0), + PHPDBG_END_COMMAND +}; + +#endif /* PHPDBG_PRINT_H */ diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c new file mode 100644 index 0000000000..f2f482b7ec --- /dev/null +++ b/phpdbg_prompt.c @@ -0,0 +1,1328 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include +#include +#include "zend.h" +#include "zend_compile.h" +#include "phpdbg.h" +#include "phpdbg_help.h" +#include "phpdbg_print.h" +#include "phpdbg_info.h" +#include "phpdbg_break.h" +#include "phpdbg_bp.h" +#include "phpdbg_opcode.h" +#include "phpdbg_list.h" +#include "phpdbg_utils.h" +#include "phpdbg_prompt.h" +#include "phpdbg_cmd.h" +#include "phpdbg_set.h" +#include "phpdbg_frame.h" + +/* {{{ command declarations */ +const phpdbg_command_t phpdbg_prompt_commands[] = { + PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, 1), + PHPDBG_COMMAND_D(compile, "attempt compilation", 'c', NULL, 0), + PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 1), + PHPDBG_COMMAND_D(next, "continue execution", 'n', NULL, 0), + PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0), + PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, 1), + PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0), + PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0), + PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0), + PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 2), + PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1), + PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0), + PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, 1), + PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, 2), + PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, 1), + PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0), + PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0), + PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, 2), + PHPDBG_COMMAND_D(quiet, "silence some output", 'Q', NULL, 1), + PHPDBG_COMMAND_D(aliases, "show alias list", 'a', NULL, 0), + PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, 1), + PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, 1), + PHPDBG_COMMAND_D(source, "execute a phpdbginit", '.', NULL, 1), + PHPDBG_COMMAND_D(shell, "shell a command", '-', NULL, 1), + PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0), + PHPDBG_END_COMMAND +}; /* }}} */ + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +static inline int phpdbg_call_register(phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +{ + phpdbg_input_t *function = input->argv[0]; + + if (zend_hash_exists( + &PHPDBG_G(registered), function->string, function->length+1)) { + + zval fname, *fretval; + zend_fcall_info fci; + + ZVAL_STRINGL(&fname, function->string, function->length, 1); + + memset(&fci, 0, sizeof(zend_fcall_info)); + + fci.size = sizeof(zend_fcall_info); + fci.function_table = &PHPDBG_G(registered); + fci.function_name = &fname; + fci.symbol_table = EG(active_symbol_table); + fci.object_ptr = NULL; + fci.retval_ptr_ptr = &fretval; + fci.no_separation = 1; + + if (input->argc > 1) { + int param; + zval params; + + array_init(¶ms); + + for (param = 0; param < (input->argc-1); param++) { + add_next_index_stringl( + ¶ms, + input->argv[param+1]->string, + input->argv[param+1]->length, 1); + + phpdbg_debug( + "created param[%d] from argv[%d]: %s", + param, param+1, input->argv[param+1]->string); + } + + zend_fcall_info_args(&fci, ¶ms TSRMLS_CC); + } else { + fci.params = NULL; + fci.param_count = 0; + } + + phpdbg_debug( + "created %d params from %d arguments", + fci.param_count, input->argc); + + zend_call_function(&fci, NULL TSRMLS_CC); + + if (fretval) { + zend_print_zval_r( + fretval, 0 TSRMLS_CC); + phpdbg_writeln(EMPTY); + } + + zval_dtor(&fname); + + return SUCCESS; + } + + return FAILURE; +} /* }}} */ + +void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */ +{ + struct stat sb; + + if (init_file && VCWD_STAT(init_file, &sb) != -1) { + FILE *fp = fopen(init_file, "r"); + if (fp) { + int line = 1; + + char cmd[PHPDBG_MAX_CMD]; + size_t cmd_len = 0L; + char *code = NULL; + size_t code_len = 0L; + zend_bool in_code = 0; + + while (fgets(cmd, PHPDBG_MAX_CMD, fp) != NULL) { + cmd_len = strlen(cmd)-1; + + while (cmd_len > 0L && isspace(cmd[cmd_len-1])) + cmd_len--; + + cmd[cmd_len] = '\0'; + + if (*cmd && cmd_len > 0L && cmd[0] != '#') { + if (cmd_len == 2) { + if (memcmp(cmd, "<:", sizeof("<:")-1) == SUCCESS) { + in_code = 1; + goto next_line; + } else { + if (memcmp(cmd, ":>", sizeof(":>")-1) == SUCCESS) { + in_code = 0; + code[code_len] = '\0'; + { + zend_eval_stringl( + code, code_len, NULL, "phpdbginit code" TSRMLS_CC); + } + free(code); + code = NULL; + goto next_line; + } + } + } + + if (in_code) { + if (code == NULL) { + code = malloc(cmd_len + 1); + } else code = realloc(code, code_len + cmd_len + 1); + + if (code) { + memcpy( + &code[code_len], cmd, cmd_len); + code_len += cmd_len; + } + goto next_line; + } + + { + phpdbg_input_t *input = phpdbg_read_input(cmd TSRMLS_CC); + switch (phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) { + case FAILURE: + if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) { + phpdbg_error("Unrecognized command in %s:%d: %s!", init_file, line, input->string); + } + } + break; + } + phpdbg_destroy_input(&input TSRMLS_CC); + } + + } +next_line: + line++; + } + + if (code) { + free(code); + } + + fclose(fp); + } else { + phpdbg_error( + "Failed to open %s for initialization", init_file); + } + + if (free_init) { + free(init_file); + } + } +} /* }}} */ + +void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC) /* {{{ */ +{ + if (!init_file && use_default) { + char *scan_dir = getenv("PHP_INI_SCAN_DIR"); + int i; + + phpdbg_try_file_init(PHPDBG_STRL(PHP_CONFIG_FILE_PATH "/" PHPDBG_INIT_FILENAME), 0 TSRMLS_CC); + + if (!scan_dir) { + scan_dir = PHP_CONFIG_FILE_SCAN_DIR; + } + while (*scan_dir != 0) { + i = 0; + while (scan_dir[i] != ':') { + if (scan_dir[i++] == 0) { + i = -1; + break; + } + } + if (i != -1) { + scan_dir[i] = 0; + } + + asprintf( + &init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME); + phpdbg_try_file_init(init_file, strlen(init_file), 1 TSRMLS_CC); + if (i == -1) { + break; + } + scan_dir += i + 1; + } + + phpdbg_try_file_init(PHPDBG_STRL(PHPDBG_INIT_FILENAME), 0 TSRMLS_CC); + } else { + phpdbg_try_file_init(init_file, init_file_len, 1 TSRMLS_CC); + } +} + +PHPDBG_COMMAND(exec) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: { + struct stat sb; + + if (VCWD_STAT(param->str, &sb) != FAILURE) { + if (sb.st_mode & (S_IFREG|S_IFLNK)) { + char *res = phpdbg_resolve_path(param->str TSRMLS_CC); + size_t res_len = strlen(res); + + if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { + + if (PHPDBG_G(exec)) { + phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec)); + efree(PHPDBG_G(exec)); + PHPDBG_G(exec) = NULL; + PHPDBG_G(exec_len) = 0L; + } + + if (PHPDBG_G(ops)) { + phpdbg_notice("Destroying compiled opcodes"); + phpdbg_clean(0 TSRMLS_CC); + } + + PHPDBG_G(exec) = res; + PHPDBG_G(exec_len) = res_len; + + phpdbg_notice("Set execution context: %s", PHPDBG_G(exec)); + } else { + phpdbg_notice("Execution context not changed"); + } + } else { + phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str); + } + } else { + phpdbg_error("Cannot stat %s, ensure the file exists", param->str); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +int phpdbg_compile(TSRMLS_D) /* {{{ */ +{ + zend_file_handle fh; + + if (EG(in_execution)) { + phpdbg_error("Cannot compile while in execution"); + return FAILURE; + } + + phpdbg_notice("Attempting compilation of %s", PHPDBG_G(exec)); + + if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, + USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC) == SUCCESS) { + + PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE TSRMLS_CC); + zend_destroy_file_handle(&fh TSRMLS_CC); + + phpdbg_notice("Success"); + return SUCCESS; + } else { + phpdbg_error("Could not open file %s", PHPDBG_G(exec)); + } + + return FAILURE; +} /* }}} */ + +PHPDBG_COMMAND(compile) /* {{{ */ +{ + if (!PHPDBG_G(exec)) { + phpdbg_error("No execution context"); + return SUCCESS; + } + + if (!EG(in_execution)) { + if (PHPDBG_G(ops)) { + phpdbg_error("Destroying previously compiled opcodes"); + phpdbg_clean(0 TSRMLS_CC); + } + } + + phpdbg_compile(TSRMLS_C); + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(step) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: + case NUMERIC_PARAM: { + if (param->type == NUMERIC_PARAM && param->num) { + PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; + } else { + PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; + } + + phpdbg_notice("Stepping %s", + (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(next) /* {{{ */ +{ + return PHPDBG_NEXT; +} /* }}} */ + +PHPDBG_COMMAND(until) /* {{{ */ +{ + if (!EG(in_execution)) { + phpdbg_error("Not executing"); + return SUCCESS; + } + + PHPDBG_G(flags) |= PHPDBG_IN_UNTIL; + { + zend_uint next = 0, + self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); + zend_op *opline = &EG(active_op_array)->opcodes[self]; + + for (next = self; next < EG(active_op_array)->last; next++) { + if (EG(active_op_array)->opcodes[next].lineno != opline->lineno) { + zend_hash_index_update( + &PHPDBG_G(seek), + (zend_ulong) &EG(active_op_array)->opcodes[next], + &EG(active_op_array)->opcodes[next], + sizeof(zend_op), NULL); + break; + } + } + } + + return PHPDBG_UNTIL; +} /* }}} */ + +PHPDBG_COMMAND(finish) /* {{{ */ +{ + if (!EG(in_execution)) { + phpdbg_error("Not executing"); + return SUCCESS; + } + + PHPDBG_G(flags) |= PHPDBG_IN_FINISH; + { + zend_uint next = 0, + self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); + + for (next = self; next < EG(active_op_array)->last; next++) { + switch (EG(active_op_array)->opcodes[next].opcode) { + case ZEND_RETURN: + case ZEND_THROW: + case ZEND_EXIT: +#ifdef ZEND_YIELD + case ZEND_YIELD: +#endif + zend_hash_index_update( + &PHPDBG_G(seek), + (zend_ulong) &EG(active_op_array)->opcodes[next], + &EG(active_op_array)->opcodes[next], + sizeof(zend_op), NULL); + break; + } + } + } + + return PHPDBG_FINISH; +} /* }}} */ + +PHPDBG_COMMAND(leave) /* {{{ */ +{ + if (!EG(in_execution)) { + phpdbg_error("Not executing"); + return SUCCESS; + } + + PHPDBG_G(flags) |= PHPDBG_IN_LEAVE; + { + zend_uint next = 0, + self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); + + for (next = self; next < EG(active_op_array)->last; next++) { + switch (EG(active_op_array)->opcodes[next].opcode) { + case ZEND_RETURN: + case ZEND_THROW: + case ZEND_EXIT: +#ifdef ZEND_YIELD + case ZEND_YIELD: +#endif + zend_hash_index_update( + &PHPDBG_G(seek), + (zend_ulong) &EG(active_op_array)->opcodes[next], + &EG(active_op_array)->opcodes[next], + sizeof(zend_op), NULL); + break; + } + } + } + + return PHPDBG_LEAVE; +} /* }}} */ + +PHPDBG_COMMAND(frame) /* {{{ */ +{ + switch (param->type) { + case NUMERIC_PARAM: + phpdbg_switch_frame(param->num TSRMLS_CC); + break; + + case EMPTY_PARAM: + phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */ +{ + zend_fcall_info fci; + + zval fname, + *trace, + exception; + + /* get filename and linenumber before unsetting exception */ + const char *filename = zend_get_executed_filename(TSRMLS_C); + zend_uint lineno = zend_get_executed_lineno(TSRMLS_C); + + /* copy exception */ + exception = *EG(exception); + zval_copy_ctor(&exception); + EG(exception) = NULL; + + phpdbg_error( + "Uncaught %s!", + Z_OBJCE(exception)->name); + + /* call __toString */ + ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring")-1, 1); + fci.size = sizeof(fci); + fci.function_table = &Z_OBJCE(exception)->function_table; + fci.function_name = &fname; + fci.symbol_table = NULL; + fci.object_ptr = &exception; + fci.retval_ptr_ptr = &trace; + fci.param_count = 0; + fci.params = NULL; + fci.no_separation = 1; + zend_call_function(&fci, NULL TSRMLS_CC); + + if (trace) { + phpdbg_writeln( + "Uncaught %s", Z_STRVAL_P(trace)); + /* remember to dtor trace */ + zval_ptr_dtor(&trace); + } + + /* output useful information about address */ + phpdbg_writeln( + "Stacked entered at %p in %s on line %u", + EG(active_op_array)->opcodes, filename, lineno); + + zval_dtor(&fname); + zval_dtor(&exception); +} /* }}} */ + +PHPDBG_COMMAND(run) /* {{{ */ +{ + if (EG(in_execution)) { + phpdbg_error("Cannot start another execution while one is in progress"); + return SUCCESS; + } + + if (PHPDBG_G(ops) || PHPDBG_G(exec)) { + zend_op **orig_opline = EG(opline_ptr); + zend_op_array *orig_op_array = EG(active_op_array); + zval **orig_retval_ptr = EG(return_value_ptr_ptr); + + if (!PHPDBG_G(ops)) { + if (phpdbg_compile(TSRMLS_C) == FAILURE) { + phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec)); + goto out; + } + } + + EG(active_op_array) = PHPDBG_G(ops); + EG(return_value_ptr_ptr) = &PHPDBG_G(retval); + if (!EG(active_symbol_table)) { + zend_rebuild_symbol_table(TSRMLS_C); + } + + /* clean seek state */ + PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK; + zend_hash_clean( + &PHPDBG_G(seek)); + + /* reset hit counters */ + phpdbg_reset_breakpoints(TSRMLS_C); + + zend_try { + php_output_activate(TSRMLS_C); + PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; + zend_execute(EG(active_op_array) TSRMLS_CC); + PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; + php_output_deactivate(TSRMLS_C); + } zend_catch { + EG(active_op_array) = orig_op_array; + EG(opline_ptr) = orig_opline; + EG(return_value_ptr_ptr) = orig_retval_ptr; + + if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + phpdbg_error("Caught exit/error from VM"); + goto out; + } + } zend_end_try(); + + if (EG(exception)) { + phpdbg_handle_exception(TSRMLS_C); + } + + EG(active_op_array) = orig_op_array; + EG(opline_ptr) = orig_opline; + EG(return_value_ptr_ptr) = orig_retval_ptr; + + } else { + phpdbg_error("Nothing to execute!"); + } + +out: + PHPDBG_FRAME(num) = 0; + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(eval) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: { + zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING); + zval retval; + + if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING; + } + + /* disable stepping while eval() in progress */ + PHPDBG_G(flags) |= PHPDBG_IN_EVAL; + zend_try { + if (zend_eval_stringl(param->str, param->len, + &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { + zend_print_zval_r( + &retval, 0 TSRMLS_CC); + phpdbg_writeln(EMPTY); + zval_dtor(&retval); + } + } zend_end_try(); + PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; + + /* switch stepping back on */ + if (stepping && + !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; + } + + CG(unclean_shutdown) = 0; + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(back) /* {{{ */ +{ + if (!EG(in_execution)) { + phpdbg_error("Not executing!"); + return SUCCESS; + } + + switch (param->type) { + case EMPTY_PARAM: + case NUMERIC_PARAM: + phpdbg_dump_backtrace( + (param->type == NUMERIC_PARAM) ? param->num : 0 TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(print) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: { + phpdbg_writeln(SEPARATE); + phpdbg_notice("Execution Context Information"); +#ifdef HAVE_LIBREADLINE + phpdbg_writeln("Readline\tyes"); +#else + phpdbg_writeln("Readline\tno"); +#endif + + phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); + phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); + phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); + phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); + phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off"); + + if (PHPDBG_G(ops)) { + phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last); + + if (PHPDBG_G(ops)->last_var) { + phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1); + } else { + phpdbg_writeln("Variables\tNone"); + } + } + + phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no"); + if (EG(in_execution)) { + phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret)); + } + + phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files))); + + phpdbg_writeln(SEPARATE); + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(info) /* {{{ */ +{ + phpdbg_error( + "No information command selected!"); + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(set) /* {{{ */ +{ + phpdbg_error( + "No information command selected!"); + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(break) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: + phpdbg_set_breakpoint_file( + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); + break; + case ADDR_PARAM: + phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC); + break; + case NUMERIC_PARAM: + if (PHPDBG_G(exec)) { + phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC); + } else { + phpdbg_error("Execution context not set!"); + } + break; + case METHOD_PARAM: + phpdbg_set_breakpoint_method(param->method.class, param->method.name TSRMLS_CC); + break; + case NUMERIC_METHOD_PARAM: + phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num TSRMLS_CC); + break; + case NUMERIC_FUNCTION_PARAM: + phpdbg_set_breakpoint_function_opline(param->str, param->num TSRMLS_CC); + break; + case FILE_PARAM: + phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC); + break; + case STR_PARAM: + phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(shell) /* {{{ */ +{ + /* don't allow this to loop, ever ... */ + switch (param->type) { + case STR_PARAM: { + FILE *fd = NULL; + if ((fd=VCWD_POPEN((char*)param->str, "w"))) { + /* do something perhaps ?? do we want input ?? */ + fclose(fd); + } else { + phpdbg_error( + "Failed to execute %s", param->str); + } + } break; + + phpdbg_default_switch_case(); + } + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(source) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: { + if (input->argc > 2) { + if (phpdbg_argv_is(1, "export")) { + FILE *h = VCWD_FOPEN(input->argv[2]->string, "w+"); + if (h) { + phpdbg_export_breakpoints(h TSRMLS_CC); + fclose(h); + } else phpdbg_error("Failed to open %s", input->argv[1]->string); + } else { + phpdbg_error( + "Incorrect usage of source command, see help"); + } + } else { + struct stat sb; + if (VCWD_STAT(param->str, &sb) != -1) { + phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC); + } else phpdbg_error("Cannot stat %s", param->str); + } + } break; + + phpdbg_default_switch_case(); + } + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(register) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: { + zend_function *function; + char *lcname = zend_str_tolower_dup(param->str, param->len); + size_t lcname_len = strlen(lcname); + + if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) { + if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) { + zend_hash_update( + &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); + function_add_ref(function); + + phpdbg_notice( + "Registered %s", lcname); + } else { + phpdbg_error("The requested function (%s) could not be found", param->str); + } + } else { + phpdbg_error( + "The requested name (%s) is already in use", lcname); + } + + efree(lcname); + } break; + + phpdbg_default_switch_case(); + } + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(quit) /* {{{ */ +{ + /* don't allow this to loop, ever ... */ + if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + + phpdbg_destroy_input((phpdbg_input_t**)&input TSRMLS_CC); + + PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; + zend_bailout(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(clean) /* {{{ */ +{ + if (EG(in_execution)) { + phpdbg_error("Cannot clean environment while executing"); + return SUCCESS; + } + + phpdbg_notice("Cleaning Execution Environment"); + + phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files))); + + phpdbg_clean(1 TSRMLS_CC); + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(clear) /* {{{ */ +{ + phpdbg_notice("Clearing Breakpoints"); + + phpdbg_writeln("File\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE])); + phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM])); + phpdbg_writeln("Methods\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD])); + phpdbg_writeln("Oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE])); + phpdbg_writeln("File oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE])); + phpdbg_writeln("Function oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE])); + phpdbg_writeln("Method oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE])); + phpdbg_writeln("Conditionals\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND])); + + phpdbg_clear_breakpoints(TSRMLS_C); + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(aliases) /* {{{ */ +{ + const phpdbg_command_t *prompt_command = phpdbg_prompt_commands; + + phpdbg_help_header(); + phpdbg_writeln("Below are the aliased, short versions of all supported commands"); + while (prompt_command && prompt_command->name) { + if (prompt_command->alias) { + if (prompt_command->subs) { + const phpdbg_command_t *sub_command = prompt_command->subs; + phpdbg_writeln(EMPTY); + phpdbg_writeln(" %c -> %9s", prompt_command->alias, prompt_command->name); + while (sub_command && sub_command->name) { + if (sub_command->alias) { + phpdbg_writeln(" |-------- %c -> %15s\t%s", sub_command->alias, + sub_command->name, sub_command->tip); + } + ++sub_command; + } + phpdbg_writeln(EMPTY); + } else { + phpdbg_writeln(" %c -> %9s\t\t\t%s", prompt_command->alias, + prompt_command->name, prompt_command->tip); + } + } + + ++prompt_command; + } + phpdbg_help_footer(); + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(help) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: { + const phpdbg_command_t *prompt_command = phpdbg_prompt_commands; + const phpdbg_command_t *help_command = phpdbg_help_commands; + + phpdbg_help_header(); + phpdbg_writeln("To get help regarding a specific command type \"help command\""); + + phpdbg_notice("Commands"); + + while (prompt_command && prompt_command->name) { + phpdbg_writeln( + " %10s\t%s", prompt_command->name, prompt_command->tip); + ++prompt_command; + } + + phpdbg_notice("Help Commands"); + + while (help_command && help_command->name) { + phpdbg_writeln(" %10s\t%s", help_command->name, help_command->tip); + ++help_command; + } + + phpdbg_help_footer(); + } break; + + default: { + phpdbg_error( + "No help can be found for the subject \"%s\"", param->str); + } + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(quiet) /* {{{ */ +{ + switch (param->type) { + case NUMERIC_PARAM: { + if (param->num) { + PHPDBG_G(flags) |= PHPDBG_IS_QUIET; + } else { + PHPDBG_G(flags) &= ~PHPDBG_IS_QUIET; + } + phpdbg_notice("Quietness %s", + (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "enabled" : "disabled"); + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_COMMAND(list) /* {{{ */ +{ + switch (param->type) { + case NUMERIC_PARAM: + case EMPTY_PARAM: + return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS); + + case FILE_PARAM: + return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS); + + case STR_PARAM: + phpdbg_list_function_byname(param->str, param->len TSRMLS_CC); + break; + + case METHOD_PARAM: + return PHPDBG_LIST_HANDLER(method)(PHPDBG_COMMAND_ARGS); + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +int phpdbg_interactive(TSRMLS_D) /* {{{ */ +{ + int ret = SUCCESS; + phpdbg_input_t *input; + + PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE; + + input = phpdbg_read_input(NULL TSRMLS_CC); + + if (input && input->length > 0L) { + do { + switch (ret = phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) { + case FAILURE: + if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) { + phpdbg_error("Failed to execute %s!", input->string); + } + } + break; + + case PHPDBG_LEAVE: + case PHPDBG_FINISH: + case PHPDBG_UNTIL: + case PHPDBG_NEXT: { + if (!EG(in_execution)) { + phpdbg_error("Not running"); + } + goto out; + } + } + + phpdbg_destroy_input(&input TSRMLS_CC); + } while ((input = phpdbg_read_input(NULL TSRMLS_CC)) && (input->length > 0L)); + + if (input && !input->length) + goto last; + + } else { +last: + if (PHPDBG_G(lcmd)) { + ret = PHPDBG_G(lcmd)->handler( + &PHPDBG_G(lparam), input TSRMLS_CC); + goto out; + } + } + +out: + phpdbg_destroy_input(&input TSRMLS_CC); + + if (EG(in_execution)) { + phpdbg_restore_frame(TSRMLS_C); + } + + PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE; + + return ret; +} /* }}} */ + +void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */ +{ + /* this is implicitly required */ + if (PHPDBG_G(ops)) { + destroy_op_array(PHPDBG_G(ops) TSRMLS_CC); + efree(PHPDBG_G(ops)); + PHPDBG_G(ops) = NULL; + } + + if (full) { + PHPDBG_G(flags) |= PHPDBG_IS_CLEANING; + + zend_bailout(); + } +} /* }}} */ + +static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_array, zend_bool nested TSRMLS_DC) /* {{{ */ +{ +#if PHP_VERSION_ID >= 50500 + return zend_create_execute_data_from_op_array(op_array, nested TSRMLS_CC); +#else + +#undef EX +#define EX(element) execute_data->element +#undef EX_CV +#define EX_CV(var) EX(CVs)[var] +#undef EX_CVs +#define EX_CVs() EX(CVs) +#undef EX_T +#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset)) +#undef EX_Ts +#define EX_Ts() EX(Ts) + + zend_execute_data *execute_data = (zend_execute_data *)zend_vm_stack_alloc( + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) + + ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC); + + EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))); + memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var); + EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2))); + EX(fbc) = NULL; + EX(called_scope) = NULL; + EX(object) = NULL; + EX(old_error_reporting) = NULL; + EX(op_array) = op_array; + EX(symbol_table) = EG(active_symbol_table); + EX(prev_execute_data) = EG(current_execute_data); + EG(current_execute_data) = execute_data; + EX(nested) = nested; + + if (!op_array->run_time_cache && op_array->last_cache_slot) { + op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); + } + + if (op_array->this_var != -1 && EG(This)) { + Z_ADDREF_P(EG(This)); /* For $this pointer */ + if (!EG(active_symbol_table)) { + EX_CV(op_array->this_var) = (zval**)EX_CVs() + (op_array->last_var + op_array->this_var); + *EX_CV(op_array->this_var) = EG(This); + } else { + if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX_CV(op_array->this_var))==FAILURE) { + Z_DELREF_P(EG(This)); + } + } + } + + EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; + EG(opline_ptr) = &EX(opline); + + EX(function_state).function = (zend_function *) op_array; + EX(function_state).arguments = NULL; + + return execute_data; +#endif +} /* }}} */ + +#if PHP_VERSION_ID >= 50500 +void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ +{ +#else +void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC) /* {{{ */ +{ + long long flags = 0; + zend_ulong address = 0L; + zend_execute_data *execute_data; + zend_bool nested = 0; +#endif + zend_bool original_in_execution = EG(in_execution); + HashTable vars; + +#if PHP_VERSION_ID < 50500 + if (EG(exception)) { + return; + } +#endif + + EG(in_execution) = 1; + +#if PHP_VERSION_ID >= 50500 + if (0) { +zend_vm_enter: + execute_data = phpdbg_create_execute_data(EG(active_op_array), 1 TSRMLS_CC); + } + zend_hash_init(&vars, EG(active_op_array)->last, NULL, NULL, 0); +#else +zend_vm_enter: + execute_data = phpdbg_create_execute_data(op_array, nested TSRMLS_CC); + nested = 1; + zend_hash_init(&vars, EG(active_op_array)->last, NULL, NULL, 0); +#endif + + while (1) { + + if ((PHPDBG_G(flags) & PHPDBG_BP_RESOLVE_MASK)) { + /* resolve nth opline breakpoints */ + phpdbg_resolve_op_array_breaks(EG(active_op_array) TSRMLS_CC); + } + +#ifdef ZEND_WIN32 + if (EG(timed_out)) { + zend_timeout(0); + } +#endif + +#define DO_INTERACTIVE() do { \ + if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \ + phpdbg_list_file( \ + zend_get_executed_filename(TSRMLS_C), \ + 3, \ + zend_get_executed_lineno(TSRMLS_C)-1, \ + zend_get_executed_lineno(TSRMLS_C) \ + TSRMLS_CC \ + ); \ + } \ + \ + do { \ + switch (phpdbg_interactive(TSRMLS_C)) { \ + case PHPDBG_LEAVE: \ + case PHPDBG_FINISH: \ + case PHPDBG_UNTIL: \ + case PHPDBG_NEXT:{ \ + goto next; \ + } \ + } \ + } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); \ +} while (0) + + /* allow conditional breakpoints and + initialization to access the vm uninterrupted */ + if ((PHPDBG_G(flags) & PHPDBG_IN_COND_BP) || + (PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) { + /* skip possible breakpoints */ + goto next; + } + + /* perform seek operation */ + if (PHPDBG_G(flags) & PHPDBG_SEEK_MASK) { + /* current address */ + zend_ulong address = (zend_ulong) execute_data->opline; + + /* run to next line */ + if (PHPDBG_G(flags) & PHPDBG_IN_UNTIL) { + if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { + PHPDBG_G(flags) &= ~PHPDBG_IN_UNTIL; + zend_hash_clean( + &PHPDBG_G(seek)); + } else { + /* skip possible breakpoints */ + goto next; + } + } + + /* run to finish */ + if (PHPDBG_G(flags) & PHPDBG_IN_FINISH) { + if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { + PHPDBG_G(flags) &= ~PHPDBG_IN_FINISH; + zend_hash_clean( + &PHPDBG_G(seek)); + } + /* skip possible breakpoints */ + goto next; + } + + /* break for leave */ + if (PHPDBG_G(flags) & PHPDBG_IN_LEAVE) { + if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { + PHPDBG_G(flags) &= ~PHPDBG_IN_LEAVE; + zend_hash_clean( + &PHPDBG_G(seek)); + phpdbg_notice( + "Breaking for leave at %s:%u", + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C) + ); + DO_INTERACTIVE(); + } else { + /* skip possible breakpoints */ + goto next; + } + } + } + + /* not while in conditionals */ + phpdbg_print_opline_ex( + execute_data, &vars, 0 TSRMLS_CC); + + /* search for breakpoints */ + { + phpdbg_breakbase_t *brake; + + if ((PHPDBG_G(flags) & PHPDBG_BP_MASK) && + (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC))) { + phpdbg_hit_breakpoint( + brake, 1 TSRMLS_CC); + DO_INTERACTIVE(); + } + } + + if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) { + DO_INTERACTIVE(); + } + +next: + if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { + phpdbg_writeln(EMPTY); + phpdbg_notice("Program received signal SIGINT"); + PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED; + DO_INTERACTIVE(); + } + + PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC); + + if (PHPDBG_G(vmret) > 0) { + switch (PHPDBG_G(vmret)) { + case 1: + EG(in_execution) = original_in_execution; + zend_hash_destroy(&vars); + return; + case 2: +#if PHP_VERSION_ID < 50500 + op_array = EG(active_op_array); +#endif + zend_hash_destroy(&vars); + goto zend_vm_enter; + break; + case 3: + execute_data = EG(current_execute_data); + break; + default: + break; + } + } + } + zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen"); +} /* }}} */ diff --git a/phpdbg_prompt.h b/phpdbg_prompt.h new file mode 100644 index 0000000000..e6706c7d5b --- /dev/null +++ b/phpdbg_prompt.h @@ -0,0 +1,68 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_PROMPT_H +#define PHPDBG_PROMPT_H + +/* {{{ */ +void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC); +void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC); +int phpdbg_interactive(TSRMLS_D); +int phpdbg_compile(TSRMLS_D); +void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */ + +/* {{{ phpdbg command handlers */ +PHPDBG_COMMAND(exec); +PHPDBG_COMMAND(compile); +PHPDBG_COMMAND(step); +PHPDBG_COMMAND(next); +PHPDBG_COMMAND(run); +PHPDBG_COMMAND(eval); +PHPDBG_COMMAND(until); +PHPDBG_COMMAND(finish); +PHPDBG_COMMAND(leave); +PHPDBG_COMMAND(frame); +PHPDBG_COMMAND(print); +PHPDBG_COMMAND(break); +PHPDBG_COMMAND(back); +PHPDBG_COMMAND(list); +PHPDBG_COMMAND(info); +PHPDBG_COMMAND(clean); +PHPDBG_COMMAND(clear); +PHPDBG_COMMAND(help); +PHPDBG_COMMAND(quiet); +PHPDBG_COMMAND(aliases); +PHPDBG_COMMAND(shell); +PHPDBG_COMMAND(set); +PHPDBG_COMMAND(source); +PHPDBG_COMMAND(register); +PHPDBG_COMMAND(quit); /* }}} */ + +/* {{{ prompt commands */ +extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */ + +/* {{{ */ +#if PHP_VERSION_ID >= 50500 +void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC); +#else +void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC); +#endif /* }}} */ + +#endif /* PHPDBG_PROMPT_H */ diff --git a/phpdbg_set.c b/phpdbg_set.c new file mode 100644 index 0000000000..2472e1868c --- /dev/null +++ b/phpdbg_set.c @@ -0,0 +1,208 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg.h" +#include "phpdbg_cmd.h" +#include "phpdbg_set.h" +#include "phpdbg_utils.h" +#include "phpdbg_bp.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_SET(prompt) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: + phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C)); + break; + + case STR_PARAM: + phpdbg_set_prompt(param->str TSRMLS_CC); + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_SET(break) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: + phpdbg_writeln("%s", + PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); + break; + + case STR_PARAM: + if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) { + phpdbg_enable_breakpoints(TSRMLS_C); + } else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) { + phpdbg_disable_breakpoints(TSRMLS_C); + } + break; + + case NUMERIC_PARAM: { + if (input->argc > 2) { + if (phpdbg_argv_is(2, "on")) { + phpdbg_enable_breakpoint(param->num TSRMLS_CC); + } else if (phpdbg_argv_is(2, "off")) { + phpdbg_disable_breakpoint(param->num TSRMLS_CC); + } + } else { + phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC); + if (brake) { + phpdbg_writeln( + "%s", brake->disabled ? "off" : "on"); + } else { + phpdbg_error("Failed to find breakpoint #%lx", param->num); + } + } + } break; + + default: + phpdbg_error( + "set break used incorrectly: set break [id] "); + } + + return SUCCESS; +} /* }}} */ + +#ifndef _WIN32 +PHPDBG_SET(color) /* {{{ */ +{ + if ((param->type == STR_PARAM) && (input->argc == 3)) { + const phpdbg_color_t *color = phpdbg_get_color( + input->argv[2]->string, input->argv[2]->length TSRMLS_CC); + int element = PHPDBG_COLOR_INVALID; + + /* @TODO(anyone) make this consistent with other set commands */ + if (color) { + if (phpdbg_argv_is(1, "prompt")) { + phpdbg_notice( + "setting prompt color to %s (%s)", color->name, color->code); + element = PHPDBG_COLOR_PROMPT; + if (PHPDBG_G(prompt)[1]) { + free(PHPDBG_G(prompt)[1]); + PHPDBG_G(prompt)[1]=NULL; + } + } else if (phpdbg_argv_is(1, "error")) { + phpdbg_notice( + "setting error color to %s (%s)", color->name, color->code); + element = PHPDBG_COLOR_ERROR; + + } else if (phpdbg_argv_is(1, "notice")) { + phpdbg_notice( + "setting notice color to %s (%s)", color->name, color->code); + element = PHPDBG_COLOR_NOTICE; + + } else goto usage; + + /* set color for element */ + phpdbg_set_color(element, color TSRMLS_CC); + } else { + phpdbg_error( + "Failed to find the requested color (%s)", input->argv[2]->string); + } + } else { +usage: + phpdbg_error( + "set color used incorrectly: set color "); + } + return SUCCESS; +} /* }}} */ + +PHPDBG_SET(colors) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: { + phpdbg_writeln( + "%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); + goto done; + } + + case STR_PARAM: { + if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) { + PHPDBG_G(flags) |= PHPDBG_IS_COLOURED; + goto done; + } else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) { + PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED; + goto done; + } + } + + default: + phpdbg_error( + "set colors used incorrectly: set colors "); + } + +done: + return SUCCESS; +} /* }}} */ +#endif + +PHPDBG_SET(oplog) /* {{{ */ +{ + switch (param->type) { + case EMPTY_PARAM: + phpdbg_notice( + "Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled"); + break; + + case NUMERIC_PARAM: switch (param->num) { + case 1: + phpdbg_error( + "An output file must be provided to enable oplog"); + break; + + case 0: { + if (PHPDBG_G(oplog)) { + phpdbg_notice("Disabling oplog"); + fclose( + PHPDBG_G(oplog)); + } else { + phpdbg_error("Oplog is not enabled!"); + } + } break; + } break; + + case STR_PARAM: { + /* open oplog */ + FILE *old = PHPDBG_G(oplog); + + PHPDBG_G(oplog) = fopen(param->str, "w+"); + if (!PHPDBG_G(oplog)) { + phpdbg_error("Failed to open %s for oplog", param->str); + PHPDBG_G(oplog) = old; + } else { + if (old) { + phpdbg_notice("Closing previously open oplog"); + fclose(old); + } + phpdbg_notice("Successfully opened oplog %s", param->str); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + diff --git a/phpdbg_set.h b/phpdbg_set.h new file mode 100644 index 0000000000..1c48786c66 --- /dev/null +++ b/phpdbg_set.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_SET_H +#define PHPDBG_SET_H + +#include "phpdbg_cmd.h" + +#define PHPDBG_SET(name) PHPDBG_COMMAND(set_##name) + +PHPDBG_SET(prompt); +#ifndef _WIN32 +PHPDBG_SET(color); +PHPDBG_SET(colors); +#endif +PHPDBG_SET(oplog); +PHPDBG_SET(break); + +static const phpdbg_command_t phpdbg_set_commands[] = { + PHPDBG_COMMAND_D_EX(prompt, "usage: set prompt ", 'p', set_prompt, NULL, 0), +#ifndef _WIN32 + PHPDBG_COMMAND_D_EX(color, "usage: set color ", 'c', set_color, NULL, 1), + PHPDBG_COMMAND_D_EX(colors, "usage: set colors ", 'C', set_colors, NULL, 1), +#endif + PHPDBG_COMMAND_D_EX(oplog, "usage: set oplog ", 'O', set_oplog, NULL, 0), + PHPDBG_COMMAND_D_EX(break, "usage: set break [id] ", 'b', set_break, NULL, 0), + PHPDBG_END_COMMAND +}; + +#endif /* PHPDBG_SET_H */ diff --git a/phpdbg_utils.c b/phpdbg_utils.c new file mode 100644 index 0000000000..86c17a71be --- /dev/null +++ b/phpdbg_utils.c @@ -0,0 +1,386 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include +#include +#include +#include "zend.h" +#include "php.h" +#include "spprintf.h" +#include "phpdbg.h" +#include "phpdbg_opcode.h" +#include "phpdbg_utils.h" + +#ifdef _WIN32 +# include "win32/time.h" +#endif + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +/* {{{ color structures */ +const static phpdbg_color_t colors[] = { + PHPDBG_COLOR_D("none", "0;0"), + + PHPDBG_COLOR_D("white", "0;64"), + PHPDBG_COLOR_D("white-bold", "1;64"), + PHPDBG_COLOR_D("white-underline", "4;64"), + PHPDBG_COLOR_D("red", "0;31"), + PHPDBG_COLOR_D("red-bold", "1;31"), + PHPDBG_COLOR_D("red-underline", "4;31"), + PHPDBG_COLOR_D("green", "0;32"), + PHPDBG_COLOR_D("green-bold", "1;32"), + PHPDBG_COLOR_D("green-underline", "4;32"), + PHPDBG_COLOR_D("yellow", "0;33"), + PHPDBG_COLOR_D("yellow-bold", "1;33"), + PHPDBG_COLOR_D("yellow-underline", "4;33"), + PHPDBG_COLOR_D("blue", "0;34"), + PHPDBG_COLOR_D("blue-bold", "1;34"), + PHPDBG_COLOR_D("blue-underline", "4;34"), + PHPDBG_COLOR_D("purple", "0;35"), + PHPDBG_COLOR_D("purple-bold", "1;35"), + PHPDBG_COLOR_D("purple-underline", "4;35"), + PHPDBG_COLOR_D("cyan", "0;36"), + PHPDBG_COLOR_D("cyan-bold", "1;36"), + PHPDBG_COLOR_D("cyan-underline", "4;36"), + PHPDBG_COLOR_D("black", "0;30"), + PHPDBG_COLOR_D("black-bold", "1;30"), + PHPDBG_COLOR_D("black-underline", "4;30"), + PHPDBG_COLOR_END +}; /* }}} */ + +PHPDBG_API int phpdbg_is_numeric(const char *str) /* {{{ */ +{ + if (!str) + return 0; + + for (; *str; str++) { + if (isspace(*str) || *str == '-') { + continue; + } + return isdigit(*str); + } + return 0; +} /* }}} */ + +PHPDBG_API int phpdbg_is_empty(const char *str) /* {{{ */ +{ + if (!str) + return 1; + + for (; *str; str++) { + if (isspace(*str)) { + continue; + } + return 0; + } + return 1; +} /* }}} */ + +PHPDBG_API int phpdbg_is_addr(const char *str) /* {{{ */ +{ + return str[0] && str[1] && memcmp(str, "0x", 2) == 0; +} /* }}} */ + +PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class, char **method) /* {{{ */ +{ + char *sep = NULL; + + if (strstr(str, "#") != NULL) + return 0; + + if (strstr(str, " ") != NULL) + return 0; + + sep = strstr(str, "::"); + + if (!sep || sep == str || sep+2 == str+len-1) { + return 0; + } + + if (class != NULL) { + + if (str[0] == '\\') { + str++; + len--; + } + + *class = estrndup(str, sep - str); + (*class)[sep - str] = 0; + } + + if (method != NULL) { + *method = estrndup(sep+2, str + len - (sep + 2)); + } + + return 1; +} /* }}} */ + +PHPDBG_API char *phpdbg_resolve_path(const char *path TSRMLS_DC) /* {{{ */ +{ + char resolved_name[MAXPATHLEN]; + + if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) { + return NULL; + } + + return estrdup(resolved_name); +} /* }}} */ + +PHPDBG_API const char *phpdbg_current_file(TSRMLS_D) /* {{{ */ +{ + const char *file = zend_get_executed_filename(TSRMLS_C); + + if (memcmp(file, "[no active file]", sizeof("[no active file]")) == 0) { + return PHPDBG_G(exec); + } + + return file; +} /* }}} */ + +PHPDBG_API const zend_function *phpdbg_get_function(const char *fname, const char *cname TSRMLS_DC) /* {{{ */ +{ + zend_function *func = NULL; + size_t fname_len = strlen(fname); + char *lcname = zend_str_tolower_dup(fname, fname_len); + + if (cname) { + zend_class_entry **ce; + size_t cname_len = strlen(cname); + char *lc_cname = zend_str_tolower_dup(cname, cname_len); + int ret = zend_lookup_class(lc_cname, cname_len, &ce TSRMLS_CC); + + efree(lc_cname); + + if (ret == SUCCESS) { + zend_hash_find(&(*ce)->function_table, lcname, fname_len+1, + (void**)&func); + } + } else { + zend_hash_find(EG(function_table), lcname, fname_len+1, + (void**)&func); + } + + efree(lcname); + return func; +} /* }}} */ + +PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{{ */ +{ + const char *p = str; + char *new = NULL; + + while (p && isspace(*p)) { + ++p; + --len; + } + + while (*p && isspace(*(p + len -1))) { + --len; + } + + if (len == 0) { + new = estrndup("", sizeof("")); + *new_len = 0; + } else { + new = estrndup(p, len); + *(new + len) = '\0'; + + if (new_len) { + *new_len = len; + } + } + + return new; + +} /* }}} */ + +PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */ +{ + int rc = 0; + char *buffer = NULL; + va_list args; + + if (format != NULL && strlen(format) > 0L) { + va_start(args, format); + vspprintf(&buffer, 0, format, args); + va_end(args); + } + + /* TODO(anyone) colours */ + + switch (type) { + case P_ERROR: + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + rc = fprintf(fp, + "\033[%sm[%s]\033[0m\n", + PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer); + } else { + rc = fprintf(fp, "[%s]\n", buffer); + } + break; + + case P_NOTICE: + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + rc = fprintf(fp, + "\033[%sm[%s]\033[0m\n", + PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer); + } else { + rc = fprintf(fp, "[%s]\n", buffer); + } + break; + + case P_WRITELN: { + if (buffer) { + rc = fprintf(fp, "%s\n", buffer); + } else { + rc = fprintf(fp, "\n"); + } + } break; + + case P_WRITE: + if (buffer) { + rc = fprintf(fp, "%s", buffer); + } + break; + + /* no formatting on logging output */ + case P_LOG: + if (buffer) { + struct timeval tp; + if (gettimeofday(&tp, NULL) == SUCCESS) { + rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer); + } else { + rc = FAILURE; + } + } + break; + } + + if (buffer) { + efree(buffer); + } + + return rc; +} /* }}} */ + +PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */ + int rc = 0; + + va_list args; + struct timeval tp; + + va_start(args, fmt); + if (gettimeofday(&tp, NULL) == SUCCESS) { + char friendly[100]; + char *format = NULL, *buffer = NULL; + + strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tp.tv_sec)); + asprintf( + &buffer, friendly, tp.tv_usec/1000); + asprintf( + &format, "[%s]: %s\n", buffer, fmt); + rc = vfprintf( + fp, format, args); + + free(format); + free(buffer); + } + va_end(args); + + return rc; +} /* }}} */ + +PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */ +{ + const phpdbg_color_t *color = colors; + + while (color && color->name) { + if (name_length == color->name_length && + memcmp(name, color->name, name_length) == SUCCESS) { + phpdbg_debug( + "phpdbg_get_color(%s, %lu): %s", name, name_length, color->code); + return color; + } + ++color; + } + + phpdbg_debug( + "phpdbg_get_color(%s, %lu): failed", name, name_length); + + return NULL; +} /* }}} */ + +PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC) /* {{{ */ +{ + PHPDBG_G(colors)[element] = color; +} /* }}} */ + +PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC) /* {{{ */ +{ + const phpdbg_color_t *color = phpdbg_get_color(name, name_length TSRMLS_CC); + + if (color) { + phpdbg_set_color(element, color TSRMLS_CC); + } else PHPDBG_G(colors)[element] = colors; +} /* }}} */ + +PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D) /* {{{ */ +{ + return colors; +} /* }}} */ + +PHPDBG_API void phpdbg_set_prompt(const char *prompt TSRMLS_DC) /* {{{ */ +{ + /* free formatted prompt */ + if (PHPDBG_G(prompt)[1]) { + free(PHPDBG_G(prompt)[1]); + PHPDBG_G(prompt)[1] = NULL; + } + /* free old prompt */ + if (PHPDBG_G(prompt)[0]) { + free(PHPDBG_G(prompt)[0]); + PHPDBG_G(prompt)[0] = NULL; + } + + /* copy new prompt */ + PHPDBG_G(prompt)[0] = strdup(prompt); +} /* }}} */ + +PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */ +{ + /* find cached prompt */ + if (PHPDBG_G(prompt)[1]) { + return PHPDBG_G(prompt)[1]; + } + + /* create cached prompt */ + if ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED)) { + asprintf( + &PHPDBG_G(prompt)[1], "\033[%sm%s\033[0m ", + PHPDBG_G(colors)[PHPDBG_COLOR_PROMPT]->code, + PHPDBG_G(prompt)[0]); + } else { + asprintf( + &PHPDBG_G(prompt)[1], "%s ", + PHPDBG_G(prompt)[0]); + } + + return PHPDBG_G(prompt)[1]; +} /* }}} */ diff --git a/phpdbg_utils.h b/phpdbg_utils.h new file mode 100644 index 0000000000..fbc17b78dd --- /dev/null +++ b/phpdbg_utils.h @@ -0,0 +1,110 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_UTILS_H +#define PHPDBG_UTILS_H + +/** + * Input scan functions + */ +PHPDBG_API int phpdbg_is_numeric(const char*); +PHPDBG_API int phpdbg_is_empty(const char*); +PHPDBG_API int phpdbg_is_addr(const char*); +PHPDBG_API int phpdbg_is_class_method(const char*, size_t, char**, char**); +PHPDBG_API const char *phpdbg_current_file(TSRMLS_D); +PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC); +PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*); +PHPDBG_API const zend_function *phpdbg_get_function(const char*, const char* TSRMLS_DC); + +/** + * Error/notice/formatting helpers + */ +enum { + P_ERROR = 1, + P_NOTICE, + P_WRITELN, + P_WRITE, + P_LOG +}; + +#ifdef ZTS +PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5); +#else +PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +#endif + +PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...); + +#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) +#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) +#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) +#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) +#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) + +#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__) +#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__) +#define phpdbg_writeln_ex(out, fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, fmt, ##__VA_ARGS__) +#define phpdbg_write_ex(out, fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, fmt, ##__VA_ARGS__) +#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__) + +#if PHPDBG_DEBUG +# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__) +#else +# define phpdbg_debug(fmt, ...) +#endif + +/* {{{ For writing blank lines */ +#define EMPTY NULL /* }}} */ + +/* {{{ For prompt lines */ +#define PROMPT "phpdbg>" /* }}} */ + +/* {{{ For separation */ +#define SEPARATE "------------------------------------------------" /* }}} */ + +/* {{{ Color Management */ +#define PHPDBG_COLOR_LEN 12 +#define PHPDBG_COLOR_D(color, code) \ + {color, sizeof(color)-1, code} +#define PHPDBG_COLOR_END \ + {NULL, 0L, {0}} + +#define PHPDBG_COLOR_INVALID -1 +#define PHPDBG_COLOR_PROMPT 0 +#define PHPDBG_COLOR_ERROR 1 +#define PHPDBG_COLOR_NOTICE 2 +#define PHPDBG_COLORS 3 + +typedef struct _phpdbg_color_t { + char *name; + size_t name_length; + const char code[PHPDBG_COLOR_LEN]; +} phpdbg_color_t; + +PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC); +PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC); +PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC); +PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D); /* }}} */ + +/* {{{ Prompt Management */ +PHPDBG_API void phpdbg_set_prompt(const char* TSRMLS_DC); +PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */ + +#endif /* PHPDBG_UTILS_H */ diff --git a/test.php b/test.php new file mode 100644 index 0000000000..5fdbcbe1a4 --- /dev/null +++ b/test.php @@ -0,0 +1,51 @@ +isGreat("PHP Rocks!!")); + +foreach (test(1,2) as $gen) + continue; + +echo "it works!\n"; + +if (isset($dump)) + var_dump($_SERVER); + +function phpdbg_test_ob() +{ + echo 'Start'; + ob_start(); + echo 'Hello'; + $b = ob_get_clean(); + echo 'End'; + echo $b; +} diff --git a/tests/commands/0001_basic.test b/tests/commands/0001_basic.test new file mode 100644 index 0000000000..08aa9ab664 --- /dev/null +++ b/tests/commands/0001_basic.test @@ -0,0 +1,8 @@ +####################################################### +# name: basic +# purpose: check basic functionality of phpdbg console +# expect: TEST::EXACT +# options: -rr +####################################################### +# [Nothing to execute!] +####################################################### diff --git a/tests/commands/0002_set.test b/tests/commands/0002_set.test new file mode 100644 index 0000000000..7720f94fff --- /dev/null +++ b/tests/commands/0002_set.test @@ -0,0 +1,23 @@ +################################################# +# name: set +# purpose: tests for set commands +# expect: TEST::CISTRING +# options: -rr +################################################# +# setting prompt color +# setting error color +# setting notice color +# Failed to find breakpoint #0 +# oplog disabled +# not enabled +# opened oplog test.log +# nothing +################################################# +set color prompt none +set color error none +set color notice none +set prompt promot> +set break 0 +set oplog +set oplog 0 +set oplog test.log diff --git a/tests/commands/0101_info.test b/tests/commands/0101_info.test new file mode 100644 index 0000000000..397a45c992 --- /dev/null +++ b/tests/commands/0101_info.test @@ -0,0 +1,19 @@ +################################################# +# name: info +# purpose: test info commands +# expect: TEST::FORMAT +# options: -rr +################################################# +#[User Classes (%d)] +#User Class test (3) +#|---- in phpdbginit code on line %d +################################################# +<: +class test { + public function testMethod(){} + private function testPrivateMethod(){} + protected function testProtectedMethod(){} +} +:> +info classes +q diff --git a/tests/commands/0102_print.test b/tests/commands/0102_print.test new file mode 100644 index 0000000000..de4acb7651 --- /dev/null +++ b/tests/commands/0102_print.test @@ -0,0 +1,28 @@ +################################################# +# name: print +# purpose: test print commands +# expect: TEST::FORMAT +# options: -rr +################################################# +#[User Class: test] +#Methods (3): +#L%d-%d test::testMethod() %s +# L%d %s ZEND_RETURN C%d +# L%d-%d test::testPrivateMethod() %s +# L%d %s ZEND_RETURN C%d +# L%d-%d test::testProtectedMethod() %s +# L%d %s ZEND_RETURN C%d +#[User Method testMethod] +# L%d-%d test::testMethod() %s +# L%d %s ZEND_RETURN C%d +################################################# +<: +class test { + public function testMethod(){} + private function testPrivateMethod(){} + protected function testProtectedMethod(){} +} +:> +print class test +print method test::testMethod +q diff --git a/tests/commands/0103_register.test b/tests/commands/0103_register.test new file mode 100644 index 0000000000..38841591ca --- /dev/null +++ b/tests/commands/0103_register.test @@ -0,0 +1,28 @@ +################################################# +# name: register +# purpose: test registration functions +# expect: TEST::FORMAT +# options: -rr +################################################# +#[Registered test_function] +#array(5) { +# [0]=> +# string(1) "1" +# [1]=> +# string(1) "2" +# [2]=> +# string(1) "3" +# [3]=> +# string(1) "4" +# [4]=> +# string(1) "5" +#} +################################################# +<: +function test_function() { + var_dump(func_get_args()); +} +:> +R test_function +test_function 1 2 3 4 5 +q diff --git a/tests/commands/0104_clean.test b/tests/commands/0104_clean.test new file mode 100644 index 0000000000..c7a579be17 --- /dev/null +++ b/tests/commands/0104_clean.test @@ -0,0 +1,15 @@ +################################################# +# name: clean +# purpose: test cleaning environment +# expect: TEST::FORMAT +# options: -rr +################################################# +#[Cleaning Execution Environment] +#Classes %d +#Functions %d +#Constants %d +#Includes %d +#[Nothing to execute!] +################################################# +clean +quit diff --git a/tests/commands/0105_clear.test b/tests/commands/0105_clear.test new file mode 100644 index 0000000000..b547b0d6ba --- /dev/null +++ b/tests/commands/0105_clear.test @@ -0,0 +1,18 @@ +################################################# +# name: clear +# purpose: test clearing breakpoints +# expect: TEST::FORMAT +# options: -rr +################################################# +#[Clearing Breakpoints] +#File%w%d +#Functions%w%d +#Methods%w%d +#Oplines%w%d +#File oplines%w%d +#Function oplines%w%d +#Method oplines%w%d +#Conditionals%w%d +################################################# +clear +quit diff --git a/tests/commands/0106_compile.test b/tests/commands/0106_compile.test new file mode 100644 index 0000000000..d79211ddf7 --- /dev/null +++ b/tests/commands/0106_compile.test @@ -0,0 +1,19 @@ +################################################# +# name: compile +# purpose: test compiling code +# expect: TEST::FORMAT +# options: -rr +################################################# +#[Attempting compilation of %s] +#[Success] +#Hello World +################################################# +<: +define('OUT', + tempnam(null, "phpdbg")); +file_put_contents(OUT, ""); +phpdbg_exec(OUT); +:> +compile +run +quit diff --git a/tests/run-tests.php b/tests/run-tests.php new file mode 100644 index 0000000000..1fb6fa1224 --- /dev/null +++ b/tests/run-tests.php @@ -0,0 +1,583 @@ +config = array_shift($argv); + $this->message = vsprintf( + array_shift($argv), $argv); + } + } + } + + /** + * + * @package phpdbg + * @subpackage testing + */ + class TestsConfiguration implements \ArrayAccess { + + /** + * + * @param array basic configuration + * @param array argv + */ + public function __construct($config, $cmd) { + $this->options = $config; + while (($key = array_shift($cmd))) { + switch (substr($key, 0, 1)) { + case '-': switch(substr($key, 1, 1)) { + case '-': { + $arg = substr($key, 2); + if (($e=strpos($arg, '=')) !== false) { + $key = substr($arg, 0, $e); + $value = substr($arg, $e+1); + } else { + $key = $arg; + $value = array_shift($cmd); + } + + if (isset($key) && isset($value)) { + switch ($key) { + case 'phpdbg': + case 'width': + $this->options[$key] = $value; + break; + + default: { + if (isset($config[$key])) { + if (is_array($config[$key])) { + $this->options[$key][] = $value; + } else { + $this->options[$key] = array($config[$key], $value); + } + } else { + $this->options[$key] = $value; + } + } + } + + } + } break; + + default: + $this->flags[] = substr($key, 1); + } break; + } + } + + if (!is_executable($this->options['phpdbg'])) { + throw new TestConfigurationException( + $this->options, 'phpdbg could not be found at the specified path (%s)', $this->options['phpdbg']); + } else $this->options['phpdbg'] = realpath($this->options['phpdbg']); + + $this->options['width'] = (integer) $this->options['width']; + + /* display properly, all the time */ + if ($this->options['width'] < 50) { + $this->options['width'] = 50; + } + + /* calculate column widths */ + $this->options['lwidth'] = ceil($this->options['width'] / 3); + $this->options['rwidth'] = ceil($this->options['width'] - $this->options['lwidth']) - 5; + } + + public function hasFlag($flag) { + return in_array( + $flag, $this->flags); + } + + public function offsetExists($offset) { return isset($this->options[$offset]); } + public function offsetGet($offset) { return $this->options[$offset]; } + public function offsetUnset($offset) { unset($this->options[$offset]); } + public function offsetSet($offset, $data) { $this->options[$offset] = $data; } + + protected $options = array(); + protected $flags = array(); + } + + /** + * Tests is the console programming API for the test suite + * + * @package phpdbg + * @subpackage testing + */ + class Tests { + + /** + * Construct the console object + * + * @param array basic configuration + * @param array command line + */ + public function __construct(TestsConfiguration &$config) { + $this->config = &$config; + + if ($this->config->hasFlag('help') || + $this->config->hasFlag('h')) { + $this->showUsage(); + exit; + } + } + + /** + * Find valid paths as specified by configuration + * + */ + public function findPaths($in = null) { + $paths = array(); + $where = ($in != null) ? array($in) : $this->config['path']; + + foreach ($where as &$path) { + if ($path) { + if (is_dir($path)) { + $paths[] = $path; + foreach (scandir($path) as $child) { + if ($child != '.' && $child != '..') { + $paths = array_merge( + $paths, $this->findPaths("$path/$child")); + } + } + } + } + } + + return $paths; + } + + /** + * + * @param string the path to log + */ + public function logPath($path) { + printf( + '%s [%s]%s', + str_repeat( + '-', $this->config['width'] - strlen($path)), + $path, PHP_EOL); + } + + /** + * + * @param string the path to log + */ + public function logPathStats($path) { + if (!isset($this->stats[$path])) { + return; + } + + $total = array_sum($this->stats[$path]); + + if ($total) { + @$this->totals[true] += $this->stats[$path][true]; + @$this->totals[false] += $this->stats[$path][false]; + + $stats = @sprintf( + "%d/%d %%%d", + $this->stats[$path][true], + $this->stats[$path][false], + (100 / $total) * $this->stats[$path][true]); + + printf( + '%s [%s]%s', + str_repeat( + ' ', $this->config['width'] - strlen($stats)), + $stats, PHP_EOL); + + printf("%s%s", str_repeat('-', $this->config['width']+3), PHP_EOL); + printf("%s", PHP_EOL); + } + } + + /** + * + */ + public function logStats() { + $total = array_sum($this->totals); + $stats = @sprintf( + "%d/%d %%%d", + $this->totals[true], + $this->totals[false], + (100 / $total) * $this->totals[true]); + printf( + '%s [%s]%s', + str_repeat( + ' ', $this->config['width'] - strlen($stats)), + $stats, PHP_EOL); + + } + + /** + * + */ + protected function showUsage() { + printf('usage: php %s [flags] [options]%s', $this->config['exec'], PHP_EOL); + printf('[options]:%s', PHP_EOL); + printf("\t--path\t\tadd a path to scan outside of tests directory%s", PHP_EOL); + printf("\t--width\t\tset line width%s", PHP_EOL); + printf("\t--options\toptions to pass to phpdbg%s", PHP_EOL); + printf("\t--phpdbg\tpath to phpdbg binary%s", PHP_EOL); + printf('[flags]:%s', PHP_EOL); + printf("\t-nodiff\t\tdo not write diffs on failure%s", PHP_EOL); + printf("\t-nolog\t\tdo not write logs on failure%s", PHP_EOL); + printf('[examples]:%s', PHP_EOL); + printf("\tphp %s --phpdbg=/usr/local/bin/phpdbg --path=/usr/src/phpdbg/tests --options -n%s", + $this->config['exec'], PHP_EOL); + + } + + /** + * Find valid tests at the specified path (assumed valid) + * + * @param string a valid path + */ + public function findTests($path) { + $tests = array(); + + foreach (scandir($path) as $file) { + if ($file == '.' || $file == '..') + continue; + + $test = sprintf('%s/%s', $path, $file); + + if (preg_match('~\.test$~', $test)) { + yield new Test($this->config, $test); + } + } + } + + /** + * + * @param Test the test to log + */ + public function logTest($path, Test $test) { + @$this->stats[$path][($result=$test->getResult())]++; + + printf( + "%-{$this->config['lwidth']}s %-{$this->config['rwidth']}s [%s]%s", + $test->name, + $test->purpose, + $result ? "PASS" : "FAIL", + PHP_EOL); + } + + protected $config; + } + + class Test { + /* + * Expect exact line for line match + */ + const EXACT = 0x00000001; + + /* + * Expect strpos() !== false + */ + const STRING = 0x00000010; + + /* + * Expect stripos() !== false + */ + const CISTRING = 0x00000100; + + /* + * Formatted output + */ + const FORMAT = 0x00001000; + + /** + * Format specifiers + */ + private static $format = array( + 'search' => array( + '%e', + '%s', + '%S', + '%a', + '%A', + '%w', + '%i', + '%d', + '%x', + '%f', + '%c', + '%t', + '%T' + ), + 'replace' => array( + DIR_SEP, + '[^\r\n]+', + '[^\r\n]*', + '.+', + '.*', + '\s*', + '[+-]?\d+', + '\d+', + '[0-9a-fA-F]+', + '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', + '.', + '\t', + '\t+' + ) + ); + + /** + * Constructs a new Test object given a specilized phpdbginit file + * + * @param array configuration + * @param string file + */ + public function __construct(TestsConfiguration &$config, &$file) { + if (($handle = fopen($file, 'r'))) { + while (($line = fgets($handle))) { + $trim = trim($line); + + switch (substr($trim, 0, 1)) { + case '#': if (($chunks = array_map('trim', preg_split('~:~', substr($trim, 1), 2)))) { + if (property_exists($this, $chunks[0])) { + switch ($chunks[0]) { + case 'expect': { + if ($chunks[1]) { + switch (strtoupper($chunks[1])) { + case 'TEST::EXACT': + case 'EXACT': { $this->expect = TEST::EXACT; } break; + + case 'TEST::STRING': + case 'STRING': { $this->expect = TEST::STRING; } break; + + case 'TEST::CISTRING': + case 'CISTRING': { $this->expect = TEST::CISTRING; } break; + + case 'TEST::FORMAT': + case 'FORMAT': { $this->expect = TEST::FORMAT; } break; + + default: + throw new TestConfigurationException( + $this->config, "unknown type of expectation (%s)", $chunks[1]); + } + } + } break; + + default: { + $this->$chunks[0] = $chunks[1]; + } + } + } else switch(substr($trim, 1, 1)) { + case '#': { /* do nothing */ } break; + + default: { + $line = preg_replace( + "~(\r\n)~", "\n", substr($trim, 1)); + + $line = trim($line); + + switch ($this->expect) { + case TEST::FORMAT: + $this->match[] = str_replace( + self::$format['search'], + self::$format['replace'], preg_quote($line)); + break; + + default: $this->match[] = $line; + } + } + } + } break; + + default: + break 2; + } + } + fclose($handle); + + $this->config = &$config; + $this->file = &$file; + } + } + + /** + * Obvious!! + * + */ + public function getResult() { + $options = sprintf( + '-i%s -qb', $this->file); + + if ($this->options) { + $options = sprintf( + '%s %s %s', + $options, + $this->config['options'], + $this->options + ); + } else { + $options = sprintf( + '%s %s', $options, $this->config['options'] + ); + } + + $result = `{$this->config['phpdbg']} {$options}`; + + if ($result) { + foreach (preg_split('~(\r|\n)~', $result) as $num => $line) { + if (!$line && !isset($this->match[$num])) + continue; + + switch ($this->expect) { + case TEST::EXACT: { + if (strcmp($line, $this->match[$num]) !== 0) { + $this->diff['wants'][$num] = &$this->match[$num]; + $this->diff['gets'][$num] = $line; + } + } continue 2; + + case TEST::STRING: { + if (strpos($line, $this->match[$num]) === false) { + $this->diff['wants'][$num] = &$this->match[$num]; + $this->diff['gets'][$num] = $line; + } + } continue 2; + + case TEST::CISTRING: { + if (stripos($line, $this->match[$num]) === false) { + $this->diff['wants'][$num] = &$this->match[$num]; + $this->diff['gets'][$num] = $line; + } + } continue 2; + + case TEST::FORMAT: { + $line = trim($line); + if (!preg_match("/^{$this->match[$num]}\$/s", $line)) { + $this->diff['wants'][$num] = &$this->match[$num]; + $this->diff['gets'][$num] = $line; + } + } continue 2; + } + } + } + + $this->writeLog($result); + $this->writeDiff(); + + return (count($this->diff) == 0); + } + + /** + * Write diff to disk if configuration allows it + * + */ + protected function writeDiff() { + $diff = sprintf( + '%s/%s.diff', + dirname($this->file), basename($this->file)); + + if (count($this->diff['wants'])) { + if (!in_array('nodiff', $this->config['flags'])) { + if (($diff = fopen($diff, 'w+'))) { + + foreach ($this->diff['wants'] as $line => $want) { + $got = $this->diff['gets'][$line]; + + fprintf( + $diff, '(%d) -%s%s', $line+1, $want, PHP_EOL); + fprintf( + $diff, '(%d) +%s%s', $line+1, $got, PHP_EOL); + } + + fclose($diff); + } + } + } else unlink($diff); + } + + /** + * Write log to disk if configuration allows it + * + */ + protected function writeLog(&$result = null) { + $log = sprintf( + '%s/%s.log', + dirname($this->file), basename($this->file)); + + if (count($this->diff) && $result) { + if (!in_array('nolog', $this->config['flags'])) { + @file_put_contents( + $log, $result); + } + } else unlink($log); + } + + public $name; + public $purpose; + public $file; + public $options; + public $expect; + + protected $match; + protected $diff; + protected $stats; + protected $totals; + } +} + +namespace { + use \phpdbg\Testing\Test; + use \phpdbg\Testing\Tests; + use \phpdbg\Testing\TestsConfiguration; + + $cwd = dirname(__FILE__); + $cmd = $_SERVER['argv']; + { + $config = new TestsConfiguration(array( + 'exec' => realpath(array_shift($cmd)), + 'phpdbg' => realpath(sprintf( + '%s/../phpdbg', $cwd + )), + 'path' => array( + realpath(dirname(__FILE__)) + ), + 'flags' => array(), + 'width' => 75 + ), $cmd); + + $tests = new Tests($config); + + foreach ($tests->findPaths() as $path) { + $tests->logPath($path); + + foreach ($tests->findTests($path) as $test) { + $tests->logTest($path, $test); + } + + $tests->logPathStats($path); + } + + $tests->logStats(); + } +} +?> diff --git a/travis/ci.sh b/travis/ci.sh new file mode 100755 index 0000000000..44d56a01ff --- /dev/null +++ b/travis/ci.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +git clone https://github.com/php/php-src +cd php-src/sapi +git clone https://github.com/krakjoe/phpdbg.git +cd ../ +./buildconf --force +./configure --disable-all --enable-phpdbg --enable-maintainer-zts +make +make test-phpdbg diff --git a/web-bootstrap.php b/web-bootstrap.php new file mode 100644 index 0000000000..7b8c5d30de --- /dev/null +++ b/web-bootstrap.php @@ -0,0 +1,64 @@ + 'localhost', + 'HTTP_CONNECTION' => 'keep-alive', + 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.65 Safari/537.36', + 'HTTP_ACCEPT_ENCODING' => 'gzip,deflate,sdch', + 'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8', + 'HTTP_COOKIE' => 'tz=Europe%2FLondon; __utma=1.347100075.1384196523.1384196523.1384196523.1; __utmc=1; __utmz=1.1384196523.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)', + 'PATH' => '/usr/local/bin:/usr/bin:/bin', + 'SERVER_SIGNATURE' => '
Apache/2.4.6 (Ubuntu) Server at phpdbg.com Port 80
', + 'SERVER_SOFTWARE' => 'Apache/2.4.6 (Ubuntu)', + 'SERVER_NAME' => 'localhost', + 'SERVER_ADDR' => '127.0.0.1', + 'SERVER_PORT' => '80', + 'REMOTE_ADDR' => '127.0.0.1', + 'DOCUMENT_ROOT' => PHPDBG_BOOTPATH, + 'REQUEST_SCHEME' => 'http', + 'CONTEXT_PREFIX' => '', + 'CONTEXT_DOCUMENT_ROOT' => PHPDBG_BOOTPATH, + 'SERVER_ADMIN' => '[no address given]', + 'SCRIPT_FILENAME' => sprintf( + '%s/%s', PHPDBG_BOOTPATH, PHPDBG_BOOTSTRAP + ), + 'REMOTE_PORT' => '47931', + 'GATEWAY_INTERFACE' => 'CGI/1.1', + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => '', + 'REQUEST_URI' => PHPDBG_BOOTSTRAPPED, + 'SCRIPT_NAME' => PHPDBG_BOOTSTRAPPED, + 'PHP_SELF' => PHPDBG_BOOTSTRAPPED, + 'REQUEST_TIME' => time(), +); + +$_GET = array(); +$_REQUEST = array(); +$_POST = array(); +$_COOKIE = array(); +$_FILES = array(); + +chdir(PHPDBG_BOOTPATH); -- cgit v1.2.1 From a1387ae0883d0d4295d9d747d684e9e8055f1f39 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Mon, 23 Dec 2013 22:36:30 +0000 Subject: credits file for phpdbg --- CREDITS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 CREDITS diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000000..036bafe1db --- /dev/null +++ b/CREDITS @@ -0,0 +1,2 @@ +phpdbg +Felipe Pena, Joe Watkins, Bob Weinand -- cgit v1.2.1 From 02352bee6055dc7e250cc4464f002f9e61c0586b Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sat, 21 Dec 2013 22:42:11 +0100 Subject: Added breaking upon fatal-ish error --- phpdbg.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/phpdbg.c b/phpdbg.c index 17193ed244..4b75ce26ca 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -438,6 +438,35 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ */ if (phpdbg_booted) { phpdbg_error("%s", message); + + switch (PG(last_error_type)) { + case E_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + case E_PARSE: + case E_RECOVERABLE_ERROR: + if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { + phpdbg_list_file( + zend_get_executed_filename(TSRMLS_C), + 3, + zend_get_executed_lineno(TSRMLS_C)-1, + zend_get_executed_lineno(TSRMLS_C) + TSRMLS_CC + ); + } + + do { + switch (phpdbg_interactive(TSRMLS_C)) { + case PHPDBG_LEAVE: + case PHPDBG_FINISH: + case PHPDBG_UNTIL: + case PHPDBG_NEXT: + return; + } + } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); + + } } else fprintf(stdout, "%s\n", message); } /* }}} */ -- cgit v1.2.1 From 31c15f0d177e503f47df22b9348796bddb08eb3b Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 23 Dec 2013 23:55:07 +0100 Subject: Fixed credits in phpdbg.* files --- phpdbg.c | 1 + phpdbg.h | 1 + 2 files changed, 2 insertions(+) diff --git a/phpdbg.c b/phpdbg.c index 4b75ce26ca..a0665a7ee5 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -14,6 +14,7 @@ +----------------------------------------------------------------------+ | Authors: Felipe Pena | | Authors: Joe Watkins | + | Authors: Bob Weinand | +----------------------------------------------------------------------+ */ diff --git a/phpdbg.h b/phpdbg.h index f0a59ce473..3a3da7636a 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -14,6 +14,7 @@ +----------------------------------------------------------------------+ | Authors: Felipe Pena | | Authors: Joe Watkins | + | Authors: Bob Weinand | +----------------------------------------------------------------------+ */ -- cgit v1.2.1 From 36f487a32cb8b9d61bbcbc37c43b7a973dbcc7f8 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 24 Dec 2013 13:11:57 +0100 Subject: Fixed #18 Errors not displaying in some configurations --- phpdbg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phpdbg.c b/phpdbg.c index a0665a7ee5..d025294f1f 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -25,6 +25,7 @@ #include "phpdbg_prompt.h" #include "phpdbg_bp.h" #include "phpdbg_break.h" +#include "phpdbg_list.h" #include "phpdbg_utils.h" #include "phpdbg_set.h" @@ -609,7 +610,8 @@ const char phpdbg_ini_hardcoded[] = "display_errors=Off\n" "log_errors=On\n" "max_execution_time=0\n" -"max_input_time=-1\n\0"; +"max_input_time=-1\n" +"error_log=\n\0"; /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */ #define INI_DEFAULT(name, value) \ -- cgit v1.2.1 From 868dbe7baffc20f964f2bc005f90e0d262e97730 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 24 Dec 2013 21:08:33 +0100 Subject: fixed incompatible pointer in phpdbg on win64 --- phpdbg_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpdbg_utils.c b/phpdbg_utils.c index 86c17a71be..7b2000da0e 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -290,8 +290,9 @@ PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */ if (gettimeofday(&tp, NULL) == SUCCESS) { char friendly[100]; char *format = NULL, *buffer = NULL; + const time_t tt = tp.tv_sec; - strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tp.tv_sec)); + strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt)); asprintf( &buffer, friendly, tp.tv_usec/1000); asprintf( -- cgit v1.2.1 From b36bae023e5e4ef190bc67d8d49f7038589233d6 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Wed, 25 Dec 2013 23:43:20 +0100 Subject: fix c89 compat --- phpdbg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index d025294f1f..fd15f80984 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -137,9 +137,8 @@ static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */ static void php_phpdbg_destroy_registered(void *data) /* {{{ */ { - TSRMLS_FETCH(); - zend_function *function = (zend_function*) data; + TSRMLS_FETCH(); destroy_zend_function( function TSRMLS_CC); -- cgit v1.2.1 From 2b111a3b14feaae1fb557a3bd675448859bcf293 Mon Sep 17 00:00:00 2001 From: krakjoe Date: Fri, 27 Dec 2013 18:03:11 +0000 Subject: update version output --- phpdbg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index fd15f80984..fb3a67747c 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -1037,11 +1037,10 @@ phpdbg_main: sapi_startup(phpdbg); phpdbg->startup(phpdbg); printf( - "phpdbg %s (built: %s %s)\nCopyright (c) 2013 %s\nPHP %s, Copyright (c) 1997-2013 The PHP Group\n%s", + "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2013 The PHP Group\n%s", PHPDBG_VERSION, __DATE__, __TIME__, - PHPDBG_AUTHORS, PHP_VERSION, get_zend_version() ); -- cgit v1.2.1 From 75bad44801d1dd66fc785ed31ffa14a6cf98f3d6 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Fri, 3 Jan 2014 11:08:10 +0800 Subject: Bump year --- phpdbg.c | 4 ++-- phpdbg.h | 2 +- phpdbg_bp.c | 2 +- phpdbg_bp.h | 2 +- phpdbg_break.c | 2 +- phpdbg_break.h | 2 +- phpdbg_cmd.c | 2 +- phpdbg_cmd.h | 2 +- phpdbg_frame.c | 2 +- phpdbg_frame.h | 2 +- phpdbg_help.c | 2 +- phpdbg_help.h | 2 +- phpdbg_info.c | 2 +- phpdbg_info.h | 2 +- phpdbg_list.c | 2 +- phpdbg_list.h | 2 +- phpdbg_opcode.c | 2 +- phpdbg_opcode.h | 2 +- phpdbg_print.c | 2 +- phpdbg_print.h | 2 +- phpdbg_prompt.c | 2 +- phpdbg_prompt.h | 2 +- phpdbg_set.c | 2 +- phpdbg_set.h | 2 +- phpdbg_utils.c | 2 +- phpdbg_utils.h | 2 +- 26 files changed, 27 insertions(+), 27 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index fb3a67747c..deb7be6e2b 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -1037,7 +1037,7 @@ phpdbg_main: sapi_startup(phpdbg); phpdbg->startup(phpdbg); printf( - "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2013 The PHP Group\n%s", + "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2014 The PHP Group\n%s", PHPDBG_VERSION, __DATE__, __TIME__, diff --git a/phpdbg.h b/phpdbg.h index 3a3da7636a..66b4f69957 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_bp.c b/phpdbg_bp.c index 69e0fa7086..511d1db57d 100644 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_bp.h b/phpdbg_bp.h index ed1b413f6d..b1a9ddf474 100644 --- a/phpdbg_bp.h +++ b/phpdbg_bp.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_break.c b/phpdbg_break.c index 1423b960e6..f56f76facd 100644 --- a/phpdbg_break.c +++ b/phpdbg_break.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_break.h b/phpdbg_break.h index 04abeb6805..f90e351d6d 100644 --- a/phpdbg_break.h +++ b/phpdbg_break.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index 9f052d6f6f..36a9d26dc2 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_cmd.h b/phpdbg_cmd.h index e779fd4b55..c86f92bb47 100644 --- a/phpdbg_cmd.h +++ b/phpdbg_cmd.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_frame.c b/phpdbg_frame.c index 24aff59dd9..de02addc1b 100644 --- a/phpdbg_frame.c +++ b/phpdbg_frame.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_frame.h b/phpdbg_frame.h index fbccd5404f..7c4574ed28 100644 --- a/phpdbg_frame.h +++ b/phpdbg_frame.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_help.c b/phpdbg_help.c index edb1265955..a02cb41c14 100644 --- a/phpdbg_help.c +++ b/phpdbg_help.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_help.h b/phpdbg_help.h index 012a1b49e7..319142cb5b 100644 --- a/phpdbg_help.h +++ b/phpdbg_help.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_info.c b/phpdbg_info.c index 1744f59215..0f4233bf30 100644 --- a/phpdbg_info.c +++ b/phpdbg_info.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_info.h b/phpdbg_info.h index 5d53812370..a6b4e3719f 100644 --- a/phpdbg_info.h +++ b/phpdbg_info.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_list.c b/phpdbg_list.c index b49be857ef..eb1091550b 100644 --- a/phpdbg_list.c +++ b/phpdbg_list.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_list.h b/phpdbg_list.h index d618027158..f9d1885eaf 100644 --- a/phpdbg_list.h +++ b/phpdbg_list.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_opcode.c b/phpdbg_opcode.c index 025d57a08d..7e64d16d92 100644 --- a/phpdbg_opcode.c +++ b/phpdbg_opcode.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_opcode.h b/phpdbg_opcode.h index 5771488e70..144442981d 100644 --- a/phpdbg_opcode.h +++ b/phpdbg_opcode.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_print.c b/phpdbg_print.c index 51edcfbf8d..c4925fe5fd 100644 --- a/phpdbg_print.c +++ b/phpdbg_print.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_print.h b/phpdbg_print.h index 1232f544d2..80010d5e7c 100644 --- a/phpdbg_print.h +++ b/phpdbg_print.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index f2f482b7ec..bb26556f5c 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_prompt.h b/phpdbg_prompt.h index e6706c7d5b..6807d88f41 100644 --- a/phpdbg_prompt.h +++ b/phpdbg_prompt.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_set.c b/phpdbg_set.c index 2472e1868c..7c4da12a46 100644 --- a/phpdbg_set.c +++ b/phpdbg_set.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_set.h b/phpdbg_set.h index 1c48786c66..120aeb34f4 100644 --- a/phpdbg_set.h +++ b/phpdbg_set.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_utils.c b/phpdbg_utils.c index 7b2000da0e..1effcfccaf 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_utils.h b/phpdbg_utils.h index fbc17b78dd..c5164c3ac3 100644 --- a/phpdbg_utils.h +++ b/phpdbg_utils.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | -- cgit v1.2.1 From 2dd38009ca2c60123a94aaecbd3e0ad4ceb4040e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Schl=C3=BCter?= Date: Sat, 18 Jan 2014 13:52:27 +0100 Subject: Merge branch 'phpdbg' into PHP-5.6 --- phpdbg.c | 66 +++++++++++++++++++++++++++++++++------------------------ phpdbg.h | 2 +- phpdbg_cmd.c | 35 +++++++++++++++++++----------- phpdbg_opcode.c | 16 ++++++++------ phpdbg_prompt.c | 20 +++++++++-------- 5 files changed, 82 insertions(+), 57 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index deb7be6e2b..e7f841c0bc 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -653,8 +653,11 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */ PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; } } else { - PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; - zend_bailout(); + /* we quit remote consoles on recv SIGINT */ + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; + zend_bailout(); + } } } /* }}} */ @@ -1198,17 +1201,17 @@ phpdbg_main: } zend_end_try(); /* initialize from file */ + PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; zend_try { - PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC); phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC); - PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; - } zend_catch { - PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; - if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { - goto phpdbg_out; - } } zend_end_try(); + PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; + + /* quit if init says so */ + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + goto phpdbg_out; + } /* step from here, not through init */ if (step) { @@ -1235,39 +1238,46 @@ phpdbg_interact: phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC); fclose(bp_tmp_fp); cleaning = 1; - goto phpdbg_out; } else { cleaning = 0; } -#ifndef _WIN32 - /* remote client disconnected */ - if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { - /* renegociate connections */ - phpdbg_open_sockets( - address, listen, &server, &socket, streams); +#ifndef _WIN32 + if (!cleaning) { + /* remote client disconnected */ + if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { - /* set streams */ - if (streams[0] && streams[1]) { - PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING; + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + /* renegociate connections */ + phpdbg_open_sockets( + address, listen, &server, &socket, streams); + + /* set streams */ + if (streams[0] && streams[1]) { + PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING; + } + + /* this must be forced */ + CG(unclean_shutdown) = 0; + } else { + /* local consoles cannot disconnect, ignore EOF */ + PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED; + } } - - /* this must be forced */ - CG(unclean_shutdown) = 0; } #endif - if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { - goto phpdbg_out; - } } zend_end_try(); - } while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); + } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); /* this must be forced */ CG(unclean_shutdown) = 0; + /* this is just helpful */ + PG(report_memleaks) = 0; + phpdbg_out: #ifndef _WIN32 - if (PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED) { + if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED; goto phpdbg_interact; } @@ -1316,7 +1326,7 @@ phpdbg_out: if (cleaning || remote) { goto phpdbg_main; } - + #ifdef ZTS /* bugggy */ /* tsrm_shutdown(); */ diff --git a/phpdbg.h b/phpdbg.h index 66b4f69957..6b7afb2370 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -149,7 +149,7 @@ #define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ #define PHPDBG_URL "http://phpdbg.com" #define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" -#define PHPDBG_VERSION "0.3.0" +#define PHPDBG_VERSION "0.3.1" #define PHPDBG_INIT_FILENAME ".phpdbginit" /* }}} */ diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index 36a9d26dc2..29424d00fe 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -467,32 +467,43 @@ PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ } if (buffered == NULL) { -#ifndef HAVE_LIBREADLINE - char buf[PHPDBG_MAX_CMD]; - if ((!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && !phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) || - !fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { - /* the user has gone away */ - phpdbg_error("Failed to read console!"); +disconnect: + if (0) { PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); zend_bailout(); return NULL; } +#ifndef HAVE_LIBREADLINE + char buf[PHPDBG_MAX_CMD]; + if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { + if (!phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) { + goto disconnect; + } + } + + /* note: EOF is ignored */ +readline: + if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { + /* the user has gone away */ + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { + goto disconnect; + } else goto readline; + } + cmd = buf; #else + /* note: EOF makes readline write prompt again in local console mode */ +readline: if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { char buf[PHPDBG_MAX_CMD]; if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { cmd = buf; - } else cmd = NULL; + } else goto disconnect; } else cmd = readline(phpdbg_get_prompt(TSRMLS_C)); if (!cmd) { - /* the user has gone away */ - phpdbg_error("Failed to read console!"); - PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); - zend_bailout(); - return NULL; + goto readline; } if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { diff --git a/phpdbg_opcode.c b/phpdbg_opcode.c index 7e64d16d92..50073eb22b 100644 --- a/phpdbg_opcode.c +++ b/phpdbg_opcode.c @@ -52,13 +52,15 @@ static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint case IS_VAR: case IS_TMP_VAR: { zend_ulong id = 0, *pid = NULL; - if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) { - id = zend_hash_num_elements(vars); - zend_hash_index_update( - vars, (zend_ulong) ops->vars - op->var, - (void**) &id, - sizeof(zend_ulong), NULL); - } else id = *pid; + if (vars != NULL) { + if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) { + id = zend_hash_num_elements(vars); + zend_hash_index_update( + vars, (zend_ulong) ops->vars - op->var, + (void**) &id, + sizeof(zend_ulong), NULL); + } else id = *pid; + } asprintf(&decode, "@%lu", id); } break; diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index bb26556f5c..cb46407957 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -551,7 +551,8 @@ PHPDBG_COMMAND(run) /* {{{ */ zend_op **orig_opline = EG(opline_ptr); zend_op_array *orig_op_array = EG(active_op_array); zval **orig_retval_ptr = EG(return_value_ptr_ptr); - + zend_bool restore = 1; + if (!PHPDBG_G(ops)) { if (phpdbg_compile(TSRMLS_C) == FAILURE) { phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec)); @@ -586,18 +587,19 @@ PHPDBG_COMMAND(run) /* {{{ */ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { phpdbg_error("Caught exit/error from VM"); - goto out; + restore = 0; } } zend_end_try(); - if (EG(exception)) { - phpdbg_handle_exception(TSRMLS_C); - } - - EG(active_op_array) = orig_op_array; - EG(opline_ptr) = orig_opline; - EG(return_value_ptr_ptr) = orig_retval_ptr; + if (restore) { + if (EG(exception)) { + phpdbg_handle_exception(TSRMLS_C); + } + EG(active_op_array) = orig_op_array; + EG(opline_ptr) = orig_opline; + EG(return_value_ptr_ptr) = orig_retval_ptr; + } } else { phpdbg_error("Nothing to execute!"); } -- cgit v1.2.1 From 137feda86a96caa368453acba9befb6c15c69d12 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sun, 19 Jan 2014 02:05:10 +0100 Subject: fix C89 compat --- phpdbg_cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index 29424d00fe..c700851243 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -459,6 +459,9 @@ PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { phpdbg_input_t *buffer = NULL; char *cmd = NULL; +#ifndef HAVE_LIBREADLINE + char buf[PHPDBG_MAX_CMD]; +#endif if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && @@ -475,7 +478,6 @@ disconnect: } #ifndef HAVE_LIBREADLINE - char buf[PHPDBG_MAX_CMD]; if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { if (!phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) { goto disconnect; -- cgit v1.2.1 From 270e487d4170b7dd36cb9fa4945532995fbe6883 Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 2 Feb 2014 13:43:43 +0000 Subject: remove use of zend directly, avoid leaks/bugs in modules etc --- phpdbg.c | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index e7f841c0bc..7c94ac19dd 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -872,6 +872,7 @@ int main(int argc, char **argv) /* {{{ */ phpdbg_main: if (!cleaning) { bp_tmp_file = malloc(L_tmpnam); + tmpnam(bp_tmp_file); if (bp_tmp_file == NULL) { phpdbg_error("Unable to create temporary file"); @@ -1117,8 +1118,7 @@ phpdbg_main: phpdbg->ini_entries = ini_entries; if (phpdbg->startup(phpdbg) == SUCCESS) { - - zend_activate(TSRMLS_C); + php_request_startup(TSRMLS_C); /* do not install sigint handlers for remote consoles */ /* sending SIGINT then provides a decent way of shutting down the server */ @@ -1186,20 +1186,11 @@ phpdbg_main: /* set default prompt */ phpdbg_set_prompt(PROMPT TSRMLS_CC); - zend_try { - zend_activate_modules(TSRMLS_C); - } zend_end_try(); - if (show_banner) { /* print blurb */ phpdbg_welcome((cleaning > 0) TSRMLS_CC); } - zend_try { - /* activate globals, they can be overwritten */ - zend_activate_auto_globals(TSRMLS_C); - } zend_end_try(); - /* initialize from file */ PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; zend_try { @@ -1269,12 +1260,6 @@ phpdbg_interact: } zend_end_try(); } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); - /* this must be forced */ - CG(unclean_shutdown) = 0; - - /* this is just helpful */ - PG(report_memleaks) = 0; - phpdbg_out: #ifndef _WIN32 if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { @@ -1297,24 +1282,14 @@ phpdbg_out: if (ini_override) { free(ini_override); } + + /* this must be forced */ + CG(unclean_shutdown) = 0; + + /* this is just helpful */ + PG(report_memleaks) = 0; - if (PG(modules_activated)) { - zend_try { - zend_deactivate_modules(TSRMLS_C); - } zend_end_try(); - } - - zend_deactivate(TSRMLS_C); - - zend_try { - zend_post_deactivate_modules(TSRMLS_C); - } zend_end_try(); - -#ifdef ZEND_SIGNALS - zend_try { - zend_signal_deactivate(TSRMLS_C); - } zend_end_try(); -#endif + php_request_shutdown((void*)0); zend_try { php_module_shutdown(TSRMLS_C); -- cgit v1.2.1 From 591e64ff5898dfcb6dcd49729546f823a6b0e775 Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 2 Feb 2014 14:04:47 +0000 Subject: update version --- phpdbg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpdbg.h b/phpdbg.h index 6b7afb2370..68c505ca63 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -149,7 +149,7 @@ #define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ #define PHPDBG_URL "http://phpdbg.com" #define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" -#define PHPDBG_VERSION "0.3.1" +#define PHPDBG_VERSION "0.3.2" #define PHPDBG_INIT_FILENAME ".phpdbginit" /* }}} */ -- cgit v1.2.1 From 1deeec0ba870b94d10f4a909193b4c47bc7a028d Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 2 Feb 2014 14:42:31 +0000 Subject: better use of tmpnam/mkstemp --- phpdbg.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index 7c94ac19dd..9341ad35a5 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -831,7 +831,13 @@ int main(int argc, char **argv) /* {{{ */ zend_bool remote = 0; int run = 0; int step = 0; - char *bp_tmp_file; + +#ifdef _WIN32 + char *bp_tmp_file = NULL; +#else + char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX"; +#endif + #ifndef _WIN32 char *address; int listen[2]; @@ -871,10 +877,23 @@ int main(int argc, char **argv) /* {{{ */ phpdbg_main: if (!cleaning) { + +#ifdef _WIN32 bp_tmp_file = malloc(L_tmpnam); - tmpnam(bp_tmp_file); - if (bp_tmp_file == NULL) { + if (bp_tmp_file) { + if (!tmpnam(bp_tmp_file)) { + free(bp_tmp_file); + bp_tmp_file = NULL; + } + } +#else + if (!mkstemp(bp_tmp_file)) { + memset(bp_tmp_file, 0, sizeof(bp_tmp_file)); + } +#endif + + if (!bp_tmp_file) { phpdbg_error("Unable to create temporary file"); } } @@ -1317,7 +1336,11 @@ phpdbg_out: free(sapi_name); } +#ifdef _WIN32 free(bp_tmp_file); +#else + unlink(bp_tmp_file); +#endif return 0; } /* }}} */ -- cgit v1.2.1 From 395a936397992ea3ad70f3a4832be0a18716fb1f Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 2 Feb 2014 14:50:32 +0000 Subject: woops --- phpdbg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index 9341ad35a5..6cb1645e65 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -892,9 +892,11 @@ phpdbg_main: memset(bp_tmp_file, 0, sizeof(bp_tmp_file)); } #endif - + if (!bp_tmp_file) { - phpdbg_error("Unable to create temporary file"); + phpdbg_error( + "Unable to create temporary file"); + return 1; } } ini_entries = NULL; -- cgit v1.2.1 From d260b5d2401a84c591ff0ded4e9d85afe06919c3 Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 2 Feb 2014 14:58:39 +0000 Subject: another patch from upstream --- phpdbg_cmd.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index c700851243..1d78c53321 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -479,7 +479,7 @@ disconnect: #ifndef HAVE_LIBREADLINE if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { - if (!phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) { + if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) { goto disconnect; } } @@ -595,6 +595,8 @@ PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *in (command->alias == *input->argv[0]->string))) { phpdbg_param_t param; + phpdbg_command_t *initial_last_cmd; + phpdbg_param_t initial_last_param; param.type = EMPTY_PARAM; @@ -657,15 +659,20 @@ PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *in } } + initial_last_param = PHPDBG_G(lparam); + initial_last_cmd = (phpdbg_command_t *)PHPDBG_G(lcmd); + PHPDBG_G(lparam) = param; + PHPDBG_G(lcmd) = (phpdbg_command_t *)command; + rc = command->handler(¶m, input TSRMLS_CC); /* only set last command when it is worth it! */ - if ((rc != FAILURE) && - !(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) { - PHPDBG_G(lcmd) = (phpdbg_command_t*) command; - phpdbg_clear_param( - &PHPDBG_G(lparam) TSRMLS_CC); - PHPDBG_G(lparam) = param; + if (rc != FAILURE && !(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) { + phpdbg_clear_param(&initial_last_param TSRMLS_CC); + } else if (PHPDBG_G(lcmd) == command && !memcmp(&PHPDBG_G(lparam),& initial_last_param, sizeof(phpdbg_param_t))) { + PHPDBG_G(lparam) = initial_last_param; + PHPDBG_G(lcmd) = initial_last_cmd; + phpdbg_clear_param(¶m TSRMLS_CC); } break; } -- cgit v1.2.1 From f1a6ca29fb6f2577b3d6a5202c7d5f5ec3b596ba Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 2 Feb 2014 15:10:17 +0000 Subject: clean symbols --- phpdbg_prompt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index cb46407957..529ab04194 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -566,6 +566,12 @@ PHPDBG_COMMAND(run) /* {{{ */ zend_rebuild_symbol_table(TSRMLS_C); } + /* clean up from last execution */ + zend_execute_data *ex = EG(current_execute_data); + if (ex && ex->symbol_table) { + zend_hash_clean(ex->symbol_table); + } + /* clean seek state */ PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK; zend_hash_clean( -- cgit v1.2.1 From 2462d2764a88c34cd5a34f09c7aa68d7ea5b6899 Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 2 Feb 2014 15:14:25 +0000 Subject: windows --- phpdbg_prompt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 529ab04194..f586bb5a84 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -552,6 +552,7 @@ PHPDBG_COMMAND(run) /* {{{ */ zend_op_array *orig_op_array = EG(active_op_array); zval **orig_retval_ptr = EG(return_value_ptr_ptr); zend_bool restore = 1; + zend_execute_data *ex = EG(current_execute_data); if (!PHPDBG_G(ops)) { if (phpdbg_compile(TSRMLS_C) == FAILURE) { @@ -567,7 +568,6 @@ PHPDBG_COMMAND(run) /* {{{ */ } /* clean up from last execution */ - zend_execute_data *ex = EG(current_execute_data); if (ex && ex->symbol_table) { zend_hash_clean(ex->symbol_table); } -- cgit v1.2.1 From 57294d68241589d2b4d1dec790200b21f26f3e7f Mon Sep 17 00:00:00 2001 From: Veres Lajos Date: Fri, 14 Feb 2014 17:16:17 +0200 Subject: a few typofixes --- phpdbg_help.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpdbg_help.c b/phpdbg_help.c index a02cb41c14..d2fea8d7c7 100644 --- a/phpdbg_help.c +++ b/phpdbg_help.c @@ -268,7 +268,7 @@ PHPDBG_HELP(break) /* {{{ */ phpdbg_writeln(EMPTY); phpdbg_writeln("\t%sbreak op ZEND_ADD", phpdbg_get_prompt(TSRMLS_C)); phpdbg_writeln("\t%sb O ZEND_ADD", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break on every occurence of the opcode provided"); + phpdbg_writeln("\tWill break on every occurrence of the opcode provided"); phpdbg_writeln(EMPTY); phpdbg_writeln("\t%sbreak del 1", phpdbg_get_prompt(TSRMLS_C)); phpdbg_writeln("\t%sb d 1", phpdbg_get_prompt(TSRMLS_C)); @@ -574,7 +574,7 @@ PHPDBG_HELP(options) /* {{{ */ phpdbg_writeln(" -c\t-c/my/php.ini\t\tSet php.ini file to load"); phpdbg_writeln(" -d\t-dmemory_limit=4G\tSet a php.ini directive"); phpdbg_writeln(" -n\tN/A\t\t\tDisable default php.ini"); - phpdbg_writeln(" -q\tN/A\t\t\tSupress welcome banner"); + phpdbg_writeln(" -q\tN/A\t\t\tSuppress welcome banner"); phpdbg_writeln(" -e\t-emytest.php\t\tSet execution context"); phpdbg_writeln(" -v\tN/A\t\t\tEnable oplog output"); phpdbg_writeln(" -s\tN/A\t\t\tEnable stepping"); -- cgit v1.2.1 From b20abadf90bb3948b26a37e2554441ef8e6bf38d Mon Sep 17 00:00:00 2001 From: Mateusz Kocielski Date: Tue, 18 Mar 2014 09:51:39 +0100 Subject: Fix phpdbg build on FreeBSD Added missing netinet/in.h header. --- phpdbg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/phpdbg.c b/phpdbg.c index 6cb1645e65..7e0e2bafcd 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -35,6 +35,7 @@ # include # include # include +# include # include # include #endif /* }}} */ -- cgit v1.2.1 From ea12799eff485479813a7b4a5c4c706e1f7bf415 Mon Sep 17 00:00:00 2001 From: Mateusz Kocielski Date: Tue, 18 Mar 2014 10:49:28 +0100 Subject: Fixed wrong indentation --- phpdbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpdbg.c b/phpdbg.c index 7e0e2bafcd..51a328d0b5 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -35,7 +35,7 @@ # include # include # include -# include +# include # include # include #endif /* }}} */ -- cgit v1.2.1 From 3e3dcde8d7337b981354e69216a0cbf3950e2703 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 21 Apr 2014 23:29:25 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- .gitignore | 4 +- Makefile.frag | 10 +- config.m4 | 15 +- config.w32 | 9 +- phpdbg.c | 312 +++++--- phpdbg.h | 76 +- phpdbg_bp.c | 102 +-- phpdbg_bp.h | 2 +- phpdbg_break.c | 126 +-- phpdbg_break.h | 23 +- phpdbg_btree.c | 221 ++++++ phpdbg_btree.h | 65 ++ phpdbg_cmd.c | 674 +++++++++++------ phpdbg_cmd.h | 112 +-- phpdbg_frame.c | 4 +- phpdbg_help.c | 1393 +++++++++++++++++++++------------- phpdbg_help.h | 60 +- phpdbg_info.c | 16 + phpdbg_info.h | 12 +- phpdbg_lexer.c | 2271 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ phpdbg_lexer.h | 348 +++++++++ phpdbg_lexer.l | 131 ++++ phpdbg_list.c | 187 ++--- phpdbg_list.h | 8 +- phpdbg_opcode.c | 5 + phpdbg_parser.y | 168 ++++ phpdbg_print.c | 175 +++-- phpdbg_print.h | 13 +- phpdbg_prompt.c | 883 ++++++++++----------- phpdbg_prompt.h | 13 +- phpdbg_set.c | 258 ++++--- phpdbg_set.h | 15 +- phpdbg_utils.c | 61 ++ phpdbg_utils.h | 27 +- phpdbg_watch.c | 789 +++++++++++++++++++ phpdbg_watch.h | 112 +++ phpdbg_win.c | 42 + phpdbg_win.h | 37 + test.php | 46 +- 39 files changed, 6802 insertions(+), 2023 deletions(-) create mode 100644 phpdbg_btree.c create mode 100644 phpdbg_btree.h create mode 100644 phpdbg_lexer.c create mode 100644 phpdbg_lexer.h create mode 100644 phpdbg_lexer.l create mode 100644 phpdbg_parser.y create mode 100644 phpdbg_watch.c create mode 100644 phpdbg_watch.h create mode 100644 phpdbg_win.c create mode 100644 phpdbg_win.h diff --git a/.gitignore b/.gitignore index 297efcbc42..af445861ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ .libs/ -./phpdbg +phpdbg *.lo *.o build +phpdbg_parser.c +phpdbg_parser.h diff --git a/Makefile.frag b/Makefile.frag index 5be6d5b00f..45768de2ef 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -8,6 +8,15 @@ $(BUILD_SHARED): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) $(BUILD_BINARY): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) $(BUILD_PHPDBG) +$(builddir)/sapi/phpdbg/phpdbg_lexer.lo: $(srcdir)/sapi/phpdbg/phpdbg_parser.h + +$(srcdir)/sapi/phpdbg/phpdbg_lexer.c: $(srcdir)/sapi/phpdbg/phpdbg_lexer.l + @(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date -cbdFo sapi/phpdbg/phpdbg_lexer.c sapi/phpdbg/phpdbg_lexer.l) + +$(srcdir)/sapi/phpdbg/phpdbg_parser.h: $(srcdir)/sapi/phpdbg/phpdbg_parser.c +$(srcdir)/sapi/phpdbg/phpdbg_parser.c: $(srcdir)/sapi/phpdbg/phpdbg_parser.y + @$(YACC) -p phpdbg_ -v -d $(srcdir)/sapi/phpdbg/phpdbg_parser.y -o $@ + install-phpdbg: $(BUILD_BINARY) @echo "Installing phpdbg binary: $(INSTALL_ROOT)$(bindir)/" @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir) @@ -25,4 +34,3 @@ test-phpdbg: .PHONY: clean-phpdbg test-phpdbg - diff --git a/config.m4 b/config.m4 index 274e6409d0..3534d90124 100644 --- a/config.m4 +++ b/config.m4 @@ -3,10 +3,10 @@ dnl $Id$ dnl PHP_ARG_ENABLE(phpdbg, for phpdbg support, -[ --enable-phpdbg Build phpdbg], yes, yes) +[ --enable-phpdbg Build phpdbg], no, no) PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build, -[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) +[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) if test "$PHP_PHPDBG" != "no"; then AC_DEFINE(HAVE_PHPDBG, 1, [ ]) @@ -18,17 +18,22 @@ if test "$PHP_PHPDBG" != "no"; then fi PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE" - PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c" + PHP_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" + if test "$PHP_READLINE" != "no"; then + PHPDBG_EXTRA_LIBS="-lreadline" + fi + PHP_SUBST(PHP_PHPDBG_CFLAGS) PHP_SUBST(PHP_PHPDBG_FILES) - + PHP_SUBST(PHPDBG_EXTRA_LIBS) + PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/phpdbg/Makefile.frag]) PHP_SELECT_SAPI(phpdbg, program, $PHP_PHPDBG_FILES, $PHP_PHPDBG_CFLAGS, [$(SAPI_PHPDBG_PATH)]) BUILD_BINARY="sapi/phpdbg/phpdbg" BUILD_SHARED="sapi/phpdbg/libphpdbg.la" - + BUILD_PHPDBG="\$(LIBTOOL) --mode=link \ \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \ \$(PHP_GLOBAL_OBJS) \ diff --git a/config.w32 b/config.w32 index 29031507b3..fcc2b61a87 100644 --- a/config.w32 +++ b/config.w32 @@ -1,19 +1,18 @@ -ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes'); +ARG_ENABLE('phpdbg', 'Build phpdbg', 'no'); ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); -PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c'; +PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c'; PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; PHPDBG_EXE='phpdbg.exe'; if (PHP_PHPDBG == "yes") { - /* build phpdbg binary */ SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); + DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); } if (PHP_PHPDBGS == "yes") { SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32'); ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib"); + DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); } - - diff --git a/phpdbg.c b/phpdbg.c index 51a328d0b5..064e266082 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -#ifndef ZEND_SIGNALS +#if !defined(ZEND_SIGNALS) || defined(_WIN32) # include #endif #include "phpdbg.h" @@ -28,6 +28,7 @@ #include "phpdbg_list.h" #include "phpdbg_utils.h" #include "phpdbg_set.h" +#include "zend_alloc.h" /* {{{ remote console headers */ #ifndef _WIN32 @@ -61,16 +62,15 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */ pg->exec = NULL; pg->exec_len = 0; + pg->buffer = NULL; pg->ops = NULL; pg->vmret = 0; pg->bp_count = 0; - pg->lcmd = NULL; pg->flags = PHPDBG_DEFAULT_FLAGS; pg->oplog = NULL; pg->io[PHPDBG_STDIN] = NULL; pg->io[PHPDBG_STDOUT] = NULL; pg->io[PHPDBG_STDERR] = NULL; - memset(&pg->lparam, 0, sizeof(phpdbg_param_t)); pg->frame.num = 0; } /* }}} */ @@ -145,6 +145,7 @@ static void php_phpdbg_destroy_registered(void *data) /* {{{ */ function TSRMLS_CC); } /* }}} */ + static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */ { zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0); @@ -157,7 +158,9 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0); zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0); zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0); - + + phpdbg_setup_watchpoints(TSRMLS_C); + zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0); zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0); @@ -178,7 +181,14 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]); zend_hash_destroy(&PHPDBG_G(seek)); zend_hash_destroy(&PHPDBG_G(registered)); + zend_hash_destroy(&PHPDBG_G(watchpoints)); + zend_llist_destroy(&PHPDBG_G(watchlist_mem)); + if (PHPDBG_G(buffer)) { + efree(PHPDBG_G(buffer)); + PHPDBG_G(buffer) = NULL; + } + if (PHPDBG_G(exec)) { efree(PHPDBG_G(exec)); PHPDBG_G(exec) = NULL; @@ -209,24 +219,24 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ return SUCCESS; } /* }}} */ -/* {{{ proto mixed phpdbg_exec(string context) +/* {{{ proto mixed phpdbg_exec(string context) Attempt to set the execution context for phpdbg If the execution context was set previously it is returned - If the execution context was not set previously boolean true is returned + If the execution context was not set previously boolean true is returned If the request to set the context fails, boolean false is returned, and an E_WARNING raised */ -static PHP_FUNCTION(phpdbg_exec) +static PHP_FUNCTION(phpdbg_exec) { char *exec = NULL; - zend_ulong exec_len = 0L; + int exec_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) { return; } - + { struct stat sb; zend_bool result = 1; - + if (VCWD_STAT(exec, &sb) != FAILURE) { if (sb.st_mode & (S_IFREG|S_IFLNK)) { if (PHPDBG_G(exec)) { @@ -234,11 +244,11 @@ static PHP_FUNCTION(phpdbg_exec) efree(PHPDBG_G(exec)); result = 0; } - + PHPDBG_G(exec) = estrndup(exec, exec_len); PHPDBG_G(exec_len) = exec_len; - - if (result) + + if (result) ZVAL_BOOL(return_value, 1); } else { zend_error( @@ -259,9 +269,9 @@ static PHP_FUNCTION(phpdbg_exec) static PHP_FUNCTION(phpdbg_break) { if (ZEND_NUM_ARGS() > 0) { - long type; + long type = 0; char *expr = NULL; - zend_uint expr_len = 0; + int expr_len = 0; phpdbg_param_t param; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &type, &expr, &expr_len) == FAILURE) { @@ -269,28 +279,7 @@ static PHP_FUNCTION(phpdbg_break) } phpdbg_parse_param(expr, expr_len, ¶m TSRMLS_CC); - - switch (type) { - case METHOD_PARAM: - phpdbg_do_break_method(¶m, NULL TSRMLS_CC); - break; - - case FILE_PARAM: - phpdbg_do_break_file(¶m, NULL TSRMLS_CC); - break; - - case NUMERIC_PARAM: - phpdbg_do_break_lineno(¶m, NULL TSRMLS_CC); - break; - - case STR_PARAM: - phpdbg_do_break_func(¶m, NULL TSRMLS_CC); - break; - - default: zend_error( - E_WARNING, "unrecognized parameter type %ld", type); - } - + phpdbg_do_break(¶m TSRMLS_CC); phpdbg_clear_param(¶m TSRMLS_CC); } else if (EG(current_execute_data) && EG(active_op_array)) { @@ -319,9 +308,9 @@ static PHP_FUNCTION(phpdbg_clear) /* {{{ proto void phpdbg_color(integer element, string color) */ static PHP_FUNCTION(phpdbg_color) { - long element; - char *color; - zend_uint color_len; + long element = 0L; + char *color = NULL; + int color_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) { return; @@ -341,8 +330,8 @@ static PHP_FUNCTION(phpdbg_color) /* {{{ proto void phpdbg_prompt(string prompt) */ static PHP_FUNCTION(phpdbg_prompt) { - char *prompt; - zend_uint prompt_len; + char *prompt = NULL; + int prompt_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) { return; @@ -403,9 +392,9 @@ static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) { return FAILURE; } - + phpdbg_booted=1; - + return SUCCESS; } /* }}} */ @@ -585,7 +574,6 @@ const opt_struct OPTIONS[] = { /* {{{ */ {'z', 1, "load zend_extension"}, /* phpdbg options */ {'q', 0, "no banner"}, - {'e', 1, "exec"}, {'v', 0, "disable quietness"}, {'s', 0, "enable stepping"}, {'b', 0, "boring colours"}, @@ -615,10 +603,10 @@ const char phpdbg_ini_hardcoded[] = /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */ #define INI_DEFAULT(name, value) \ - Z_SET_REFCOUNT(tmp, 0); \ - Z_UNSET_ISREF(tmp); \ - ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \ - zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL); + Z_SET_REFCOUNT(tmp, 0); \ + Z_UNSET_ISREF(tmp); \ + ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \ + zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL); void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */ { @@ -666,11 +654,11 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */ int phpdbg_open_socket(const char *interface, short port) /* {{{ */ { int fd = socket(AF_INET, SOCK_STREAM, 0); - + switch (fd) { case -1: return -1; - + default: { int reuse = 1; @@ -678,27 +666,27 @@ int phpdbg_open_socket(const char *interface, short port) /* {{{ */ case -1: close(fd); return -2; - + default: { struct sockaddr_in address; - + memset(&address, 0, sizeof(address)); - + address.sin_port = htons(port); address.sin_family = AF_INET; - + if ((*interface == '*')) { - address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_addr.s_addr = htonl(INADDR_ANY); } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) { close(fd); return -3; } - + switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) { case -1: close(fd); return -4; - + default: { listen(fd, 5); } @@ -707,28 +695,28 @@ int phpdbg_open_socket(const char *interface, short port) /* {{{ */ } } } - + return fd; } /* }}} */ static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */ -{ +{ if ((*socket)[0] >= 0) { shutdown( (*socket)[0], SHUT_RDWR); close((*socket)[0]); } - + if (streams[0]) { fclose(streams[0]); } - + if ((*socket)[1] >= 0) { shutdown( (*socket)[1], SHUT_RDWR); close((*socket)[1]); } - + if (streams[1]) { fclose(streams[1]); } @@ -798,14 +786,34 @@ int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*sock dup2((*socket)[0], fileno(stdin)); dup2((*socket)[1], fileno(stdout)); - + setbuf(stdout, NULL); streams[0] = fdopen((*socket)[0], "r"); streams[1] = fdopen((*socket)[1], "w"); - + return SUCCESS; } /* }}} */ + +void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) { + int is_handled = FAILURE; + TSRMLS_FETCH(); + + switch (sig) { + case SIGBUS: + case SIGSEGV: + is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC); + if (is_handled == FAILURE) { +#ifdef ZEND_SIGNALS + zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL TSRMLS_CC); +#else + sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL); +#endif + } + break; + } + +} #endif int main(int argc, char **argv) /* {{{ */ @@ -852,6 +860,10 @@ int main(int argc, char **argv) /* {{{ */ #endif #ifndef _WIN32 + struct sigaction signal_struct; + signal_struct.sa_sigaction = phpdbg_signal_handler; + signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER; + address = strdup("127.0.0.1"); socket[0] = -1; socket[1] = -1; @@ -888,17 +900,17 @@ phpdbg_main: bp_tmp_file = NULL; } } + + if (!bp_tmp_file) { + phpdbg_error("Unable to create temporary file"); + return 1; + } #else if (!mkstemp(bp_tmp_file)) { memset(bp_tmp_file, 0, sizeof(bp_tmp_file)); } #endif - if (!bp_tmp_file) { - phpdbg_error( - "Unable to create temporary file"); - return 1; - } } ini_entries = NULL; ini_entries_len = 0; @@ -920,8 +932,7 @@ phpdbg_main: run = 0; step = 0; sapi_name = NULL; - - + while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) { switch (opt) { case 'r': @@ -965,7 +976,7 @@ phpdbg_main: ini_entries_len += len + sizeof("=1\n\0") - 2; } } break; - + case 'z': zend_extensions_len++; if (zend_extensions) { @@ -976,16 +987,6 @@ phpdbg_main: /* begin phpdbg options */ - case 'e': { /* set execution context */ - exec_len = strlen(php_optarg); - if (exec_len) { - if (exec) { - free(exec); - } - exec = strdup(php_optarg); - } - } break; - case 'S': { /* set SAPI name */ if (sapi_name) { free(sapi_name); @@ -1001,7 +1002,7 @@ phpdbg_main: if (init_file) { free(init_file); } - + init_file_len = strlen(php_optarg); if (init_file_len) { init_file = strdup(php_optarg); @@ -1038,7 +1039,7 @@ phpdbg_main: #ifndef _WIN32 /* if you pass a listen port, we will accept input on listen port */ /* and write output to listen port * 2 */ - + case 'l': { /* set listen ports */ if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) { if (sscanf(php_optarg, "%d", &listen[0]) != 1) { @@ -1050,7 +1051,7 @@ phpdbg_main: } } } break; - + case 'a': { /* set bind address */ free(address); if (!php_optarg) { @@ -1076,6 +1077,19 @@ phpdbg_main: } break; } } + + /* set exec if present on command line */ + if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS)) + { + exec_len = strlen(argv[php_optind]); + if (exec_len) { + if (exec) { + free(exec); + } + exec = strdup(argv[php_optind]); + } + php_optind++; + } #ifndef _WIN32 /* setup remote server if necessary */ @@ -1093,7 +1107,7 @@ phpdbg_main: if (sapi_name) { phpdbg->name = sapi_name; } - + phpdbg->ini_defaults = phpdbg_ini_defaults; phpdbg->phpinfo_as_text = 1; phpdbg->php_ini_ignore_cwd = 1; @@ -1114,14 +1128,14 @@ phpdbg_main: memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded)); } ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2; - + if (zend_extensions_len) { zend_ulong zend_extension = 0L; - + while (zend_extension < zend_extensions_len) { const char *ze = zend_extensions[zend_extension]; size_t ze_len = strlen(ze); - + ini_entries = realloc( ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n")))); memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1)); @@ -1133,40 +1147,81 @@ phpdbg_main: free(zend_extensions[zend_extension]); zend_extension++; } - + free(zend_extensions); } phpdbg->ini_entries = ini_entries; - + if (phpdbg->startup(phpdbg) == SUCCESS) { - php_request_startup(TSRMLS_C); +#ifdef _WIN32 + EXCEPTION_POINTERS *xp; + __try { +#endif + zend_mm_heap *mm_heap = zend_mm_set_heap(NULL TSRMLS_CC); +#if ZEND_DEBUG + if (!mm_heap->use_zend_alloc) { + mm_heap->_malloc = malloc; + mm_heap->_realloc = realloc; + mm_heap->_free = free; +#endif + PHPDBG_G(original_free_function) = mm_heap->_free; + mm_heap->_free = phpdbg_watch_efree; + mm_heap->use_zend_alloc = 0; +#if ZEND_DEBUG + } +#endif + zend_mm_set_heap(mm_heap TSRMLS_CC); + + zend_activate(TSRMLS_C); + +#if defined(ZEND_SIGNALS) && !defined(_WIN32) + zend_try { + zend_signal_activate(TSRMLS_C); + } zend_end_try(); +#endif + +#if defined(ZEND_SIGNALS) && !defined(_WIN32) + zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try(); + zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } 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 + + if (php_request_startup(TSRMLS_C) == SUCCESS) { + int i; + + SG(request_info).argc = argc - php_optind + 1; + SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *)); + for (i = SG(request_info).argc; --i;) { + SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]); + } + SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup(""); + + php_hash_environment(TSRMLS_C); + } + + /* make sure to turn off buffer for ev command */ + php_output_activate(TSRMLS_C); + php_output_deactivate(TSRMLS_C); /* do not install sigint handlers for remote consoles */ /* sending SIGINT then provides a decent way of shutting down the server */ -#ifdef ZEND_SIGNALS -# ifndef _WIN32 +#if defined(ZEND_SIGNALS) && !defined(_WIN32) if (listen[0] < 0) { -# endif - zend_try { - zend_signal_activate(TSRMLS_C); - zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); - } zend_end_try(); -# ifndef _WIN32 + zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try(); } -# endif -#else -# ifndef _WIN32 +#elif !defined(_WIN32) if (listen[0] < 0) { -# endif +#endif signal(SIGINT, phpdbg_sigint_handler); #ifndef _WIN32 } -#endif #endif PG(modules_activated) = 0; - + /* set flags from command line */ PHPDBG_G(flags) = flags; @@ -1182,10 +1237,9 @@ phpdbg_main: PHPDBG_G(io)[PHPDBG_STDIN] = stdin; PHPDBG_G(io)[PHPDBG_STDOUT] = stdout; PHPDBG_G(io)[PHPDBG_STDERR] = stderr; - + if (exec) { /* set execution context */ - PHPDBG_G(exec) = phpdbg_resolve_path( - exec TSRMLS_CC); + PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec)); free(exec); @@ -1213,6 +1267,11 @@ phpdbg_main: phpdbg_welcome((cleaning > 0) TSRMLS_CC); } + /* auto compile */ + if (PHPDBG_G(exec)) { + phpdbg_compile(TSRMLS_C); + } + /* initialize from file */ PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; zend_try { @@ -1233,14 +1292,17 @@ phpdbg_main: if (run) { /* no need to try{}, run does it ... */ - PHPDBG_COMMAND_HANDLER(run)(NULL, NULL TSRMLS_CC); + PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); if (run > 1) { /* if -r is on the command line more than once just quit */ goto phpdbg_out; } } +/* #ifndef for making compiler shutting up */ +#ifndef _WIN32 phpdbg_interact: +#endif /* phpdbg main() */ do { zend_try { @@ -1282,21 +1344,42 @@ phpdbg_interact: } zend_end_try(); } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); -phpdbg_out: + /* this must be forced */ + CG(unclean_shutdown) = 0; + + /* this is just helpful */ + PG(report_memleaks) = 0; + #ifndef _WIN32 +phpdbg_out: if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED; goto phpdbg_interact; } #endif +#ifdef _WIN32 + } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) { + phpdbg_error("Access violation (Segementation fault) encountered\ntrying to abort cleanly..."); + } +phpdbg_out: +#endif + + { + int i; + /* free argv */ + for (i = SG(request_info).argc; --i;) { + efree(SG(request_info).argv[i]); + } + efree(SG(request_info).argv); + } + #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); } @@ -1318,6 +1401,7 @@ phpdbg_out: } zend_end_try(); sapi_shutdown(); + } if (cleaning || remote) { @@ -1331,7 +1415,7 @@ phpdbg_out: #ifndef _WIN32 if (address) { - free(address); + free(address); } #endif diff --git a/phpdbg.h b/phpdbg.h index 68c505ca63..be009e40d0 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -39,6 +39,9 @@ #include "zend_globals.h" #include "zend_ini_scanner.h" #include "zend_stream.h" +#ifndef _WIN32 +# include "zend_signal.h" +#endif #include "SAPI.h" #include #include @@ -68,6 +71,8 @@ #include "phpdbg_cmd.h" #include "phpdbg_utils.h" +#include "phpdbg_btree.h" +#include "phpdbg_watch.h" #ifdef ZTS # define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) @@ -116,23 +121,26 @@ #define PHPDBG_IN_EVAL (1<<11) #define PHPDBG_IS_STEPPING (1<<12) -#define PHPDBG_IS_QUIET (1<<13) -#define PHPDBG_IS_QUITTING (1<<14) -#define PHPDBG_IS_COLOURED (1<<15) -#define PHPDBG_IS_CLEANING (1<<16) - -#define PHPDBG_IN_UNTIL (1<<17) -#define PHPDBG_IN_FINISH (1<<18) -#define PHPDBG_IN_LEAVE (1<<19) - -#define PHPDBG_IS_REGISTERED (1<<20) -#define PHPDBG_IS_STEPONEVAL (1<<21) -#define PHPDBG_IS_INITIALIZING (1<<22) -#define PHPDBG_IS_SIGNALED (1<<23) -#define PHPDBG_IS_INTERACTIVE (1<<24) -#define PHPDBG_IS_BP_ENABLED (1<<25) -#define PHPDBG_IS_REMOTE (1<<26) -#define PHPDBG_IS_DISCONNECTED (1<<27) +#define PHPDBG_STEP_OPCODE (1<<13) +#define PHPDBG_IS_QUIET (1<<14) +#define PHPDBG_IS_QUITTING (1<<15) +#define PHPDBG_IS_COLOURED (1<<16) +#define PHPDBG_IS_CLEANING (1<<17) + +#define PHPDBG_IN_UNTIL (1<<18) +#define PHPDBG_IN_FINISH (1<<19) +#define PHPDBG_IN_LEAVE (1<<20) + +#define PHPDBG_IS_REGISTERED (1<<21) +#define PHPDBG_IS_STEPONEVAL (1<<22) +#define PHPDBG_IS_INITIALIZING (1<<23) +#define PHPDBG_IS_SIGNALED (1<<24) +#define PHPDBG_IS_INTERACTIVE (1<<25) +#define PHPDBG_IS_BP_ENABLED (1<<26) +#define PHPDBG_IS_REMOTE (1<<27) +#define PHPDBG_IS_DISCONNECTED (1<<28) + +#define PHPDBG_SHOW_REFCOUNTS (1<<29) #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) @@ -149,7 +157,7 @@ #define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ #define PHPDBG_URL "http://phpdbg.com" #define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" -#define PHPDBG_VERSION "0.3.2" +#define PHPDBG_VERSION "0.4.0" #define PHPDBG_INIT_FILENAME ".phpdbginit" /* }}} */ @@ -159,12 +167,25 @@ #define PHPDBG_STDERR 2 #define PHPDBG_IO_FDS 3 /* }}} */ + /* {{{ structs */ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */ HashTable registered; /* registered */ HashTable seek; /* seek oplines */ phpdbg_frame_t frame; /* frame */ + zend_uint last_line; /* last executed line */ + +#ifndef _WIN32 + struct sigaction old_sigsegv_signal; /* segv signal handler */ +#endif + + phpdbg_btree watchpoint_tree; /* tree with watchpoints */ + phpdbg_btree watch_HashTables; /* tree with original dtors of watchpoints */ + HashTable watchpoints; /* watchpoints */ + zend_llist watchlist_mem; /* triggered watchpoints */ + zend_bool watchpoint_hit; /* a watchpoint was hit */ + void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */ char *exec; /* file to execute */ size_t exec_len; /* size of exec */ @@ -178,11 +199,24 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) char *prompt[2]; /* prompt */ const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */ - - phpdbg_command_t *lcmd; /* last command */ - phpdbg_param_t lparam; /* last param */ + char *buffer; /* buffer */ zend_ulong flags; /* phpdbg flags */ ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ +/* the beginning (= the important part) of the _zend_mm_heap struct defined in Zend/zend_alloc.c + Needed for realizing watchpoints */ +struct _zend_mm_heap { + int use_zend_alloc; + void *(*_malloc)(size_t); + void (*_free)(void *); + void *(*_realloc)(void *, size_t); + size_t free_bitmap; + size_t large_free_bitmap; + size_t block_size; + size_t compact_size; + zend_mm_segment *segments_list; + zend_mm_storage *storage; +}; + #endif /* PHPDBG_H */ diff --git a/phpdbg_bp.c b/phpdbg_bp.c index 511d1db57d..a18316a228 100644 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@ -135,27 +135,27 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ switch (brake->type) { case PHPDBG_BREAK_FILE: { fprintf(handle, - "break file %s:%lu\n", + "break %s:%lu\n", ((phpdbg_breakfile_t*)brake)->filename, ((phpdbg_breakfile_t*)brake)->line); } break; case PHPDBG_BREAK_SYM: { fprintf(handle, - "break func %s\n", + "break %s\n", ((phpdbg_breaksymbol_t*)brake)->symbol); } break; case PHPDBG_BREAK_METHOD: { fprintf(handle, - "break method %s::%s\n", + "break %s::%s\n", ((phpdbg_breakmethod_t*)brake)->class_name, ((phpdbg_breakmethod_t*)brake)->func_name); } break; case PHPDBG_BREAK_METHOD_OPLINE: { fprintf(handle, - "break address %s::%s#%ld\n", + "break %s::%s#%ld\n", ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); @@ -163,21 +163,21 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ case PHPDBG_BREAK_FUNCTION_OPLINE: { fprintf(handle, - "break address %s#%ld\n", + "break %s#%ld\n", ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_FILE_OPLINE: { fprintf(handle, - "break address %s:%ld\n", + "break %s:#%ld\n", ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_OPCODE: { fprintf(handle, - "break op %s\n", + "break %s\n", ((phpdbg_breakop_t*)brake)->name); } break; @@ -209,7 +209,7 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ } } else { fprintf( - handle, "break on %s\n", conditional->code); + handle, "break if %s\n", conditional->code); } } break; } @@ -221,14 +221,20 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRMLS_DC) /* {{{ */ { - struct stat sb; - - if (VCWD_STAT(path, &sb) != FAILURE) { - if (sb.st_mode & (S_IFREG|S_IFLNK)) { + php_stream_statbuf ssb; + char realpath[MAXPATHLEN]; + + if (php_stream_stat_path(path, &ssb) != FAILURE) { + if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) { HashTable *broken; phpdbg_breakfile_t new_break; - size_t path_len = strlen(path); - + size_t path_len = 0L; + + if (VCWD_REALPATH(path, realpath)) { + path = realpath; + } + path_len = strlen(path); + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len, (void**)&broken) == FAILURE) { HashTable breaks; @@ -324,9 +330,9 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char PHPDBG_BREAK_MAPPING(new_break.id, class_table); } else { phpdbg_notice("Breakpoint exists at %s::%s", class_name, func_name); - } + } - efree(lcname); + efree(lcname); } /* }}} */ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ */ @@ -355,7 +361,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC) /* {{{ */ { phpdbg_breakline_t opline_break; - if (op_array->last < brake->opline_num) { + if (op_array->last <= brake->opline_num) { if (brake->class_name == NULL) { phpdbg_error("There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num); } else if (brake->func_name == NULL) { @@ -760,56 +766,26 @@ PHPDBG_API void phpdbg_set_breakpoint_expression(const char *expr, size_t expr_l } } /* }}} */ -PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */ { - if (input->argc > 3 && phpdbg_argv_is(2, "if")) { - phpdbg_breakcond_t new_break; - phpdbg_param_t new_param; - - zend_ulong expr_hash = 0L; - size_t expr_len; - const char *join = strstr(input->string, "if"); - const char *expr = (join) + sizeof("if"); - - expr_len = strlen(expr); - expr = phpdbg_trim(expr, expr_len, &expr_len); - expr_hash = zend_inline_hash_func(expr, expr_len); - - { - /* get a clean parameter from input string */ - size_t sparam_len = 0L; - char *sparam = input->string; - - sparam[ - strstr(input->string, " ") - input->string] = 0; - sparam_len = strlen(sparam); - - switch (phpdbg_parse_param(sparam, sparam_len, &new_param TSRMLS_CC)) { - case EMPTY_PARAM: - case NUMERIC_PARAM: - phpdbg_clear_param( - &new_param TSRMLS_CC); - goto usage; - - default: { /* do nothing */ } break; - } - - expr_hash += phpdbg_hash_param(&new_param TSRMLS_CC); - } - - if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], expr_hash)) { + phpdbg_breakcond_t new_break; + phpdbg_param_t *condition; + zend_ulong hash = 0L; + + if (param->next) { + condition = param->next; + hash = zend_inline_hash_func(condition->str, condition->len); + + if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash)) { phpdbg_create_conditional_break( - &new_break, &new_param, expr, expr_len, expr_hash TSRMLS_CC); + &new_break, param, + condition->str, condition->len, hash TSRMLS_CC); } else { phpdbg_notice( - "Conditional break %s exists at the specified location", expr); - } - - phpdbg_clear_param(&new_param TSRMLS_CC); - } else { -usage: - phpdbg_error("usage: break at if "); + "Conditional break %s exists at the specified location", condition->str); + } } + } /* }}} */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_array TSRMLS_DC) /* {{{ */ @@ -992,7 +968,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void*)&bp, &position) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { zval *retval = NULL; int orig_interactive = CG(interactive); zval **orig_retval = EG(return_value_ptr_ptr); diff --git a/phpdbg_bp.h b/phpdbg_bp.h index b1a9ddf474..97980e7ed7 100644 --- a/phpdbg_bp.h +++ b/phpdbg_bp.h @@ -119,7 +119,7 @@ PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const cha PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC); PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC); PHPDBG_API void phpdbg_set_breakpoint_expression(const char* expression, size_t expression_len TSRMLS_DC); -PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC); /* }}} */ +PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param TSRMLS_DC); /* }}} */ /* {{{ Breakpoint Detection API */ PHPDBG_API phpdbg_breakbase_t* phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC); /* }}} */ diff --git a/phpdbg_break.c b/phpdbg_break.c index f56f76facd..be76b22b05 100644 --- a/phpdbg_break.c +++ b/phpdbg_break.c @@ -24,132 +24,32 @@ #include "phpdbg_opcode.h" #include "phpdbg_break.h" #include "phpdbg_bp.h" +#include "phpdbg_prompt.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -PHPDBG_BREAK(file) /* {{{ */ -{ - switch (param->type) { - case FILE_PARAM: - phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - -PHPDBG_BREAK(method) /* {{{ */ -{ - switch (param->type) { - case METHOD_PARAM: - phpdbg_set_breakpoint_method(param->method.class, param->method.name TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - -PHPDBG_BREAK(address) /* {{{ */ -{ - switch (param->type) { - case ADDR_PARAM: - phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC); - break; - - case NUMERIC_METHOD_PARAM: - phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num TSRMLS_CC); - break; - - case NUMERIC_FUNCTION_PARAM: - phpdbg_set_breakpoint_function_opline(param->str, param->num TSRMLS_CC); - break; +#define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[10]) - case FILE_PARAM: - phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - -PHPDBG_BREAK(on) /* {{{ */ -{ - switch (param->type) { - case STR_PARAM: - phpdbg_set_breakpoint_expression(param->str, param->len TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ +/** + * Commands + */ +const phpdbg_command_t phpdbg_break_commands[] = { + PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c"), + PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n"), + PHPDBG_END_COMMAND +}; PHPDBG_BREAK(at) /* {{{ */ { - phpdbg_set_breakpoint_at(param, input TSRMLS_CC); - - return SUCCESS; -} /* }}} */ - -PHPDBG_BREAK(lineno) /* {{{ */ -{ - switch (param->type) { - case NUMERIC_PARAM: { - if (PHPDBG_G(exec)) { - phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC); - } else { - phpdbg_error("Execution context not set!"); - } - } break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - -PHPDBG_BREAK(func) /* {{{ */ -{ - switch (param->type) { - case STR_PARAM: - phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - -PHPDBG_BREAK(op) /* {{{ */ -{ - switch (param->type) { - case STR_PARAM: - phpdbg_set_breakpoint_opcode(param->str, param->len TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } + phpdbg_set_breakpoint_at(param TSRMLS_CC); return SUCCESS; } /* }}} */ PHPDBG_BREAK(del) /* {{{ */ { - switch (param->type) { - case NUMERIC_PARAM: { - phpdbg_delete_breakpoint(param->num TSRMLS_CC); - } break; - - phpdbg_default_switch_case(); - } + phpdbg_delete_breakpoint(param->num TSRMLS_CC); return SUCCESS; } /* }}} */ diff --git a/phpdbg_break.h b/phpdbg_break.h index f90e351d6d..dc06da62b7 100644 --- a/phpdbg_break.h +++ b/phpdbg_break.h @@ -29,30 +29,9 @@ /** * Printer Forward Declarations */ -PHPDBG_BREAK(file); -PHPDBG_BREAK(func); -PHPDBG_BREAK(method); -PHPDBG_BREAK(address); PHPDBG_BREAK(at); -PHPDBG_BREAK(op); -PHPDBG_BREAK(on); -PHPDBG_BREAK(lineno); PHPDBG_BREAK(del); -/** - * Commands - */ -static const phpdbg_command_t phpdbg_break_commands[] = { - PHPDBG_COMMAND_D_EX(file, "specify breakpoint by file:line", 'F', break_file, NULL, 1), - PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, 1), - PHPDBG_COMMAND_D_EX(method, "specify breakpoint by class::method", 'm', break_method, NULL, 1), - PHPDBG_COMMAND_D_EX(address, "specify breakpoint by address", 'a', break_address, NULL, 1), - PHPDBG_COMMAND_D_EX(op, "specify breakpoint by opcode", 'O', break_op, NULL, 1), - PHPDBG_COMMAND_D_EX(on, "specify breakpoint by condition", 'o', break_on, NULL, 1), - PHPDBG_COMMAND_D_EX(at, "specify breakpoint by location and condition", 'A', break_at, NULL, 1), - PHPDBG_COMMAND_D_EX(lineno, "specify breakpoint by line of currently executing file", 'l', break_lineno, NULL, 1), - PHPDBG_COMMAND_D_EX(del, "delete breakpoint by identifier number", 'd', break_del, NULL, 1), - PHPDBG_END_COMMAND -}; +extern const phpdbg_command_t phpdbg_break_commands[]; #endif /* PHPDBG_BREAK_H */ diff --git a/phpdbg_btree.c b/phpdbg_btree.c new file mode 100644 index 0000000000..8fc2561e04 --- /dev/null +++ b/phpdbg_btree.c @@ -0,0 +1,221 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_btree.h" +#include "phpdbg.h" + +#define CHOOSE_BRANCH(n) \ + branch = branch->branches[!!(n)]; + +#ifdef _Win32 +# define emalloc malloc +# define efree free +#endif + +/* depth in bits */ +void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth) { + tree->depth = depth; + tree->branch = NULL; + tree->count = 0; +} + +phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx) { + phpdbg_btree_branch *branch = tree->branch; + int i = tree->depth - 1; + + if (branch == NULL) { + return NULL; + } + + do { + if ((idx >> i) % 2 == 1) { + if (branch->branches[1]) { + CHOOSE_BRANCH(1); + } else { + return NULL; + } + } else { + if (branch->branches[0]) { + CHOOSE_BRANCH(0); + } else { + return NULL; + } + } + } while (i--); + + return &branch->result; +} + +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; + } + + /* 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]); + } + break; + } + /* follow branch according to bits in idx until having found an impossible branch */ + if (had_alternative_branch || (idx >> i) % 2 == 1) { + if (branch->branches[1]) { + if (branch->branches[0]) { + last_superior_i = i; + } + CHOOSE_BRANCH(1); + } else { + CHOOSE_BRANCH(0); + had_alternative_branch = 1; + } + } else { + CHOOSE_BRANCH(0); + } + } while (i--); + + return &branch->result; +} + +phpdbg_btree_position phpdbg_btree_find_between(phpdbg_btree *tree, zend_ulong lower_idx, zend_ulong higher_idx) { + phpdbg_btree_position pos; + + pos.tree = tree; + pos.end = lower_idx; + pos.cur = higher_idx; + + return pos; +} + +phpdbg_btree_result *phpdbg_btree_next(phpdbg_btree_position *pos) { + phpdbg_btree_result *result = phpdbg_btree_find_closest(pos->tree, pos->cur); + + if (result == NULL || result->idx < pos->end) { + return NULL; + } + + pos->cur = result->idx - 1; + + return result; +} + +int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, int flags) { + int i = tree->depth - 1; + phpdbg_btree_branch **branch = &tree->branch; + + do { + if (*branch == NULL) { + break; + } + branch = &(*branch)->branches[(idx >> i) % 2]; + } while (i--); + + if (*branch == NULL) { + if (!(flags & PHPDBG_BTREE_INSERT)) { + return FAILURE; + } + + { + phpdbg_btree_branch *memory = *branch = emalloc((i + 2) * sizeof(phpdbg_btree_branch)); + do { + (*branch)->branches[!((idx >> i) % 2)] = NULL; + branch = &(*branch)->branches[(idx >> i) % 2]; + *branch = ++memory; + } while (i--); + tree->count++; + } + } else if (!(flags & PHPDBG_BTREE_UPDATE)) { + return FAILURE; + } + + (*branch)->result.idx = idx; + (*branch)->result.ptr = ptr; + + return SUCCESS; +} + +int phpdbg_btree_delete(phpdbg_btree *tree, zend_ulong idx) { + int i = tree->depth; + phpdbg_btree_branch *branch = tree->branch; + int i_last_dual_branch = -1, last_dual_branch_branch; + phpdbg_btree_branch *last_dual_branch = NULL; + + goto check_branch_existence; + do { + if (branch->branches[0] && branch->branches[1]) { + last_dual_branch = branch; + i_last_dual_branch = i; + last_dual_branch_branch = (idx >> i) % 2; + } + branch = branch->branches[(idx >> i) % 2]; + +check_branch_existence: + if (branch == NULL) { + return FAILURE; + } + } while (i--); + + tree->count--; + + if (i_last_dual_branch == -1) { + efree(tree->branch); + 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]); + last_dual_branch->branches[!last_dual_branch_branch] = last_dual_branch + 1; + + branch = last_dual_branch->branches[!last_dual_branch_branch]; + for (i = i_last_dual_branch; i--;) { + 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]); + } + + last_dual_branch->branches[last_dual_branch_branch] = NULL; + } + + return SUCCESS; +} diff --git a/phpdbg_btree.h b/phpdbg_btree.h new file mode 100644 index 0000000000..5fb217db35 --- /dev/null +++ b/phpdbg_btree.h @@ -0,0 +1,65 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_BTREE_H +#define PHPDBG_BTREE_H + +#include "zend.h" + +typedef struct { + zend_ulong idx; + void *ptr; +} phpdbg_btree_result; + +typedef union _phpdbg_btree_branch phpdbg_btree_branch; +union _phpdbg_btree_branch { + phpdbg_btree_branch *branches[2]; + phpdbg_btree_result result; +}; + +typedef struct { + zend_ulong count; + zend_ulong depth; + phpdbg_btree_branch *branch; +} phpdbg_btree; + +typedef struct { + phpdbg_btree *tree; + zend_ulong cur; + zend_ulong end; +} phpdbg_btree_position; + +void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth); +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); +phpdbg_btree_result *phpdbg_btree_next(phpdbg_btree_position *pos); +int phpdbg_btree_delete(phpdbg_btree *tree, zend_ulong idx); + +#define PHPDBG_BTREE_INSERT 1 +#define PHPDBG_BTREE_UPDATE 2 +#define PHPDBG_BTREE_OVERWRITE (PHPDBG_BTREE_INSERT | PHPDBG_BTREE_UPDATE) + +int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, int flags); +#define phpdbg_btree_insert(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_INSERT) +#define phpdbg_btree_update(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_UPDATE) +#define phpdbg_btree_overwrite(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_OWERWRITE) + +#endif diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index 1d78c53321..d4ce8ebc55 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -22,12 +22,32 @@ #include "phpdbg_cmd.h" #include "phpdbg_utils.h" #include "phpdbg_set.h" +#include "phpdbg_prompt.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +static inline const char *phpdbg_command_name(const phpdbg_command_t *command, char *buffer) { + size_t pos = 0; + + if (command->parent) { + memcpy(&buffer[pos], command->parent->name, command->parent->name_len); + pos += command->parent->name_len; + memcpy(&buffer[pos], " ", sizeof(" ")-1); + pos += (sizeof(" ")-1); + } + + memcpy(&buffer[pos], command->name, command->name_len); + pos += command->name_len; + buffer[pos] = 0; + + return buffer; +} + PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */ { switch (param->type) { + case STACK_PARAM: + return "stack"; case EMPTY_PARAM: return "empty"; case ADDR_PARAM: @@ -208,10 +228,19 @@ PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **point PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest TSRMLS_DC) /* {{{ */ { switch ((dest->type = src->type)) { + case STACK_PARAM: + /* nope */ + break; + case STR_PARAM: dest->str = estrndup(src->str, src->len); dest->len = src->len; break; + + case OP_PARAM: + dest->str = estrndup(src->str, src->len); + dest->len = src->len; + break; case ADDR_PARAM: dest->addr = src->addr; @@ -226,6 +255,7 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des dest->method.name = estrdup(src->method.name); break; + case NUMERIC_FILE_PARAM: case FILE_PARAM: dest->file.name = estrdup(src->file.name); dest->file.line = src->file.line; @@ -246,6 +276,10 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des break; case EMPTY_PARAM: { /* do nothing */ } break; + + default: { + /* not yet */ + } } } /* }}} */ @@ -254,6 +288,10 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) / zend_ulong hash = param->type; switch (param->type) { + case STACK_PARAM: + /* nope */ + break; + case STR_PARAM: hash += zend_inline_hash_func(param->str, param->len); break; @@ -291,6 +329,10 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) / break; case EMPTY_PARAM: { /* do nothing */ } break; + + default: { + /* not yet */ + } } return hash; @@ -301,7 +343,11 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa if (l && r) { if (l->type == r->type) { switch (l->type) { - + case STACK_PARAM: + /* nope, or yep */ + return 1; + break; + case NUMERIC_FUNCTION_PARAM: if (l->num != r->num) { break; @@ -356,112 +402,400 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa case EMPTY_PARAM: return 1; + + default: { + /* not yet */ + } } } } return 0; } /* }}} */ -PHPDBG_API phpdbg_input_t **phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC) /* {{{ */ -{ - char *p; - char b[PHPDBG_MAX_CMD]; - int l=0; - enum states { - IN_BETWEEN, - IN_WORD, - IN_STRING - } state = IN_BETWEEN; - phpdbg_input_t **argv = NULL; - - argv = (phpdbg_input_t**) emalloc(sizeof(phpdbg_input_t*)); - (*argc) = 0; - -#define RESET_STATE() do { \ - phpdbg_input_t *arg = emalloc(sizeof(phpdbg_input_t)); \ - if (arg) { \ - b[l]=0; \ - arg->length = l; \ - arg->string = estrndup(b, arg->length); \ - arg->argv = NULL; \ - arg->argc = 0; \ - argv = (phpdbg_input_t**) erealloc(argv, sizeof(phpdbg_input_t*) * ((*argc)+1)); \ - argv[(*argc)++] = arg; \ - l = 0; \ - } \ - state = IN_BETWEEN; \ -} while (0) - - for (p = buffer; *p != '\0'; p++) { - int c = (unsigned char) *p; - switch (state) { - case IN_BETWEEN: - if (isspace(c)) { - continue; - } - if (c == '"') { - state = IN_STRING; - continue; - } - state = IN_WORD; - b[l++]=c; - continue; - - case IN_STRING: - if (c == '"') { - if (buffer[(p - buffer)-1] == '\\') { - b[l-1]=c; - continue; - } - RESET_STATE(); - } else { - b[l++]=c; - } - continue; +/* {{{ */ +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); + break; + + case ADDR_PARAM: + fprintf(stderr, "%s ADDR_PARAM(%lu)\n", msg, param->addr); + break; + + case NUMERIC_FILE_PARAM: + fprintf(stderr, "%s NUMERIC_FILE_PARAM(%s:#%lu)\n", msg, param->file.name, param->file.line); + break; + + case FILE_PARAM: + fprintf(stderr, "%s FILE_PARAM(%s:%lu)\n", msg, param->file.name, param->file.line); + break; + + case METHOD_PARAM: + fprintf(stderr, "%s METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); + break; + + case NUMERIC_METHOD_PARAM: + fprintf(stderr, "%s NUMERIC_METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); + break; + + case NUMERIC_FUNCTION_PARAM: + fprintf(stderr, "%s NUMERIC_FUNCTION_PARAM(%s::%ld)\n", msg, param->str, param->num); + break; + + case NUMERIC_PARAM: + fprintf(stderr, "%s NUMERIC_PARAM(%ld)\n", msg, param->num); + break; + + case COND_PARAM: + fprintf(stderr, "%s COND_PARAM(%s=%lu)\n", msg, param->str, param->len); + break; + + case OP_PARAM: + fprintf(stderr, "%s OP_PARAM(%s=%lu)\n", msg, param->str, param->len); + break; + + default: { + /* not yet */ + } + } + } +} /* }}} */ - case IN_WORD: - if (isspace(c)) { - RESET_STATE(); - } else { - b[l++]=c; +/* {{{ */ +PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) { + if (stack && stack->next) { + phpdbg_param_t *remove = stack->next; + + while (remove) { + phpdbg_param_t *next = NULL; + + if (remove->next) + next = remove->next; + + 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); + break; + + case NUMERIC_FUNCTION_PARAM: + case STR_PARAM: + case OP_PARAM: + if (remove->str) + free(remove->str); + break; + + case NUMERIC_FILE_PARAM: + case FILE_PARAM: + if (remove->file.name) + free(remove->file.name); + break; + + default: { + /* nothing */ } - continue; + } + + free(remove); + remove = NULL; + + if (next) + remove = next; + else break; } } + + stack->next = NULL; +} /* }}} */ - switch (state) { - case IN_WORD: { - RESET_STATE(); - } break; +/* {{{ */ +PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param) { + phpdbg_param_t *next = calloc(1, sizeof(phpdbg_param_t)); - case IN_STRING: - phpdbg_error( - "Malformed command line (unclosed quote) @ %ld: %s!", - (p - buffer)-1, &buffer[(p - buffer)-1]); - break; + if (!next) + return; - case IN_BETWEEN: - break; + *(next) = *(param); + + next->next = NULL; + + if (stack->top == NULL) { + stack->top = next; + next->top = NULL; + stack->next = next; + } else { + stack->top->next = next; + next->top = stack->top; + stack->top = next; } - if ((*argc) == 0) { - /* not needed */ - efree(argv); + stack->len++; +} /* }}} */ - /* to be sure */ - return NULL; +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC) { + if (command) { + char buffer[128] = {0,}; + const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL; + const char *arg = command->args; + size_t least = 0L, + received = 0L, + current = 0L; + zend_bool optional = 0; + + /* check for arg spec */ + if (!(arg) || !(*arg)) { + if (!top) { + return SUCCESS; + } + + asprintf(why, + "The command \"%s\" expected no arguments", + phpdbg_command_name(command, buffer)); + return FAILURE; + } + + least = 0L; + + /* count least amount of arguments */ + while (arg && *arg) { + if (arg[0] == '|') { + break; + } + least++; + arg++; + } + + arg = command->args; + +#define verify_arg(e, a, t) if (!(a)) { \ + if (!optional) { \ + asprintf(why, \ + "The command \"%s\" expected %s and got nothing at parameter %lu", \ + phpdbg_command_name(command, buffer), \ + (e), \ + current); \ + return FAILURE;\ + } \ +} else if ((a)->type != (t)) { \ + asprintf(why, \ + "The command \"%s\" expected %s and got %s at parameter %lu", \ + phpdbg_command_name(command, buffer), \ + (e),\ + phpdbg_get_param_type((a) TSRMLS_CC), \ + current); \ + return FAILURE; \ +} + + while (arg && *arg) { + current++; + + switch (*arg) { + case '|': { + current--; + optional = 1; + arg++; + } continue; + + case 'i': verify_arg("raw input", top, STR_PARAM); break; + case 's': verify_arg("string", top, STR_PARAM); break; + case 'n': verify_arg("number", top, NUMERIC_PARAM); break; + case 'm': verify_arg("method", top, METHOD_PARAM); break; + case 'a': verify_arg("address", top, ADDR_PARAM); break; + case 'f': verify_arg("file:line", top, FILE_PARAM); break; + case 'c': verify_arg("condition", top, COND_PARAM); break; + case 'o': verify_arg("opcode", top, OP_PARAM); break; + case 'b': verify_arg("boolean", top, NUMERIC_PARAM); break; + + case '*': { /* do nothing */ } break; + } + + if (top ) { + top = top->next; + } else break; + + received++; + arg++; + } + +#undef verify_arg + + if ((received < least)) { + asprintf(why, + "The command \"%s\" expected at least %lu arguments (%s) and received %lu", + phpdbg_command_name(command, buffer), + least, + command->args, + received); + return FAILURE; + } } + + return SUCCESS; +} + +/* {{{ */ +PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why) { + const phpdbg_command_t *command = commands; + phpdbg_param_t *name = *top; + const phpdbg_command_t *matched[3] = {NULL, NULL, NULL}; + ulong matches = 0L; + + while (command && command->name && command->handler) { + if ((name->len == 1) || (command->name_len >= name->len)) { + /* match single letter alias */ + if (command->alias && (name->len == 1)) { + if (command->alias == (*name->str)) { + matched[matches] = command; + matches++; + } + } else { - return argv; + /* match full, case insensitive, command name */ + if (strncasecmp(command->name, name->str, name->len) == SUCCESS) { + if (matches < 3) { + + /* only allow abbreviating commands that can be aliased */ + if (((name->len != command->name_len) && command->alias) || + (name->len == command->name_len)) { + matched[matches] = command; + matches++; + } + + + /* exact match */ + if (name->len == command->name_len) + break; + } else break; + } + } + } + + command++; + } + + switch (matches) { + case 0: { + if (parent) { + asprintf( + why, + "The command \"%s %s\" could not be found", + parent->name, name->str); + } else asprintf( + why, + "The command \"%s\" could not be found", + name->str); + } return parent; + + case 1: { + (*top) = (*top)->next; + + command = matched[0]; + } break; + + default: { + char *list = NULL; + zend_uint it = 0; + size_t pos = 0; + + while (it < matches) { + if (!list) { + list = malloc( + matched[it]->name_len + 1 + + ((it+1) < matches ? sizeof(", ")-1 : 0)); + } else { + list = realloc(list, + (pos + matched[it]->name_len) + 1 + + ((it+1) < matches ? sizeof(", ")-1 : 0)); + } + memcpy(&list[pos], matched[it]->name, matched[it]->name_len); + pos += matched[it]->name_len; + if ((it+1) < matches) { + memcpy(&list[pos], ", ", sizeof(", ")-1); + pos += (sizeof(", ") - 1); + } + + list[pos] = 0; + it++; + } + + asprintf( + why, + "The command \"%s\" is ambigious, matching %lu commands (%s)", + name->str, matches, list); + free(list); + } return NULL; + } + + if (command->subs && (*top) && ((*top)->type == STR_PARAM)) { + return phpdbg_stack_resolve(command->subs, command, top, why); + } else { + return command; + } + + return NULL; } /* }}} */ -PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ +/* {{{ */ +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) { + phpdbg_param_t *top = NULL; + const phpdbg_command_t *handler = NULL; + + if (stack->type != STACK_PARAM) { + asprintf( + why, "The passed argument was not a stack !!"); + return FAILURE; + } + + if (!stack->len) { + asprintf( + why, "The stack contains nothing !!"); + return FAILURE; + } + + top = (phpdbg_param_t*) stack->next; + + switch (top->type) { + case EVAL_PARAM: + return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC); + + case RUN_PARAM: + return PHPDBG_COMMAND_HANDLER(run)(top TSRMLS_CC); + + case SHELL_PARAM: + return PHPDBG_COMMAND_HANDLER(sh)(top TSRMLS_CC); + + case STR_PARAM: { + handler = phpdbg_stack_resolve( + phpdbg_prompt_commands, NULL, &top, why); + + if (handler) { + if (phpdbg_stack_verify(handler, &top, why TSRMLS_CC) == SUCCESS) { + return handler->handler(top TSRMLS_CC); + } + } + } return FAILURE; + + default: + asprintf( + why, "The first parameter makes no sense !!"); + return FAILURE; + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { - phpdbg_input_t *buffer = NULL; char *cmd = NULL; #ifndef HAVE_LIBREADLINE char buf[PHPDBG_MAX_CMD]; #endif + char *buffer = NULL; if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && @@ -513,32 +847,8 @@ readline: } #endif } else cmd = buffered; - - /* allocate and sanitize buffer */ - buffer = (phpdbg_input_t*) ecalloc(1, sizeof(phpdbg_input_t)); - if (!buffer) { - return NULL; - } - - buffer->string = phpdbg_trim(cmd, strlen(cmd), &buffer->length); - - /* store constant pointer to start of buffer */ - buffer->start = (char* const*) buffer->string; - - buffer->argv = phpdbg_read_argv( - buffer->string, &buffer->argc TSRMLS_CC); - -#ifdef PHPDBG_DEBUG - if (buffer->argc) { - int arg = 0; - - while (arg < buffer->argc) { - phpdbg_debug( - "argv %d=%s", arg, buffer->argv[arg]->string); - arg++; - } - } -#endif + + buffer = estrdup(cmd); #ifdef HAVE_LIBREADLINE if (!buffered && cmd && @@ -546,144 +856,34 @@ readline: free(cmd); } #endif - - return buffer; } - return NULL; -} /* }}} */ + if (buffer && isspace(*buffer)) { + char *trimmed = buffer; + while (isspace(*trimmed)) + trimmed++; -PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC) /* {{{ */ -{ - if (argv) { - if (argc) { - int arg; - for (arg=0; argstring) { - efree((*input)->string); + if (buffer && strlen(buffer)) { + if (PHPDBG_G(buffer)) { + efree(PHPDBG_G(buffer)); + } + PHPDBG_G(buffer) = estrdup(buffer); + } else { + if (PHPDBG_G(buffer)) { + buffer = estrdup(PHPDBG_G(buffer)); } - - phpdbg_destroy_argv( - (*input)->argv, (*input)->argc TSRMLS_CC); - - efree(*input); } + + return buffer; } /* }}} */ -PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */ { - int rc = FAILURE; - - if (input->argc > 0) { - while (command && command->name && command->handler) { - if (((command->name_len == input->argv[0]->length) && - (memcmp(command->name, input->argv[0]->string, command->name_len) == SUCCESS)) || - (command->alias && - (input->argv[0]->length == 1) && - (command->alias == *input->argv[0]->string))) { - - phpdbg_param_t param; - phpdbg_command_t *initial_last_cmd; - phpdbg_param_t initial_last_param; - - param.type = EMPTY_PARAM; - - if (input->argc > 1) { - if (command->subs) { - phpdbg_input_t sub = *input; - - sub.string += input->argv[0]->length; - sub.length -= input->argv[0]->length; - - sub.string = phpdbg_trim( - sub.string, sub.length, &sub.length); - - sub.argc--; - sub.argv++; - - phpdbg_debug( - "trying sub commands in \"%s\" for \"%s\" with %d arguments", - command->name, sub.argv[0]->string, sub.argc-1); - - if (phpdbg_do_cmd(command->subs, &sub TSRMLS_CC) == SUCCESS) { - efree(sub.string); - return SUCCESS; - } - - efree(sub.string); - } - - /* no sub command found */ - { - char *store = input->string; - - input->string += input->argv[0]->length; - input->length -= input->argv[0]->length; - - input->string = phpdbg_trim( - input->string, input->length, &input->length); - - efree(store); - } - - /* pass parameter on */ - phpdbg_parse_param( - input->string, - input->length, - ¶m TSRMLS_CC); - } - - phpdbg_debug( - "found command %s for %s with %d arguments", - command->name, input->argv[0]->string, input->argc-1); - { - int arg; - for (arg=1; argargc; arg++) { - phpdbg_debug( - "\t#%d: [%s=%zu]", - arg, - input->argv[arg]->string, - input->argv[arg]->length); - } - } - - initial_last_param = PHPDBG_G(lparam); - initial_last_cmd = (phpdbg_command_t *)PHPDBG_G(lcmd); - PHPDBG_G(lparam) = param; - PHPDBG_G(lcmd) = (phpdbg_command_t *)command; - - rc = command->handler(¶m, input TSRMLS_CC); - - /* only set last command when it is worth it! */ - if (rc != FAILURE && !(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) { - phpdbg_clear_param(&initial_last_param TSRMLS_CC); - } else if (PHPDBG_G(lcmd) == command && !memcmp(&PHPDBG_G(lparam),& initial_last_param, sizeof(phpdbg_param_t))) { - PHPDBG_G(lparam) = initial_last_param; - PHPDBG_G(lcmd) = initial_last_cmd; - phpdbg_clear_param(¶m TSRMLS_CC); - } - break; - } - command++; - } - } else { - /* this should NEVER happen */ - phpdbg_error( - "No function executed!!"); - } - - return rc; + efree(*input); } /* }}} */ diff --git a/phpdbg_cmd.h b/phpdbg_cmd.h index c86f92bb47..571d065f59 100644 --- a/phpdbg_cmd.h +++ b/phpdbg_cmd.h @@ -23,8 +23,6 @@ #include "TSRM.h" -typedef struct _phpdbg_command_t phpdbg_command_t; - /* {{{ Command and Parameter */ enum { NO_ARG = 0, @@ -36,24 +34,23 @@ typedef enum { EMPTY_PARAM = 0, ADDR_PARAM, FILE_PARAM, + NUMERIC_FILE_PARAM, METHOD_PARAM, STR_PARAM, NUMERIC_PARAM, NUMERIC_FUNCTION_PARAM, - NUMERIC_METHOD_PARAM + NUMERIC_METHOD_PARAM, + STACK_PARAM, + EVAL_PARAM, + SHELL_PARAM, + COND_PARAM, + OP_PARAM, + ORIG_PARAM, + RUN_PARAM } phpdbg_param_type; -typedef struct _phpdbg_input_t phpdbg_input_t; - -struct _phpdbg_input_t { - char * const *start; - char *string; - size_t length; - phpdbg_input_t **argv; - int argc; -}; - -typedef struct _phpdbg_param { +typedef struct _phpdbg_param phpdbg_param_t; +struct _phpdbg_param { phpdbg_param_type type; long num; zend_ulong addr; @@ -67,10 +64,31 @@ typedef struct _phpdbg_param { } method; char *str; size_t len; -} phpdbg_param_t; + phpdbg_param_t *next; + phpdbg_param_t *top; +}; -typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t*, const phpdbg_input_t* TSRMLS_DC); +#define phpdbg_init_param(v, t) do{ \ + (v)->type = (t); \ + (v)->addr = 0; \ + (v)->num = 0; \ + (v)->file.name = NULL; \ + (v)->file.line = 0; \ + (v)->method.class = NULL; \ + (v)->method.name = NULL; \ + (v)->str = NULL; \ + (v)->len = 0; \ + (v)->next = NULL; \ + (v)->top = NULL; \ +} while(0) + +#ifndef YYSTYPE +#define YYSTYPE phpdbg_param_t +#endif + +typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t* TSRMLS_DC); +typedef struct _phpdbg_command_t phpdbg_command_t; struct _phpdbg_command_t { const char *name; /* Command name */ size_t name_len; /* Command name length */ @@ -79,7 +97,8 @@ struct _phpdbg_command_t { char alias; /* Alias */ phpdbg_command_handler_t handler; /* Command handler */ const phpdbg_command_t *subs; /* Sub Commands */ - char arg_type; /* Accept args? */ + char *args; /* Argument Spec */ + const phpdbg_command_t *parent; /* Parent Command */ }; /* }}} */ @@ -95,35 +114,29 @@ typedef struct { } phpdbg_frame_t; /* }}} */ - - /* * Workflow: -* 1) read input -* input takes the line from console, creates argc/argv -* 2) parse parameters into suitable types based on arg_type -* takes input from 1) and arg_type and creates parameters -* 3) do command -* executes commands -* 4) destroy parameters -* cleans up what was allocated by creation of parameters -* 5) destroy input -* cleans up what was allocated by creation of input +* 1) the lexer/parser creates a stack of commands and arguments from input +* 2) the commands at the top of the stack are resolved sensibly using aliases, abbreviations and case insensitive matching +* 3) the remaining arguments in the stack are verified (optionally) against the handlers declared argument specification +* 4) the handler is called passing the top of the stack as the only parameter +* 5) the stack is destroyed upon return from the handler */ /* * Input Management */ -PHPDBG_API phpdbg_input_t* phpdbg_read_input(char *buffered TSRMLS_DC); -PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t** TSRMLS_DC); +PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC); +PHPDBG_API void phpdbg_destroy_input(char** TSRMLS_DC); -/* -* Argument Management -*/ -PHPDBG_API phpdbg_input_t** phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC); -PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC); -#define phpdbg_argv_is(n, s) \ - (memcmp(input->argv[n]->string, s, input->argv[n]->length) == SUCCESS) +/** + * Stack Management + */ +PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, 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, char **why); +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC); +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC); +PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack); /* * Parameter Management @@ -135,28 +148,27 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *, const phpdbg_par PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t * TSRMLS_DC); PHPDBG_API const char* phpdbg_get_param_type(const phpdbg_param_t* TSRMLS_DC); PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC); - -/* -* Command Executor -*/ -PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t*, phpdbg_input_t* TSRMLS_DC); +PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg); /** * Command Declarators */ #define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name -#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, has_args) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, has_args} +#define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent} + +#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL} -#define PHPDBG_COMMAND_D(name, tip, alias, children, has_args) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, has_args} +#define PHPDBG_COMMAND_D(name, tip, alias, children, args) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL} -#define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC) +#define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param TSRMLS_DC) -#define PHPDBG_COMMAND_ARGS param, input TSRMLS_CC +#define PHPDBG_COMMAND_ARGS param TSRMLS_CC -#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0'} +#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0', NULL} /* * Default Switch Case diff --git a/phpdbg_frame.c b/phpdbg_frame.c index de02addc1b..a235fe8cb0 100644 --- a/phpdbg_frame.c +++ b/phpdbg_frame.c @@ -167,7 +167,7 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ zval **tmp; zval **file, **line; HashPosition position; - int i = 1, limit = num; + int i = 0, limit = num; int user_defined; if (limit < 0) { @@ -186,7 +186,7 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position) == FAILURE) { - phpdbg_write("frame #0: {main} at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line)); + phpdbg_write("frame #%d: {main} at %s:%ld", i, Z_STRVAL_PP(file), Z_LVAL_PP(line)); break; } diff --git a/phpdbg_help.c b/phpdbg_help.c index d2fea8d7c7..f2d074ded6 100644 --- a/phpdbg_help.c +++ b/phpdbg_help.c @@ -15,589 +15,916 @@ | Authors: Felipe Pena | | Authors: Joe Watkins | | Authors: Bob Weinand | + | Authors: Terry Ellison | +----------------------------------------------------------------------+ */ #include "phpdbg.h" #include "phpdbg_help.h" -#include "phpdbg_print.h" -#include "phpdbg_utils.h" -#include "phpdbg_break.h" -#include "phpdbg_list.h" -#include "phpdbg_info.h" -#include "phpdbg_set.h" +#include "phpdbg_prompt.h" +#include "zend.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -PHPDBG_HELP(exec) /* {{{ */ +/* {{{ Commands Table */ +#define PHPDBG_COMMAND_HELP_D(name, tip, alias, action) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, action, NULL, 0} + +const phpdbg_command_t phpdbg_help_commands[] = { + PHPDBG_COMMAND_HELP_D(aliases, "show alias list", 'a', phpdbg_do_help_aliases), + PHPDBG_COMMAND_HELP_D(options, "command line options", 0, NULL), + PHPDBG_COMMAND_HELP_D(overview, "help overview", 0, NULL), + PHPDBG_COMMAND_HELP_D(phpdbginit, "phpdbginit file format", 0, NULL), + PHPDBG_COMMAND_HELP_D(syntax, "syntax overview", 0, NULL), + PHPDBG_END_COMMAND +}; /* }}} */ + +/* {{{ pretty_print. Formatting escapes and wrapping text in a string before printing it. */ +void pretty_print(char *text TSRMLS_DC) { - phpdbg_help_header(); - phpdbg_writeln("\tWill attempt execution, if compilation has not yet taken place, it occurs now"); - phpdbg_writeln("The execution context must be set before execution can take place"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + char *new, *p, *q; + + const char *prompt_escape = phpdbg_get_prompt(TSRMLS_C); + unsigned int prompt_escape_len = strlen(prompt_escape); + unsigned int prompt_len = strlen(PHPDBG_G(prompt)[0]); + + const char *bold_on_escape = PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "\033[1m" : ""; + const char *bold_off_escape = PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "\033[0m" : ""; + unsigned int bold_escape_len = strlen(bold_on_escape); + + unsigned int term_width = phpdbg_get_terminal_width(TSRMLS_C); + unsigned int size = 0; + + int in_bold = 0; + + char *last_new_blank = NULL; /* position in new buffer of last blank char */ + unsigned int last_blank_count = 0; /* printable char offset of last blank char */ + unsigned int line_count = 0; /* number printable chars on current line */ + + /* First pass calculates a safe size for the pretty print version */ + for (p = text; *p; p++) { + if (UNEXPECTED(p[0] == '*') && p[1] == '*') { + size += bold_escape_len - 2; + p++; + } else if (UNEXPECTED(p[0] == '$') && p[1] == 'P') { + size += prompt_escape_len - 2; + p++; + } else if (UNEXPECTED(p[0] == '\\')) { + p++; + } + } + size += (p-text)+1; + + new = emalloc(size); + /* + * Second pass substitutes the bold and prompt escape sequences and line wrap + * + * ** toggles bold on and off if PHPDBG_IS_COLOURED flag is set + * $P substitutes the prompt sequence + * Lines are wrapped by replacing the last blank with a CR before + * characters. (This defaults to 100 if the width can't be detected). In the + * pathelogical case where no blanks are found, then the wrap occurs at the + * first blank. + */ + for (p = text, q = new; *p; p++) { + if (UNEXPECTED(*p == ' ')) { + last_new_blank = q; + last_blank_count = line_count++; + *q++ = ' '; + } else if (UNEXPECTED(*p == '\n')) { + last_new_blank = NULL; + *q++ = *p; + last_blank_count = 0; + line_count = 0; + } else if (UNEXPECTED(p[0] == '*') && p[1] == '*') { + if (bold_escape_len) { + in_bold = !in_bold; + memcpy (q, in_bold ? bold_on_escape : bold_off_escape, bold_escape_len); + q += bold_escape_len; + /* bold on/off has zero print width so line count is unchanged */ + } + p++; + } else if (UNEXPECTED(p[0] == '$') && p[1] == 'P') { + memcpy (q, prompt_escape, prompt_escape_len); + q += prompt_escape_len; + line_count += prompt_len; + p++; + } else if (UNEXPECTED(p[0] == '\\')) { + p++; + *q++ = *p; + line_count++; + } else { + *q++ = *p; + line_count++; + } -PHPDBG_HELP(step) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("You can enable and disable stepping at any phpdbg prompt during execution"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sstepping 1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%ss 1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill enable stepping"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("While stepping is enabled you are presented with a prompt after the execution of each opcode"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + if (UNEXPECTED(line_count>=term_width) && last_new_blank) { + *last_new_blank = '\n'; + last_new_blank = NULL; + line_count -= last_blank_count; + last_blank_count = 0; + } + } + *q++ = '\0'; -PHPDBG_HELP(next) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_write("Step back into the vm and execute the next opcode"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%snext", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sn", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: is only useful while executing"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + if ((q-new)>size) { + phpdbg_error("Output overrun of %lu bytes", ((q-new) - size)); + } -PHPDBG_HELP(until) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Step back into the vm, skipping breakpoints until the next source line"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%suntil", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%su", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: is only useful while executing"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + phpdbg_write("%s\n", new); + efree(new); +} /* }}} */ -PHPDBG_HELP(finish) /* {{{ */ +/* {{{ summary_print. Print a summary line giving, the command, its alias and tip */ +void summary_print(phpdbg_command_t const * const cmd TSRMLS_DC) { - phpdbg_help_header(); - phpdbg_writeln("Step back into the vm, skipping breakpoints until past the end of the current stack"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sfinish", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sF", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: this allows all breakpoints that would otherwise break execution in the current scope to be skipped"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ - -PHPDBG_HELP(leave) /* {{{ */ + char *summary; + spprintf(&summary, 0, "Command: **%s** Alias: **%c** **%s**\n", cmd->name, cmd->alias, cmd->tip); + pretty_print(summary TSRMLS_CC); + efree(summary); +} + +/* {{{ get_help. Retries and formats text from the phpdbg help text table */ +static char *get_help(const char * const key TSRMLS_DC) { - phpdbg_help_header(); - phpdbg_writeln("Step back into the vm, skipping breakpoints until the current stack is returning"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sleave", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sL", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill cause a break when instructed to leave the current context"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: this allows inspection of the return value before it is returned"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + phpdbg_help_text_t *p; -PHPDBG_HELP(compile) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Pre-compilation of the execution context provides the opportunity to inspect opcodes before execution"); - phpdbg_writeln("The execution context must be set for compilation to succeed"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%scompile", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sc", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill compile the current execution context, populating class/function/constant/etc tables"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: It is a good idea to clean the environment between each compilation"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + /* Note that phpdbg_help_text is not assumed to be collated in key order. This is an + inconvience that means that help can't be logically grouped Not worth + the savings */ -PHPDBG_HELP(print) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("By default, print will show information about the current execution context"); - phpdbg_writeln("Other printing commands give access to instruction information"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sprint class \\my\\class", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sp c \\my\\class", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the instructions for the methods in \\my\\class"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sprint method \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sp m \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the instructions for \\my\\class::method"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sprint func .getSomething", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sp f .getSomething", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the instructions for ::getSomething in the active scope"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sprint func my_function", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sp f my_function", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the instructions for the global function my_function"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sprint opline", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sp o", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the instruction for the current opline"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sprint exec", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sp e", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the instructions for the execution context"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sprint stack", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sp s", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the instructions for the current stack"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Specific printers loaded are show below:"); - phpdbg_notice("Commands"); - { - const phpdbg_command_t *print_command = phpdbg_print_commands; - - phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); - while (print_command && print_command->name) { - if (print_command->alias) { - phpdbg_writeln("\t[%c]\t%s\t\t%s", print_command->alias, print_command->name, print_command->tip); - } else { - phpdbg_writeln("\t[ ]\t%s\t\t%s", print_command->name, print_command->tip); - } - ++print_command; + for (p = phpdbg_help_text; p->key; p++) { + if (!strcmp(p->key, key)) { + return p->text; } } - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ - -PHPDBG_HELP(run) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Execute the current context inside the phpdbg vm"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%srun", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sr", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill cause execution of the context, if it is set."); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: The execution context must be set, but not necessarily compiled before execution occurs"); - phpdbg_help_footer(); - return SUCCESS; + return ""; /* return empty string to denote no match found */ } /* }}} */ -PHPDBG_HELP(eval) /* {{{ */ +/* {{{ get_command. Return number of matching commands from a command table. + * Unlike the command parser, the help search is sloppy that is partial matches can occur + * * Any single character key is taken as an alias. + * * Other keys are matched again the table on the first len characters. + * * This means that non-unique keys can generate multiple matches. + * * The first matching command is returned as an OUT parameter. * + * The rationale here is to assist users in finding help on commands. So unique matches + * will be used to generate a help message but non-unique one will be used to list alternatives. + */ +static int get_command( + const char *key, size_t len, /* pointer and length of key */ + phpdbg_command_t const **command, /* address of first matching command */ + phpdbg_command_t const * commands /* command table to be scanned */ + TSRMLS_DC) { - phpdbg_help_header(); - phpdbg_writeln("Access to eval() allows you to change the environment during execution, careful though!!"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%seval $variable", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sE $variable", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print_r($variable) on the console, if it is defined"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%seval $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sE $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill set $variable in the current scope"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: eval() will always show the result; do not prefix the code with \"return\""); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ - -PHPDBG_HELP(break) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Setting a breakpoint stops execution at a specific stage"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sbreak [file] test.php:1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb [F] test.php:1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break execution on line 1 of test.php"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak [func] my_function", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb [f] my_function", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break execution on entry to my_function"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak [method] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb [m] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break execution on entry to \\my\\class::method"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak [address] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb [a] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break at the opline with the address provided"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak [address] my_function#1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb [a] my_function#1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break at the opline number 1 of the function my_function"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak [address] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb [a] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break at the opline number 2 of the method \\my\\class::method"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak address test.php:3", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb a test.php:3", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break at the opline number 3 of test.php"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak [lineno] 200", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb [l] 200", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break at line 200 of the currently executing file"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak on ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb on ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break when the condition evaluates to true"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak at phpdbg::isGreat if ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break at every opcode in phpdbg::isGreat when the condition evaluates to true"); - phpdbg_writeln("\t%sbreak at test.php:20 if ($expression == true)", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break at every opcode on line 20 of test.php when the condition evaluates to true"); - phpdbg_write("\t"); - phpdbg_notice("The location can be anything accepted by file, func, method, or address break commands"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak op ZEND_ADD", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb O ZEND_ADD", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill break on every occurrence of the opcode provided"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%sbreak del 1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sb d 1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill remove the breakpoint with the given identifier"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: An address is only valid for the current compilation"); - phpdbg_writeln(EMPTY); - phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Specific breakers loaded are show below:"); - phpdbg_notice("Commands"); - { - const phpdbg_command_t *break_command = phpdbg_break_commands; - - phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); - while (break_command && break_command->name) { - if (break_command->alias) { - phpdbg_writeln("\t[%c]\t%s\t\t%s", break_command->alias, break_command->name, break_command->tip); - } else { - phpdbg_writeln("\t[ ]\t%s\t\t%s", break_command->name, break_command->tip); + const phpdbg_command_t *c; + unsigned int num_matches = 0; + + if (len == 1) { + for (c=commands; c->name; c++) { + if (c->alias == key[0]) { + num_matches++; + if ( num_matches == 1 && command) { + *command = c; + } } - ++break_command; } - } - phpdbg_writeln("Note: Conditional breaks are costly, use them sparingly!"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ - -PHPDBG_HELP(clean) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("While debugging you may experience errors because of attempts to redeclare classes, constants or functions"); - phpdbg_writeln("Cleaning the environment cleans these tables, so that files can be recompiled without exiting phpdbg"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ - -PHPDBG_HELP(clear) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Clearing breakpoints means you can once again run code without interruption"); - phpdbg_writeln("Note: all breakpoints are lost; be sure debugging is complete before clearing"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ - -PHPDBG_HELP(info) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("info commands provide quick access to various types of information about the PHP environment"); - phpdbg_writeln("Specific info commands are show below:"); - phpdbg_notice("Commands"); - { - const phpdbg_command_t *info_command = phpdbg_info_commands; - - phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); - while (info_command && info_command->name) { - if (info_command->alias) { - phpdbg_writeln("\t[%c]\t%s\t\t%s", info_command->alias, info_command->name, info_command->tip); - } else { - phpdbg_writeln("\t[ ]\t%s\t\t%s", info_command->name, info_command->tip); + } else { + for (c=commands; c->name; c++) { + if (!strncmp(c->name, key, len)) { + ++num_matches; + if ( num_matches == 1 && command) { + *command = c; + } } - ++info_command; } } - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + return num_matches; -PHPDBG_HELP(quiet) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Setting quietness on will stop the OPLINE output during execution"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%squiet 1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sQ 1", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill silence OPLINE output, while"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%squiet 0", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sQ 0", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill enable OPLINE output again"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: Quietness is disabled automatically while stepping"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ +} /* }}} */ -PHPDBG_HELP(back) /* {{{ */ +PHPDBG_COMMAND(help) /* {{{ */ { - phpdbg_help_header(); - phpdbg_writeln("The backtrace is built with the default debug backtrace functionality"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sback 5", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%st 5", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill limit the number of frames to 5, the default is no limit"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: it is not necessary for an exception to be thrown to show a backtrace"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + phpdbg_command_t const *cmd; + int n; -PHPDBG_HELP(frame) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("When viewing a backtrace, it is sometimes useful to jump to a frame in that trace"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sframe 2", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sf 2", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill go to frame 2, temporarily affecting scope and allowing access to the variables in that frame"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: the current frame is restored when execution continues"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ + if (!param || param->type == EMPTY_PARAM) { + pretty_print(get_help("overview!" TSRMLS_CC) TSRMLS_CC); + return SUCCESS; + } -PHPDBG_HELP(list) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("The list command displays source code for the given argument"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%slist [lines] 2", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sl [l] 2", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print next 2 lines from the current file"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%slist [func] my_function", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sl [f] my_function", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the source of the global function \"my_function\""); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%slist [func] .mine", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sl [f] .mine", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the source of the method \"mine\" from the active scope"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%slist [method] my::method", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sl [m] my::method", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the source of \"my::method\""); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%slist c myClass", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sl c myClass", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill print the source of \"myClass\""); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: before listing functions you must have a populated function table, try compile!!"); - phpdbg_writeln(EMPTY); - phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Specific listers loaded are show below:"); - phpdbg_notice("Commands"); - { - const phpdbg_command_t *list_command = phpdbg_list_commands; - - phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); - while (list_command && list_command->name) { - if (list_command->alias) { - phpdbg_writeln("\t[%c]\t%s\t\t%s", list_command->alias, list_command->name, list_command->tip); + if (param && param->type == STR_PARAM) { + n = get_command(param->str, param->len, &cmd, phpdbg_prompt_commands TSRMLS_CC); + + if (n==1) { + summary_print(cmd TSRMLS_CC); + pretty_print(get_help(cmd->name TSRMLS_CC) TSRMLS_CC); + return SUCCESS; + + } else if (n>1) { + if (param->len > 1) { + for (cmd=phpdbg_prompt_commands; cmd->name; cmd++) { + if (!strncmp(cmd->name, param->str, param->len)) { + summary_print(cmd TSRMLS_CC); + } + } + pretty_print(get_help("duplicate!" TSRMLS_CC) TSRMLS_CC); + return SUCCESS; } else { - phpdbg_writeln("\t[ ]\t%s\t\t%s", list_command->name, list_command->tip); + phpdbg_error("Internal help error, non-unique alias \"%c\"", param->str[0]); + return FAILURE; + } + + } else { /* no prompt command found so try help topic */ + n = get_command( param->str, param->len, &cmd, phpdbg_help_commands TSRMLS_CC); + + if (n>0) { + if (cmd->alias == 'a') { /* help aliases executes a canned routine */ + return cmd->handler(param TSRMLS_CC); + } else { + pretty_print(get_help(cmd->name TSRMLS_CC) TSRMLS_CC); + return SUCCESS; + } } - ++list_command; } } - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ -PHPDBG_HELP(oplog) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Even when quietness is enabled you may wish to save opline logs to a file"); - phpdbg_writeln("Setting a new oplog closes the previously open log"); - phpdbg_writeln("The log includes a high resolution timestamp on each entry"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%soplog /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sO /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill open the file /path/to/my.oplog for writing, creating it if it does not exist"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("\t%soplog 0", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sO 0", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill close the currently open log file, disabling oplog"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: upon failure to open a new oplog, the last oplog is held open"); - phpdbg_help_footer(); - return SUCCESS; + return FAILURE; + } /* }}} */ -PHPDBG_HELP(set) /* {{{ */ +PHPDBG_HELP(aliases) /* {{{ */ { - phpdbg_help_header(); - phpdbg_writeln("Configure how phpdbg looks and behaves with the set command"); - phpdbg_writeln("Specific set commands are show below:"); - phpdbg_notice("Commands"); - { - const phpdbg_command_t *set_command = phpdbg_set_commands; - - phpdbg_writeln("\tAlias\tCommand\t\tPurpose"); - while (set_command && set_command->name) { - if (set_command->alias) { - phpdbg_writeln("\t[%c]\t%s\t\t%s", set_command->alias, set_command->name, set_command->tip); - } else { - phpdbg_writeln("\t[ ]\t%s\t\t%s", set_command->name, set_command->tip); + const phpdbg_command_t *c, *c_sub; + int len; + + /* Print out aliases for all commands except help as this one comes last */ + phpdbg_writeln("Below are the aliased, short versions of all supported commands"); + for(c = phpdbg_prompt_commands; c->name; c++) { + if (c->alias && c->alias != 'h') { + phpdbg_writeln(" %c %-20s %s", c->alias, c->name, c->tip); + if (c->subs) { + len = 20 - 1 - c->name_len; + for(c_sub = c->subs; c_sub->alias; c_sub++) { + if (c_sub->alias) { + phpdbg_writeln(" %c %c %s %-*s %s", + c->alias, c_sub->alias, (char *)c->name, len, c_sub->name, c_sub->tip); + } + } } - ++set_command; } } -#ifndef _WIN32 - phpdbg_notice("Colors"); - { - const phpdbg_color_t *color = phpdbg_get_colors(TSRMLS_C); - - if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { - phpdbg_writeln("\t%-20s\t\tExample", "Name"); - } else { - phpdbg_writeln("\tName"); - } - - while (color && color->name) { - if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { - phpdbg_writeln( - "\t%-20s\t\t\033[%smphpdbg rocks :)\033[0m", color->name, color->code); - } else { - phpdbg_writeln("\t%s", color->name); - } - ++color; + + /* Print out aliases for help as this one comes last, with the added text on how aliases are used */ + get_command("h", 1, &c, phpdbg_prompt_commands TSRMLS_CC); + phpdbg_writeln(" %c %-20s %s\n", c->alias, c->name, c->tip); + + len = 20 - 1 - c->name_len; + for(c_sub = c->subs; c_sub->alias; c_sub++) { + if (c_sub->alias) { + phpdbg_writeln(" %c %c %s %-*s %s", + c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip); } } - phpdbg_writeln("The for set color can be \"prompt\", \"notice\", or \"error\""); -#endif - phpdbg_help_footer(); + + pretty_print(get_help("aliases!" TSRMLS_CC) TSRMLS_CC); return SUCCESS; } /* }}} */ -PHPDBG_HELP(register) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Register any global function for use as a command in phpdbg console"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sregister scandir", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%sR scandir", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill register the scandir function for use in phpdbg"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: arguments passed as strings, return (if present) print_r'd on console"); - if (zend_hash_num_elements(&PHPDBG_G(registered))) { - HashPosition position; - char *name = NULL; - zend_uint name_len = 0; - - phpdbg_notice("Registered Functions (%d)", zend_hash_num_elements(&PHPDBG_G(registered))); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(registered), &position); - zend_hash_get_current_key_ex(&PHPDBG_G(registered), &name, &name_len, NULL, 1, &position) == HASH_KEY_IS_STRING; - zend_hash_move_forward_ex(&PHPDBG_G(registered), &position)) { - phpdbg_writeln("|-------> %s", name); - efree(name); - } - } - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ +/* {{{ Help Text Table + * Contains help text entries keyed by a lowercase ascii key. + * Text is in ascii and enriched by a simple markup: + * ** toggles bold font emphasis. + * $P insert an bold phpdbg> prompt. + * \ escapes the following character. Note that this is itself escaped inside string + * constants so \\\\ is required to output a single \ e.g. as in namespace names. + * + * Text will be wrapped according to the STDOUT terminal width, so paragraphs are + * flowed using the C stringizing and the CR definition. Also note that entries + * are collated in alphabetic order on key. + * + * Also note the convention that help text not directly referenceable as a help param + * has a key ending in ! + */ +#define CR "\n" +phpdbg_help_text_t phpdbg_help_text[] = { + +/******************************** General Help Topics ********************************/ +{"overview!", CR +"**phpdbg** is a lightweight, powerful and easy to use debugging platform for PHP5.4+" CR +"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 +" **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 +" **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 + +"Type **help ** 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 " +"(and list out options if not unique), so **help clea** will give help on the **clean** command, " +"but **help cl** will list the summary for **clean** and **clear**." CR CR + +"Type **help aliases** to show a full alias list, including any registered phpdginit functions" CR +"Type **help syntax** for a general introduction to the command syntax." CR +"Type **help options** for a list of phpdbg command line options." CR +"Type **help phpdbginit** to show how to customise the debugger environment." +}, +{"options", CR +"Below are the command line options supported by phpdbg" CR CR + /* note the extra 4 space index in because of the extra **** */ +"**Command Line Options and Flags**" CR +" **Option** **Example Argument** **Description**" CR +" **-c** **-c**/my/php.ini Set php.ini file to load" CR +" **-d** **-d**memory_limit=4G Set a php.ini directive" CR +" **-n** Disable default php.ini" CR +" **-q** Supress welcome banner" CR +" **-v** Enable oplog output" CR +" **-s** Enable stepping" CR +" **-b** Disable colour" CR +" **-i** **-i**my.init Set .phpdbginit file" CR +" **-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 +" **-E** Enable step through eval, careful!" 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 +" **-V** Print version number" CR +" **--** **--** arg1 arg2 Use to delimit phpdbg arguments and php $argv; append any $argv " +"argument after it" CR CR + +"**Remote Console Mode**" CR CR + +"This mode is enabled by specifying the **-a** option. Phpdbg will bind only to the loopback " +"interface by default, and this can only be overridden by explicitly setting the remote console " +"bind address using the **-a** option. If **-a** is specied without an argument, then phpdbg " +"will bind to all available interfaces. You should be aware of the security implications of " +"doing this, so measures should be taken to secure this service if bound to a publicly accessible " +"interface/port." CR CR + +"Specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2." +}, + +{"phpdbginit", CR +"Phpdgb uses an debugger script file to initialize the debugger context. By default, phpdbg looks " +"for the file named **.phpdbginit** in the current working directory. This location can be " +"overridden on the command line using the **-i** switch (see **help options** for a more " +"details)." CR CR + +"Debugger scripts can also be executed using the **source** command." CR CR + +"A script file can contain a sequence of valid debugger commands, comments and embedded PHP " +"code. " CR CR + +"Comment lines are prefixed by the **#** character. Note that comments are only allowed in script " +"files and not in interactive sessions." CR CR + +"PHP code is delimited by the start and end escape tags **<:** and **:>**. PHP code can be used " +"to define application context for a debugging session and also to extend the debugger by defining " +"and **register** PHP functions as new commands." CR CR + +"Also note that executing a **clear** command will cause the current **phpdbginit** to be reparsed " +"/ reloaded." +}, + +{"syntax", CR +"Commands start with a keyword, and some (**break**, " +"**info**, **set**, **print** and **list**) may include a subcommand keyword. All keywords are " +"lower case but also have a single letter alias that may be used as an alternative to typing in the" +"keyword in full. Note some aliases are uppercase, and that keywords cannot be abbreviated other " +"than by substitution by the alias." CR CR + +"Some commands take an argument. Arguments are typed according to their format:" CR +" * **omitted**" CR +" * **address** **0x** followed by a hex string" CR +" * **number** an optionally signed number" CR +" * **method** a valid **Class::methodName** expression" CR +" * **func#op** a valid **Function name** follow by # and an integer" CR +" * **method#op** a valid **Class::methodName** follow by # and an integer" CR +" * **string** a general string" CR +" * **function** a valid **Function name**" CR +" * **file:line** a valid **filename** follow by : and an integer" CR CR + +"In some cases the type of the argument enables the second keyword to be omitted." CR CR + +"Type **help** for an overview of all commands and type **help ** to get detailed help " +"on any specific command." CR CR + +"**Valid Examples**" CR CR + +" $P quit" CR +" $P q" CR +" Quit the debugger" CR CR + +" $P ev $total[2]" CR +" Evaluate and print the variable $total[2] in the current stack frame" CR +" " CR +" $P break 200" CR +" $P b my_source.php:200" CR +" Break at line 200 in the current source and in file **my_source.php**. " CR CR + +" $P b @ ClassX::get_args if $arg[0] == \"fred\"" CR +" $P b ~ 3" CR +" Break at ClassX::get_args() if $arg[0] == \"fred\" and delete breakpoint 3" CR CR + +"**Examples of invalid commands**" CR + +" $P #This is a comment" CR +" Comments introduced by the **#** character are only allowed in **phpdbginit** script files." +}, + +/******************************** Help Codicils ********************************/ +{"aliases!", CR +"Note that aliases can be used for either command or sub-command keywords or both, so **info b** " +"is a synomyn for **info break** and **l func** for **list func**, etc." CR CR + +"Note that help will also accept any alias as a parameter and provide help on that command, for example **h p** will provide help on the print command." +}, + +{"duplicate!", CR +"Parameter is not unique. For detailed help select help on one of the above commands." +}, + +/******************************** Help on Commands ********************************/ +{"back", +"Provide a formatted backtrace using the standard debug_backtrace() functionality. An optional " +"unsigned integer argument specifying the maximum number of frames to be traced; if omitted then " +"a complete backtrace is given." CR CR + +"**Examples**" CR CR +" $P back 5" CR +" $P t " CR +" " CR +"A backtrace can be executed at any time during execution." +}, + +{"break", +"Breakpoints can be set at a range of targets within the execution environment. Execution will " +"be paused if the program flow hits a breakpoint. The break target can be one of the following " +"types:" CR CR + +" **Target** **Alias** **Purpose**" CR +" **at** **A** specify breakpoint by location and condition" CR +" **del** **d** delete breakpoint by breakpoint identifier number" CR CR + +"**Break at** takes two arguments. The first is any valid target. The second " +"is a valid PHP expression which will trigger the break in " +"execution, if evaluated as true in a boolean context at the specified target." CR CR -PHPDBG_HELP(source) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Sourcing a phpdbginit during your debugging session might save some time"); - phpdbg_writeln("The source command can also be used to export breakpoints to a phpdbginit file"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%ssource /my/init", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%s. /my/init", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill execute the phpdbginit file at /my/init"); - phpdbg_writeln("\t%ssource export /my/init", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%s. export /my/init", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill export breakpoints to /my/init in phpdbginit file format"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ +"Note that breakpoints can also be disabled and re-enabled by the **set break** command." CR CR + +"**Examples**" CR CR +" $P break test.php:100" CR +" $P b test.php:100" CR +" Break execution at line 100 of test.php" CR CR + +" $P break 200" CR +" $P b 200" CR +" Break execution at line 200 of the currently PHP script file" CR CR + +" $P break \\\\mynamespace\\\\my_function" CR +" $P b \\\\mynamespace\\\\my_function" CR +" Break execution on entry to \\\\mynamespace\\\\my_function" CR CR + +" $P break classX::method" CR +" $P b classX::method" CR +" Break execution on entry to classX::method" CR CR + +" $P break 0x7ff68f570e08" CR +" $P b 0x7ff68f570e08" CR +" Break at the opline at the address 0x7ff68f570e08" CR CR -PHPDBG_HELP(shell) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Direct access to shell commands saves having to switch windows/consoles"); - phpdbg_writeln(EMPTY); - phpdbg_notice("Examples"); - phpdbg_writeln("\t%sshell ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\t%s- ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C)); - phpdbg_writeln("\tWill execute ls /usr/src/php-src, displaying the output in the console"); - phpdbg_writeln(EMPTY); - phpdbg_writeln("Note: read only commands please!"); - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ +" $P break my_function#14" CR +" $P b my_function#14" CR +" Break at the opline #14 of the function my_function" CR CR -PHPDBG_HELP(options) /* {{{ */ -{ - phpdbg_help_header(); - phpdbg_writeln("Below are the command line options supported by phpdbg"); - phpdbg_notice("Command Line Options and Flags"); - phpdbg_writeln(" -c\t-c/my/php.ini\t\tSet php.ini file to load"); - phpdbg_writeln(" -d\t-dmemory_limit=4G\tSet a php.ini directive"); - phpdbg_writeln(" -n\tN/A\t\t\tDisable default php.ini"); - phpdbg_writeln(" -q\tN/A\t\t\tSuppress welcome banner"); - phpdbg_writeln(" -e\t-emytest.php\t\tSet execution context"); - phpdbg_writeln(" -v\tN/A\t\t\tEnable oplog output"); - phpdbg_writeln(" -s\tN/A\t\t\tEnable stepping"); - phpdbg_writeln(" -b\tN/A\t\t\tDisable colour"); - phpdbg_writeln(" -i\t-imy.init\t\tSet .phpdbginit file"); - phpdbg_writeln(" -I\tN/A\t\t\tIgnore default .phpdbginit"); - phpdbg_writeln(" -O\t-Omy.oplog\t\tSets oplog output file"); - phpdbg_writeln(" -r\tN/A\t\t\tRun execution context"); - phpdbg_writeln(" -E\tN/A\t\t\tEnable step through eval, careful!"); - phpdbg_writeln(" -S\t-Scli\t\t\tOverride SAPI name, careful!"); -#ifndef _WIN32 - phpdbg_writeln(" -l\t-l4000\t\t\tSetup remote console ports"); - phpdbg_writeln(" -a\t-a192.168.0.3\t\tSetup remote console bind address"); -#endif - phpdbg_writeln(" -V\tN/A\t\t\tVersion number"); - phpdbg_notice("Passing -rr will quit automatically after execution"); -#ifndef _WIN32 - phpdbg_writeln("Remote Console Mode"); - phpdbg_notice("For security, phpdbg will bind only to the loopback interface by default"); - phpdbg_writeln("-a without an argument implies all; phpdbg will bind to all available interfaces."); - phpdbg_writeln("specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2."); - phpdbg_notice("Steps should be taken to secure this service if bound to a public interface/port"); -#endif - phpdbg_help_footer(); - return SUCCESS; -} /* }}} */ +" $P break \\\\my\\\\class::method#2" CR +" $P b \\\\my\\\\class::method#2" CR +" Break at the opline #2 of the method \\\\my\\\\class::method" CR CR + +" $P break test.php:#3" CR +" $P b test.php:#3" CR +" Break at opline #3 in test.php" CR CR + +" $P break if $cnt > 10" CR +" $P b if $cnt > 10" CR +" Break when the condition ($cnt > 10) evaluates to true" CR CR + +" $P break at phpdbg::isGreat if $opt == 'S'" CR +" $P break @ phpdbg::isGreat if $opt == 'S'" CR +" Break at any opcode in phpdbg::isGreat when the condition ($opt == 'S') is true" CR CR + +" $P break at test.php:20 if !isset($x)" CR +" Break at every opcode on line 20 of test.php when the condition evaluates to true" CR CR + +" $P break ZEND_ADD" CR +" $P b ZEND_ADD" CR +" Break on any occurence of the opcode ZEND_ADD" CR CR + +" $P break del 2" CR +" $P b ~ 2" CR +" Remove breakpoint 2" CR CR + +"Note: Conditional breaks are costly in terms of runtime overhead. Use them only when required " +"as they significantly slow execution." CR CR + +"Note: An address is only valid for the current compilation." +}, + +{"clean", +"Classes, constants or functions can only be declared once in PHP. You may experience errors " +"during a debug session if you attempt to recompile a PHP source. The clean command clears " +"the Zend runtime tables which holds the sets of compiled classes, constants and functions, " +"releasing any associated storage back into the storage pool. This enables recompilation to " +"take place." CR CR + +"Note that you cannot selectively trim any of these resource pools. You can only do a complete " +"clean." +}, + +{"clear", +"Clearing breakpoints means you can once again run code without interruption." CR CR + +"Note: use break delete N to clear a specific breakpoint." CR CR + +"Note: if all breakpoints are cleared, then the PHP script will run until normal completion." +}, + +{"ev", +"The **ev** command takes a string expression which it evaluates and then displays. It " +"evaluates in the context of the lowest (that is the executing) frame, unless this has first " +"been explicitly changed by issuing a **frame** command. " CR CR + +"**Examples**" CR CR +" $P ev $variable" CR +" Will print_r($variable) on the console, if it is defined" CR CR + +" $P ev $variable = \"Hello phpdbg :)\"" CR +" Will set $variable in the current scope" CR CR + +"Note that **ev** allows any valid PHP expression including assignments, function calls and " +"other write statements. This enables you to change the environment during execution, so care " +"is needed here. You can even call PHP functions which have breakpoints defined. " CR CR + +"Note: **ev** will always show the result, so do not prefix the code with **return**" +}, + +{"exec", +"The **exec** command sets the execution context, that is the script to be executed. The " +"execution context must be defined either by executing the **exec** command or by using the " +"**-e** command line option." CR CR + +"Note that the **exec** command also can be used to replace a previously defined execution " +"context." CR CR + +"**Examples**" CR CR + +" $P exec /tmp/script.php" CR +" $P e /tmp/script.php" CR +" Set the execution context to **/tmp/script.php**" +}, + +//*********** 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 " +"breakpoints that are encountered within the current stack frame will be skipped. Execution " +"will then continue until the next breakpoint after leaving the stack frame or unitil " +"completion of the script" CR CR + +"Note when **step**ping is enabled, any opcode steps within the current stack frame are also " +"skipped. "CR CR + +"Note **finish** will trigger a \"not executing\" error if not executing." +}, + +{"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. " "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 +" $P frame 2" CR +" $P E $count" CR +" 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." +}, + +{"info", +"**info** commands provide quick access to various types of information about the PHP environment" CR +"Specific info commands are show below:" CR CR + +" **Target** **Alias** **Purpose**" CR +" **break** **b** show current breakpoints" CR +" **files** **F** show included files" CR +" **classes** **c** show loaded classes" CR +" **funcs** **f** show loaded classes" CR +" **error** **e** show last error" CR +" **vars** **v** show active variables" CR +" **literal** **l** show active literal constants" CR +" **memory** **m** show memory manager stats" +}, + +// ******** same issue about breakpoints in called frames +{"leave", +"The **leave** command causes control to be passed back to the vm, continuing execution. Any " +"breakpoints that are encountered within the current stack frame will be skipped. In effect a " +"temporary breakpoint is associated with any return opcode, so that a break in execution occurs " +"before leaving the current stack frame. This allows inspection / modification of any frame " +"variables including the return value before it is returned" CR CR + +"**Examples**" CR CR + +" $P leave" CR +" $P L" CR CR + +"Note when **step**ping is enabled, any opcode steps within the current stack frame are also " +"skipped. "CR CR + +"Note **leave** will trigger a \"not executing\" error if not executing." +}, + +{"list", +"The list command displays source code for the given argument. The target type is specficied by " +"a second subcommand keyword:" CR CR + +" **Type** **Alias** **Purpose**" CR +" **lines** **l** List N lines from the current execution point" CR +" **func** **f** List the complete source for a specified function" CR +" **method** **m** List the complete source for a specified class::method" CR +" **class** **c** List the complete source for a specified class" CR CR + +"Note that the context of **lines**, **func** and **method** can be determined by parsing the " +"argument, so these subcommands are optional. However, you must specify the **class** keyword " +"to list off a class." CR CR + +"**Examples**" CR CR +" $P list 2" CR +" $P l l 2" CR +" List the next 2 lines from the current file" CR CR + +" $P list my_function" CR +" $P l f my_function" CR +" List the source of the function **my_function**" CR CR + +//************ ???? +" $P list func .mine" CR +" $P l f .mine" CR +" List the source of the method **mine** from the active class in scope" CR CR + +" $P list m my::method" CR +" $P l my::method" CR +" List the source of **my::method**" CR CR + +" $P list c myClass" CR +" $P l c myClass" CR +" List the source of **myClass**" CR CR + +"Note that functions and classes can only be listed if the corresponding classes and functions " +"table in the Zend executor has a corresponding entry. You can use the compile command to " +"populate these tables for a given execution context." +}, + +{"continue", +"Continue with execution after hitting a break or watchpoint" CR CR + +"**Examples**" CR CR +" $P continue" CR +" $P c" CR +" Continue executing until the next break or watchpoint" CR CR + +"Note **continue** will trigger a \"not running\" error if not executing." +}, + +{"print", +"By default, print will show information about the current execution context." CR +"Other printing commands give access to instruction information." CR +"Specific printers loaded are show below:" CR CR + +" **Type** **Alias** **Purpose**" CR +" **exec** **e** print out the instructions in the execution context" CR +" **opline** **o** print out the instruction in the current opline" CR +" **class** **c** print out the instructions in the specified class" CR +" **method** **m** print out the instructions in the specified method" CR +" **func** **f** print out the instructions in the specified function" CR +" **stack** **s** print out the instructions in the current stack" CR CR + +"**Examples**" CR CR +" $P print class \\\\my\\\\class" CR +" $P p c \\\\my\\\\class" CR +" Print the instructions for the methods in \\\\my\\\\class" CR CR + +" $P print method \\\\my\\\\class::method" CR +" $P p m \\\\my\\\\class::method" CR +" Print the instructions for \\\\my\\\\class::method" CR CR + +" $P print func .getSomething" CR +" $P p f .getSomething" CR +//************* Check this local method scope +" Print the instructions for ::getSomething in the active scope" CR CR + +" $P print func my_function" CR +" $P p f my_function" CR +" Print the instructions for the global function my_function" CR CR + +" $P print opline" CR +" $P p o" CR +" Print the instruction for the current opline" CR CR + +" $P print exec" CR +" $P p e" CR +" Print the instructions for the execution context" CR CR + +" $P print stack" CR +" $P p s" CR +" Print the instructions for the current stack" +}, + +{"register", +//******* Needs a general explanation of the how registered functions work +"Register any global function for use as a command in phpdbg console" CR CR + +"**Examples**" CR CR +" $P register scandir" CR +" $P R scandir" CR +" Will register the scandir function for use in phpdbg" CR CR + +"Note: arguments passed as strings, return (if present) print_r'd on console" +}, + +{"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" +"**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 + +"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." +}, + +{"set", +"The **set** command is used to configure how phpdbg looks and behaves. Specific set commands " +"are as follows:" CR CR + +" **Type** **Alias** **Purpose**" CR +" **prompt** **p** set the prompt" CR +" **color** **c** set color " CR +" **colors** **C** set colors []" CR +" **oplog** **O** set oplog [output]" CR +" **break** **b** set break **id** " CR +" **breaks** **B** set breaks []" CR +" **quiet** **q** set quiet []" CR +" **stepping** **s** set stepping []" CR +" **refcount** **r** set refcount [] " CR CR + +"Valid colors are **none**, **white**, **red**, **green**, **yellow**, **blue**, **purple**, " +"**cyan** and **black**. All colours except **none** can be followed by an optional " +"**-bold** or **-underline** qualifier." CR CR + +"Color elements can be one of **prompt**, **notice**, or **error**." CR CR + +"**Examples**" CR CR +" $P S C on" CR +" Set colors on" CR CR + +" $P set p >" CR +" $P set color prompt white-bold" CR +" Set the prompt to a bold >" CR CR + +" $P S c error red-bold" CR +" Use red bold for errors" CR CR + +" $P S refcount on" CR +" Enable refcount display when hitting watchpoints" CR CR + +" $P S b 4 off" CR +" Temporarily disable breakpoint 4. This can be subsequently reenabled by a **s b 4 on**." CR +//*********** check oplog syntax +}, + +{"sh", +"Direct access to shell commands saves having to switch windows/consoles" CR CR + +"**Examples**" CR CR +" $P sh ls /usr/src/php-src" CR +" Will execute ls /usr/src/php-src, displaying the output in the console" +//*********** what does this mean????Note: read only commands please! +}, + +{"source", +"Sourcing a **phpdbginit** script during your debugging session might save some time." CR CR + +"**Examples**" CR CR + +" $P source /my/init" CR +" $P < /my/init" CR +" Will execute the phpdbginit file at /my/init" CR CR +}, + +{"export", +"Exporting breakpoints allows you to share, and or save your current debugging session" CR CR + +"**Examples**" CR CR + +" $P export /my/exports" CR +" $P > /my/exports" CR +" Will export all breakpoints to /my/exports" CR CR +}, + +{"step", +"Execute opcodes until next line" CR CR + +"**Examples**" CR CR + +" $P s" CR +" Will continue and break again in the next encountered line" CR CR +}, + +{"until", +"The **until** command causes control to be passed back to the vm, continuing execution. Any " +"breakpoints that are encountered before the next source line will be skipped. Execution " +"will then continue until the next breakpoint or completion of the script" CR CR + +"Note when **step**ping is enabled, any opcode steps within the current line are also skipped. "CR CR + +"Note that if the next line is **not** executed then **all** subsequent breakpoints will be " +"skipped. " CR CR + +"Note **until** will trigger a \"not executing\" error if not executing." + +}, +{"watch", +"Sets watchpoints on variables as long as they are defined" CR +"Passing no parameter to **watch**, lists all actually active watchpoints" CR CR + +"**Format for $variable**" CR CR +" **$var** Variable $var" CR +" **$var[]** All array elements of $var" CR +" **$var->** All properties of $var" CR +" **$var->a** Property $var->a" CR +" **$var[b]** Array element with key b in array $var" CR CR + +"Subcommands of **watch**:" CR CR + +" **Type** **Alias** **Purpose**" CR +" **array** **a** Sets watchpoint on array/object to observe if an entry is added or removed" CR +" **recursive** **r** Watches variable recursively and automatically adds watchpoints if some entry is added to an array/object" CR +" **delete** **d** Removes watchpoint" CR CR + +"Note when **recursive** watchpoints are removed, watchpoints on all the children are removed too" CR CR + +"**Examples**" CR CR +" $P watch" CR +" List currently active watchpoints" CR CR + +" $P watch $array" CR +" $P w $array" CR +" Set watchpoint on $array" CR CR + +" $P watch recursive $obj->" CR +" $P w r $obj->" CR +" Set recursive watchpoint on $obj->" CR CR + +" $P watch delete $obj->a" CR +" $P w d $obj->a" CR +" Remove watchpoint $obj->a" CR CR + +"Technical note: If using this feature with a debugger, you will get many segmentation faults, each time when a memory page containing a watched address is hit." CR +" You then you can continue, phpdbg will remove the write protection, so that the program can continue." CR +" If phpdbg could not handle that segfault, the same segfault is triggered again and this time phpdbg will abort." +}, +{NULL, NULL /* end of table marker */} +}; /* }}} */ diff --git a/phpdbg_help.h b/phpdbg_help.h index 319142cb5b..16a1e771e3 100644 --- a/phpdbg_help.h +++ b/phpdbg_help.h @@ -30,63 +30,19 @@ /** * Helper Forward Declarations */ -PHPDBG_HELP(exec); -PHPDBG_HELP(compile); -PHPDBG_HELP(step); -PHPDBG_HELP(next); -PHPDBG_HELP(run); -PHPDBG_HELP(eval); -PHPDBG_HELP(until); -PHPDBG_HELP(finish); -PHPDBG_HELP(leave); -PHPDBG_HELP(print); -PHPDBG_HELP(break); -PHPDBG_HELP(clean); -PHPDBG_HELP(clear); -PHPDBG_HELP(info); -PHPDBG_HELP(back); -PHPDBG_HELP(frame); -PHPDBG_HELP(quiet); -PHPDBG_HELP(list); -PHPDBG_HELP(set); -PHPDBG_HELP(register); -PHPDBG_HELP(options); -PHPDBG_HELP(source); -PHPDBG_HELP(shell); +PHPDBG_HELP(aliases); -/** - * Commands - */ -static const phpdbg_command_t phpdbg_help_commands[] = { - PHPDBG_COMMAND_D_EX(exec, "the execution context should be a valid path", 'e', help_exec, NULL, 0), - PHPDBG_COMMAND_D_EX(compile, "allow inspection of code before execution", 'c', help_compile, NULL, 0), - PHPDBG_COMMAND_D_EX(step, "step through execution to break at every opcode", 's', help_step, NULL, 0), - PHPDBG_COMMAND_D_EX(next, "continue executing while stepping or after breaking", 'n', help_next, NULL, 0), - PHPDBG_COMMAND_D_EX(run, "execute inside the phpdbg vm", 'r', help_run, NULL, 0), - PHPDBG_COMMAND_D_EX(eval, "access to eval() allows affecting the environment", 'E', help_eval, NULL, 0), - PHPDBG_COMMAND_D_EX(until, "continue until the current line is executed", 'u', help_until, NULL, 0), - PHPDBG_COMMAND_D_EX(finish, "continue until the current function has returned", 'F', help_finish, NULL, 0), - PHPDBG_COMMAND_D_EX(leave, "continue until the current function is returning", 'L', help_leave, NULL, 0), - PHPDBG_COMMAND_D_EX(print, "print context information or instructions", 'p', help_print, NULL, 0), - PHPDBG_COMMAND_D_EX(break, "breakpoints allow execution interruption", 'b', help_break, NULL, 0), - PHPDBG_COMMAND_D_EX(clean, "resetting the environment is useful while debugging", 'X', help_clean, NULL, 0), - PHPDBG_COMMAND_D_EX(clear, "reset breakpoints to execute without interruption", 'c', help_clear, NULL, 0), - PHPDBG_COMMAND_D_EX(info, "quick access to useful information on the console", 'i', help_info, NULL, 0), - PHPDBG_COMMAND_D_EX(back, "show debug backtrace information during execution", 't', help_back, NULL, 0), - PHPDBG_COMMAND_D_EX(frame, "switch to a frame in the current stack for inspection", 'f', help_frame, NULL, 0), - PHPDBG_COMMAND_D_EX(quiet, "be quiet during execution", 'Q', help_quiet, NULL, 0), - PHPDBG_COMMAND_D_EX(list, "list code gives you quick access to code", 'l', help_list, NULL, 0), - PHPDBG_COMMAND_D_EX(set, "configure how phpdbg looks and behaves", 'S', help_set, NULL, 0), - PHPDBG_COMMAND_D_EX(register, "register a function for use as a command", 'R', help_register,NULL, 0), - PHPDBG_COMMAND_D_EX(options, "show information about command line options", 'o', help_options, NULL, 0), - PHPDBG_COMMAND_D_EX(source, "load a phpdbginit file at the console", '.', help_source, NULL, 0), - PHPDBG_COMMAND_D_EX(shell, "execute system commands with direct shell access", '-', help_shell, NULL, 0), - PHPDBG_END_COMMAND -}; +extern const phpdbg_command_t phpdbg_help_commands[]; #define phpdbg_help_header() \ phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); #define phpdbg_help_footer() \ phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); +typedef struct _phpdbg_help_text_t { + char *key; + char *text; +} phpdbg_help_text_t; + +extern phpdbg_help_text_t phpdbg_help_text[]; #endif /* PHPDBG_HELP_H */ diff --git a/phpdbg_info.c b/phpdbg_info.c index 0f4233bf30..97f88bfa1e 100644 --- a/phpdbg_info.c +++ b/phpdbg_info.c @@ -23,9 +23,25 @@ #include "phpdbg_utils.h" #include "phpdbg_info.h" #include "phpdbg_bp.h" +#include "phpdbg_prompt.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +#define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[14]) + +const phpdbg_command_t phpdbg_info_commands[] = { + PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0), + PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0), + PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0), + PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0), + PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0), + PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0), + PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0), + PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0), + PHPDBG_END_COMMAND +}; + PHPDBG_INFO(break) /* {{{ */ { phpdbg_print_breakpoints(PHPDBG_BREAK_FILE TSRMLS_CC); diff --git a/phpdbg_info.h b/phpdbg_info.h index a6b4e3719f..c36e6bebd6 100644 --- a/phpdbg_info.h +++ b/phpdbg_info.h @@ -34,16 +34,6 @@ PHPDBG_INFO(vars); PHPDBG_INFO(literal); PHPDBG_INFO(memory); -static const phpdbg_command_t phpdbg_info_commands[] = { - PHPDBG_COMMAND_D_EX(break, "show breakpoints", 'b', info_break, NULL, 0), - PHPDBG_COMMAND_D_EX(files, "show included files", 'F', info_files, NULL, 0), - PHPDBG_COMMAND_D_EX(classes, "show loaded classes", 'c', info_classes, NULL, 0), - PHPDBG_COMMAND_D_EX(funcs, "show loaded classes", 'f', info_funcs, NULL, 0), - PHPDBG_COMMAND_D_EX(error, "show last error", 'e', info_error, NULL, 0), - PHPDBG_COMMAND_D_EX(vars, "show active variables", 'v', info_vars, NULL, 0), - PHPDBG_COMMAND_D_EX(literal, "show active literal constants", 'l', info_literal, NULL, 0), - PHPDBG_COMMAND_D_EX(memory, "show memory manager stats", 'm', info_memory, NULL, 0), - PHPDBG_END_COMMAND -}; +extern const phpdbg_command_t phpdbg_info_commands[]; #endif /* PHPDBG_INFO_H */ diff --git a/phpdbg_lexer.c b/phpdbg_lexer.c new file mode 100644 index 0000000000..c289004b98 --- /dev/null +++ b/phpdbg_lexer.c @@ -0,0 +1,2271 @@ +#line 2 "sapi/phpdbg/phpdbg_lexer.c" + +#line 4 "sapi/phpdbg/phpdbg_lexer.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 37 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void yypop_buffer_state (yyscan_t yyscanner ); + +static void yyensure_buffer_stack (yyscan_t yyscanner ); +static void yy_load_buffer_state (yyscan_t yyscanner ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); + +void *yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(yyscanner) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 18 +#define YY_END_OF_BUFFER 19 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_acclist[229] = + { 0, + 19, 4, 15, 18, 4, 17, 18, 17, 18, 4, + 7, 18, 4, 12, 15, 18, 4, 12, 15, 18, + 4, 9, 18, 4, 15, 18, 4, 15, 18, 4, + 15, 18, 4, 15, 18, 4, 15, 18, 4, 15, + 18, 3, 4, 15, 18, 4, 15, 18, 4, 15, + 18, 4, 15, 18, 4, 15, 18, 16, 18, 16, + 17, 18, 15, 18, 7, 18, 12, 15, 18, 12, + 15, 18, 9, 18, 15, 18, 15, 18, 15, 18, + 15, 18, 15, 18, 15, 18, 15, 18, 15, 18, + 15, 18, 15, 18, 4, 15, 4, 4, 4, 17, + + 17, 4, 12, 15, 4, 15, 4, 8, 4, 15, + 4, 15, 4, 15, 1, 4, 15, 4, 15, 4, + 11, 15, 4, 15, 4, 10, 15, 4, 15, 2, + 4, 15, 4, 15, 4, 15, 4, 15, 16, 16, + 17, 15, 12, 15, 15, 8, 15, 15, 15, 15, + 5, 15, 11, 15, 15, 10, 15, 15, 15, 15, + 4, 4, 13, 15, 4, 15, 4, 15, 4, 15, + 4, 15, 3, 4, 15, 4, 15, 4, 15, 13, + 15, 15, 15, 15, 15, 15, 15, 4, 6, 4, + 15, 4, 15, 4, 15, 4, 15, 4, 15, 6, + + 15, 15, 15, 15, 15, 4, 15, 4, 15, 4, + 15, 15, 15, 15, 4, 14, 15, 4, 15, 4, + 15, 14, 15, 15, 15, 4, 15, 15 + } ; + +static yyconst flex_int16_t yy_accept[127] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 2, 5, 8, + 10, 13, 17, 21, 24, 27, 30, 33, 36, 39, + 42, 46, 49, 52, 55, 58, 60, 63, 65, 67, + 70, 73, 75, 77, 79, 81, 83, 85, 87, 89, + 91, 93, 95, 97, 98, 99, 101, 102, 105, 107, + 109, 111, 113, 115, 118, 120, 123, 125, 128, 130, + 133, 135, 137, 139, 140, 142, 143, 143, 145, 146, + 147, 148, 149, 150, 151, 153, 155, 156, 158, 159, + 160, 161, 162, 165, 167, 169, 171, 173, 176, 178, + 180, 180, 182, 183, 184, 185, 186, 187, 188, 190, + + 192, 194, 196, 198, 200, 201, 202, 203, 204, 205, + 206, 208, 210, 212, 213, 214, 215, 218, 220, 222, + 224, 225, 226, 228, 229, 229 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5, 6, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 1, 1, + 1, 1, 1, 1, 10, 10, 10, 11, 12, 10, + 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, + 1, 1, 1, 1, 16, 1, 17, 18, 10, 19, + + 20, 21, 13, 22, 23, 13, 13, 24, 13, 25, + 26, 13, 13, 27, 28, 29, 30, 31, 13, 32, + 33, 34, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[35] = + { 0, + 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[133] = + { 0, + 0, 0, 33, 35, 38, 0, 357, 71, 74, 76, + 352, 79, 87, 90, 96, 100, 108, 109, 112, 120, + 123, 126, 138, 142, 148, 0, 104, 316, 455, 151, + 162, 313, 73, 92, 65, 146, 122, 94, 152, 127, + 155, 163, 172, 318, 131, 176, 182, 288, 190, 314, + 178, 184, 187, 211, 212, 215, 221, 224, 225, 235, + 236, 239, 245, 0, 203, 260, 259, 248, 264, 455, + 237, 190, 243, 253, 255, 222, 259, 194, 249, 250, + 277, 229, 0, 285, 286, 289, 295, 304, 307, 310, + 184, 0, 252, 283, 292, 296, 306, 309, 163, 328, + + 329, 332, 341, 344, 455, 326, 331, 330, 342, 343, + 362, 370, 371, 394, 368, 356, 410, 384, 404, 426, + 376, 378, 420, 411, 455, 442, 445, 447, 450, 148, + 452, 96 + } ; + +static yyconst flex_int16_t yy_def[133] = + { 0, + 125, 1, 126, 126, 125, 5, 125, 127, 128, 125, + 128, 127, 127, 128, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 129, 129, 130, 125, 130, + 130, 125, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 127, 128, 128, 128, 125, 13, 13, 128, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 129, 129, 130, 125, 130, 130, 125, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 128, 49, 127, 127, 127, 127, 127, 127, 127, + 125, 69, 130, 130, 130, 130, 130, 130, 128, 127, + + 127, 127, 127, 127, 125, 130, 130, 130, 130, 130, + 131, 127, 127, 132, 130, 130, 131, 127, 127, 132, + 130, 130, 127, 130, 0, 125, 125, 125, 125, 125, + 125, 125 + } ; + +static yyconst flex_int16_t yy_nxt[490] = + { 0, + 8, 9, 10, 11, 12, 8, 13, 12, 14, 8, + 8, 8, 8, 8, 15, 8, 8, 8, 16, 17, + 18, 8, 8, 8, 19, 20, 21, 22, 23, 8, + 8, 8, 24, 25, 27, 10, 27, 10, 28, 10, + 10, 29, 30, 28, 31, 30, 32, 28, 28, 28, + 28, 28, 33, 28, 28, 28, 34, 35, 36, 28, + 37, 28, 38, 39, 28, 28, 40, 28, 28, 28, + 41, 42, 44, 67, 44, 46, 47, 47, 47, 45, + 44, 67, 44, 48, 71, 48, 48, 45, 44, 73, + 44, 48, 125, 48, 48, 45, 120, 44, 50, 44, + + 67, 44, 67, 44, 45, 65, 47, 51, 45, 44, + 44, 44, 44, 44, 72, 44, 45, 45, 49, 76, + 45, 44, 52, 44, 44, 55, 44, 44, 45, 44, + 67, 45, 53, 125, 45, 67, 82, 56, 54, 44, + 57, 44, 75, 44, 58, 44, 45, 60, 66, 44, + 45, 44, 59, 79, 67, 68, 45, 68, 68, 67, + 67, 62, 74, 67, 61, 125, 68, 63, 68, 68, + 67, 67, 77, 44, 80, 44, 78, 46, 47, 44, + 45, 44, 81, 47, 47, 44, 45, 44, 44, 105, + 44, 84, 45, 69, 43, 45, 83, 83, 67, 83, + + 83, 83, 67, 86, 65, 47, 83, 83, 83, 83, + 83, 85, 44, 44, 44, 44, 44, 94, 44, 45, + 45, 43, 44, 45, 44, 44, 44, 44, 44, 45, + 67, 125, 45, 45, 99, 87, 44, 44, 44, 44, + 44, 56, 44, 45, 45, 67, 44, 45, 44, 88, + 93, 67, 68, 45, 68, 68, 67, 67, 67, 95, + 67, 67, 106, 67, 91, 89, 58, 67, 67, 90, + 92, 92, 67, 92, 92, 92, 96, 78, 97, 76, + 92, 92, 92, 92, 92, 67, 44, 44, 44, 44, + 44, 67, 44, 45, 45, 100, 44, 45, 44, 107, + + 67, 98, 101, 45, 67, 44, 102, 44, 44, 108, + 44, 44, 45, 44, 67, 45, 125, 67, 45, 43, + 125, 70, 103, 109, 67, 78, 58, 110, 104, 44, + 44, 44, 44, 44, 67, 44, 45, 45, 67, 67, + 45, 114, 44, 111, 44, 44, 112, 44, 115, 45, + 67, 67, 45, 116, 125, 113, 125, 125, 114, 111, + 56, 76, 43, 44, 67, 44, 43, 43, 43, 43, + 45, 44, 44, 44, 44, 122, 67, 43, 45, 45, + 125, 125, 125, 125, 67, 44, 67, 44, 125, 125, + 119, 121, 45, 118, 66, 124, 78, 125, 66, 66, + + 66, 66, 67, 123, 125, 44, 125, 44, 125, 66, + 43, 44, 45, 44, 43, 43, 43, 43, 45, 67, + 125, 44, 58, 44, 125, 43, 66, 125, 45, 76, + 66, 66, 66, 66, 67, 125, 125, 125, 56, 125, + 125, 66, 26, 26, 26, 43, 43, 44, 44, 44, + 64, 64, 117, 117, 7, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125 + } ; + +static yyconst flex_int16_t yy_chk[490] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 4, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 8, 35, 8, 9, 9, 10, 10, 8, + 12, 33, 12, 12, 33, 12, 12, 12, 13, 35, + 13, 13, 14, 13, 13, 13, 132, 15, 14, 15, + + 34, 16, 38, 16, 15, 27, 27, 15, 16, 17, + 18, 17, 18, 19, 34, 19, 17, 18, 13, 38, + 19, 20, 16, 20, 21, 18, 21, 22, 20, 22, + 37, 21, 17, 45, 22, 40, 45, 19, 17, 23, + 20, 23, 37, 24, 20, 24, 23, 22, 130, 25, + 24, 25, 21, 40, 36, 30, 25, 30, 30, 30, + 39, 24, 36, 41, 23, 99, 31, 25, 31, 31, + 31, 42, 39, 43, 41, 43, 39, 46, 46, 51, + 43, 51, 42, 47, 47, 52, 51, 52, 53, 91, + 53, 51, 52, 31, 49, 53, 49, 49, 72, 49, + + 49, 49, 78, 53, 65, 65, 49, 49, 49, 49, + 49, 52, 54, 55, 54, 55, 56, 72, 56, 54, + 55, 49, 57, 56, 57, 58, 59, 58, 59, 57, + 76, 82, 58, 59, 82, 55, 60, 61, 60, 61, + 62, 57, 62, 60, 61, 71, 63, 62, 63, 59, + 71, 73, 68, 63, 68, 68, 68, 79, 80, 73, + 93, 74, 93, 75, 67, 61, 62, 77, 66, 63, + 69, 69, 69, 69, 69, 69, 74, 80, 79, 77, + 69, 69, 69, 69, 69, 81, 84, 85, 84, 85, + 86, 94, 86, 84, 85, 84, 87, 86, 87, 94, + + 95, 81, 85, 87, 96, 88, 86, 88, 89, 95, + 89, 90, 88, 90, 97, 89, 50, 98, 90, 48, + 44, 32, 87, 96, 28, 97, 89, 98, 90, 100, + 101, 100, 101, 102, 106, 102, 100, 101, 108, 107, + 102, 106, 103, 100, 103, 104, 101, 104, 107, 103, + 109, 110, 104, 108, 11, 102, 7, 0, 110, 104, + 103, 109, 111, 111, 116, 111, 111, 111, 111, 111, + 111, 112, 113, 112, 113, 116, 115, 111, 112, 113, + 0, 0, 0, 0, 121, 118, 122, 118, 0, 0, + 113, 115, 118, 112, 114, 121, 122, 0, 114, 114, + + 114, 114, 114, 118, 0, 119, 0, 119, 0, 114, + 117, 117, 119, 117, 117, 117, 117, 117, 117, 124, + 0, 123, 119, 123, 0, 117, 120, 0, 123, 124, + 120, 120, 120, 120, 120, 0, 0, 0, 123, 0, + 0, 120, 126, 126, 126, 127, 127, 128, 128, 128, + 129, 129, 131, 131, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125 + } ; + +#define REJECT \ +{ \ +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ \ +yy_cp = yyg->yy_full_match; /* restore poss. backed-over text */ \ +++yyg->yy_lp; \ +goto find_rule; \ +} + +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 2 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" + +/* + * phpdbg_lexer.l + */ + +#include "phpdbg.h" +#include "phpdbg_cmd.h" +#define YYSTYPE phpdbg_param_t + +#include "phpdbg_parser.h" + + + +#define YY_NO_UNISTD_H 1 +#line 629 "sapi/phpdbg/phpdbg_lexer.c" + +#define INITIAL 0 +#define RAW 1 +#define NORMAL 2 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + yy_size_t yy_n_chars; + yy_size_t yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + yy_state_type *yy_state_buf; + yy_state_type *yy_state_ptr; + char *yy_full_match; + int yy_lp; + + /* These are only needed for trailing context rules, + * but there's no conditional variable for that yet. */ + int yy_looking_for_trail_begin; + int yy_full_lp; + int *yy_full_state; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (yyscan_t yyscanner ); + +int yyget_debug (yyscan_t yyscanner ); + +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *yyget_in (yyscan_t yyscanner ); + +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *yyget_out (yyscan_t yyscanner ); + +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +yy_size_t yyget_leng (yyscan_t yyscanner ); + +char *yyget_text (yyscan_t yyscanner ); + +int yyget_lineno (yyscan_t yyscanner ); + +void yyset_lineno (int line_number ,yyscan_t yyscanner ); + +int yyget_column (yyscan_t yyscanner ); + +void yyset_column (int column_no ,yyscan_t yyscanner ); + +YYSTYPE * yyget_lval (yyscan_t yyscanner ); + +void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (yyscan_t yyscanner ); +#else +extern int yywrap (yyscan_t yyscanner ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param ,yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 44 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" + + +#line 882 "sapi/phpdbg/phpdbg_lexer.c" + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + /* Create the reject buffer large enough to save one state per allowed character. */ + if ( ! yyg->yy_state_buf ) + yyg->yy_state_buf = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE ,yyscanner); + if ( ! yyg->yy_state_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; + + yyg->yy_state_ptr = yyg->yy_state_buf; + *yyg->yy_state_ptr++ = yy_current_state; + +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 126 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yyg->yy_state_ptr++ = yy_current_state; + ++yy_cp; + } + while ( yy_current_state != 125 ); + +yy_find_action: + yy_current_state = *--yyg->yy_state_ptr; + yyg->yy_lp = yy_accept[yy_current_state]; +find_rule: /* we branch to this label when backing up */ + for ( ; ; ) /* until we find what rule we matched */ + { + if ( yyg->yy_lp && yyg->yy_lp < yy_accept[yy_current_state + 1] ) + { + yy_act = yy_acclist[yyg->yy_lp]; + { + yyg->yy_full_match = yy_cp; + break; + } + } + --yy_cp; + yy_current_state = *--yyg->yy_state_ptr; + yyg->yy_lp = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + +case 1: +YY_RULE_SETUP +#line 47 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_EVAL; + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 52 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_SHELL; + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 57 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_RUN; + } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 63 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + BEGIN(NORMAL); + REJECT; + } + YY_BREAK + + +case 5: +YY_RULE_SETUP +#line 70 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_IF; + } + YY_BREAK + + +case 6: +YY_RULE_SETUP +#line 78 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + return T_PROTO; + } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 84 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ return T_POUND; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 85 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ return T_DCOLON; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 86 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ return T_COLON; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 88 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 1; + return T_TRUTHY; + } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 93 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 0; + return T_FALSY; + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 98 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = atoi(yytext); + return T_DIGITS; + } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 103 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, ADDR_PARAM); + yylval->addr = strtoul(yytext, 0, 16); + return T_ADDR; + } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 108 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, OP_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + return T_OPCODE; + } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 114 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + return T_ID; + } + YY_BREAK + +case 16: +YY_RULE_SETUP +#line 122 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + BEGIN(INITIAL); + return T_INPUT; +} + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 130 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +{ /* ignore whitespace */ } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 131 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK +#line 1129 "sapi/phpdbg/phpdbg_lexer.c" + case YY_STATE_EOF(INITIAL): + case YY_STATE_EOF(RAW): + case YY_STATE_EOF(NORMAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + yyg->yy_state_ptr = yyg->yy_state_buf; + *yyg->yy_state_ptr++ = yy_current_state; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 126 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yyg->yy_state_ptr++ = yy_current_state; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + + register YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 126 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 125); + if ( ! yy_is_jam ) + *yyg->yy_state_ptr++ = yy_current_state; + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) +{ + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register yy_size_t number_to_move = yyg->yy_n_chars + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ,yyscanner ); + + yyfree((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + yy_size_t i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +yy_size_t yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ + +int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + + yyg->yy_state_buf = 0; + yyg->yy_state_ptr = 0; + yyg->yy_full_match = 0; + yyg->yy_lp = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + yyfree ( yyg->yy_state_buf , yyscanner); + yyg->yy_state_buf = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 131 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" + + + diff --git a/phpdbg_lexer.h b/phpdbg_lexer.h new file mode 100644 index 0000000000..1958cef9a2 --- /dev/null +++ b/phpdbg_lexer.h @@ -0,0 +1,348 @@ +#ifndef yyHEADER_H +#define yyHEADER_H 1 +#define yyIN_HEADER 1 + +#line 6 "sapi/phpdbg/phpdbg_lexer.h" + +#line 8 "sapi/phpdbg/phpdbg_lexer.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 37 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void yypop_buffer_state (yyscan_t yyscanner ); + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); + +void *yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void yyfree (void * ,yyscan_t yyscanner ); + +/* Begin user sect3 */ + +#define yywrap(yyscanner) 1 +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 +#define RAW 1 +#define NORMAL 2 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (yyscan_t yyscanner ); + +int yyget_debug (yyscan_t yyscanner ); + +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *yyget_in (yyscan_t yyscanner ); + +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *yyget_out (yyscan_t yyscanner ); + +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +yy_size_t yyget_leng (yyscan_t yyscanner ); + +char *yyget_text (yyscan_t yyscanner ); + +int yyget_lineno (yyscan_t yyscanner ); + +void yyset_lineno (int line_number ,yyscan_t yyscanner ); + +int yyget_column (yyscan_t yyscanner ); + +void yyset_column (int column_no ,yyscan_t yyscanner ); + +YYSTYPE * yyget_lval (yyscan_t yyscanner ); + +void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (yyscan_t yyscanner ); +#else +extern int yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param ,yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#line 131 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" + + +#line 347 "sapi/phpdbg/phpdbg_lexer.h" +#undef yyIN_HEADER +#endif /* yyHEADER_H */ diff --git a/phpdbg_lexer.l b/phpdbg_lexer.l new file mode 100644 index 0000000000..ad5edd9f8f --- /dev/null +++ b/phpdbg_lexer.l @@ -0,0 +1,131 @@ +%{ + +/* + * phpdbg_lexer.l + */ + +#include "phpdbg.h" +#include "phpdbg_cmd.h" +#define YYSTYPE phpdbg_param_t + +#include "phpdbg_parser.h" + +%} + +%s RAW +%s NORMAL + +%option outfile="sapi/phpdbg/phpdbg_lexer.c" header-file="sapi/phpdbg/phpdbg_lexer.h" +%option warn nodefault + +%option reentrant noyywrap never-interactive nounistd +%option bison-bridge + +T_TRUE "true" +T_YES "yes" +T_ON "on" +T_ENABLED "enabled" +T_FALSE "false" +T_NO "no" +T_OFF "off" +T_DISABLED "disabled" +T_EVAL "ev" +T_SHELL "sh" +T_IF "if" +T_RUN "run" +T_RUN_SHORT "r" + +WS [ \r\n\t]+ +DIGITS [0-9\.]+ +ID [^ \r\n\t:#]+ +ADDR 0x[a-fA-F0-9]+ +OPCODE (ZEND_|zend_)([A-Za-z])+ +INPUT [^\n]+ +%% + +{ + {T_EVAL} { + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_EVAL; + } + {T_SHELL} { + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_SHELL; + } + {T_RUN}|{T_RUN_SHORT} { + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_RUN; + } + + .+ { + BEGIN(NORMAL); + REJECT; + } +} + +{ + {T_IF} { + BEGIN(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_IF; + } +} + +{ + {ID}[:]{1}[//]{2} { + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + return T_PROTO; + } + [#]{1} { return T_POUND; } + [:]{2} { return T_DCOLON; } + [:]{1} { return T_COLON; } + + {T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE} { + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 1; + return T_TRUTHY; + } + {T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE} { + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 0; + return T_FALSY; + } + {DIGITS} { + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = atoi(yytext); + return T_DIGITS; + } + {ADDR} { + phpdbg_init_param(yylval, ADDR_PARAM); + yylval->addr = strtoul(yytext, 0, 16); + return T_ADDR; + } + {OPCODE} { + phpdbg_init_param(yylval, OP_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + return T_OPCODE; + } + {ID} { + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + return T_ID; + } +} + +{INPUT} { + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = strndup(yytext, yyleng); + yylval->len = yyleng; + BEGIN(INITIAL); + return T_INPUT; +} + +{WS} { /* ignore whitespace */ } +%% diff --git a/phpdbg_list.c b/phpdbg_list.c index eb1091550b..037c6c38b2 100644 --- a/phpdbg_list.c +++ b/phpdbg_list.c @@ -29,9 +29,22 @@ #include "phpdbg.h" #include "phpdbg_list.h" #include "phpdbg_utils.h" +#include "phpdbg_prompt.h" +#include "php_streams.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +#define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13]) + +const phpdbg_command_t phpdbg_list_commands[] = { + PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l"), + PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s"), + PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m"), + PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s"), + PHPDBG_END_COMMAND +}; + PHPDBG_LIST(lines) /* {{{ */ { if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) { @@ -41,12 +54,12 @@ PHPDBG_LIST(lines) /* {{{ */ switch (param->type) { case NUMERIC_PARAM: - case EMPTY_PARAM: phpdbg_list_file(phpdbg_current_file(TSRMLS_C), - param->type == EMPTY_PARAM ? 0 : (param->num < 0 ? 1 - param->num : param->num), - (param->type != EMPTY_PARAM && param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), + (param->num < 0 ? 1 - param->num : param->num), + (param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), 0 TSRMLS_CC); break; + case FILE_PARAM: phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC); break; @@ -59,41 +72,28 @@ PHPDBG_LIST(lines) /* {{{ */ PHPDBG_LIST(func) /* {{{ */ { - switch (param->type) { - case STR_PARAM: - phpdbg_list_function_byname( - param->str, param->len TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } + phpdbg_list_function_byname(param->str, param->len TSRMLS_CC); return SUCCESS; } /* }}} */ PHPDBG_LIST(method) /* {{{ */ { - switch (param->type) { - case METHOD_PARAM: { - zend_class_entry **ce; - - if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { - zend_function *function; - char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); + zend_class_entry **ce; - if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) { - phpdbg_list_function(function TSRMLS_CC); - } else { - phpdbg_error("Could not find %s::%s", param->method.class, param->method.name); - } + if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + zend_function *function; + char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); - efree(lcname); - } else { - phpdbg_error("Could not find the class %s", param->method.class); - } - } break; + if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) { + phpdbg_list_function(function TSRMLS_CC); + } else { + phpdbg_error("Could not find %s::%s", param->method.class, param->method.name); + } - phpdbg_default_switch_case(); + efree(lcname); + } else { + phpdbg_error("Could not find the class %s", param->method.class); } return SUCCESS; @@ -101,30 +101,24 @@ PHPDBG_LIST(method) /* {{{ */ PHPDBG_LIST(class) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - zend_class_entry **ce; - - if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { - if ((*ce)->type == ZEND_USER_CLASS) { - if ((*ce)->info.user.filename) { - phpdbg_list_file( - (*ce)->info.user.filename, - (*ce)->info.user.line_end - (*ce)->info.user.line_start + 1, - (*ce)->info.user.line_start, 0 TSRMLS_CC - ); - } else { - phpdbg_error("The source of the requested class (%s) cannot be found", (*ce)->name); - } - } else { - phpdbg_error("The class requested (%s) is not user defined", (*ce)->name); - } + zend_class_entry **ce; + + if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + if ((*ce)->type == ZEND_USER_CLASS) { + if ((*ce)->info.user.filename) { + phpdbg_list_file( + (*ce)->info.user.filename, + (*ce)->info.user.line_end - (*ce)->info.user.line_start + 1, + (*ce)->info.user.line_start, 0 TSRMLS_CC + ); } else { - phpdbg_error("The requested class (%s) could not be found", param->str); + phpdbg_error("The source of the requested class (%s) cannot be found", (*ce)->name); } - } break; - - phpdbg_default_switch_case(); + } else { + phpdbg_error("The class requested (%s) is not user defined", (*ce)->name); + } + } else { + phpdbg_error("The requested class (%s) could not be found", param->str); } return SUCCESS; @@ -132,97 +126,46 @@ PHPDBG_LIST(class) /* {{{ */ void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */ { - unsigned char *mem, *pos, *last_pos, *end_pos; struct stat st; -#ifndef _WIN32 - int fd; -#else - HANDLE fd, map; -#endif - int all_content = (count == 0); - int line = 0, displayed = 0; - + char *opened = NULL; + char buffer[8096] = {0,}; + long line = 0; + + php_stream *stream = NULL; + if (VCWD_STAT(filename, &st) == FAILURE) { phpdbg_error("Failed to stat file %s", filename); return; } - -#ifndef _WIN32 - if ((fd = VCWD_OPEN(filename, O_RDONLY)) == FAILURE) { + + stream = php_stream_open_wrapper(filename, "rb", USE_PATH, &opened); + + if (!stream) { phpdbg_error("Failed to open file %s to list", filename); return; } - - pos = last_pos = mem = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - end_pos = mem + st.st_size; -#else - - fd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd == INVALID_HANDLE_VALUE) { - phpdbg_error("Failed to open file!"); - return; - } - - map = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL); - if (map == NULL) { - phpdbg_error("Failed to map file!"); - CloseHandle(fd); - return; - } - - pos = last_pos = mem = (char*) MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); - if (mem == NULL) { - phpdbg_error("Failed to map file in memory"); - CloseHandle(map); - CloseHandle(fd); - return; - } - end_pos = mem + st.st_size; -#endif - while (1) { - if (pos == end_pos) { - break; - } - - pos = memchr(last_pos, '\n', end_pos - last_pos); - - if (!pos) { - /* No more line breaks */ - pos = end_pos; - } - + + while (php_stream_gets(stream, buffer, sizeof(buffer)) != NULL) { ++line; - + if (!offset || offset <= line) { /* Without offset, or offset reached */ if (!highlight) { - phpdbg_writeln("%05u: %.*s", line, (int)(pos - last_pos), last_pos); + phpdbg_write("%05ld: %s", line, buffer); } else { if (highlight != line) { - phpdbg_writeln(" %05u: %.*s", line, (int)(pos - last_pos), last_pos); + phpdbg_write(" %05ld: %s", line, buffer); } else { - phpdbg_writeln(">%05u: %.*s", line, (int)(pos - last_pos), last_pos); + phpdbg_write(">%05ld: %s", line, buffer); } } - ++displayed; } - - last_pos = pos + 1; - - if (!all_content && displayed == count) { - /* Reached max line to display */ + + if ((count + (offset-1)) == line) break; - } } - -#ifndef _WIN32 - munmap(mem, st.st_size); - close(fd); -#else - UnmapViewOfFile(mem); - CloseHandle(map); - CloseHandle(fd); -#endif + + php_stream_close(stream); } /* }}} */ void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */ diff --git a/phpdbg_list.h b/phpdbg_list.h index f9d1885eaf..14905f6567 100644 --- a/phpdbg_list.h +++ b/phpdbg_list.h @@ -36,12 +36,6 @@ void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC); void phpdbg_list_function(const zend_function* TSRMLS_DC); void phpdbg_list_file(const char*, long, long, int TSRMLS_DC); -static const phpdbg_command_t phpdbg_list_commands[] = { - PHPDBG_COMMAND_D_EX(lines, "lists the specified lines", 'l', list_lines, NULL, 1), - PHPDBG_COMMAND_D_EX(class, "lists the specified class", 'c', list_class, NULL, 1), - PHPDBG_COMMAND_D_EX(method, "lists the specified method", 'm', list_method, NULL, 1), - PHPDBG_COMMAND_D_EX(func, "lists the specified function", 'f', list_func, NULL, 1), - PHPDBG_END_COMMAND -}; +extern const phpdbg_command_t phpdbg_list_commands[]; #endif /* PHPDBG_LIST_H */ diff --git a/phpdbg_opcode.c b/phpdbg_opcode.c index 50073eb22b..6b13625fc1 100644 --- a/phpdbg_opcode.c +++ b/phpdbg_opcode.c @@ -183,6 +183,7 @@ void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */ { +#if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO #define CASE(s) case s: return #s switch (opcode) { CASE(ZEND_NOP); @@ -360,4 +361,8 @@ const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */ default: return "UNKNOWN"; } +#else + const char *ret = zend_get_opcode_name(opcode); + return ret?ret:"UNKNOWN"; +#endif } /* }}} */ diff --git a/phpdbg_parser.y b/phpdbg_parser.y new file mode 100644 index 0000000000..4a84504e2e --- /dev/null +++ b/phpdbg_parser.y @@ -0,0 +1,168 @@ +%error-verbose +%{ + +/* + * phpdbg_parser.y + * (from php-src root) + * flex sapi/phpdbg/dev/phpdbg_lexer.l + * bison sapi/phpdbg/dev/phpdbg_parser.y + */ + +#include "phpdbg.h" +#include "phpdbg_cmd.h" +#include "phpdbg_utils.h" +#include "phpdbg_cmd.h" +#include "phpdbg_prompt.h" + +#define YYSTYPE phpdbg_param_t + +#include "phpdbg_parser.h" +#include "phpdbg_lexer.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +int yyerror(phpdbg_param_t *stack, yyscan_t scanner, const char *msg) { + TSRMLS_FETCH(); + phpdbg_error("Parse Error: %s", msg); + { + const phpdbg_param_t *top = stack; + + while (top) { + phpdbg_param_debug( + top, "--> "); + top = top->next; + } + } + return 0; +} +%} + +%code requires { +#include "phpdbg.h" +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif +} +%output "sapi/phpdbg/phpdbg_parser.c" +%defines "sapi/phpdbg/phpdbg_parser.h" + +%define api.pure +%lex-param { yyscan_t scanner } +%parse-param { phpdbg_param_t *stack } +%parse-param { yyscan_t scanner } + +%token T_EVAL "eval" +%token T_RUN "run" +%token T_SHELL "shell" +%token T_IF "if (condition)" +%token T_TRUTHY "truthy (true, on, yes or enabled)" +%token T_FALSY "falsy (false, off, no or disabled)" +%token T_STRING "string (some input, perhaps)" +%token T_COLON ": (colon)" +%token T_DCOLON ":: (double colon)" +%token T_POUND "# (pound sign)" +%token T_PROTO "protocol (file://)" +%token T_DIGITS "digits (numbers)" +%token T_LITERAL "literal (string)" +%token T_ADDR "address" +%token T_OPCODE "opcode" +%token T_ID "identifier (command or function name)" +%token T_INPUT "input (input string or data)" +%token T_UNEXPECTED "input" +%% + +input + : parameters + | /* nothing */ + ; + +parameters + : parameter { phpdbg_stack_push(stack, &$1); } + | parameters parameter { phpdbg_stack_push(stack, &$2); } + ; + +parameter + : T_ID T_COLON T_DIGITS { + $$.type = FILE_PARAM; + $$.file.name = $2.str; + $$.file.line = $3.num; + } + | T_ID T_COLON T_POUND T_DIGITS { + $$.type = NUMERIC_FILE_PARAM; + $$.file.name = $1.str; + $$.file.line = $4.num; + } + | T_PROTO T_ID T_COLON T_DIGITS { + $$.type = FILE_PARAM; + $$.file.name = malloc($1.len + + $2.len + 1); + if ($$.file.name) { + memcpy(&$$.file.name[0], $1.str, $1.len); + memcpy(&$$.file.name[$1.len], $2.str, $2.len); + $$.file.name[$1.len + $2.len] = '\0'; + } + $$.file.line = $4.num; + } + | T_PROTO T_ID T_COLON T_POUND T_DIGITS { + $$.type = NUMERIC_FILE_PARAM; + $$.file.name = malloc($1.len + + $2.len + 1); + if ($$.file.name) { + memcpy(&$$.file.name[0], $1.str, $1.len); + memcpy(&$$.file.name[$1.len], $2.str, $2.len); + $$.file.name[$1.len + $2.len] = '\0'; + } + $$.file.line = $5.num; + } + | T_ID T_DCOLON T_ID { + $$.type = METHOD_PARAM; + $$.method.class = $1.str; + $$.method.name = $3.str; + } + | T_ID T_DCOLON T_ID T_POUND T_DIGITS { + $$.type = NUMERIC_METHOD_PARAM; + $$.method.class = $1.str; + $$.method.name = $3.str; + $$.num = $5.num; + } + | T_ID T_POUND T_DIGITS { + $$.type = NUMERIC_FUNCTION_PARAM; + $$.str = $1.str; + $$.len = $1.len; + $$.num = $3.num; + } + | T_IF T_INPUT { + $$.type = COND_PARAM; + $$.str = $2.str; + $$.len = $2.len; + } + | T_EVAL T_INPUT { + $$.type = EVAL_PARAM; + $$.str = $2.str; + $$.len = $2.len; + } + | T_SHELL T_INPUT { + $$.type = SHELL_PARAM; + $$.str = $2.str; + $$.len = $2.len; + } + | T_RUN { + $$.type = RUN_PARAM; + $$.len = 0; + } + | T_RUN T_INPUT { + $$.type = RUN_PARAM; + $$.str = $2.str; + $$.len = $2.len; + } + | T_OPCODE { $$ = $1; } + | T_ADDR { $$ = $1; } + | T_LITERAL { $$ = $1; } + | T_TRUTHY { $$ = $1; } + | T_FALSY { $$ = $1; } + | T_DIGITS { $$ = $1; } + | T_ID { $$ = $1; } + ; + +%% diff --git a/phpdbg_print.c b/phpdbg_print.c index c4925fe5fd..76321a5042 100644 --- a/phpdbg_print.c +++ b/phpdbg_print.c @@ -26,6 +26,19 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9]) + +const phpdbg_command_t phpdbg_print_commands[] = { + PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0), + PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0), + PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s"), + PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m"), + PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s"), + PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0), + PHPDBG_END_COMMAND +}; + PHPDBG_PRINT(opline) /* {{{ */ { if (EG(in_execution) && EG(current_execute_data)) { @@ -77,7 +90,7 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) phpdbg_error("\tFailed to decode opline %16p", opline); } opline++; - } while (++opcode < end); + } while (opcode++ < end); zend_hash_destroy(&vars); } } break; @@ -141,36 +154,30 @@ PHPDBG_PRINT(class) /* {{{ */ { zend_class_entry **ce; - switch (param->type) { - case STR_PARAM: { - if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { - phpdbg_notice("%s %s: %s", - ((*ce)->type == ZEND_USER_CLASS) ? - "User" : "Internal", - ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? - "Interface" : - ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? - "Abstract Class" : - "Class", - (*ce)->name); - - phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table)); - if (zend_hash_num_elements(&(*ce)->function_table)) { - HashPosition position; - zend_function *method; - - for (zend_hash_internal_pointer_reset_ex(&(*ce)->function_table, &position); - zend_hash_get_current_data_ex(&(*ce)->function_table, (void**) &method, &position) == SUCCESS; - zend_hash_move_forward_ex(&(*ce)->function_table, &position)) { - phpdbg_print_function_helper(method TSRMLS_CC); - } - } - } else { - phpdbg_error("The class %s could not be found", param->str); + if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + phpdbg_notice("%s %s: %s", + ((*ce)->type == ZEND_USER_CLASS) ? + "User" : "Internal", + ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? + "Interface" : + ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? + "Abstract Class" : + "Class", + (*ce)->name); + + phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table)); + if (zend_hash_num_elements(&(*ce)->function_table)) { + HashPosition position; + zend_function *method; + + for (zend_hash_internal_pointer_reset_ex(&(*ce)->function_table, &position); + zend_hash_get_current_data_ex(&(*ce)->function_table, (void**) &method, &position) == SUCCESS; + zend_hash_move_forward_ex(&(*ce)->function_table, &position)) { + phpdbg_print_function_helper(method TSRMLS_CC); } - } break; - - phpdbg_default_switch_case(); + } + } else { + phpdbg_error("The class %s could not be found", param->str); } return SUCCESS; @@ -178,31 +185,25 @@ PHPDBG_PRINT(class) /* {{{ */ PHPDBG_PRINT(method) /* {{{ */ { - switch (param->type) { - case METHOD_PARAM: { - zend_class_entry **ce; - - if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { - zend_function *fbc; - char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); + zend_class_entry **ce; - if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { - phpdbg_notice("%s Method %s", - (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", - fbc->common.function_name); + if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + zend_function *fbc; + char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); - phpdbg_print_function_helper(fbc TSRMLS_CC); - } else { - phpdbg_error("The method %s could not be found", param->method.name); - } + if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { + phpdbg_notice("%s Method %s", + (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", + fbc->common.function_name); - efree(lcname); - } else { - phpdbg_error("The class %s could not be found", param->method.class); - } - } break; + phpdbg_print_function_helper(fbc TSRMLS_CC); + } else { + phpdbg_error("The method %s could not be found", param->method.name); + } - phpdbg_default_switch_case(); + efree(lcname); + } else { + phpdbg_error("The class %s could not be found", param->method.class); } return SUCCESS; @@ -210,49 +211,43 @@ PHPDBG_PRINT(method) /* {{{ */ PHPDBG_PRINT(func) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - HashTable *func_table = EG(function_table); - zend_function* fbc; - const char *func_name = param->str; - size_t func_name_len = param->len; - char *lcname; - /* search active scope if begins with period */ - if (func_name[0] == '.') { - if (EG(scope)) { - func_name++; - func_name_len--; - - func_table = &EG(scope)->function_table; - } else { - phpdbg_error("No active class"); - return SUCCESS; - } - } else if (!EG(function_table)) { - phpdbg_error("No function table loaded"); - return SUCCESS; - } else { - func_table = EG(function_table); - } - - lcname = zend_str_tolower_dup(func_name, func_name_len); - - if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { - phpdbg_notice("%s %s %s", - (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", - (fbc->common.scope) ? "Method" : "Function", - fbc->common.function_name); + HashTable *func_table = EG(function_table); + zend_function* fbc; + const char *func_name = param->str; + size_t func_name_len = param->len; + char *lcname; + /* search active scope if begins with period */ + if (func_name[0] == '.') { + if (EG(scope)) { + func_name++; + func_name_len--; + + func_table = &EG(scope)->function_table; + } else { + phpdbg_error("No active class"); + return SUCCESS; + } + } else if (!EG(function_table)) { + phpdbg_error("No function table loaded"); + return SUCCESS; + } else { + func_table = EG(function_table); + } - phpdbg_print_function_helper(fbc TSRMLS_CC); - } else { - phpdbg_error("The function %s could not be found", func_name); - } + lcname = zend_str_tolower_dup(func_name, func_name_len); - efree(lcname); - } break; + if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { + phpdbg_notice("%s %s %s", + (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", + (fbc->common.scope) ? "Method" : "Function", + fbc->common.function_name); - phpdbg_default_switch_case(); + phpdbg_print_function_helper(fbc TSRMLS_CC); + } else { + phpdbg_error("The function %s could not be found", func_name); } + efree(lcname); + return SUCCESS; } /* }}} */ diff --git a/phpdbg_print.h b/phpdbg_print.h index 80010d5e7c..ed85e965c1 100644 --- a/phpdbg_print.h +++ b/phpdbg_print.h @@ -35,17 +35,6 @@ PHPDBG_PRINT(method); PHPDBG_PRINT(func); PHPDBG_PRINT(stack); -/** - * Commands - */ -static const phpdbg_command_t phpdbg_print_commands[] = { - PHPDBG_COMMAND_D_EX(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0), - PHPDBG_COMMAND_D_EX(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0), - PHPDBG_COMMAND_D_EX(class, "print out the instructions in the specified class", 'c', print_class, NULL, 1), - PHPDBG_COMMAND_D_EX(method, "print out the instructions in the specified method", 'm', print_method, NULL, 1), - PHPDBG_COMMAND_D_EX(func, "print out the instructions in the specified function", 'f', print_func, NULL, 1), - PHPDBG_COMMAND_D_EX(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0), - PHPDBG_END_COMMAND -}; +extern const phpdbg_command_t phpdbg_print_commands[]; #endif /* PHPDBG_PRINT_H */ diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index f586bb5a84..7a28a75129 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -35,99 +35,154 @@ #include "phpdbg_cmd.h" #include "phpdbg_set.h" #include "phpdbg_frame.h" +#include "phpdbg_lexer.h" +#include "phpdbg_parser.h" + +int yyparse(phpdbg_param_t *stack, yyscan_t scanner); /* {{{ command declarations */ const phpdbg_command_t phpdbg_prompt_commands[] = { - PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, 1), - PHPDBG_COMMAND_D(compile, "attempt compilation", 'c', NULL, 0), - PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 1), - PHPDBG_COMMAND_D(next, "continue execution", 'n', NULL, 0), - PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0), - PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, 1), + PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s"), + PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0), + PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0), + PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s"), + PHPDBG_COMMAND_D(ev, "evaluate some code", 0, NULL, "i"), PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0), PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0), PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0), - PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 2), - PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1), - PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0), - PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, 1), - PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, 2), - PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, 1), + PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 0), + PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c"), + PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n"), + PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n"), + PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*"), + PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s"), PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0), PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0), - PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, 2), - PHPDBG_COMMAND_D(quiet, "silence some output", 'Q', NULL, 1), - PHPDBG_COMMAND_D(aliases, "show alias list", 'a', NULL, 0), - PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, 1), - PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, 1), - PHPDBG_COMMAND_D(source, "execute a phpdbginit", '.', NULL, 1), - PHPDBG_COMMAND_D(shell, "shell a command", '-', NULL, 1), + PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s"), + PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s"), + PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s"), + PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s"), + PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s"), + PHPDBG_COMMAND_D(sh, "shell a command", 0, NULL, "i"), PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0), + PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss"), PHPDBG_END_COMMAND }; /* }}} */ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -static inline int phpdbg_call_register(phpdbg_input_t *input TSRMLS_DC) /* {{{ */ +static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ */ { - phpdbg_input_t *function = input->argv[0]; - - if (zend_hash_exists( - &PHPDBG_G(registered), function->string, function->length+1)) { - - zval fname, *fretval; - zend_fcall_info fci; - - ZVAL_STRINGL(&fname, function->string, function->length, 1); - - memset(&fci, 0, sizeof(zend_fcall_info)); - - fci.size = sizeof(zend_fcall_info); - fci.function_table = &PHPDBG_G(registered); - fci.function_name = &fname; - fci.symbol_table = EG(active_symbol_table); - fci.object_ptr = NULL; - fci.retval_ptr_ptr = &fretval; - fci.no_separation = 1; - - if (input->argc > 1) { - int param; - zval params; - - array_init(¶ms); + phpdbg_param_t *name = NULL; - for (param = 0; param < (input->argc-1); param++) { - add_next_index_stringl( - ¶ms, - input->argv[param+1]->string, - input->argv[param+1]->length, 1); + if (stack->type == STACK_PARAM) { + name = stack->next; + + if (!name || name->type != STR_PARAM) { + return FAILURE; + } + + if (zend_hash_exists( + &PHPDBG_G(registered), name->str, name->len+1)) { + + zval fname, *fretval; + zend_fcall_info fci; + + ZVAL_STRINGL(&fname, name->str, name->len, 1); + + memset(&fci, 0, sizeof(zend_fcall_info)); + + fci.size = sizeof(zend_fcall_info); + fci.function_table = &PHPDBG_G(registered); + fci.function_name = &fname; + fci.symbol_table = EG(active_symbol_table); + fci.object_ptr = NULL; + fci.retval_ptr_ptr = &fretval; + fci.no_separation = 1; + + if (name->next) { + zval params; + phpdbg_param_t *next = name->next; + + array_init(¶ms); + + while (next) { + char *buffered = NULL; + + switch (next->type) { + case OP_PARAM: + case COND_PARAM: + case STR_PARAM: + add_next_index_stringl( + ¶ms, + next->str, + next->len, 1); + break; + + case NUMERIC_PARAM: + add_next_index_long(¶ms, next->num); + break; + + case METHOD_PARAM: + spprintf(&buffered, 0, "%s::%s", + next->method.class, next->method.name); + add_next_index_string(¶ms, buffered, 0); + break; + + case NUMERIC_METHOD_PARAM: + spprintf(&buffered, 0, "%s::%s#%ld", + next->method.class, next->method.name, next->num); + add_next_index_string(¶ms, buffered, 0); + break; + + case NUMERIC_FUNCTION_PARAM: + spprintf(&buffered, 0, "%s#%ld", + next->str, next->num); + add_next_index_string(¶ms, buffered, 0); + break; + + case FILE_PARAM: + spprintf(&buffered, 0, "%s:%ld", + next->file.name, next->file.line); + add_next_index_string(¶ms, buffered, 0); + break; + + case NUMERIC_FILE_PARAM: + spprintf(&buffered, 0, "%s:#%ld", + next->file.name, next->file.line); + add_next_index_string(¶ms, buffered, 0); + break; + + default: { + /* not yet */ + } + } + + next = next->next; + } - phpdbg_debug( - "created param[%d] from argv[%d]: %s", - param, param+1, input->argv[param+1]->string); + zend_fcall_info_args(&fci, ¶ms TSRMLS_CC); + } else { + fci.params = NULL; + fci.param_count = 0; } - zend_fcall_info_args(&fci, ¶ms TSRMLS_CC); - } else { - fci.params = NULL; - fci.param_count = 0; - } - - phpdbg_debug( - "created %d params from %d arguments", - fci.param_count, input->argc); + phpdbg_debug( + "created %d params from arguments", + fci.param_count); - zend_call_function(&fci, NULL TSRMLS_CC); + zend_call_function(&fci, NULL TSRMLS_CC); - if (fretval) { - zend_print_zval_r( - fretval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); - } + if (fretval) { + zend_print_zval_r( + fretval, 0 TSRMLS_CC); + phpdbg_writeln(EMPTY); + } - zval_dtor(&fname); + zval_dtor(&fname); - return SUCCESS; + return SUCCESS; + } } return FAILURE; @@ -136,7 +191,7 @@ static inline int phpdbg_call_register(phpdbg_input_t *input TSRMLS_DC) /* {{{ * void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */ { struct stat sb; - + if (init_file && VCWD_STAT(init_file, &sb) != -1) { FILE *fp = fopen(init_file, "r"); if (fp) { @@ -190,19 +245,47 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ } { - phpdbg_input_t *input = phpdbg_read_input(cmd TSRMLS_CC); - switch (phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) { - case FAILURE: - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) { - phpdbg_error("Unrecognized command in %s:%d: %s!", init_file, line, input->string); - } - } + char *why = NULL; + char *input = phpdbg_read_input(cmd TSRMLS_CC); + phpdbg_param_t stack; + yyscan_t scanner; + YY_BUFFER_STATE state; + + phpdbg_init_param(&stack, STACK_PARAM); + + if (yylex_init(&scanner)) { + phpdbg_error( + "could not initialize scanner"); break; } + + state = yy_scan_string(input, scanner); + + if (yyparse(&stack, scanner) <= 0) { + switch (phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + case FAILURE: +// if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + phpdbg_error( + "Unrecognized command in %s:%d: %s, %s!", + init_file, line, input, why); + } +// } + break; + } + } + + if (why) { + free(why); + why = NULL; + } + + yy_delete_buffer(state, scanner); + yylex_destroy(scanner); + + phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); } - } next_line: line++; @@ -264,47 +347,47 @@ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TS PHPDBG_COMMAND(exec) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - struct stat sb; - - if (VCWD_STAT(param->str, &sb) != FAILURE) { - if (sb.st_mode & (S_IFREG|S_IFLNK)) { - char *res = phpdbg_resolve_path(param->str TSRMLS_CC); - size_t res_len = strlen(res); - - if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { - - if (PHPDBG_G(exec)) { - phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec)); - efree(PHPDBG_G(exec)); - PHPDBG_G(exec) = NULL; - PHPDBG_G(exec_len) = 0L; - } + struct stat sb; - if (PHPDBG_G(ops)) { - phpdbg_notice("Destroying compiled opcodes"); - phpdbg_clean(0 TSRMLS_CC); - } + if (VCWD_STAT(param->str, &sb) != FAILURE) { + if (sb.st_mode & (S_IFREG|S_IFLNK)) { + char *res = phpdbg_resolve_path(param->str TSRMLS_CC); + size_t res_len = strlen(res); - PHPDBG_G(exec) = res; - PHPDBG_G(exec_len) = res_len; + if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { - phpdbg_notice("Set execution context: %s", PHPDBG_G(exec)); - } else { - phpdbg_notice("Execution context not changed"); - } - } else { - phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str); + if (PHPDBG_G(exec)) { + phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec)); + efree(PHPDBG_G(exec)); + PHPDBG_G(exec) = NULL; + PHPDBG_G(exec_len) = 0L; + } + + if (PHPDBG_G(ops)) { + phpdbg_notice("Destroying compiled opcodes"); + phpdbg_clean(0 TSRMLS_CC); + } + + PHPDBG_G(exec) = res; + PHPDBG_G(exec_len) = res_len; + + *SG(request_info).argv = PHPDBG_G(exec); + php_hash_environment(TSRMLS_C); + + phpdbg_notice("Set execution context: %s", PHPDBG_G(exec)); + + if (phpdbg_compile(TSRMLS_C) == FAILURE) { + phpdbg_error("Failed to compile %s", PHPDBG_G(exec)); } } else { - phpdbg_error("Cannot stat %s, ensure the file exists", param->str); + phpdbg_notice("Execution context not changed"); } - } break; - - phpdbg_default_switch_case(); + } else { + phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str); + } + } else { + phpdbg_error("Cannot stat %s, ensure the file exists", param->str); } - return SUCCESS; } /* }}} */ @@ -312,6 +395,11 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ { zend_file_handle fh; + if (!PHPDBG_G(exec)) { + phpdbg_error("No execution context"); + return SUCCESS; + } + if (EG(in_execution)) { phpdbg_error("Cannot compile while in execution"); return FAILURE; @@ -334,47 +422,16 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ return FAILURE; } /* }}} */ -PHPDBG_COMMAND(compile) /* {{{ */ -{ - if (!PHPDBG_G(exec)) { - phpdbg_error("No execution context"); - return SUCCESS; - } - - if (!EG(in_execution)) { - if (PHPDBG_G(ops)) { - phpdbg_error("Destroying previously compiled opcodes"); - phpdbg_clean(0 TSRMLS_CC); - } - } - - phpdbg_compile(TSRMLS_C); - - return SUCCESS; -} /* }}} */ - PHPDBG_COMMAND(step) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: - case NUMERIC_PARAM: { - if (param->type == NUMERIC_PARAM && param->num) { - PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; - } else { - PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; - } - - phpdbg_notice("Stepping %s", - (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); - } break; - - phpdbg_default_switch_case(); + if (EG(in_execution)) { + PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } - return SUCCESS; + return PHPDBG_NEXT; } /* }}} */ -PHPDBG_COMMAND(next) /* {{{ */ +PHPDBG_COMMAND(continue) /* {{{ */ { return PHPDBG_NEXT; } /* }}} */ @@ -475,17 +532,9 @@ PHPDBG_COMMAND(leave) /* {{{ */ PHPDBG_COMMAND(frame) /* {{{ */ { - switch (param->type) { - case NUMERIC_PARAM: - phpdbg_switch_frame(param->num TSRMLS_CC); - break; - - case EMPTY_PARAM: - phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num); - break; - - phpdbg_default_switch_case(); - } + if (!param) { + phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num); + } else phpdbg_switch_frame(param->num TSRMLS_CC); return SUCCESS; } /* }}} */ @@ -580,6 +629,31 @@ PHPDBG_COMMAND(run) /* {{{ */ /* reset hit counters */ phpdbg_reset_breakpoints(TSRMLS_C); + if (param && param->type != EMPTY_PARAM && param->len != 0) { + char **argv = emalloc(5 * sizeof(char *)); + int argc = 0; + int i; + char *argv_str = strtok(param->str, " "); + + while (argv_str) { + 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]); + } + argv[0] = SG(request_info).argv[0]; + for (i = SG(request_info).argc; --i;) { + efree(SG(request_info).argv[i]); + } + efree(SG(request_info).argv); + SG(request_info).argv = erealloc(argv, ++argc * sizeof(char *)); + SG(request_info).argc = argc; + + php_hash_environment(TSRMLS_C); + } + zend_try { php_output_activate(TSRMLS_C); PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; @@ -615,42 +689,36 @@ out: return SUCCESS; } /* }}} */ -PHPDBG_COMMAND(eval) /* {{{ */ +PHPDBG_COMMAND(ev) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING); - zval retval; - - if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { - PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING; - } - - /* disable stepping while eval() in progress */ - PHPDBG_G(flags) |= PHPDBG_IN_EVAL; - zend_try { - if (zend_eval_stringl(param->str, param->len, - &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { - zend_print_zval_r( - &retval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); - zval_dtor(&retval); - } - } zend_end_try(); - PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; + zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING); + zval retval; - /* switch stepping back on */ - if (stepping && - !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { - PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; - } + if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING; + } - CG(unclean_shutdown) = 0; - } break; + /* disable stepping while eval() in progress */ + PHPDBG_G(flags) |= PHPDBG_IN_EVAL; + zend_try { + if (zend_eval_stringl(param->str, param->len, + &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { + zend_print_zval_r( + &retval, 0 TSRMLS_CC); + phpdbg_writeln(EMPTY); + zval_dtor(&retval); + } + } zend_end_try(); + PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; - phpdbg_default_switch_case(); + /* switch stepping back on */ + if (stepping && + !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } + CG(unclean_shutdown) = 0; + return SUCCESS; } /* }}} */ @@ -661,14 +729,10 @@ PHPDBG_COMMAND(back) /* {{{ */ return SUCCESS; } - switch (param->type) { - case EMPTY_PARAM: - case NUMERIC_PARAM: - phpdbg_dump_backtrace( - (param->type == NUMERIC_PARAM) ? param->num : 0 TSRMLS_CC); - break; - - phpdbg_default_switch_case(); + if (!param) { + phpdbg_dump_backtrace(0 TSRMLS_CC); + } else { + phpdbg_dump_backtrace(param->num TSRMLS_CC); } return SUCCESS; @@ -676,47 +740,41 @@ PHPDBG_COMMAND(back) /* {{{ */ PHPDBG_COMMAND(print) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: { - phpdbg_writeln(SEPARATE); - phpdbg_notice("Execution Context Information"); + phpdbg_writeln(SEPARATE); + phpdbg_notice("Execution Context Information"); #ifdef HAVE_LIBREADLINE - phpdbg_writeln("Readline\tyes"); + phpdbg_writeln("Readline\tyes"); #else - phpdbg_writeln("Readline\tno"); + phpdbg_writeln("Readline\tno"); #endif - phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); - phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); - phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); - phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); - phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off"); + phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); + phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); + phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); + phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); + phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off"); - if (PHPDBG_G(ops)) { - phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last); - - if (PHPDBG_G(ops)->last_var) { - phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1); - } else { - phpdbg_writeln("Variables\tNone"); - } - } + if (PHPDBG_G(ops)) { + phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last); - phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no"); - if (EG(in_execution)) { - phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret)); - } + if (PHPDBG_G(ops)->last_var) { + phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1); + } else { + phpdbg_writeln("Variables\tNone"); + } + } - phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files))); + phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no"); + if (EG(in_execution)) { + phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret)); + } - phpdbg_writeln(SEPARATE); - } break; + phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files))); - phpdbg_default_switch_case(); - } + phpdbg_writeln(SEPARATE); return SUCCESS; } /* }}} */ @@ -732,19 +790,18 @@ PHPDBG_COMMAND(info) /* {{{ */ PHPDBG_COMMAND(set) /* {{{ */ { phpdbg_error( - "No information command selected!"); + "No set command selected!"); return SUCCESS; } /* }}} */ PHPDBG_COMMAND(break) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: - phpdbg_set_breakpoint_file( + if (!param) { + phpdbg_set_breakpoint_file( zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); - break; + } else switch (param->type) { case ADDR_PARAM: phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC); break; @@ -767,9 +824,18 @@ PHPDBG_COMMAND(break) /* {{{ */ case FILE_PARAM: phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC); break; + case NUMERIC_FILE_PARAM: + phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line TSRMLS_CC); + break; + case COND_PARAM: + phpdbg_set_breakpoint_expression(param->str, param->len TSRMLS_CC); + break; case STR_PARAM: phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC); break; + case OP_PARAM: + phpdbg_set_breakpoint_opcode(param->str, param->len TSRMLS_CC); + break; phpdbg_default_switch_case(); } @@ -777,83 +843,72 @@ PHPDBG_COMMAND(break) /* {{{ */ return SUCCESS; } /* }}} */ -PHPDBG_COMMAND(shell) /* {{{ */ +PHPDBG_COMMAND(sh) /* {{{ */ { - /* don't allow this to loop, ever ... */ - switch (param->type) { - case STR_PARAM: { - FILE *fd = NULL; - if ((fd=VCWD_POPEN((char*)param->str, "w"))) { - /* do something perhaps ?? do we want input ?? */ - fclose(fd); - } else { - phpdbg_error( - "Failed to execute %s", param->str); - } - } break; - - phpdbg_default_switch_case(); + FILE *fd = NULL; + if ((fd=VCWD_POPEN((char*)param->str, "w"))) { + /* do something perhaps ?? do we want input ?? */ + fclose(fd); + } else { + phpdbg_error( + "Failed to execute %s", param->str); } + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(source) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - if (input->argc > 2) { - if (phpdbg_argv_is(1, "export")) { - FILE *h = VCWD_FOPEN(input->argv[2]->string, "w+"); - if (h) { - phpdbg_export_breakpoints(h TSRMLS_CC); - fclose(h); - } else phpdbg_error("Failed to open %s", input->argv[1]->string); - } else { - phpdbg_error( - "Incorrect usage of source command, see help"); - } - } else { - struct stat sb; - if (VCWD_STAT(param->str, &sb) != -1) { - phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC); - } else phpdbg_error("Cannot stat %s", param->str); - } - } break; + struct stat sb; + + if (VCWD_STAT(param->str, &sb) != -1) { + phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC); + } else { + phpdbg_error( + "Failed to stat %s, file does not exist", param->str); + } + + return SUCCESS; +} /* }}} */ - phpdbg_default_switch_case(); +PHPDBG_COMMAND(export) /* {{{ */ +{ + FILE *handle = VCWD_FOPEN(param->str, "w+"); + + if (handle) { + phpdbg_export_breakpoints(handle TSRMLS_CC); + fclose(handle); + } else { + phpdbg_error( + "Failed to open or create %s, check path and permissions", param->str); } + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(register) /* {{{ */ { - switch (param->type) { - case STR_PARAM: { - zend_function *function; - char *lcname = zend_str_tolower_dup(param->str, param->len); - size_t lcname_len = strlen(lcname); - - if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) { - if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) { - zend_hash_update( - &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); - function_add_ref(function); - - phpdbg_notice( - "Registered %s", lcname); - } else { - phpdbg_error("The requested function (%s) could not be found", param->str); - } - } else { - phpdbg_error( - "The requested name (%s) is already in use", lcname); - } - - efree(lcname); - } break; - - phpdbg_default_switch_case(); + zend_function *function; + char *lcname = zend_str_tolower_dup(param->str, param->len); + size_t lcname_len = strlen(lcname); + + if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) { + if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) { + zend_hash_update( + &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); + function_add_ref(function); + + phpdbg_notice( + "Registered %s", lcname); + } else { + phpdbg_error("The requested function (%s) could not be found", param->str); + } + } else { + phpdbg_error( + "The requested name (%s) is already in use", lcname); } + + efree(lcname); return SUCCESS; } /* }}} */ @@ -861,14 +916,11 @@ PHPDBG_COMMAND(quit) /* {{{ */ { /* don't allow this to loop, ever ... */ if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - - phpdbg_destroy_input((phpdbg_input_t**)&input TSRMLS_CC); - PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; zend_bailout(); } - return SUCCESS; + return PHPDBG_NEXT; } /* }}} */ PHPDBG_COMMAND(clean) /* {{{ */ @@ -908,100 +960,12 @@ PHPDBG_COMMAND(clear) /* {{{ */ return SUCCESS; } /* }}} */ -PHPDBG_COMMAND(aliases) /* {{{ */ -{ - const phpdbg_command_t *prompt_command = phpdbg_prompt_commands; - - phpdbg_help_header(); - phpdbg_writeln("Below are the aliased, short versions of all supported commands"); - while (prompt_command && prompt_command->name) { - if (prompt_command->alias) { - if (prompt_command->subs) { - const phpdbg_command_t *sub_command = prompt_command->subs; - phpdbg_writeln(EMPTY); - phpdbg_writeln(" %c -> %9s", prompt_command->alias, prompt_command->name); - while (sub_command && sub_command->name) { - if (sub_command->alias) { - phpdbg_writeln(" |-------- %c -> %15s\t%s", sub_command->alias, - sub_command->name, sub_command->tip); - } - ++sub_command; - } - phpdbg_writeln(EMPTY); - } else { - phpdbg_writeln(" %c -> %9s\t\t\t%s", prompt_command->alias, - prompt_command->name, prompt_command->tip); - } - } - - ++prompt_command; - } - phpdbg_help_footer(); - - return SUCCESS; -} /* }}} */ - -PHPDBG_COMMAND(help) /* {{{ */ -{ - switch (param->type) { - case EMPTY_PARAM: { - const phpdbg_command_t *prompt_command = phpdbg_prompt_commands; - const phpdbg_command_t *help_command = phpdbg_help_commands; - - phpdbg_help_header(); - phpdbg_writeln("To get help regarding a specific command type \"help command\""); - - phpdbg_notice("Commands"); - - while (prompt_command && prompt_command->name) { - phpdbg_writeln( - " %10s\t%s", prompt_command->name, prompt_command->tip); - ++prompt_command; - } - - phpdbg_notice("Help Commands"); - - while (help_command && help_command->name) { - phpdbg_writeln(" %10s\t%s", help_command->name, help_command->tip); - ++help_command; - } - - phpdbg_help_footer(); - } break; - - default: { - phpdbg_error( - "No help can be found for the subject \"%s\"", param->str); - } - } - - return SUCCESS; -} /* }}} */ - -PHPDBG_COMMAND(quiet) /* {{{ */ -{ - switch (param->type) { - case NUMERIC_PARAM: { - if (param->num) { - PHPDBG_G(flags) |= PHPDBG_IS_QUIET; - } else { - PHPDBG_G(flags) &= ~PHPDBG_IS_QUIET; - } - phpdbg_notice("Quietness %s", - (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "enabled" : "disabled"); - } break; - - phpdbg_default_switch_case(); - } - - return SUCCESS; -} /* }}} */ - PHPDBG_COMMAND(list) /* {{{ */ { - switch (param->type) { + if (!param) { + return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS); + } else switch (param->type) { case NUMERIC_PARAM: - case EMPTY_PARAM: return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS); case FILE_PARAM: @@ -1020,54 +984,101 @@ PHPDBG_COMMAND(list) /* {{{ */ return SUCCESS; } /* }}} */ +PHPDBG_COMMAND(watch) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_list_watchpoints(TSRMLS_C); + } else switch (param->type) { + case STR_PARAM: + if (phpdbg_create_var_watchpoint(param->str, param->len TSRMLS_CC) != FAILURE) { + phpdbg_notice("Set watchpoint on %.*s", (int)param->len, param->str); + } + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + int phpdbg_interactive(TSRMLS_D) /* {{{ */ { int ret = SUCCESS; - phpdbg_input_t *input; + char *why = NULL; + char *input = NULL; + phpdbg_param_t stack; PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE; input = phpdbg_read_input(NULL TSRMLS_CC); - if (input && input->length > 0L) { + if (input) { do { - switch (ret = phpdbg_do_cmd(phpdbg_prompt_commands, input TSRMLS_CC)) { - case FAILURE: - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(input TSRMLS_CC) == FAILURE) { - phpdbg_error("Failed to execute %s!", input->string); + yyscan_t scanner; + YY_BUFFER_STATE state; + + phpdbg_init_param(&stack, STACK_PARAM); + + if (yylex_init(&scanner)) { + phpdbg_error( + "could not initialize scanner"); + return FAILURE; + } + + state = yy_scan_string(input, scanner); + + if (yyparse(&stack, scanner) <= 0) { + switch (ret = phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + case FAILURE: + if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + if (why) { + phpdbg_error("%s", why); + } + } } - } - break; - case PHPDBG_LEAVE: - case PHPDBG_FINISH: - case PHPDBG_UNTIL: - case PHPDBG_NEXT: { - if (!EG(in_execution)) { - phpdbg_error("Not running"); + if (why) { + free(why); + why = NULL; + } + break; + + case PHPDBG_LEAVE: + case PHPDBG_FINISH: + case PHPDBG_UNTIL: + case PHPDBG_NEXT: { + if (!EG(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + phpdbg_error("Not running"); + } + goto out; } - goto out; } } - phpdbg_destroy_input(&input TSRMLS_CC); - } while ((input = phpdbg_read_input(NULL TSRMLS_CC)) && (input->length > 0L)); + if (why) { + free(why); + why = NULL; + } - if (input && !input->length) - goto last; + yy_delete_buffer(state, scanner); + yylex_destroy(scanner); - } else { -last: - if (PHPDBG_G(lcmd)) { - ret = PHPDBG_G(lcmd)->handler( - &PHPDBG_G(lparam), input TSRMLS_CC); - goto out; - } + phpdbg_stack_free(&stack); + phpdbg_destroy_input(&input TSRMLS_CC); + + } while ((input = phpdbg_read_input(NULL TSRMLS_CC))); } out: - phpdbg_destroy_input(&input TSRMLS_CC); + if (input) { + phpdbg_stack_free(&stack); + phpdbg_destroy_input(&input TSRMLS_CC); + } + + if (why) { + free(why); + } if (EG(in_execution)) { phpdbg_restore_frame(TSRMLS_C); @@ -1075,6 +1086,8 @@ out: PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE; + phpdbg_print_changed_zvals(TSRMLS_C); + return ret; } /* }}} */ @@ -1214,7 +1227,7 @@ zend_vm_enter: ); \ } \ \ - do { \ +/* do { */\ switch (phpdbg_interactive(TSRMLS_C)) { \ case PHPDBG_LEAVE: \ case PHPDBG_FINISH: \ @@ -1223,7 +1236,7 @@ zend_vm_enter: goto next; \ } \ } \ - } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); \ +/* } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); */\ } while (0) /* allow conditional breakpoints and @@ -1285,22 +1298,30 @@ zend_vm_enter: phpdbg_print_opline_ex( execute_data, &vars, 0 TSRMLS_CC); + if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING && (PHPDBG_G(flags) & PHPDBG_STEP_OPCODE || execute_data->opline->lineno != PHPDBG_G(last_line))) { + PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; + DO_INTERACTIVE(); + } + + /* check if some watchpoint was hit */ + { + if (phpdbg_print_changed_zvals(TSRMLS_C) == SUCCESS) { + DO_INTERACTIVE(); + } + } + /* search for breakpoints */ { phpdbg_breakbase_t *brake; - if ((PHPDBG_G(flags) & PHPDBG_BP_MASK) && - (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC))) { - phpdbg_hit_breakpoint( - brake, 1 TSRMLS_CC); + if ((PHPDBG_G(flags) & PHPDBG_BP_MASK) + && (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC)) + && (brake->type != PHPDBG_BREAK_FILE || execute_data->opline->lineno != PHPDBG_G(last_line))) { + phpdbg_hit_breakpoint(brake, 1 TSRMLS_CC); DO_INTERACTIVE(); } } - if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) { - DO_INTERACTIVE(); - } - next: if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { phpdbg_writeln(EMPTY); @@ -1309,6 +1330,8 @@ next: DO_INTERACTIVE(); } + PHPDBG_G(last_line) = execute_data->opline->lineno; + PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC); if (PHPDBG_G(vmret) > 0) { diff --git a/phpdbg_prompt.h b/phpdbg_prompt.h index 6807d88f41..ef648aabeb 100644 --- a/phpdbg_prompt.h +++ b/phpdbg_prompt.h @@ -30,11 +30,10 @@ void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */ /* {{{ phpdbg command handlers */ PHPDBG_COMMAND(exec); -PHPDBG_COMMAND(compile); PHPDBG_COMMAND(step); -PHPDBG_COMMAND(next); +PHPDBG_COMMAND(continue); PHPDBG_COMMAND(run); -PHPDBG_COMMAND(eval); +PHPDBG_COMMAND(ev); PHPDBG_COMMAND(until); PHPDBG_COMMAND(finish); PHPDBG_COMMAND(leave); @@ -47,13 +46,13 @@ PHPDBG_COMMAND(info); PHPDBG_COMMAND(clean); PHPDBG_COMMAND(clear); PHPDBG_COMMAND(help); -PHPDBG_COMMAND(quiet); -PHPDBG_COMMAND(aliases); -PHPDBG_COMMAND(shell); +PHPDBG_COMMAND(sh); PHPDBG_COMMAND(set); PHPDBG_COMMAND(source); +PHPDBG_COMMAND(export); PHPDBG_COMMAND(register); -PHPDBG_COMMAND(quit); /* }}} */ +PHPDBG_COMMAND(quit); +PHPDBG_COMMAND(watch); /* }}} */ /* {{{ prompt commands */ extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */ diff --git a/phpdbg_set.c b/phpdbg_set.c index 7c4da12a46..54269a8193 100644 --- a/phpdbg_set.c +++ b/phpdbg_set.c @@ -23,56 +23,52 @@ #include "phpdbg_set.h" #include "phpdbg_utils.h" #include "phpdbg_bp.h" +#include "phpdbg_prompt.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -PHPDBG_SET(prompt) /* {{{ */ -{ - switch (param->type) { - case EMPTY_PARAM: - phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C)); - break; +#define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[18]) - case STR_PARAM: - phpdbg_set_prompt(param->str TSRMLS_CC); - break; - - phpdbg_default_switch_case(); - } +const phpdbg_command_t phpdbg_set_commands[] = { + PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt []", 'p', set_prompt, NULL, "|s"), +#ifndef _WIN32 + PHPDBG_SET_COMMAND_D(color, "usage: set color ", 'c', set_color, NULL, "ss"), + PHPDBG_SET_COMMAND_D(colors, "usage: set colors []", 'C', set_colors, NULL, "|b"), +#endif + PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog []", 'O', set_oplog, NULL, "|s"), + PHPDBG_SET_COMMAND_D(break, "usage: set break id []", 'b', set_break, NULL, "l|b"), + PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks []", 'B', set_breaks, NULL, "|b"), + PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet []", 'q', set_quiet, NULL, "|b"), + PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping []", 's', set_stepping, NULL, "|s"), + PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount []", 'r', set_refcount, NULL, "|b"), + PHPDBG_END_COMMAND +}; +PHPDBG_SET(prompt) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C)); + } else phpdbg_set_prompt(param->str TSRMLS_CC); + return SUCCESS; } /* }}} */ PHPDBG_SET(break) /* {{{ */ { switch (param->type) { - case EMPTY_PARAM: - phpdbg_writeln("%s", - PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); - break; - - case STR_PARAM: - if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) { - phpdbg_enable_breakpoints(TSRMLS_C); - } else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) { - phpdbg_disable_breakpoints(TSRMLS_C); - } - break; - case NUMERIC_PARAM: { - if (input->argc > 2) { - if (phpdbg_argv_is(2, "on")) { - phpdbg_enable_breakpoint(param->num TSRMLS_CC); - } else if (phpdbg_argv_is(2, "off")) { - phpdbg_disable_breakpoint(param->num TSRMLS_CC); - } + if (param->next) { + if (param->next->num) { + phpdbg_enable_breakpoint(param->num TSRMLS_CC); + } else phpdbg_disable_breakpoint(param->num TSRMLS_CC); } else { phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC); if (brake) { phpdbg_writeln( "%s", brake->disabled ? "off" : "on"); } else { - phpdbg_error("Failed to find breakpoint #%lx", param->num); + phpdbg_error("Failed to find breakpoint #%ld", param->num); } } } break; @@ -85,104 +81,96 @@ PHPDBG_SET(break) /* {{{ */ return SUCCESS; } /* }}} */ -#ifndef _WIN32 -PHPDBG_SET(color) /* {{{ */ +PHPDBG_SET(breaks) /* {{{ */ { - if ((param->type == STR_PARAM) && (input->argc == 3)) { - const phpdbg_color_t *color = phpdbg_get_color( - input->argv[2]->string, input->argv[2]->length TSRMLS_CC); - int element = PHPDBG_COLOR_INVALID; - - /* @TODO(anyone) make this consistent with other set commands */ - if (color) { - if (phpdbg_argv_is(1, "prompt")) { - phpdbg_notice( - "setting prompt color to %s (%s)", color->name, color->code); - element = PHPDBG_COLOR_PROMPT; - if (PHPDBG_G(prompt)[1]) { - free(PHPDBG_G(prompt)[1]); - PHPDBG_G(prompt)[1]=NULL; - } - } else if (phpdbg_argv_is(1, "error")) { - phpdbg_notice( - "setting error color to %s (%s)", color->name, color->code); - element = PHPDBG_COLOR_ERROR; + if (!param || param->type == EMPTY_PARAM) { + phpdbg_writeln("%s", + PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); + } else switch (param->type) { + case NUMERIC_PARAM: { + if (param->num) { + phpdbg_enable_breakpoints(TSRMLS_C); + } else phpdbg_disable_breakpoints(TSRMLS_C); + } break; - } else if (phpdbg_argv_is(1, "notice")) { - phpdbg_notice( - "setting notice color to %s (%s)", color->name, color->code); - element = PHPDBG_COLOR_NOTICE; + default: + phpdbg_error( + "set break used incorrectly: set break [id] "); + } - } else goto usage; + return SUCCESS; +} /* }}} */ - /* set color for element */ - phpdbg_set_color(element, color TSRMLS_CC); - } else { - phpdbg_error( - "Failed to find the requested color (%s)", input->argv[2]->string); - } - } else { -usage: +#ifndef _WIN32 +PHPDBG_SET(color) /* {{{ */ +{ + const phpdbg_color_t *color = phpdbg_get_color( + param->next->str, param->next->len TSRMLS_CC); + + if (!color) { phpdbg_error( - "set color used incorrectly: set color "); + "Failed to find the requested color (%s)", param->next->str); + return SUCCESS; } + + switch (phpdbg_get_element(param->str, param->len TSRMLS_CC)) { + case PHPDBG_COLOR_PROMPT: + phpdbg_notice( + "setting prompt color to %s (%s)", color->name, color->code); + if (PHPDBG_G(prompt)[1]) { + free(PHPDBG_G(prompt)[1]); + PHPDBG_G(prompt)[1]=NULL; + } + phpdbg_set_color(PHPDBG_COLOR_PROMPT, color TSRMLS_CC); + break; + + case PHPDBG_COLOR_ERROR: + phpdbg_notice( + "setting error color to %s (%s)", color->name, color->code); + phpdbg_set_color(PHPDBG_COLOR_ERROR, color TSRMLS_CC); + break; + + case PHPDBG_COLOR_NOTICE: + phpdbg_notice( + "setting notice color to %s (%s)", color->name, color->code); + phpdbg_set_color(PHPDBG_COLOR_NOTICE, color TSRMLS_CC); + break; + + default: + phpdbg_error( + "Failed to find the requested element (%s)", param->str); + } + return SUCCESS; } /* }}} */ PHPDBG_SET(colors) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: { - phpdbg_writeln( - "%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); - goto done; - } - - case STR_PARAM: { - if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) { + if (!param || param->type == EMPTY_PARAM) { + phpdbg_writeln("%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); + } else switch (param->type) { + case NUMERIC_PARAM: { + if (param->num) { PHPDBG_G(flags) |= PHPDBG_IS_COLOURED; - goto done; - } else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) { + } else { PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED; - goto done; } - } + } break; default: phpdbg_error( "set colors used incorrectly: set colors "); } -done: return SUCCESS; } /* }}} */ #endif PHPDBG_SET(oplog) /* {{{ */ { - switch (param->type) { - case EMPTY_PARAM: - phpdbg_notice( - "Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled"); - break; - - case NUMERIC_PARAM: switch (param->num) { - case 1: - phpdbg_error( - "An output file must be provided to enable oplog"); - break; - - case 0: { - if (PHPDBG_G(oplog)) { - phpdbg_notice("Disabling oplog"); - fclose( - PHPDBG_G(oplog)); - } else { - phpdbg_error("Oplog is not enabled!"); - } - } break; - } break; - + if (!param || param->type == EMPTY_PARAM) { + phpdbg_notice("Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled"); + } else switch (param->type) { case STR_PARAM: { /* open oplog */ FILE *old = PHPDBG_G(oplog); @@ -206,3 +194,65 @@ PHPDBG_SET(oplog) /* {{{ */ return SUCCESS; } /* }}} */ +PHPDBG_SET(quiet) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_writeln("Quietness %s", + PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); + } else switch (param->type) { + case NUMERIC_PARAM: { + if (param->num) { + PHPDBG_G(flags) |= PHPDBG_IS_QUIET; + } else { + PHPDBG_G(flags) &= ~PHPDBG_IS_QUIET; + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_SET(stepping) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_writeln("Stepping %s", + PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line"); + } else switch (param->type) { + case STR_PARAM: { + if ((param->len == sizeof("opcode")-1) && + (memcmp(param->str, "opcode", sizeof("opcode")) == SUCCESS)) { + PHPDBG_G(flags) |= PHPDBG_STEP_OPCODE; + } else if ((param->len == sizeof("line")-1) && + (memcmp(param->str, "line", sizeof("line")) == SUCCESS)) { + PHPDBG_G(flags) &= ~PHPDBG_STEP_OPCODE; + } else { + phpdbg_error("usage set stepping []"); + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_SET(refcount) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_writeln("Refcount %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); + } else switch (param->type) { + case NUMERIC_PARAM: { + if (param->num) { + PHPDBG_G(flags) |= PHPDBG_SHOW_REFCOUNTS; + } else { + PHPDBG_G(flags) &= ~PHPDBG_SHOW_REFCOUNTS; + } + } break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ diff --git a/phpdbg_set.h b/phpdbg_set.h index 120aeb34f4..dea61ed382 100644 --- a/phpdbg_set.h +++ b/phpdbg_set.h @@ -32,16 +32,11 @@ PHPDBG_SET(colors); #endif PHPDBG_SET(oplog); PHPDBG_SET(break); +PHPDBG_SET(breaks); +PHPDBG_SET(quiet); +PHPDBG_SET(stepping); +PHPDBG_SET(refcount); -static const phpdbg_command_t phpdbg_set_commands[] = { - PHPDBG_COMMAND_D_EX(prompt, "usage: set prompt ", 'p', set_prompt, NULL, 0), -#ifndef _WIN32 - PHPDBG_COMMAND_D_EX(color, "usage: set color ", 'c', set_color, NULL, 1), - PHPDBG_COMMAND_D_EX(colors, "usage: set colors ", 'C', set_colors, NULL, 1), -#endif - PHPDBG_COMMAND_D_EX(oplog, "usage: set oplog ", 'O', set_oplog, NULL, 0), - PHPDBG_COMMAND_D_EX(break, "usage: set break [id] ", 'b', set_break, NULL, 0), - PHPDBG_END_COMMAND -}; +extern const phpdbg_command_t phpdbg_set_commands[]; #endif /* PHPDBG_SET_H */ diff --git a/phpdbg_utils.c b/phpdbg_utils.c index 1effcfccaf..c9b22a2039 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -30,6 +30,8 @@ #ifdef _WIN32 # include "win32/time.h" +#elif defined(HAVE_SYS_IOCTL_H) +# include "sys/ioctl.h" #endif ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -65,6 +67,14 @@ const static phpdbg_color_t colors[] = { PHPDBG_COLOR_END }; /* }}} */ +/* {{{ */ +const static phpdbg_element_t elements[] = { + PHPDBG_ELEMENT_D("prompt", PHPDBG_COLOR_PROMPT), + PHPDBG_ELEMENT_D("error", PHPDBG_COLOR_ERROR), + PHPDBG_ELEMENT_D("notice", PHPDBG_COLOR_NOTICE), + PHPDBG_ELEMENT_END +}; /* }}} */ + PHPDBG_API int phpdbg_is_numeric(const char *str) /* {{{ */ { if (!str) @@ -347,6 +357,21 @@ PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D) /* {{{ */ return colors; } /* }}} */ +PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC) { + const phpdbg_element_t *element = elements; + + while (element && element->name) { + if (len == element->name_length) { + if (strncasecmp(name, element->name, len) == SUCCESS) { + return element->id; + } + } + element++; + } + + return PHPDBG_COLOR_INVALID; +} + PHPDBG_API void phpdbg_set_prompt(const char *prompt TSRMLS_DC) /* {{{ */ { /* free formatted prompt */ @@ -385,3 +410,39 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */ return PHPDBG_G(prompt)[1]; } /* }}} */ + +int phpdbg_rebuild_symtable(TSRMLS_D) { + if (!EG(active_op_array)) { + phpdbg_error("No active op array!"); + return FAILURE; + } + + if (!EG(active_symbol_table)) { + zend_rebuild_symbol_table(TSRMLS_C); + + if (!EG(active_symbol_table)) { + phpdbg_error("No active symbol table!"); + return FAILURE; + } + } + + return SUCCESS; +} + +PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */ +{ + int columns; +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; +#elif defined(HAVE_SYS_IOCTL_H) + struct winsize w; + + columns = ioctl(fileno(stdout), TIOCGWINSZ, &w) == 0 ? w.ws_col : 100; +#else + columns = 100; +#endif + return columns; +} /* }}} */ diff --git a/phpdbg_utils.h b/phpdbg_utils.h index c5164c3ac3..68ae7e44a3 100644 --- a/phpdbg_utils.h +++ b/phpdbg_utils.h @@ -85,12 +85,17 @@ PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...); {color, sizeof(color)-1, code} #define PHPDBG_COLOR_END \ {NULL, 0L, {0}} +#define PHPDBG_ELEMENT_LEN 3 +#define PHPDBG_ELEMENT_D(name, id) \ + {name, sizeof(name)-1, id} +#define PHPDBG_ELEMENT_END \ + {NULL, 0L, 0} #define PHPDBG_COLOR_INVALID -1 -#define PHPDBG_COLOR_PROMPT 0 -#define PHPDBG_COLOR_ERROR 1 -#define PHPDBG_COLOR_NOTICE 2 -#define PHPDBG_COLORS 3 +#define PHPDBG_COLOR_PROMPT 0 +#define PHPDBG_COLOR_ERROR 1 +#define PHPDBG_COLOR_NOTICE 2 +#define PHPDBG_COLORS 3 typedef struct _phpdbg_color_t { char *name; @@ -98,13 +103,25 @@ typedef struct _phpdbg_color_t { const char code[PHPDBG_COLOR_LEN]; } phpdbg_color_t; +typedef struct _phpdbg_element_t { + char *name; + size_t name_length; + int id; +} phpdbg_element_t; + PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC); PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC); PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC); -PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D); /* }}} */ +PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D); +PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC); /* }}} */ /* {{{ Prompt Management */ PHPDBG_API void phpdbg_set_prompt(const char* TSRMLS_DC); PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */ +/* {{{ Console Width */ +PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */ + +int phpdbg_rebuild_symtable(TSRMLS_D); + #endif /* PHPDBG_UTILS_H */ diff --git a/phpdbg_watch.c b/phpdbg_watch.c new file mode 100644 index 0000000000..a6bf6289bf --- /dev/null +++ b/phpdbg_watch.c @@ -0,0 +1,789 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "phpdbg.h" +#include "phpdbg_btree.h" +#include "phpdbg_watch.h" +#include "phpdbg_utils.h" +#ifndef _WIN32 +# include +# include +#endif + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + + +typedef struct { + void *page; + size_t size; + char reenable_writing; + /* data must be last element */ + void *data; +} phpdbg_watch_memdump; + +#define MEMDUMP_SIZE(size) (sizeof(phpdbg_watch_memdump) - sizeof(void *) + (size)) + + +static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr TSRMLS_DC) { + 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); + + if (result == NULL) { + return NULL; + } + + watch = result->ptr; + + /* check if that addr is in a mprotect()'ed memory area */ + if ((char *)phpdbg_get_page_boundary(watch->addr.ptr) > (char *)addr || (char *)phpdbg_get_page_boundary(watch->addr.ptr) + phpdbg_get_total_page_size(watch->addr.ptr, watch->size) < (char *)addr) { + /* failure */ + return NULL; + } + + return watch; +} + +static void phpdbg_change_watchpoint_access(phpdbg_watchpoint_t *watch, int access TSRMLS_DC) { + int m; + + /* pagesize is assumed to be in the range of 2^x */ + m = mprotect(phpdbg_get_page_boundary(watch->addr.ptr), phpdbg_get_total_page_size(watch->addr.ptr, watch->size), access); +} + +static inline void phpdbg_activate_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + phpdbg_change_watchpoint_access(watch, PROT_READ TSRMLS_CC); +} + +static inline void phpdbg_deactivate_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + phpdbg_change_watchpoint_access(watch, PROT_READ | PROT_WRITE TSRMLS_CC); +} + +static inline void phpdbg_store_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + phpdbg_btree_insert(&PHPDBG_G(watchpoint_tree), (zend_ulong)watch->addr.ptr, watch); +} + +static inline void phpdbg_remove_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + 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) { + watch->addr.ptr = addr; + watch->size = size; +} + +void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch) { + phpdbg_create_addr_watchpoint(zv, sizeof(zval), watch); + watch->type = WATCH_ON_ZVAL; +} + +void phpdbg_create_ht_watchpoint(HashTable *ht, phpdbg_watchpoint_t *watch) { + phpdbg_create_addr_watchpoint(ht, sizeof(HashTable), watch); + watch->type = WATCH_ON_HASHTABLE; +} + +void phpdbg_watch_HashTable_dtor(zval **ptr); + +static int phpdbg_create_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + watch->flags |= PHPDBG_WATCH_SIMPLE; + + phpdbg_store_watchpoint(watch TSRMLS_CC); + zend_hash_add(&PHPDBG_G(watchpoints), watch->str, watch->str_len, &watch, sizeof(phpdbg_watchpoint_t *), NULL); + + if (watch->type == WATCH_ON_ZVAL) { + phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong)watch->parent_container, watch->parent_container->pDestructor); + watch->parent_container->pDestructor = (dtor_func_t)phpdbg_watch_HashTable_dtor; + } + + phpdbg_activate_watchpoint(watch TSRMLS_CC); + + return SUCCESS; +} + +static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + HashTable *ht; + + switch (Z_TYPE_P(watch->addr.zv)) { + case IS_ARRAY: + ht = Z_ARRVAL_P(watch->addr.zv); + break; + case IS_OBJECT: + ht = Z_OBJPROP_P(watch->addr.zv); + break; + default: + return FAILURE; + } + + phpdbg_create_ht_watchpoint(ht, watch); + + phpdbg_create_watchpoint(watch TSRMLS_CC); + + return SUCCESS; +} + +static char *phpdbg_get_property_key(char *key) { + if (*key != 0) { + return key; + } + return strchr(key + 1, 0) + 1; +} + +static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { + HashTable *ht; + + if (watch->type != WATCH_ON_ZVAL) { + return FAILURE; + } + + watch->flags |= PHPDBG_WATCH_RECURSIVE; + phpdbg_create_watchpoint(watch TSRMLS_CC); + + switch (Z_TYPE_P(watch->addr.zv)) { + case IS_ARRAY: + ht = Z_ARRVAL_P(watch->addr.zv); + break; + case IS_OBJECT: + ht = Z_OBJPROP_P(watch->addr.zv); + break; + default: + return SUCCESS; + } + + { + HashPosition position; + zval **zv; + zval key; + + for (zend_hash_internal_pointer_reset_ex(ht, &position); + zend_hash_get_current_data_ex(ht, (void **)&zv, &position) == SUCCESS; + zend_hash_move_forward_ex(ht, &position)) { + phpdbg_watchpoint_t *new_watch = emalloc(sizeof(phpdbg_watchpoint_t)); + + new_watch->flags = PHPDBG_WATCH_RECURSIVE; + new_watch->parent = watch; + new_watch->parent_container = ht; + + zend_hash_get_current_key_zval_ex(ht, &key, &position); + if (Z_TYPE(key) == IS_STRING) { + new_watch->name_in_parent = zend_strndup(Z_STRVAL(key), Z_STRLEN(key)); + new_watch->name_in_parent_len = Z_STRLEN(key); + } else { + new_watch->name_in_parent = NULL; + new_watch->name_in_parent_len = asprintf(&new_watch->name_in_parent, "%ld", Z_LVAL(key)); + } + + new_watch->str = NULL; + new_watch->str_len = asprintf(&new_watch->str, "%.*s%s%s%s", (int)watch->str_len, watch->str, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(new_watch->name_in_parent), Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"]":""); + + phpdbg_create_zval_watchpoint(*zv, new_watch); + phpdbg_create_recursive_watchpoint(new_watch TSRMLS_CC); + } + } + + { + phpdbg_watchpoint_t *new_watch = emalloc(sizeof(phpdbg_watchpoint_t)); + + new_watch->parent = watch; + new_watch->parent_container = watch->parent_container; + new_watch->name_in_parent = zend_strndup(watch->name_in_parent, watch->name_in_parent_len); + new_watch->name_in_parent_len = watch->name_in_parent_len; + new_watch->str = NULL; + new_watch->str_len = asprintf(&new_watch->str, "%.*s[]", (int)watch->str_len, watch->str); + new_watch->flags = PHPDBG_WATCH_RECURSIVE; + + phpdbg_create_ht_watchpoint(ht, new_watch); + phpdbg_create_watchpoint(new_watch TSRMLS_CC); + } + + return SUCCESS; +} + +static int phpdbg_delete_watchpoint_recursive(phpdbg_watchpoint_t *watch, zend_bool user_request TSRMLS_DC) { + if (watch->type == WATCH_ON_HASHTABLE || (watch->type == WATCH_ON_ZVAL && (Z_TYPE_P(watch->addr.zv) == IS_ARRAY || Z_TYPE_P(watch->addr.zv) == IS_OBJECT))) { + HashTable *ht; + phpdbg_btree_result *result; + + if (watch->type == WATCH_ON_HASHTABLE && user_request) { + HashPosition position; + zval **zv; + zval key; + char *str; + int str_len; + phpdbg_watchpoint_t **watchpoint; + + ht = watch->addr.ht; + + for (zend_hash_internal_pointer_reset_ex(ht, &position); + zend_hash_get_current_data_ex(ht, (void **)&zv, &position) == SUCCESS; + zend_hash_move_forward_ex(ht, &position)) { + zend_hash_get_current_key_zval_ex(ht, &key, &position); + str = NULL; + if (Z_TYPE(key) == IS_STRING) { + str_len = asprintf(&str, "%.*s%s%s%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(Z_STRVAL(key)), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":""); + } else { + str_len = asprintf(&str, "%.*s%s%li%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_LVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":""); + } + + if (zend_hash_find(&PHPDBG_G(watchpoints), str, str_len, (void **) &watchpoint) == SUCCESS) { + phpdbg_delete_watchpoint_recursive(*watchpoint, 1 TSRMLS_CC); + } + } + } else { + switch (Z_TYPE_P(watch->addr.zv)) { + case IS_ARRAY: + ht = Z_ARRVAL_P(watch->addr.zv); + break; + case IS_OBJECT: + ht = Z_OBJPROP_P(watch->addr.zv); + break; + } + + if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) ht))) { + phpdbg_delete_watchpoint_recursive((phpdbg_watchpoint_t *) result->ptr, user_request TSRMLS_CC); + } + } + } + + return zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); +} + +static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) { + int ret; + phpdbg_watchpoint_t *watch; + phpdbg_btree_result *result; + + if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)tmp_watch->addr.ptr)) == NULL) { + return FAILURE; + } + + watch = result->ptr; + + if (watch->flags & PHPDBG_WATCH_RECURSIVE) { + ret = phpdbg_delete_watchpoint_recursive(watch, 1 TSRMLS_CC); + } else { + ret = zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + } + + free(tmp_watch->str); + efree(tmp_watch); + + return ret; +} + +static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) { + int ret = FAILURE; + zend_bool new_index = 1; + char *last_index; + int index_len = 0; + zval **zv; + + if (len < 2 || *input != '$') { + goto error; + } + + while (i++ < len) { + if (i == len) { + new_index = 1; + } else { + switch (input[i]) { + case '[': + new_index = 1; + break; + case ']': + break; + case '>': + if (last_index[index_len - 1] == '-') { + new_index = 1; + index_len--; + } + break; + + default: + if (new_index) { + last_index = input + i; + new_index = 0; + } + if (input[i - 1] == ']') { + goto error; + } + index_len++; + } + } + + if (new_index && index_len == 0) { + HashPosition position; + for (zend_hash_internal_pointer_reset_ex(parent, &position); + zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS; + zend_hash_move_forward_ex(parent, &position)) { + if (i == len || (i == len - 1 && input[len - 1] == ']')) { + zval *key = emalloc(sizeof(zval)); + phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); + watch->flags = 0; + zend_hash_get_current_key_zval_ex(parent, key, &position); + convert_to_string(key); + watch->str = malloc(i + Z_STRLEN_P(key) + 2); + watch->str_len = sprintf(watch->str, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":""); + efree(key); + watch->name_in_parent = zend_strndup(last_index, index_len); + watch->name_in_parent_len = index_len; + watch->parent_container = parent; + phpdbg_create_zval_watchpoint(*zv, watch); + + ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; + } else if (Z_TYPE_PP(zv) == IS_OBJECT) { + phpdbg_watchpoint_parse_input(input, len, Z_OBJPROP_PP(zv), i, callback, silent TSRMLS_CC); + } else if (Z_TYPE_PP(zv) == IS_ARRAY) { + phpdbg_watchpoint_parse_input(input, len, Z_ARRVAL_PP(zv), i, callback, silent TSRMLS_CC); + } else { + /* Ignore silently */ + } + } + return ret; + } else if (new_index) { + char last_chr = last_index[index_len]; + last_index[index_len] = 0; + if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) { + if (!silent) { + phpdbg_error("%.*s is undefined", (int)i, input); + } + return FAILURE; + } + last_index[index_len] = last_chr; + if (i == len) { + phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); + watch->flags = 0; + watch->str = zend_strndup(input, len); + watch->str_len = len; + watch->name_in_parent = zend_strndup(last_index, index_len); + watch->name_in_parent_len = index_len; + watch->parent_container = parent; + phpdbg_create_zval_watchpoint(*zv, watch); + + ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; + } else if (Z_TYPE_PP(zv) == IS_OBJECT) { + parent = Z_OBJPROP_PP(zv); + } else if (Z_TYPE_PP(zv) == IS_ARRAY) { + parent = Z_ARRVAL_PP(zv); + } else { + phpdbg_error("%.*s is nor an array nor an object", (int)i, input); + return FAILURE; + } + index_len = 0; + } + } + + return ret; + error: + phpdbg_error("Malformed input"); + return FAILURE; +} + +static int phpdbg_watchpoint_parse_symtables(char *input, size_t len, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) { + if (EG(This) && len >= 5 && !memcmp("$this", input, 5)) { + zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), NULL); + } + + if (zend_is_auto_global(input, len TSRMLS_CC) && phpdbg_watchpoint_parse_input(input, len, &EG(symbol_table), 0, callback, 1 TSRMLS_CC) != FAILURE) { + return SUCCESS; + } + + return phpdbg_watchpoint_parse_input(input, len, EG(active_symbol_table), 0, callback, 0 TSRMLS_CC); +} + +PHPDBG_WATCH(delete) /* {{{ */ +{ + switch (param->type) { + case STR_PARAM: + if (phpdbg_delete_var_watchpoint(param->str, param->len TSRMLS_CC) == FAILURE) { + phpdbg_error("Nothing was deleted, no corresponding watchpoint found"); + } else { + phpdbg_notice("Removed watchpoint %.*s", (int)param->len, param->str); + } + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_WATCH(recursive) /* {{{ */ +{ + if (phpdbg_rebuild_symtable(TSRMLS_C) == FAILURE) { + return SUCCESS; + } + + switch (param->type) { + case STR_PARAM: + if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_recursive_watchpoint TSRMLS_CC) != FAILURE) { + phpdbg_notice("Set recursive watchpoint on %.*s", (int)param->len, param->str); + } + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +PHPDBG_WATCH(array) /* {{{ */ +{ + if (phpdbg_rebuild_symtable(TSRMLS_C) == FAILURE) { + return SUCCESS; + } + + switch (param->type) { + case STR_PARAM: + if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_array_watchpoint TSRMLS_CC) != FAILURE) { + phpdbg_notice("Set array watchpoint on %.*s", (int)param->len, param->str); + } + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + +void phpdbg_watch_HashTable_dtor(zval **zv) { + TSRMLS_FETCH(); + + phpdbg_btree_result *result; + zval_ptr_dtor_wrapper(zv); + + + if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)*zv))) { + phpdbg_watchpoint_t *watch = result->ptr; + + PHPDBG_G(watchpoint_hit) = 1; + + phpdbg_notice("%.*s was removed, removing watchpoint%s", (int)watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_RECURSIVE)?" recursively":""); + + if (watch->flags & PHPDBG_WATCH_RECURSIVE) { + phpdbg_delete_watchpoint_recursive(watch, 0 TSRMLS_CC); + } else { + zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + } + } +} + + +int phpdbg_create_var_watchpoint(char *input, size_t len TSRMLS_DC) { + if (phpdbg_rebuild_symtable(TSRMLS_C) == FAILURE) { + return FAILURE; + } + + return phpdbg_watchpoint_parse_symtables(input, len, phpdbg_create_watchpoint TSRMLS_CC); +} + +int phpdbg_delete_var_watchpoint(char *input, size_t len TSRMLS_DC) { + if (phpdbg_rebuild_symtable(TSRMLS_C) == FAILURE) { + return FAILURE; + } + + return phpdbg_watchpoint_parse_symtables(input, len, phpdbg_delete_watchpoint TSRMLS_CC); +} + +#ifdef _WIN32 +int phpdbg_watchpoint_segfault_handler(void *addr TSRMLS_DC) { +#else +int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC) { +#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 + TSRMLS_CC); + + 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(TSRMLS_D) { + zend_hash_clean(&PHPDBG_G(watchpoints)); +} + +static void phpdbg_watch_dtor(void *pDest) { + TSRMLS_FETCH(); + + phpdbg_watchpoint_t *watch = *(phpdbg_watchpoint_t **)pDest; + + phpdbg_deactivate_watchpoint(watch TSRMLS_CC); + phpdbg_remove_watchpoint(watch TSRMLS_CC); + + free(watch->str); + free(watch->name_in_parent); + efree(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(*(void **)llist_data); +} + +void phpdbg_setup_watchpoints(TSRMLS_D) { +#if _SC_PAGE_SIZE + phpdbg_pagesize = sysconf(_SC_PAGE_SIZE); +#elif _SC_PAGESIZE + phpdbg_pagesize = sysconf(_SC_PAGESIZE); +#elif _SC_NUTC_OS_PAGESIZE + phpdbg_pagesize = sysconf(_SC_NUTC_OS_PAGESIZE); +#else + 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, phpdbg_watch_dtor, 0 ZEND_FILE_LINE_CC); +} + +static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { + /* 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, *htresult; + int elementDiff; + void *curTest; + + dump->reenable_writing = 0; + + while ((result = phpdbg_btree_next(&pos))) { + phpdbg_watchpoint_t *watch = result->ptr, *htwatch; + void *oldPtr = (char *)&dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page); + char reenable = 1; + + if (watch->addr.ptr < dump->page || watch->addr.ptr + watch->size > dump->page + dump->size) { + continue; + } + + /* Test if the zval was separated and if necessary move the watchpoint */ + if (zend_hash_find(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len + 1, &curTest) == SUCCESS) { + if (watch->type == WATCH_ON_HASHTABLE) { + switch (Z_TYPE_PP((zval **)curTest)) { + case IS_ARRAY: + curTest = (void *)Z_ARRVAL_PP((zval **)curTest); + break; + case IS_OBJECT: + curTest = (void *)Z_OBJPROP_PP((zval **)curTest); + break; + } + } else { + curTest = *(void **)curTest; + } + + if (curTest != watch->addr.ptr) { + phpdbg_deactivate_watchpoint(watch TSRMLS_CC); + phpdbg_remove_watchpoint(watch TSRMLS_CC); + watch->addr.ptr = curTest; + phpdbg_store_watchpoint(watch TSRMLS_CC); + phpdbg_activate_watchpoint(watch TSRMLS_CC); + + reenable = 0; + } + } + + /* Show to the user what changed and delete watchpoint upon removal */ + if (memcmp(oldPtr, watch->addr.ptr, watch->size) != SUCCESS) { + if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS || (watch->type == WATCH_ON_ZVAL && memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value))) || (watch->type == WATCH_ON_HASHTABLE +#if ZEND_DEBUG + && !watch->addr.ht->inconsistent +#endif + && zend_hash_num_elements((HashTable *)oldPtr) != zend_hash_num_elements(watch->addr.ht))) { + PHPDBG_G(watchpoint_hit) = 1; + + phpdbg_notice("Breaking on watchpoint %s", watch->str); + } + + switch (watch->type) { + case WATCH_ON_ZVAL: { + int removed = ((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc && !zend_symtable_exists(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len + 1); + int show_value = memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value)); + int show_ref = ((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc || ((zval *)oldPtr)->is_ref__gc != watch->addr.zv->is_ref__gc; + + if (removed || show_value) { + phpdbg_write("Old value: "); + if ((Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) && removed) { + phpdbg_writeln("Value inaccessible, HashTable already destroyed"); + } else { + zend_print_flat_zval_r((zval *)oldPtr TSRMLS_CC); + phpdbg_writeln(""); + } + } + if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && (removed || show_ref)) { + phpdbg_writeln("Old refcount: %d; Old is_ref: %d", ((zval *)oldPtr)->refcount__gc, ((zval *)oldPtr)->is_ref__gc); + } + + /* check if zval was removed */ + if (removed) { + phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str); + zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + + reenable = 0; + + if (Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) { + goto remove_ht_watch; + } + + break; + } + + if (show_value) { + phpdbg_write("New value: "); + zend_print_flat_zval_r(watch->addr.zv TSRMLS_CC); + phpdbg_writeln(""); + } + if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && show_ref) { + phpdbg_writeln("New refcount: %d; New is_ref: %d", watch->addr.zv->refcount__gc, watch->addr.zv->is_ref__gc); + } + + if ((Z_TYPE_P(watch->addr.zv) == IS_ARRAY && Z_ARRVAL_P(watch->addr.zv) != Z_ARRVAL_P((zval *)oldPtr)) || (Z_TYPE_P(watch->addr.zv) != IS_OBJECT && Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) { + /* add new watchpoints if necessary */ + if (watch->flags & PHPDBG_WATCH_RECURSIVE) { + phpdbg_create_recursive_watchpoint(watch TSRMLS_CC); + } + } + + if ((Z_TYPE_P((zval *)oldPtr) != IS_ARRAY || Z_ARRVAL_P(watch->addr.zv) == Z_ARRVAL_P((zval *)oldPtr)) && (Z_TYPE_P((zval *)oldPtr) != IS_OBJECT || Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) { + break; + } + +remove_ht_watch: + if ((htresult = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)Z_ARRVAL_P((zval *)oldPtr)))) { + htwatch = htresult->ptr; + zend_hash_del(&PHPDBG_G(watchpoints), htwatch->str, htwatch->str_len); + } + + break; + } + case WATCH_ON_HASHTABLE: + +#ifdef ZEND_DEBUG + if (watch->addr.ht->inconsistent) { + phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str); + zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + + reenable = 0; + + break; + } +#endif + + elementDiff = zend_hash_num_elements((HashTable *)oldPtr) - zend_hash_num_elements(watch->addr.ht); + if (elementDiff) { + if (elementDiff > 0) { + phpdbg_writeln("%d elements were removed from the array", elementDiff); + } else { + phpdbg_writeln("%d elements were added to the array", -elementDiff); + + /* add new watchpoints if necessary */ + if (watch->flags & PHPDBG_WATCH_RECURSIVE) { + phpdbg_create_recursive_watchpoint(watch TSRMLS_CC); + } + } + } + if (((HashTable *)oldPtr)->pInternalPointer != watch->addr.ht->pInternalPointer) { + phpdbg_writeln("Internal pointer of array was changed"); + } + break; + } + } + + dump->reenable_writing = dump->reenable_writing | reenable; + } +} + +int phpdbg_print_changed_zvals(TSRMLS_D) { + 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 TSRMLS_CC); + } 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; +} + +void phpdbg_list_watchpoints(TSRMLS_D) { + HashPosition position; + phpdbg_watchpoint_t **watch; + + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(watchpoints), &position); + zend_hash_get_current_data_ex(&PHPDBG_G(watchpoints), (void**) &watch, &position) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(watchpoints), &position)) { + phpdbg_writeln("%.*s", (int)(*watch)->str_len, (*watch)->str); + } +} + +void phpdbg_watch_efree(void *ptr) { + TSRMLS_FETCH(); + phpdbg_btree_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) { + zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + } + } + + PHPDBG_G(original_free_function)(ptr); +} diff --git a/phpdbg_watch.h b/phpdbg_watch.h new file mode 100644 index 0000000000..d00bcff77e --- /dev/null +++ b/phpdbg_watch.h @@ -0,0 +1,112 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WATCH_H +#define PHPDBG_WATCH_H + +#include "TSRM.h" +#include "phpdbg_cmd.h" + +#ifdef _WIN32 +# include "phpdbg_win.h" +#endif + +#define PHPDBG_WATCH(name) PHPDBG_COMMAND(watch_##name) + +/** + * Printer Forward Declarations + */ +PHPDBG_WATCH(array); +PHPDBG_WATCH(delete); +PHPDBG_WATCH(recursive); + +/** + * Commands + */ + +static const phpdbg_command_t phpdbg_watch_commands[] = { + PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s"), + PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s"), + PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s"), + PHPDBG_END_COMMAND +}; + +/* Watchpoint functions/typedefs */ + +typedef enum { + WATCH_ON_ZVAL, + WATCH_ON_HASHTABLE, +} phpdbg_watchtype; + + +#define PHPDBG_WATCH_SIMPLE 0x0 +#define PHPDBG_WATCH_RECURSIVE 0x1 + +typedef struct _phpdbg_watchpoint_t phpdbg_watchpoint_t; + +struct _phpdbg_watchpoint_t { + phpdbg_watchpoint_t *parent; + HashTable *parent_container; + char *name_in_parent; + size_t name_in_parent_len; + char *str; + size_t str_len; + union { + zval *zv; + HashTable *ht; + void *ptr; + } addr; + size_t size; + phpdbg_watchtype type; + char flags; +}; + +void phpdbg_setup_watchpoints(TSRMLS_D); + +#ifndef _WIN32 +int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC); +#else +int phpdbg_watchpoint_segfault_handler(void *addr TSRMLS_DC); +#endif + +void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch); +void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch); + +int phpdbg_delete_var_watchpoint(char *input, size_t len TSRMLS_DC); +int phpdbg_create_var_watchpoint(char *input, size_t len TSRMLS_DC); + +int phpdbg_print_changed_zvals(TSRMLS_D); + +void phpdbg_list_watchpoints(TSRMLS_D); + +void phpdbg_watch_efree(void *ptr); + + +static long phpdbg_pagesize; + +static zend_always_inline void *phpdbg_get_page_boundary(void *addr) { + return (void *)((size_t)addr & ~(phpdbg_pagesize - 1)); +} + +static zend_always_inline size_t phpdbg_get_total_page_size(void *addr, size_t size) { + return (size_t)phpdbg_get_page_boundary((void *)((size_t)addr + size - 1)) - (size_t)phpdbg_get_page_boundary(addr) + phpdbg_pagesize; +} + +#endif diff --git a/phpdbg_win.c b/phpdbg_win.c new file mode 100644 index 0000000000..b0cbdf267a --- /dev/null +++ b/phpdbg_win.c @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "phpdbg.h" + +int mprotect(void *addr, size_t size, int protection) { + int var; + return (int)VirtualProtect(addr, size, protection == (PROT_READ | PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, &var); +} + +int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp) { + EXCEPTION_RECORD *xr = xp->ExceptionRecord; + CONTEXT *xc = xp->ContextRecord; + + if(xr->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + TSRMLS_FETCH(); + + if (phpdbg_watchpoint_segfault_handler((void *)xr->ExceptionInformation[1] TSRMLS_CC) == SUCCESS) { + return EXCEPTION_CONTINUE_EXECUTION; + } + } + + return EXCEPTION_CONTINUE_SEARCH; +} diff --git a/phpdbg_win.h b/phpdbg_win.h new file mode 100644 index 0000000000..68c3052790 --- /dev/null +++ b/phpdbg_win.h @@ -0,0 +1,37 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WIN_H +#define PHPDBG_WIN_H + +#include "winbase.h" +#include "windows.h" +#include "excpt.h" + +#define PROT_READ 1 +#define PROT_WRITE 2 + +int mprotect(void *addr, size_t size, int protection); + +void phpdbg_win_set_mm_heap(zend_mm_heap *heap); + +int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp); + +#endif \ No newline at end of file diff --git a/test.php b/test.php index 5fdbcbe1a4..d93c81a89a 100644 --- a/test.php +++ b/test.php @@ -6,11 +6,16 @@ if (isset($include)) { $stdout = fopen("php://stdout", "w+"); class phpdbg { - public function isGreat($greeting = null) { - printf( - "%s: %s\n", __METHOD__, $greeting); - return $this; - } + private $sprintf = "%s: %s\n"; + + public function isGreat($greeting = null) { + printf($this->sprintf, __METHOD__, $greeting); + return $this; + } +} + +function mine() { + var_dump(func_get_args()); } function test($x, $y = 0) { @@ -49,3 +54,34 @@ function phpdbg_test_ob() echo 'End'; echo $b; } + +$array = [ + 1, + 2, + [3, 4], + [5, 6], +]; + +$array[] = 7; + +array_walk($array, function (&$item) { + if (is_array($item)) + $item[0] += 2; + else + $item -= 1; +}); + +class testClass { + public $a = 2; + protected $b = [1, 3]; + private $c = 7; +} + +$obj = new testClass; + +$test = $obj->a; + +$obj->a += 2; +$test -= 2; + +unset($obj); -- cgit v1.2.1 From 91b599f4a3d525ce75e43a630f150d11bfdde08e Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 24 Apr 2014 11:05:52 +0200 Subject: Merge remote-tracking branch 'phpdbg/master' into PHP-5.6 --- .gitignore | 2 - config.w32 | 4 +- phpdbg_lexer.c | 8 +- phpdbg_lexer.l | 8 +- phpdbg_parser.c | 1885 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ phpdbg_parser.h | 126 ++++ phpdbg_watch.c | 10 +- 7 files changed, 2026 insertions(+), 17 deletions(-) create mode 100644 phpdbg_parser.c create mode 100644 phpdbg_parser.h diff --git a/.gitignore b/.gitignore index af445861ac..5506a2652d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,3 @@ phpdbg *.lo *.o build -phpdbg_parser.c -phpdbg_parser.h diff --git a/config.w32 b/config.w32 index fcc2b61a87..33a7b46d4f 100644 --- a/config.w32 +++ b/config.w32 @@ -1,7 +1,7 @@ ARG_ENABLE('phpdbg', 'Build phpdbg', 'no'); ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); -PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c'; +PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c phpdbg_parser.c phpdbg_lexer.c'; PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; PHPDBG_EXE='phpdbg.exe'; @@ -9,10 +9,12 @@ if (PHP_PHPDBG == "yes") { SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); + ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H"); } if (PHP_PHPDBGS == "yes") { SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32'); ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib"); DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); + ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H"); } diff --git a/phpdbg_lexer.c b/phpdbg_lexer.c index c289004b98..94a4ba9766 100644 --- a/phpdbg_lexer.c +++ b/phpdbg_lexer.c @@ -1026,7 +1026,7 @@ YY_RULE_SETUP #line 78 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_PROTO; } @@ -1087,7 +1087,7 @@ YY_RULE_SETUP #line 108 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, OP_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_OPCODE; } @@ -1097,7 +1097,7 @@ YY_RULE_SETUP #line 114 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_ID; } @@ -1108,7 +1108,7 @@ YY_RULE_SETUP #line 122 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; BEGIN(INITIAL); return T_INPUT; diff --git a/phpdbg_lexer.l b/phpdbg_lexer.l index ad5edd9f8f..b3536feab8 100644 --- a/phpdbg_lexer.l +++ b/phpdbg_lexer.l @@ -77,7 +77,7 @@ INPUT [^\n]+ { {ID}[:]{1}[//]{2} { phpdbg_init_param(yylval, STR_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_PROTO; } @@ -107,13 +107,13 @@ INPUT [^\n]+ } {OPCODE} { phpdbg_init_param(yylval, OP_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_OPCODE; } {ID} { phpdbg_init_param(yylval, STR_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_ID; } @@ -121,7 +121,7 @@ INPUT [^\n]+ {INPUT} { phpdbg_init_param(yylval, STR_PARAM); - yylval->str = strndup(yytext, yyleng); + yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; BEGIN(INITIAL); return T_INPUT; diff --git a/phpdbg_parser.c b/phpdbg_parser.c new file mode 100644 index 0000000000..79af58f8c9 --- /dev/null +++ b/phpdbg_parser.c @@ -0,0 +1,1885 @@ +/* A Bison parser, made by GNU Bison 2.7. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2012 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 . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + 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. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.7" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +/* Line 371 of yacc.c */ +#line 2 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + + +/* + * phpdbg_parser.y + * (from php-src root) + * flex sapi/phpdbg/dev/phpdbg_lexer.l + * bison sapi/phpdbg/dev/phpdbg_parser.y + */ + +#include "phpdbg.h" +#include "phpdbg_cmd.h" +#include "phpdbg_utils.h" +#include "phpdbg_cmd.h" +#include "phpdbg_prompt.h" + +#define YYSTYPE phpdbg_param_t + +#include "phpdbg_parser.h" +#include "phpdbg_lexer.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +int yyerror(phpdbg_param_t *stack, yyscan_t scanner, const char *msg) { + TSRMLS_FETCH(); + phpdbg_error("Parse Error: %s", msg); + { + const phpdbg_param_t *top = stack; + + while (top) { + phpdbg_param_debug( + top, "--> "); + top = top->next; + } + } + return 0; +} + +/* Line 371 of yacc.c */ +#line 106 "sapi/phpdbg/phpdbg_parser.c" + +# 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 +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "phpdbg_parser.h". */ +#ifndef YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED +# define YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ +/* Line 387 of yacc.c */ +#line 40 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + +#include "phpdbg.h" +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + + +/* Line 387 of yacc.c */ +#line 147 "sapi/phpdbg/phpdbg_parser.c" + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_EVAL = 258, + T_RUN = 259, + T_SHELL = 260, + T_IF = 261, + T_TRUTHY = 262, + T_FALSY = 263, + T_STRING = 264, + 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 + }; +#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_PROTO 268 +#define T_DIGITS 269 +#define T_LITERAL 270 +#define T_ADDR 271 +#define T_OPCODE 272 +#define T_ID 273 +#define T_INPUT 274 +#define T_UNEXPECTED 275 + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +#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 (phpdbg_param_t *stack, yyscan_t scanner); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +/* Line 390 of yacc.c */ +#line 224 "sapi/phpdbg/phpdbg_parser.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(N) (N) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# 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 EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# 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 + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#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 24 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 33 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 21 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 4 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 24 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 37 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 275 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 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 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 6, 8, 11, 15, 20, 25, + 31, 35, 41, 45, 48, 51, 54, 56, 59, 61, + 63, 65, 67, 69, 71 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 22, 0, -1, 23, -1, -1, 24, -1, 23, 24, + -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, 3, 19, + -1, 5, 19, -1, 4, -1, 4, 19, -1, 17, + -1, 16, -1, 15, -1, 7, -1, 8, -1, 14, + -1, 18, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 76, 76, 77, 81, 82, 86, 91, 96, 107, + 118, 123, 129, 135, 140, 145, 150, 154, 159, 160, + 161, 162, 163, 164, 165 +}; +#endif + +#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[] = +{ + "$end", "error", "$undefined", "\"eval\"", "\"run\"", "\"shell\"", + "\"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)\"", + "\"input (input string or data)\"", "\"input\"", "$accept", "input", + "parameters", "parameter", YY_NULL +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +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 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 21, 22, 22, 23, 23, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 0, 1, 2, 3, 4, 4, 5, + 3, 5, 3, 2, 2, 2, 1, 2, 1, 1, + 1, 1, 1, 1, 1 +}; + +/* 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[] = +{ + 3, 0, 16, 0, 0, 21, 22, 0, 23, 20, + 19, 18, 24, 0, 2, 4, 14, 17, 15, 13, + 0, 0, 0, 0, 1, 5, 0, 0, 6, 10, + 12, 0, 8, 7, 0, 9, 11 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 13, 14, 15 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -11 +static const yytype_int8 yypact[] = +{ + -3, -10, 1, 2, 3, -11, -11, 6, -11, -11, + -11, -11, -4, 23, -3, -11, -11, -11, -11, -11, + 15, 4, 8, 13, -11, -11, 5, 14, -11, 17, + -11, 16, -11, -11, 18, -11, -11 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -11, -11, -11, 19 +}; + +/* 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 YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 1, 2, 3, 4, 5, 6, 21, 22, 23, 16, + 7, 8, 9, 10, 11, 12, 27, 31, 28, 32, + 17, 18, 19, 24, 20, 26, 29, 30, 33, 34, + 35, 0, 36, 25 +}; + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-11))) + +#define yytable_value_is_error(Yytable_value) \ + YYID (0) + +static const yytype_int8 yycheck[] = +{ + 3, 4, 5, 6, 7, 8, 10, 11, 12, 19, + 13, 14, 15, 16, 17, 18, 12, 12, 14, 14, + 19, 19, 19, 0, 18, 10, 18, 14, 14, 12, + 14, -1, 14, 14 +}; + +/* 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, 22, 23, 24, 19, 19, 19, 19, + 18, 10, 11, 12, 0, 24, 10, 12, 14, 18, + 14, 12, 14, 14, 12, 14, 14 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* 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. 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) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (stack, scanner, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, scanner) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, stack, scanner); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, phpdbg_param_t *stack, yyscan_t scanner) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, stack, scanner) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + phpdbg_param_t *stack; + yyscan_t scanner; +#endif +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; + YYUSE (stack); + YYUSE (scanner); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, phpdbg_param_t *stack, yyscan_t scanner) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, stack, scanner) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + phpdbg_param_t *stack; + yyscan_t scanner; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, stack, scanner); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule, phpdbg_param_t *stack, yyscan_t scanner) +#else +static void +yy_reduce_print (yyvsp, yyrule, stack, scanner) + YYSTYPE *yyvsp; + int yyrule; + phpdbg_param_t *stack; + yyscan_t scanner; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , stack, scanner); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule, stack, scanner); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* 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. + + 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 + + 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 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; + } + } + } + } + + 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_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + 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. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, phpdbg_param_t *stack, yyscan_t scanner) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, stack, scanner) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + phpdbg_param_t *stack; + yyscan_t scanner; +#endif +{ + YYUSE (yyvaluep); + YYUSE (stack); + YYUSE (scanner); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (phpdbg_param_t *stack, yyscan_t scanner) +#else +int +yyparse (stack, scanner) + phpdbg_param_t *stack; + yyscan_t scanner; +#endif +#endif +{ +/* 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 YY_INITIAL_VALUE(yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: +/* Line 1792 of yacc.c */ +#line 81 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { phpdbg_stack_push(stack, &(yyvsp[(1) - (1)])); } + break; + + case 5: +/* Line 1792 of yacc.c */ +#line 82 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { phpdbg_stack_push(stack, &(yyvsp[(2) - (2)])); } + break; + + case 6: +/* Line 1792 of yacc.c */ +#line 86 "/usr/src/php-src/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 7: +/* Line 1792 of yacc.c */ +#line 91 "/usr/src/php-src/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 8: +/* Line 1792 of yacc.c */ +#line 96 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = FILE_PARAM; + (yyval).file.name = malloc((yyvsp[(1) - (4)]).len + + (yyvsp[(2) - (4)]).len + 1); + if ((yyval).file.name) { + memcpy(&(yyval).file.name[0], (yyvsp[(1) - (4)]).str, (yyvsp[(1) - (4)]).len); + memcpy(&(yyval).file.name[(yyvsp[(1) - (4)]).len], (yyvsp[(2) - (4)]).str, (yyvsp[(2) - (4)]).len); + (yyval).file.name[(yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len] = '\0'; + } + (yyval).file.line = (yyvsp[(4) - (4)]).num; + } + break; + + case 9: +/* Line 1792 of yacc.c */ +#line 107 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = NUMERIC_FILE_PARAM; + (yyval).file.name = malloc((yyvsp[(1) - (5)]).len + + (yyvsp[(2) - (5)]).len + 1); + if ((yyval).file.name) { + memcpy(&(yyval).file.name[0], (yyvsp[(1) - (5)]).str, (yyvsp[(1) - (5)]).len); + memcpy(&(yyval).file.name[(yyvsp[(1) - (5)]).len], (yyvsp[(2) - (5)]).str, (yyvsp[(2) - (5)]).len); + (yyval).file.name[(yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len] = '\0'; + } + (yyval).file.line = (yyvsp[(5) - (5)]).num; + } + break; + + case 10: +/* Line 1792 of yacc.c */ +#line 118 "/usr/src/php-src/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 11: +/* Line 1792 of yacc.c */ +#line 123 "/usr/src/php-src/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 12: +/* Line 1792 of yacc.c */ +#line 129 "/usr/src/php-src/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 13: +/* Line 1792 of yacc.c */ +#line 135 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = COND_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } + break; + + case 14: +/* Line 1792 of yacc.c */ +#line 140 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = EVAL_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } + break; + + case 15: +/* Line 1792 of yacc.c */ +#line 145 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = SHELL_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } + break; + + case 16: +/* Line 1792 of yacc.c */ +#line 150 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = RUN_PARAM; + (yyval).len = 0; + } + break; + + case 17: +/* Line 1792 of yacc.c */ +#line 154 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = RUN_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } + break; + + case 18: +/* Line 1792 of yacc.c */ +#line 159 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 19: +/* Line 1792 of yacc.c */ +#line 160 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 20: +/* Line 1792 of yacc.c */ +#line 161 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 21: +/* Line 1792 of yacc.c */ +#line 162 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 22: +/* Line 1792 of yacc.c */ +#line 163 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 23: +/* Line 1792 of yacc.c */ +#line 164 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 24: +/* Line 1792 of yacc.c */ +#line 165 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + +/* Line 1792 of yacc.c */ +#line 1653 "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); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| 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) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (stack, scanner, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + 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 (stack, scanner, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, stack, scanner); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, stack, scanner); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (stack, scanner, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* 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, stack, scanner); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, stack, scanner); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +/* Line 2055 of yacc.c */ +#line 168 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + diff --git a/phpdbg_parser.h b/phpdbg_parser.h new file mode 100644 index 0000000000..6acb8963c9 --- /dev/null +++ b/phpdbg_parser.h @@ -0,0 +1,126 @@ +/* A Bison parser, made by GNU Bison 2.7. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2012 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 . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + 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_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED +# define YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ +/* Line 2058 of yacc.c */ +#line 40 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + +#include "phpdbg.h" +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + + +/* Line 2058 of yacc.c */ +#line 55 "sapi/phpdbg/phpdbg_parser.h" + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_EVAL = 258, + T_RUN = 259, + T_SHELL = 260, + T_IF = 261, + T_TRUTHY = 262, + T_FALSY = 263, + T_STRING = 264, + 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 + }; +#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_PROTO 268 +#define T_DIGITS 269 +#define T_LITERAL 270 +#define T_ADDR 271 +#define T_OPCODE 272 +#define T_ID 273 +#define T_INPUT 274 +#define T_UNEXPECTED 275 + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +#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 (phpdbg_param_t *stack, yyscan_t scanner); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */ diff --git a/phpdbg_watch.c b/phpdbg_watch.c index a6bf6289bf..9ee580ca0b 100644 --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@ -463,10 +463,9 @@ PHPDBG_WATCH(array) /* {{{ */ } /* }}} */ void phpdbg_watch_HashTable_dtor(zval **zv) { - TSRMLS_FETCH(); - phpdbg_btree_result *result; zval_ptr_dtor_wrapper(zv); + TSRMLS_FETCH(); if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)*zv))) { @@ -545,9 +544,8 @@ void phpdbg_watchpoints_clean(TSRMLS_D) { } static void phpdbg_watch_dtor(void *pDest) { - TSRMLS_FETCH(); - phpdbg_watchpoint_t *watch = *(phpdbg_watchpoint_t **)pDest; + TSRMLS_FETCH(); phpdbg_deactivate_watchpoint(watch TSRMLS_CC); phpdbg_remove_watchpoint(watch TSRMLS_CC); @@ -599,7 +597,7 @@ static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { void *oldPtr = (char *)&dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page); char reenable = 1; - if (watch->addr.ptr < dump->page || watch->addr.ptr + watch->size > dump->page + dump->size) { + if ((size_t)watch->addr.ptr < (size_t)dump->page || (size_t)watch->addr.ptr + watch->size > (size_t)dump->page + dump->size) { continue; } @@ -774,8 +772,8 @@ void phpdbg_list_watchpoints(TSRMLS_D) { } void phpdbg_watch_efree(void *ptr) { - TSRMLS_FETCH(); phpdbg_btree_result *result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong)ptr); + TSRMLS_FETCH(); if (result) { phpdbg_watchpoint_t *watch = result->ptr; -- cgit v1.2.1 From 9a8123fabbdeea05d9b94638d09efb1440004d50 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sat, 26 Apr 2014 00:15:32 +0200 Subject: Merge remote-tracking branch 'phpdbg/master' into PHP-5.6 * phpdbg/master: removed /EHa as __try/__catch syntax is used anyway fix ZEND_DEBUG usage fix CFLAGS_PHPDBGS and some formatting --- config.w32 | 9 ++++----- phpdbg_watch.c | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/config.w32 b/config.w32 index 33a7b46d4f..17e15b6ced 100644 --- a/config.w32 +++ b/config.w32 @@ -6,15 +6,14 @@ PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; PHPDBG_EXE='phpdbg.exe'; if (PHP_PHPDBG == "yes") { - SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); - ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); - DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); + SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); + ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H"); } if (PHP_PHPDBGS == "yes") { SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32'); ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib"); - DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); - ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H"); + ADD_FLAG("CFLAGS_PHPDBGS", "/D YY_NO_UNISTD_H"); } + diff --git a/phpdbg_watch.c b/phpdbg_watch.c index 9ee580ca0b..0359b5a7de 100644 --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@ -702,7 +702,7 @@ remove_ht_watch: } case WATCH_ON_HASHTABLE: -#ifdef ZEND_DEBUG +#if ZEND_DEBUG if (watch->addr.ht->inconsistent) { phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str); zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); -- cgit v1.2.1 From a1edc8e396f09b0bdd997d80ac778738e4c5dc83 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sun, 27 Apr 2014 18:01:26 +0200 Subject: Merge remote-tracking branch 'phpdbg/master' into PHP-5.6 * phpdbg/master: C89 compat --- phpdbg_watch.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phpdbg_watch.c b/phpdbg_watch.c index 0359b5a7de..2efbb1237c 100644 --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@ -464,9 +464,9 @@ PHPDBG_WATCH(array) /* {{{ */ void phpdbg_watch_HashTable_dtor(zval **zv) { phpdbg_btree_result *result; - zval_ptr_dtor_wrapper(zv); TSRMLS_FETCH(); + zval_ptr_dtor_wrapper(zv); if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)*zv))) { phpdbg_watchpoint_t *watch = result->ptr; @@ -772,9 +772,11 @@ void phpdbg_list_watchpoints(TSRMLS_D) { } void phpdbg_watch_efree(void *ptr) { - phpdbg_btree_result *result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong)ptr); + phpdbg_btree_result *result; TSRMLS_FETCH(); + result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong)ptr); + if (result) { phpdbg_watchpoint_t *watch = result->ptr; -- cgit v1.2.1 From eae7a94fe007daf7fc575db2bd36a582c3873fbf Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Thu, 1 May 2014 11:38:08 +0200 Subject: Added stdion/stdout/stderr constsnts and their php:// wrappers Fixes issue #85 --- phpdbg.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/phpdbg.c b/phpdbg.c index 064e266082..fc121839e8 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -533,6 +533,69 @@ static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */ fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); } /* }}} */ +/* copied from sapi/cli/php_cli.c cli_register_file_handles */ +static void phpdbg_register_file_handles(TSRMLS_D) /* {{{ */ +{ + zval *zin, *zout, *zerr; + php_stream *s_in, *s_out, *s_err; + php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL; + zend_constant ic, oc, ec; + + MAKE_STD_ZVAL(zin); + MAKE_STD_ZVAL(zout); + MAKE_STD_ZVAL(zerr); + + s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in); + s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out); + s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err); + + if (s_in==NULL || s_out==NULL || s_err==NULL) { + FREE_ZVAL(zin); + FREE_ZVAL(zout); + FREE_ZVAL(zerr); + if (s_in) php_stream_close(s_in); + if (s_out) php_stream_close(s_out); + if (s_err) php_stream_close(s_err); + return; + } + +#if PHP_DEBUG + /* do not close stdout and stderr */ + s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE; + s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE; +#endif + + php_stream_to_zval(s_in, zin); + php_stream_to_zval(s_out, zout); + php_stream_to_zval(s_err, zerr); + + ic.value = *zin; + ic.flags = CONST_CS; + ic.name = zend_strndup(ZEND_STRL("STDIN")); + ic.name_len = sizeof("STDIN"); + ic.module_number = 0; + zend_register_constant(&ic TSRMLS_CC); + + oc.value = *zout; + oc.flags = CONST_CS; + oc.name = zend_strndup(ZEND_STRL("STDOUT")); + oc.name_len = sizeof("STDOUT"); + oc.module_number = 0; + zend_register_constant(&oc TSRMLS_CC); + + ec.value = *zerr; + ec.flags = CONST_CS; + ec.name = zend_strndup(ZEND_STRL("STDERR")); + ec.name_len = sizeof("STDERR"); + ec.module_number = 0; + zend_register_constant(&ec TSRMLS_CC); + + FREE_ZVAL(zin); + FREE_ZVAL(zout); + FREE_ZVAL(zerr); +} +/* }}} */ + /* {{{ sapi_module_struct phpdbg_sapi_module */ static sapi_module_struct phpdbg_sapi_module = { @@ -1262,6 +1325,9 @@ phpdbg_main: /* set default prompt */ phpdbg_set_prompt(PROMPT TSRMLS_CC); + /* Make stdin, stdout and stderr accessible from PHP scripts */ + phpdbg_register_file_handles(TSRMLS_C); + if (show_banner) { /* print blurb */ phpdbg_welcome((cleaning > 0) TSRMLS_CC); -- cgit v1.2.1 From d4b5ef2e4a0676f421a64995b7114b50fb18ec9c Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sat, 3 May 2014 11:40:25 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- config.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.m4 b/config.m4 index 3534d90124..a1b2f9faa1 100644 --- a/config.m4 +++ b/config.m4 @@ -21,7 +21,7 @@ if test "$PHP_PHPDBG" != "no"; then 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" if test "$PHP_READLINE" != "no"; then - PHPDBG_EXTRA_LIBS="-lreadline" + PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS" fi PHP_SUBST(PHP_PHPDBG_CFLAGS) -- cgit v1.2.1 From 3200d99763b08cf4585adb6d7cb755bbcb4ac493 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 3 Jun 2014 21:15:02 +0000 Subject: Merge sapi/phpdbg into PHP-5.6 --- phpdbg.c | 47 +++++++++++++++++++++++++++++++++++------------ phpdbg_watch.c | 2 +- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index fc121839e8..0239e692b4 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -879,6 +879,32 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) { } #endif +static inline zend_mm_heap *phpdbg_mm_get_heap() { + zend_mm_heap *mm_heap; + + TSRMLS_FETCH(); + + mm_heap = zend_mm_set_heap(NULL TSRMLS_CC); + zend_mm_set_heap(mm_heap TSRMLS_CC); + + return mm_heap; +} + +void *phpdbg_malloc_wrapper(size_t size) +{ + return zend_mm_alloc(phpdbg_mm_get_heap(), size); +} + +void phpdbg_free_wrapper(void *p) +{ + zend_mm_free(phpdbg_mm_get_heap(), p); +} + +void *phpdbg_realloc_wrapper(void *ptr, size_t size) +{ + return zend_mm_realloc(phpdbg_mm_get_heap(), ptr, size); +} + int main(int argc, char **argv) /* {{{ */ { sapi_module_struct *phpdbg = &phpdbg_sapi_module; @@ -1221,20 +1247,17 @@ phpdbg_main: EXCEPTION_POINTERS *xp; __try { #endif - zend_mm_heap *mm_heap = zend_mm_set_heap(NULL TSRMLS_CC); -#if ZEND_DEBUG - if (!mm_heap->use_zend_alloc) { - mm_heap->_malloc = malloc; - mm_heap->_realloc = realloc; - mm_heap->_free = free; -#endif - PHPDBG_G(original_free_function) = mm_heap->_free; - mm_heap->_free = phpdbg_watch_efree; + zend_mm_heap *mm_heap = phpdbg_mm_get_heap(); + + if (mm_heap->use_zend_alloc) { + mm_heap->_malloc = phpdbg_malloc_wrapper; + mm_heap->_realloc = phpdbg_realloc_wrapper; + mm_heap->_free = phpdbg_free_wrapper; mm_heap->use_zend_alloc = 0; -#if ZEND_DEBUG } -#endif - zend_mm_set_heap(mm_heap TSRMLS_CC); + + PHPDBG_G(original_free_function) = mm_heap->_free; + mm_heap->_free = phpdbg_watch_efree; zend_activate(TSRMLS_C); diff --git a/phpdbg_watch.c b/phpdbg_watch.c index 2efbb1237c..e88622444b 100644 --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@ -580,7 +580,7 @@ void phpdbg_setup_watchpoints(TSRMLS_D) { 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, phpdbg_watch_dtor, 0 ZEND_FILE_LINE_CC); + zend_hash_init(&PHPDBG_G(watchpoints), 8, NULL, phpdbg_watch_dtor, 0 ZEND_FILE_LINE_CC); } static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { -- cgit v1.2.1 From b264783d637ee3512da1d92107297741671dbb3b Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Wed, 4 Jun 2014 02:18:39 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- phpdbg.c | 6 +++--- tests/commands/0002_set.test | 2 -- tests/commands/0103_register.test | 10 +++++----- tests/commands/0106_compile.test | 1 - tests/run-tests.php | 28 ++++++++++++++++++++-------- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index 0239e692b4..93fdbd7424 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -159,8 +159,6 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */ zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0); zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0); - phpdbg_setup_watchpoints(TSRMLS_C); - zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0); zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0); @@ -1256,10 +1254,12 @@ phpdbg_main: mm_heap->use_zend_alloc = 0; } + zend_activate(TSRMLS_C); + PHPDBG_G(original_free_function) = mm_heap->_free; mm_heap->_free = phpdbg_watch_efree; - zend_activate(TSRMLS_C); + phpdbg_setup_watchpoints(TSRMLS_C); #if defined(ZEND_SIGNALS) && !defined(_WIN32) zend_try { diff --git a/tests/commands/0002_set.test b/tests/commands/0002_set.test index 7720f94fff..468ac6d9ea 100644 --- a/tests/commands/0002_set.test +++ b/tests/commands/0002_set.test @@ -9,7 +9,6 @@ # setting notice color # Failed to find breakpoint #0 # oplog disabled -# not enabled # opened oplog test.log # nothing ################################################# @@ -19,5 +18,4 @@ set color notice none set prompt promot> set break 0 set oplog -set oplog 0 set oplog test.log diff --git a/tests/commands/0103_register.test b/tests/commands/0103_register.test index 38841591ca..703a12f771 100644 --- a/tests/commands/0103_register.test +++ b/tests/commands/0103_register.test @@ -7,15 +7,15 @@ #[Registered test_function] #array(5) { # [0]=> -# string(1) "1" +# int(1) # [1]=> -# string(1) "2" +# int(2) # [2]=> -# string(1) "3" +# int(3) # [3]=> -# string(1) "4" +# int(4) # [4]=> -# string(1) "5" +# int(5) #} ################################################# <: diff --git a/tests/commands/0106_compile.test b/tests/commands/0106_compile.test index d79211ddf7..7193600ea3 100644 --- a/tests/commands/0106_compile.test +++ b/tests/commands/0106_compile.test @@ -14,6 +14,5 @@ define('OUT', file_put_contents(OUT, ""); phpdbg_exec(OUT); :> -compile run quit diff --git a/tests/run-tests.php b/tests/run-tests.php index 1fb6fa1224..47a998ccae 100644 --- a/tests/run-tests.php +++ b/tests/run-tests.php @@ -284,6 +284,8 @@ namespace phpdbg\testing { $test->purpose, $result ? "PASS" : "FAIL", PHP_EOL); + + return $result; } protected $config; @@ -426,7 +428,7 @@ namespace phpdbg\testing { */ public function getResult() { $options = sprintf( - '-i%s -qb', $this->file); + '-i%s -nqb', $this->file); if ($this->options) { $options = sprintf( @@ -492,13 +494,18 @@ namespace phpdbg\testing { * */ protected function writeDiff() { - $diff = sprintf( - '%s/%s.diff', - dirname($this->file), basename($this->file)); - if (count($this->diff['wants'])) { - if (!in_array('nodiff', $this->config['flags'])) { - if (($diff = fopen($diff, 'w+'))) { + 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]; @@ -552,6 +559,9 @@ namespace { $cwd = dirname(__FILE__); $cmd = $_SERVER['argv']; + + $retval = 0; + { $config = new TestsConfiguration(array( 'exec' => realpath(array_shift($cmd)), @@ -571,7 +581,7 @@ namespace { $tests->logPath($path); foreach ($tests->findTests($path) as $test) { - $tests->logTest($path, $test); + $retval |= !$tests->logTest($path, $test); } $tests->logPathStats($path); @@ -579,5 +589,7 @@ namespace { $tests->logStats(); } + + die($retval); } ?> -- cgit v1.2.1 From 5e6c5e9569abaec5fdea6e9254fe38e340921c50 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 9 Jun 2014 10:06:29 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- .gitignore | 1 + Makefile.frag | 15 +- config.m4 | 2 +- phpdbg.h | 7 +- phpdbg_lexer.c | 3125 ++++++++++++++++--------------------------------------- phpdbg_lexer.h | 385 +------ phpdbg_lexer.l | 270 ++--- phpdbg_parser.c | 550 +++++----- phpdbg_parser.h | 24 +- phpdbg_parser.y | 152 +-- phpdbg_prompt.c | 37 +- travis/ci.sh | 1 + 12 files changed, 1524 insertions(+), 3045 deletions(-) diff --git a/.gitignore b/.gitignore index 5506a2652d..51165dab2f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ phpdbg *.lo *.o +*.output build diff --git a/Makefile.frag b/Makefile.frag index 45768de2ef..d787b0fb18 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -8,14 +8,17 @@ $(BUILD_SHARED): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) $(BUILD_BINARY): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) $(BUILD_PHPDBG) -$(builddir)/sapi/phpdbg/phpdbg_lexer.lo: $(srcdir)/sapi/phpdbg/phpdbg_parser.h +%.c: %.y +%.c: %.l -$(srcdir)/sapi/phpdbg/phpdbg_lexer.c: $(srcdir)/sapi/phpdbg/phpdbg_lexer.l - @(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date -cbdFo sapi/phpdbg/phpdbg_lexer.c sapi/phpdbg/phpdbg_lexer.l) +$(builddir)/phpdbg_lexer.lo: $(srcdir)/phpdbg_parser.h -$(srcdir)/sapi/phpdbg/phpdbg_parser.h: $(srcdir)/sapi/phpdbg/phpdbg_parser.c -$(srcdir)/sapi/phpdbg/phpdbg_parser.c: $(srcdir)/sapi/phpdbg/phpdbg_parser.y - @$(YACC) -p phpdbg_ -v -d $(srcdir)/sapi/phpdbg/phpdbg_parser.y -o $@ +$(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) + +$(srcdir)/phpdbg_parser.h: $(srcdir)/phpdbg_parser.c +$(srcdir)/phpdbg_parser.c: $(srcdir)/phpdbg_parser.y + @$(YACC) -p phpdbg_ -v -d $(srcdir)/phpdbg_parser.y -o $@ install-phpdbg: $(BUILD_BINARY) @echo "Installing phpdbg binary: $(INSTALL_ROOT)$(bindir)/" diff --git a/config.m4 b/config.m4 index a1b2f9faa1..ecac171506 100644 --- a/config.m4 +++ b/config.m4 @@ -28,7 +28,7 @@ if test "$PHP_PHPDBG" != "no"; then PHP_SUBST(PHP_PHPDBG_FILES) PHP_SUBST(PHPDBG_EXTRA_LIBS) - PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/phpdbg/Makefile.frag]) + PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/phpdbg/Makefile.frag], [$abs_srcdir/sapi/phpdbg], [$abs_builddir/sapi/phpdbg]) PHP_SELECT_SAPI(phpdbg, program, $PHP_PHPDBG_FILES, $PHP_PHPDBG_CFLAGS, [$(SAPI_PHPDBG_PATH)]) BUILD_BINARY="sapi/phpdbg/phpdbg" diff --git a/phpdbg.h b/phpdbg.h index be009e40d0..12350d5425 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -69,11 +69,14 @@ # include #endif +#include "phpdbg_lexer.h" #include "phpdbg_cmd.h" #include "phpdbg_utils.h" #include "phpdbg_btree.h" #include "phpdbg_watch.h" +int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); + #ifdef ZTS # define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) #else @@ -176,10 +179,12 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) phpdbg_frame_t frame; /* frame */ zend_uint last_line; /* last executed line */ + phpdbg_lexer_data lexer; /* lexer data */ + phpdbg_param_t *parser_stack; /* param stack during lexer / parser phase */ + #ifndef _WIN32 struct sigaction old_sigsegv_signal; /* segv signal handler */ #endif - phpdbg_btree watchpoint_tree; /* tree with watchpoints */ phpdbg_btree watch_HashTables; /* tree with original dtors of watchpoints */ HashTable watchpoints; /* watchpoints */ diff --git a/phpdbg_lexer.c b/phpdbg_lexer.c index 94a4ba9766..420dcac042 100644 --- a/phpdbg_lexer.c +++ b/phpdbg_lexer.c @@ -1,2271 +1,996 @@ -#line 2 "sapi/phpdbg/phpdbg_lexer.c" - -#line 4 "sapi/phpdbg/phpdbg_lexer.c" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 37 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yyg->yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yyg->yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#endif - -/* The state buf must be large enough to hold one state per character in the main buffer. - */ -#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = yyg->yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - yy_size_t yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ - ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ - : NULL) - -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] - -void yyrestart (FILE *input_file ,yyscan_t yyscanner ); -void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void yypop_buffer_state (yyscan_t yyscanner ); - -static void yyensure_buffer_stack (yyscan_t yyscanner ); -static void yy_load_buffer_state (yyscan_t yyscanner ); -static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); - -#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) - -YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); - -void *yyalloc (yy_size_t ,yyscan_t yyscanner ); -void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void yyfree (void * ,yyscan_t yyscanner ); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define yywrap(yyscanner) 1 -#define YY_SKIP_YYWRAP - -typedef unsigned char YY_CHAR; - -typedef int yy_state_type; - -#define yytext_ptr yytext_r - -static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); -static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yyg->yytext_ptr = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ - yyg->yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yyg->yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 18 -#define YY_END_OF_BUFFER 19 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static yyconst flex_int16_t yy_acclist[229] = - { 0, - 19, 4, 15, 18, 4, 17, 18, 17, 18, 4, - 7, 18, 4, 12, 15, 18, 4, 12, 15, 18, - 4, 9, 18, 4, 15, 18, 4, 15, 18, 4, - 15, 18, 4, 15, 18, 4, 15, 18, 4, 15, - 18, 3, 4, 15, 18, 4, 15, 18, 4, 15, - 18, 4, 15, 18, 4, 15, 18, 16, 18, 16, - 17, 18, 15, 18, 7, 18, 12, 15, 18, 12, - 15, 18, 9, 18, 15, 18, 15, 18, 15, 18, - 15, 18, 15, 18, 15, 18, 15, 18, 15, 18, - 15, 18, 15, 18, 4, 15, 4, 4, 4, 17, - - 17, 4, 12, 15, 4, 15, 4, 8, 4, 15, - 4, 15, 4, 15, 1, 4, 15, 4, 15, 4, - 11, 15, 4, 15, 4, 10, 15, 4, 15, 2, - 4, 15, 4, 15, 4, 15, 4, 15, 16, 16, - 17, 15, 12, 15, 15, 8, 15, 15, 15, 15, - 5, 15, 11, 15, 15, 10, 15, 15, 15, 15, - 4, 4, 13, 15, 4, 15, 4, 15, 4, 15, - 4, 15, 3, 4, 15, 4, 15, 4, 15, 13, - 15, 15, 15, 15, 15, 15, 15, 4, 6, 4, - 15, 4, 15, 4, 15, 4, 15, 4, 15, 6, - - 15, 15, 15, 15, 15, 4, 15, 4, 15, 4, - 15, 15, 15, 15, 4, 14, 15, 4, 15, 4, - 15, 14, 15, 15, 15, 4, 15, 15 - } ; - -static yyconst flex_int16_t yy_accept[127] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 2, 5, 8, - 10, 13, 17, 21, 24, 27, 30, 33, 36, 39, - 42, 46, 49, 52, 55, 58, 60, 63, 65, 67, - 70, 73, 75, 77, 79, 81, 83, 85, 87, 89, - 91, 93, 95, 97, 98, 99, 101, 102, 105, 107, - 109, 111, 113, 115, 118, 120, 123, 125, 128, 130, - 133, 135, 137, 139, 140, 142, 143, 143, 145, 146, - 147, 148, 149, 150, 151, 153, 155, 156, 158, 159, - 160, 161, 162, 165, 167, 169, 171, 173, 176, 178, - 180, 180, 182, 183, 184, 185, 186, 187, 188, 190, - - 192, 194, 196, 198, 200, 201, 202, 203, 204, 205, - 206, 208, 210, 212, 213, 214, 215, 218, 220, 222, - 224, 225, 226, 228, 229, 229 - } ; - -static yyconst flex_int32_t yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 5, 6, 7, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 9, 1, 1, - 1, 1, 1, 1, 10, 10, 10, 11, 12, 10, - 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, - 1, 1, 1, 1, 16, 1, 17, 18, 10, 19, - - 20, 21, 13, 22, 23, 13, 13, 24, 13, 25, - 26, 13, 13, 27, 28, 29, 30, 31, 13, 32, - 33, 34, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst flex_int32_t yy_meta[35] = - { 0, - 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1 - } ; - -static yyconst flex_int16_t yy_base[133] = - { 0, - 0, 0, 33, 35, 38, 0, 357, 71, 74, 76, - 352, 79, 87, 90, 96, 100, 108, 109, 112, 120, - 123, 126, 138, 142, 148, 0, 104, 316, 455, 151, - 162, 313, 73, 92, 65, 146, 122, 94, 152, 127, - 155, 163, 172, 318, 131, 176, 182, 288, 190, 314, - 178, 184, 187, 211, 212, 215, 221, 224, 225, 235, - 236, 239, 245, 0, 203, 260, 259, 248, 264, 455, - 237, 190, 243, 253, 255, 222, 259, 194, 249, 250, - 277, 229, 0, 285, 286, 289, 295, 304, 307, 310, - 184, 0, 252, 283, 292, 296, 306, 309, 163, 328, - - 329, 332, 341, 344, 455, 326, 331, 330, 342, 343, - 362, 370, 371, 394, 368, 356, 410, 384, 404, 426, - 376, 378, 420, 411, 455, 442, 445, 447, 450, 148, - 452, 96 - } ; - -static yyconst flex_int16_t yy_def[133] = - { 0, - 125, 1, 126, 126, 125, 5, 125, 127, 128, 125, - 128, 127, 127, 128, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 129, 129, 130, 125, 130, - 130, 125, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 127, 128, 128, 128, 125, 13, 13, 128, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 129, 129, 130, 125, 130, 130, 125, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 128, 49, 127, 127, 127, 127, 127, 127, 127, - 125, 69, 130, 130, 130, 130, 130, 130, 128, 127, - - 127, 127, 127, 127, 125, 130, 130, 130, 130, 130, - 131, 127, 127, 132, 130, 130, 131, 127, 127, 132, - 130, 130, 127, 130, 0, 125, 125, 125, 125, 125, - 125, 125 - } ; - -static yyconst flex_int16_t yy_nxt[490] = - { 0, - 8, 9, 10, 11, 12, 8, 13, 12, 14, 8, - 8, 8, 8, 8, 15, 8, 8, 8, 16, 17, - 18, 8, 8, 8, 19, 20, 21, 22, 23, 8, - 8, 8, 24, 25, 27, 10, 27, 10, 28, 10, - 10, 29, 30, 28, 31, 30, 32, 28, 28, 28, - 28, 28, 33, 28, 28, 28, 34, 35, 36, 28, - 37, 28, 38, 39, 28, 28, 40, 28, 28, 28, - 41, 42, 44, 67, 44, 46, 47, 47, 47, 45, - 44, 67, 44, 48, 71, 48, 48, 45, 44, 73, - 44, 48, 125, 48, 48, 45, 120, 44, 50, 44, - - 67, 44, 67, 44, 45, 65, 47, 51, 45, 44, - 44, 44, 44, 44, 72, 44, 45, 45, 49, 76, - 45, 44, 52, 44, 44, 55, 44, 44, 45, 44, - 67, 45, 53, 125, 45, 67, 82, 56, 54, 44, - 57, 44, 75, 44, 58, 44, 45, 60, 66, 44, - 45, 44, 59, 79, 67, 68, 45, 68, 68, 67, - 67, 62, 74, 67, 61, 125, 68, 63, 68, 68, - 67, 67, 77, 44, 80, 44, 78, 46, 47, 44, - 45, 44, 81, 47, 47, 44, 45, 44, 44, 105, - 44, 84, 45, 69, 43, 45, 83, 83, 67, 83, - - 83, 83, 67, 86, 65, 47, 83, 83, 83, 83, - 83, 85, 44, 44, 44, 44, 44, 94, 44, 45, - 45, 43, 44, 45, 44, 44, 44, 44, 44, 45, - 67, 125, 45, 45, 99, 87, 44, 44, 44, 44, - 44, 56, 44, 45, 45, 67, 44, 45, 44, 88, - 93, 67, 68, 45, 68, 68, 67, 67, 67, 95, - 67, 67, 106, 67, 91, 89, 58, 67, 67, 90, - 92, 92, 67, 92, 92, 92, 96, 78, 97, 76, - 92, 92, 92, 92, 92, 67, 44, 44, 44, 44, - 44, 67, 44, 45, 45, 100, 44, 45, 44, 107, - - 67, 98, 101, 45, 67, 44, 102, 44, 44, 108, - 44, 44, 45, 44, 67, 45, 125, 67, 45, 43, - 125, 70, 103, 109, 67, 78, 58, 110, 104, 44, - 44, 44, 44, 44, 67, 44, 45, 45, 67, 67, - 45, 114, 44, 111, 44, 44, 112, 44, 115, 45, - 67, 67, 45, 116, 125, 113, 125, 125, 114, 111, - 56, 76, 43, 44, 67, 44, 43, 43, 43, 43, - 45, 44, 44, 44, 44, 122, 67, 43, 45, 45, - 125, 125, 125, 125, 67, 44, 67, 44, 125, 125, - 119, 121, 45, 118, 66, 124, 78, 125, 66, 66, - - 66, 66, 67, 123, 125, 44, 125, 44, 125, 66, - 43, 44, 45, 44, 43, 43, 43, 43, 45, 67, - 125, 44, 58, 44, 125, 43, 66, 125, 45, 76, - 66, 66, 66, 66, 67, 125, 125, 125, 56, 125, - 125, 66, 26, 26, 26, 43, 43, 44, 44, 44, - 64, 64, 117, 117, 7, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125 - } ; - -static yyconst flex_int16_t yy_chk[490] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 3, 4, 4, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 8, 35, 8, 9, 9, 10, 10, 8, - 12, 33, 12, 12, 33, 12, 12, 12, 13, 35, - 13, 13, 14, 13, 13, 13, 132, 15, 14, 15, - - 34, 16, 38, 16, 15, 27, 27, 15, 16, 17, - 18, 17, 18, 19, 34, 19, 17, 18, 13, 38, - 19, 20, 16, 20, 21, 18, 21, 22, 20, 22, - 37, 21, 17, 45, 22, 40, 45, 19, 17, 23, - 20, 23, 37, 24, 20, 24, 23, 22, 130, 25, - 24, 25, 21, 40, 36, 30, 25, 30, 30, 30, - 39, 24, 36, 41, 23, 99, 31, 25, 31, 31, - 31, 42, 39, 43, 41, 43, 39, 46, 46, 51, - 43, 51, 42, 47, 47, 52, 51, 52, 53, 91, - 53, 51, 52, 31, 49, 53, 49, 49, 72, 49, - - 49, 49, 78, 53, 65, 65, 49, 49, 49, 49, - 49, 52, 54, 55, 54, 55, 56, 72, 56, 54, - 55, 49, 57, 56, 57, 58, 59, 58, 59, 57, - 76, 82, 58, 59, 82, 55, 60, 61, 60, 61, - 62, 57, 62, 60, 61, 71, 63, 62, 63, 59, - 71, 73, 68, 63, 68, 68, 68, 79, 80, 73, - 93, 74, 93, 75, 67, 61, 62, 77, 66, 63, - 69, 69, 69, 69, 69, 69, 74, 80, 79, 77, - 69, 69, 69, 69, 69, 81, 84, 85, 84, 85, - 86, 94, 86, 84, 85, 84, 87, 86, 87, 94, - - 95, 81, 85, 87, 96, 88, 86, 88, 89, 95, - 89, 90, 88, 90, 97, 89, 50, 98, 90, 48, - 44, 32, 87, 96, 28, 97, 89, 98, 90, 100, - 101, 100, 101, 102, 106, 102, 100, 101, 108, 107, - 102, 106, 103, 100, 103, 104, 101, 104, 107, 103, - 109, 110, 104, 108, 11, 102, 7, 0, 110, 104, - 103, 109, 111, 111, 116, 111, 111, 111, 111, 111, - 111, 112, 113, 112, 113, 116, 115, 111, 112, 113, - 0, 0, 0, 0, 121, 118, 122, 118, 0, 0, - 113, 115, 118, 112, 114, 121, 122, 0, 114, 114, - - 114, 114, 114, 118, 0, 119, 0, 119, 0, 114, - 117, 117, 119, 117, 117, 117, 117, 117, 117, 124, - 0, 123, 119, 123, 0, 117, 120, 0, 123, 124, - 120, 120, 120, 120, 120, 0, 0, 0, 123, 0, - 0, 120, 126, 126, 126, 127, 127, 128, 128, 128, - 129, 129, 131, 131, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125 - } ; - -#define REJECT \ -{ \ -*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ \ -yy_cp = yyg->yy_full_match; /* restore poss. backed-over text */ \ -++yyg->yy_lp; \ -goto find_rule; \ -} - -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -#line 1 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -#line 2 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" - +/* Generated by re2c 0.13.5 */ +#line 1 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" /* * phpdbg_lexer.l */ #include "phpdbg.h" #include "phpdbg_cmd.h" -#define YYSTYPE phpdbg_param_t #include "phpdbg_parser.h" - +#define LEX(v) (PHPDBG_G(lexer).v) -#define YY_NO_UNISTD_H 1 -#line 629 "sapi/phpdbg/phpdbg_lexer.c" +#define YYCTYPE unsigned char +#define YYSETCONDITION(x) LEX(state) = x; +#define YYGETCONDITION() LEX(state) +#define YYCURSOR LEX(cursor) +#define YYMARKER LEX(marker) +#define yyleng LEX(len) +#define yytext ((char*) LEX(text)) +#undef YYDEBUG +#define YYDEBUG(a, b) +#define YYFILL(n) -#define INITIAL 0 +#define NORMAL 0 #define RAW 1 -#define NORMAL 2 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -/* Holds the entire state of the reentrant scanner. */ -struct yyguts_t - { - - /* User-defined. Not touched by flex. */ - YY_EXTRA_TYPE yyextra_r; - - /* The rest are the same as the globals declared in the non-reentrant scanner. */ - FILE *yyin_r, *yyout_r; - size_t yy_buffer_stack_top; /**< index of top of stack. */ - size_t yy_buffer_stack_max; /**< capacity of stack. */ - YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ - char yy_hold_char; - yy_size_t yy_n_chars; - yy_size_t yyleng_r; - char *yy_c_buf_p; - int yy_init; - int yy_start; - int yy_did_buffer_switch_on_eof; - int yy_start_stack_ptr; - int yy_start_stack_depth; - int *yy_start_stack; - yy_state_type yy_last_accepting_state; - char* yy_last_accepting_cpos; - - int yylineno_r; - int yy_flex_debug_r; - - yy_state_type *yy_state_buf; - yy_state_type *yy_state_ptr; - char *yy_full_match; - int yy_lp; - - /* These are only needed for trailing context rules, - * but there's no conditional variable for that yet. */ - int yy_looking_for_trail_begin; - int yy_full_lp; - int *yy_full_state; - - char *yytext_r; - int yy_more_flag; - int yy_more_len; - - YYSTYPE * yylval_r; - - }; /* end struct yyguts_t */ - -static int yy_init_globals (yyscan_t yyscanner ); - - /* This must go here because YYSTYPE and YYLTYPE are included - * from bison output in section 1.*/ - # define yylval yyg->yylval_r - -int yylex_init (yyscan_t* scanner); - -int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int yylex_destroy (yyscan_t yyscanner ); - -int yyget_debug (yyscan_t yyscanner ); - -void yyset_debug (int debug_flag ,yyscan_t yyscanner ); - -YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); - -void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); - -FILE *yyget_in (yyscan_t yyscanner ); +#define INITIAL 2 -void yyset_in (FILE * in_str ,yyscan_t yyscanner ); +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -FILE *yyget_out (yyscan_t yyscanner ); +void phpdbg_init_lexer (phpdbg_param_t *stack, char *input TSRMLS_DC) { + PHPDBG_G(parser_stack) = stack; -void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + YYSETCONDITION(INITIAL); -yy_size_t yyget_leng (yyscan_t yyscanner ); - -char *yyget_text (yyscan_t yyscanner ); - -int yyget_lineno (yyscan_t yyscanner ); - -void yyset_lineno (int line_number ,yyscan_t yyscanner ); - -int yyget_column (yyscan_t yyscanner ); - -void yyset_column (int column_no ,yyscan_t yyscanner ); - -YYSTYPE * yyget_lval (yyscan_t yyscanner ); - -void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap (yyscan_t yyscanner ); -#else -extern int yywrap (yyscan_t yyscanner ); -#endif -#endif - - static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#ifdef __cplusplus -static int yyinput (yyscan_t yyscanner ); -#else -static int input (yyscan_t yyscanner ); -#endif - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ - { \ - int c = '*'; \ - size_t n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else \ - { \ - errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(yyin); \ - } \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int yylex \ - (YYSTYPE * yylval_param ,yyscan_t yyscanner); - -#define YY_DECL int yylex \ - (YYSTYPE * yylval_param , yyscan_t yyscanner) -#endif /* !YY_DECL */ + LEX(text) = YYCURSOR = (unsigned char *) input; + LEX(len) = strlen(input); +} -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif +int phpdbg_lex (phpdbg_param_t* yylval) { + TSRMLS_FETCH(); /* Slow, but this is not a major problem here. TODO: Use TSRMLS_DC */ -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif +restart: + LEX(text) = YYCURSOR; -#define YY_RULE_SETUP \ - YY_USER_ACTION -/** The main scanner function which does all the work. - */ -YY_DECL +#line 48 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - -#line 44 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" - - -#line 882 "sapi/phpdbg/phpdbg_lexer.c" - - yylval = yylval_param; - - if ( !yyg->yy_init ) + YYCTYPE yych; + unsigned int yyaccept = 0; + if (YYGETCONDITION() < 1) { + goto yyc_NORMAL; + } else { + if (YYGETCONDITION() < 2) { + goto yyc_RAW; + } else { + goto yyc_INITIAL; + } + } +/* *********************************** */ +yyc_INITIAL: + { + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 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); + YYFILL(3); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= '\t') { + if (yych <= 0x00) goto yy6; + if (yych <= 0x08) goto yy11; + } else { + if (yych <= '\n') goto yy4; + if (yych != '\r') goto yy11; + } + } else { + if (yych <= 'e') { + if (yych <= ' ') goto yy2; + if (yych <= 'd') goto yy11; + goto yy7; + } else { + if (yych <= 'q') goto yy11; + if (yych <= 'r') goto yy9; + if (yych <= 's') goto yy8; + goto yy11; + } + } +yy2: + YYDEBUG(2, *YYCURSOR); + ++YYCURSOR; + if (yybm[0+(yych = *YYCURSOR)] & 128) { + goto yy19; + } +yy3: + YYDEBUG(3, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 161 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - yyg->yy_init = 1; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - /* Create the reject buffer large enough to save one state per allowed character. */ - if ( ! yyg->yy_state_buf ) - yyg->yy_state_buf = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE ,yyscanner); - if ( ! yyg->yy_state_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); - - if ( ! yyg->yy_start ) - yyg->yy_start = 1; /* first start state */ + YYSETCONDITION(NORMAL); - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + YYCURSOR = LEX(text); + goto restart; +} +#line 138 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy4: + YYDEBUG(4, *YYCURSOR); + ++YYCURSOR; + if (yybm[0+(yych = *YYCURSOR)] & 128) { + goto yy19; } - - yy_load_buffer_state(yyscanner ); + YYDEBUG(5, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + return 0; +} +#line 151 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy6: + YYDEBUG(6, *YYCURSOR); + yych = *++YYCURSOR; + goto yy3; +yy7: + YYDEBUG(7, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == 'v') goto yy17; + goto yy3; +yy8: + YYDEBUG(8, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == 'h') goto yy15; + goto yy3; +yy9: + YYDEBUG(9, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy12; +yy10: + YYDEBUG(10, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 155 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_RUN; +} +#line 180 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy11: + YYDEBUG(11, *YYCURSOR); + yych = *++YYCURSOR; + goto yy3; +yy12: + YYDEBUG(12, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == 'n') goto yy14; + YYDEBUG(13, *YYCURSOR); + YYCURSOR = YYMARKER; + goto yy10; +yy14: + YYDEBUG(14, *YYCURSOR); + yych = *++YYCURSOR; + goto yy10; +yy15: + YYDEBUG(15, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(16, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 150 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_SHELL; +} +#line 207 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy17: + YYDEBUG(17, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(18, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 145 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_EVAL; +} +#line 219 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy19: + YYDEBUG(19, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(20, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy19; } - - while ( 1 ) /* loops until end-of-file is reached */ + YYDEBUG(21, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - yy_cp = yyg->yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yyg->yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yyg->yy_start; + /* ignore whitespace */ - yyg->yy_state_ptr = yyg->yy_state_buf; - *yyg->yy_state_ptr++ = yy_current_state; - -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 126 ) - yy_c = yy_meta[(unsigned int) yy_c]; + goto restart; +} +#line 237 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" + } +/* *********************************** */ +yyc_NORMAL: + { + static const unsigned char yybm[] = { + 0, 16, 16, 16, 16, 16, 16, 16, + 16, 8, 8, 16, 16, 8, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 8, 16, 16, 0, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 48, 16, + 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 0, 16, 16, 16, 16, 16, + 16, 208, 208, 208, 208, 208, 208, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 16, 16, 16, 16, 16, + 16, 208, 208, 208, 208, 208, 208, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }; + YYDEBUG(22, *YYCURSOR); + YYFILL(11); + yych = *YYCURSOR; + if (yych <= ':') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych <= 0x00) goto yy29; + if (yych <= 0x08) goto yy32; + if (yych >= '\n') goto yy27; + } else { + if (yych == '\r') goto yy24; + if (yych <= 0x1F) goto yy32; + } + } else { + if (yych <= '.') { + if (yych == '#') goto yy47; + if (yych <= '-') goto yy32; + goto yy34; + } else { + if (yych <= '/') goto yy32; + if (yych <= '0') goto yy37; + if (yych <= '9') goto yy34; + goto yy49; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - *yyg->yy_state_ptr++ = yy_current_state; - ++yy_cp; } - while ( yy_current_state != 125 ); - -yy_find_action: - yy_current_state = *--yyg->yy_state_ptr; - yyg->yy_lp = yy_accept[yy_current_state]; -find_rule: /* we branch to this label when backing up */ - for ( ; ; ) /* until we find what rule we matched */ - { - if ( yyg->yy_lp && yyg->yy_lp < yy_accept[yy_current_state + 1] ) - { - yy_act = yy_acclist[yyg->yy_lp]; - { - yyg->yy_full_match = yy_cp; - break; + } else { + if (yych <= 'i') { + if (yych <= 'd') { + if (yych == 'Z') goto yy38; + if (yych <= 'c') goto yy32; + goto yy39; + } else { + if (yych <= 'e') goto yy40; + if (yych <= 'f') goto yy41; + if (yych <= 'h') goto yy32; + goto yy30; + } + } else { + if (yych <= 's') { + if (yych <= 'm') goto yy32; + if (yych <= 'n') goto yy42; + if (yych <= 'o') goto yy43; + goto yy32; + } else { + if (yych <= 'x') { + if (yych <= 't') goto yy44; + goto yy32; + } else { + if (yych <= 'y') goto yy45; + if (yych <= 'z') goto yy46; + goto yy32; } } - --yy_cp; - yy_current_state = *--yyg->yy_state_ptr; - yyg->yy_lp = yy_accept[yy_current_state]; } + } +yy24: + YYDEBUG(24, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(25, *YYCURSOR); + if (yybm[0+yych] & 8) { + goto yy24; + } + YYDEBUG(26, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + /* ignore whitespace */ - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ - -case 1: -YY_RULE_SETUP -#line 47 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_EVAL; - } - YY_BREAK -case 2: -YY_RULE_SETUP -#line 52 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_SHELL; - } - YY_BREAK -case 3: -YY_RULE_SETUP -#line 57 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_RUN; - } - YY_BREAK -case 4: -YY_RULE_SETUP -#line 63 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - BEGIN(NORMAL); - REJECT; - } - YY_BREAK - - -case 5: -YY_RULE_SETUP -#line 70 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_IF; - } - YY_BREAK - - -case 6: -YY_RULE_SETUP -#line 78 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - phpdbg_init_param(yylval, STR_PARAM); - yylval->str = zend_strndup(yytext, yyleng); - yylval->len = yyleng; - return T_PROTO; - } - YY_BREAK -case 7: -YY_RULE_SETUP -#line 84 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ return T_POUND; } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 85 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ return T_DCOLON; } - YY_BREAK -case 9: -YY_RULE_SETUP -#line 86 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ return T_COLON; } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 88 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - phpdbg_init_param(yylval, NUMERIC_PARAM); - yylval->num = 1; - return T_TRUTHY; - } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 93 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - phpdbg_init_param(yylval, NUMERIC_PARAM); - yylval->num = 0; - return T_FALSY; - } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 98 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - phpdbg_init_param(yylval, NUMERIC_PARAM); - yylval->num = atoi(yytext); - return T_DIGITS; - } - YY_BREAK -case 13: -YY_RULE_SETUP -#line 103 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - phpdbg_init_param(yylval, ADDR_PARAM); - yylval->addr = strtoul(yytext, 0, 16); - return T_ADDR; - } - YY_BREAK -case 14: -YY_RULE_SETUP -#line 108 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - phpdbg_init_param(yylval, OP_PARAM); - yylval->str = zend_strndup(yytext, yyleng); - yylval->len = yyleng; - return T_OPCODE; - } - YY_BREAK -case 15: -YY_RULE_SETUP -#line 114 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ - phpdbg_init_param(yylval, STR_PARAM); - yylval->str = zend_strndup(yytext, yyleng); - yylval->len = yyleng; - return T_ID; - } - YY_BREAK - -case 16: -YY_RULE_SETUP -#line 122 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ + goto restart; +} +#line 348 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy27: + YYDEBUG(27, *YYCURSOR); + ++YYCURSOR; + if (yybm[0+(yych = *YYCURSOR)] & 8) { + goto yy24; + } +yy28: + YYDEBUG(28, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + return 0; +} +#line 362 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy29: + YYDEBUG(29, *YYCURSOR); + yych = *++YYCURSOR; + goto yy28; +yy30: + YYDEBUG(30, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'f') goto yy94; + goto yy33; +yy31: + YYDEBUG(31, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; - BEGIN(INITIAL); - return T_INPUT; -} - YY_BREAK -case 17: -/* rule 17 can match eol */ -YY_RULE_SETUP -#line 130 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -{ /* ignore whitespace */ } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 131 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" -YY_FATAL_ERROR( "flex scanner jammed" ); - YY_BREAK -#line 1129 "sapi/phpdbg/phpdbg_lexer.c" - case YY_STATE_EOF(INITIAL): - case YY_STATE_EOF(RAW): - case YY_STATE_EOF(NORMAL): - yyterminate(); - - case YY_END_OF_BUFFER: + return T_ID; +} +#line 383 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy32: + YYDEBUG(32, *YYCURSOR); + yyaccept = 0; + YYMARKER = ++YYCURSOR; + YYFILL(3); + yych = *YYCURSOR; +yy33: + YYDEBUG(33, *YYCURSOR); + if (yybm[0+yych] & 16) { + goto yy32; + } + if (yych <= '9') goto yy31; + goto yy54; +yy34: + YYDEBUG(34, *YYCURSOR); + yyaccept = 1; + YYMARKER = ++YYCURSOR; + YYFILL(3); + yych = *YYCURSOR; + YYDEBUG(35, *YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy34; + } + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x00) goto yy36; + if (yych <= 0x08) goto yy32; + } else { + if (yych != '\r') goto yy32; + } + } else { + if (yych <= '#') { + if (yych <= ' ') goto yy36; + if (yych <= '"') goto yy32; + } else { + if (yych == ':') goto yy54; + goto yy32; + } + } +yy36: + YYDEBUG(36, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 106 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yyg->yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = atoi(yytext); + return T_DIGITS; +} +#line 432 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy37: + YYDEBUG(37, *YYCURSOR); + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy34; + } + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x00) goto yy36; + if (yych <= 0x08) goto yy33; + goto yy36; + } else { + if (yych == '\r') goto yy36; + goto yy33; } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); - - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yyg->yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yyg->yy_c_buf_p; - goto yy_find_action; - } + } else { + if (yych <= '#') { + if (yych <= ' ') goto yy36; + if (yych <= '"') goto yy33; + goto yy36; + } else { + if (yych == 'x') goto yy90; + goto yy33; } - - else switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_END_OF_FILE: - { - yyg->yy_did_buffer_switch_on_eof = 0; - - if ( yywrap(yyscanner ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = - yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yyg->yy_c_buf_p = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ -} /* end of yylex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; +yy38: + YYDEBUG(38, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'E') goto yy87; + goto yy33; +yy39: + YYDEBUG(39, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy81; + goto yy33; +yy40: + YYDEBUG(40, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy76; + goto yy33; +yy41: + YYDEBUG(41, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy73; + goto yy33; +yy42: + YYDEBUG(42, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy71; + goto yy33; +yy43: + YYDEBUG(43, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'f') goto yy70; + if (yych == 'n') goto yy66; + goto yy33; +yy44: + YYDEBUG(44, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy68; + goto yy33; +yy45: + YYDEBUG(45, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy65; + goto yy33; +yy46: + YYDEBUG(46, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy53; + goto yy33; +yy47: + YYDEBUG(47, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(48, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 84 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + return T_POUND; +} +#line 523 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy49: + YYDEBUG(49, *YYCURSOR); + ++YYCURSOR; + if ((yych = *YYCURSOR) == ':') goto yy51; + YYDEBUG(50, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 90 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + return T_COLON; +} +#line 534 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy51: + YYDEBUG(51, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(52, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + return T_DCOLON; +} +#line 544 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy53: + YYDEBUG(53, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy59; + goto yy33; +yy54: + YYDEBUG(54, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == '/') goto yy56; +yy55: + YYDEBUG(55, *YYCURSOR); + YYCURSOR = YYMARKER; + if (yyaccept <= 3) { + if (yyaccept <= 1) { + if (yyaccept <= 0) { + goto yy31; + } else { + goto yy36; + } + } else { + if (yyaccept <= 2) { + goto yy64; + } else { + goto yy67; + } } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; + } else { + if (yyaccept <= 5) { + if (yyaccept <= 4) { + goto yy72; + } else { + goto yy93; + } + } else { + goto yy95; } } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; - - else +yy56: + YYDEBUG(56, *YYCURSOR); + yych = *++YYCURSOR; + if (yych != '/') goto yy55; + YYDEBUG(57, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(58, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 78 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - yy_size_t num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); - + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = zend_strndup(yytext, yyleng); + yylval->len = yyleng; + return T_PROTO; +} +#line 598 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy59: + YYDEBUG(59, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy33; + YYDEBUG(60, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy33; +yy61: + YYDEBUG(61, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy62; + } + goto yy33; +yy62: + YYDEBUG(62, *YYCURSOR); + yyaccept = 2; + YYMARKER = ++YYCURSOR; + YYFILL(3); + yych = *YYCURSOR; + YYDEBUG(63, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy62; + } + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x00) goto yy64; + if (yych <= 0x08) goto yy32; + } else { + if (yych != '\r') goto yy32; + } + } else { + if (yych <= '#') { + if (yych <= ' ') goto yy64; + if (yych <= '"') goto yy32; + } else { + if (yych == ':') goto yy54; + goto yy32; } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } - - if ( yyg->yy_n_chars == 0 ) +yy64: + YYDEBUG(64, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart(yyin ,yyscanner); + phpdbg_init_param(yylval, OP_PARAM); + yylval->str = zend_strndup(yytext, yyleng); + yylval->len = yyleng; + return T_OPCODE; +} +#line 652 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy65: + YYDEBUG(65, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy33; +yy66: + YYDEBUG(66, *YYCURSOR); + yyaccept = 3; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\r') { + if (yych <= 0x08) { + if (yych >= 0x01) goto yy33; + } else { + if (yych <= '\n') goto yy67; + if (yych <= '\f') goto yy33; } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; + } else { + if (yych <= ' ') { + if (yych <= 0x1F) goto yy33; + } else { + if (yych != '#') goto yy33; } } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { - /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); - if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); - } - - yyg->yy_n_chars += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (yyscan_t yyscanner) -{ - register yy_state_type yy_current_state; - register char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_current_state = yyg->yy_start; - - yyg->yy_state_ptr = yyg->yy_state_buf; - *yyg->yy_state_ptr++ = yy_current_state; - - for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) +yy67: + YYDEBUG(67, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 94 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 126 ) - yy_c = yy_meta[(unsigned int) yy_c]; + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 1; + return T_TRUTHY; +} +#line 685 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy68: + YYDEBUG(68, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy33; + YYDEBUG(69, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy66; + goto yy33; +yy70: + YYDEBUG(70, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'f') goto yy33; +yy71: + YYDEBUG(71, *YYCURSOR); + yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\r') { + if (yych <= 0x08) { + if (yych >= 0x01) goto yy33; + } else { + if (yych <= '\n') goto yy72; + if (yych <= '\f') goto yy33; + } + } else { + if (yych <= ' ') { + if (yych <= 0x1F) goto yy33; + } else { + if (yych != '#') goto yy33; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - *yyg->yy_state_ptr++ = yy_current_state; } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) -{ - register int yy_is_jam; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - - register YY_CHAR yy_c = 1; - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) +yy72: + YYDEBUG(72, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 100 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 126 ) - yy_c = yy_meta[(unsigned int) yy_c]; + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 0; + return T_FALSY; +} +#line 728 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy73: + YYDEBUG(73, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy33; + YYDEBUG(74, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy33; + YYDEBUG(75, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy71; + goto yy33; +yy76: + YYDEBUG(76, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy33; + YYDEBUG(77, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy33; + YYDEBUG(78, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy33; + YYDEBUG(79, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy33; + YYDEBUG(80, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy66; + goto yy33; +yy81: + YYDEBUG(81, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy33; + YYDEBUG(82, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy33; + YYDEBUG(83, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy33; + YYDEBUG(84, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy33; + YYDEBUG(85, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy33; + YYDEBUG(86, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy71; + goto yy33; +yy87: + YYDEBUG(87, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'N') goto yy33; + YYDEBUG(88, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'D') goto yy33; + YYDEBUG(89, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '_') goto yy61; + goto yy33; +yy90: + YYDEBUG(90, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy91; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 125); - if ( ! yy_is_jam ) - *yyg->yy_state_ptr++ = yy_current_state; - - (void)yyg; - return yy_is_jam ? 0 : yy_current_state; -} - - static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) -{ - register char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_cp = yyg->yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yyg->yy_hold_char; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register yy_size_t number_to_move = yyg->yy_n_chars + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - - while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); + goto yy33; +yy91: + YYDEBUG(91, *YYCURSOR); + yyaccept = 5; + YYMARKER = ++YYCURSOR; + YYFILL(3); + yych = *YYCURSOR; + YYDEBUG(92, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy91; } - - *--yy_cp = (char) c; - - yyg->yytext_ptr = yy_bp; - yyg->yy_hold_char = *yy_cp; - yyg->yy_c_buf_p = yy_cp; -} - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (yyscan_t yyscanner) -#else - static int input (yyscan_t yyscanner) -#endif - -{ - int c; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - *yyg->yy_c_buf_p = yyg->yy_hold_char; - - if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x00) goto yy93; + if (yych <= 0x08) goto yy32; + } else { + if (yych != '\r') goto yy32; + } + } else { + if (yych <= '#') { + if (yych <= ' ') goto yy93; + if (yych <= '"') goto yy32; + } else { + if (yych == ':') goto yy54; + goto yy32; + } + } +yy93: + YYDEBUG(93, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - /* This was really a NUL. */ - *yyg->yy_c_buf_p = '\0'; - - else - { /* need more input */ - yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; - ++yyg->yy_c_buf_p; - - switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart(yyin ,yyscanner); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap(yyscanner ) ) - return EOF; - - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(yyscanner); -#else - return input(yyscanner); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = yyg->yytext_ptr + offset; - break; - } + phpdbg_init_param(yylval, ADDR_PARAM); + yylval->addr = strtoul(yytext, 0, 16); + return T_ADDR; +} +#line 848 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy94: + YYDEBUG(94, *YYCURSOR); + yyaccept = 6; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\r') { + if (yych <= 0x08) { + if (yych >= 0x01) goto yy33; + } else { + if (yych <= '\n') goto yy95; + if (yych <= '\f') goto yy33; + } + } else { + if (yych <= ' ') { + if (yych <= 0x1F) goto yy33; + } else { + if (yych != '#') goto yy33; } } - - c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ - *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ - yyg->yy_hold_char = *++yyg->yy_c_buf_p; - - return c; +yy95: + YYDEBUG(95, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_IF; } -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * @param yyscanner The scanner object. - * @note This function does not reset the start condition to @c INITIAL . - */ - void yyrestart (FILE * input_file , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! YY_CURRENT_BUFFER ){ - yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); +#line 876 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } - - yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); - yy_load_buffer_state(yyscanner ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * @param yyscanner The scanner object. - */ - void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* TODO. We should be able to replace this entire function body - * with - * yypop_buffer_state(); - * yypush_buffer_state(new_buffer); - */ - yyensure_buffer_stack (yyscanner); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; +/* *********************************** */ +yyc_RAW: + { + static const unsigned char yybm[] = { + 0, 64, 64, 64, 64, 64, 64, 64, + 64, 224, 128, 64, 64, 224, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 224, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + }; + YYDEBUG(96, *YYCURSOR); + YYFILL(2); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy98; } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - yy_load_buffer_state(yyscanner ); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yyg->yy_did_buffer_switch_on_eof = 1; -} - -static void yy_load_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - yyg->yy_hold_char = *yyg->yy_c_buf_p; -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * @param yyscanner The scanner object. - * @return the allocated buffer state. - */ - YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer(b,file ,yyscanner); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with yy_create_buffer() - * @param yyscanner The scanner object. - */ - void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yyfree((void *) b->yy_ch_buf ,yyscanner ); - - yyfree((void *) b ,yyscanner ); -} - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a yyrestart() or at EOF. - */ - static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) - -{ - int oerrno = errno; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_flush_buffer(b ,yyscanner); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then yy_init_buffer was _probably_ - * called from yyrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * @param yyscanner The scanner object. - */ - void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - yy_load_buffer_state(yyscanner ); + if (yych <= 0x00) goto yy103; + if (yych == '\n') goto yy101; + goto yy104; +yy98: + YYDEBUG(98, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(99, *YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy98; + } + if (yych <= 0x00) goto yy100; + if (yych == '\n') goto yy106; + goto yy104; +yy100: + YYDEBUG(100, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = zend_strndup(yytext, yyleng); + yylval->len = yyleng; + return T_INPUT; } - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * @param yyscanner The scanner object. - */ -void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (new_buffer == NULL) - return; - - yyensure_buffer_stack(yyscanner); - - /* This block is copied from yy_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) +#line 946 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy101: + YYDEBUG(101, *YYCURSOR); + ++YYCURSOR; + if (yybm[0+(yych = *YYCURSOR)] & 128) { + goto yy106; + } +yy102: + YYDEBUG(102, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + return 0; +} +#line 960 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy103: + YYDEBUG(103, *YYCURSOR); + yych = *++YYCURSOR; + goto yy102; +yy104: + YYDEBUG(104, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(105, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy104; } + goto yy100; +yy106: + YYDEBUG(106, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(107, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy106; + } + YYDEBUG(108, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + /* ignore whitespace */ - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - yyg->yy_buffer_stack_top++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from yy_switch_to_buffer. */ - yy_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * @param yyscanner The scanner object. - */ -void yypop_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (!YY_CURRENT_BUFFER) - return; - - yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); - YY_CURRENT_BUFFER_LVALUE = NULL; - if (yyg->yy_buffer_stack_top > 0) - --yyg->yy_buffer_stack_top; - - if (YY_CURRENT_BUFFER) { - yy_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void yyensure_buffer_stack (yyscan_t yyscanner) -{ - yy_size_t num_to_alloc; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (!yyg->yy_buffer_stack) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; - yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - yyg->yy_buffer_stack_max = num_to_alloc; - yyg->yy_buffer_stack_top = 0; - return; - } - - if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = yyg->yy_buffer_stack_max + grow_size; - yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc - (yyg->yy_buffer_stack, - num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - /* zero only the new slots.*/ - memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); - yyg->yy_buffer_stack_max = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer(b ,yyscanner ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to yylex() will - * scan from a @e copy of @a str. - * @param yystr a NUL-terminated string to scan - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * yy_scan_bytes() instead. - */ -YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) -{ - - return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); -} - -/** Setup the input buffer state to scan the given bytes. The next call to yylex() will - * scan from a @e copy of @a bytes. - * @param yybytes the byte buffer to scan - * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - yy_size_t i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; - buf = (char *) yyalloc(n ,yyscanner ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < _yybytes_len; ++i ) - buf[i] = yybytes[i]; - - buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer(buf,n ,yyscanner); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) -{ - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = yyg->yy_hold_char; \ - yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ - yyg->yy_hold_char = *yyg->yy_c_buf_p; \ - *yyg->yy_c_buf_p = '\0'; \ - yyleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the user-defined data for this scanner. - * @param yyscanner The scanner object. - */ -YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyextra; -} - -/** Get the current line number. - * @param yyscanner The scanner object. - */ -int yyget_lineno (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yylineno; -} - -/** Get the current column number. - * @param yyscanner The scanner object. - */ -int yyget_column (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yycolumn; -} - -/** Get the input stream. - * @param yyscanner The scanner object. - */ -FILE *yyget_in (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyin; -} - -/** Get the output stream. - * @param yyscanner The scanner object. - */ -FILE *yyget_out (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyout; -} - -/** Get the length of the current token. - * @param yyscanner The scanner object. - */ -yy_size_t yyget_leng (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyleng; -} - -/** Get the current token. - * @param yyscanner The scanner object. - */ - -char *yyget_text (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yytext; -} - -/** Set the user-defined data. This data is never touched by the scanner. - * @param user_defined The data to be associated with this scanner. - * @param yyscanner The scanner object. - */ -void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyextra = user_defined ; -} - -/** Set the current line number. - * @param line_number - * @param yyscanner The scanner object. - */ -void yyset_lineno (int line_number , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* lineno is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); - - yylineno = line_number; -} - -/** Set the current column. - * @param line_number - * @param yyscanner The scanner object. - */ -void yyset_column (int column_no , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* column is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - YY_FATAL_ERROR( "yyset_column called with no buffer" ); - - yycolumn = column_no; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param in_str A readable stream. - * @param yyscanner The scanner object. - * @see yy_switch_to_buffer - */ -void yyset_in (FILE * in_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyin = in_str ; -} - -void yyset_out (FILE * out_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyout = out_str ; -} - -int yyget_debug (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yy_flex_debug; -} - -void yyset_debug (int bdebug , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yy_flex_debug = bdebug ; -} - -/* Accessor methods for yylval and yylloc */ - -YYSTYPE * yyget_lval (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yylval; -} - -void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yylval = yylval_param; -} - -/* User-visible API */ - -/* yylex_init is special because it creates the scanner itself, so it is - * the ONLY reentrant function that doesn't take the scanner as the last argument. - * That's why we explicitly handle the declaration, instead of using our macros. - */ - -int yylex_init(yyscan_t* ptr_yy_globals) - -{ - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - return yy_init_globals ( *ptr_yy_globals ); -} - -/* yylex_init_extra has the same functionality as yylex_init, but follows the - * convention of taking the scanner as the last argument. Note however, that - * this is a *pointer* to a scanner, as it will be allocated by this call (and - * is the reason, too, why this function also must handle its own declaration). - * The user defined value in the first argument will be available to yyalloc in - * the yyextra field. - */ - -int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) - -{ - struct yyguts_t dummy_yyguts; - - yyset_extra (yy_user_defined, &dummy_yyguts); - - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in - yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - yyset_extra (yy_user_defined, *ptr_yy_globals); - - return yy_init_globals ( *ptr_yy_globals ); -} - -static int yy_init_globals (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - /* Initialization is the same as for the non-reentrant scanner. - * This function is called from yylex_destroy(), so don't allocate here. - */ - - yyg->yy_buffer_stack = 0; - yyg->yy_buffer_stack_top = 0; - yyg->yy_buffer_stack_max = 0; - yyg->yy_c_buf_p = (char *) 0; - yyg->yy_init = 0; - yyg->yy_start = 0; - - yyg->yy_start_stack_ptr = 0; - yyg->yy_start_stack_depth = 0; - yyg->yy_start_stack = NULL; - - yyg->yy_state_buf = 0; - yyg->yy_state_ptr = 0; - yyg->yy_full_match = 0; - yyg->yy_lp = 0; - -/* Defined in main.c */ -#ifdef YY_STDINIT - yyin = stdin; - yyout = stdout; -#else - yyin = (FILE *) 0; - yyout = (FILE *) 0; -#endif - - /* For future reference: Set errno on error, since we are called by - * yylex_init() - */ - return 0; + goto restart; } - -/* yylex_destroy is for both reentrant and non-reentrant scanners. */ -int yylex_destroy (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); - YY_CURRENT_BUFFER_LVALUE = NULL; - yypop_buffer_state(yyscanner); +#line 992 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } - - /* Destroy the stack itself. */ - yyfree(yyg->yy_buffer_stack ,yyscanner); - yyg->yy_buffer_stack = NULL; - - /* Destroy the start condition stack. */ - yyfree(yyg->yy_start_stack ,yyscanner ); - yyg->yy_start_stack = NULL; - - yyfree ( yyg->yy_state_buf , yyscanner); - yyg->yy_state_buf = NULL; - - /* Reset the globals. This is important in a non-reentrant scanner so the next time - * yylex() is called, initialization will occur. */ - yy_init_globals( yyscanner); - - /* Destroy the main struct (reentrant only). */ - yyfree ( yyscanner , yyscanner ); - yyscanner = NULL; - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) -{ - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; } -#endif +#line 168 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) -{ - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; } -#endif - -void *yyalloc (yy_size_t size , yyscan_t yyscanner) -{ - return (void *) malloc( size ); -} - -void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) -{ - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); -} - -void yyfree (void * ptr , yyscan_t yyscanner) -{ - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ -} - -#define YYTABLES_NAME "yytables" - -#line 131 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" - - - diff --git a/phpdbg_lexer.h b/phpdbg_lexer.h index 1958cef9a2..ab51e7daa8 100644 --- a/phpdbg_lexer.h +++ b/phpdbg_lexer.h @@ -1,348 +1,41 @@ -#ifndef yyHEADER_H -#define yyHEADER_H 1 -#define yyIN_HEADER 1 +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_LEXER_H +#define PHPDBG_LEXER_H + +#include "phpdbg_cmd.h" + +typedef struct { + unsigned int len; + unsigned char *text; + unsigned char *cursor; + unsigned char *marker; + int state; +} phpdbg_lexer_data; + +#define yyparse phpdbg_parse +#define yylex phpdbg_lex + +void phpdbg_init_lexer (phpdbg_param_t *stack, char *input TSRMLS_DC); + +int phpdbg_lex (phpdbg_param_t* yylval); -#line 6 "sapi/phpdbg/phpdbg_lexer.h" - -#line 8 "sapi/phpdbg/phpdbg_lexer.h" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 37 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#endif - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; #endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - yy_size_t yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -void yyrestart (FILE *input_file ,yyscan_t yyscanner ); -void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void yypop_buffer_state (yyscan_t yyscanner ); - -YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); - -void *yyalloc (yy_size_t ,yyscan_t yyscanner ); -void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void yyfree (void * ,yyscan_t yyscanner ); - -/* Begin user sect3 */ - -#define yywrap(yyscanner) 1 -#define YY_SKIP_YYWRAP - -#define yytext_ptr yytext_r - -#ifdef YY_HEADER_EXPORT_START_CONDITIONS -#define INITIAL 0 -#define RAW 1 -#define NORMAL 2 - -#endif - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -int yylex_init (yyscan_t* scanner); - -int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int yylex_destroy (yyscan_t yyscanner ); - -int yyget_debug (yyscan_t yyscanner ); - -void yyset_debug (int debug_flag ,yyscan_t yyscanner ); - -YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); - -void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); - -FILE *yyget_in (yyscan_t yyscanner ); - -void yyset_in (FILE * in_str ,yyscan_t yyscanner ); - -FILE *yyget_out (yyscan_t yyscanner ); - -void yyset_out (FILE * out_str ,yyscan_t yyscanner ); - -yy_size_t yyget_leng (yyscan_t yyscanner ); - -char *yyget_text (yyscan_t yyscanner ); - -int yyget_lineno (yyscan_t yyscanner ); - -void yyset_lineno (int line_number ,yyscan_t yyscanner ); - -int yyget_column (yyscan_t yyscanner ); - -void yyset_column (int column_no ,yyscan_t yyscanner ); - -YYSTYPE * yyget_lval (yyscan_t yyscanner ); - -void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap (yyscan_t yyscanner ); -#else -extern int yywrap (yyscan_t yyscanner ); -#endif -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int yylex \ - (YYSTYPE * yylval_param ,yyscan_t yyscanner); - -#define YY_DECL int yylex \ - (YYSTYPE * yylval_param , yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -#undef YY_NEW_FILE -#undef YY_FLUSH_BUFFER -#undef yy_set_bol -#undef yy_new_buffer -#undef yy_set_interactive -#undef YY_DO_BEFORE_ACTION - -#ifdef YY_DECL_IS_OURS -#undef YY_DECL_IS_OURS -#undef YY_DECL -#endif - -#line 131 "/usr/src/php-src/sapi/phpdbg/phpdbg_lexer.l" - - -#line 347 "sapi/phpdbg/phpdbg_lexer.h" -#undef yyIN_HEADER -#endif /* yyHEADER_H */ diff --git a/phpdbg_lexer.l b/phpdbg_lexer.l index b3536feab8..4d9c837f1e 100644 --- a/phpdbg_lexer.l +++ b/phpdbg_lexer.l @@ -1,131 +1,169 @@ -%{ - /* * phpdbg_lexer.l */ #include "phpdbg.h" #include "phpdbg_cmd.h" -#define YYSTYPE phpdbg_param_t #include "phpdbg_parser.h" -%} - -%s RAW -%s NORMAL - -%option outfile="sapi/phpdbg/phpdbg_lexer.c" header-file="sapi/phpdbg/phpdbg_lexer.h" -%option warn nodefault - -%option reentrant noyywrap never-interactive nounistd -%option bison-bridge - -T_TRUE "true" -T_YES "yes" -T_ON "on" -T_ENABLED "enabled" -T_FALSE "false" -T_NO "no" -T_OFF "off" -T_DISABLED "disabled" -T_EVAL "ev" -T_SHELL "sh" -T_IF "if" -T_RUN "run" -T_RUN_SHORT "r" - -WS [ \r\n\t]+ -DIGITS [0-9\.]+ -ID [^ \r\n\t:#]+ -ADDR 0x[a-fA-F0-9]+ -OPCODE (ZEND_|zend_)([A-Za-z])+ -INPUT [^\n]+ -%% - -{ - {T_EVAL} { - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_EVAL; - } - {T_SHELL} { - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_SHELL; - } - {T_RUN}|{T_RUN_SHORT} { - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_RUN; - } - - .+ { - BEGIN(NORMAL); - REJECT; - } -} - -{ - {T_IF} { - BEGIN(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_IF; - } -} - -{ - {ID}[:]{1}[//]{2} { - phpdbg_init_param(yylval, STR_PARAM); - yylval->str = zend_strndup(yytext, yyleng); - yylval->len = yyleng; - return T_PROTO; - } - [#]{1} { return T_POUND; } - [:]{2} { return T_DCOLON; } - [:]{1} { return T_COLON; } - - {T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE} { - phpdbg_init_param(yylval, NUMERIC_PARAM); - yylval->num = 1; - return T_TRUTHY; - } - {T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE} { - phpdbg_init_param(yylval, NUMERIC_PARAM); - yylval->num = 0; - return T_FALSY; - } - {DIGITS} { - phpdbg_init_param(yylval, NUMERIC_PARAM); - yylval->num = atoi(yytext); - return T_DIGITS; - } - {ADDR} { - phpdbg_init_param(yylval, ADDR_PARAM); - yylval->addr = strtoul(yytext, 0, 16); - return T_ADDR; - } - {OPCODE} { - phpdbg_init_param(yylval, OP_PARAM); - yylval->str = zend_strndup(yytext, yyleng); - yylval->len = yyleng; - return T_OPCODE; - } - {ID} { - phpdbg_init_param(yylval, STR_PARAM); - yylval->str = zend_strndup(yytext, yyleng); - yylval->len = yyleng; - return T_ID; - } -} - -{INPUT} { +#define LEX(v) (PHPDBG_G(lexer).v) + +#define YYCTYPE unsigned char +#define YYSETCONDITION(x) LEX(state) = x; +#define YYGETCONDITION() LEX(state) +#define YYCURSOR LEX(cursor) +#define YYMARKER LEX(marker) +#define yyleng LEX(len) +#define yytext ((char*) LEX(text)) +#undef YYDEBUG +#define YYDEBUG(a, b) +#define YYFILL(n) + +#define NORMAL 0 +#define RAW 1 +#define INITIAL 2 + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +void phpdbg_init_lexer (phpdbg_param_t *stack, char *input TSRMLS_DC) { + PHPDBG_G(parser_stack) = stack; + + YYSETCONDITION(INITIAL); + + LEX(text) = YYCURSOR = (unsigned char *) input; + LEX(len) = strlen(input); +} + +int phpdbg_lex (phpdbg_param_t* yylval) { + TSRMLS_FETCH(); /* Slow, but this is not a major problem here. TODO: Use TSRMLS_DC */ + +restart: + LEX(text) = YYCURSOR; + +/*!re2c +re2c:yyfill:check = 0; +T_TRUE "true" +T_YES "yes" +T_ON "on" +T_ENABLED "enabled" +T_FALSE "false" +T_NO "no" +T_OFF "off" +T_DISABLED "disabled" +T_EVAL "ev" +T_SHELL "sh" +T_IF "if" +T_RUN "run" +T_RUN_SHORT "r" +WS [ \r\n\t]+ +DIGITS [0-9\.]+ +ID [^ \r\n\t:#\000]+ +ADDR [0][x][a-fA-F0-9]+ +OPCODE (ZEND_|zend_)([A-Za-z])+ +INPUT [^\n\000]+ + + := yyleng = (size_t) YYCURSOR - (size_t) yytext; + +<*>[\n\000] { + return 0; +} + +{T_IF} { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_IF; +} + +{ID}[:]{1}[//]{2} { + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = zend_strndup(yytext, yyleng); + yylval->len = yyleng; + return T_PROTO; +} +[#]{1} { + return T_POUND; +} +[:]{2} { + return T_DCOLON; +} +[:]{1} { + return T_COLON; +} + +{T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE} { + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 1; + return T_TRUTHY; +} + +{T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE} { + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = 0; + return T_FALSY; +} + +{DIGITS} { + phpdbg_init_param(yylval, NUMERIC_PARAM); + yylval->num = atoi(yytext); + return T_DIGITS; +} + +{ADDR} { + phpdbg_init_param(yylval, ADDR_PARAM); + yylval->addr = strtoul(yytext, 0, 16); + return T_ADDR; +} + +{OPCODE} { + phpdbg_init_param(yylval, OP_PARAM); + yylval->str = zend_strndup(yytext, yyleng); + yylval->len = yyleng; + return T_OPCODE; +} + +{ID} { + phpdbg_init_param(yylval, STR_PARAM); + yylval->str = zend_strndup(yytext, yyleng); + yylval->len = yyleng; + return T_ID; +} + +{INPUT} { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; - BEGIN(INITIAL); return T_INPUT; } -{WS} { /* ignore whitespace */ } -%% +<*>{WS} { + /* ignore whitespace */ + + goto restart; +} + +{T_EVAL} { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_EVAL; +} +{T_SHELL} { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_SHELL; +} +{T_RUN}|{T_RUN_SHORT} { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_RUN; +} + +. { + YYSETCONDITION(NORMAL); + + YYCURSOR = LEX(text); + goto restart; +} + +*/ +} diff --git a/phpdbg_parser.c b/phpdbg_parser.c index 79af58f8c9..f9a3e4d299 100644 --- a/phpdbg_parser.c +++ b/phpdbg_parser.c @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 2.7. */ +/* A Bison parser, made by GNU Bison 2.6.2. */ /* Bison implementation for Yacc-like parsers in C @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.7" +#define YYBISON_VERSION "2.6.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -59,11 +59,18 @@ #define YYPULL 1 - +/* Substitute the variable and function names. */ +#define yyparse phpdbg_parse +#define yylex phpdbg_lex +#define yyerror phpdbg_error +#define yylval phpdbg_lval +#define yychar phpdbg_char +#define yydebug phpdbg_debug +#define yynerrs phpdbg_nerrs /* Copy the first part of user declarations. */ -/* Line 371 of yacc.c */ -#line 2 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 336 of yacc.c */ +#line 1 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" /* @@ -84,25 +91,14 @@ #include "phpdbg_parser.h" #include "phpdbg_lexer.h" +#undef yyerror +static int yyerror(void ***tsrm_ls, const char *msg); + ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -int yyerror(phpdbg_param_t *stack, yyscan_t scanner, const char *msg) { - TSRMLS_FETCH(); - phpdbg_error("Parse Error: %s", msg); - { - const phpdbg_param_t *top = stack; - - while (top) { - phpdbg_param_debug( - top, "--> "); - top = top->next; - } - } - return 0; -} -/* Line 371 of yacc.c */ -#line 106 "sapi/phpdbg/phpdbg_parser.c" +/* Line 336 of yacc.c */ +#line 102 "sapi/phpdbg/phpdbg_parser.c" # ifndef YY_NULL # if defined __cplusplus && 201103L <= __cplusplus @@ -122,18 +118,18 @@ int yyerror(phpdbg_param_t *stack, yyscan_t scanner, const char *msg) { /* In a future release of Bison, this section will be replaced by #include "phpdbg_parser.h". */ -#ifndef YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED -# define YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED +#ifndef PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H +# define PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG -extern int yydebug; +extern int phpdbg_debug; #endif /* "%code requires" blocks. */ -/* Line 387 of yacc.c */ -#line 40 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 350 of yacc.c */ +#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -142,8 +138,8 @@ typedef void* yyscan_t; #endif -/* Line 387 of yacc.c */ -#line 147 "sapi/phpdbg/phpdbg_parser.c" +/* Line 350 of yacc.c */ +#line 143 "sapi/phpdbg/phpdbg_parser.c" /* Tokens. */ #ifndef YYTOKENTYPE @@ -203,24 +199,24 @@ typedef int YYSTYPE; #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); +int phpdbg_parse (void *YYPARSE_PARAM); #else -int yyparse (); +int phpdbg_parse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus -int yyparse (phpdbg_param_t *stack, yyscan_t scanner); +int phpdbg_parse (void *tsrm_ls); #else -int yyparse (); +int phpdbg_parse (); #endif #endif /* ! YYPARSE_PARAM */ -#endif /* !YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */ +#endif /* !PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H */ /* Copy the second part of user declarations. */ -/* Line 390 of yacc.c */ -#line 224 "sapi/phpdbg/phpdbg_parser.c" +/* Line 353 of yacc.c */ +#line 220 "sapi/phpdbg/phpdbg_parser.c" #ifdef short # undef short @@ -273,24 +269,24 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* 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 /* 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) @@ -438,18 +434,18 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 24 +#define YYFINAL 25 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 33 +#define YYLAST 41 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 21 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 4 +#define YYNNTS 5 /* YYNRULES -- Number of rules. */ -#define YYNRULES 24 +#define YYNRULES 25 /* YYNRULES -- Number of states. */ -#define YYNSTATES 37 +#define YYNSTATES 38 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 @@ -496,30 +492,30 @@ static const yytype_uint8 yytranslate[] = YYRHS. */ static const yytype_uint8 yyprhs[] = { - 0, 0, 3, 5, 6, 8, 11, 15, 20, 25, - 31, 35, 41, 45, 48, 51, 54, 56, 59, 61, - 63, 65, 67, 69, 71 + 0, 0, 3, 5, 7, 8, 10, 13, 17, 22, + 27, 33, 37, 43, 47, 49, 51, 53, 55, 57, + 59, 61, 64, 67, 70, 72 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 22, 0, -1, 23, -1, -1, 24, -1, 23, 24, - -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, 3, 19, - -1, 5, 19, -1, 4, -1, 4, 19, -1, 17, - -1, 16, -1, 15, -1, 7, -1, 8, -1, 14, - -1, 18, -1 + 22, 0, -1, 23, -1, 25, -1, -1, 24, -1, + 23, 24, -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, 17, -1, 16, + -1, 15, -1, 7, -1, 8, -1, 14, -1, 18, + -1, 6, 19, -1, 3, 19, -1, 5, 19, -1, + 4, -1, 4, 19, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 76, 76, 77, 81, 82, 86, 91, 96, 107, - 118, 123, 129, 135, 140, 145, 150, 154, 159, 160, - 161, 162, 163, 164, 165 + 0, 66, 66, 67, 68, 72, 73, 77, 82, 87, + 97, 107, 112, 118, 124, 125, 126, 127, 128, 129, + 130, 134, 139, 144, 149, 153 }; #endif @@ -536,7 +532,7 @@ static const char *const yytname[] = "\"digits (numbers)\"", "\"literal (string)\"", "\"address\"", "\"opcode\"", "\"identifier (command or function name)\"", "\"input (input string or data)\"", "\"input\"", "$accept", "input", - "parameters", "parameter", YY_NULL + "parameters", "parameter", "full_expression", YY_NULL }; #endif @@ -554,17 +550,17 @@ static const yytype_uint16 yytoknum[] = /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 21, 22, 22, 23, 23, 24, 24, 24, 24, + 0, 21, 22, 22, 22, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24 + 24, 25, 25, 25, 25, 25 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 1, 0, 1, 2, 3, 4, 4, 5, - 3, 5, 3, 2, 2, 2, 1, 2, 1, 1, - 1, 1, 1, 1, 1 + 0, 2, 1, 1, 0, 1, 2, 3, 4, 4, + 5, 3, 5, 3, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 1, 2 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. @@ -572,16 +568,16 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 3, 0, 16, 0, 0, 21, 22, 0, 23, 20, - 19, 18, 24, 0, 2, 4, 14, 17, 15, 13, - 0, 0, 0, 0, 1, 5, 0, 0, 6, 10, - 12, 0, 8, 7, 0, 9, 11 + 4, 0, 24, 0, 0, 17, 18, 0, 19, 16, + 15, 14, 20, 0, 2, 5, 3, 22, 25, 23, + 21, 0, 0, 0, 0, 1, 6, 0, 0, 7, + 11, 13, 0, 9, 8, 0, 10, 12 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 13, 14, 15 + -1, 13, 14, 15, 16 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing @@ -589,16 +585,16 @@ static const yytype_int8 yydefgoto[] = #define YYPACT_NINF -11 static const yytype_int8 yypact[] = { - -3, -10, 1, 2, 3, -11, -11, 6, -11, -11, - -11, -11, -4, 23, -3, -11, -11, -11, -11, -11, - 15, 4, 8, 13, -11, -11, 5, 14, -11, 17, - -11, 16, -11, -11, 18, -11, -11 + -3, -10, 10, 11, 12, -11, -11, 14, -11, -11, + -11, -11, -4, 28, 9, -11, -11, -11, -11, -11, + -11, 23, 6, 16, 21, -11, -11, 7, 22, -11, + 25, -11, 24, -11, -11, 26, -11, -11 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -11, -11, -11, 19 + -11, -11, -11, 27, -11 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -607,24 +603,26 @@ static const yytype_int8 yypgoto[] = #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { - 1, 2, 3, 4, 5, 6, 21, 22, 23, 16, - 7, 8, 9, 10, 11, 12, 27, 31, 28, 32, - 17, 18, 19, 24, 20, 26, 29, 30, 33, 34, - 35, 0, 36, 25 + 1, 2, 3, 4, 5, 6, 22, 23, 24, 17, + 7, 8, 9, 10, 11, 12, 5, 6, 28, 32, + 29, 33, 7, 8, 9, 10, 11, 12, 25, 18, + 19, 20, 21, 27, 30, 31, 34, 35, 36, 0, + 37, 26 }; -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-11))) +#define yypact_value_is_default(yystate) \ + ((yystate) == (-11)) -#define yytable_value_is_error(Yytable_value) \ +#define yytable_value_is_error(yytable_value) \ YYID (0) static const yytype_int8 yycheck[] = { 3, 4, 5, 6, 7, 8, 10, 11, 12, 19, - 13, 14, 15, 16, 17, 18, 12, 12, 14, 14, - 19, 19, 19, 0, 18, 10, 18, 14, 14, 12, - 14, -1, 14, 14 + 13, 14, 15, 16, 17, 18, 7, 8, 12, 12, + 14, 14, 13, 14, 15, 16, 17, 18, 0, 19, + 19, 19, 18, 10, 18, 14, 14, 12, 14, -1, + 14, 14 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -632,9 +630,9 @@ static const yytype_int8 yycheck[] = static const yytype_uint8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 13, 14, 15, - 16, 17, 18, 22, 23, 24, 19, 19, 19, 19, - 18, 10, 11, 12, 0, 24, 10, 12, 14, 18, - 14, 12, 14, 14, 12, 14, 14 + 16, 17, 18, 22, 23, 24, 25, 19, 19, 19, + 19, 18, 10, 11, 12, 0, 24, 10, 12, 14, + 18, 14, 12, 14, 14, 12, 14, 14 }; #define yyerrok (yyerrstatus = 0) @@ -676,27 +674,56 @@ do \ } \ else \ { \ - yyerror (stack, scanner, YY_("syntax error: cannot back up")); \ + yyerror (tsrm_ls, 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). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + /* This macro is provided for backward compatibility. */ + #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ + #ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, YYLEX_PARAM) #else -# define YYLEX yylex (&yylval, scanner) +# define YYLEX yylex (&yylval) #endif /* Enable debugging if requested. */ @@ -719,7 +746,7 @@ do { \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ - Type, Value, stack, scanner); \ + Type, Value, tsrm_ls); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) @@ -733,23 +760,21 @@ do { \ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, phpdbg_param_t *stack, yyscan_t scanner) +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *tsrm_ls) #else static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep, stack, scanner) +yy_symbol_value_print (yyoutput, yytype, yyvaluep, tsrm_ls) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; - phpdbg_param_t *stack; - yyscan_t scanner; + void *tsrm_ls; #endif { FILE *yyo = yyoutput; YYUSE (yyo); if (!yyvaluep) return; - YYUSE (stack); - YYUSE (scanner); + YYUSE (tsrm_ls); # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); @@ -759,7 +784,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, stack, scanner) switch (yytype) { default: - break; + break; } } @@ -771,15 +796,14 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, stack, scanner) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, phpdbg_param_t *stack, yyscan_t scanner) +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *tsrm_ls) #else static void -yy_symbol_print (yyoutput, yytype, yyvaluep, stack, scanner) +yy_symbol_print (yyoutput, yytype, yyvaluep, tsrm_ls) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; - phpdbg_param_t *stack; - yyscan_t scanner; + void *tsrm_ls; #endif { if (yytype < YYNTOKENS) @@ -787,7 +811,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, stack, scanner) else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - yy_symbol_value_print (yyoutput, yytype, yyvaluep, stack, scanner); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, tsrm_ls); YYFPRINTF (yyoutput, ")"); } @@ -830,14 +854,13 @@ do { \ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule, phpdbg_param_t *stack, yyscan_t scanner) +yy_reduce_print (YYSTYPE *yyvsp, int yyrule, void *tsrm_ls) #else static void -yy_reduce_print (yyvsp, yyrule, stack, scanner) +yy_reduce_print (yyvsp, yyrule, tsrm_ls) YYSTYPE *yyvsp; int yyrule; - phpdbg_param_t *stack; - yyscan_t scanner; + void *tsrm_ls; #endif { int yynrhs = yyr2[yyrule]; @@ -851,7 +874,7 @@ yy_reduce_print (yyvsp, yyrule, stack, scanner) YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) - , stack, scanner); + , tsrm_ls); YYFPRINTF (stderr, "\n"); } } @@ -859,7 +882,7 @@ yy_reduce_print (yyvsp, yyrule, stack, scanner) # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ - yy_reduce_print (yyvsp, Rule, stack, scanner); \ + yy_reduce_print (yyvsp, Rule, tsrm_ls); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that @@ -1005,6 +1028,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, { YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULL; @@ -1067,13 +1091,11 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, 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; - } + yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; } } } @@ -1093,12 +1115,10 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, # undef YYCASE_ } - { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; if (*yymsg_alloc < yysize) { @@ -1139,20 +1159,18 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, phpdbg_param_t *stack, yyscan_t scanner) +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *tsrm_ls) #else static void -yydestruct (yymsg, yytype, yyvaluep, stack, scanner) +yydestruct (yymsg, yytype, yyvaluep, tsrm_ls) const char *yymsg; int yytype; YYSTYPE *yyvaluep; - phpdbg_param_t *stack; - yyscan_t scanner; + void *tsrm_ls; #endif { YYUSE (yyvaluep); - YYUSE (stack); - YYUSE (scanner); + YYUSE (tsrm_ls); if (!yymsg) yymsg = "Deleting"; @@ -1162,7 +1180,7 @@ yydestruct (yymsg, yytype, yyvaluep, stack, scanner) { default: - break; + break; } } @@ -1187,43 +1205,19 @@ yyparse (YYPARSE_PARAM) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int -yyparse (phpdbg_param_t *stack, yyscan_t scanner) +yyparse (void *tsrm_ls) #else int -yyparse (stack, scanner) - phpdbg_param_t *stack; - yyscan_t scanner; +yyparse (tsrm_ls) + void *tsrm_ls; #endif #endif { /* 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 YY_INITIAL_VALUE(yyval_default); +YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; @@ -1254,7 +1248,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; + int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; @@ -1272,8 +1266,9 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); Keep to zero when no symbol should be popped. */ int yylen = 0; - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); @@ -1282,6 +1277,13 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); 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; /*------------------------------------------------------------. @@ -1422,9 +1424,7 @@ yybackup: yychar = YYEMPTY; yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; @@ -1460,21 +1460,27 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 4: -/* Line 1792 of yacc.c */ -#line 81 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { phpdbg_stack_push(stack, &(yyvsp[(1) - (1)])); } + case 3: +/* Line 1802 of yacc.c */ +#line 67 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 5: -/* Line 1792 of yacc.c */ -#line 82 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { phpdbg_stack_push(stack, &(yyvsp[(2) - (2)])); } +/* Line 1802 of yacc.c */ +#line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 6: -/* Line 1792 of yacc.c */ -#line 86 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 1802 of yacc.c */ +#line 73 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); } + break; + + case 7: +/* Line 1802 of yacc.c */ +#line 77 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; (yyval).file.name = (yyvsp[(2) - (3)]).str; @@ -1482,9 +1488,9 @@ yyreduce: } break; - case 7: -/* Line 1792 of yacc.c */ -#line 91 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + case 8: +/* Line 1802 of yacc.c */ +#line 82 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; (yyval).file.name = (yyvsp[(1) - (4)]).str; @@ -1492,13 +1498,12 @@ yyreduce: } break; - case 8: -/* Line 1792 of yacc.c */ -#line 96 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + case 9: +/* Line 1802 of yacc.c */ +#line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; - (yyval).file.name = malloc((yyvsp[(1) - (4)]).len + - (yyvsp[(2) - (4)]).len + 1); + (yyval).file.name = malloc((yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len + 1); if ((yyval).file.name) { memcpy(&(yyval).file.name[0], (yyvsp[(1) - (4)]).str, (yyvsp[(1) - (4)]).len); memcpy(&(yyval).file.name[(yyvsp[(1) - (4)]).len], (yyvsp[(2) - (4)]).str, (yyvsp[(2) - (4)]).len); @@ -1508,13 +1513,12 @@ yyreduce: } break; - case 9: -/* Line 1792 of yacc.c */ -#line 107 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + case 10: +/* Line 1802 of yacc.c */ +#line 97 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; - (yyval).file.name = malloc((yyvsp[(1) - (5)]).len + - (yyvsp[(2) - (5)]).len + 1); + (yyval).file.name = malloc((yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len + 1); if ((yyval).file.name) { memcpy(&(yyval).file.name[0], (yyvsp[(1) - (5)]).str, (yyvsp[(1) - (5)]).len); memcpy(&(yyval).file.name[(yyvsp[(1) - (5)]).len], (yyvsp[(2) - (5)]).str, (yyvsp[(2) - (5)]).len); @@ -1524,9 +1528,9 @@ yyreduce: } break; - case 10: -/* Line 1792 of yacc.c */ -#line 118 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + case 11: +/* Line 1802 of yacc.c */ +#line 107 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (3)]).str; @@ -1534,9 +1538,9 @@ yyreduce: } break; - case 11: -/* Line 1792 of yacc.c */ -#line 123 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + case 12: +/* Line 1802 of yacc.c */ +#line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (5)]).str; @@ -1545,9 +1549,9 @@ yyreduce: } break; - case 12: -/* Line 1792 of yacc.c */ -#line 129 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" + case 13: +/* Line 1802 of yacc.c */ +#line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FUNCTION_PARAM; (yyval).str = (yyvsp[(1) - (3)]).str; @@ -1556,100 +1560,100 @@ yyreduce: } break; - case 13: -/* Line 1792 of yacc.c */ -#line 135 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { - (yyval).type = COND_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; - } - break; - case 14: -/* Line 1792 of yacc.c */ -#line 140 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { - (yyval).type = EVAL_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; - } +/* Line 1802 of yacc.c */ +#line 124 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 15: -/* Line 1792 of yacc.c */ -#line 145 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { - (yyval).type = SHELL_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; - } +/* Line 1802 of yacc.c */ +#line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 16: -/* Line 1792 of yacc.c */ -#line 150 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { - (yyval).type = RUN_PARAM; - (yyval).len = 0; - } +/* Line 1802 of yacc.c */ +#line 126 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 17: -/* Line 1792 of yacc.c */ -#line 154 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { - (yyval).type = RUN_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; - } +/* Line 1802 of yacc.c */ +#line 127 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 18: -/* Line 1792 of yacc.c */ -#line 159 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 1802 of yacc.c */ +#line 128 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 19: -/* Line 1792 of yacc.c */ -#line 160 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 1802 of yacc.c */ +#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 20: -/* Line 1792 of yacc.c */ -#line 161 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 1802 of yacc.c */ +#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 21: -/* Line 1792 of yacc.c */ -#line 162 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } +/* Line 1802 of yacc.c */ +#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = COND_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } break; case 22: -/* Line 1792 of yacc.c */ -#line 163 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } +/* Line 1802 of yacc.c */ +#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = EVAL_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } break; case 23: -/* Line 1792 of yacc.c */ -#line 164 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } +/* Line 1802 of yacc.c */ +#line 144 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = SHELL_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } break; case 24: -/* Line 1792 of yacc.c */ -#line 165 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } +/* Line 1802 of yacc.c */ +#line 149 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = RUN_PARAM; + (yyval).len = 0; + } break; + case 25: +/* Line 1802 of yacc.c */ +#line 153 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { + (yyval).type = RUN_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } + break; -/* Line 1792 of yacc.c */ -#line 1653 "sapi/phpdbg/phpdbg_parser.c" + +/* Line 1802 of yacc.c */ +#line 1657 "sapi/phpdbg/phpdbg_parser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1699,7 +1703,7 @@ yyerrlab: { ++yynerrs; #if ! YYERROR_VERBOSE - yyerror (stack, scanner, YY_("syntax error")); + yyerror (tsrm_ls, YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) @@ -1726,7 +1730,7 @@ yyerrlab: yymsgp = yymsg; } } - yyerror (stack, scanner, yymsgp); + yyerror (tsrm_ls, yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } @@ -1750,7 +1754,7 @@ yyerrlab: else { yydestruct ("Error: discarding", - yytoken, &yylval, stack, scanner); + yytoken, &yylval, tsrm_ls); yychar = YYEMPTY; } } @@ -1806,15 +1810,13 @@ yyerrlab1: yydestruct ("Error: popping", - yystos[yystate], yyvsp, stack, scanner); + yystos[yystate], yyvsp, tsrm_ls); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ @@ -1843,7 +1845,7 @@ yyabortlab: | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: - yyerror (stack, scanner, YY_("memory exhausted")); + yyerror (tsrm_ls, YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif @@ -1855,7 +1857,7 @@ yyreturn: user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, stack, scanner); + yytoken, &yylval, tsrm_ls); } /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ @@ -1864,7 +1866,7 @@ yyreturn: while (yyssp != yyss) { yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, stack, scanner); + yystos[*yyssp], yyvsp, tsrm_ls); YYPOPSTACK (1); } #ifndef yyoverflow @@ -1880,6 +1882,30 @@ yyreturn: } -/* Line 2055 of yacc.c */ -#line 168 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 2048 of yacc.c */ +#line 160 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +static int yyerror(void ***tsrm_ls, const char *msg) { + phpdbg_error("Parse Error: %s", msg); + + { + const phpdbg_param_t *top = PHPDBG_G(parser_stack); + + while (top) { + phpdbg_param_debug(top, "--> "); + top = top->next; + } + } + return 0; +} + +int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) { + phpdbg_init_lexer(stack, input TSRMLS_CC); + +#ifdef ZTS + return yyparse(TSRMLS_C); +#else + return yyparse(NULL); +#endif +} diff --git a/phpdbg_parser.h b/phpdbg_parser.h index 6acb8963c9..b3aadb9c62 100644 --- a/phpdbg_parser.h +++ b/phpdbg_parser.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 2.7. */ +/* A Bison parser, made by GNU Bison 2.6.2. */ /* Bison interface for Yacc-like parsers in C @@ -30,18 +30,18 @@ This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ -#ifndef YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED -# define YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED +#ifndef PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H +# define PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG -extern int yydebug; +extern int phpdbg_debug; #endif /* "%code requires" blocks. */ -/* Line 2058 of yacc.c */ -#line 40 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" +/* Line 2055 of yacc.c */ +#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -50,7 +50,7 @@ typedef void* yyscan_t; #endif -/* Line 2058 of yacc.c */ +/* Line 2055 of yacc.c */ #line 55 "sapi/phpdbg/phpdbg_parser.h" /* Tokens. */ @@ -111,16 +111,16 @@ typedef int YYSTYPE; #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); +int phpdbg_parse (void *YYPARSE_PARAM); #else -int yyparse (); +int phpdbg_parse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus -int yyparse (phpdbg_param_t *stack, yyscan_t scanner); +int phpdbg_parse (void *tsrm_ls); #else -int yyparse (); +int phpdbg_parse (); #endif #endif /* ! YYPARSE_PARAM */ -#endif /* !YY_YY_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */ +#endif /* !PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H */ diff --git a/phpdbg_parser.y b/phpdbg_parser.y index 4a84504e2e..fd81edfc29 100644 --- a/phpdbg_parser.y +++ b/phpdbg_parser.y @@ -1,4 +1,3 @@ -%error-verbose %{ /* @@ -19,23 +18,15 @@ #include "phpdbg_parser.h" #include "phpdbg_lexer.h" +#undef yyerror +static int yyerror(void ***tsrm_ls, const char *msg); + ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -int yyerror(phpdbg_param_t *stack, yyscan_t scanner, const char *msg) { - TSRMLS_FETCH(); - phpdbg_error("Parse Error: %s", msg); - { - const phpdbg_param_t *top = stack; - - while (top) { - phpdbg_param_debug( - top, "--> "); - top = top->next; - } - } - return 0; -} %} + +%pure-parser +%error-verbose %code requires { #include "phpdbg.h" @@ -44,59 +35,58 @@ int yyerror(phpdbg_param_t *stack, yyscan_t scanner, const char *msg) { typedef void* yyscan_t; #endif } + +%parse-param { void *tsrm_ls } + %output "sapi/phpdbg/phpdbg_parser.c" %defines "sapi/phpdbg/phpdbg_parser.h" - -%define api.pure -%lex-param { yyscan_t scanner } -%parse-param { phpdbg_param_t *stack } -%parse-param { yyscan_t scanner } - -%token T_EVAL "eval" -%token T_RUN "run" -%token T_SHELL "shell" -%token T_IF "if (condition)" -%token T_TRUTHY "truthy (true, on, yes or enabled)" -%token T_FALSY "falsy (false, off, no or disabled)" -%token T_STRING "string (some input, perhaps)" -%token T_COLON ": (colon)" -%token T_DCOLON ":: (double colon)" -%token T_POUND "# (pound sign)" -%token T_PROTO "protocol (file://)" -%token T_DIGITS "digits (numbers)" -%token T_LITERAL "literal (string)" -%token T_ADDR "address" -%token T_OPCODE "opcode" -%token T_ID "identifier (command or function name)" -%token T_INPUT "input (input string or data)" -%token T_UNEXPECTED "input" -%% + +%token T_EVAL "eval" +%token T_RUN "run" +%token T_SHELL "shell" +%token T_IF "if (condition)" +%token T_TRUTHY "truthy (true, on, yes or enabled)" +%token T_FALSY "falsy (false, off, no or disabled)" +%token T_STRING "string (some input, perhaps)" +%token T_COLON ": (colon)" +%token T_DCOLON ":: (double colon)" +%token T_POUND "# (pound sign)" +%token T_PROTO "protocol (file://)" +%token T_DIGITS "digits (numbers)" +%token T_LITERAL "literal (string)" +%token T_ADDR "address" +%token T_OPCODE "opcode" +%token T_ID "identifier (command or function name)" +%token T_INPUT "input (input string or data)" +%token T_UNEXPECTED "input" + +%% /* Rules */ input - : parameters - | /* nothing */ - ; + : parameters + | full_expression { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); } + | /* nothing */ + ; parameters - : parameter { phpdbg_stack_push(stack, &$1); } - | parameters parameter { phpdbg_stack_push(stack, &$2); } + : parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); } + | parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); } ; parameter - : T_ID T_COLON T_DIGITS { + : T_ID T_COLON T_DIGITS { $$.type = FILE_PARAM; $$.file.name = $2.str; $$.file.line = $3.num; } - | T_ID T_COLON T_POUND T_DIGITS { + | T_ID T_COLON T_POUND T_DIGITS { $$.type = NUMERIC_FILE_PARAM; $$.file.name = $1.str; $$.file.line = $4.num; } - | T_PROTO T_ID T_COLON T_DIGITS { + | T_PROTO T_ID T_COLON T_DIGITS { $$.type = FILE_PARAM; - $$.file.name = malloc($1.len + - $2.len + 1); + $$.file.name = malloc($1.len + $2.len + 1); if ($$.file.name) { memcpy(&$$.file.name[0], $1.str, $1.len); memcpy(&$$.file.name[$1.len], $2.str, $2.len); @@ -104,10 +94,9 @@ parameter } $$.file.line = $4.num; } - | T_PROTO T_ID T_COLON T_POUND T_DIGITS { + | T_PROTO T_ID T_COLON T_POUND T_DIGITS { $$.type = NUMERIC_FILE_PARAM; - $$.file.name = malloc($1.len + - $2.len + 1); + $$.file.name = malloc($1.len + $2.len + 1); if ($$.file.name) { memcpy(&$$.file.name[0], $1.str, $1.len); memcpy(&$$.file.name[$1.len], $2.str, $2.len); @@ -115,54 +104,81 @@ parameter } $$.file.line = $5.num; } - | T_ID T_DCOLON T_ID { + | T_ID T_DCOLON T_ID { $$.type = METHOD_PARAM; $$.method.class = $1.str; $$.method.name = $3.str; } - | T_ID T_DCOLON T_ID T_POUND T_DIGITS { + | T_ID T_DCOLON T_ID T_POUND T_DIGITS { $$.type = NUMERIC_METHOD_PARAM; $$.method.class = $1.str; $$.method.name = $3.str; $$.num = $5.num; } - | T_ID T_POUND T_DIGITS { + | T_ID T_POUND T_DIGITS { $$.type = NUMERIC_FUNCTION_PARAM; $$.str = $1.str; $$.len = $1.len; $$.num = $3.num; } - | T_IF T_INPUT { + | T_OPCODE { $$ = $1; } + | T_ADDR { $$ = $1; } + | T_LITERAL { $$ = $1; } + | T_TRUTHY { $$ = $1; } + | T_FALSY { $$ = $1; } + | T_DIGITS { $$ = $1; } + | T_ID { $$ = $1; } + ; + +full_expression + : T_IF T_INPUT { $$.type = COND_PARAM; $$.str = $2.str; $$.len = $2.len; } - | T_EVAL T_INPUT { + | T_EVAL T_INPUT { $$.type = EVAL_PARAM; $$.str = $2.str; $$.len = $2.len; } - | T_SHELL T_INPUT { + | T_SHELL T_INPUT { $$.type = SHELL_PARAM; $$.str = $2.str; $$.len = $2.len; } - | T_RUN { + | T_RUN { $$.type = RUN_PARAM; $$.len = 0; } - | T_RUN T_INPUT { + | T_RUN T_INPUT { $$.type = RUN_PARAM; $$.str = $2.str; $$.len = $2.len; } - | T_OPCODE { $$ = $1; } - | T_ADDR { $$ = $1; } - | T_LITERAL { $$ = $1; } - | T_TRUTHY { $$ = $1; } - | T_FALSY { $$ = $1; } - | T_DIGITS { $$ = $1; } - | T_ID { $$ = $1; } ; %% + +static int yyerror(void ***tsrm_ls, const char *msg) { + phpdbg_error("Parse Error: %s", msg); + + { + const phpdbg_param_t *top = PHPDBG_G(parser_stack); + + while (top) { + phpdbg_param_debug(top, "--> "); + top = top->next; + } + } + return 0; +} + +int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) { + phpdbg_init_lexer(stack, input TSRMLS_CC); + +#ifdef ZTS + return yyparse(TSRMLS_C); +#else + return yyparse(NULL); +#endif +} diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 7a28a75129..5379e77586 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -38,8 +38,6 @@ #include "phpdbg_lexer.h" #include "phpdbg_parser.h" -int yyparse(phpdbg_param_t *stack, yyscan_t scanner); - /* {{{ command declarations */ const phpdbg_command_t phpdbg_prompt_commands[] = { PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s"), @@ -248,20 +246,10 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ char *why = NULL; char *input = phpdbg_read_input(cmd TSRMLS_CC); phpdbg_param_t stack; - yyscan_t scanner; - YY_BUFFER_STATE state; phpdbg_init_param(&stack, STACK_PARAM); - - if (yylex_init(&scanner)) { - phpdbg_error( - "could not initialize scanner"); - break; - } - state = yy_scan_string(input, scanner); - - if (yyparse(&stack, scanner) <= 0) { + if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { switch (phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { case FAILURE: // if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { @@ -274,15 +262,12 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ break; } } - + if (why) { free(why); why = NULL; } - - yy_delete_buffer(state, scanner); - yylex_destroy(scanner); - + phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); } @@ -1014,20 +999,9 @@ int phpdbg_interactive(TSRMLS_D) /* {{{ */ if (input) { do { - yyscan_t scanner; - YY_BUFFER_STATE state; - phpdbg_init_param(&stack, STACK_PARAM); - if (yylex_init(&scanner)) { - phpdbg_error( - "could not initialize scanner"); - return FAILURE; - } - - state = yy_scan_string(input, scanner); - - if (yyparse(&stack, scanner) <= 0) { + if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { switch (ret = phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { case FAILURE: if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { @@ -1061,9 +1035,6 @@ int phpdbg_interactive(TSRMLS_D) /* {{{ */ why = NULL; } - yy_delete_buffer(state, scanner); - yylex_destroy(scanner); - phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); diff --git a/travis/ci.sh b/travis/ci.sh index 44d56a01ff..d9f3ac6a02 100755 --- a/travis/ci.sh +++ b/travis/ci.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh git clone https://github.com/php/php-src cd php-src/sapi +rm -rf phpdbg git clone https://github.com/krakjoe/phpdbg.git cd ../ ./buildconf --force -- cgit v1.2.1 From 79230e5561588be7e63f3ee93c06e7065e5038a9 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 15 Jun 2014 15:47:14 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- .travis.yml | 11 ++++++++++- config.m4 | 1 + phpdbg_utils.c | 9 ++++++--- phpdbg_utils.h | 20 ++++++++++++++++++++ tests/run-tests.php | 22 ++++++++++++---------- travis/ci.sh | 5 +++-- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 353402858e..d5b492e7cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,12 @@ language: c -script: ./travis/ci.sh +env: +- PHP="PHP-5.4" +- PHP="PHP-5.5" +- PHP="PHP-5.6" +- PHP="master" + +before_script: ./travis/ci.sh + +script: +- ./php-src/sapi/cli/php php-src/sapi/phpdbg/tests/run-tests.php -diff2stdout --phpdbg php-src/sapi/phpdbg/phpdbg diff --git a/config.m4 b/config.m4 index ecac171506..1a6640eaca 100644 --- a/config.m4 +++ b/config.m4 @@ -9,6 +9,7 @@ PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build, [ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) if test "$PHP_PHPDBG" != "no"; then + AC_HEADER_TIOCGWINSZ AC_DEFINE(HAVE_PHPDBG, 1, [ ]) if test "$PHP_PHPDBG_DEBUG" != "no"; then diff --git a/phpdbg_utils.c b/phpdbg_utils.c index c9b22a2039..98748b202a 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -32,6 +32,9 @@ # include "win32/time.h" #elif defined(HAVE_SYS_IOCTL_H) # include "sys/ioctl.h" +# ifndef GWINSZ_IN_SYS_IOCTL +# include +# endif #endif ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -437,12 +440,12 @@ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; -#elif defined(HAVE_SYS_IOCTL_H) +#elif defined(HAVE_SYS_IOCTL_H) && defined (TIOCGWINSZ) struct winsize w; - columns = ioctl(fileno(stdout), TIOCGWINSZ, &w) == 0 ? w.ws_col : 100; + columns = ioctl(fileno(stdout), TIOCGWINSZ, &w) == 0 ? w.ws_col : 80; #else - columns = 100; + columns = 80; #endif return columns; } /* }}} */ diff --git a/phpdbg_utils.h b/phpdbg_utils.h index 68ae7e44a3..56bacfc459 100644 --- a/phpdbg_utils.h +++ b/phpdbg_utils.h @@ -124,4 +124,24 @@ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */ int phpdbg_rebuild_symtable(TSRMLS_D); +#if PHP_VERSION_ID < 50500 +/* copy from zend_hash.c PHP 5.5 for 5.4 compatibility */ +static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) { + Bucket *p; + + p = pos ? (*pos) : ht->pInternalPointer; + + if (!p) { + Z_TYPE_P(key) = IS_NULL; + } else if (p->nKeyLength) { + Z_TYPE_P(key) = IS_STRING; + Z_STRVAL_P(key) = IS_INTERNED(p->arKey) ? (char*)p->arKey : estrndup(p->arKey, p->nKeyLength - 1); + Z_STRLEN_P(key) = p->nKeyLength - 1; + } else { + Z_TYPE_P(key) = IS_LONG; + Z_LVAL_P(key) = p->h; + } +} +#endif + #endif /* PHPDBG_UTILS_H */ diff --git a/tests/run-tests.php b/tests/run-tests.php index 47a998ccae..1cc31d815e 100644 --- a/tests/run-tests.php +++ b/tests/run-tests.php @@ -135,8 +135,8 @@ namespace phpdbg\testing { * @param array basic configuration * @param array command line */ - public function __construct(TestsConfiguration &$config) { - $this->config = &$config; + public function __construct(TestsConfiguration $config) { + $this->config = $config; if ($this->config->hasFlag('help') || $this->config->hasFlag('h')) { @@ -153,7 +153,7 @@ namespace phpdbg\testing { $paths = array(); $where = ($in != null) ? array($in) : $this->config['path']; - foreach ($where as &$path) { + foreach ($where as $path) { if ($path) { if (is_dir($path)) { $paths[] = $path; @@ -243,6 +243,7 @@ namespace phpdbg\testing { 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); @@ -266,9 +267,11 @@ namespace phpdbg\testing { $test = sprintf('%s/%s', $path, $file); if (preg_match('~\.test$~', $test)) { - yield new Test($this->config, $test); + $tests[] = new Test($this->config, $test); } } + + return $tests; } /** @@ -354,7 +357,7 @@ namespace phpdbg\testing { * @param array configuration * @param string file */ - public function __construct(TestsConfiguration &$config, &$file) { + public function __construct(TestsConfiguration $config, $file) { if (($handle = fopen($file, 'r'))) { while (($line = fgets($handle))) { $trim = trim($line); @@ -417,8 +420,8 @@ namespace phpdbg\testing { } fclose($handle); - $this->config = &$config; - $this->file = &$file; + $this->config = $config; + $this->file = $file; } } @@ -427,8 +430,7 @@ namespace phpdbg\testing { * */ public function getResult() { - $options = sprintf( - '-i%s -nqb', $this->file); + $options = sprintf('-i%s -nqb', $this->file); if ($this->options) { $options = sprintf( @@ -526,7 +528,7 @@ namespace phpdbg\testing { * Write log to disk if configuration allows it * */ - protected function writeLog(&$result = null) { + protected function writeLog($result = null) { $log = sprintf( '%s/%s.log', dirname($this->file), basename($this->file)); diff --git a/travis/ci.sh b/travis/ci.sh index d9f3ac6a02..206b158b9b 100755 --- a/travis/ci.sh +++ b/travis/ci.sh @@ -1,10 +1,11 @@ #!/usr/bin/env sh git clone https://github.com/php/php-src -cd php-src/sapi +cd php-src +git checkout $PHP +cd sapi rm -rf phpdbg git clone https://github.com/krakjoe/phpdbg.git cd ../ ./buildconf --force ./configure --disable-all --enable-phpdbg --enable-maintainer-zts make -make test-phpdbg -- cgit v1.2.1 From 55d97085a4eedb485f4aeb840091172b650adfcf Mon Sep 17 00:00:00 2001 From: Lior Kaplan Date: Mon, 16 Jun 2014 23:34:50 +0300 Subject: Update copyright year to 2014 --- phpdbg_btree.c | 2 +- phpdbg_btree.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phpdbg_btree.c b/phpdbg_btree.c index 8fc2561e04..491445399b 100644 --- a/phpdbg_btree.c +++ b/phpdbg_btree.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/phpdbg_btree.h b/phpdbg_btree.h index 5fb217db35..af2a6ac314 100644 --- a/phpdbg_btree.h +++ b/phpdbg_btree.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | -- cgit v1.2.1 From 679d08e8ba3b6e5b596f7c23c5402b2f92896db9 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Mon, 23 Jun 2014 10:04:40 +0200 Subject: Fix https://github.com/krakjoe/phpdbg/issues/91 Enable edit feature when build with libedit. Notice: coloured prompt only enable with READLINE --- config.m4 | 2 +- phpdbg.h | 2 +- phpdbg_cmd.c | 6 +++--- phpdbg_prompt.c | 5 +++++ phpdbg_utils.c | 6 +++++- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/config.m4 b/config.m4 index 1a6640eaca..d78a439af0 100644 --- a/config.m4 +++ b/config.m4 @@ -21,7 +21,7 @@ if test "$PHP_PHPDBG" != "no"; then PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE" PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c" - if test "$PHP_READLINE" != "no"; then + if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS" fi diff --git a/phpdbg.h b/phpdbg.h index 12350d5425..b2e7a03c21 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -64,7 +64,7 @@ # include "TSRM.h" #endif -#ifdef HAVE_LIBREADLINE +#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) # include # include #endif diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index d4ce8ebc55..a45513bee6 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -792,7 +792,7 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { char *cmd = NULL; -#ifndef HAVE_LIBREADLINE +#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) char buf[PHPDBG_MAX_CMD]; #endif char *buffer = NULL; @@ -811,7 +811,7 @@ disconnect: return NULL; } -#ifndef HAVE_LIBREADLINE +#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) { goto disconnect; @@ -850,7 +850,7 @@ readline: buffer = estrdup(cmd); -#ifdef HAVE_LIBREADLINE +#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { free(cmd); diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 5379e77586..d91ef3f3f5 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -732,6 +732,11 @@ PHPDBG_COMMAND(print) /* {{{ */ #else phpdbg_writeln("Readline\tno"); #endif +#ifdef HAVE_LIBEDIT + phpdbg_writeln("Libedit\t\tyes"); +#else + phpdbg_writeln("Libedit\t\tno"); +#endif phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); diff --git a/phpdbg_utils.c b/phpdbg_utils.c index 98748b202a..3b4eac7327 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -400,12 +400,16 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */ } /* create cached prompt */ +#ifdef HAVE_LIBREADLINE + /* 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 ", PHPDBG_G(colors)[PHPDBG_COLOR_PROMPT]->code, PHPDBG_G(prompt)[0]); - } else { + } else +#endif + { asprintf( &PHPDBG_G(prompt)[1], "%s ", PHPDBG_G(prompt)[0]); -- cgit v1.2.1 From 7efbccd60fda3ee235f88bbb9a1e53f6ef74f6f5 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Mon, 23 Jun 2014 10:17:43 +0200 Subject: Better fix for phpdbg + libedit - fix include - disable coloured prompt only with libedit --- phpdbg.h | 5 ++++- phpdbg_utils.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/phpdbg.h b/phpdbg.h index b2e7a03c21..eb4faf1f94 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -64,10 +64,13 @@ # include "TSRM.h" #endif -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) +#ifdef LIBREADLINE # include # include #endif +#ifdef HAVE_LIBEDIT +# include +#endif #include "phpdbg_lexer.h" #include "phpdbg_cmd.h" diff --git a/phpdbg_utils.c b/phpdbg_utils.c index 3b4eac7327..3ce2fade17 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -400,7 +400,7 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */ } /* create cached prompt */ -#ifdef HAVE_LIBREADLINE +#ifndef HAVE_LIBEDIT /* TODO: libedit doesn't seems to support coloured prompt */ if ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED)) { asprintf( -- cgit v1.2.1 From 05955fbce52918158e1fb0219c519a9a0d6f1d5b Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Wed, 25 Jun 2014 13:56:45 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- Makefile.frag | 3 +++ phpdbg.1 | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 phpdbg.1 diff --git a/Makefile.frag b/Makefile.frag index d787b0fb18..b276aaaa53 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -26,6 +26,9 @@ install-phpdbg: $(BUILD_BINARY) @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run @$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT) + @echo "Installing phpdbg man page: $(INSTALL_ROOT)$(mandir)/man1/" + @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 + @$(INSTALL_DATA) sapi/phpdbg/phpdbg.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)phpdbg$(program_suffix).1 clean-phpdbg: @echo "Cleaning phpdbg object files ..." diff --git a/phpdbg.1 b/phpdbg.1 new file mode 100644 index 0000000000..5e4d144c83 --- /dev/null +++ b/phpdbg.1 @@ -0,0 +1,59 @@ +.TH PHPDBG 1 +.SH NAME +phpdbg \- The interactive PHP debugger +.SH SYNOPSIS +.B phpdbg +[OPTION] +[\fB\-e\fIFILE\fR] +.SH DESCRIPTION +.B phpdbg +a lightweight, powerful, easy to use debugging platform for PHP5. +.SH OPTIONS +The following switches are implemented (just like cli SAPI): +.TP +.BR \-n +No \fBphp.ini\fR file will be used +.TP +.BR \-c \fIpath\fB|\fIfile\fR +Look for \fBphp.ini\fR file in the directory \fIpath\fR or use the specified \fIfile\fR +.TP +.BR \-z \fIfile\fR +Load Zend extension \fIfile\fR +.TP +.BR \-d \fIfoo\fB[=\fIbar\fB]\fR +Define INI entry \fIfoo\fR with value \fIbar\fR +.PP The following switches change the default behaviour of phpdbg: +.TP +.BR \-v +Disables quietness +.TP +.BR \-s +Enabled stepping +.TP +.BR -e \fIfile\fR +Sets execution context +.TP +.BR \-b +Disables use of colour on the console +.TP +.BR \-I +Ignore .phpdbginit (default init file) +.TP +.BR \-i \fIpath\fB|\ffile\fR +Override .phpgdbinit location (implies -I) +.TP +.BR \-O \fIfile\fR +Set oplog output to \fIfile\fR +.TP +.BR \-q +Do not print banner on startup +.TP +.BR \-r +Jump straight to run +.TP +.BR \-E +Enable step through eval() +.SH NOTES +Passing -rr will cause phpdbg to quit after execution, rather than returning to the console +.SH AUTHOR +Written by Felipe Pena, Joe Watkins and Bob Weinand, formatted by OndÅ™ej Surý for Debian project. -- cgit v1.2.1 From 856801b84f167f42d628ee5111d1bf34bb0abf1a Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 29 Jun 2014 12:49:10 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- phpdbg_help.c | 7 +- phpdbg_lexer.c | 1005 +++++++++++++++++++++++++++++++------------------------ phpdbg_lexer.l | 38 +-- phpdbg_list.c | 23 +- phpdbg_parser.c | 80 ++--- phpdbg_parser.y | 12 +- 6 files changed, 662 insertions(+), 503 deletions(-) diff --git a/phpdbg_help.c b/phpdbg_help.c index f2d074ded6..1e58dc69ca 100644 --- a/phpdbg_help.c +++ b/phpdbg_help.c @@ -318,8 +318,9 @@ phpdbg_help_text_t phpdbg_help_text[] = { "**Information**" CR " **list** list PHP source" CR " **info** displays information on the debug session" CR -" **print** show opcodes " 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 "**Starting and Stopping Execution**" CR @@ -613,7 +614,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { {"finish", "The **finish** command causes control to be passed back to the vm, continuing execution. Any " "breakpoints that are encountered within the current stack frame will be skipped. Execution " -"will then continue until the next breakpoint after leaving the stack frame or unitil " +"will then continue until the next breakpoint after leaving the stack frame or until " "completion of the script" CR CR "Note when **step**ping is enabled, any opcode steps within the current stack frame are also " @@ -629,7 +630,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { "**Examples**" CR CR " $P frame 2" CR -" $P E $count" CR +" $P ev $count" CR " 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 " diff --git a/phpdbg_lexer.c b/phpdbg_lexer.c index 420dcac042..3092dc396d 100644 --- a/phpdbg_lexer.c +++ b/phpdbg_lexer.c @@ -96,33 +96,49 @@ yyc_INITIAL: }; YYDEBUG(0, *YYCURSOR); - YYFILL(3); + YYFILL(4); yych = *YYCURSOR; - if (yych <= 0x1F) { - if (yych <= '\t') { + if (yych <= 'D') { + if (yych <= '\n') { if (yych <= 0x00) goto yy6; if (yych <= 0x08) goto yy11; + if (yych >= '\n') goto yy4; } else { - if (yych <= '\n') goto yy4; - if (yych != '\r') goto yy11; + if (yych <= '\r') { + if (yych <= '\f') goto yy11; + } else { + if (yych != ' ') goto yy11; + } } } else { - if (yych <= 'e') { - if (yych <= ' ') goto yy2; - if (yych <= 'd') goto yy11; - goto yy7; + if (yych <= 'd') { + if (yych <= 'Q') { + if (yych <= 'E') goto yy7; + goto yy11; + } else { + if (yych <= 'R') goto yy10; + if (yych <= 'S') goto yy8; + goto yy11; + } } else { - if (yych <= 'q') goto yy11; - if (yych <= 'r') goto yy9; - if (yych <= 's') goto yy8; - goto yy11; + if (yych <= 'q') { + if (yych <= 'e') goto yy7; + goto yy11; + } else { + if (yych <= 'r') goto yy9; + if (yych <= 's') goto yy8; + goto yy11; + } } } -yy2: YYDEBUG(2, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy19; + if ((yych = *YYCURSOR) <= '\f') { + if (yych <= 0x08) goto yy3; + if (yych <= '\n') goto yy26; + } else { + if (yych <= '\r') goto yy26; + if (yych == ' ') goto yy26; } yy3: YYDEBUG(3, *YYCURSOR); @@ -134,49 +150,60 @@ yy3: YYCURSOR = LEX(text); goto restart; } -#line 138 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 154 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy19; + if ((yych = *YYCURSOR) <= '\f') { + if (yych <= 0x08) goto yy5; + if (yych <= '\n') goto yy26; + } else { + if (yych <= '\r') goto yy26; + if (yych == ' ') goto yy26; } +yy5: YYDEBUG(5, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 151 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 172 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" yy6: YYDEBUG(6, *YYCURSOR); yych = *++YYCURSOR; goto yy3; yy7: YYDEBUG(7, *YYCURSOR); - yych = *++YYCURSOR; - if (yych == 'v') goto yy17; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'V') goto yy22; + if (yych == 'v') goto yy22; goto yy3; yy8: YYDEBUG(8, *YYCURSOR); - yych = *++YYCURSOR; - if (yych == 'h') goto yy15; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'H') goto yy18; + if (yych == 'h') goto yy18; goto yy3; yy9: YYDEBUG(9, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy15; + } + if (yych == 'U') goto yy12; if (yych == 'u') goto yy12; + goto yy3; yy10: YYDEBUG(10, *YYCURSOR); - yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 155 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" - { - YYSETCONDITION(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_RUN; -} -#line 180 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy12; + if (yych == 'u') goto yy12; + goto yy3; yy11: YYDEBUG(11, *YYCURSOR); yych = *++YYCURSOR; @@ -184,18 +211,62 @@ yy11: yy12: YYDEBUG(12, *YYCURSOR); yych = *++YYCURSOR; + if (yych == 'N') goto yy14; if (yych == 'n') goto yy14; +yy13: YYDEBUG(13, *YYCURSOR); YYCURSOR = YYMARKER; - goto yy10; + goto yy3; yy14: YYDEBUG(14, *YYCURSOR); yych = *++YYCURSOR; - goto yy10; + if (yybm[0+yych] & 128) { + goto yy15; + } + goto yy13; yy15: YYDEBUG(15, *YYCURSOR); ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; YYDEBUG(16, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy15; + } + YYDEBUG(17, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 155 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_RUN; +} +#line 245 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy18: + YYDEBUG(18, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '\f') { + if (yych <= 0x08) goto yy13; + if (yych >= '\v') goto yy13; + } else { + if (yych <= '\r') goto yy19; + if (yych != ' ') goto yy13; + } +yy19: + YYDEBUG(19, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(20, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy21; + if (yych <= '\n') goto yy19; + } else { + if (yych <= '\r') goto yy19; + if (yych == ' ') goto yy19; + } +yy21: + YYDEBUG(21, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 150 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -203,11 +274,32 @@ yy15: phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } -#line 207 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy17: - YYDEBUG(17, *YYCURSOR); +#line 278 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy22: + YYDEBUG(22, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '\f') { + if (yych <= 0x08) goto yy13; + if (yych >= '\v') goto yy13; + } else { + if (yych <= '\r') goto yy23; + if (yych != ' ') goto yy13; + } +yy23: + YYDEBUG(23, *YYCURSOR); ++YYCURSOR; - YYDEBUG(18, *YYCURSOR); + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(24, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy25; + if (yych <= '\n') goto yy23; + } else { + if (yych <= '\r') goto yy23; + if (yych == ' ') goto yy23; + } +yy25: + YYDEBUG(25, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 145 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -215,17 +307,22 @@ yy17: phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } -#line 219 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy19: - YYDEBUG(19, *YYCURSOR); +#line 311 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy26: + YYDEBUG(26, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(20, *YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy19; + YYDEBUG(27, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy28; + if (yych <= '\n') goto yy26; + } else { + if (yych <= '\r') goto yy26; + if (yych == ' ') goto yy26; } - YYDEBUG(21, *YYCURSOR); +yy28: + YYDEBUG(28, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -233,7 +330,7 @@ yy19: goto restart; } -#line 237 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 334 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } /* *********************************** */ yyc_NORMAL: @@ -272,71 +369,60 @@ yyc_NORMAL: 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, }; - YYDEBUG(22, *YYCURSOR); + YYDEBUG(29, *YYCURSOR); YYFILL(11); yych = *YYCURSOR; - if (yych <= ':') { - if (yych <= ' ') { - if (yych <= '\n') { - if (yych <= 0x00) goto yy29; - if (yych <= 0x08) goto yy32; - if (yych >= '\n') goto yy27; - } else { - if (yych == '\r') goto yy24; - if (yych <= 0x1F) goto yy32; - } - } else { - if (yych <= '.') { - if (yych == '#') goto yy47; - if (yych <= '-') goto yy32; - goto yy34; - } else { - if (yych <= '/') goto yy32; - if (yych <= '0') goto yy37; - if (yych <= '9') goto yy34; - goto yy49; - } - } - } else { - if (yych <= 'i') { - if (yych <= 'd') { - if (yych == 'Z') goto yy38; - if (yych <= 'c') goto yy32; - goto yy39; - } else { - if (yych <= 'e') goto yy40; - if (yych <= 'f') goto yy41; - if (yych <= 'h') goto yy32; - goto yy30; - } - } else { - if (yych <= 's') { - if (yych <= 'm') goto yy32; - if (yych <= 'n') goto yy42; - if (yych <= 'o') goto yy43; - goto yy32; - } else { - if (yych <= 'x') { - if (yych <= 't') goto yy44; - goto yy32; - } else { - if (yych <= 'y') goto yy45; - if (yych <= 'z') goto yy46; - goto yy32; - } - } - } + YYDEBUG(-1, yych); + switch (yych) { + case 0x00: goto yy36; + case '\t': + case '\r': + case ' ': goto yy31; + case '\n': goto yy34; + case '#': goto yy55; + case '-': goto yy41; + case '.': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy42; + case '0': goto yy45; + case ':': goto yy57; + case 'D': + case 'd': goto yy46; + case 'E': + case 'e': goto yy47; + case 'F': + case 'f': goto yy48; + case 'I': + case 'i': goto yy37; + case 'N': + case 'n': goto yy49; + case 'O': + case 'o': goto yy50; + case 'T': + case 't': goto yy51; + case 'Y': + case 'y': goto yy52; + case 'Z': goto yy53; + case 'z': goto yy54; + default: goto yy39; } -yy24: - YYDEBUG(24, *YYCURSOR); +yy31: + YYDEBUG(31, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(25, *YYCURSOR); + YYDEBUG(32, *YYCURSOR); if (yybm[0+yych] & 8) { - goto yy24; + goto yy31; } - YYDEBUG(26, *YYCURSOR); + YYDEBUG(33, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -344,33 +430,34 @@ yy24: goto restart; } -#line 348 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy27: - YYDEBUG(27, *YYCURSOR); +#line 434 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy34: + YYDEBUG(34, *YYCURSOR); ++YYCURSOR; if (yybm[0+(yych = *YYCURSOR)] & 8) { - goto yy24; + goto yy31; } -yy28: - YYDEBUG(28, *YYCURSOR); +yy35: + YYDEBUG(35, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 362 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy29: - YYDEBUG(29, *YYCURSOR); +#line 448 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy36: + YYDEBUG(36, *YYCURSOR); yych = *++YYCURSOR; - goto yy28; -yy30: - YYDEBUG(30, *YYCURSOR); + goto yy35; +yy37: + YYDEBUG(37, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'f') goto yy94; - goto yy33; -yy31: - YYDEBUG(31, *YYCURSOR); + if (yych == 'F') goto yy106; + if (yych == 'f') goto yy106; + goto yy40; +yy38: + YYDEBUG(38, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -379,48 +466,56 @@ yy31: yylval->len = yyleng; return T_ID; } -#line 383 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy32: - YYDEBUG(32, *YYCURSOR); +#line 470 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy39: + YYDEBUG(39, *YYCURSOR); yyaccept = 0; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; -yy33: - YYDEBUG(33, *YYCURSOR); +yy40: + YYDEBUG(40, *YYCURSOR); if (yybm[0+yych] & 16) { - goto yy32; + goto yy39; } - if (yych <= '9') goto yy31; - goto yy54; -yy34: - YYDEBUG(34, *YYCURSOR); + if (yych <= '9') goto yy38; + goto yy62; +yy41: + YYDEBUG(41, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy42; + } + goto yy40; +yy42: + YYDEBUG(42, *YYCURSOR); yyaccept = 1; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(35, *YYCURSOR); + YYDEBUG(43, *YYCURSOR); if (yybm[0+yych] & 32) { - goto yy34; + goto yy42; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy36; - if (yych <= 0x08) goto yy32; + if (yych <= 0x00) goto yy44; + if (yych <= 0x08) goto yy39; } else { - if (yych != '\r') goto yy32; + if (yych != '\r') goto yy39; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy36; - if (yych <= '"') goto yy32; + if (yych <= ' ') goto yy44; + if (yych <= '"') goto yy39; } else { - if (yych == ':') goto yy54; - goto yy32; + if (yych == ':') goto yy62; + goto yy39; } } -yy36: - YYDEBUG(36, *YYCURSOR); +yy44: + YYDEBUG(44, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 106 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -428,164 +523,168 @@ yy36: yylval->num = atoi(yytext); return T_DIGITS; } -#line 432 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy37: - YYDEBUG(37, *YYCURSOR); +#line 527 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy45: + YYDEBUG(45, *YYCURSOR); yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 32) { - goto yy34; + goto yy42; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy36; - if (yych <= 0x08) goto yy33; - goto yy36; + if (yych <= 0x00) goto yy44; + if (yych <= 0x08) goto yy40; + goto yy44; } else { - if (yych == '\r') goto yy36; - goto yy33; + if (yych == '\r') goto yy44; + goto yy40; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy36; - if (yych <= '"') goto yy33; - goto yy36; + if (yych <= ' ') goto yy44; + if (yych <= '"') goto yy40; + goto yy44; } else { - if (yych == 'x') goto yy90; - goto yy33; + if (yych == 'x') goto yy102; + goto yy40; } } -yy38: - YYDEBUG(38, *YYCURSOR); +yy46: + YYDEBUG(46, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy87; - goto yy33; -yy39: - YYDEBUG(39, *YYCURSOR); + if (yych == 'I') goto yy96; + if (yych == 'i') goto yy96; + goto yy40; +yy47: + YYDEBUG(47, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'i') goto yy81; - goto yy33; -yy40: - YYDEBUG(40, *YYCURSOR); + if (yych == 'N') goto yy91; + if (yych == 'n') goto yy91; + goto yy40; +yy48: + YYDEBUG(48, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'n') goto yy76; - goto yy33; -yy41: - YYDEBUG(41, *YYCURSOR); + if (yych == 'A') goto yy88; + if (yych == 'a') goto yy88; + goto yy40; +yy49: + YYDEBUG(49, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'a') goto yy73; - goto yy33; -yy42: - YYDEBUG(42, *YYCURSOR); + if (yych == 'O') goto yy84; + if (yych == 'o') goto yy84; + goto yy40; +yy50: + YYDEBUG(50, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'o') goto yy71; - goto yy33; -yy43: - YYDEBUG(43, *YYCURSOR); + if (yych <= 'N') { + if (yych == 'F') goto yy83; + if (yych <= 'M') goto yy40; + goto yy77; + } else { + if (yych <= 'f') { + if (yych <= 'e') goto yy40; + goto yy83; + } else { + if (yych == 'n') goto yy77; + goto yy40; + } + } +yy51: + YYDEBUG(51, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'f') goto yy70; - if (yych == 'n') goto yy66; - goto yy33; -yy44: - YYDEBUG(44, *YYCURSOR); + if (yych == 'R') goto yy81; + if (yych == 'r') goto yy81; + goto yy40; +yy52: + YYDEBUG(52, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'r') goto yy68; - goto yy33; -yy45: - YYDEBUG(45, *YYCURSOR); + if (yych == 'E') goto yy76; + if (yych == 'e') goto yy76; + goto yy40; +yy53: + YYDEBUG(53, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy65; - goto yy33; -yy46: - YYDEBUG(46, *YYCURSOR); + if (yych == 'E') goto yy73; + goto yy40; +yy54: + YYDEBUG(54, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy53; - goto yy33; -yy47: - YYDEBUG(47, *YYCURSOR); + if (yych == 'e') goto yy61; + goto yy40; +yy55: + YYDEBUG(55, *YYCURSOR); ++YYCURSOR; - YYDEBUG(48, *YYCURSOR); + YYDEBUG(56, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 84 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return T_POUND; } -#line 523 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy49: - YYDEBUG(49, *YYCURSOR); +#line 634 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy57: + YYDEBUG(57, *YYCURSOR); ++YYCURSOR; - if ((yych = *YYCURSOR) == ':') goto yy51; - YYDEBUG(50, *YYCURSOR); + if ((yych = *YYCURSOR) == ':') goto yy59; + YYDEBUG(58, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 90 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return T_COLON; } -#line 534 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy51: - YYDEBUG(51, *YYCURSOR); +#line 645 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy59: + YYDEBUG(59, *YYCURSOR); ++YYCURSOR; - YYDEBUG(52, *YYCURSOR); + YYDEBUG(60, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return T_DCOLON; } -#line 544 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy53: - YYDEBUG(53, *YYCURSOR); +#line 655 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy61: + YYDEBUG(61, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'n') goto yy59; - goto yy33; -yy54: - YYDEBUG(54, *YYCURSOR); + if (yych == 'n') goto yy67; + goto yy40; +yy62: + YYDEBUG(62, *YYCURSOR); yych = *++YYCURSOR; - if (yych == '/') goto yy56; -yy55: - YYDEBUG(55, *YYCURSOR); + if (yych == '/') goto yy64; +yy63: + YYDEBUG(63, *YYCURSOR); YYCURSOR = YYMARKER; - if (yyaccept <= 3) { - if (yyaccept <= 1) { - if (yyaccept <= 0) { - goto yy31; - } else { - goto yy36; - } + if (yyaccept <= 1) { + if (yyaccept <= 0) { + goto yy38; } else { - if (yyaccept <= 2) { - goto yy64; - } else { - goto yy67; - } + goto yy44; } } else { - if (yyaccept <= 5) { - if (yyaccept <= 4) { - goto yy72; - } else { - goto yy93; - } + if (yyaccept <= 2) { + goto yy72; } else { - goto yy95; + goto yy105; } } -yy56: - YYDEBUG(56, *YYCURSOR); +yy64: + YYDEBUG(64, *YYCURSOR); yych = *++YYCURSOR; - if (yych != '/') goto yy55; - YYDEBUG(57, *YYCURSOR); + if (yych != '/') goto yy63; + YYDEBUG(65, *YYCURSOR); ++YYCURSOR; - YYDEBUG(58, *YYCURSOR); + YYDEBUG(66, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 78 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -594,52 +693,52 @@ yy56: yylval->len = yyleng; return T_PROTO; } -#line 598 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy59: - YYDEBUG(59, *YYCURSOR); +#line 697 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy67: + YYDEBUG(67, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'd') goto yy33; - YYDEBUG(60, *YYCURSOR); + if (yych != 'd') goto yy40; + YYDEBUG(68, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != '_') goto yy33; -yy61: - YYDEBUG(61, *YYCURSOR); + if (yych != '_') goto yy40; +yy69: + YYDEBUG(69, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 64) { - goto yy62; + goto yy70; } - goto yy33; -yy62: - YYDEBUG(62, *YYCURSOR); + goto yy40; +yy70: + YYDEBUG(70, *YYCURSOR); yyaccept = 2; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(63, *YYCURSOR); + YYDEBUG(71, *YYCURSOR); if (yybm[0+yych] & 64) { - goto yy62; + goto yy70; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy64; - if (yych <= 0x08) goto yy32; + if (yych <= 0x00) goto yy72; + if (yych <= 0x08) goto yy39; } else { - if (yych != '\r') goto yy32; + if (yych != '\r') goto yy39; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy64; - if (yych <= '"') goto yy32; + if (yych <= ' ') goto yy72; + if (yych <= '"') goto yy39; } else { - if (yych == ':') goto yy54; - goto yy32; + if (yych == ':') goto yy62; + goto yy39; } } -yy64: - YYDEBUG(64, *YYCURSOR); +yy72: + YYDEBUG(72, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -648,32 +747,53 @@ yy64: yylval->len = yyleng; return T_OPCODE; } -#line 652 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy65: - YYDEBUG(65, *YYCURSOR); +#line 751 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy73: + YYDEBUG(73, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 's') goto yy33; -yy66: - YYDEBUG(66, *YYCURSOR); - yyaccept = 3; + if (yych != 'N') goto yy40; + YYDEBUG(74, *YYCURSOR); + yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\r') { - if (yych <= 0x08) { - if (yych >= 0x01) goto yy33; - } else { - if (yych <= '\n') goto yy67; - if (yych <= '\f') goto yy33; - } + if (yych != 'D') goto yy40; + YYDEBUG(75, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '_') goto yy69; + goto yy40; +yy76: + YYDEBUG(76, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'S') goto yy77; + if (yych != 's') goto yy40; +yy77: + YYDEBUG(77, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy40; + if (yych >= '\v') goto yy40; } else { - if (yych <= ' ') { - if (yych <= 0x1F) goto yy33; - } else { - if (yych != '#') goto yy33; - } + if (yych <= '\r') goto yy78; + if (yych != ' ') goto yy40; } -yy67: - YYDEBUG(67, *YYCURSOR); +yy78: + YYDEBUG(78, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(79, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy80; + if (yych <= '\n') goto yy78; + } else { + if (yych <= '\r') goto yy78; + if (yych == ' ') goto yy78; + } +yy80: + YYDEBUG(80, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 94 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -681,42 +801,52 @@ yy67: yylval->num = 1; return T_TRUTHY; } -#line 685 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy68: - YYDEBUG(68, *YYCURSOR); +#line 805 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy81: + YYDEBUG(81, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'u') goto yy33; - YYDEBUG(69, *YYCURSOR); + if (yych == 'U') goto yy82; + if (yych != 'u') goto yy40; +yy82: + YYDEBUG(82, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy66; - goto yy33; -yy70: - YYDEBUG(70, *YYCURSOR); + if (yych == 'E') goto yy77; + if (yych == 'e') goto yy77; + goto yy40; +yy83: + YYDEBUG(83, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'f') goto yy33; -yy71: - YYDEBUG(71, *YYCURSOR); - yyaccept = 4; + if (yych == 'F') goto yy84; + if (yych != 'f') goto yy40; +yy84: + YYDEBUG(84, *YYCURSOR); + yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\r') { - if (yych <= 0x08) { - if (yych >= 0x01) goto yy33; - } else { - if (yych <= '\n') goto yy72; - if (yych <= '\f') goto yy33; - } + if (yych <= '\f') { + if (yych <= 0x08) goto yy40; + if (yych >= '\v') goto yy40; } else { - if (yych <= ' ') { - if (yych <= 0x1F) goto yy33; - } else { - if (yych != '#') goto yy33; - } + if (yych <= '\r') goto yy85; + if (yych != ' ') goto yy40; } -yy72: - YYDEBUG(72, *YYCURSOR); +yy85: + YYDEBUG(85, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(86, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy87; + if (yych <= '\n') goto yy85; + } else { + if (yych <= '\r') goto yy85; + if (yych == ' ') goto yy85; + } +yy87: + YYDEBUG(87, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 100 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -724,119 +854,130 @@ yy72: yylval->num = 0; return T_FALSY; } -#line 728 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy73: - YYDEBUG(73, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'l') goto yy33; - YYDEBUG(74, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych != 's') goto yy33; - YYDEBUG(75, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy71; - goto yy33; -yy76: - YYDEBUG(76, *YYCURSOR); +#line 858 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy88: + YYDEBUG(88, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'a') goto yy33; - YYDEBUG(77, *YYCURSOR); + if (yych == 'L') goto yy89; + if (yych != 'l') goto yy40; +yy89: + YYDEBUG(89, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'b') goto yy33; - YYDEBUG(78, *YYCURSOR); + if (yych == 'S') goto yy90; + if (yych != 's') goto yy40; +yy90: + YYDEBUG(90, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'l') goto yy33; - YYDEBUG(79, *YYCURSOR); + if (yych == 'E') goto yy84; + if (yych == 'e') goto yy84; + goto yy40; +yy91: + YYDEBUG(91, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'e') goto yy33; - YYDEBUG(80, *YYCURSOR); + if (yych == 'A') goto yy92; + if (yych != 'a') goto yy40; +yy92: + YYDEBUG(92, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'd') goto yy66; - goto yy33; -yy81: - YYDEBUG(81, *YYCURSOR); + if (yych == 'B') goto yy93; + if (yych != 'b') goto yy40; +yy93: + YYDEBUG(93, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 's') goto yy33; - YYDEBUG(82, *YYCURSOR); + if (yych == 'L') goto yy94; + if (yych != 'l') goto yy40; +yy94: + YYDEBUG(94, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'a') goto yy33; - YYDEBUG(83, *YYCURSOR); + if (yych == 'E') goto yy95; + if (yych != 'e') goto yy40; +yy95: + YYDEBUG(95, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'b') goto yy33; - YYDEBUG(84, *YYCURSOR); + if (yych == 'D') goto yy77; + if (yych == 'd') goto yy77; + goto yy40; +yy96: + YYDEBUG(96, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'l') goto yy33; - YYDEBUG(85, *YYCURSOR); + if (yych == 'S') goto yy97; + if (yych != 's') goto yy40; +yy97: + YYDEBUG(97, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'e') goto yy33; - YYDEBUG(86, *YYCURSOR); + if (yych == 'A') goto yy98; + if (yych != 'a') goto yy40; +yy98: + YYDEBUG(98, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'd') goto yy71; - goto yy33; -yy87: - YYDEBUG(87, *YYCURSOR); + if (yych == 'B') goto yy99; + if (yych != 'b') goto yy40; +yy99: + YYDEBUG(99, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'N') goto yy33; - YYDEBUG(88, *YYCURSOR); + if (yych == 'L') goto yy100; + if (yych != 'l') goto yy40; +yy100: + YYDEBUG(100, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'D') goto yy33; - YYDEBUG(89, *YYCURSOR); + if (yych == 'E') goto yy101; + if (yych != 'e') goto yy40; +yy101: + YYDEBUG(101, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == '_') goto yy61; - goto yy33; -yy90: - YYDEBUG(90, *YYCURSOR); + if (yych == 'D') goto yy84; + if (yych == 'd') goto yy84; + goto yy40; +yy102: + YYDEBUG(102, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 128) { - goto yy91; + goto yy103; } - goto yy33; -yy91: - YYDEBUG(91, *YYCURSOR); - yyaccept = 5; + goto yy40; +yy103: + YYDEBUG(103, *YYCURSOR); + yyaccept = 3; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(92, *YYCURSOR); + YYDEBUG(104, *YYCURSOR); if (yybm[0+yych] & 128) { - goto yy91; + goto yy103; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy93; - if (yych <= 0x08) goto yy32; + if (yych <= 0x00) goto yy105; + if (yych <= 0x08) goto yy39; } else { - if (yych != '\r') goto yy32; + if (yych != '\r') goto yy39; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy93; - if (yych <= '"') goto yy32; + if (yych <= ' ') goto yy105; + if (yych <= '"') goto yy39; } else { - if (yych == ':') goto yy54; - goto yy32; + if (yych == ':') goto yy62; + goto yy39; } } -yy93: - YYDEBUG(93, *YYCURSOR); +yy105: + YYDEBUG(105, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -844,27 +985,33 @@ yy93: yylval->addr = strtoul(yytext, 0, 16); return T_ADDR; } -#line 848 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy94: - YYDEBUG(94, *YYCURSOR); - yyaccept = 6; +#line 989 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy106: + YYDEBUG(106, *YYCURSOR); + yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\r') { - if (yych <= 0x08) { - if (yych >= 0x01) goto yy33; - } else { - if (yych <= '\n') goto yy95; - if (yych <= '\f') goto yy33; - } + if (yych <= '\f') { + if (yych <= 0x08) goto yy40; + if (yych >= '\v') goto yy40; } else { - if (yych <= ' ') { - if (yych <= 0x1F) goto yy33; - } else { - if (yych != '#') goto yy33; - } + if (yych <= '\r') goto yy107; + if (yych != ' ') goto yy40; } -yy95: - YYDEBUG(95, *YYCURSOR); +yy107: + YYDEBUG(107, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(108, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy109; + if (yych <= '\n') goto yy107; + } else { + if (yych <= '\r') goto yy107; + if (yych == ' ') goto yy107; + } +yy109: + YYDEBUG(109, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -872,7 +1019,7 @@ yy95: phpdbg_init_param(yylval, EMPTY_PARAM); return T_IF; } -#line 876 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1023 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } /* *********************************** */ yyc_RAW: @@ -911,29 +1058,29 @@ yyc_RAW: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, }; - YYDEBUG(96, *YYCURSOR); + YYDEBUG(110, *YYCURSOR); YYFILL(2); yych = *YYCURSOR; if (yybm[0+yych] & 32) { - goto yy98; + goto yy112; } - if (yych <= 0x00) goto yy103; - if (yych == '\n') goto yy101; - goto yy104; -yy98: - YYDEBUG(98, *YYCURSOR); + if (yych <= 0x00) goto yy117; + if (yych == '\n') goto yy115; + goto yy118; +yy112: + YYDEBUG(112, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(99, *YYCURSOR); + YYDEBUG(113, *YYCURSOR); if (yybm[0+yych] & 32) { - goto yy98; + goto yy112; } - if (yych <= 0x00) goto yy100; - if (yych == '\n') goto yy106; - goto yy104; -yy100: - YYDEBUG(100, *YYCURSOR); + if (yych <= 0x00) goto yy114; + if (yych == '\n') goto yy120; + goto yy118; +yy114: + YYDEBUG(114, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -942,45 +1089,45 @@ yy100: yylval->len = yyleng; return T_INPUT; } -#line 946 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy101: - YYDEBUG(101, *YYCURSOR); +#line 1093 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy115: + YYDEBUG(115, *YYCURSOR); ++YYCURSOR; if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy106; + goto yy120; } -yy102: - YYDEBUG(102, *YYCURSOR); +yy116: + YYDEBUG(116, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 960 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy103: - YYDEBUG(103, *YYCURSOR); +#line 1107 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy117: + YYDEBUG(117, *YYCURSOR); yych = *++YYCURSOR; - goto yy102; -yy104: - YYDEBUG(104, *YYCURSOR); + goto yy116; +yy118: + YYDEBUG(118, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(105, *YYCURSOR); + YYDEBUG(119, *YYCURSOR); if (yybm[0+yych] & 64) { - goto yy104; + goto yy118; } - goto yy100; -yy106: - YYDEBUG(106, *YYCURSOR); + goto yy114; +yy120: + YYDEBUG(120, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(107, *YYCURSOR); + YYDEBUG(121, *YYCURSOR); if (yybm[0+yych] & 128) { - goto yy106; + goto yy120; } - YYDEBUG(108, *YYCURSOR); + YYDEBUG(122, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -988,7 +1135,7 @@ yy106: goto restart; } -#line 992 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } } #line 168 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" diff --git a/phpdbg_lexer.l b/phpdbg_lexer.l index 4d9c837f1e..7b3ce38c47 100644 --- a/phpdbg_lexer.l +++ b/phpdbg_lexer.l @@ -43,21 +43,21 @@ restart: /*!re2c re2c:yyfill:check = 0; -T_TRUE "true" -T_YES "yes" -T_ON "on" -T_ENABLED "enabled" -T_FALSE "false" -T_NO "no" -T_OFF "off" -T_DISABLED "disabled" -T_EVAL "ev" -T_SHELL "sh" -T_IF "if" -T_RUN "run" +T_TRUE 'true' +T_YES 'yes' +T_ON 'on' +T_ENABLED 'enabled' +T_FALSE 'false' +T_NO 'no' +T_OFF 'off' +T_DISABLED 'disabled' +T_EVAL 'ev' +T_SHELL 'sh' +T_IF 'if' +T_RUN 'run' T_RUN_SHORT "r" WS [ \r\n\t]+ -DIGITS [0-9\.]+ +DIGITS [-]?[0-9\.]+ ID [^ \r\n\t:#\000]+ ADDR [0][x][a-fA-F0-9]+ OPCODE (ZEND_|zend_)([A-Za-z])+ @@ -69,7 +69,7 @@ INPUT [^\n\000]+ return 0; } -{T_IF} { +{T_IF}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_IF; @@ -91,13 +91,13 @@ INPUT [^\n\000]+ return T_COLON; } -{T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE} { +({T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE}){WS} { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 1; return T_TRUTHY; } -{T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE} { +({T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE}){WS} { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 0; return T_FALSY; @@ -142,17 +142,17 @@ INPUT [^\n\000]+ goto restart; } -{T_EVAL} { +{T_EVAL}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } -{T_SHELL} { +{T_SHELL}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } -{T_RUN}|{T_RUN_SHORT} { +({T_RUN}|{T_RUN_SHORT}){WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_RUN; diff --git a/phpdbg_list.c b/phpdbg_list.c index 037c6c38b2..e8db4e605c 100644 --- a/phpdbg_list.c +++ b/phpdbg_list.c @@ -130,14 +130,14 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig char *opened = NULL; char buffer[8096] = {0,}; long line = 0; - + php_stream *stream = NULL; if (VCWD_STAT(filename, &st) == FAILURE) { phpdbg_error("Failed to stat file %s", filename); return; } - + stream = php_stream_open_wrapper(filename, "rb", USE_PATH, &opened); if (!stream) { @@ -145,11 +145,17 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig return; } + if (offset < 0) { + count += offset; + offset = 0; + } + while (php_stream_gets(stream, buffer, sizeof(buffer)) != NULL) { + long linelen = strlen(buffer); + ++line; - if (!offset || offset <= line) { - /* Without offset, or offset reached */ + if (offset <= line) { if (!highlight) { phpdbg_write("%05ld: %s", line, buffer); } else { @@ -159,10 +165,15 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig phpdbg_write(">%05ld: %s", line, buffer); } } + + if (buffer[linelen - 1] != '\n') { + phpdbg_write("\n"); + } } - - if ((count + (offset-1)) == line) + + if (count > 0 && count + offset - 1 < line) { break; + } } php_stream_close(stream); diff --git a/phpdbg_parser.c b/phpdbg_parser.c index f9a3e4d299..e34c2f48ff 100644 --- a/phpdbg_parser.c +++ b/phpdbg_parser.c @@ -436,7 +436,7 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 25 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 41 +#define YYLAST 42 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 21 @@ -493,8 +493,8 @@ static const yytype_uint8 yytranslate[] = static const yytype_uint8 yyprhs[] = { 0, 0, 3, 5, 7, 8, 10, 13, 17, 22, - 27, 33, 37, 43, 47, 49, 51, 53, 55, 57, - 59, 61, 64, 67, 70, 72 + 27, 33, 37, 43, 47, 50, 52, 54, 56, 58, + 60, 62, 64, 67, 70, 72 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ @@ -504,9 +504,9 @@ static const yytype_int8 yyrhs[] = 23, 24, -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, 17, -1, 16, - -1, 15, -1, 7, -1, 8, -1, 14, -1, 18, - -1, 6, 19, -1, 3, 19, -1, 5, 19, -1, + 12, 14, -1, 18, 12, 14, -1, 6, 19, -1, + 17, -1, 16, -1, 15, -1, 7, -1, 8, -1, + 14, -1, 18, -1, 3, 19, -1, 5, 19, -1, 4, -1, 4, 19, -1 }; @@ -514,8 +514,8 @@ static const yytype_int8 yyrhs[] = static const yytype_uint8 yyrline[] = { 0, 66, 66, 67, 68, 72, 73, 77, 82, 87, - 97, 107, 112, 118, 124, 125, 126, 127, 128, 129, - 130, 134, 139, 144, 149, 153 + 97, 107, 112, 118, 124, 129, 130, 131, 132, 133, + 134, 135, 139, 144, 149, 153 }; #endif @@ -552,15 +552,15 @@ static const yytype_uint8 yyr1[] = { 0, 21, 22, 22, 22, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 25, 25, 25, 25, 25 + 24, 24, 25, 25, 25, 25 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 0, 1, 2, 3, 4, 4, - 5, 3, 5, 3, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 1, 2 + 5, 3, 5, 3, 2, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 1, 2 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. @@ -568,9 +568,9 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 4, 0, 24, 0, 0, 17, 18, 0, 19, 16, - 15, 14, 20, 0, 2, 5, 3, 22, 25, 23, - 21, 0, 0, 0, 0, 1, 6, 0, 0, 7, + 4, 0, 24, 0, 0, 18, 19, 0, 20, 17, + 16, 15, 21, 0, 2, 5, 3, 22, 25, 23, + 14, 0, 0, 0, 0, 1, 6, 0, 0, 7, 11, 13, 0, 9, 8, 0, 10, 12 }; @@ -585,16 +585,16 @@ static const yytype_int8 yydefgoto[] = #define YYPACT_NINF -11 static const yytype_int8 yypact[] = { - -3, -10, 10, 11, 12, -11, -11, 14, -11, -11, - -11, -11, -4, 28, 9, -11, -11, -11, -11, -11, - -11, 23, 6, 16, 21, -11, -11, 7, 22, -11, - 25, -11, 24, -11, -11, 26, -11, -11 + -3, -10, 11, 12, 13, -11, -11, 15, -11, -11, + -11, -11, -4, 29, 10, -11, -11, -11, -11, -11, + -11, 24, 7, 17, 22, -11, -11, 8, 23, -11, + 26, -11, 25, -11, -11, 27, -11, -11 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -11, -11, -11, 27, -11 + -11, -11, -11, 28, -11 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -604,10 +604,10 @@ static const yytype_int8 yypgoto[] = static const yytype_uint8 yytable[] = { 1, 2, 3, 4, 5, 6, 22, 23, 24, 17, - 7, 8, 9, 10, 11, 12, 5, 6, 28, 32, - 29, 33, 7, 8, 9, 10, 11, 12, 25, 18, - 19, 20, 21, 27, 30, 31, 34, 35, 36, 0, - 37, 26 + 7, 8, 9, 10, 11, 12, 4, 5, 6, 28, + 32, 29, 33, 7, 8, 9, 10, 11, 12, 25, + 18, 19, 20, 21, 27, 30, 31, 34, 35, 36, + 0, 37, 26 }; #define yypact_value_is_default(yystate) \ @@ -619,10 +619,10 @@ static const yytype_uint8 yytable[] = static const yytype_int8 yycheck[] = { 3, 4, 5, 6, 7, 8, 10, 11, 12, 19, - 13, 14, 15, 16, 17, 18, 7, 8, 12, 12, - 14, 14, 13, 14, 15, 16, 17, 18, 0, 19, - 19, 19, 18, 10, 18, 14, 14, 12, 14, -1, - 14, 14 + 13, 14, 15, 16, 17, 18, 6, 7, 8, 12, + 12, 14, 14, 13, 14, 15, 16, 17, 18, 0, + 19, 19, 19, 18, 10, 18, 14, 14, 12, 14, + -1, 14, 14 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -1563,53 +1563,53 @@ yyreduce: case 14: /* Line 1802 of yacc.c */ #line 124 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } + { + (yyval).type = COND_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } break; case 15: /* Line 1802 of yacc.c */ -#line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 16: /* Line 1802 of yacc.c */ -#line 126 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 17: /* Line 1802 of yacc.c */ -#line 127 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 131 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 18: /* Line 1802 of yacc.c */ -#line 128 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 19: /* Line 1802 of yacc.c */ -#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 133 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 20: /* Line 1802 of yacc.c */ -#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 21: /* Line 1802 of yacc.c */ -#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" - { - (yyval).type = COND_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; - } +#line 135 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 22: diff --git a/phpdbg_parser.y b/phpdbg_parser.y index fd81edfc29..702bf78455 100644 --- a/phpdbg_parser.y +++ b/phpdbg_parser.y @@ -121,6 +121,11 @@ parameter $$.len = $1.len; $$.num = $3.num; } + | T_IF T_INPUT { + $$.type = COND_PARAM; + $$.str = $2.str; + $$.len = $2.len; + } | T_OPCODE { $$ = $1; } | T_ADDR { $$ = $1; } | T_LITERAL { $$ = $1; } @@ -131,12 +136,7 @@ parameter ; full_expression - : T_IF T_INPUT { - $$.type = COND_PARAM; - $$.str = $2.str; - $$.len = $2.len; - } - | T_EVAL T_INPUT { + : T_EVAL T_INPUT { $$.type = EVAL_PARAM; $$.str = $2.str; $$.len = $2.len; -- cgit v1.2.1 From 18c9f8fbb9336c1a5ef1f3614b4ff37599bc237c Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 6 Jul 2014 01:17:50 +0200 Subject: Merge sapi/phpdbg into PHP-5.6 --- Makefile.frag | 2 +- phpdbg.c | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Makefile.frag b/Makefile.frag index b276aaaa53..36c7512d69 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -28,7 +28,7 @@ install-phpdbg: $(BUILD_BINARY) @$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT) @echo "Installing phpdbg man page: $(INSTALL_ROOT)$(mandir)/man1/" @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 - @$(INSTALL_DATA) sapi/phpdbg/phpdbg.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)phpdbg$(program_suffix).1 + @$(INSTALL_DATA) $(srcdir)/phpdbg.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)phpdbg$(program_suffix).1 clean-phpdbg: @echo "Cleaning phpdbg object files ..." diff --git a/phpdbg.c b/phpdbg.c index 93fdbd7424..1fbd18a423 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -856,7 +856,8 @@ int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*sock return SUCCESS; } /* }}} */ -void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) { +void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */ +{ int is_handled = FAILURE; TSRMLS_FETCH(); @@ -874,10 +875,11 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) { break; } -} +} /* }}} */ #endif -static inline zend_mm_heap *phpdbg_mm_get_heap() { +static inline zend_mm_heap *phpdbg_mm_get_heap() /* {{{ */ +{ zend_mm_heap *mm_heap; TSRMLS_FETCH(); @@ -886,22 +888,22 @@ static inline zend_mm_heap *phpdbg_mm_get_heap() { zend_mm_set_heap(mm_heap TSRMLS_CC); return mm_heap; -} +} /* }}} */ -void *phpdbg_malloc_wrapper(size_t size) +void *phpdbg_malloc_wrapper(size_t size) /* {{{ */ { return zend_mm_alloc(phpdbg_mm_get_heap(), size); -} +} /* }}} */ -void phpdbg_free_wrapper(void *p) +void phpdbg_free_wrapper(void *p) /* {{{ */ { zend_mm_free(phpdbg_mm_get_heap(), p); -} +} /* }}} */ -void *phpdbg_realloc_wrapper(void *ptr, size_t size) +void *phpdbg_realloc_wrapper(void *ptr, size_t size) /* {{{ */ { return zend_mm_realloc(phpdbg_mm_get_heap(), ptr, size); -} +} /* }}} */ int main(int argc, char **argv) /* {{{ */ { -- cgit v1.2.1 From 29d8aad2f65cab8d94ce6203f9cc5eb3e2691589 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 15 Sep 2014 05:48:09 +0200 Subject: Merge phpdbg into PHP-5.6 --- .travis.yml | 1 - README.md | 2 +- phpdbg.c | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index d5b492e7cf..2e777fbe13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ env: - PHP="PHP-5.4" - PHP="PHP-5.5" - PHP="PHP-5.6" -- PHP="master" before_script: ./travis/ci.sh diff --git a/README.md b/README.md index e7e5c731a8..a2a84deb7b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ The interactive PHP debugger ============================ -Implemented as a SAPI module, phpdbg can excert complete control over the environment without impacting the functionality or performance of your code. +Implemented as a SAPI module, phpdbg can exert complete control over the environment without impacting the functionality or performance of your code. phpdbg aims to be a lightweight, powerful, easy to use debugging platform for PHP 5.4+ diff --git a/phpdbg.c b/phpdbg.c index 1fbd18a423..c881559e6e 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -1296,14 +1296,14 @@ phpdbg_main: /* do not install sigint handlers for remote consoles */ /* sending SIGINT then provides a decent way of shutting down the server */ -#if defined(ZEND_SIGNALS) && !defined(_WIN32) - if (listen[0] < 0) { - zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try(); - } -#elif !defined(_WIN32) +#ifndef _WIN32 if (listen[0] < 0) { #endif +#if defined(ZEND_SIGNALS) && !defined(_WIN32) + zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try(); +#else signal(SIGINT, phpdbg_sigint_handler); +#endif #ifndef _WIN32 } #endif -- cgit v1.2.1 From 062284e4fbe8a66251eef01beb9242edd21d23a1 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Fri, 24 Oct 2014 19:22:45 +0200 Subject: Merge phpdbg into PHP-5.6 --- config.m4 | 22 +- config.w32 | 7 +- phpdbg.c | 530 +++++++------ phpdbg.h | 156 ++-- phpdbg_bp.c | 226 +++--- phpdbg_bp.h | 13 + phpdbg_break.c | 8 +- phpdbg_cmd.c | 341 +++++---- phpdbg_cmd.h | 31 +- phpdbg_eol.c | 172 +++++ phpdbg_eol.h | 46 ++ phpdbg_frame.c | 135 ++-- phpdbg_help.c | 62 +- phpdbg_help.h | 4 +- phpdbg_info.c | 429 +++++++---- phpdbg_info.h | 2 + phpdbg_io.c | 272 +++++++ phpdbg_io.h | 34 + phpdbg_lexer.c | 1576 +++++++++++++++++++++++--------------- phpdbg_lexer.l | 27 +- phpdbg_list.c | 194 +++-- phpdbg_list.h | 15 +- phpdbg_opcode.c | 22 +- phpdbg_out.c | 1305 +++++++++++++++++++++++++++++++ phpdbg_out.h | 93 +++ phpdbg_parser.c | 482 ++++++------ phpdbg_parser.h | 43 +- phpdbg_parser.y | 29 +- phpdbg_print.c | 111 +-- phpdbg_prompt.c | 833 +++++++++++++------- phpdbg_prompt.h | 11 +- phpdbg_rinit_hook.c | 101 +++ phpdbg_rinit_hook.h | 41 + phpdbg_set.c | 116 ++- phpdbg_sigio_win32.c | 120 +++ phpdbg_sigio_win32.h | 42 + phpdbg_sigsafe.c | 111 +++ phpdbg_sigsafe.h | 25 + phpdbg_utils.c | 419 +++++++--- phpdbg_utils.h | 62 +- phpdbg_wait.c | 419 ++++++++++ phpdbg_wait.h | 29 + phpdbg_watch.c | 228 ++---- phpdbg_watch.h | 6 +- phpdbg_webdata_transfer.c | 185 +++++ phpdbg_webdata_transfer.h | 27 + tests/commands/0002_set.test | 2 +- tests/commands/0102_print.test | 5 +- tests/commands/0104_clean.test | 10 +- tests/commands/0105_clear.test | 2 +- tests/commands/0106_compile.test | 4 +- xml.md | 759 ++++++++++++++++++ zend_mm_structs.h | 102 +++ 53 files changed, 7561 insertions(+), 2485 deletions(-) create mode 100644 phpdbg_eol.c create mode 100644 phpdbg_eol.h create mode 100644 phpdbg_io.c create mode 100644 phpdbg_io.h create mode 100644 phpdbg_out.c create mode 100644 phpdbg_out.h create mode 100644 phpdbg_rinit_hook.c create mode 100644 phpdbg_rinit_hook.h create mode 100644 phpdbg_sigio_win32.c create mode 100644 phpdbg_sigio_win32.h create mode 100644 phpdbg_sigsafe.c create mode 100644 phpdbg_sigsafe.h create mode 100644 phpdbg_wait.c create mode 100644 phpdbg_wait.h create mode 100644 phpdbg_webdata_transfer.c create mode 100644 phpdbg_webdata_transfer.h create mode 100644 xml.md create mode 100644 zend_mm_structs.h diff --git a/config.m4 b/config.m4 index d78a439af0..528abb5822 100644 --- a/config.m4 +++ b/config.m4 @@ -3,12 +3,15 @@ dnl $Id$ dnl PHP_ARG_ENABLE(phpdbg, for phpdbg support, -[ --enable-phpdbg Build phpdbg], no, no) +[ --enable-phpdbg Build phpdbg], no, no) + +PHP_ARG_ENABLE(phpdbg-webhelper, for phpdbg web SAPI support, +[ --enable-phpdbg-webhelper Build phpdbg web SAPI support], yes, yes) PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build, -[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) +[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) -if test "$PHP_PHPDBG" != "no"; then +if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then AC_HEADER_TIOCGWINSZ AC_DEFINE(HAVE_PHPDBG, 1, [ ]) @@ -18,8 +21,19 @@ if test "$PHP_PHPDBG" != "no"; then AC_DEFINE(PHPDBG_DEBUG, 0, [ ]) fi + if test "$PHP_PHPDBG_WEBHELPER" != "no"; then + if ! test -d ext/phpdbg_webhelper; then + ln -s ../sapi/phpdbg ext/phpdbg_webhelper + fi + if test "$PHP_JSON" != "no"; then + PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared) + else + AC_MSG_ERROR(Webhelper extension of phpdbg needs json enabled) + fi + fi + PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE" - PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c" + PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c phpdbg_eol.c phpdbg_out.c" if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS" diff --git a/config.w32 b/config.w32 index 17e15b6ced..6f0bd8f811 100644 --- a/config.w32 +++ b/config.w32 @@ -1,7 +1,11 @@ ARG_ENABLE('phpdbg', 'Build phpdbg', 'no'); ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); -PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c phpdbg_parser.c phpdbg_lexer.c'; +PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c ' + + 'phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c ' + + 'phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c '+ + 'phpdbg_parser.c phpdbg_lexer.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c ' + + 'phpdbg_sigio_win32.c phpdbg_eol.c phpdbg_out.c'; PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; PHPDBG_EXE='phpdbg.exe'; @@ -9,6 +13,7 @@ if (PHP_PHPDBG == "yes") { SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H"); + ADD_FLAG("LDFLAGS_PHPDBG", "/stack:8388608"); } if (PHP_PHPDBGS == "yes") { diff --git a/phpdbg.c b/phpdbg.c index c881559e6e..f09dc4ee13 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -28,7 +28,9 @@ #include "phpdbg_list.h" #include "phpdbg_utils.h" #include "phpdbg_set.h" +#include "phpdbg_io.h" #include "zend_alloc.h" +#include "phpdbg_eol.h" /* {{{ remote console headers */ #ifndef _WIN32 @@ -36,6 +38,7 @@ # include # include # include +# include # include # include # include @@ -43,6 +46,20 @@ ZEND_DECLARE_MODULE_GLOBALS(phpdbg); +static PHP_INI_MH(OnUpdateEol) +{ + if (!new_value) { + return FAILURE; + } + + return phpdbg_eol_global_update(new_value TSRMLS_CC); +} + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, socket_path, zend_phpdbg_globals, phpdbg_globals) + STD_PHP_INI_ENTRY("phpdbg.eol", "2", PHP_INI_ALL, OnUpdateEol, socket_path, zend_phpdbg_globals, phpdbg_globals) +PHP_INI_END() + static zend_bool phpdbg_booted = 0; #if PHP_VERSION_ID >= 50500 @@ -63,20 +80,39 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */ pg->exec = NULL; pg->exec_len = 0; pg->buffer = NULL; + pg->last_was_newline = 1; pg->ops = NULL; pg->vmret = 0; pg->bp_count = 0; pg->flags = PHPDBG_DEFAULT_FLAGS; pg->oplog = NULL; - pg->io[PHPDBG_STDIN] = NULL; - pg->io[PHPDBG_STDOUT] = NULL; - pg->io[PHPDBG_STDERR] = NULL; + memset(pg->io, 0, sizeof(pg->io)); pg->frame.num = 0; + pg->sapi_name_ptr = NULL; + pg->socket_fd = -1; + pg->socket_server_fd = -1; + + pg->req_id = 0; + pg->err_buf.active = 0; + pg->err_buf.type = 0; + + pg->input_buflen = 0; + pg->sigsafe_mem.mem = NULL; + pg->sigsegv_bailout = NULL; + +#ifdef PHP_WIN32 + pg->sigio_watcher_thread = INVALID_HANDLE_VALUE; + memset(&pg->swd, 0, sizeof(struct win32_sigio_watcher_data)); +#endif + + pg->eol = PHPDBG_EOL_LF; } /* }}} */ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ { ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL); + REGISTER_INI_ENTRIES(); + #if PHP_VERSION_ID >= 50500 zend_execute_old = zend_execute_ex; zend_execute_ex = phpdbg_execute_ex; @@ -86,7 +122,7 @@ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ #endif REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT); - + REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT); @@ -179,6 +215,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]); zend_hash_destroy(&PHPDBG_G(seek)); zend_hash_destroy(&PHPDBG_G(registered)); + zend_hash_destroy(&PHPDBG_G(file_sources)); zend_hash_destroy(&PHPDBG_G(watchpoints)); zend_llist_destroy(&PHPDBG_G(watchlist_mem)); @@ -186,7 +223,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ efree(PHPDBG_G(buffer)); PHPDBG_G(buffer) = NULL; } - + if (PHPDBG_G(exec)) { efree(PHPDBG_G(exec)); PHPDBG_G(exec) = NULL; @@ -226,7 +263,7 @@ static PHP_FUNCTION(phpdbg_exec) { char *exec = NULL; int exec_len = 0; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) { return; } @@ -308,7 +345,7 @@ static PHP_FUNCTION(phpdbg_color) { long element = 0L; char *color = NULL; - int color_len = 0; + size_t color_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) { return; @@ -329,7 +366,7 @@ static PHP_FUNCTION(phpdbg_color) static PHP_FUNCTION(phpdbg_prompt) { char *prompt = NULL; - int prompt_len = 0; + size_t prompt_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) { return; @@ -426,7 +463,12 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ * We must not request TSRM before being boot */ if (phpdbg_booted) { - phpdbg_error("%s", message); + if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) { + phpdbg_error("eval", "msg=\"%s\"", "%s", message); + return; + } + + phpdbg_error("php", "msg=\"%s\"", "%s", message); switch (PG(last_error_type)) { case E_ERROR: @@ -446,7 +488,7 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ } do { - switch (phpdbg_interactive(TSRMLS_C)) { + switch (phpdbg_interactive(1 TSRMLS_CC)) { case PHPDBG_LEAVE: case PHPDBG_FINISH: case PHPDBG_UNTIL: @@ -516,9 +558,42 @@ static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* { static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */ { - return phpdbg_write("%s", message); + 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); } /* }}} */ +/* beginning of struct, see main/streams/plain_wrapper.c line 111 */ +typedef struct { + FILE *file; + int fd; +} php_stdio_stream_data; + +static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) { + php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; + + while (data->fd >= 0) { + struct stat stat[3]; + memset(stat, 0, sizeof(stat)); + if (((fstat(fileno(stderr), &stat[2]) < 0) & (fstat(fileno(stdout), &stat[0]) < 0)) | (fstat(data->fd, &stat[1]) < 0)) { + break; + } + + if (stat[0].st_dev == stat[1].st_dev && stat[0].st_ino == stat[1].st_ino) { + phpdbg_script(P_STDOUT, "%.*s", (int) count, buf); + return count; + } + if (stat[2].st_dev == stat[1].st_dev && stat[2].st_ino == stat[1].st_ino) { + phpdbg_script(P_STDERR, "%.*s", (int) count, buf); + return count; + } + break; + } + + return PHPDBG_G(php_stdiop_write)(stream, buf, count TSRMLS_CC); +} + #if PHP_VERSION_ID >= 50700 static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC) /* {{{ */ { @@ -528,7 +603,9 @@ static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */ TSRMLS_FETCH(); #endif - fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); + if (!phpdbg_active_sigsafe_mem(TSRMLS_C)) { + fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); + } } /* }}} */ /* copied from sapi/cli/php_cli.c cli_register_file_handles */ @@ -644,10 +721,9 @@ const opt_struct OPTIONS[] = { /* {{{ */ {'r', 0, "run"}, {'E', 0, "step-through-eval"}, {'S', 1, "sapi-name"}, -#ifndef _WIN32 {'l', 1, "listen"}, {'a', 1, "address-or-any"}, -#endif + {'x', 0, "xml output"}, {'V', 0, "version"}, {'-', 0, NULL} }; /* }}} */ @@ -679,17 +755,25 @@ static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */ { /* print blurb */ if (!cleaning) { - phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", - PHPDBG_VERSION); - phpdbg_writeln("To get help using phpdbg type \"help\" and press enter"); - phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); + phpdbg_xml(""); + phpdbg_notice("intro", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); + phpdbg_writeln("intro", "help=\"help\"", "To get help using phpdbg type \"help\" and press enter"); + phpdbg_notice("intro", "report=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES); + phpdbg_xml(""); } else { - phpdbg_notice("Clean Execution Environment"); + if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) { + phpdbg_notice(NULL, NULL, "Clean Execution Environment"); + } - phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files))); + phpdbg_write("cleaninfo", "classes=\"%d\" functions=\"%d\" constants=\"%d\" includes=\"%d\"", + "Classes %d\n" + "Functions %d\n" + "Constants %d\n" + "Includes %d\n", + zend_hash_num_elements(EG(class_table)), + zend_hash_num_elements(EG(function_table)), + zend_hash_num_elements(EG(zend_constants)), + zend_hash_num_elements(&EG(included_files))); } } /* }}} */ @@ -697,163 +781,130 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */ { TSRMLS_FETCH(); - if (EG(in_execution)) { - /* set signalled only when not interactive */ - if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { - PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; - } - } else { + if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { /* we quit remote consoles on recv SIGINT */ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; zend_bailout(); } - } -} /* }}} */ - -#ifndef _WIN32 -int phpdbg_open_socket(const char *interface, short port) /* {{{ */ -{ - int fd = socket(AF_INET, SOCK_STREAM, 0); - - switch (fd) { - case -1: - return -1; - - default: { - int reuse = 1; - - switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) { - case -1: - close(fd); - return -2; - - default: { - struct sockaddr_in address; - - memset(&address, 0, sizeof(address)); - - address.sin_port = htons(port); - address.sin_family = AF_INET; - - if ((*interface == '*')) { - address.sin_addr.s_addr = htonl(INADDR_ANY); - } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) { - close(fd); - return -3; - } - - switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) { - case -1: - close(fd); - return -4; - - default: { - listen(fd, 5); - } - } - } + } else { + /* set signalled only when not interactive */ + if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { + if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { + char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1]; + + phpdbg_set_sigsafe_mem(mem TSRMLS_CC); + zend_try { + phpdbg_force_interruption(TSRMLS_C); + } zend_end_try() + phpdbg_clear_sigsafe_mem(TSRMLS_C); + return; } + PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; } } - - return fd; } /* }}} */ -static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */ -{ - if ((*socket)[0] >= 0) { - shutdown( - (*socket)[0], SHUT_RDWR); - close((*socket)[0]); - } - if (streams[0]) { - fclose(streams[0]); +static void phpdbg_remote_close(int socket, FILE *stream) { + if (socket >= 0) { + phpdbg_close_socket(socket); } - if ((*socket)[1] >= 0) { - shutdown( - (*socket)[1], SHUT_RDWR); - close((*socket)[1]); + if (stream) { + fclose(stream); } - - if (streams[1]) { - fclose(streams[1]); - } -} /* }}} */ +} /* don't inline this, want to debug it easily, will inline when done */ +static int phpdbg_remote_init(const char* address, unsigned short port, int server, int *socket, FILE **stream TSRMLS_DC) { + phpdbg_remote_close(*socket, *stream); -int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */ -{ - if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) { - ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]); - ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]); - } - - streams[0] = NULL; - streams[1] = NULL; - - if ((*listen)[0] < 0 || (*listen)[1] < 0) { - if ((*listen)[0] < 0) { - phpdbg_rlog(stderr, - "console failed to initialize (stdin) on %s:%d", address, port[0]); - } - - if ((*listen)[1] < 0) { - phpdbg_rlog(stderr, - "console failed to initialize (stdout) on %s:%d", address, port[1]); - } - - if ((*listen)[0] >= 0) { - close((*listen)[0]); - } - - if ((*listen)[1] >= 0) { - close((*listen)[1]); - } + if (server < 0) { + phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%u failed", address, port); return FAILURE; } - phpdbg_close_sockets(socket, streams); - - phpdbg_rlog(stderr, - "accepting connections on %s:%d/%d", address, port[0], port[1]); + phpdbg_rlog(fileno(stderr), "accepting connections on %s:%u", address, port); { - struct sockaddr_in address; + struct sockaddr_storage address; socklen_t size = sizeof(address); char buffer[20] = {0}; + /* XXX error checks */ + memset(&address, 0, size); + *socket = accept(server, (struct sockaddr *) &address, &size); + inet_ntop(AF_INET, &(((struct sockaddr_in *)&address)->sin_addr), buffer, sizeof(buffer)); - { - memset(&address, 0, size); - (*socket)[0] = accept( - (*listen)[0], (struct sockaddr *) &address, &size); - inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); - - phpdbg_rlog(stderr, "connection (stdin) from %s", buffer); - } - - { - memset(&address, 0, size); - (*socket)[1] = accept( - (*listen)[1], (struct sockaddr *) &address, &size); - inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); - - phpdbg_rlog(stderr, "connection (stdout) from %s", buffer); - } + phpdbg_rlog(fileno(stderr), "connection established from %s", buffer); } - dup2((*socket)[0], fileno(stdin)); - dup2((*socket)[1], fileno(stdout)); +#ifndef _WIN32 + dup2(*socket, fileno(stdout)); + dup2(*socket, fileno(stdin)); setbuf(stdout, NULL); - streams[0] = fdopen((*socket)[0], "r"); - streams[1] = fdopen((*socket)[1], "w"); + *stream = fdopen(*socket, "r+"); + phpdbg_set_async_io(*socket); +#endif return SUCCESS; +} + +#ifndef _WIN32 +/* This function *strictly* assumes that SIGIO is *only* used on the remote connection stream */ +void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */ +{ + int flags; + size_t newlen; + size_t i/*, last_nl*/; + TSRMLS_FETCH(); + +// if (!(info->si_band & POLLIN)) { +// return; /* Not interested in writeablility etc., just interested in incoming data */ +// } + + /* only non-blocking reading, avoid non-blocking writing */ + flags = fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_GETFL, 0); + fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags | O_NONBLOCK); + + do { + char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1]; + size_t off = 0; + + if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) { + break; + } + for (i = 0; i < newlen; i++) { + switch (mem[off + i]) { + case '\x03': /* ^C char */ + if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { + break; /* or quit ??? */ + } + if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { + phpdbg_set_sigsafe_mem(mem TSRMLS_CC); + zend_try { + phpdbg_force_interruption(TSRMLS_C); + } zend_end_try(); + phpdbg_clear_sigsafe_mem(TSRMLS_C); + break; + } + if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { + PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; + } + break; +/* case '\n': + zend_llist_add_element(PHPDBG_G(stdin), strndup() + last_nl = PHPDBG_G(stdin_buf).len + i; + break; +*/ } + } + off += i; + } while (0); + + + fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags); } /* }}} */ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */ @@ -864,6 +915,9 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */ switch (sig) { case SIGBUS: case SIGSEGV: + if (PHPDBG_G(sigsegv_bailout)) { + LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE); + } is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC); if (is_handled == FAILURE) { #ifdef ZEND_SIGNALS @@ -936,33 +990,26 @@ int main(int argc, char **argv) /* {{{ */ char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX"; #endif -#ifndef _WIN32 char *address; - int listen[2]; - int server[2]; - int socket[2]; - FILE* streams[2] = {NULL, NULL}; -#endif + int listen = -1; + int server = -1; + int socket = -1; + FILE* stream = NULL; #ifdef ZTS void ***tsrm_ls; #endif #ifndef _WIN32 + struct sigaction sigio_struct; struct sigaction signal_struct; signal_struct.sa_sigaction = phpdbg_signal_handler; signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER; + sigio_struct.sa_sigaction = phpdbg_sigio_handler; + sigio_struct.sa_flags = SA_SIGINFO; +#endif address = strdup("127.0.0.1"); - socket[0] = -1; - socket[1] = -1; - listen[0] = -1; - listen[1] = -1; - server[0] = -1; - server[1] = -1; - streams[0] = NULL; - streams[1] = NULL; -#endif #ifdef PHP_WIN32 _fmode = _O_BINARY; /* sets default for file streams to binary */ @@ -991,7 +1038,7 @@ phpdbg_main: } if (!bp_tmp_file) { - phpdbg_error("Unable to create temporary file"); + phpdbg_error("tmpfile", "", "Unable to create temporary file"); return 1; } #else @@ -1125,21 +1172,12 @@ phpdbg_main: show_banner = 0; break; -#ifndef _WIN32 - /* if you pass a listen port, we will accept input on listen port */ - /* and write output to listen port * 2 */ - - case 'l': { /* set listen ports */ - if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) { - if (sscanf(php_optarg, "%d", &listen[0]) != 1) { - /* default to hardcoded ports */ - listen[0] = 4000; - listen[1] = 8000; - } else { - listen[1] = (listen[0] * 2); - } + /* if you pass a listen port, we will read and write on listen port */ + case 'l': /* set listen ports */ + if (sscanf(php_optarg, "%d", &listen) != 1) { + listen = 8000; } - } break; + break; case 'a': { /* set bind address */ free(address); @@ -1147,7 +1185,10 @@ phpdbg_main: address = strdup("*"); } else address = strdup(php_optarg); } break; -#endif + + case 'x': + flags |= PHPDBG_WRITE_XML; + break; case 'V': { sapi_startup(phpdbg); @@ -1180,19 +1221,6 @@ phpdbg_main: php_optind++; } -#ifndef _WIN32 - /* setup remote server if necessary */ - if (!cleaning && - (listen[0] > 0 && listen[1] > 0)) { - if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) { - remote = 0; - exit(0); - } - /* set remote flag to stop service shutting down upon quit */ - remote = 1; - } -#endif - if (sapi_name) { phpdbg->name = sapi_name; } @@ -1247,7 +1275,24 @@ phpdbg_main: EXCEPTION_POINTERS *xp; __try { #endif - zend_mm_heap *mm_heap = phpdbg_mm_get_heap(); + zend_mm_heap *mm_heap; + + /* setup remote server if necessary */ + if (!cleaning && listen > 0) { + server = phpdbg_open_socket(address, listen TSRMLS_CC); + if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) { + exit(0); + } + +#ifndef _WIN32 + sigaction(SIGIO, &sigio_struct, NULL); +#endif + + /* set remote flag to stop service shutting down upon quit */ + remote = 1; + } + + mm_heap = phpdbg_mm_get_heap(); if (mm_heap->use_zend_alloc) { mm_heap->_malloc = phpdbg_malloc_wrapper; @@ -1258,6 +1303,8 @@ phpdbg_main: zend_activate(TSRMLS_C); + phpdbg_init_list(TSRMLS_C); + PHPDBG_G(original_free_function) = mm_heap->_free; mm_heap->_free = phpdbg_watch_efree; @@ -1277,10 +1324,17 @@ phpdbg_main: sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); #endif + PHPDBG_G(sapi_name_ptr) = sapi_name; + + php_output_activate(TSRMLS_C); + php_output_deactivate(TSRMLS_C); + + php_output_activate(TSRMLS_C); + if (php_request_startup(TSRMLS_C) == SUCCESS) { int i; - - SG(request_info).argc = argc - php_optind + 1; + + SG(request_info).argc = argc - php_optind + 1; SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *)); for (i = SG(request_info).argc; --i;) { SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]); @@ -1290,14 +1344,10 @@ phpdbg_main: php_hash_environment(TSRMLS_C); } - /* make sure to turn off buffer for ev command */ - php_output_activate(TSRMLS_C); - php_output_deactivate(TSRMLS_C); - /* do not install sigint handlers for remote consoles */ /* sending SIGINT then provides a decent way of shutting down the server */ #ifndef _WIN32 - if (listen[0] < 0) { + if (listen < 0) { #endif #if defined(ZEND_SIGNALS) && !defined(_WIN32) zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try(); @@ -1313,18 +1363,44 @@ phpdbg_main: /* set flags from command line */ PHPDBG_G(flags) = flags; -#ifndef _WIN32 /* setup io here */ - if (streams[0] && streams[1]) { + if (remote) { PHPDBG_G(flags) |= PHPDBG_IS_REMOTE; - +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); +#endif + } + +#ifndef _WIN32 + PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; + PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin); + PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; + PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout); +#else + /* XXX this is a complete mess here with FILE/fd/SOCKET, + we should let only one to survive probably. Need + a clean separation whether it's a remote or local + prompt. And what is supposed to go as user interaction, + error log, etc. */ + if (remote) { + PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; + PHPDBG_G(io)[PHPDBG_STDIN].fd = socket; + PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; + PHPDBG_G(io)[PHPDBG_STDOUT].fd = socket; + } else { + PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; + PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin); + PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; + PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout); } #endif + PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr; + PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr); - PHPDBG_G(io)[PHPDBG_STDIN] = stdin; - PHPDBG_G(io)[PHPDBG_STDOUT] = stdout; - PHPDBG_G(io)[PHPDBG_STDERR] = stderr; +#ifndef _WIN32 + PHPDBG_G(php_stdiop_write) = php_stream_stdio_ops.write; + php_stream_stdio_ops.write = phpdbg_stdiop_write; +#endif if (exec) { /* set execution context */ PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); @@ -1336,8 +1412,7 @@ phpdbg_main: if (oplog_file) { /* open oplog */ PHPDBG_G(oplog) = fopen(oplog_file, "w+"); if (!PHPDBG_G(oplog)) { - phpdbg_error( - "Failed to open oplog %s", oplog_file); + phpdbg_error("oplog", "path=\"%s\"", "Failed to open oplog %s", oplog_file); } free(oplog_file); } @@ -1348,7 +1423,7 @@ phpdbg_main: phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC); /* set default prompt */ - phpdbg_set_prompt(PROMPT TSRMLS_CC); + phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT TSRMLS_CC); /* Make stdin, stdout and stderr accessible from PHP scripts */ phpdbg_register_file_handles(TSRMLS_C); @@ -1390,14 +1465,11 @@ phpdbg_main: } } -/* #ifndef for making compiler shutting up */ -#ifndef _WIN32 phpdbg_interact: -#endif /* phpdbg main() */ do { zend_try { - phpdbg_interactive(TSRMLS_C); + phpdbg_interactive(1 TSRMLS_CC); } zend_catch { if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { FILE *bp_tmp_fp = fopen(bp_tmp_file, "w"); @@ -1408,18 +1480,16 @@ phpdbg_interact: cleaning = 0; } -#ifndef _WIN32 if (!cleaning) { /* remote client disconnected */ if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { /* renegociate connections */ - phpdbg_open_sockets( - address, listen, &server, &socket, streams); + phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC); /* set streams */ - if (streams[0] && streams[1]) { + if (stream) { PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING; } @@ -1431,7 +1501,6 @@ phpdbg_interact: } } } -#endif } zend_end_try(); } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); @@ -1441,21 +1510,19 @@ phpdbg_interact: /* this is just helpful */ PG(report_memleaks) = 0; -#ifndef _WIN32 phpdbg_out: if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) { PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED; goto phpdbg_interact; } -#endif #ifdef _WIN32 } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) { - phpdbg_error("Access violation (Segementation fault) encountered\ntrying to abort cleanly..."); + phpdbg_error("segfault", "", "Access violation (Segementation fault) encountered\ntrying to abort cleanly..."); } -phpdbg_out: +/* phpdbg_out: */ #endif - + { int i; /* free argv */ @@ -1468,8 +1535,7 @@ phpdbg_out: #ifndef ZTS /* force cleanup of auto and core globals */ zend_hash_clean(CG(auto_globals)); - memset( - &core_globals, 0, sizeof(php_core_globals)); + memset( &core_globals, 0, sizeof(php_core_globals)); #endif if (ini_entries) { free(ini_entries); @@ -1478,15 +1544,17 @@ phpdbg_out: if (ini_override) { free(ini_override); } - + /* this must be forced */ CG(unclean_shutdown) = 0; - + /* this is just helpful */ PG(report_memleaks) = 0; php_request_shutdown((void*)0); + php_output_deactivate(TSRMLS_C); + zend_try { php_module_shutdown(TSRMLS_C); } zend_end_try(); @@ -1498,7 +1566,7 @@ phpdbg_out: if (cleaning || remote) { goto phpdbg_main; } - + #ifdef ZTS /* bugggy */ /* tsrm_shutdown(); */ @@ -1510,10 +1578,10 @@ phpdbg_out: } #endif - if (sapi_name) { - free(sapi_name); + if (PHPDBG_G(sapi_name_ptr)) { + free(PHPDBG_G(sapi_name_ptr)); } - + #ifdef _WIN32 free(bp_tmp_file); #else diff --git a/phpdbg.h b/phpdbg.h index eb4faf1f94..8c0dbb4afa 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -29,6 +29,8 @@ # define PHPDBG_API #endif +#include +#include #include "php.h" #include "php_globals.h" #include "php_variables.h" @@ -40,20 +42,21 @@ #include "zend_ini_scanner.h" #include "zend_stream.h" #ifndef _WIN32 -# include "zend_signal.h" +# include "zend_signal.h" #endif #include "SAPI.h" #include #include #if defined(_WIN32) && !defined(__MINGW32__) -# include -# include "config.w32.h" -# undef strcasecmp -# undef strncasecmp -# define strcasecmp _stricmp -# define strncasecmp _strnicmp +# include +# include "config.w32.h" +# include "win32/php_stdint.h" +# undef strcasecmp +# undef strncasecmp +# define strcasecmp _stricmp +# define strncasecmp _strnicmp #else -# include "php_config.h" +# include "php_config.h" #endif #ifndef O_BINARY # define O_BINARY 0 @@ -64,21 +67,41 @@ # include "TSRM.h" #endif -#ifdef LIBREADLINE -# include -# include +#ifdef HAVE_LIBREADLINE +# include +# include #endif #ifdef HAVE_LIBEDIT -# include +# include #endif -#include "phpdbg_lexer.h" -#include "phpdbg_cmd.h" -#include "phpdbg_utils.h" -#include "phpdbg_btree.h" -#include "phpdbg_watch.h" +/* {{{ remote console headers */ +#ifndef _WIN32 +# include +# include +# include +# include +# include +#endif /* }}} */ -int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); +/* {{{ strings */ +#define PHPDBG_NAME "phpdbg" +#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ +#define PHPDBG_URL "http://phpdbg.com" +#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" +#define PHPDBG_VERSION "0.4.0" +#define PHPDBG_INIT_FILENAME ".phpdbginit" +#define PHPDBG_DEFAULT_PROMPT "prompt>" +/* }}} */ + +/* Hey, apple. One shouldn't define *functions* from the standard C library as marcos. */ +#ifdef memcpy +#define memcpy_tmp(...) memcpy(__VA_ARGS__) +#undef memcpy +#define memcpy(...) memcpy_tmp(__VA_ARGS__) +#endif + +#if !defined(PHPDBG_WEBDATA_TRANSFER_H) && !defined(PHPDBG_WEBHELPER_H) #ifdef ZTS # define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) @@ -86,6 +109,19 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); # define PHPDBG_G(v) (phpdbg_globals.v) #endif +#include "phpdbg_sigsafe.h" +#include "phpdbg_out.h" +#include "phpdbg_lexer.h" +#include "phpdbg_cmd.h" +#include "phpdbg_utils.h" +#include "phpdbg_btree.h" +#include "phpdbg_watch.h" +#ifdef PHP_WIN32 +# include "phpdbg_sigio_win32.h" +#endif + +int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); + #define PHPDBG_NEXT 2 #define PHPDBG_UNTIL 3 #define PHPDBG_FINISH 4 @@ -145,11 +181,14 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); #define PHPDBG_IS_BP_ENABLED (1<<26) #define PHPDBG_IS_REMOTE (1<<27) #define PHPDBG_IS_DISCONNECTED (1<<28) +#define PHPDBG_WRITE_XML (1<<29) + +#define PHPDBG_SHOW_REFCOUNTS (1<<30) -#define PHPDBG_SHOW_REFCOUNTS (1<<29) +#define PHPDBG_IN_SIGNAL_HANDLER (1<<30) #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_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP) #define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP|PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP) #ifndef _WIN32 @@ -158,21 +197,27 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); # define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED) #endif /* }}} */ -/* {{{ strings */ -#define PHPDBG_NAME "phpdbg" -#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ -#define PHPDBG_URL "http://phpdbg.com" -#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" -#define PHPDBG_VERSION "0.4.0" -#define PHPDBG_INIT_FILENAME ".phpdbginit" -/* }}} */ - /* {{{ output descriptors */ #define PHPDBG_STDIN 0 #define PHPDBG_STDOUT 1 #define PHPDBG_STDERR 2 #define PHPDBG_IO_FDS 3 /* }}} */ +#define phpdbg_try_access \ + { \ + JMP_BUF *__orig_bailout = PHPDBG_G(sigsegv_bailout); \ + JMP_BUF __bailout; \ + \ + PHPDBG_G(sigsegv_bailout) = &__bailout; \ + if (SETJMP(__bailout) == 0) { +#define phpdbg_catch_access \ + } else { \ + PHPDBG_G(sigsegv_bailout) = __orig_bailout; +#define phpdbg_end_try_access() \ + } \ + PHPDBG_G(sigsegv_bailout) = __orig_bailout; \ + } + /* {{{ structs */ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) @@ -202,29 +247,52 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) int bp_count; /* breakpoint count */ int vmret; /* return from last opcode handler execution */ + zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); + HashTable file_sources; + FILE *oplog; /* opline log */ - FILE *io[PHPDBG_IO_FDS]; /* io */ + struct { + FILE *ptr; + int fd; + } io[PHPDBG_IO_FDS]; /* io */ + size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC); + int in_script_xml; /* in output mode */ + struct { + zend_bool active; + int type; + int fd; + char *tag; + char *msg; + int msglen; + char *xml; + int xmllen; + } err_buf; /* error buffer */ + zend_ulong req_id; /* "request id" to keep track of commands */ char *prompt[2]; /* prompt */ const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */ char *buffer; /* buffer */ + zend_bool last_was_newline; /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */ + + char input_buffer[PHPDBG_MAX_CMD]; /* stdin input buffer */ + int input_buflen; /* length of stdin input buffer */ + phpdbg_signal_safe_mem sigsafe_mem; /* memory to use in async safe environment (only once!) */ + + JMP_BUF *sigsegv_bailout; /* bailout address for accesibility probing */ zend_ulong flags; /* phpdbg flags */ + + char *socket_path; /* phpdbg.path ini setting */ + char *sapi_name_ptr; /* store sapi name to free it if necessary to not leak memory */ + int socket_fd; /* file descriptor to socket (wait command) (-1 if unused) */ + int socket_server_fd; /* file descriptor to master socket (wait command) (-1 if unused) */ +#ifdef PHP_WIN32 + HANDLE sigio_watcher_thread; /* sigio watcher thread handle */ + struct win32_sigio_watcher_data swd; +#endif + int8_t eol; ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ -/* the beginning (= the important part) of the _zend_mm_heap struct defined in Zend/zend_alloc.c - Needed for realizing watchpoints */ -struct _zend_mm_heap { - int use_zend_alloc; - void *(*_malloc)(size_t); - void (*_free)(void *); - void *(*_realloc)(void *, size_t); - size_t free_bitmap; - size_t large_free_bitmap; - size_t block_size; - size_t compact_size; - zend_mm_segment *segments_list; - zend_mm_storage *storage; -}; +#endif #endif /* PHPDBG_H */ diff --git a/phpdbg_bp.c b/phpdbg_bp.c index a18316a228..81674a0daf 100644 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@ -43,8 +43,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut */ static inline void _phpdbg_break_mapping(int id, HashTable *table TSRMLS_DC) { - zend_hash_index_update( - &PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id), (void**) &table, sizeof(void*), NULL); + zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id), (void**) &table, sizeof(void*), NULL); } #define PHPDBG_BREAK_MAPPING(id, table) _phpdbg_break_mapping(id, table TSRMLS_CC) @@ -97,8 +96,8 @@ PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */ HashTable **table = NULL; for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void **) &table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { phpdbg_breakbase_t *brake; for (zend_hash_internal_pointer_reset_ex((*table), &position[1]); @@ -117,13 +116,11 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ zend_ulong id = 0L; if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) { - phpdbg_notice( - "Exporting %d breakpoints", - zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])); + phpdbg_notice("exportbreakpoint", "count=\"%d\"", "Exporting %d breakpoints", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])); /* this only looks like magic, it isn't */ for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void **) &table, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { phpdbg_breakbase_t *brake; zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], NULL, NULL, &id, 0, &position[0]); @@ -223,18 +220,18 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML { php_stream_statbuf ssb; char realpath[MAXPATHLEN]; - + if (php_stream_stat_path(path, &ssb) != FAILURE) { if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) { HashTable *broken; phpdbg_breakfile_t new_break; size_t path_len = 0L; - + if (VCWD_REALPATH(path, realpath)) { path = realpath; } path_len = strlen(path); - + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len, (void**)&broken) == FAILURE) { HashTable breaks; @@ -253,22 +250,21 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML new_break.filename = estrndup(path, path_len); new_break.line = line_num; - zend_hash_index_update( - broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL); + zend_hash_index_update( broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL); - phpdbg_notice("Breakpoint #%d added at %s:%ld", + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); PHPDBG_BREAK_MAPPING(new_break.id, broken); } else { - phpdbg_error("Breakpoint at %s:%ld exists", path, line_num); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); } } else { - phpdbg_error("Cannot set breakpoint in %s, it is not a regular file", path); + phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path); } } else { - phpdbg_error("Cannot stat %s, it does not exist", path); + phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", path); } } /* }}} */ @@ -285,12 +281,12 @@ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len T zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol, name_len, &new_break, sizeof(phpdbg_breaksymbol_t), NULL); - phpdbg_notice("Breakpoint #%d added at %s", + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" function=\"%s\"", "Breakpoint #%d added at %s", new_break.id, new_break.symbol); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); } else { - phpdbg_notice("Breakpoint exists at %s", name); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" function=\"%s\"", "Breakpoint exists at %s", name); } } /* }}} */ @@ -324,12 +320,12 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char zend_hash_update(class_table, lcname, func_len, &new_break, sizeof(phpdbg_breakmethod_t), NULL); - phpdbg_notice("Breakpoint #%d added at %s::%s", + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" method=\"%s::%s\"", "Breakpoint #%d added at %s::%s", new_break.id, class_name, func_name); PHPDBG_BREAK_MAPPING(new_break.id, class_table); } else { - phpdbg_notice("Breakpoint exists at %s::%s", class_name, func_name); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" method=\"%s::%s\"", "Breakpoint exists at %s::%s", class_name, func_name); } efree(lcname); @@ -350,11 +346,11 @@ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline, &new_break, sizeof(phpdbg_breakline_t), NULL); - phpdbg_notice("Breakpoint #%d added at %#lx", + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" opline=\"%#lx\"", "Breakpoint #%d added at %#lx", new_break.id, new_break.opline); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); } else { - phpdbg_notice("Breakpoint exists at %#lx", opline); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" opline=\"%#lx\"", "Breakpoint exists at %#lx", opline); } } /* }}} */ @@ -363,11 +359,11 @@ PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_o phpdbg_breakline_t opline_break; if (op_array->last <= brake->opline_num) { if (brake->class_name == NULL) { - phpdbg_error("There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num); + phpdbg_error("breakpoint", "type=\"maxoplines\" add=\"fail\" maxoplinenum=\"%d\" function=\"%s\" usedoplinenum=\"%ld\"", "There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num); } else if (brake->func_name == NULL) { - phpdbg_error("There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num); + phpdbg_error("breakpoint", "type=\"maxoplines\" add=\"fail\" maxoplinenum=\"%d\" file=\"%s\" usedoplinenum=\"%ld\"", "There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num); } else { - phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num); + phpdbg_error("breakpoint", "type=\"maxoplines\" add=\"fail\" maxoplinenum=\"%d\" method=\"%s::%s\" usedoplinenum=\"%ld\"", "There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num); } return FAILURE; @@ -423,7 +419,7 @@ PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC zend_hash_internal_pointer_end(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); zend_hash_get_current_data(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void **)&opline_break); - phpdbg_notice("Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)", + 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, brake->class_name?brake->class_name:"", brake->class_name&&brake->func_name?"::":"", @@ -474,7 +470,7 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRML if (zend_hash_find(func_table, zend_str_tolower_dup(new_break->func_name, new_break->func_len), new_break->func_len + 1, (void **)&func) == FAILURE) { if (new_break->class_name != NULL && new_break->func_name != NULL) { - phpdbg_error("Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name); + phpdbg_error("breakpoint", "type=\"nomethod\" method=\"%s::%s\"", "Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name); return 2; } return FAILURE; @@ -482,9 +478,9 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRML if (func->type != ZEND_USER_FUNCTION) { if (new_break->class_name == NULL) { - phpdbg_error("%s is not an user defined function, no oplines exist", new_break->func_name); + phpdbg_error("breakpoint", "type=\"internalfunction\" function=\"%s\"", "%s is not an user defined function, no oplines exist", new_break->func_name); } else { - phpdbg_error("%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name); + phpdbg_error("breakpoint", "type=\"internalfunction\" method=\"%s::%s\"", "%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name); } return 2; } @@ -512,11 +508,11 @@ PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const cha switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { case FAILURE: - phpdbg_notice("Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); + phpdbg_notice("breakpoint", "pending=\"pending\" id=\"%d\" method=\"%::%s\" num=\"%ld\"", "Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); break; case SUCCESS: - phpdbg_notice("Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); + phpdbg_notice("breakpoint", "id=\"%d\" method=\"%::%s\" num=\"%ld\"", "Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); break; case 2: @@ -542,7 +538,7 @@ PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const cha } if (zend_hash_index_exists(method_table, opline)) { - phpdbg_notice("Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline); + phpdbg_error("breakpoint", "type=\"exists\" method=\"%s\" num=\"%ld\"", "Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline); efree((char*)new_break.func_name); efree((char*)new_break.class_name); PHPDBG_G(bp_count)--; @@ -571,11 +567,11 @@ PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { case FAILURE: - phpdbg_notice("Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline); + phpdbg_notice("breakpoint", "pending=\"pending\" id=\"%d\" function=\"%s\" num=\"%ld\"", "Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline); break; case SUCCESS: - phpdbg_notice("Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline); + phpdbg_notice("breakpoint", "id=\"%d\" function=\"%s\" num=\"%ld\"", "Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline); break; case 2: @@ -592,7 +588,7 @@ PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend } if (zend_hash_index_exists(func_table, opline)) { - phpdbg_notice("Breakpoint already exists for %s#%ld", new_break.func_name, opline); + phpdbg_error("breakpoint", "type=\"exists\" function=\"%s\" num=\"%ld\"", "Breakpoint already exists for %s#%ld", new_break.func_name, opline); efree((char*)new_break.func_name); PHPDBG_G(bp_count)--; return; @@ -620,11 +616,11 @@ PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong o switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { case FAILURE: - phpdbg_notice("Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline); + phpdbg_notice("breakpoint", "pending=\"pending\" id=\"%d\" file=\"%s\" num=\"%ld\"", "Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline); break; case SUCCESS: - phpdbg_notice("Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline); + phpdbg_notice("breakpoint", "id=\"%d\" file=\"%s\" num=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline); break; case 2: @@ -641,7 +637,7 @@ PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong o } if (zend_hash_index_exists(file_table, opline)) { - phpdbg_notice("Breakpoint already exists for %s:%ld", new_break.class_name, opline); + phpdbg_error("breakpoint", "type=\"exists\" file=\"%s\" num=\"%d\"", "Breakpoint already exists for %s:%ld", new_break.class_name, opline); efree((char*)new_break.class_name); PHPDBG_G(bp_count)--; return; @@ -660,8 +656,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len T zend_ulong hash = zend_hash_func(name, name_len); if (zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash)) { - phpdbg_notice( - "Breakpoint exists for %s", name); + phpdbg_error("breakpoint", "type=\"exists\" opcode=\"%s\"", "Breakpoint exists for %s", name); return; } @@ -674,7 +669,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len T PHPDBG_G(flags) |= PHPDBG_HAS_OPCODE_BP; - phpdbg_notice("Breakpoint #%d added at %s", new_break.id, name); + phpdbg_notice("breakpoint", "id=\"%d\" opcode=\"%s\"", "Breakpoint #%d added at %s", new_break.id, name); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]); } /* }}} */ @@ -691,9 +686,10 @@ PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRML zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t), NULL); - phpdbg_notice("Breakpoint #%d added at %#lx", - new_break.id, new_break.opline); + phpdbg_notice("breakpoint", "id=\"%d\" opline=\"%#lx\"", "Breakpoint #%d added at %#lx", new_break.id, new_break.opline); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + } else { + phpdbg_error("breakpoint", "type=\"exists\" opline=\"%#lx\"", "Breakpoint exists for opline %#lx", (zend_ulong) opline); } } /* }}} */ @@ -729,8 +725,7 @@ static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, co Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0'; Z_TYPE(pv) = IS_STRING; - new_break.ops = zend_compile_string( - &pv, "Conditional Breakpoint Code" TSRMLS_CC); + new_break.ops = zend_compile_string(&pv, "Conditional Breakpoint Code" TSRMLS_CC); zval_dtor(&pv); @@ -739,14 +734,12 @@ static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, co &PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash, &new_break, sizeof(phpdbg_breakcond_t), (void**)&brake); - phpdbg_notice("Conditional breakpoint #%d added %s/%p", - brake->id, brake->code, brake->ops); + phpdbg_notice("breakpoint", "id=\"%d\" expression=\"%s\" ptr=\"%p\"", "Conditional breakpoint #%d added %s/%p", brake->id, brake->code, brake->ops); PHPDBG_G(flags) |= PHPDBG_HAS_COND_BP; PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_COND]); } else { - phpdbg_error( - "Failed to compile code for expression %s", expr); + phpdbg_error("compile", "expression=\"%s\"", "Failed to compile code for expression %s", expr); efree((char*)new_break.code); PHPDBG_G(bp_count)--; } @@ -762,7 +755,7 @@ PHPDBG_API void phpdbg_set_breakpoint_expression(const char *expr, size_t expr_l phpdbg_create_conditional_break( &new_break, NULL, expr, expr_len, expr_hash TSRMLS_CC); } else { - phpdbg_notice("Conditional break %s exists", expr); + phpdbg_error("breakpoint", "type=\"exists\" expression=\"%s\"", "Conditional break %s exists", expr); } } /* }}} */ @@ -771,21 +764,18 @@ PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param TSRMLS_DC) phpdbg_breakcond_t new_break; phpdbg_param_t *condition; zend_ulong hash = 0L; - + if (param->next) { condition = param->next; hash = zend_inline_hash_func(condition->str, condition->len); - + if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash)) { - phpdbg_create_conditional_break( - &new_break, param, - condition->str, condition->len, hash TSRMLS_CC); + phpdbg_create_conditional_break(&new_break, param, condition->str, condition->len, hash TSRMLS_CC); } else { - phpdbg_notice( - "Conditional break %s exists at the specified location", condition->str); - } + phpdbg_notice("breakpoint", "type=\"exists\" arg=\"%s\"", "Conditional break %s exists at the specified location", condition->str); + } } - + } /* }}} */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_array TSRMLS_DC) /* {{{ */ @@ -970,7 +960,6 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void*)&bp, &position) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { zval *retval = NULL; - int orig_interactive = CG(interactive); zval **orig_retval = EG(return_value_ptr_ptr); zend_op_array *orig_ops = EG(active_op_array); zend_op **orig_opline = EG(opline_ptr); @@ -995,8 +984,6 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut zend_rebuild_symbol_table(TSRMLS_C); } - CG(interactive) = 0; - zend_try { PHPDBG_G(flags) |= PHPDBG_IN_COND_BP; zend_execute(EG(active_op_array) TSRMLS_CC); @@ -1008,8 +995,6 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut breakpoint = SUCCESS; } } zend_catch { - CG(interactive) = orig_interactive; - EG(no_extensions)=1; EG(return_value_ptr_ptr) = orig_retval; EG(active_op_array) = orig_ops; @@ -1017,8 +1002,6 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP; } zend_end_try(); - CG(interactive) = orig_interactive; - EG(no_extensions)=1; EG(return_value_ptr_ptr) = orig_retval; EG(active_op_array) = orig_ops; @@ -1148,10 +1131,10 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ break; } - phpdbg_notice("Deleted breakpoint #%ld", num); + phpdbg_notice("breakpoint", "deleted=\"success\" id=\"%ld\"", "Deleted breakpoint #%ld", num); PHPDBG_BREAK_UNMAPPING(num); } else { - phpdbg_error("Failed to find breakpoint #%ld", num); + phpdbg_error("breakpoint", "type=\"nobreakpoint\" deleted=\"fail\" id=\"%ld\"", "Failed to find breakpoint #%ld", num); } } /* }}} */ @@ -1189,7 +1172,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* switch (brake->type) { case PHPDBG_BREAK_FILE: { - phpdbg_notice("Breakpoint #%d at %s:%ld, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d at %s:%ld, hits: %lu", ((phpdbg_breakfile_t*)brake)->id, ((phpdbg_breakfile_t*)brake)->filename, ((phpdbg_breakfile_t*)brake)->line, @@ -1197,7 +1180,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_SYM: { - phpdbg_notice("Breakpoint #%d in %s() at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" function=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s() at %s:%u, hits: %lu", ((phpdbg_breaksymbol_t*)brake)->id, ((phpdbg_breaksymbol_t*)brake)->symbol, zend_get_executed_filename(TSRMLS_C), @@ -1206,7 +1189,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_OPLINE: { - phpdbg_notice("Breakpoint #%d in %#lx at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" opline=\"%#lx\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %#lx at %s:%u, hits: %lu", ((phpdbg_breakline_t*)brake)->id, ((phpdbg_breakline_t*)brake)->opline, zend_get_executed_filename(TSRMLS_C), @@ -1215,7 +1198,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_METHOD_OPLINE: { - phpdbg_notice("Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" method=\"%s::%s\" num=\"%lu\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu", ((phpdbg_breakopline_t*)brake)->id, ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->func_name, @@ -1226,7 +1209,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_FUNCTION_OPLINE: { - phpdbg_notice("Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" num=\"%lu\" function=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu", ((phpdbg_breakopline_t*)brake)->id, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num, @@ -1236,9 +1219,8 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_FILE_OPLINE: { - phpdbg_notice("Breakpoint #%d in %s:%lu at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" num=\"%lu\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in #%lu at %s:%u, hits: %lu", ((phpdbg_breakopline_t*)brake)->id, - ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->opline_num, zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C), @@ -1246,7 +1228,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_OPCODE: { - phpdbg_notice("Breakpoint #%d in %s at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" opcode=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s at %s:%u, hits: %lu", ((phpdbg_breakop_t*)brake)->id, ((phpdbg_breakop_t*)brake)->name, zend_get_executed_filename(TSRMLS_C), @@ -1255,7 +1237,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_METHOD: { - phpdbg_notice("Breakpoint #%d in %s::%s() at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" method=\"%s::%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s::%s() at %s:%u, hits: %lu", ((phpdbg_breakmethod_t*)brake)->id, ((phpdbg_breakmethod_t*)brake)->class_name, ((phpdbg_breakmethod_t*)brake)->func_name, @@ -1267,7 +1249,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* case PHPDBG_BREAK_COND: { if (((phpdbg_breakcond_t*)brake)->paramed) { char *param; - phpdbg_notice("Conditional breakpoint #%d: at %s if %s %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" location=\"%s\" eval=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Conditional breakpoint #%d: at %s if %s at %s:%u, hits: %lu", ((phpdbg_breakcond_t*)brake)->id, phpdbg_param_tostring(&((phpdbg_breakcond_t*)brake)->param, ¶m TSRMLS_CC), ((phpdbg_breakcond_t*)brake)->code, @@ -1277,7 +1259,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* if (param) free(param); } else { - phpdbg_notice("Conditional breakpoint #%d: on %s == true %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" eval=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Conditional breakpoint #%d: on %s == true at %s:%u, hits: %lu", ((phpdbg_breakcond_t*)brake)->id, ((phpdbg_breakcond_t*)brake)->code, zend_get_executed_filename(TSRMLS_C), @@ -1289,7 +1271,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* default: { unknown: - phpdbg_notice("Unknown breakpoint at %s:%u", + phpdbg_notice("breakpoint", "id=\"\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Unknown breakpoint at %s:%u", zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C)); } @@ -1350,17 +1332,19 @@ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ { + phpdbg_xml(""); + switch (type) { case PHPDBG_BREAK_SYM: if ((PHPDBG_G(flags) & PHPDBG_HAS_SYM_BP)) { HashPosition position; phpdbg_breaksymbol_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Function Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Function Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], (void**) &brake, &position) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position)) { - phpdbg_writeln("#%d\t\t%s%s", + phpdbg_writeln("function", "id=\"%d\" name=\"%s\" disabled=\"%s\"", "#%d\t\t%s%s", brake->id, brake->symbol, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } @@ -1373,8 +1357,8 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ zend_uint class_len = 0; zend_ulong class_idx = 0L; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Method Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Method Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0]); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], (void**) &class_table, &position[0]) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0])) { @@ -1386,7 +1370,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]); zend_hash_get_current_data_ex(class_table, (void**)&brake, &position[1]) == SUCCESS; zend_hash_move_forward_ex(class_table, &position[1])) { - phpdbg_writeln("#%d\t\t%s::%s%s", + phpdbg_writeln("method", "id=\"%d\" name=\"%s::%s\" disabled=\"%s\"", "#%d\t\t%s::%s%s", brake->id, brake->class_name, brake->func_name, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } @@ -1399,8 +1383,8 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ HashPosition position[2]; HashTable *points; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("File Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("File Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0]); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], (void**) &points, &position[0]) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0])) { @@ -1409,7 +1393,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ for (zend_hash_internal_pointer_reset_ex(points, &position[1]); zend_hash_get_current_data_ex(points, (void**)&brake, &position[1]) == SUCCESS; zend_hash_move_forward_ex(points, &position[1])) { - phpdbg_writeln("#%d\t\t%s:%lu%s", + phpdbg_writeln("file", "id=\"%d\" name=\"%s\" line=\"%lu\" disabled=\"%s\"", "#%d\t\t%s:%lu%s", brake->id, brake->filename, brake->line, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } @@ -1421,8 +1405,8 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ HashPosition position; phpdbg_breakline_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Opline Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Opline Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void**) &brake, &position) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position)) { @@ -1430,16 +1414,16 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ case PHPDBG_BREAK_METHOD_OPLINE: case PHPDBG_BREAK_FUNCTION_OPLINE: case PHPDBG_BREAK_FILE_OPLINE: - phpdbg_writeln("#%d\t\t%#lx\t\t(%s breakpoint)%s", brake->id, brake->opline, - brake->type == PHPDBG_BREAK_METHOD_OPLINE?"method": - brake->type == PHPDBG_BREAK_FUNCTION_OPLINE?"function": - brake->type == PHPDBG_BREAK_FILE_OPLINE?"file": + phpdbg_writeln("opline", "id=\"%d\" num=\"%#lx\" type=\"%s\" disabled=\"%s\"", "#%d\t\t%#lx\t\t(%s breakpoint)%s", brake->id, brake->opline, + brake->type == PHPDBG_BREAK_METHOD_OPLINE ? "method" : + brake->type == PHPDBG_BREAK_FUNCTION_OPLINE ? "function" : + brake->type == PHPDBG_BREAK_FILE_OPLINE ? "file" : "--- error ---", ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); break; default: - phpdbg_writeln("#%d\t\t%#lx", brake->id, brake->opline); + phpdbg_writeln("opline", "id=\"%d\" num=\"%#lx\" disabled=\"%s\"", "#%d\t\t%#lx%s", brake->id, brake->opline, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); break; } } @@ -1452,8 +1436,8 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ zend_uint class_len = 0, method_len = 0; zend_ulong class_idx = 0L, method_idx = 0L; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Method opline Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Method opline Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0]); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], (void**) &class_table, &position[0]) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0])) { @@ -1473,7 +1457,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ for (zend_hash_internal_pointer_reset_ex(method_table, &position[2]); zend_hash_get_current_data_ex(method_table, (void**)&brake, &position[2]) == SUCCESS; zend_hash_move_forward_ex(method_table, &position[2])) { - phpdbg_writeln("#%d\t\t%s::%s opline %ld%s", + phpdbg_writeln("methodopline", "id=\"%d\" name=\"%s::%s\" num=\"%ld\" disabled=\"%s\"", "#%d\t\t%s::%s opline %ld%s", brake->id, brake->class_name, brake->func_name, brake->opline_num, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } @@ -1491,8 +1475,8 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ zend_uint function_len = 0; zend_ulong function_idx = 0L; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Function opline Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Function opline Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0]); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], (void**) &function_table, &position[0]) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0])) { @@ -1505,7 +1489,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ for (zend_hash_internal_pointer_reset_ex(function_table, &position[1]); zend_hash_get_current_data_ex(function_table, (void**)&brake, &position[1]) == SUCCESS; zend_hash_move_forward_ex(function_table, &position[1])) { - phpdbg_writeln("#%d\t\t%s opline %ld%s", + phpdbg_writeln("functionopline", "id=\"%d\" name=\"%s\" num=\"%ld\" disabled=\"%s\"", "#%d\t\t%s opline %ld%s", brake->id, brake->func_name, brake->opline_num, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } @@ -1521,8 +1505,8 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ zend_uint file_len = 0; zend_ulong file_idx = 0L; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("File opline Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("File opline Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0]); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], (void**) &file_table, &position[0]) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0])) { @@ -1535,7 +1519,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ for (zend_hash_internal_pointer_reset_ex(file_table, &position[1]); zend_hash_get_current_data_ex(file_table, (void**)&brake, &position[1]) == SUCCESS; zend_hash_move_forward_ex(file_table, &position[1])) { - phpdbg_writeln("#%d\t\t%s opline %ld%s", + phpdbg_writeln("fileopline", "id=\"%d\" name=\"%s\" num=\"%ld\" disabled=\"%s\"", "#%d\t\t%s opline %ld%s", brake->id, brake->class_name, brake->opline_num, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } @@ -1547,15 +1531,15 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ HashPosition position; phpdbg_breakcond_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Conditional Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Conditional Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void**) &brake, &position) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { if (brake->paramed) { switch (brake->param.type) { case STR_PARAM: - phpdbg_writeln("#%d\t\tat %s if %s%s", + phpdbg_writeln("evalfunction", "id=\"%d\" name=\"%s\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s if %s%s", brake->id, brake->param.str, brake->code, @@ -1563,7 +1547,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ break; case NUMERIC_FUNCTION_PARAM: - phpdbg_writeln("#%d\t\tat %s#%ld if %s%s", + phpdbg_writeln("evalfunctionopline", "id=\"%d\" name=\"%s\" num=\"%ld\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s#%ld if %s%s", brake->id, brake->param.str, brake->param.num, @@ -1572,7 +1556,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ break; case METHOD_PARAM: - phpdbg_writeln("#%d\t\tat %s::%s if %s%s", + phpdbg_writeln("evalmethod", "id=\"%d\" name=\"%s::%s\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s::%s if %s%s", brake->id, brake->param.method.class, brake->param.method.name, @@ -1581,7 +1565,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ break; case NUMERIC_METHOD_PARAM: - phpdbg_writeln("#%d\t\tat %s::%s#%ld if %s%s", + phpdbg_writeln("evalmethodopline", "id=\"%d\" name=\"%s::%s\" num=\"%d\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s::%s#%ld if %s%s", brake->id, brake->param.method.class, brake->param.method.name, @@ -1591,7 +1575,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ break; case FILE_PARAM: - phpdbg_writeln("#%d\t\tat %s:%lu if %s%s", + phpdbg_writeln("evalfile", "id=\"%d\" name=\"%s\" line=\"%d\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s:%lu if %s%s", brake->id, brake->param.file.name, brake->param.file.line, @@ -1600,7 +1584,7 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ break; case ADDR_PARAM: - phpdbg_writeln("#%d\t\tat #%lx if %s%s", + phpdbg_writeln("evalopline", "id=\"%d\" opline=\"%#lx\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat #%lx if %s%s", brake->id, brake->param.addr, brake->code, @@ -1608,11 +1592,11 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ break; default: - phpdbg_error("Invalid parameter type for conditional breakpoint"); + phpdbg_error("eval", "type=\"invalidparameter\"", "Invalid parameter type for conditional breakpoint"); return; } } else { - phpdbg_writeln("#%d\t\tif %s%s", + phpdbg_writeln("eval", "id=\"%d\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tif %s%s", brake->id, brake->code, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } @@ -1623,15 +1607,17 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ HashPosition position; phpdbg_breakop_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Opcode Breakpoints:"); + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Opcode Breakpoints:\n"); for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position); zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], (void**) &brake, &position) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position)) { - phpdbg_writeln("#%d\t\t%s%s", + phpdbg_writeln("opcode", "id=\"%d\" name=\"%s\" disabled=\"%s\"", "#%d\t\t%s%s", brake->id, brake->name, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } } break; } + + phpdbg_xml(""); } /* }}} */ diff --git a/phpdbg_bp.h b/phpdbg_bp.h index 97980e7ed7..a6227cba6c 100644 --- a/phpdbg_bp.h +++ b/phpdbg_bp.h @@ -21,6 +21,19 @@ #ifndef PHPDBG_BP_H #define PHPDBG_BP_H +/* {{{ defines */ +#define PHPDBG_BREAK_FILE 0 +#define PHPDBG_BREAK_SYM 1 +#define PHPDBG_BREAK_OPLINE 2 +#define PHPDBG_BREAK_METHOD 3 +#define PHPDBG_BREAK_COND 4 +#define PHPDBG_BREAK_OPCODE 5 +#define PHPDBG_BREAK_FUNCTION_OPLINE 6 +#define PHPDBG_BREAK_METHOD_OPLINE 7 +#define PHPDBG_BREAK_FILE_OPLINE 8 +#define PHPDBG_BREAK_MAP 9 +#define PHPDBG_BREAK_TABLES 10 /* }}} */ + /* {{{ */ typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */ diff --git a/phpdbg_break.c b/phpdbg_break.c index be76b22b05..386d4d9562 100644 --- a/phpdbg_break.c +++ b/phpdbg_break.c @@ -28,15 +28,15 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[10]) +#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[10], flags) /** * Commands */ const phpdbg_command_t phpdbg_break_commands[] = { - PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c"), - PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n"), + PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c", 0), + PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n", 0), PHPDBG_END_COMMAND }; diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index a45513bee6..30ea48cfbe 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -23,6 +23,7 @@ #include "phpdbg_utils.h" #include "phpdbg_set.h" #include "phpdbg_prompt.h" +#include "phpdbg_io.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -39,7 +40,7 @@ static inline const char *phpdbg_command_name(const phpdbg_command_t *command, c memcpy(&buffer[pos], command->name, command->name_len); pos += command->name_len; buffer[pos] = 0; - + return buffer; } @@ -231,12 +232,12 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des case STACK_PARAM: /* nope */ break; - + case STR_PARAM: dest->str = estrndup(src->str, src->len); dest->len = src->len; break; - + case OP_PARAM: dest->str = estrndup(src->str, src->len); dest->len = src->len; @@ -276,7 +277,7 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des break; case EMPTY_PARAM: { /* do nothing */ } break; - + default: { /* not yet */ } @@ -291,7 +292,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) / case STACK_PARAM: /* nope */ break; - + case STR_PARAM: hash += zend_inline_hash_func(param->str, param->len); break; @@ -329,7 +330,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) / break; case EMPTY_PARAM: { /* do nothing */ } break; - + default: { /* not yet */ } @@ -347,7 +348,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa /* nope, or yep */ return 1; break; - + case NUMERIC_FUNCTION_PARAM: if (l->num != r->num) { break; @@ -402,7 +403,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa case EMPTY_PARAM: return 1; - + default: { /* not yet */ } @@ -419,43 +420,43 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) case STR_PARAM: fprintf(stderr, "%s STR_PARAM(%s=%lu)\n", msg, param->str, param->len); break; - + case ADDR_PARAM: fprintf(stderr, "%s ADDR_PARAM(%lu)\n", msg, param->addr); break; - + case NUMERIC_FILE_PARAM: fprintf(stderr, "%s NUMERIC_FILE_PARAM(%s:#%lu)\n", msg, param->file.name, param->file.line); break; - + case FILE_PARAM: fprintf(stderr, "%s FILE_PARAM(%s:%lu)\n", msg, param->file.name, param->file.line); break; - + case METHOD_PARAM: fprintf(stderr, "%s METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); break; - + case NUMERIC_METHOD_PARAM: fprintf(stderr, "%s NUMERIC_METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); break; - + case NUMERIC_FUNCTION_PARAM: fprintf(stderr, "%s NUMERIC_FUNCTION_PARAM(%s::%ld)\n", msg, param->str, param->num); break; - + case NUMERIC_PARAM: fprintf(stderr, "%s NUMERIC_PARAM(%ld)\n", msg, param->num); break; - + case COND_PARAM: fprintf(stderr, "%s COND_PARAM(%s=%lu)\n", msg, param->str, param->len); break; - + case OP_PARAM: fprintf(stderr, "%s OP_PARAM(%s=%lu)\n", msg, param->str, param->len); break; - + default: { /* not yet */ } @@ -467,13 +468,13 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) { if (stack && stack->next) { phpdbg_param_t *remove = stack->next; - + while (remove) { phpdbg_param_t *next = NULL; - + if (remove->next) next = remove->next; - + switch (remove->type) { case NUMERIC_METHOD_PARAM: case METHOD_PARAM: @@ -487,29 +488,30 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) { case STR_PARAM: case OP_PARAM: if (remove->str) - free(remove->str); + free(remove->str); break; - + case NUMERIC_FILE_PARAM: case FILE_PARAM: if (remove->file.name) free(remove->file.name); break; - + default: { /* nothing */ } } - + free(remove); remove = NULL; - + if (next) - remove = next; + remove = next; else break; } } - + + stack->next = NULL; } /* }}} */ @@ -537,30 +539,29 @@ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param) stack->len++; } /* }}} */ -PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC) { +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC) { if (command) { char buffer[128] = {0,}; const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL; const char *arg = command->args; size_t least = 0L, - received = 0L, - current = 0L; + received = 0L, + current = 0L; zend_bool optional = 0; - + /* check for arg spec */ if (!(arg) || !(*arg)) { if (!top) { return SUCCESS; } - - asprintf(why, - "The command \"%s\" expected no arguments", + + phpdbg_error("command", "type=\"toomanyargs\" command=\"%s\" expected=\"0\"", "The command \"%s\" expected no arguments", phpdbg_command_name(command, buffer)); return FAILURE; } - + least = 0L; - + /* count least amount of arguments */ while (arg && *arg) { if (arg[0] == '|') { @@ -569,21 +570,19 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param least++; arg++; } - + arg = command->args; #define verify_arg(e, a, t) if (!(a)) { \ if (!optional) { \ - asprintf(why, \ - "The command \"%s\" expected %s and got nothing at parameter %lu", \ + phpdbg_error("command", "type=\"noarg\" command=\"%s\" expected=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got nothing at parameter %lu", \ phpdbg_command_name(command, buffer), \ (e), \ current); \ return FAILURE;\ } \ } else if ((a)->type != (t)) { \ - asprintf(why, \ - "The command \"%s\" expected %s and got %s at parameter %lu", \ + phpdbg_error("command", "type=\"wrongarg\" command=\"%s\" expected=\"%s\" got=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got %s at parameter %lu", \ phpdbg_command_name(command, buffer), \ (e),\ phpdbg_get_param_type((a) TSRMLS_CC), \ @@ -593,14 +592,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param while (arg && *arg) { current++; - + switch (*arg) { case '|': { current--; optional = 1; arg++; } continue; - + case 'i': verify_arg("raw input", top, STR_PARAM); break; case 's': verify_arg("string", top, STR_PARAM); break; case 'n': verify_arg("number", top, NUMERIC_PARAM); break; @@ -610,14 +609,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param case 'c': verify_arg("condition", top, COND_PARAM); break; case 'o': verify_arg("opcode", top, OP_PARAM); break; case 'b': verify_arg("boolean", top, NUMERIC_PARAM); break; - + case '*': { /* do nothing */ } break; } - + if (top ) { top = top->next; } else break; - + received++; arg++; } @@ -625,28 +624,27 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param #undef verify_arg if ((received < least)) { - asprintf(why, - "The command \"%s\" expected at least %lu arguments (%s) and received %lu", + phpdbg_error("command", "type=\"toofewargs\" command=\"%s\" expected=\"%d\" argtypes=\"%s\" got=\"%d\"", "The command \"%s\" expected at least %lu arguments (%s) and received %lu", phpdbg_command_name(command, buffer), least, - command->args, + command->args, received); return FAILURE; } } - + return SUCCESS; } /* {{{ */ -PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why) { +PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC) { const phpdbg_command_t *command = commands; phpdbg_param_t *name = *top; const phpdbg_command_t *matched[3] = {NULL, NULL, NULL}; ulong matches = 0L; - + while (command && command->name && command->handler) { - if ((name->len == 1) || (command->name_len >= name->len)) { + if (name->len == 1 || command->name_len >= name->len) { /* match single letter alias */ if (command->alias && (name->len == 1)) { if (command->alias == (*name->str)) { @@ -654,85 +652,76 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t * matches++; } } else { - /* match full, case insensitive, command name */ if (strncasecmp(command->name, name->str, name->len) == SUCCESS) { if (matches < 3) { - /* only allow abbreviating commands that can be aliased */ - if (((name->len != command->name_len) && command->alias) || - (name->len == command->name_len)) { + if ((name->len != command->name_len && command->alias) || name->len == command->name_len) { matched[matches] = command; matches++; } - - + /* exact match */ - if (name->len == command->name_len) + if (name->len == command->name_len) { break; - } else break; + } + } else { + break; + } } } } - + command++; } - + switch (matches) { - case 0: { + case 0: if (parent) { - asprintf( - why, - "The command \"%s %s\" could not be found", - parent->name, name->str); - } else asprintf( - why, - "The command \"%s\" could not be found", - name->str); - } return parent; - - case 1: { + phpdbg_error("command", "type=\"notfound\" command=\"%s\" subcommand=\"%s\"", "The command \"%s %s\" could not be found", parent->name, name->str); + } else { + phpdbg_error("command", "type=\"notfound\" command=\"%s\"", "The command \"%s\" could not be found", name->str); + } + return parent; + + case 1: (*top) = (*top)->next; command = matched[0]; - } break; - + break; + default: { char *list = NULL; zend_uint it = 0; size_t pos = 0; - + while (it < matches) { if (!list) { - list = malloc( - matched[it]->name_len + 1 + - ((it+1) < matches ? sizeof(", ")-1 : 0)); + list = emalloc(matched[it]->name_len + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0)); } else { - list = realloc(list, - (pos + matched[it]->name_len) + 1 + - ((it+1) < matches ? sizeof(", ")-1 : 0)); + list = erealloc(list, (pos + matched[it]->name_len) + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0)); } memcpy(&list[pos], matched[it]->name, matched[it]->name_len); pos += matched[it]->name_len; - if ((it+1) < matches) { - memcpy(&list[pos], ", ", sizeof(", ")-1); + if ((it + 1) < matches) { + memcpy(&list[pos], ", ", sizeof(", ") - 1); pos += (sizeof(", ") - 1); } - + list[pos] = 0; it++; } - - asprintf( - why, - "The command \"%s\" is ambigious, matching %lu commands (%s)", - name->str, matches, list); - free(list); - } return NULL; + + /* ", " separated matches */ + phpdbg_error("command", "type=\"ambiguous\" command=\"%s\" matches=\"%lu\" matched=\"%s\"", "The command \"%s\" is ambigious, matching %lu commands (%s)", name->str, matches, list); + efree(list); + + return NULL; + } } if (command->subs && (*top) && ((*top)->type == STR_PARAM)) { - return phpdbg_stack_resolve(command->subs, command, top, why); + return phpdbg_stack_resolve(command->subs, command, top TSRMLS_CC); } else { return command; } @@ -741,103 +730,148 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t * } /* }}} */ /* {{{ */ -PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) { +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC) { phpdbg_param_t *top = NULL; const phpdbg_command_t *handler = NULL; - + if (stack->type != STACK_PARAM) { - asprintf( - why, "The passed argument was not a stack !!"); + phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !"); return FAILURE; } - + if (!stack->len) { - asprintf( - why, "The stack contains nothing !!"); + phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !"); return FAILURE; } - - top = (phpdbg_param_t*) stack->next; - + + top = (phpdbg_param_t *) stack->next; + switch (top->type) { case EVAL_PARAM: + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC); case RUN_PARAM: + if (!allow_async_unsafe) { + phpdbg_error("signalsegv", "command=\"run\"", "run command is disallowed during hard interrupt"); + } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return PHPDBG_COMMAND_HANDLER(run)(top TSRMLS_CC); - + case SHELL_PARAM: + if (!allow_async_unsafe) { + phpdbg_error("signalsegv", "command=\"sh\"", "sh command is disallowed during hard interrupt"); + return FAILURE; + } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return PHPDBG_COMMAND_HANDLER(sh)(top TSRMLS_CC); - + case STR_PARAM: { - handler = phpdbg_stack_resolve( - phpdbg_prompt_commands, NULL, &top, why); - + handler = phpdbg_stack_resolve(phpdbg_prompt_commands, NULL, &top TSRMLS_CC); + if (handler) { - if (phpdbg_stack_verify(handler, &top, why TSRMLS_CC) == SUCCESS) { + if (!allow_async_unsafe && !(handler->flags & PHPDBG_ASYNC_SAFE)) { + phpdbg_error("signalsegv", "command=\"%s\"", "%s command is disallowed during hard interrupt", handler->name); + return FAILURE; + } + + if (phpdbg_stack_verify(handler, &top TSRMLS_CC) == SUCCESS) { + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return handler->handler(top TSRMLS_CC); } } } return FAILURE; - + default: - asprintf( - why, "The first parameter makes no sense !!"); + phpdbg_error("command", "type=\"invalidcommand\"", "The first parameter makes no sense !"); return FAILURE; } - + return SUCCESS; } /* }}} */ -PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ +PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { char *cmd = NULL; -#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) - char buf[PHPDBG_MAX_CMD]; -#endif char *buffer = NULL; if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && - (buffered == NULL)) { - fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) { + fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); } if (buffered == NULL) { -disconnect: if (0) { +disconnect: PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); zend_bailout(); return NULL; } -#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) - if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { - if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) { +#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)) + + /* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */ + /* strongly assuming to be in blocking mode... */ +#if USE_LIB_STAR +readline: + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) +#endif + { + char buf[PHPDBG_MAX_CMD]; + int bytes = PHPDBG_G(input_buflen), len = 0; + if (PHPDBG_G(input_buflen)) { + memcpy(buf, PHPDBG_G(input_buffer), bytes); + } + + phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C)); + PHPDBG_G(last_was_newline) = 1; + + do { + int i; + if (bytes <= 0) { + continue; + } + + for (i = len; i < len + bytes; i++) { + if (buf[i] == '\x03') { + if (i != len + bytes - 1) { + memmove(buf + i, buf + i + 1, len + bytes - i - 1); + } + len--; + i--; + continue; + } + if (buf[i] == '\n') { + PHPDBG_G(input_buflen) = len + bytes - 1 - i; + if (PHPDBG_G(input_buflen)) { + memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen)); + } + if (i != PHPDBG_MAX_CMD - 1) { + buf[i + 1] = 0; + } + cmd = buf; + goto end; + } + } + len += bytes; + /* XXX export the timeout through INI??*/ + } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0); + + if (bytes <= 0) { goto disconnect; } + + cmd = buf; } - - /* note: EOF is ignored */ -readline: - if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { - /* the user has gone away */ - if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { - goto disconnect; - } else goto readline; +#if USE_LIB_STAR + else { + cmd = readline(phpdbg_get_prompt(TSRMLS_C)); } - cmd = buf; -#else - /* note: EOF makes readline write prompt again in local console mode */ -readline: - if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { - char buf[PHPDBG_MAX_CMD]; - if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { - cmd = buf; - } else goto disconnect; - } else cmd = readline(phpdbg_get_prompt(TSRMLS_C)); - if (!cmd) { goto readline; } @@ -846,13 +880,15 @@ readline: add_history(cmd); } #endif - } else cmd = buffered; - + } else { + cmd = buffered; + } +end: + PHPDBG_G(last_was_newline) = 1; buffer = estrdup(cmd); -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) - if (!buffered && cmd && - !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { +#if USE_LIB_STAR + if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { free(cmd); } #endif @@ -878,7 +914,7 @@ readline: buffer = estrdup(PHPDBG_G(buffer)); } } - + return buffer; } /* }}} */ @@ -886,4 +922,3 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */ { efree(*input); } /* }}} */ - diff --git a/phpdbg_cmd.h b/phpdbg_cmd.h index 571d065f59..3896551c9a 100644 --- a/phpdbg_cmd.h +++ b/phpdbg_cmd.h @@ -86,6 +86,8 @@ struct _phpdbg_param { #define YYSTYPE phpdbg_param_t #endif +#define PHPDBG_ASYNC_SAFE 1 + typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t* TSRMLS_DC); typedef struct _phpdbg_command_t phpdbg_command_t; @@ -97,8 +99,9 @@ struct _phpdbg_command_t { char alias; /* Alias */ phpdbg_command_handler_t handler; /* Command handler */ const phpdbg_command_t *subs; /* Sub Commands */ - char *args; /* Argument Spec */ - const phpdbg_command_t *parent; /* Parent Command */ + char *args; /* Argument Spec */ + const phpdbg_command_t *parent; /* Parent Command */ + zend_bool flags; /* General flags */ }; /* }}} */ @@ -106,7 +109,7 @@ struct _phpdbg_command_t { #define PHPDBG_STRL(s) s, sizeof(s)-1 #define PHPDBG_MAX_CMD 500 #define PHPDBG_FRAME(v) (PHPDBG_G(frame).v) -#define PHPDBG_EX(v) (EG(current_execute_data)->v) +#define PHPDBG_EX(v) (EG(current_execute_data)->v) typedef struct { int num; @@ -133,9 +136,9 @@ PHPDBG_API void phpdbg_destroy_input(char** TSRMLS_DC); * Stack Management */ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, 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, char **why); -PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC); -PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC); +PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC); +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC); +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC); PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack); /* @@ -155,27 +158,27 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) */ #define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name -#define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent} +#define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent, flags) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent, flags} -#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL} +#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args, flags) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL, flags} -#define PHPDBG_COMMAND_D(name, tip, alias, children, args) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL} +#define PHPDBG_COMMAND_D(name, tip, alias, children, args, flags) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL, flags} #define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param TSRMLS_DC) #define PHPDBG_COMMAND_ARGS param TSRMLS_CC -#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0', NULL} +#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, NULL, NULL, 0} /* * Default Switch Case */ #define phpdbg_default_switch_case() \ default: \ - phpdbg_error("Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \ + phpdbg_error("command", "type=\"wrongarg\" got=\"%s\"", "Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \ break #endif /* PHPDBG_CMD_H */ diff --git a/phpdbg_eol.c b/phpdbg_eol.c new file mode 100644 index 0000000000..fc20d567bc --- /dev/null +++ b/phpdbg_eol.c @@ -0,0 +1,172 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "phpdbg.h" +#include "phpdbg_eol.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +#define EOL_LIST_LEN 4 +struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = { + {"CRLF", "\r\n", PHPDBG_EOL_CRLF}, +/* {"LFCR", "\n\r", PHPDBG_EOL_LFCR},*/ + {"LF", "\n", PHPDBG_EOL_LF}, + {"CR", "\r", PHPDBG_EOL_CR}, +}; + +int phpdbg_eol_global_update(char *name TSRMLS_DC) +{ + + if (0 == memcmp(name, "CRLF", 4) || 0 == memcmp(name, "crlf", 4) || 0 == memcmp(name, "DOS", 3) || 0 == memcmp(name, "dos", 3)) { + PHPDBG_G(eol) = PHPDBG_EOL_CRLF; + } else if (0 == memcmp(name, "LF", 2) || 0 == memcmp(name, "lf", 2) || 0 == memcmp(name, "UNIX", 4) || 0 == memcmp(name, "unix", 4)) { + PHPDBG_G(eol) = PHPDBG_EOL_LF; + } else if (0 == memcmp(name, "CR", 2) || 0 == memcmp(name, "cr", 2) || 0 == memcmp(name, "MAC", 3) || 0 == memcmp(name, "mac", 3)) { + PHPDBG_G(eol) = PHPDBG_EOL_CR; + } else { + return FAILURE; + } + + return SUCCESS; +} + +char *phpdbg_eol_name(int id) +{ + size_t i = 0; + + while (i < EOL_LIST_LEN) { + + if (id == phpdbg_eol_list[i].id) { + return phpdbg_eol_list[i].name; + } + + i++; + } + + return NULL; +} + +char *phpdbg_eol_rep(int id) +{ + size_t i = 0; + + while (i < EOL_LIST_LEN) { + + if (id == phpdbg_eol_list[i].id) { + return phpdbg_eol_list[i].rep; + } + + i++; + } + + return NULL; +} + + +/* Inspired by https://ccrma.stanford.edu/~craig/utility/flip/flip.cpp */ +void phpdbg_eol_convert(char **str, int *len TSRMLS_DC) +{ + char *in = *str, *out ; + int in_len = *len, out_len, cursor, i; + char last, cur; + + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) != PHPDBG_IS_REMOTE) { + return; + } + + out_len = *len; + if (PHPDBG_EOL_CRLF == PHPDBG_G(eol)) { /* XXX add LFCR case if it's gonna be needed */ + /* depending on the source EOL the out str will have all CR/LF duplicated */ + for (i = 0; i < in_len; i++) { + if (0x0a == in[i] || 0x0d == in[i]) { + out_len++; + } + } + out = (char *)emalloc(out_len); + + last = cur = in[0]; + i = cursor = 0; + for (; i < in_len;) { + if (0x0a == cur && last != 0x0d) { + out[cursor] = 0x0d; + cursor++; + out[cursor] = cur; + } else if(0x0d == cur) { + if (i + 1 < in_len && 0x0a != in[i+1]) { + out[cursor] = cur; + cursor++; + out[cursor] = 0x0a; + last = 0x0a; + } else { + out[cursor] = 0x0d; + last = 0x0d; + } + } else { + out[cursor] = cur; + last = cur; + } + + i++; + cursor++; + cur = in[i]; + } + + } else if (PHPDBG_EOL_LF == PHPDBG_G(eol) || PHPDBG_EOL_CR == PHPDBG_G(eol)) { + char want, kick; + + if (PHPDBG_EOL_LF == PHPDBG_G(eol)) { + want = 0x0a; + kick = 0x0d; + } else { + want = 0x0d; + kick = 0x0a; + } + + /* We gonna have a smaller or equally long string, estimation is almost neglecting */ + out = (char *)emalloc(out_len); + + last = cur = in[0]; + i = cursor = 0; + for (; cursor < in_len;) { + if (kick == cur) { + out[cursor] = want; + } else if (want == cur) { + if (kick != last) { + out[cursor] = want; + } + } else { + out[cursor] = cur; + } + + last = cur; + cursor++; + cur = in[cursor]; + } + } else { + return; + } + + efree(*str); + *str = erealloc(out, cursor); + *len = cursor; + in = NULL; +} diff --git a/phpdbg_eol.h b/phpdbg_eol.h new file mode 100644 index 0000000000..68b54cbe34 --- /dev/null +++ b/phpdbg_eol.h @@ -0,0 +1,46 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_EOL_H +#define PHPDBG_EOL_H + +#include "phpdbg.h" + +struct phpdbg_eol_rep { + char *name; + char *rep; + int id; +}; + +enum { + PHPDBG_EOL_CRLF, /* DOS */ + /*PHPDBG_EOL_LFCR,*/ /* for Risc OS? */ + PHPDBG_EOL_LF, /* UNIX */ + PHPDBG_EOL_CR /* MAC */ +}; + +int phpdbg_eol_global_update(char *name TSRMLS_DC); + +char *phpdbg_eol_name(int id); + +char *phpdbg_eol_rep(int id); + +void phpdbg_eol_convert(char **str, int *len TSRMLS_DC); + +#endif /* PHPDBG_EOL_H */ + diff --git a/phpdbg_frame.c b/phpdbg_frame.c index a235fe8cb0..df304e3541 100644 --- a/phpdbg_frame.c +++ b/phpdbg_frame.c @@ -52,22 +52,27 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ int i = 0; if (PHPDBG_FRAME(num) == frame) { - phpdbg_notice("Already in frame #%d", frame); + phpdbg_notice("frame", "id=\"%d\"", "Already in frame #%d", frame); return; } - while (execute_data) { - if (i++ == frame) { - break; - } + phpdbg_try_access { + while (execute_data) { + if (i++ == frame) { + break; + } - do { - execute_data = execute_data->prev_execute_data; - } while (execute_data && execute_data->opline == NULL); - } + do { + execute_data = execute_data->prev_execute_data; + } while (execute_data && execute_data->opline == NULL); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Couldn't switch frames, invalid data source"); + return; + } phpdbg_end_try_access(); if (execute_data == NULL) { - phpdbg_error("No frame #%d", frame); + phpdbg_error("frame", "type=\"maxnum\" id=\"%d\"", "No frame #%d", frame); return; } @@ -90,7 +95,7 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ EG(called_scope) = PHPDBG_EX(current_called_scope); } - phpdbg_notice("Switched to frame #%d", frame); + phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame); phpdbg_list_file( zend_get_executed_filename(TSRMLS_C), 3, @@ -104,61 +109,84 @@ static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */ { zval **funcname, **class, **type, **args, **argstmp; char is_class; + int has_args = FAILURE; - zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"), - (void **)&funcname); + zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"), (void **) &funcname); - if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp), - "object", sizeof("object"), (void **)&class)) == FAILURE) { - is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"), - (void **)&class); + if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "object", sizeof("object"), (void **) &class)) == FAILURE) { + is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"), (void **)&class); } else { - zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class), - (zend_uint *)&Z_STRLEN_PP(class) TSRMLS_CC); + zend_get_object_classname(*class, (const char **) &Z_STRVAL_PP(class), (zend_uint *) &Z_STRLEN_PP(class) TSRMLS_CC); } if (is_class == SUCCESS) { zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type); } - phpdbg_write("%s%s%s(", + has_args = zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"), (void **)&args) == SUCCESS; + + phpdbg_xml(" symbol=\"%s%s%s\"", is_class == FAILURE?"":Z_STRVAL_PP(class), is_class == FAILURE?"":Z_STRVAL_PP(type), Z_STRVAL_PP(funcname) ); + if (has_args) { + phpdbg_xml(">"); + } else { + phpdbg_xml(" />"); + } - if (zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"), - (void **)&args) == SUCCESS) { + phpdbg_out("%s%s%s(", + is_class == FAILURE?"":Z_STRVAL_PP(class), + is_class == FAILURE?"":Z_STRVAL_PP(type), + Z_STRVAL_PP(funcname) + ); + + if (has_args) { HashPosition iterator; - const zend_function *func = phpdbg_get_function( - Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC); - const zend_arg_info *arginfo = func ? func->common.arg_info : NULL; - int j = 0, m = func ? func->common.num_args : 0; + const zend_function *func = NULL; + const zend_arg_info *arginfo = NULL; + int j = 0, m; zend_bool is_variadic = 0; + phpdbg_try_access { + /* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */ + if ((func = phpdbg_get_function(Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC))) { + arginfo = func->common.arg_info; + } + } phpdbg_end_try_access(); + + m = func ? func->common.num_args : 0; + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator); - while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args), - (void **) &argstmp, &iterator) == SUCCESS) { + while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args), (void **) &argstmp, &iterator) == SUCCESS) { if (j) { - phpdbg_write(", "); + phpdbg_out(", "); } + phpdbg_xml("= 50600 - is_variadic = arginfo[j].is_variadic; + is_variadic = arginfo ? arginfo[j].is_variadic : 0; #endif - phpdbg_write("%s=%s", - arginfo[j].name, is_variadic ? "[": ""); + phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arginfo ? arginfo[j].name : ""); + phpdbg_out("%s=%s", arginfo ? arginfo[j].name : "?", is_variadic ? "[": ""); + + } else { + phpdbg_xml(">"); } ++j; zend_print_flat_zval_r(*argstmp TSRMLS_CC); zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator); + + phpdbg_xml(""); } if (is_variadic) { - phpdbg_write("]"); + phpdbg_out("]"); } + phpdbg_xml(""); } - phpdbg_write(")"); + phpdbg_out(")"); } void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ @@ -171,36 +199,47 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ int user_defined; if (limit < 0) { - phpdbg_error("Invalid backtrace size %d", limit); + phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit); + return; } - zend_fetch_debug_backtrace( - &zbacktrace, 0, 0, limit TSRMLS_CC); + phpdbg_try_access { + zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit TSRMLS_CC); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Couldn't fetch backtrace, invalid data source"); + return; + } phpdbg_end_try_access(); + + phpdbg_xml(""); zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position); - zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position); + zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void **) &tmp, &position); while (1) { - user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file); - zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line); + user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **) &file); + zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **) &line); zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position); - if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), - (void**)&tmp, &position) == FAILURE) { - phpdbg_write("frame #%d: {main} at %s:%ld", i, Z_STRVAL_PP(file), Z_LVAL_PP(line)); + if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void **) &tmp, &position) == FAILURE) { + phpdbg_write("frame", "id=\"%d\" symbol=\"{main}\" file=\"%s\" line=\"%d\"", "frame #%d: {main} at %s:%ld", i, Z_STRVAL_PP(file), Z_LVAL_PP(line)); break; } if (user_defined == SUCCESS) { - phpdbg_write("frame #%d: ", i++); + phpdbg_out("frame #%d: ", i); + phpdbg_xml(" "); + phpdbg_out(" => "); + phpdbg_xml(""); + zval_dtor(&zbacktrace); } /* }}} */ diff --git a/phpdbg_help.c b/phpdbg_help.c index 1e58dc69ca..652e170694 100644 --- a/phpdbg_help.c +++ b/phpdbg_help.c @@ -22,6 +22,7 @@ #include "phpdbg.h" #include "phpdbg_help.h" #include "phpdbg_prompt.h" +#include "phpdbg_eol.h" #include "zend.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -61,6 +62,11 @@ void pretty_print(char *text TSRMLS_DC) unsigned int last_blank_count = 0; /* printable char offset of last blank char */ unsigned int line_count = 0; /* number printable chars on current line */ + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + phpdbg_xml("", text); + return; + } + /* First pass calculates a safe size for the pretty print version */ for (p = text; *p; p++) { if (UNEXPECTED(p[0] == '*') && p[1] == '*') { @@ -128,10 +134,10 @@ void pretty_print(char *text TSRMLS_DC) *q++ = '\0'; if ((q-new)>size) { - phpdbg_error("Output overrun of %lu bytes", ((q-new) - size)); + phpdbg_error("help", "overrun=\"%lu\"", "Output overrun of %lu bytes", ((q - new) - size)); } - phpdbg_write("%s\n", new); + phpdbg_out("%s\n", new); efree(new); } /* }}} */ @@ -201,7 +207,7 @@ static int get_command( return num_matches; -} /* }}} */ +} /* }}} */ PHPDBG_COMMAND(help) /* {{{ */ { @@ -231,7 +237,7 @@ PHPDBG_COMMAND(help) /* {{{ */ pretty_print(get_help("duplicate!" TSRMLS_CC) TSRMLS_CC); return SUCCESS; } else { - phpdbg_error("Internal help error, non-unique alias \"%c\"", param->str[0]); + phpdbg_error("help", "type=\"ambiguousalias\" alias=\"%s\"", "Internal help error, non-unique alias \"%c\"", param->str[0]); return FAILURE; } @@ -259,34 +265,41 @@ PHPDBG_HELP(aliases) /* {{{ */ int len; /* Print out aliases for all commands except help as this one comes last */ - phpdbg_writeln("Below are the aliased, short versions of all supported commands"); + phpdbg_writeln("help", "", "Below are the aliased, short versions of all supported commands"); + phpdbg_xml(""); for(c = phpdbg_prompt_commands; c->name; c++) { if (c->alias && c->alias != 'h') { - phpdbg_writeln(" %c %-20s %s", c->alias, c->name, c->tip); + phpdbg_writeln("command", "alias=\"%c\" name=\"%s\" tip=\"%s\"", " %c %-20s %s", c->alias, c->name, c->tip); if (c->subs) { len = 20 - 1 - c->name_len; for(c_sub = c->subs; c_sub->alias; c_sub++) { if (c_sub->alias) { - phpdbg_writeln(" %c %c %s %-*s %s", - c->alias, c_sub->alias, (char *)c->name, len, c_sub->name, c_sub->tip); + phpdbg_writeln("subcommand", "parent_alias=\"%c\" alias=\"%c\" parent=\"%s\" name=\"%-*s\" tip=\"%s\"", " %c %c %s %-*s %s", + c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip); } } } } } + phpdbg_xml(""); + /* Print out aliases for help as this one comes last, with the added text on how aliases are used */ get_command("h", 1, &c, phpdbg_prompt_commands TSRMLS_CC); - phpdbg_writeln(" %c %-20s %s\n", c->alias, c->name, c->tip); + phpdbg_writeln("aliasinfo", "alias=\"%c\" name=\"%s\" tip=\"%s\"", " %c %-20s %s\n", c->alias, c->name, c->tip); + + phpdbg_xml(""); len = 20 - 1 - c->name_len; for(c_sub = c->subs; c_sub->alias; c_sub++) { if (c_sub->alias) { - phpdbg_writeln(" %c %c %s %-*s %s", + phpdbg_writeln("alias", "parent_alias=\"%c\" alias=\"%c\" parent=\"%s\" name=\"%-*s\" tip=\"%s\"", " %c %c %s %-*s %s", c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip); } } + phpdbg_xml(""); + pretty_print(get_help("aliases!" TSRMLS_CC) TSRMLS_CC); return SUCCESS; } /* }}} */ @@ -307,7 +320,7 @@ PHPDBG_HELP(aliases) /* {{{ */ * Also note the convention that help text not directly referenceable as a help param * has a key ending in ! */ -#define CR "\n" +#define CR "\n" phpdbg_help_text_t phpdbg_help_text[] = { /******************************** General Help Topics ********************************/ @@ -362,7 +375,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { " **-c** **-c**/my/php.ini Set php.ini file to load" CR " **-d** **-d**memory_limit=4G Set a php.ini directive" CR " **-n** Disable default php.ini" CR -" **-q** Supress welcome banner" CR +" **-q** Suppress welcome banner" CR " **-v** Enable oplog output" CR " **-s** Enable stepping" CR " **-b** Disable colour" CR @@ -375,6 +388,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { " **-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 +" **-x** Enable xml output (instead of normal text output)" CR " **-V** Print version number" CR " **--** **--** arg1 arg2 Use to delimit phpdbg arguments and php $argv; append any $argv " "argument after it" CR CR @@ -386,9 +400,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { "bind address using the **-a** option. If **-a** is specied without an argument, then phpdbg " "will bind to all available interfaces. You should be aware of the security implications of " "doing this, so measures should be taken to secure this service if bound to a publicly accessible " -"interface/port." CR CR - -"Specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2." +"interface/port." }, {"phpdbginit", CR @@ -545,7 +557,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { " $P break ZEND_ADD" CR " $P b ZEND_ADD" CR -" Break on any occurence of the opcode ZEND_ADD" CR CR +" Break on any occurrence of the opcode ZEND_ADD" CR CR " $P break del 2" CR " $P b ~ 2" CR @@ -642,14 +654,16 @@ phpdbg_help_text_t phpdbg_help_text[] = { "Specific info commands are show below:" CR CR " **Target** **Alias** **Purpose**" CR -" **break** **b** show current breakpoints" CR -" **files** **F** show included files" CR -" **classes** **c** show loaded classes" CR -" **funcs** **f** show loaded classes" CR -" **error** **e** show last error" CR -" **vars** **v** show active variables" CR -" **literal** **l** show active literal constants" CR -" **memory** **m** show memory manager stats" +" **break** **b** show current breakpoints" CR +" **files** **F** show included files" CR +" **classes** **c** show loaded classes" CR +" **funcs** **f** show loaded functions" CR +" **error** **e** show last error" CR +" **constants** **d** show user-defined constants" CR +" **vars** **v** show active variables" CR +" **globals** **g** show superglobal variables" CR +" **literal** **l** show active literal constants" CR +" **memory** **m** show memory manager stats" }, // ******** same issue about breakpoints in called frames diff --git a/phpdbg_help.h b/phpdbg_help.h index 16a1e771e3..4a433fda6c 100644 --- a/phpdbg_help.h +++ b/phpdbg_help.h @@ -35,9 +35,9 @@ PHPDBG_HELP(aliases); extern const phpdbg_command_t phpdbg_help_commands[]; #define phpdbg_help_header() \ - phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); + phpdbg_notice("version", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); #define phpdbg_help_footer() \ - phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); + phpdbg_notice("issues", "url=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES); typedef struct _phpdbg_help_text_t { char *key; diff --git a/phpdbg_info.c b/phpdbg_info.c index 97f88bfa1e..4774fa5a9e 100644 --- a/phpdbg_info.c +++ b/phpdbg_info.c @@ -27,18 +27,20 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[14]) +#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[14], flags) const phpdbg_command_t phpdbg_info_commands[] = { - PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0), - PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0), - PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0), - PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0), - PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0), - PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0), - PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0), - PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0), + PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(constants, "show user defined constants", 'd', info_constants, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(globals, "show superglobals", 'g', info_globals, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0, PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; @@ -62,15 +64,21 @@ PHPDBG_INFO(files) /* {{{ */ HashPosition pos; char *fname; - phpdbg_notice("Included files: %d", - zend_hash_num_elements(&EG(included_files))); - - zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos); - while (zend_hash_get_current_key_ex(&EG(included_files), &fname, - NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { - phpdbg_writeln("File: %s", fname); - zend_hash_move_forward_ex(&EG(included_files), &pos); - } + phpdbg_try_access { + phpdbg_notice("includedfilecount", "num=\"%d\"", "Included files: %d", zend_hash_num_elements(&EG(included_files))); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Could not fetch included file count, invalid data source"); + } phpdbg_end_try_access(); + + phpdbg_try_access { + zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos); + while (zend_hash_get_current_key_ex(&EG(included_files), &fname, NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { + phpdbg_writeln("includedfile", "name=\"%s\"", "File: %s", fname); + zend_hash_move_forward_ex(&EG(included_files), &pos); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Could not fetch file name, invalid data source, aborting included file listing"); + } phpdbg_end_try_access(); return SUCCESS; } /* }}} */ @@ -78,23 +86,98 @@ PHPDBG_INFO(files) /* {{{ */ PHPDBG_INFO(error) /* {{{ */ { if (PG(last_error_message)) { - phpdbg_writeln("Last error: %s at %s line %d", - PG(last_error_message), PG(last_error_file), PG(last_error_lineno)); + phpdbg_try_access { + phpdbg_writeln("lasterror", "error=\"%s\" file=\"%s\" line=\"%d\"", "Last error: %s at %s line %d", PG(last_error_message), PG(last_error_file), PG(last_error_lineno)); + } phpdbg_catch_access { + phpdbg_notice("lasterror", "error=\"\"", "No error found!"); + } phpdbg_end_try_access(); } else { - phpdbg_notice("No error found!"); + phpdbg_notice("lasterror", "error=\"\"", "No error found!"); } return SUCCESS; } /* }}} */ -PHPDBG_INFO(vars) /* {{{ */ +PHPDBG_INFO(constants) /* {{{ */ { - HashTable vars; + HashPosition pos; + HashTable consts; + zend_constant *data; + + zend_hash_init(&consts, 8, NULL, NULL, 0); + + if (EG(zend_constants)) { + phpdbg_try_access { + zend_hash_internal_pointer_reset_ex(EG(zend_constants), &pos); + while (zend_hash_get_current_data_ex(EG(zend_constants), (void **) &data, &pos) == SUCCESS) { + if (data->module_number == PHP_USER_CONSTANT) { + zend_hash_update(&consts, data->name, data->name_len, (void **) &data, sizeof(zend_constant *), NULL); + } + zend_hash_move_forward_ex(EG(zend_constants), &pos); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Cannot fetch all the constants, invalid data source"); + } phpdbg_end_try_access(); + } + + phpdbg_notice("constantinfo", "num=\"%d\"", "User-defined constants (%d)", zend_hash_num_elements(&consts)); + + if (zend_hash_num_elements(&consts)) { + phpdbg_out("Address Refs Type Constant\n"); + for (zend_hash_internal_pointer_reset_ex(&consts, &pos); + zend_hash_get_current_data_ex(&consts, (void **) &data, &pos) == SUCCESS; + zend_hash_move_forward_ex(&consts, &pos)) { + data = *(zend_constant **) 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_REFCOUNT(data->value), zend_zval_type_name(&data->value), data->name_len - 1, 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 ? "..." : ""); + } phpdbg_catch_access { + VARIABLEINFO("", ""); + } phpdbg_end_try_access(); + break; + case IS_BOOL: + VARIABLEINFO("value=\"%s\"", "\nbool (%s)", Z_LVAL(data->value) ? "true" : "false"); + break; + case IS_LONG: + VARIABLEINFO("value=\"%ld\"", "\nint (%ld)", Z_LVAL(data->value)); + break; + case IS_DOUBLE: + VARIABLEINFO("value=\"%lf\"", "\ndouble (%lf)", Z_DVAL(data->value)); + break; + default: + VARIABLEINFO("", ""); + +#undef VARIABLEINFO + } + } + } + + return SUCCESS; +} /* }}} */ + +static int phpdbg_arm_auto_global(zend_auto_global *auto_global TSRMLS_DC) { + if (auto_global->armed) { + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", auto_global->name_len, auto_global->name); + } else { + auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC); + } + } + + return 0; +} + +static int phpdbg_print_symbols(zend_bool show_globals TSRMLS_DC) { + HashTable vars, *symtable; HashPosition pos; char *var; zval **data; if (!EG(active_op_array)) { - phpdbg_error("No active op array!"); + phpdbg_error("inactive", "type=\"op_array\"", "No active op array!"); return SUCCESS; } @@ -102,100 +185,112 @@ PHPDBG_INFO(vars) /* {{{ */ zend_rebuild_symbol_table(TSRMLS_C); if (!EG(active_symbol_table)) { - phpdbg_error("No active symbol table!"); + phpdbg_error("inactive", "type=\"symbol_table\"", "No active symbol table!"); return SUCCESS; } } + + if (show_globals) { + /* that array should only be manipulated during init, so safe for async access during execution */ + zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_arm_auto_global TSRMLS_CC); + symtable = &EG(symbol_table); + } else { + symtable = EG(active_symbol_table); + } + zend_hash_init(&vars, 8, NULL, NULL, 0); - zend_hash_internal_pointer_reset_ex(EG(active_symbol_table), &pos); - while (zend_hash_get_current_key_ex(EG(active_symbol_table), &var, - NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { - zend_hash_get_current_data_ex(EG(active_symbol_table), (void **)&data, &pos); - if (*var != '_') { - zend_hash_update( - &vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL); + phpdbg_try_access { + zend_hash_internal_pointer_reset_ex(symtable, &pos); + while (zend_hash_get_current_key_ex(symtable, &var, NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { + zend_hash_get_current_data_ex(symtable, (void **)&data, &pos); + if (zend_is_auto_global(var, strlen(var) TSRMLS_CC) ^ !show_globals) { + zend_hash_update(&vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL); + } + zend_hash_move_forward_ex(symtable, &pos); } - zend_hash_move_forward_ex(EG(active_symbol_table), &pos); - } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Cannot fetch all data from the symbol table, invalid data source"); + } phpdbg_end_try_access(); - { + if (show_globals) { + phpdbg_notice("variableinfo", "num=\"%d\"", "Superglobal variables (%d)", zend_hash_num_elements(&vars)); + } else { zend_op_array *ops = EG(active_op_array); - + if (ops->function_name) { if (ops->scope) { - phpdbg_notice( - "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "method=\"%s::%s\" num=\"%d\"", "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars)); } else { - phpdbg_notice( - "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "function=\"%s\" num=\"%d\"", "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars)); } } else { if (ops->filename) { - phpdbg_notice( - "Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "file=\"%s\" num=\"%d\"", "Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars)); } else { - phpdbg_notice( - "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "opline=\"%p\" num=\"%d\"", "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars)); } } } if (zend_hash_num_elements(&vars)) { - phpdbg_writeln("Address\t\tRefs\tType\t\tVariable"); + phpdbg_out("Address Refs Type Variable\n"); for (zend_hash_internal_pointer_reset_ex(&vars, &pos); - zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS; - zend_hash_move_forward_ex(&vars, &pos)) { + zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS; + zend_hash_move_forward_ex(&vars, &pos)) { char *var; + zend_bool invalid_data = 1; zend_hash_get_current_key_ex(&vars, &var, NULL, NULL, 0, &pos); - if (*data) { - phpdbg_write( - "%p\t%d\t", - *data, - Z_REFCOUNT_PP(data)); - - switch (Z_TYPE_PP(data)) { - case IS_STRING: phpdbg_write("(string)\t"); break; - case IS_LONG: phpdbg_write("(integer)\t"); break; - case IS_DOUBLE: phpdbg_write("(float)\t"); break; - case IS_RESOURCE: phpdbg_write("(resource)\t"); break; - case IS_ARRAY: phpdbg_write("(array)\t"); break; - case IS_OBJECT: phpdbg_write("(object)\t"); break; - case IS_NULL: phpdbg_write("(null)\t"); break; - } - - if (Z_TYPE_PP(data) == IS_RESOURCE) { - int type; - - phpdbg_writeln( - "%s$%s", Z_ISREF_PP(data) ? "&": "", var); - if (zend_list_find(Z_RESVAL_PP(data), &type)) { - phpdbg_write( - "|-------(typeof)------> (%s)", - zend_rsrc_list_get_rsrc_type(type TSRMLS_CC)); - } else { - phpdbg_write( - "|-------(typeof)------> (unknown)"); + phpdbg_try_access { + if (!(invalid_data = !*data)) { +#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_PP(data), zend_zval_type_name(*data), Z_ISREF_PP(data) ? "&": "", var, ##__VA_ARGS__) + + switch (Z_TYPE_PP(data)) { + case IS_RESOURCE: + phpdbg_try_access { + int type; + VARIABLEINFO("type=\"%s\"", "\n|-------(typeof)------> (%s)\n", zend_list_find(Z_RESVAL_PP(data), &type) ? zend_rsrc_list_get_rsrc_type(type TSRMLS_CC) : "unknown"); + } phpdbg_catch_access { + VARIABLEINFO("type=\"unknown\"", "\n|-------(typeof)------> (unknown)\n"); + } phpdbg_end_try_access(); + break; + case IS_OBJECT: + phpdbg_try_access { + VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (%s)\n", Z_OBJCE_PP(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_PP(data), Z_STRLEN_PP(data) < 255 ? Z_STRLEN_PP(data) : 255, Z_STRVAL_PP(data), Z_STRLEN_PP(data) > 255 ? "..." : ""); + } phpdbg_catch_access { + VARIABLEINFO("", ""); + } phpdbg_end_try_access(); + break; + case IS_BOOL: + VARIABLEINFO("value=\"%s\"", "\nbool (%s)", Z_LVAL_PP(data) ? "true" : "false"); + break; + case IS_LONG: + VARIABLEINFO("value=\"%ld\"", "\nint (%ld)", Z_LVAL_PP(data)); + break; + case IS_DOUBLE: + VARIABLEINFO("value=\"%lf\"", "\ndouble (%lf)", Z_DVAL_PP(data)); + break; + default: + VARIABLEINFO("", ""); } - phpdbg_writeln(EMPTY); - } else if (Z_TYPE_PP(data) == IS_OBJECT) { - phpdbg_writeln( - "%s$%s", Z_ISREF_PP(data) ? "&": "", var); - phpdbg_write( - "|-----(instanceof)----> (%s)", Z_OBJCE_PP(data)->name); - phpdbg_writeln(EMPTY); - } else { - phpdbg_write( - "%s$%s", Z_ISREF_PP(data) ? "&": "", var); } - } else { - phpdbg_write( - "n/a\tn/a\tn/a\t$%s", var); + +#undef VARIABLEINFO + } phpdbg_end_try_access(); + + if (invalid_data) { + phpdbg_writeln("variable", "name=\"%s\"", "n/a\tn/a\tn/a\t$%s", var); } - phpdbg_writeln(EMPTY); } } @@ -204,42 +299,47 @@ PHPDBG_INFO(vars) /* {{{ */ return SUCCESS; } /* }}} */ +PHPDBG_INFO(vars) /* {{{ */ +{ + return phpdbg_print_symbols(0 TSRMLS_CC); +} + +PHPDBG_INFO(globals) /* {{{ */ +{ + return phpdbg_print_symbols(1 TSRMLS_CC); +} + PHPDBG_INFO(literal) /* {{{ */ { + /* literals are assumed to not be manipulated during executing of their op_array and as such async safe */ if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) { zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops); int literal = 0, count = ops->last_literal-1; if (ops->function_name) { if (ops->scope) { - phpdbg_notice( - "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count); + phpdbg_notice("literalinfo", "method=\"%s::%s\" num=\"%d\"", "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count); } else { - phpdbg_notice( - "Literal Constants in %s() (%d)", ops->function_name, count); + phpdbg_notice("literalinfo", "function=\"%s\" num=\"%d\"", "Literal Constants in %s() (%d)", ops->function_name, count); } } else { if (ops->filename) { - phpdbg_notice( - "Literal Constants in %s (%d)", ops->filename, count); + phpdbg_notice("literalinfo", "file=\"%s\" num=\"%d\"", "Literal Constants in %s (%d)", ops->filename, count); } else { - phpdbg_notice( - "Literal Constants @ %p (%d)", ops, count); + phpdbg_notice("literalinfo", "opline=\"%p\" num=\"%d\"", "Literal Constants @ %p (%d)", ops, count); } } while (literal < ops->last_literal) { if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) { - phpdbg_write("|-------- C%u -------> [", literal); - zend_print_zval( - &ops->literals[literal].constant, 0); - phpdbg_write("]"); - phpdbg_writeln(EMPTY); + phpdbg_write("literal", "id=\"%u\"", "|-------- C%u -------> [", literal); + zend_print_zval(&ops->literals[literal].constant, 0); + phpdbg_out("]\n"); } literal++; } } else { - phpdbg_error("Not executing!"); + phpdbg_error("inactive", "type=\"execution\"", "Not executing!"); } return SUCCESS; @@ -247,28 +347,40 @@ PHPDBG_INFO(literal) /* {{{ */ PHPDBG_INFO(memory) /* {{{ */ { - if (is_zend_mm(TSRMLS_C)) { - phpdbg_notice("Memory Manager Information"); - phpdbg_notice("Current"); - phpdbg_writeln("|-------> Used:\t%.3f kB", - (float) (zend_memory_usage(0 TSRMLS_CC)/1024)); - phpdbg_writeln("|-------> Real:\t%.3f kB", - (float) (zend_memory_usage(1 TSRMLS_CC)/1024)); - phpdbg_notice("Peak"); - phpdbg_writeln("|-------> Used:\t%.3f kB", - (float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024)); - phpdbg_writeln("|-------> Real:\t%.3f kB", - (float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024)); + size_t used, real, peak_used, peak_real; + zend_mm_heap *heap; + zend_bool is_mm; + + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + heap = zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC); + } + if ((is_mm = is_zend_mm(TSRMLS_C))) { + used = zend_memory_usage(0 TSRMLS_CC); + real = zend_memory_usage(1 TSRMLS_CC); + peak_used = zend_memory_peak_usage(0 TSRMLS_CC); + peak_real = zend_memory_peak_usage(1 TSRMLS_CC); + } + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + zend_mm_set_heap(heap TSRMLS_CC); + } + + if (is_mm) { + phpdbg_notice("meminfo", "", "Memory Manager Information"); + phpdbg_notice("current", "", "Current"); + phpdbg_writeln("used", "mem=\"%.3f\"", "|-------> Used:\t%.3f kB", (float) (used / 1024)); + phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (real / 1024)); + phpdbg_notice("peak", "", "Peak"); + phpdbg_writeln("used", "mem=\"%.3f\"", "|-------> Used:\t%.3f kB", (float) (peak_used / 1024)); + phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (peak_real / 1024)); } else { - phpdbg_error("Memory Manager Disabled!"); + phpdbg_error("inactive", "type=\"memory_manager\"", "Memory Manager Disabled!"); } return SUCCESS; } /* }}} */ static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */ { - phpdbg_write( - "%s %s %s (%d)", + phpdbg_writeln("class", "type=\"%s\" flags=\"%s\" name=\"%s\" methodcount=\"%d\"", "%s %s %s (%d)", ((*ce)->type == ZEND_USER_CLASS) ? "User" : "Internal", ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? @@ -287,44 +399,44 @@ PHPDBG_INFO(classes) /* {{{ */ zend_hash_init(&classes, 8, NULL, NULL, 0); - for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position); - zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS; - zend_hash_move_forward_ex(EG(class_table), &position)) { - - if ((*ce)->type == ZEND_USER_CLASS) { - zend_hash_next_index_insert( - &classes, ce, sizeof(ce), NULL); + phpdbg_try_access { + for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position); + zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS; + zend_hash_move_forward_ex(EG(class_table), &position)) { + if ((*ce)->type == ZEND_USER_CLASS) { + zend_hash_next_index_insert(&classes, ce, sizeof(ce), NULL); + } } - } + } phpdbg_catch_access { + phpdbg_notice("signalsegv", "", "Not all classes could be fetched, possibly invalid data source"); + } phpdbg_end_try_access(); - phpdbg_notice("User Classes (%d)", - zend_hash_num_elements(&classes)); + phpdbg_notice("classinfo", "num=\"%d\"", "User Classes (%d)", zend_hash_num_elements(&classes)); + /* once added, assume that classes are stable... until shutdown. */ for (zend_hash_internal_pointer_reset_ex(&classes, &position); - zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS; - zend_hash_move_forward_ex(&classes, &position)) { + zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS; + zend_hash_move_forward_ex(&classes, &position)) { phpdbg_print_class_name(ce TSRMLS_CC); - phpdbg_writeln(EMPTY); if ((*ce)->parent) { - zend_class_entry *pce = (*ce)->parent; + zend_class_entry *pce; + + phpdbg_xml(""); + pce = (*ce)->parent; do { - phpdbg_write("|-------- "); + phpdbg_out("|-------- "); phpdbg_print_class_name(&pce TSRMLS_CC); - phpdbg_writeln(EMPTY); } while ((pce = pce->parent)); + phpdbg_xml(""); } if ((*ce)->info.user.filename) { - phpdbg_writeln( - "|---- in %s on line %u", - (*ce)->info.user.filename, - (*ce)->info.user.line_start); + phpdbg_writeln("classsource", "file=\"%s\" line=\"%u\"", "|---- in %s on line %u", (*ce)->info.user.filename, (*ce)->info.user.line_start); } else { - phpdbg_writeln("|---- no source code"); + phpdbg_writeln("classsource", "", "|---- no source code"); } - phpdbg_writeln(EMPTY); } zend_hash_destroy(&classes); @@ -340,29 +452,34 @@ PHPDBG_INFO(funcs) /* {{{ */ zend_hash_init(&functions, 8, NULL, NULL, 0); - for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position); - zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS; - zend_hash_move_forward_ex(EG(function_table), &position)) { - - if (zf->type == ZEND_USER_FUNCTION) { - zend_hash_next_index_insert( - &functions, (void**) &zf, sizeof(zend_function), NULL); + phpdbg_try_access { + for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position); + zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS; + zend_hash_move_forward_ex(EG(function_table), &position)) { + if (zf->type == ZEND_USER_FUNCTION) { + zend_hash_next_index_insert(&functions, (void**) &zf, sizeof(zend_function), NULL); + } } - } + } phpdbg_catch_access { + phpdbg_notice("signalsegv", "", "Not all functions could be fetched, possibly invalid data source"); + } phpdbg_end_try_access(); - phpdbg_notice("User Functions (%d)", - zend_hash_num_elements(&functions)); + phpdbg_notice("functioninfo", "num=\"%d\"", "User Functions (%d)", zend_hash_num_elements(&functions)); for (zend_hash_internal_pointer_reset_ex(&functions, &position); zend_hash_get_current_data_ex(&functions, (void**)&pzf, &position) == SUCCESS; zend_hash_move_forward_ex(&functions, &position)) { zend_op_array *op_array = &((*pzf)->op_array); - phpdbg_writeln( - "|-------- %s in %s on line %d", - op_array->function_name ? op_array->function_name : "{main}", - op_array->filename ? op_array->filename : "(no source code)", - op_array->line_start); + phpdbg_write("function", "name=\"%s\"", "|-------- %s", op_array->function_name ? op_array->function_name : "{main}"); + + if (op_array->filename) { + phpdbg_writeln("functionsource", "file=\"%s\" line=\"%d\"", " in %s on line %d", + op_array->filename, + op_array->line_start); + } else { + phpdbg_writeln("functionsource", "", " (no source code)"); + } } zend_hash_destroy(&functions); diff --git a/phpdbg_info.h b/phpdbg_info.h index c36e6bebd6..aac9fa3ab3 100644 --- a/phpdbg_info.h +++ b/phpdbg_info.h @@ -30,7 +30,9 @@ PHPDBG_INFO(break); PHPDBG_INFO(classes); PHPDBG_INFO(funcs); PHPDBG_INFO(error); +PHPDBG_INFO(constants); PHPDBG_INFO(vars); +PHPDBG_INFO(globals); PHPDBG_INFO(literal); PHPDBG_INFO(memory); diff --git a/phpdbg_io.c b/phpdbg_io.c new file mode 100644 index 0000000000..97f0356285 --- /dev/null +++ b/phpdbg_io.c @@ -0,0 +1,272 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "phpdbg_io.h" + +#ifdef PHP_WIN32 +#undef UNICODE +#include "win32/inet.h" +#include +#include +#include +#include "win32/sockets.h" + +#else + +#if HAVE_SYS_TYPES_H +#include +#endif +#include +#include +#if HAVE_ARPA_INET_H +#include +#endif +#include +#include +#include +#endif + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC) { + int got_now, i = len, j; + char *p = ptr; +#ifndef PHP_WIN32 + struct pollfd pfd; + + if (tmo < 0) goto recv_once; + pfd.fd = sock; + pfd.events = POLLIN; + + j = poll(&pfd, 1, tmo); + + if (j == 0) { +#else + struct fd_set readfds; + struct timeval ttmo; + + if (tmo < 0) goto recv_once; + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + + ttmo.tv_sec = 0; + ttmo.tv_usec = tmo*1000; + + j = select(0, &readfds, NULL, NULL, &ttmo); + + if (j <= 0) { +#endif + return -1; + } + +recv_once: + while(i > 0) { + if (tmo < 0) { + /* There's something to read. Read what's available and proceed + disregarding whether len could be exhausted or not.*/ + int can_read = recv(sock, p, i, MSG_PEEK); +#ifndef _WIN32 + if (can_read == -1 && errno == EINTR) { + continue; + } +#endif + i = can_read; + } + +#ifdef _WIN32 + got_now = recv(sock, p, i, 0); +#else + do { + got_now = recv(sock, p, i, 0); + } while (got_now == -1 && errno == EINTR); +#endif + + if (got_now == -1) { + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Read operation timed out!\n")); + return -1; + } + i -= got_now; + p += got_now; + } + + return p - ptr; +} + +PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len) { + int sent, i = len; + const char *p = ptr; +/* XXX poll/select needed here? */ + while(i > 0) { + sent = send(sock, p, i, 0); + if (sent == -1) { + return -1; + } + i -= sent; + p += sent; + } + + return len; +} + + +PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC) { + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + return phpdbg_consume_bytes(sock, ptr, len, tmo TSRMLS_CC); + } + + return read(sock, ptr, len); +} + + +PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC) { + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + return phpdbg_send_bytes(sock, ptr, len); + } + + return write(sock, ptr, len); +} + + +PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC) { + struct addrinfo res; + int fd = phpdbg_create_listenable_socket(interface, port, &res TSRMLS_CC); + + if (fd == -1) { + return -1; + } + + if (bind(fd, res.ai_addr, res.ai_addrlen) == -1) { + phpdbg_close_socket(fd); + return -4; + } + + listen(fd, 5); + + return fd; +} + + +PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *addr_res TSRMLS_DC) { + int sock = -1, rc; + int reuse = 1; + struct in6_addr serveraddr; + struct addrinfo hints, *res = NULL; + char port_buf[8]; + int8_t any_addr = *addr == '*'; + + do { + memset(&hints, 0, sizeof hints); + if (any_addr) { + hints.ai_flags = AI_PASSIVE; + } else { + hints.ai_flags = AI_NUMERICSERV; + } + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + rc = inet_pton(AF_INET, addr, &serveraddr); + if (1 == rc) { + hints.ai_family = AF_INET; + if (!any_addr) { + hints.ai_flags |= AI_NUMERICHOST; + } + } else { + rc = inet_pton(AF_INET6, addr, &serveraddr); + if (1 == rc) { + hints.ai_family = AF_INET6; + if (!any_addr) { + hints.ai_flags |= AI_NUMERICHOST; + } + } else { + /* XXX get host by name ??? */ + } + } + + snprintf(port_buf, 7, "%u", port); + if (!any_addr) { + rc = getaddrinfo(addr, port_buf, &hints, &res); + } else { + rc = getaddrinfo(NULL, port_buf, &hints, &res); + } + + if (0 != rc) { +#ifndef PHP_WIN32 + if (rc == EAI_SYSTEM) { + char buf[128]; + int wrote; + + wrote = snprintf(buf, 128, "Could not translate address '%s'", addr); + buf[wrote] = '\0'; + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); + + return sock; + } else { +#endif + char buf[256]; + int wrote; + + 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)); + + return sock; +#ifndef PHP_WIN32 + } +#endif + return sock; + } + + if((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { + char buf[128]; + int wrote; + + wrote = sprintf(buf, "Unable to create socket"); + buf[wrote] = '\0'; + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); + + return sock; + } + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)) == -1) { + phpdbg_close_socket(sock); + return sock; + } + + + } while (0); + + *addr_res = *res; + + return sock; +} + +PHPDBG_API void phpdbg_close_socket(int sock) { + if (socket >= 0) { +#ifdef _WIN32 + closesocket(sock); +#else + shutdown(sock, SHUT_RDWR); + close(sock); +#endif + } +} + diff --git a/phpdbg_io.h b/phpdbg_io.h new file mode 100644 index 0000000000..3ac8f4112d --- /dev/null +++ b/phpdbg_io.h @@ -0,0 +1,34 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_IO_H +#define PHPDBG_IO_H + +#include "phpdbg.h" + +PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC); +PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len); +PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC); +PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC); + +PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *res TSRMLS_DC); +PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC); +PHPDBG_API void phpdbg_close_socket(int sock); + +#endif /* PHPDBG_IO_H */ + diff --git a/phpdbg_lexer.c b/phpdbg_lexer.c index 3092dc396d..90f3a449da 100644 --- a/phpdbg_lexer.c +++ b/phpdbg_lexer.c @@ -1,5 +1,5 @@ /* Generated by re2c 0.13.5 */ -#line 1 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 1 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" /* * phpdbg_lexer.l */ @@ -23,8 +23,9 @@ #define YYFILL(n) #define NORMAL 0 -#define RAW 1 -#define INITIAL 2 +#define PRE_RAW 1 +#define RAW 2 +#define INITIAL 3 ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -44,14 +45,18 @@ restart: LEX(text) = YYCURSOR; -#line 48 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 49 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" { YYCTYPE yych; unsigned int yyaccept = 0; - if (YYGETCONDITION() < 1) { - goto yyc_NORMAL; + if (YYGETCONDITION() < 2) { + if (YYGETCONDITION() < 1) { + goto yyc_NORMAL; + } else { + goto yyc_PRE_RAW; + } } else { - if (YYGETCONDITION() < 2) { + if (YYGETCONDITION() < 3) { goto yyc_RAW; } else { goto yyc_INITIAL; @@ -62,10 +67,10 @@ yyc_INITIAL: { static const unsigned char yybm[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 128, 128, 0, 0, 128, 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, - 128, 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, @@ -98,1046 +103,1417 @@ yyc_INITIAL: YYDEBUG(0, *YYCURSOR); YYFILL(4); yych = *YYCURSOR; - if (yych <= 'D') { - if (yych <= '\n') { - if (yych <= 0x00) goto yy6; - if (yych <= 0x08) goto yy11; - if (yych >= '\n') goto yy4; + if (yybm[0+yych] & 32) { + goto yy4; + } + if (yych <= 'E') { + if (yych <= '\f') { + if (yych <= 0x00) goto yy7; + if (yych != '\t') goto yy12; } else { - if (yych <= '\r') { - if (yych <= '\f') goto yy11; + if (yych <= 0x1F) { + if (yych >= 0x0E) goto yy12; } else { - if (yych != ' ') goto yy11; + if (yych <= ' ') goto yy2; + if (yych <= 'D') goto yy12; + goto yy8; } } } else { if (yych <= 'd') { - if (yych <= 'Q') { - if (yych <= 'E') goto yy7; - goto yy11; - } else { - if (yych <= 'R') goto yy10; - if (yych <= 'S') goto yy8; - goto yy11; - } + if (yych <= 'Q') goto yy12; + if (yych <= 'R') goto yy11; + if (yych <= 'S') goto yy9; + goto yy12; } else { if (yych <= 'q') { - if (yych <= 'e') goto yy7; - goto yy11; + if (yych <= 'e') goto yy8; + goto yy12; } else { - if (yych <= 'r') goto yy9; - if (yych <= 's') goto yy8; - goto yy11; + if (yych <= 'r') goto yy10; + if (yych <= 's') goto yy9; + goto yy12; } } } +yy2: YYDEBUG(2, *YYCURSOR); ++YYCURSOR; if ((yych = *YYCURSOR) <= '\f') { + if (yych <= 0x00) goto yy29; if (yych <= 0x08) goto yy3; - if (yych <= '\n') goto yy26; + if (yych <= '\n') goto yy29; } else { - if (yych <= '\r') goto yy26; - if (yych == ' ') goto yy26; + if (yych <= '\r') goto yy29; + if (yych == ' ') goto yy29; } yy3: YYDEBUG(3, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 161 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 176 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { YYSETCONDITION(NORMAL); YYCURSOR = LEX(text); goto restart; } -#line 154 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 161 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; - if ((yych = *YYCURSOR) <= '\f') { - if (yych <= 0x08) goto yy5; - if (yych <= '\n') goto yy26; - } else { - if (yych <= '\r') goto yy26; - if (yych == ' ') goto yy26; - } -yy5: + YYFILL(1); + yych = *YYCURSOR; YYDEBUG(5, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy28; + } + if (yych <= 0x00) goto yy27; + if (yych == '\n') goto yy4; +yy6: + YYDEBUG(6, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 172 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy6: - YYDEBUG(6, *YYCURSOR); - yych = *++YYCURSOR; - goto yy3; +#line 180 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" yy7: YYDEBUG(7, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'V') goto yy22; - if (yych == 'v') goto yy22; + yych = *++YYCURSOR; goto yy3; yy8: YYDEBUG(8, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'H') goto yy18; - if (yych == 'h') goto yy18; + if (yych == 'V') goto yy23; + if (yych == 'v') goto yy23; goto yy3; yy9: YYDEBUG(9, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy15; - } - if (yych == 'U') goto yy12; - if (yych == 'u') goto yy12; + if (yych == 'H') goto yy19; + if (yych == 'h') goto yy19; goto yy3; yy10: YYDEBUG(10, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'U') goto yy12; - if (yych == 'u') goto yy12; + if (yybm[0+yych] & 64) { + goto yy16; + } + if (yych == 'U') goto yy13; + if (yych == 'u') goto yy13; goto yy3; yy11: YYDEBUG(11, *YYCURSOR); - yych = *++YYCURSOR; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy13; + if (yych == 'u') goto yy13; goto yy3; yy12: YYDEBUG(12, *YYCURSOR); yych = *++YYCURSOR; - if (yych == 'N') goto yy14; - if (yych == 'n') goto yy14; + goto yy3; yy13: YYDEBUG(13, *YYCURSOR); - YYCURSOR = YYMARKER; - goto yy3; + yych = *++YYCURSOR; + if (yych == 'N') goto yy15; + if (yych == 'n') goto yy15; yy14: YYDEBUG(14, *YYCURSOR); - yych = *++YYCURSOR; - if (yybm[0+yych] & 128) { - goto yy15; - } - goto yy13; + YYCURSOR = YYMARKER; + goto yy3; yy15: YYDEBUG(15, *YYCURSOR); + yych = *++YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy16; + } + goto yy14; +yy16: + YYDEBUG(16, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(16, *YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy15; - } YYDEBUG(17, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy16; + } + YYDEBUG(18, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 155 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 163 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_RUN; } -#line 245 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy18: - YYDEBUG(18, *YYCURSOR); +#line 253 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy19: + YYDEBUG(19, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '\f') { - if (yych <= 0x08) goto yy13; - if (yych >= '\v') goto yy13; + if (yych <= 0x08) goto yy14; + if (yych >= '\v') goto yy14; } else { - if (yych <= '\r') goto yy19; - if (yych != ' ') goto yy13; + if (yych <= '\r') goto yy20; + if (yych != ' ') goto yy14; } -yy19: - YYDEBUG(19, *YYCURSOR); +yy20: + YYDEBUG(20, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(20, *YYCURSOR); + YYDEBUG(21, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy21; - if (yych <= '\n') goto yy19; + if (yych <= 0x08) goto yy22; + if (yych <= '\n') goto yy20; } else { - if (yych <= '\r') goto yy19; - if (yych == ' ') goto yy19; + if (yych <= '\r') goto yy20; + if (yych == ' ') goto yy20; } -yy21: - YYDEBUG(21, *YYCURSOR); +yy22: + YYDEBUG(22, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 150 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 158 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } -#line 278 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy22: - YYDEBUG(22, *YYCURSOR); +#line 286 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy23: + YYDEBUG(23, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '\f') { - if (yych <= 0x08) goto yy13; - if (yych >= '\v') goto yy13; + if (yych <= 0x08) goto yy14; + if (yych >= '\v') goto yy14; } else { - if (yych <= '\r') goto yy23; - if (yych != ' ') goto yy13; + if (yych <= '\r') goto yy24; + if (yych != ' ') goto yy14; } -yy23: - YYDEBUG(23, *YYCURSOR); +yy24: + YYDEBUG(24, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(24, *YYCURSOR); + YYDEBUG(25, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy25; - if (yych <= '\n') goto yy23; + if (yych <= 0x08) goto yy26; + if (yych <= '\n') goto yy24; } else { - if (yych <= '\r') goto yy23; - if (yych == ' ') goto yy23; + if (yych <= '\r') goto yy24; + if (yych == ' ') goto yy24; } -yy25: - YYDEBUG(25, *YYCURSOR); +yy26: + YYDEBUG(26, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 145 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 153 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } -#line 311 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy26: - YYDEBUG(26, *YYCURSOR); +#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; - YYDEBUG(27, *YYCURSOR); - if (yych <= '\f') { - if (yych <= 0x08) goto yy28; - if (yych <= '\n') goto yy26; - } else { - if (yych <= '\r') goto yy26; - if (yych == ' ') goto yy26; +yy29: + YYDEBUG(29, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy28; } -yy28: - YYDEBUG(28, *YYCURSOR); + if (yych <= 0x00) goto yy27; + if (yych == '\n') goto yy4; + YYDEBUG(30, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { /* ignore whitespace */ goto restart; } -#line 334 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 344 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" } /* *********************************** */ yyc_NORMAL: { static const unsigned char yybm[] = { - 0, 16, 16, 16, 16, 16, 16, 16, - 16, 8, 8, 16, 16, 8, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 8, 16, 16, 0, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 48, 16, - 176, 176, 176, 176, 176, 176, 176, 176, - 176, 176, 0, 16, 16, 16, 16, 16, - 16, 208, 208, 208, 208, 208, 208, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 16, 16, 16, 16, 16, - 16, 208, 208, 208, 208, 208, 208, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, + 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, }; - YYDEBUG(29, *YYCURSOR); + YYDEBUG(31, *YYCURSOR); YYFILL(11); yych = *YYCURSOR; - YYDEBUG(-1, yych); - switch (yych) { - case 0x00: goto yy36; - case '\t': - case '\r': - case ' ': goto yy31; - case '\n': goto yy34; - case '#': goto yy55; - case '-': goto yy41; - case '.': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': goto yy42; - case '0': goto yy45; - case ':': goto yy57; - case 'D': - case 'd': goto yy46; - case 'E': - case 'e': goto yy47; - case 'F': - case 'f': goto yy48; - case 'I': - case 'i': goto yy37; - case 'N': - case 'n': goto yy49; - case 'O': - case 'o': goto yy50; - case 'T': - case 't': goto yy51; - case 'Y': - case 'y': goto yy52; - case 'Z': goto yy53; - case 'z': goto yy54; - default: goto yy39; + if (yybm[0+yych] & 2) { + goto yy33; } -yy31: - YYDEBUG(31, *YYCURSOR); + 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; + } + } + } + } +yy33: + YYDEBUG(33, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(32, *YYCURSOR); - if (yybm[0+yych] & 8) { - goto yy31; + YYDEBUG(34, *YYCURSOR); + if (yybm[0+yych] & 2) { + goto yy33; } - YYDEBUG(33, *YYCURSOR); + if (yych <= 0x00) goto yy39; + if (yych == '\n') goto yy36; + YYDEBUG(35, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { /* ignore whitespace */ goto restart; } -#line 434 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy34: - YYDEBUG(34, *YYCURSOR); +#line 493 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy36: + YYDEBUG(36, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 8) { - goto yy31; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(37, *YYCURSOR); + if (yybm[0+yych] & 2) { + goto yy33; } -yy35: - YYDEBUG(35, *YYCURSOR); + if (yych <= 0x00) goto yy39; + if (yych == '\n') goto yy36; +yy38: + YYDEBUG(38, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 448 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy36: - YYDEBUG(36, *YYCURSOR); +#line 512 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy39: + YYDEBUG(39, *YYCURSOR); yych = *++YYCURSOR; - goto yy35; -yy37: - YYDEBUG(37, *YYCURSOR); + goto yy38; +yy40: + YYDEBUG(40, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'F') goto yy106; - if (yych == 'f') goto yy106; - goto yy40; -yy38: - YYDEBUG(38, *YYCURSOR); + if (yybm[0+yych] & 16) { + goto yy45; + } + if (yych == 'r') goto yy113; + goto yy44; +yy41: + YYDEBUG(41, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 133 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_ID; } -#line 470 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy39: - YYDEBUG(39, *YYCURSOR); +#line 536 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +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; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; -yy40: - YYDEBUG(40, *YYCURSOR); - if (yybm[0+yych] & 16) { - goto yy39; - } - if (yych <= '9') goto yy38; - goto yy62; -yy41: - YYDEBUG(41, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 32) { - goto yy42; +yy44: + YYDEBUG(44, *YYCURSOR); + if (yybm[0+yych] & 8) { + goto yy43; } - goto yy40; -yy42: - YYDEBUG(42, *YYCURSOR); + if (yych <= '9') goto yy41; + goto yy65; +yy45: + YYDEBUG(45, *YYCURSOR); yyaccept = 1; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(43, *YYCURSOR); - if (yybm[0+yych] & 32) { - goto yy42; + YYDEBUG(46, *YYCURSOR); + if (yybm[0+yych] & 16) { + goto yy45; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy44; - if (yych <= 0x08) goto yy39; + if (yych <= 0x00) goto yy47; + if (yych <= 0x08) goto yy43; } else { - if (yych != '\r') goto yy39; + if (yych != '\r') goto yy43; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy44; - if (yych <= '"') goto yy39; + if (yych <= ' ') goto yy47; + if (yych <= '"') goto yy43; } else { - if (yych == ':') goto yy62; - goto yy39; + if (yych == ':') goto yy65; + goto yy43; } } -yy44: - YYDEBUG(44, *YYCURSOR); +yy47: + YYDEBUG(47, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 106 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 114 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = atoi(yytext); return T_DIGITS; } -#line 527 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy45: - YYDEBUG(45, *YYCURSOR); +#line 592 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy48: + YYDEBUG(48, *YYCURSOR); yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 32) { - goto yy42; + if (yybm[0+yych] & 16) { + goto yy45; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy44; - if (yych <= 0x08) goto yy40; - goto yy44; + if (yych <= 0x00) goto yy47; + if (yych <= 0x08) goto yy44; + goto yy47; } else { - if (yych == '\r') goto yy44; - goto yy40; + if (yych == '\r') goto yy47; + goto yy44; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy44; - if (yych <= '"') goto yy40; - goto yy44; + if (yych <= ' ') goto yy47; + if (yych <= '"') goto yy44; + goto yy47; } else { - if (yych == 'x') goto yy102; - goto yy40; + if (yych == 'x') goto yy105; + goto yy44; } } -yy46: - YYDEBUG(46, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'I') goto yy96; - if (yych == 'i') goto yy96; - goto yy40; -yy47: - YYDEBUG(47, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'N') goto yy91; - if (yych == 'n') goto yy91; - goto yy40; -yy48: - YYDEBUG(48, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'A') goto yy88; - if (yych == 'a') goto yy88; - goto yy40; yy49: YYDEBUG(49, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'O') goto yy84; - if (yych == 'o') goto yy84; - goto yy40; + if (yych == 'I') goto yy99; + if (yych == 'i') goto yy99; + goto yy44; yy50: YYDEBUG(50, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= 'N') { - if (yych == 'F') goto yy83; - if (yych <= 'M') goto yy40; - goto yy77; - } else { - if (yych <= 'f') { - if (yych <= 'e') goto yy40; - goto yy83; - } else { - if (yych == 'n') goto yy77; - goto yy40; - } - } + if (yych == 'N') goto yy94; + if (yych == 'n') goto yy94; + goto yy44; yy51: YYDEBUG(51, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'R') goto yy81; - if (yych == 'r') goto yy81; - goto yy40; + if (yych == 'A') goto yy91; + if (yych == 'a') goto yy91; + goto yy44; yy52: YYDEBUG(52, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy76; - if (yych == 'e') goto yy76; - goto yy40; + if (yych == 'O') goto yy87; + if (yych == 'o') goto yy87; + goto yy44; yy53: YYDEBUG(53, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy73; - goto yy40; + if (yych <= 'N') { + if (yych == 'F') goto yy86; + if (yych <= 'M') goto yy44; + goto yy80; + } else { + if (yych <= 'f') { + if (yych <= 'e') goto yy44; + goto yy86; + } else { + if (yych == 'n') goto yy80; + goto yy44; + } + } yy54: YYDEBUG(54, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy61; - goto yy40; + if (yych == 'R') goto yy84; + if (yych == 'r') goto yy84; + goto yy44; yy55: YYDEBUG(55, *YYCURSOR); - ++YYCURSOR; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'E') goto yy79; + if (yych == 'e') goto yy79; + goto yy44; +yy56: YYDEBUG(56, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'E') goto yy76; + goto yy44; +yy57: + YYDEBUG(57, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy64; + goto yy44; +yy58: + YYDEBUG(58, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(59, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 84 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 92 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return T_POUND; } -#line 634 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy57: - YYDEBUG(57, *YYCURSOR); +#line 699 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy60: + YYDEBUG(60, *YYCURSOR); ++YYCURSOR; - if ((yych = *YYCURSOR) == ':') goto yy59; - YYDEBUG(58, *YYCURSOR); + if ((yych = *YYCURSOR) == ':') goto yy62; + YYDEBUG(61, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 90 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 98 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return T_COLON; } -#line 645 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy59: - YYDEBUG(59, *YYCURSOR); +#line 710 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy62: + YYDEBUG(62, *YYCURSOR); ++YYCURSOR; - YYDEBUG(60, *YYCURSOR); + YYDEBUG(63, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 95 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return T_DCOLON; } -#line 655 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy61: - YYDEBUG(61, *YYCURSOR); +#line 720 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy64: + YYDEBUG(64, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'n') goto yy67; - goto yy40; -yy62: - YYDEBUG(62, *YYCURSOR); + if (yych == 'n') goto yy70; + goto yy44; +yy65: + YYDEBUG(65, *YYCURSOR); yych = *++YYCURSOR; - if (yych == '/') goto yy64; -yy63: - YYDEBUG(63, *YYCURSOR); + if (yych == '/') goto yy67; +yy66: + YYDEBUG(66, *YYCURSOR); YYCURSOR = YYMARKER; - if (yyaccept <= 1) { - if (yyaccept <= 0) { - goto yy38; + if (yyaccept <= 2) { + if (yyaccept <= 1) { + if (yyaccept <= 0) { + goto yy41; + } else { + goto yy47; + } } else { - goto yy44; + goto yy75; } } else { - if (yyaccept <= 2) { - goto yy72; + if (yyaccept <= 3) { + goto yy108; } else { - goto yy105; + goto yy119; } } -yy64: - YYDEBUG(64, *YYCURSOR); +yy67: + YYDEBUG(67, *YYCURSOR); yych = *++YYCURSOR; - if (yych != '/') goto yy63; - YYDEBUG(65, *YYCURSOR); + if (yych != '/') goto yy66; + YYDEBUG(68, *YYCURSOR); ++YYCURSOR; - YYDEBUG(66, *YYCURSOR); + YYDEBUG(69, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 78 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 86 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_PROTO; } -#line 697 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy67: - YYDEBUG(67, *YYCURSOR); +#line 766 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy70: + YYDEBUG(70, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'd') goto yy40; - YYDEBUG(68, *YYCURSOR); + if (yych != 'd') goto yy44; + YYDEBUG(71, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != '_') goto yy40; -yy69: - YYDEBUG(69, *YYCURSOR); + if (yych != '_') goto yy44; +yy72: + YYDEBUG(72, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 64) { - goto yy70; + if (yybm[0+yych] & 32) { + goto yy73; } - goto yy40; -yy70: - YYDEBUG(70, *YYCURSOR); - yyaccept = 2; + goto yy44; +yy73: + YYDEBUG(73, *YYCURSOR); + yyaccept = 2; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(71, *YYCURSOR); - if (yybm[0+yych] & 64) { - goto yy70; + YYDEBUG(74, *YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy73; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy72; - if (yych <= 0x08) goto yy39; + if (yych <= 0x00) goto yy75; + if (yych <= 0x08) goto yy43; } else { - if (yych != '\r') goto yy39; + if (yych != '\r') goto yy43; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy72; - if (yych <= '"') goto yy39; + if (yych <= ' ') goto yy75; + if (yych <= '"') goto yy43; } else { - if (yych == ':') goto yy62; - goto yy39; + if (yych == ':') goto yy65; + goto yy43; } } -yy72: - YYDEBUG(72, *YYCURSOR); +yy75: + YYDEBUG(75, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 126 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, OP_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_OPCODE; } -#line 751 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy73: - YYDEBUG(73, *YYCURSOR); +#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 yy40; - YYDEBUG(74, *YYCURSOR); + if (yych != 'N') goto yy44; + YYDEBUG(77, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'D') goto yy40; - YYDEBUG(75, *YYCURSOR); + if (yych != 'D') goto yy44; + YYDEBUG(78, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == '_') goto yy69; - goto yy40; -yy76: - YYDEBUG(76, *YYCURSOR); + if (yych == '_') goto yy72; + goto yy44; +yy79: + YYDEBUG(79, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'S') goto yy77; - if (yych != 's') goto yy40; -yy77: - YYDEBUG(77, *YYCURSOR); + if (yych == 'S') goto yy80; + if (yych != 's') goto yy44; +yy80: + YYDEBUG(80, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\f') { - if (yych <= 0x08) goto yy40; - if (yych >= '\v') goto yy40; - } else { - if (yych <= '\r') goto yy78; - if (yych != ' ') goto yy40; + if (yybm[0+yych] & 64) { + goto yy81; } -yy78: - YYDEBUG(78, *YYCURSOR); + goto yy44; +yy81: + YYDEBUG(81, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(79, *YYCURSOR); - if (yych <= '\f') { - if (yych <= 0x08) goto yy80; - if (yych <= '\n') goto yy78; - } else { - if (yych <= '\r') goto yy78; - if (yych == ' ') goto yy78; + YYDEBUG(82, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy81; } -yy80: - YYDEBUG(80, *YYCURSOR); + YYDEBUG(83, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 94 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 102 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 1; return T_TRUTHY; } -#line 805 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy81: - YYDEBUG(81, *YYCURSOR); +#line 866 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy84: + YYDEBUG(84, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'U') goto yy82; - if (yych != 'u') goto yy40; -yy82: - YYDEBUG(82, *YYCURSOR); + if (yych == 'U') goto yy85; + if (yych != 'u') goto yy44; +yy85: + YYDEBUG(85, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy77; - if (yych == 'e') goto yy77; - goto yy40; -yy83: - YYDEBUG(83, *YYCURSOR); + if (yych == 'E') goto yy80; + if (yych == 'e') goto yy80; + goto yy44; +yy86: + YYDEBUG(86, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'F') goto yy84; - if (yych != 'f') goto yy40; -yy84: - YYDEBUG(84, *YYCURSOR); + if (yych == 'F') goto yy87; + if (yych != 'f') goto yy44; +yy87: + YYDEBUG(87, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy40; - if (yych >= '\v') goto yy40; + if (yych <= 0x08) goto yy44; + if (yych >= '\v') goto yy44; } else { - if (yych <= '\r') goto yy85; - if (yych != ' ') goto yy40; + if (yych <= '\r') goto yy88; + if (yych != ' ') goto yy44; } -yy85: - YYDEBUG(85, *YYCURSOR); +yy88: + YYDEBUG(88, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(86, *YYCURSOR); + YYDEBUG(89, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy87; - if (yych <= '\n') goto yy85; + if (yych <= 0x08) goto yy90; + if (yych <= '\n') goto yy88; } else { - if (yych <= '\r') goto yy85; - if (yych == ' ') goto yy85; + if (yych <= '\r') goto yy88; + if (yych == ' ') goto yy88; } -yy87: - YYDEBUG(87, *YYCURSOR); +yy90: + YYDEBUG(90, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 100 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 108 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 0; return T_FALSY; } -#line 858 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy88: - YYDEBUG(88, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'L') goto yy89; - if (yych != 'l') goto yy40; -yy89: - YYDEBUG(89, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'S') goto yy90; - if (yych != 's') goto yy40; -yy90: - YYDEBUG(90, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy84; - if (yych == 'e') goto yy84; - goto yy40; +#line 919 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" yy91: YYDEBUG(91, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'A') goto yy92; - if (yych != 'a') goto yy40; + if (yych == 'L') goto yy92; + if (yych != 'l') goto yy44; yy92: YYDEBUG(92, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'B') goto yy93; - if (yych != 'b') goto yy40; + if (yych == 'S') goto yy93; + if (yych != 's') goto yy44; yy93: YYDEBUG(93, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'L') goto yy94; - if (yych != 'l') goto yy40; + if (yych == 'E') goto yy87; + if (yych == 'e') goto yy87; + goto yy44; yy94: YYDEBUG(94, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy95; - if (yych != 'e') goto yy40; + if (yych == 'A') goto yy95; + if (yych != 'a') goto yy44; yy95: YYDEBUG(95, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'D') goto yy77; - if (yych == 'd') goto yy77; - goto yy40; + if (yych == 'B') goto yy96; + if (yych != 'b') goto yy44; yy96: YYDEBUG(96, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'S') goto yy97; - if (yych != 's') goto yy40; + if (yych == 'L') goto yy97; + if (yych != 'l') goto yy44; yy97: YYDEBUG(97, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'A') goto yy98; - if (yych != 'a') goto yy40; + if (yych == 'E') goto yy98; + if (yych != 'e') goto yy44; yy98: YYDEBUG(98, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'B') goto yy99; - if (yych != 'b') goto yy40; + if (yych == 'D') goto yy80; + if (yych == 'd') goto yy80; + goto yy44; yy99: YYDEBUG(99, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'L') goto yy100; - if (yych != 'l') goto yy40; + if (yych == 'S') goto yy100; + if (yych != 's') goto yy44; yy100: YYDEBUG(100, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy101; - if (yych != 'e') goto yy40; + if (yych == 'A') goto yy101; + if (yych != 'a') goto yy44; yy101: YYDEBUG(101, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'D') goto yy84; - if (yych == 'd') goto yy84; - goto yy40; + if (yych == 'B') goto yy102; + if (yych != 'b') goto yy44; yy102: YYDEBUG(102, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy103; - } - goto yy40; + if (yych == 'L') goto yy103; + if (yych != 'l') goto yy44; yy103: YYDEBUG(103, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'E') goto yy104; + if (yych != 'e') goto yy44; +yy104: + YYDEBUG(104, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'D') goto yy87; + if (yych == 'd') goto yy87; + goto yy44; +yy105: + YYDEBUG(105, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy106; + } + goto yy44; +yy106: + YYDEBUG(106, *YYCURSOR); yyaccept = 3; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(104, *YYCURSOR); + YYDEBUG(107, *YYCURSOR); if (yybm[0+yych] & 128) { - goto yy103; + goto yy106; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy105; - if (yych <= 0x08) goto yy39; + if (yych <= 0x00) goto yy108; + if (yych <= 0x08) goto yy43; } else { - if (yych != '\r') goto yy39; + if (yych != '\r') goto yy43; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy105; - if (yych <= '"') goto yy39; + if (yych <= ' ') goto yy108; + if (yych <= '"') goto yy43; } else { - if (yych == ':') goto yy62; - goto yy39; + if (yych == ':') goto yy65; + goto yy43; } } -yy105: - YYDEBUG(105, *YYCURSOR); +yy108: + YYDEBUG(108, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 120 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, ADDR_PARAM); yylval->addr = strtoul(yytext, 0, 16); return T_ADDR; } -#line 989 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy106: - YYDEBUG(106, *YYCURSOR); +#line 1050 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy109: + YYDEBUG(109, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy40; - if (yych >= '\v') goto yy40; + if (yych <= 0x08) goto yy44; + if (yych >= '\v') goto yy44; } else { - if (yych <= '\r') goto yy107; - if (yych != ' ') goto yy40; + if (yych <= '\r') goto yy110; + if (yych != ' ') goto yy44; } -yy107: - YYDEBUG(107, *YYCURSOR); +yy110: + YYDEBUG(110, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(108, *YYCURSOR); + YYDEBUG(111, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy109; - if (yych <= '\n') goto yy107; + if (yych <= 0x08) goto yy112; + if (yych <= '\n') goto yy110; } else { - if (yych <= '\r') goto yy107; - if (yych == ' ') goto yy107; + if (yych <= '\r') goto yy110; + if (yych == ' ') goto yy110; } -yy109: - YYDEBUG(109, *YYCURSOR); +yy112: + YYDEBUG(112, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 80 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_IF; } -#line 1023 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1084 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy113: + YYDEBUG(113, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= ' ') { + if (yych <= '\f') { + if (yych <= 0x08) goto yy44; + if (yych >= '\v') goto yy44; + } else { + if (yych <= '\r') goto yy114; + if (yych <= 0x1F) goto yy44; + } + } else { + if (yych <= '.') { + if (yych <= ',') goto yy44; + if (yych <= '-') goto yy116; + goto yy117; + } else { + if (yych <= '/') goto yy44; + if (yych <= '9') goto yy117; + goto yy44; + } + } +yy114: + YYDEBUG(114, *YYCURSOR); + ++YYCURSOR; + YYFILL(2); + yych = *YYCURSOR; + YYDEBUG(115, *YYCURSOR); + if (yych <= ' ') { + if (yych <= '\f') { + if (yych <= 0x08) goto yy66; + if (yych <= '\n') goto yy114; + goto yy66; + } else { + if (yych <= '\r') goto yy114; + if (yych <= 0x1F) goto yy66; + goto yy114; + } + } else { + if (yych <= '.') { + if (yych <= ',') goto yy66; + if (yych <= '-') goto yy120; + goto yy121; + } else { + if (yych <= '/') goto yy66; + if (yych <= '9') goto yy121; + goto yy66; + } + } +yy116: + YYDEBUG(116, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '.') goto yy117; + if (yych <= '/') goto yy44; + if (yych >= ':') goto yy44; +yy117: + YYDEBUG(117, *YYCURSOR); + yyaccept = 4; + YYMARKER = ++YYCURSOR; + YYFILL(3); + yych = *YYCURSOR; + YYDEBUG(118, *YYCURSOR); + if (yych <= ' ') { + if (yych <= '\n') { + if (yych <= 0x00) goto yy119; + if (yych <= 0x08) goto yy43; + } else { + if (yych == '\r') goto yy119; + if (yych <= 0x1F) goto yy43; + } + } else { + if (yych <= '.') { + if (yych == '#') goto yy119; + if (yych <= '-') goto yy43; + goto yy117; + } else { + if (yych <= '/') goto yy43; + if (yych <= '9') goto yy117; + if (yych <= ':') goto yy65; + goto yy43; + } + } +yy119: + YYDEBUG(119, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 73 "/Users/Bob/php-src-5.6/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); + yych = *++YYCURSOR; + if (yych == '.') goto yy121; + if (yych <= '/') goto yy66; + if (yych >= ':') goto yy66; +yy121: + YYDEBUG(121, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(122, *YYCURSOR); + if (yych == '.') goto yy121; + if (yych <= '/') goto yy119; + if (yych <= '9') goto yy121; + goto yy119; } /* *********************************** */ -yyc_RAW: +yyc_PRE_RAW: { static const unsigned char yybm[] = { - 0, 64, 64, 64, 64, 64, 64, 64, - 64, 224, 128, 64, 64, 224, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 224, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, + 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, }; - YYDEBUG(110, *YYCURSOR); + YYDEBUG(123, *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; + } else { + if (yych <= '\t') goto yy125; + if (yych <= '\f') goto yy132; + } + } else { + if (yych <= ' ') { + if (yych <= 0x1F) goto yy132; + } else { + if (yych == '-') goto yy131; + goto yy132; + } + } +yy125: + YYDEBUG(125, *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; + } +yy126: + YYDEBUG(126, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 169 "/Users/Bob/php-src-5.6/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); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(128, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy141; + } + if (yych <= 0x00) goto yy140; + if (yych == '\n') goto yy127; +yy129: + YYDEBUG(129, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" + { + return 0; +} +#line 1296 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy130: + YYDEBUG(130, *YYCURSOR); + yych = *++YYCURSOR; + goto yy126; +yy131: + YYDEBUG(131, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy133; + goto yy126; +yy132: + YYDEBUG(132, *YYCURSOR); + yych = *++YYCURSOR; + goto yy126; +yy133: + YYDEBUG(133, *YYCURSOR); + ++YYCURSOR; + YYFILL(2); + yych = *YYCURSOR; + YYDEBUG(134, *YYCURSOR); if (yybm[0+yych] & 32) { - goto yy112; + goto yy133; } - if (yych <= 0x00) goto yy117; - if (yych == '\n') goto yy115; - goto yy118; -yy112: - YYDEBUG(112, *YYCURSOR); + if (yych <= '.') { + if (yych <= ',') goto yy135; + if (yych <= '-') goto yy136; + goto yy137; + } else { + if (yych <= '/') goto yy135; + if (yych <= '9') goto yy137; + } +yy135: + YYDEBUG(135, *YYCURSOR); + YYCURSOR = YYMARKER; + goto yy126; +yy136: + YYDEBUG(136, *YYCURSOR); + yych = *++YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy137; + } + goto yy135; +yy137: + YYDEBUG(137, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(113, *YYCURSOR); + YYDEBUG(138, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy137; + } + YYDEBUG(139, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 73 "/Users/Bob/php-src-5.6/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" + } +/* *********************************** */ +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, + }; + YYDEBUG(144, *YYCURSOR); + YYFILL(1); + yych = *YYCURSOR; if (yybm[0+yych] & 32) { - goto yy112; + goto yy146; } - if (yych <= 0x00) goto yy114; - if (yych == '\n') goto yy120; - goto yy118; -yy114: - YYDEBUG(114, *YYCURSOR); + if (yych <= 0x00) goto yy152; + if (yych == '\n') goto yy149; + goto yy153; +yy146: + YYDEBUG(146, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(147, *YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy146; + } + if (yych <= 0x00) goto yy152; + if (yych == '\n') goto yy149; + goto yy153; +yy148: + YYDEBUG(148, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 140 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_INPUT; } -#line 1093 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy115: - YYDEBUG(115, *YYCURSOR); +#line 1452 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy149: + YYDEBUG(149, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy120; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(150, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy149; } -yy116: - YYDEBUG(116, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x00) goto yy152; + if (yych == '\t') goto yy155; + } else { + if (yych <= '\r') goto yy155; + if (yych == ' ') goto yy155; + } +yy151: + YYDEBUG(151, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 1107 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy117: - YYDEBUG(117, *YYCURSOR); +#line 1476 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy152: + YYDEBUG(152, *YYCURSOR); yych = *++YYCURSOR; - goto yy116; -yy118: - YYDEBUG(118, *YYCURSOR); + goto yy151; +yy153: + YYDEBUG(153, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(119, *YYCURSOR); - if (yybm[0+yych] & 64) { - goto yy118; + YYDEBUG(154, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy153; } - goto yy114; -yy120: - YYDEBUG(120, *YYCURSOR); + goto yy148; +yy155: + YYDEBUG(155, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(121, *YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy120; + YYDEBUG(156, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy149; } - YYDEBUG(122, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x00) goto yy152; + if (yych == '\t') goto yy155; + } else { + if (yych <= '\r') goto yy155; + if (yych == ' ') goto yy155; + } + YYDEBUG(157, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { /* ignore whitespace */ goto restart; } -#line 1139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1515 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" } } -#line 168 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 183 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" } diff --git a/phpdbg_lexer.l b/phpdbg_lexer.l index 7b3ce38c47..0c27fc22ac 100644 --- a/phpdbg_lexer.l +++ b/phpdbg_lexer.l @@ -21,8 +21,9 @@ #define YYFILL(n) #define NORMAL 0 -#define RAW 1 -#define INITIAL 2 +#define PRE_RAW 1 +#define RAW 2 +#define INITIAL 3 ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -65,10 +66,17 @@ INPUT [^\n\000]+ := yyleng = (size_t) YYCURSOR - (size_t) yytext; -<*>[\n\000] { +<*>{WS}?[\n\000] { return 0; } +[-][r]{WS}?{DIGITS} { + char *text = yytext + 2; + while (*++text < '0'); + yylval->num = atoi(text); + return T_REQ_ID; +} + {T_IF}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); @@ -143,21 +151,28 @@ INPUT [^\n\000]+ } {T_EVAL}{WS} { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } {T_SHELL}{WS} { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } ({T_RUN}|{T_RUN_SHORT}){WS} { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_RUN; } +. { + YYSETCONDITION(RAW); + + YYCURSOR = LEX(text); + goto restart; +} + . { YYSETCONDITION(NORMAL); diff --git a/phpdbg_list.c b/phpdbg_list.c index e8db4e605c..80b5d2b189 100644 --- a/phpdbg_list.c +++ b/phpdbg_list.c @@ -34,21 +34,21 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13]) +#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[13], flags) const phpdbg_command_t phpdbg_list_commands[] = { - PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l"), - PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s"), - PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m"), - PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s"), + PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l", PHPDBG_ASYNC_SAFE), + PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m", PHPDBG_ASYNC_SAFE), + PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s", PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; PHPDBG_LIST(lines) /* {{{ */ { if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) { - phpdbg_error("Not executing, and execution context not set"); + phpdbg_error("inactive", "type=\"execution\"", "Not executing, and execution context not set"); return SUCCESS; } @@ -59,7 +59,7 @@ PHPDBG_LIST(lines) /* {{{ */ (param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), 0 TSRMLS_CC); break; - + case FILE_PARAM: phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC); break; @@ -81,19 +81,19 @@ PHPDBG_LIST(method) /* {{{ */ { zend_class_entry **ce; - if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { zend_function *function; char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) { phpdbg_list_function(function TSRMLS_CC); } else { - phpdbg_error("Could not find %s::%s", param->method.class, param->method.name); + phpdbg_error("list", "type=\"notfound\" method=\"%s::%s\"", "Could not find %s::%s", param->method.class, param->method.name); } efree(lcname); } else { - phpdbg_error("Could not find the class %s", param->method.class); + phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "Could not find the class %s", param->method.class); } return SUCCESS; @@ -103,7 +103,7 @@ PHPDBG_LIST(class) /* {{{ */ { zend_class_entry **ce; - if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { if ((*ce)->type == ZEND_USER_CLASS) { if ((*ce)->info.user.filename) { phpdbg_list_file( @@ -112,71 +112,62 @@ PHPDBG_LIST(class) /* {{{ */ (*ce)->info.user.line_start, 0 TSRMLS_CC ); } else { - phpdbg_error("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", (*ce)->name); } } else { - phpdbg_error("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", (*ce)->name); } } else { - phpdbg_error("The requested class (%s) could not be found", param->str); + phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "The requested class (%s) could not be found", param->str); } return SUCCESS; } /* }}} */ -void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */ +void phpdbg_list_file(const char *filename, uint count, int offset, uint highlight TSRMLS_DC) /* {{{ */ { - struct stat st; - char *opened = NULL; - char buffer[8096] = {0,}; - long line = 0; - - php_stream *stream = NULL; - - if (VCWD_STAT(filename, &st) == FAILURE) { - phpdbg_error("Failed to stat file %s", filename); - return; - } + uint line, lastline; + phpdbg_file_source **data; - stream = php_stream_open_wrapper(filename, "rb", USE_PATH, &opened); - - if (!stream) { - phpdbg_error("Failed to open file %s to list", filename); + if (zend_hash_find(&PHPDBG_G(file_sources), filename, strlen(filename), (void **) &data) == FAILURE) { + phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file..."); return; } - + if (offset < 0) { count += offset; offset = 0; } - - while (php_stream_gets(stream, buffer, sizeof(buffer)) != NULL) { - long linelen = strlen(buffer); - - ++line; - - if (offset <= line) { - if (!highlight) { - phpdbg_write("%05ld: %s", line, buffer); - } else { - if (highlight != line) { - phpdbg_write(" %05ld: %s", line, buffer); - } else { - phpdbg_write(">%05ld: %s", line, buffer); - } - } - if (buffer[linelen - 1] != '\n') { - phpdbg_write("\n"); + lastline = offset + count; + + if (lastline > (*data)->lines) { + lastline = (*data)->lines; + } + + phpdbg_xml("", filename); + + for (line = offset; line < lastline;) { + uint linestart = (*data)->line[line++]; + uint linelen = (*data)->line[line] - linestart; + char *buffer = (*data)->buf + linestart; + + if (!highlight) { + phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer); + } else { + if (highlight != line) { + phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer); + } else { + phpdbg_write("line", "line=\"%u\" code=\"%.*s\" current=\"current\"", ">%05u: %.*s", line, linelen, buffer); } } - if (count > 0 && count + offset - 1 < line) { - break; + if (*(buffer + linelen - 1) != '\n' || !linelen) { + phpdbg_out("\n"); } } - - php_stream_close(stream); + + phpdbg_xml(""); } /* }}} */ void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */ @@ -184,14 +175,13 @@ void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */ const zend_op_array *ops; if (fbc->type != ZEND_USER_FUNCTION) { - phpdbg_error("The function requested (%s) is not user defined", fbc->common.function_name); + phpdbg_error("list", "type=\"internalfunction\" function=\"%s\"", "The function requested (%s) is not user defined", fbc->common.function_name); return; } - ops = (zend_op_array*)fbc; + ops = (zend_op_array *)fbc; - phpdbg_list_file(ops->filename, - ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC); + phpdbg_list_file(ops->filename, ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC); } /* }}} */ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */ @@ -209,11 +199,11 @@ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ * func_table = &EG(scope)->function_table; } else { - phpdbg_error("No active class"); + phpdbg_error("inactive", "type=\"noclasses\"", "No active class"); return; } } else if (!EG(function_table)) { - phpdbg_error("No function table loaded"); + phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded"); return; } else { func_table = EG(function_table); @@ -222,12 +212,86 @@ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ * /* use lowercase names, case insensitive */ func_name = zend_str_tolower_dup(func_name, func_name_len); - if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) { - phpdbg_list_function(fbc TSRMLS_CC); - } else { - phpdbg_error("Function %s not found", func_name); - } + phpdbg_try_access { + if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) { + phpdbg_list_function(fbc TSRMLS_CC); + } else { + phpdbg_error("list", "type=\"nofunction\" function=\"%s\"", "Function %s not found", func_name); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "function=\"%s\"", "Could not list function %s, invalid data source", func_name); + } phpdbg_end_try_access(); efree(func_name); } /* }}} */ +zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) { + phpdbg_file_source data, *dataptr; + zend_file_handle fake = {0}; + zend_op_array *ret; + char *filename = (char *)(file->opened_path ? file->opened_path : file->filename); + uint line; + char *bufptr, *endptr; + + zend_stream_fixup(file, &data.buf, &data.len TSRMLS_CC); + + 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 HAVE_MMAP + if (file->handle.stream.mmap.map) { + data.map = file->handle.stream.mmap.map; + } +#endif + + 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; + zend_hash_add(&PHPDBG_G(file_sources), filename, strlen(filename), &dataptr, sizeof(phpdbg_file_source *), NULL); + + for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) { + if (*bufptr == '\n') { + dataptr->line[++line] = (uint)(bufptr - data.buf) + 1; + } + } + dataptr->lines = ++line; + dataptr->line[line] = endptr - data.buf; + dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line); + + ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC); + + fake.opened_path = NULL; + zend_file_handle_dtor(&fake TSRMLS_CC); + + 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); + } + + efree(data); +} + +void phpdbg_init_list(TSRMLS_D) { + PHPDBG_G(compile_file) = zend_compile_file; + zend_hash_init(&PHPDBG_G(file_sources), 1, NULL, (dtor_func_t) phpdbg_free_file_source, 0); + zend_compile_file = phpdbg_compile_file; +} diff --git a/phpdbg_list.h b/phpdbg_list.h index 14905f6567..c88328bfea 100644 --- a/phpdbg_list.h +++ b/phpdbg_list.h @@ -34,8 +34,21 @@ PHPDBG_LIST(func); void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC); void phpdbg_list_function(const zend_function* TSRMLS_DC); -void phpdbg_list_file(const char*, long, long, int TSRMLS_DC); +void phpdbg_list_file(const char*, uint, int, uint TSRMLS_DC); extern const phpdbg_command_t phpdbg_list_commands[]; +void phpdbg_init_list(TSRMLS_D); + +typedef struct { + char *filename; + char *buf; + size_t len; +#if HAVE_MMAP + void *map; +#endif + uint lines; + uint line[1]; +} phpdbg_file_source; + #endif /* PHPDBG_LIST_H */ diff --git a/phpdbg_opcode.c b/phpdbg_opcode.c index 6b13625fc1..331718accc 100644 --- a/phpdbg_opcode.c +++ b/phpdbg_opcode.c @@ -92,8 +92,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM case ZEND_JMPZNZ: decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); - asprintf( - &decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value); + asprintf(&decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value); goto result; case ZEND_JMPZ: @@ -103,13 +102,9 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM #ifdef ZEND_JMP_SET case ZEND_JMP_SET: -#endif -#ifdef ZEND_JMP_SET_VAR - case ZEND_JMP_SET_VAR: #endif decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); - asprintf( - &decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes); + asprintf(&decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes); goto result; case ZEND_RECV_INIT: @@ -121,8 +116,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM result: decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC); format: - asprintf( - &decode[0], + asprintf(&decode[0], "%-20s %-20s %-20s", decode[1] ? decode[1] : "", decode[2] ? decode[2] : "", @@ -153,7 +147,7 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, ze if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) { /* output line info */ - phpdbg_notice("L%-5u %16p %-30s %s %s", + phpdbg_notice("opline", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\" file=\"%s\"", "L%-5u %16p %-30s %s %s", opline->lineno, opline, phpdbg_decode_opcode(opline->opcode), @@ -162,7 +156,7 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, ze } if (!ignore_flags && PHPDBG_G(oplog)) { - phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s", + phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %-30s %s %s", opline->lineno, opline, phpdbg_decode_opcode(opline->opcode), @@ -333,12 +327,6 @@ const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */ #ifdef ZEND_SEPARATE CASE(ZEND_SEPARATE); #endif -#ifdef ZEND_QM_ASSIGN_VAR - CASE(ZEND_QM_ASSIGN_VAR); -#endif -#ifdef ZEND_JMP_SET_VAR - CASE(ZEND_JMP_SET_VAR); -#endif #ifdef ZEND_DISCARD_EXCEPTION CASE(ZEND_DISCARD_EXCEPTION); #endif diff --git a/phpdbg_out.c b/phpdbg_out.c new file mode 100644 index 0000000000..a4793f144f --- /dev/null +++ b/phpdbg_out.c @@ -0,0 +1,1305 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "php.h" +#include "spprintf.h" +#include "phpdbg.h" +#include "phpdbg_io.h" +#include "phpdbg_eol.h" +#include "ext/standard/html.h" + +#ifdef _WIN32 +# include "win32/time.h" +#endif + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +/* copied from php-src/main/snprintf.c and slightly modified */ +/* + * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions + * + * XXX: this is a magic number; do not decrease it + * Emax = 1023 + * NDIG = 320 + * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1; + */ +#define NUM_BUF_SIZE 2048 + +/* + * Descriptor for buffer area + */ +struct buf_area { + char *buf_end; + char *nextb; /* pointer to next byte to read/write */ +}; + +typedef struct buf_area buffy; + +/* + * The INS_CHAR macro inserts a character in the buffer and writes + * the buffer back to disk if necessary + * It uses the char pointers sp and bep: + * sp points to the next available character in the buffer + * bep points to the end-of-buffer+1 + * While using this macro, note that the nextb pointer is NOT updated. + * + * NOTE: Evaluation of the c argument should not have any side-effects + */ +#define INS_CHAR(c, sp, bep, cc) \ + { \ + if (sp < bep) \ + { \ + *sp++ = c; \ + } \ + cc++; \ + } + +#define NUM( c ) ( c - '0' ) + +#define STR_TO_DEC( str, num ) \ + num = NUM( *str++ ) ; \ + while ( isdigit((int)*str ) ) \ + { \ + num *= 10 ; \ + num += NUM( *str++ ) ; \ + } + +/* + * This macro does zero padding so that the precision + * requirement is satisfied. The padding is done by + * adding '0's to the left of the string that is going + * to be printed. + */ +#define FIX_PRECISION( adjust, precision, s, s_len ) \ + if ( adjust ) \ + while ( s_len < precision ) \ + { \ + *--s = '0' ; \ + s_len++ ; \ + } + +/* + * Macro that does padding. The padding is done by printing + * the character ch. + */ +#define PAD( width, len, ch ) do \ + { \ + INS_CHAR( ch, sp, bep, cc ) ; \ + width-- ; \ + } \ + while ( width > len ) + +/* + * Prefix the character ch to the string str + * Increase length + * Set the has_prefix flag + */ +#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES + + +#ifdef HAVE_LOCALE_H +#include +#define LCONV_DECIMAL_POINT (*lconv->decimal_point) +#else +#define LCONV_DECIMAL_POINT '.' +#endif +#define NUL '\0' +#define S_NULL "(null)" +#define S_NULL_LEN 6 +#define FLOAT_DIGITS 6 + +/* + * Do format conversion placing the output in buffer + */ +static int format_converter(register buffy *odp, const char *fmt, zend_bool escape_xml, va_list ap TSRMLS_DC) { + char *sp; + char *bep; + int cc = 0; + int i; + + char *s = NULL, *free_s = NULL; + int s_len, free_zcopy; + zval *zvp, zcopy; + + int min_width = 0; + int precision = 0; + enum { + LEFT, RIGHT + } adjust; + char pad_char; + char prefix_char; + + double fp_num; + wide_int i_num = (wide_int) 0; + u_wide_int ui_num; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and % */ + +#ifdef HAVE_LOCALE_H + struct lconv *lconv = NULL; +#endif + + /* + * Flag variables + */ + length_modifier_e modifier; + boolean_e alternate_form; + boolean_e print_sign; + boolean_e print_blank; + boolean_e adjust_precision; + boolean_e adjust_width; + bool_int is_negative; + + sp = odp->nextb; + bep = odp->buf_end; + + while (*fmt) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } else { + /* + * Default variable settings + */ + adjust = RIGHT; + alternate_form = print_sign = print_blank = NO; + pad_char = ' '; + prefix_char = NUL; + free_zcopy = 0; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (isascii((int)*fmt) && !islower((int)*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = YES; + else if (*fmt == '#') + alternate_form = YES; + else if (*fmt == ' ') + print_blank = YES; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (isdigit((int)*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } else if (*fmt == '*') { + min_width = va_arg(ap, int); + fmt++; + adjust_width = YES; + if (min_width < 0) { + adjust = LEFT; + min_width = -min_width; + } + } else + adjust_width = NO; + + /* + * Check if a precision was specified + */ + if (*fmt == '.') { + adjust_precision = YES; + fmt++; + if (isdigit((int)*fmt)) { + STR_TO_DEC(fmt, precision); + } else if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + if (precision < 0) + precision = 0; + } else + precision = 0; + + if (precision > FORMAT_CONV_MAX_PRECISION && *fmt != 's' && *fmt != 'v' && *fmt != 'b') { + precision = FORMAT_CONV_MAX_PRECISION; + } + } else + adjust_precision = NO; + } else + adjust_precision = adjust_width = NO; + + /* + * Modifier check + */ + switch (*fmt) { + case 'L': + fmt++; + modifier = LM_LONG_DOUBLE; + break; + case 'I': + fmt++; +#if SIZEOF_LONG_LONG + if (*fmt == '6' && *(fmt+1) == '4') { + fmt += 2; + modifier = LM_LONG_LONG; + } else +#endif + if (*fmt == '3' && *(fmt+1) == '2') { + fmt += 2; + modifier = LM_LONG; + } else { +#ifdef _WIN64 + modifier = LM_LONG_LONG; +#else + modifier = LM_LONG; +#endif + } + break; + case 'l': + fmt++; +#if SIZEOF_LONG_LONG + if (*fmt == 'l') { + fmt++; + modifier = LM_LONG_LONG; + } else +#endif + modifier = LM_LONG; + break; + case 'z': + fmt++; + modifier = LM_SIZE_T; + break; + case 'j': + fmt++; +#if SIZEOF_INTMAX_T + modifier = LM_INTMAX_T; +#else + modifier = LM_SIZE_T; +#endif + break; + case 't': + fmt++; +#if SIZEOF_PTRDIFF_T + modifier = LM_PTRDIFF_T; +#else + modifier = LM_SIZE_T; +#endif + break; + case 'h': + fmt++; + if (*fmt == 'h') { + fmt++; + } + /* these are promoted to int, so no break */ + default: + modifier = LM_STD; + break; + } + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + case 'Z': + zvp = (zval*) va_arg(ap, zval*); + zend_make_printable_zval(zvp, &zcopy, &free_zcopy); + if (free_zcopy) { + zvp = &zcopy; + } + s_len = Z_STRLEN_P(zvp); + s = Z_STRVAL_P(zvp); + if (adjust_precision && precision < s_len) { + s_len = precision; + } + break; + case 'u': + switch(modifier) { + default: + i_num = (wide_int) va_arg(ap, unsigned int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + i_num = (wide_int) va_arg(ap, unsigned long int); + break; + case LM_SIZE_T: + i_num = (wide_int) va_arg(ap, size_t); + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + i_num = (wide_int) va_arg(ap, u_wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + i_num = (wide_int) va_arg(ap, uintmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + i_num = (wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + /* + * The rest also applies to other integer formats, so fall + * into that case. + */ + case 'd': + case 'i': + /* + * Get the arg if we haven't already. + */ + if ((*fmt) != 'u') { + switch(modifier) { + default: + i_num = (wide_int) va_arg(ap, int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + i_num = (wide_int) va_arg(ap, long int); + break; + case LM_SIZE_T: +#if SIZEOF_SSIZE_T + i_num = (wide_int) va_arg(ap, ssize_t); +#else + i_num = (wide_int) va_arg(ap, size_t); +#endif + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + i_num = (wide_int) va_arg(ap, wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + i_num = (wide_int) va_arg(ap, intmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + i_num = (wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + } + s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (*fmt != 'u') { + if (is_negative) { + prefix_char = '-'; + } else if (print_sign) { + prefix_char = '+'; + } else if (print_blank) { + prefix_char = ' '; + } + } + break; + + + case 'o': + switch(modifier) { + default: + ui_num = (u_wide_int) va_arg(ap, unsigned int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + ui_num = (u_wide_int) va_arg(ap, unsigned long int); + break; + case LM_SIZE_T: + ui_num = (u_wide_int) va_arg(ap, size_t); + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + ui_num = (u_wide_int) va_arg(ap, uintmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + ui_num = (u_wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + + case 'x': + case 'X': + switch(modifier) { + default: + ui_num = (u_wide_int) va_arg(ap, unsigned int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + ui_num = (u_wide_int) va_arg(ap, unsigned long int); + break; + case LM_SIZE_T: + ui_num = (u_wide_int) va_arg(ap, size_t); + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + ui_num = (u_wide_int) va_arg(ap, uintmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + ui_num = (u_wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && i_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + + case 's': + case 'v': + s = va_arg(ap, char *); + if (s != NULL) { + if (adjust_precision) { + s_len = precision; + } else { + s_len = strlen(s); + } + + if (escape_xml) { + /* added: support for xml escaping */ + + int old_slen = s_len, i = 0; + char *old_s = s, *s_ptr; + free_s = s_ptr = s = emalloc(old_slen * 6 + 1); + do { + if (old_s[i] == '&' || old_s[i] == '"' || old_s[i] == '<') { + *s_ptr++ = '&'; + switch (old_s[i]) { + case '"': + s_len += 5; + *s_ptr++ = 'q'; + *s_ptr++ = 'u'; + *s_ptr++ = 'o'; + *s_ptr++ = 't'; + break; + case '<': + s_len += 3; + *s_ptr++ = 'l'; + *s_ptr++ = 't'; + break; + case '&': + s_len += 4; + *s_ptr++ = 'a'; + *s_ptr++ = 'm'; + *s_ptr++ = 'p'; + break; + } + *s_ptr++ = ';'; + } else { + *s_ptr++ = old_s[i]; + } + } while (i++ < old_slen); + } + } else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + + case 'b': + if (escape_xml) { + s = PHPDBG_G(err_buf).xml; + } else { + s = PHPDBG_G(err_buf).msg; + } + + if (s != NULL) { + if (escape_xml) { + s_len = PHPDBG_G(err_buf).xmllen; + } else { + s_len = PHPDBG_G(err_buf).msglen; + } + + if (adjust_precision && precision != s_len) { + s_len = precision; + } + } else { + s = ""; + s_len = 0; + } + pad_char = ' '; + break; + + + case 'r': + if (PHPDBG_G(req_id)) { + s_len = spprintf(&s, 0, "req=\"%lu\"", PHPDBG_G(req_id)); + free_s = s; + } else { + s = ""; + s_len = 0; + } + break; + + + case 'f': + case 'F': + case 'e': + case 'E': + + switch(modifier) { + case LM_LONG_DOUBLE: + fp_num = (double) va_arg(ap, long double); + break; + case LM_STD: + fp_num = va_arg(ap, double); + break; + default: + goto fmt_error; + } + + if (zend_isnan(fp_num)) { + s = "NAN"; + s_len = 3; + } else if (zend_isinf(fp_num)) { + s = "INF"; + s_len = 3; + } else { +#ifdef HAVE_LOCALE_H + if (!lconv) { + lconv = localeconv(); + } +#endif + s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form, + (adjust_precision == NO) ? FLOAT_DIGITS : precision, + (*fmt == 'f')?LCONV_DECIMAL_POINT:'.', + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'g': + case 'k': + case 'G': + case 'H': + switch(modifier) { + case LM_LONG_DOUBLE: + fp_num = (double) va_arg(ap, long double); + break; + case LM_STD: + fp_num = va_arg(ap, double); + break; + default: + goto fmt_error; + } + + if (zend_isnan(fp_num)) { + s = "NAN"; + s_len = 3; + break; + } else if (zend_isinf(fp_num)) { + if (fp_num > 0) { + s = "INF"; + s_len = 3; + } else { + s = "-INF"; + s_len = 4; + } + break; + } + + if (adjust_precision == NO) { + precision = FLOAT_DIGITS; + } else if (precision == 0) { + precision = 1; + } + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ +#ifdef HAVE_LOCALE_H + if (!lconv) { + lconv = localeconv(); + } +#endif + s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]); + if (*s == '-') { + prefix_char = *s++; + } else if (print_sign) { + prefix_char = '+'; + } else if (print_blank) { + prefix_char = ' '; + } + + s_len = strlen(s); + + if (alternate_form && (strchr(s, '.')) == NULL) { + s[s_len++] = '.'; + } + break; + + + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case 'n': + *(va_arg(ap, int *)) = cc; + goto skip_output; + + /* + * Always extract the argument as a "char *" pointer. We + * should be using "void *" but there are still machines + * that don't understand it. + * If the pointer size is equal to the size of an unsigned + * integer we convert the pointer to a hex number, otherwise + * we print "%p" to indicate that we don't handle "%p". + */ + case 'p': + if (sizeof(char *) <= sizeof(u_wide_int)) { + ui_num = (u_wide_int)((size_t) va_arg(ap, char *)); + s = ap_php_conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + if (ui_num != 0) { + *--s = 'x'; + *--s = '0'; + s_len += 2; + } + } else { + s = "%p"; + s_len = 2; + } + pad_char = ' '; + break; + + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + +fmt_error: + php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt); + /* + * The default case is for unrecognized %'s. + * We print % to help the user identify what + * option is not understood. + * This is also useful in case the user wants to pass + * the output of format_converter to another function + * that understands some other % (like syslog). + * Note that we can't point s inside fmt because the + * unknown could be preceded by width etc. + */ + default: + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + break; + } + + if (prefix_char != NUL) { + *--s = prefix_char; + s_len++; + } + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc) + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + /* + * Print the string s. + */ + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + if (free_zcopy) { + zval_dtor(&zcopy); + } + } +skip_output: + if (free_s) { + efree(free_s); + free_s = NULL; + } + + fmt++; + } + odp->nextb = sp; + return (cc); +} + +static void strx_printv(int *ccp, char *buf, size_t len, const char *format, zend_bool escape_xml, va_list ap TSRMLS_DC) { + buffy od; + int cc; + + /* + * First initialize the descriptor + * Notice that if no length is given, we initialize buf_end to the + * highest possible address. + */ + if (len == 0) { + od.buf_end = (char *) ~0; + od.nextb = (char *) ~0; + } else { + od.buf_end = &buf[len-1]; + od.nextb = buf; + } + + /* + * Do the conversion + */ + cc = format_converter(&od, format, escape_xml, ap TSRMLS_CC); + if (len != 0 && od.nextb <= od.buf_end) { + *(od.nextb) = '\0'; + } + if (ccp) { + *ccp = cc; + } +} + +static int phpdbg_xml_vsnprintf(char *buf, size_t len, const char *format, zend_bool escape_xml, va_list ap TSRMLS_DC) { + int cc; + + strx_printv(&cc, buf, len, format, escape_xml, ap TSRMLS_CC); + return (cc); +} + +PHPDBG_API int phpdbg_xml_vasprintf(char **buf, const char *format, zend_bool escape_xml, va_list ap TSRMLS_DC) { + va_list ap2; + int cc; + + va_copy(ap2, ap); + cc = phpdbg_xml_vsnprintf(NULL, 0, format, escape_xml, ap2 TSRMLS_CC); + va_end(ap2); + + *buf = NULL; + + if (cc >= 0) { + if ((*buf = emalloc(++cc)) != NULL) { + if ((cc = phpdbg_xml_vsnprintf(*buf, cc, format, escape_xml, ap TSRMLS_CC)) < 0) { + efree(*buf); + *buf = NULL; + } + } + } + + return cc; +} +/* copy end */ + +PHPDBG_API int _phpdbg_xml_asprintf(char **buf TSRMLS_DC, const char *format, zend_bool escape_xml, ...) { + int ret; + va_list va; + + va_start(va, escape_xml); + ret = phpdbg_xml_vasprintf(buf, format, escape_xml, va TSRMLS_CC); + va_end(va); + + return ret; +} + +PHPDBG_API int _phpdbg_asprintf(char **buf TSRMLS_DC, const char *format, ...) { + int ret; + va_list va; + + va_start(va, format); + ret = phpdbg_xml_vasprintf(buf, format, 0, va TSRMLS_CC); + va_end(va); + + return ret; +} + +static int phpdbg_encode_xml(char **buf, char *msg, int msglen, int from, char *to) { + int i; + int tolen = to ? strlen(to) : 5; + char *tmp = *buf = emalloc(msglen * tolen); + for (i = 0; i++ < msglen; msg++) { + if (*msg == '&') { + memcpy(tmp, ZEND_STRL("&")); + tmp += sizeof("&") - 1; + } else if (*msg == '<') { + memcpy(tmp, ZEND_STRL("<")); + tmp += sizeof("<") - 1; + } else if (((int) *msg) == from) { + memcpy(tmp, to, tolen); + tmp += tolen; + } else { + *tmp++ = *msg; + } + } + + { + int len = tmp - *buf; + *buf = erealloc(*buf, len + 1); + return len; + } +} + +static void phpdbg_encode_ctrl_chars(char **buf, int *buflen) { + char *tmp, *tmpptr; + int len; + int i; + + tmp = tmpptr = emalloc(*buflen * 5); + + for (i = 0; i < *buflen; i++) { + if ((*buf)[i] < 0x20) { + *tmpptr++ = '&'; + *tmpptr++ = '#'; + if ((unsigned int) ((*buf)[i]) > 9) { + *tmpptr++ = ((*buf)[i] / 10) + '0'; + } + *tmpptr++ = ((*buf)[i] % 10) + '0'; + *tmpptr++ = ';'; + } else { + *tmpptr++ = (*buf)[i]; + } + } + + len = tmpptr - tmp; + + efree(*buf); + *buf = erealloc(tmp, len + 1); + *buflen = len; +} + +static int phpdbg_process_print(int fd, int type, const char *tag, const char *msg, int msglen, const char *xml, int xmllen TSRMLS_DC) { + char *msgout = NULL, *buf; + int msgoutlen, xmloutlen, buflen; + const char *severity; + + if ((PHPDBG_G(flags) & PHPDBG_WRITE_XML) && PHPDBG_G(in_script_xml) && PHPDBG_G(in_script_xml) != type) { + phpdbg_mixed_write(fd, ZEND_STRL("") TSRMLS_CC); + PHPDBG_G(in_script_xml) = 0; + } + + switch (type) { + case P_ERROR: + severity = "error"; + if (!PHPDBG_G(last_was_newline)) { + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + phpdbg_mixed_write(fd, ZEND_STRL("\n" "") TSRMLS_CC); + } else { + phpdbg_mixed_write(fd, ZEND_STRL("\n") TSRMLS_CC); + } + PHPDBG_G(last_was_newline) = 1; + } + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + msgoutlen = phpdbg_asprintf(&msgout, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, msglen, msg); + } else { + msgoutlen = phpdbg_asprintf(&msgout, "[%.*s]\n", msglen, msg); + } + break; + + case P_NOTICE: + severity = "notice"; + if (!PHPDBG_G(last_was_newline)) { + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + phpdbg_mixed_write(fd, ZEND_STRL("\n" "") TSRMLS_CC); + } else { + phpdbg_mixed_write(fd, ZEND_STRL("\n") TSRMLS_CC); + } + PHPDBG_G(last_was_newline) = 1; + } + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + msgoutlen = phpdbg_asprintf(&msgout, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, msglen, msg); + } else { + msgoutlen = phpdbg_asprintf(&msgout, "[%.*s]\n", msglen, msg); + } + break; + + case P_WRITELN: + severity = "normal"; + if (msg) { + msgoutlen = phpdbg_asprintf(&msgout, "%.*s\n", msglen, msg); + } else { + msgoutlen = 1; + msgout = estrdup("\n"); + } + PHPDBG_G(last_was_newline) = 1; + break; + + case P_WRITE: + severity = "normal"; + if (msg) { + msgout = estrndup(msg, msglen); + msgoutlen = msglen; + PHPDBG_G(last_was_newline) = msg[msglen - 1] == '\n'; + } else { + msgoutlen = 0; + msgout = estrdup(""); + } + break; + + case P_STDOUT: + case P_STDERR: + if (msg) { + PHPDBG_G(last_was_newline) = msg[msglen - 1] == '\n'; + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + if (PHPDBG_G(in_script_xml) != type) { + char *stream_buf; + int stream_buflen = phpdbg_asprintf(&stream_buf, "", type == P_STDERR ? "stderr" : "stdout"); + phpdbg_mixed_write(fd, stream_buf, stream_buflen TSRMLS_CC); + efree(stream_buf); + PHPDBG_G(in_script_xml) = type; + } +#if PHP_VERSION_ID >= 50600 + buf = php_escape_html_entities((unsigned char *) msg, msglen, (size_t *) &buflen, 0, ENT_NOQUOTES, PG(internal_encoding) && PG(internal_encoding)[0] ? PG(internal_encoding) : (SG(default_charset) ? SG(default_charset) : "UTF-8") TSRMLS_CC); +#else + buf = php_escape_html_entities((unsigned char *) msg, msglen, (size_t *) &buflen, 0, ENT_NOQUOTES, SG(default_charset) ? SG(default_charset) : "UTF-8" TSRMLS_CC); +#endif + phpdbg_encode_ctrl_chars(&buf, &buflen); + phpdbg_mixed_write(fd, buf, buflen TSRMLS_CC); + efree(buf); + } else { + phpdbg_mixed_write(fd, msg, msglen TSRMLS_CC); + } + return msglen; + } + break; + + /* no formatting on logging output */ + case P_LOG: + severity = "log"; + if (msg) { + struct timeval tp; + if (gettimeofday(&tp, NULL) == SUCCESS) { + msgoutlen = phpdbg_asprintf(&msgout, "[%ld %.8F]: %.*s\n", tp.tv_sec, tp.tv_usec / 1000000., msglen, msg); + } else { + msgoutlen = FAILURE; + } + } + break; + } + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + char *xmlout; + + if (PHPDBG_G(req_id)) { + char *xmlbuf = NULL; + xmllen = phpdbg_asprintf(&xmlbuf, "req=\"%lu\" %.*s", PHPDBG_G(req_id), xmllen, xml); + xml = xmlbuf; + } + if (msgout) { + buflen = phpdbg_encode_xml(&buf, msgout, msgoutlen, '"', """); + xmloutlen = phpdbg_asprintf(&xmlout, "<%s severity=\"%s\" %.*s msgout=\"%.*s\" />", tag, severity, xmllen, xml, buflen, buf); + + efree(buf); + } else { + xmloutlen = phpdbg_asprintf(&xmlout, "<%s severity=\"%s\" %.*s msgout=\"\" />", tag, severity, xmllen, xml); + } + + phpdbg_encode_ctrl_chars(&xmlout, &xmloutlen); + phpdbg_eol_convert(&xmlout, &xmloutlen TSRMLS_CC); + phpdbg_mixed_write(fd, xmlout, xmloutlen TSRMLS_CC); + efree(xmlout); + } else if (msgout) { + phpdbg_eol_convert(&msgout, &msgoutlen TSRMLS_CC); + phpdbg_mixed_write(fd, msgout, msgoutlen TSRMLS_CC); + } + + if (PHPDBG_G(req_id) && (PHPDBG_G(flags) & PHPDBG_WRITE_XML)) { + efree((char *) xml); + } + + if (msgout) { + efree(msgout); + } + + return msgout ? msgoutlen : xmloutlen; +} /* }}} */ + +PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, va_list args) { + char *msg = NULL, *xml = NULL; + int msglen = 0, xmllen = 0; + int len; + va_list argcpy; + + if (strfmt != NULL && strlen(strfmt) > 0L) { + va_copy(argcpy, args); + msglen = phpdbg_xml_vasprintf(&msg, strfmt, 0, argcpy TSRMLS_CC); + va_end(argcpy); + } + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + if (xmlfmt != NULL && strlen(xmlfmt) > 0L) { + va_copy(argcpy, args); + xmllen = phpdbg_xml_vasprintf(&xml, xmlfmt, 1, argcpy TSRMLS_CC); + va_end(argcpy); + } else { + xml = estrdup(""); + } + } + + if (PHPDBG_G(err_buf).active && type != P_STDOUT && type != P_STDERR) { + PHPDBG_G(err_buf).type = type; + PHPDBG_G(err_buf).fd = fd; + PHPDBG_G(err_buf).tag = estrdup(tag); + PHPDBG_G(err_buf).msg = msg; + PHPDBG_G(err_buf).msglen = msglen; + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + PHPDBG_G(err_buf).xml = xml; + PHPDBG_G(err_buf).xmllen = xmllen; + } + + return msglen; + } + + len = phpdbg_process_print(fd, type, tag, msg, msglen, xml, xmllen TSRMLS_CC); + + if (msg) { + efree(msg); + } + + if (xml) { + efree(xml); + } + + return len; +} + +PHPDBG_API void phpdbg_free_err_buf(TSRMLS_D) { + if (PHPDBG_G(err_buf).type == 0) { + return; + } + + PHPDBG_G(err_buf).type = 0; + + efree(PHPDBG_G(err_buf).tag); + efree(PHPDBG_G(err_buf).msg); + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + efree(PHPDBG_G(err_buf).xml); + } +} + +PHPDBG_API void phpdbg_activate_err_buf(zend_bool active TSRMLS_DC) { + PHPDBG_G(err_buf).active = active; +} + +PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const char *strfmt TSRMLS_DC, ...) { + int len; + va_list args; + int errbuf_active = PHPDBG_G(err_buf).active; + + PHPDBG_G(err_buf).active = 0; + +#ifdef ZTS + va_start(args, tsrm_ls); +#else + va_start(args, strfmt); +#endif + len = phpdbg_vprint(PHPDBG_G(err_buf).type TSRMLS_CC, PHPDBG_G(err_buf).fd, tag ? tag : PHPDBG_G(err_buf).tag, xmlfmt, strfmt, args); + va_end(args); + + PHPDBG_G(err_buf).active = errbuf_active; + phpdbg_free_err_buf(TSRMLS_C); + + return len; +} + +PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) { + va_list args; + int len; + + va_start(args, strfmt); + len = phpdbg_vprint(type TSRMLS_CC, fd, tag, xmlfmt, strfmt, args); + va_end(args); + + return len; +} + +PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) { + int len = 0; + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + va_list args; + char *buffer; + int buflen; + + va_start(args, fmt); + buflen = phpdbg_xml_vasprintf(&buffer, fmt, 1, args TSRMLS_CC); + va_end(args); + + phpdbg_encode_ctrl_chars(&buffer, &buflen); + + if (PHPDBG_G(in_script_xml)) { + phpdbg_mixed_write(fd, ZEND_STRL("") TSRMLS_CC); + PHPDBG_G(in_script_xml) = 0; + } + + len = phpdbg_mixed_write(fd, buffer, buflen TSRMLS_CC); + efree(buffer); + } + + return len; +} + +PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...) { + va_list args; + char *buffer; + int buflen; + int len = 0; + + va_start(args, fmt); + buflen = phpdbg_xml_vasprintf(&buffer, fmt, 0, args TSRMLS_CC); + va_end(args); + + len = phpdbg_mixed_write(fd, buffer, buflen TSRMLS_CC); + efree(buffer); + + return len; +} + +PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) { + va_list args; + char *buffer; + int buflen; + int len = 0; + + va_start(args, fmt); + buflen = phpdbg_xml_vasprintf(&buffer, fmt, 0, args TSRMLS_CC); + va_end(args); + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + char *msg; + int msglen; + + msglen = phpdbg_encode_xml(&msg, buffer, buflen, 256, NULL); + phpdbg_encode_ctrl_chars(&msg, &msglen); + phpdbg_eol_convert(&msg, &msglen TSRMLS_CC); + + if (PHPDBG_G(in_script_xml)) { + phpdbg_mixed_write(fd, ZEND_STRL("") TSRMLS_CC); + PHPDBG_G(in_script_xml) = 0; + } + + phpdbg_mixed_write(fd, ZEND_STRL("") TSRMLS_CC); + len = phpdbg_mixed_write(fd, msg, msglen TSRMLS_CC); + phpdbg_mixed_write(fd, ZEND_STRL("") TSRMLS_CC); + } else { + phpdbg_eol_convert(&buffer, &buflen TSRMLS_CC); + len = phpdbg_mixed_write(fd, buffer, buflen TSRMLS_CC); + } + + return len; +} + + +PHPDBG_API int phpdbg_rlog_internal(int fd TSRMLS_DC, const char *fmt, ...) { /* {{{ */ + int rc = 0; + + va_list args; + struct timeval tp; + + va_start(args, fmt); + if (gettimeofday(&tp, NULL) == SUCCESS) { + char friendly[100]; + char *format = NULL, *buffer = NULL, *outbuf = NULL; + const time_t tt = tp.tv_sec; + +#ifdef PHP_WIN32 + strftime(friendly, 100, "%a %b %d %H.%%04d %Y", localtime(&tt)); +#else + strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt)); +#endif + phpdbg_asprintf(&buffer, friendly, tp.tv_usec/1000); + phpdbg_asprintf(&format, "[%s]: %s\n", buffer, fmt); + rc = phpdbg_xml_vasprintf(&outbuf, format, 0, args TSRMLS_CC); + + if (outbuf) { + rc = phpdbg_mixed_write(fd, outbuf, rc TSRMLS_CC); + efree(outbuf); + } + + efree(format); + efree(buffer); + } + va_end(args); + + return rc; +} /* }}} */ diff --git a/phpdbg_out.h b/phpdbg_out.h new file mode 100644 index 0000000000..ea25b04279 --- /dev/null +++ b/phpdbg_out.h @@ -0,0 +1,93 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_OUT_H +#define PHPDBG_OUT_H + +/** + * Error/notice/formatting helpers + */ +enum { + P_ERROR = 1, + P_NOTICE, + P_WRITELN, + P_WRITE, + P_STDOUT, + P_STDERR, + P_LOG +}; + +#ifdef ZTS +PHPDBG_API int phpdbg_print(int severity TSRMLS_DC, 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 TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +PHPDBG_API int phpdbg_rlog_internal(int fd TSRMLS_DC, 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 TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_notice(tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_writeln(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_write(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_script(type, fmt, ...) phpdbg_print(type TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, NULL, NULL, fmt, ##__VA_ARGS__) +#define phpdbg_log(fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_xml(fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_out(fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) + +#define phpdbg_error_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_notice_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_writeln_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_write_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_script_ex(out, type, fmt, ...) phpdbg_print(type TSRMLS_CC, out, NULL, NULL, fmt, ##__VA_ARGS__) +#define phpdbg_log_ex(out, fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_xml_ex(out, fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_out_ex(out, fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) + +#define phpdbg_rlog(fd, fmt, ...) phpdbg_rlog_internal(fd TSRMLS_CC, fmt, ##__VA_ARGS__) + +#define phpdbg_xml_asprintf(buf, ...) _phpdbg_xml_asprintf(buf TSRMLS_CC, ##__VA_ARGS__) +PHPDBG_API int _phpdbg_xml_asprintf(char **buf TSRMLS_DC, const char *format, zend_bool escape_xml, ...); + +#define phpdbg_asprintf(buf, ...) _phpdbg_asprintf(buf TSRMLS_CC, ##__VA_ARGS__) +PHPDBG_API int _phpdbg_asprintf(char **buf TSRMLS_DC, const char *format, ...); + + +#if PHPDBG_DEBUG +# define phpdbg_debug(fmt, ...) phpdbg_log_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#else +# define phpdbg_debug(fmt, ...) +#endif + +PHPDBG_API void phpdbg_free_err_buf(TSRMLS_D); +PHPDBG_API void phpdbg_activate_err_buf(zend_bool active TSRMLS_DC); +PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const char *strfmt TSRMLS_DC, ...); + + +/* {{{ For separation */ +#define SEPARATE "------------------------------------------------" /* }}} */ + +#endif /* PHPDBG_OUT_H */ diff --git a/phpdbg_parser.c b/phpdbg_parser.c index e34c2f48ff..c766868369 100644 --- a/phpdbg_parser.c +++ b/phpdbg_parser.c @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.6.2. */ +/* A Bison parser, made by GNU Bison 2.5. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.6.2" +#define YYBISON_VERSION "2.5" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -58,6 +58,8 @@ /* Pull parsers. */ #define YYPULL 1 +/* Using locations. */ +#define YYLSP_NEEDED 0 /* Substitute the variable and function names. */ #define yyparse phpdbg_parse @@ -68,9 +70,11 @@ #define yydebug phpdbg_debug #define yynerrs phpdbg_nerrs + /* Copy the first part of user declarations. */ -/* Line 336 of yacc.c */ -#line 1 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 268 of yacc.c */ +#line 1 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" /* @@ -97,16 +101,14 @@ static int yyerror(void ***tsrm_ls, const char *msg); ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -/* Line 336 of yacc.c */ -#line 102 "sapi/phpdbg/phpdbg_parser.c" -# ifndef YY_NULL -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULL nullptr -# else -# define YY_NULL 0 -# endif -# endif +/* Line 268 of yacc.c */ +#line 107 "sapi/phpdbg/phpdbg_parser.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE @@ -116,20 +118,15 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); # define YYERROR_VERBOSE 1 #endif -/* In a future release of Bison, this section will be replaced - by #include "phpdbg_parser.h". */ -#ifndef PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H -# define PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int phpdbg_debug; +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 #endif + /* "%code requires" blocks. */ -/* Line 350 of yacc.c */ -#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 288 of yacc.c */ +#line 31 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -138,8 +135,9 @@ typedef void* yyscan_t; #endif -/* Line 350 of yacc.c */ -#line 143 "sapi/phpdbg/phpdbg_parser.c" + +/* Line 288 of yacc.c */ +#line 141 "sapi/phpdbg/phpdbg_parser.c" /* Tokens. */ #ifndef YYTOKENTYPE @@ -164,7 +162,8 @@ typedef void* yyscan_t; T_OPCODE = 272, T_ID = 273, T_INPUT = 274, - T_UNEXPECTED = 275 + T_UNEXPECTED = 275, + T_REQ_ID = 276 }; #endif /* Tokens. */ @@ -186,6 +185,8 @@ typedef void* yyscan_t; #define T_ID 273 #define T_INPUT 274 #define T_UNEXPECTED 275 +#define T_REQ_ID 276 + @@ -197,26 +198,11 @@ 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 *tsrm_ls); -#else -int phpdbg_parse (); -#endif -#endif /* ! YYPARSE_PARAM */ - -#endif /* !PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H */ - /* Copy the second part of user declarations. */ -/* Line 353 of yacc.c */ -#line 220 "sapi/phpdbg/phpdbg_parser.c" + +/* Line 343 of yacc.c */ +#line 206 "sapi/phpdbg/phpdbg_parser.c" #ifdef short # undef short @@ -322,7 +308,6 @@ YYID (yyi) # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif @@ -414,42 +399,42 @@ union yyalloc #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do +/* Copy COUNT objects from FROM to TO. 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))) +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ while (YYID (0)) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 25 +#define YYFINAL 26 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 42 +#define YYLAST 48 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 21 +#define YYNTOKENS 22 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 5 +#define YYNNTS 6 /* YYNRULES -- Number of rules. */ -#define YYNRULES 25 +#define YYNRULES 28 /* YYNRULES -- Number of states. */ -#define YYNSTATES 38 +#define YYNSTATES 43 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 275 +#define YYMAXUTOK 276 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -484,7 +469,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 + 15, 16, 17, 18, 19, 20, 21 }; #if YYDEBUG @@ -492,34 +477,35 @@ static const yytype_uint8 yytranslate[] = YYRHS. */ static const yytype_uint8 yyprhs[] = { - 0, 0, 3, 5, 7, 8, 10, 13, 17, 22, - 27, 33, 37, 43, 47, 50, 52, 54, 56, 58, - 60, 62, 64, 67, 70, 72 + 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 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 22, 0, -1, 23, -1, 25, -1, -1, 24, -1, - 23, 24, -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, 3, 19, -1, 5, 19, -1, - 4, -1, 4, 19, -1 + 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 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 66, 66, 67, 68, 72, 73, 77, 82, 87, - 97, 107, 112, 118, 124, 129, 130, 131, 132, 133, - 134, 135, 139, 144, 149, 153 + 0, 67, 67, 68, 69, 73, 74, 75, 79, 84, + 89, 99, 109, 114, 120, 126, 131, 132, 133, 134, + 135, 136, 137, 141, 142, 146, 151, 156, 160 }; #endif -#if YYDEBUG || YYERROR_VERBOSE || 1 +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = @@ -531,8 +517,9 @@ static const char *const yytname[] = "\":: (double colon)\"", "\"# (pound sign)\"", "\"protocol (file://)\"", "\"digits (numbers)\"", "\"literal (string)\"", "\"address\"", "\"opcode\"", "\"identifier (command or function name)\"", - "\"input (input string or data)\"", "\"input\"", "$accept", "input", - "parameters", "parameter", "full_expression", YY_NULL + "\"input (input string or data)\"", "\"input\"", + "\"request id (-r %d)\"", "$accept", "input", "parameters", "parameter", + "req_id", "full_expression", 0 }; #endif @@ -543,24 +530,24 @@ 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 + 275, 276 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 21, 22, 22, 22, 23, 23, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 25, 25, 25, 25 + 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 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 1, 1, 0, 1, 2, 3, 4, 4, - 5, 3, 5, 3, 2, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 1, 2 + 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 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. @@ -568,33 +555,35 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 4, 0, 24, 0, 0, 18, 19, 0, 20, 17, - 16, 15, 21, 0, 2, 5, 3, 22, 25, 23, - 14, 0, 0, 0, 0, 1, 6, 0, 0, 7, - 11, 13, 0, 9, 8, 0, 10, 12 + 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 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 13, 14, 15, 16 + -1, 13, 14, 15, 18, 16 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -11 +#define YYPACT_NINF -16 static const yytype_int8 yypact[] = { - -3, -10, 11, 12, 13, -11, -11, 15, -11, -11, - -11, -11, -4, 29, 10, -11, -11, -11, -11, -11, - -11, 24, 7, 17, 22, -11, -11, 8, 23, -11, - 26, -11, 25, -11, -11, 27, -11, -11 + -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 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -11, -11, -11, 28, -11 + -16, -16, -16, 34, 5, -16 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -603,26 +592,26 @@ static const yytype_int8 yypgoto[] = #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { - 1, 2, 3, 4, 5, 6, 22, 23, 24, 17, + 1, 2, 3, 4, 5, 6, 17, 19, 20, 21, 7, 8, 9, 10, 11, 12, 4, 5, 6, 28, - 32, 29, 33, 7, 8, 9, 10, 11, 12, 25, - 18, 19, 20, 21, 27, 30, 31, 34, 35, 36, - 0, 37, 26 + 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 }; #define yypact_value_is_default(yystate) \ - ((yystate) == (-11)) + ((yystate) == (-16)) #define yytable_value_is_error(yytable_value) \ YYID (0) static const yytype_int8 yycheck[] = { - 3, 4, 5, 6, 7, 8, 10, 11, 12, 19, - 13, 14, 15, 16, 17, 18, 6, 7, 8, 12, - 12, 14, 14, 13, 14, 15, 16, 17, 18, 0, - 19, 19, 19, 18, 10, 18, 14, 14, 12, 14, - -1, 14, 14 + 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 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -630,9 +619,10 @@ static const yytype_int8 yycheck[] = static const yytype_uint8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 13, 14, 15, - 16, 17, 18, 22, 23, 24, 25, 19, 19, 19, - 19, 18, 10, 11, 12, 0, 24, 10, 12, 14, - 18, 14, 12, 14, 14, 12, 14, 14 + 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 }; #define yyerrok (yyerrstatus = 0) @@ -662,18 +652,17 @@ static const yytype_uint8 yystos[] = #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ yyerror (tsrm_ls, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ @@ -683,33 +672,32 @@ while (YYID (0)) #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; \ - } \ +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ while (YYID (0)) #endif -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) - - /* This macro is provided for backward compatibility. */ @@ -770,8 +758,6 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, tsrm_ls) void *tsrm_ls; #endif { - FILE *yyo = yyoutput; - YYUSE (yyo); if (!yyvaluep) return; YYUSE (tsrm_ls); @@ -1026,12 +1012,12 @@ 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 yysize0 = yytnamerr (0, yytname[yytoken]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ - const char *yyformat = YY_NULL; + const char *yyformat = 0; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per @@ -1091,7 +1077,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, break; } yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + yysize1 = yysize + yytnamerr (0, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; @@ -1185,6 +1171,20 @@ yydestruct (yymsg, yytype, yyvaluep, tsrm_ls) } +/* 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 *tsrm_ls); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ /*----------. @@ -1230,7 +1230,7 @@ YYSTYPE yylval; `yyss': related to states. `yyvs': related to semantic values. - Refer to the stacks through separate pointers, to allow yyoverflow + Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ @@ -1284,6 +1284,7 @@ YYSTYPE yylval; The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; + goto yysetstate; /*------------------------------------------------------------. @@ -1461,26 +1462,37 @@ yyreduce: switch (yyn) { case 3: -/* Line 1802 of yacc.c */ -#line 67 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 68 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 5: -/* Line 1802 of yacc.c */ -#line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 73 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 6: -/* Line 1802 of yacc.c */ -#line 73 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 74 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); } break; case 7: -/* Line 1802 of yacc.c */ -#line 77 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 75 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (2)]); } + break; + + case 8: + +/* Line 1806 of yacc.c */ +#line 79 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; (yyval).file.name = (yyvsp[(2) - (3)]).str; @@ -1488,9 +1500,10 @@ yyreduce: } break; - case 8: -/* Line 1802 of yacc.c */ -#line 82 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 9: + +/* Line 1806 of yacc.c */ +#line 84 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; (yyval).file.name = (yyvsp[(1) - (4)]).str; @@ -1498,9 +1511,10 @@ yyreduce: } break; - case 9: -/* Line 1802 of yacc.c */ -#line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 10: + +/* Line 1806 of yacc.c */ +#line 89 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; (yyval).file.name = malloc((yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len + 1); @@ -1513,9 +1527,10 @@ yyreduce: } break; - case 10: -/* Line 1802 of yacc.c */ -#line 97 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 11: + +/* Line 1806 of yacc.c */ +#line 99 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; (yyval).file.name = malloc((yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len + 1); @@ -1528,9 +1543,10 @@ yyreduce: } break; - case 11: -/* Line 1802 of yacc.c */ -#line 107 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 12: + +/* Line 1806 of yacc.c */ +#line 109 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (3)]).str; @@ -1538,9 +1554,10 @@ yyreduce: } break; - case 12: -/* Line 1802 of yacc.c */ -#line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 13: + +/* Line 1806 of yacc.c */ +#line 114 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (5)]).str; @@ -1549,9 +1566,10 @@ yyreduce: } break; - case 13: -/* Line 1802 of yacc.c */ -#line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 14: + +/* Line 1806 of yacc.c */ +#line 120 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FUNCTION_PARAM; (yyval).str = (yyvsp[(1) - (3)]).str; @@ -1560,9 +1578,10 @@ yyreduce: } break; - case 14: -/* Line 1802 of yacc.c */ -#line 124 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 15: + +/* Line 1806 of yacc.c */ +#line 126 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = COND_PARAM; (yyval).str = (yyvsp[(2) - (2)]).str; @@ -1570,90 +1589,109 @@ yyreduce: } break; - case 15: -/* Line 1802 of yacc.c */ -#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } - break; - case 16: -/* Line 1802 of yacc.c */ -#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 131 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 17: -/* Line 1802 of yacc.c */ -#line 131 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 132 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 18: -/* Line 1802 of yacc.c */ -#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 133 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 19: -/* Line 1802 of yacc.c */ -#line 133 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 134 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 20: -/* Line 1802 of yacc.c */ -#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 135 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 21: -/* Line 1802 of yacc.c */ -#line 135 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 136 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 22: -/* Line 1802 of yacc.c */ -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1806 of yacc.c */ +#line 137 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 23: + +/* Line 1806 of yacc.c */ +#line 141 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" + { PHPDBG_G(req_id) = (yyvsp[(1) - (1)]).num; } + break; + + case 25: + +/* Line 1806 of yacc.c */ +#line 146 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = EVAL_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; + (yyval).str = (yyvsp[(3) - (3)]).str; + (yyval).len = (yyvsp[(3) - (3)]).len; } break; - case 23: -/* Line 1802 of yacc.c */ -#line 144 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 26: + +/* Line 1806 of yacc.c */ +#line 151 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = SHELL_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; + (yyval).str = (yyvsp[(3) - (3)]).str; + (yyval).len = (yyvsp[(3) - (3)]).len; } break; - case 24: -/* Line 1802 of yacc.c */ -#line 149 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 27: + +/* Line 1806 of yacc.c */ +#line 156 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = RUN_PARAM; (yyval).len = 0; } break; - case 25: -/* Line 1802 of yacc.c */ -#line 153 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 28: + +/* Line 1806 of yacc.c */ +#line 160 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = RUN_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; + (yyval).str = (yyvsp[(3) - (3)]).str; + (yyval).len = (yyvsp[(3) - (3)]).len; } break; -/* Line 1802 of yacc.c */ -#line 1657 "sapi/phpdbg/phpdbg_parser.c" + +/* Line 1806 of yacc.c */ +#line 1695 "sapi/phpdbg/phpdbg_parser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1840,7 +1878,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined yyoverflow || YYERROR_VERBOSE +#if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -1882,12 +1920,13 @@ yyreturn: } -/* Line 2048 of yacc.c */ -#line 160 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 2067 of yacc.c */ +#line 167 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" static int yyerror(void ***tsrm_ls, const char *msg) { - phpdbg_error("Parse Error: %s", msg); + phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg); { const phpdbg_param_t *top = PHPDBG_G(parser_stack); @@ -1909,3 +1948,4 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) { return yyparse(NULL); #endif } + diff --git a/phpdbg_parser.h b/phpdbg_parser.h index b3aadb9c62..dfa155d718 100644 --- a/phpdbg_parser.h +++ b/phpdbg_parser.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.6.2. */ +/* A Bison parser, made by GNU Bison 2.5. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,18 +30,10 @@ This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ -#ifndef PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H -# define PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int phpdbg_debug; -#endif /* "%code requires" blocks. */ -/* Line 2055 of yacc.c */ -#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 2068 of yacc.c */ +#line 31 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -50,8 +42,9 @@ typedef void* yyscan_t; #endif -/* Line 2055 of yacc.c */ -#line 55 "sapi/phpdbg/phpdbg_parser.h" + +/* Line 2068 of yacc.c */ +#line 48 "sapi/phpdbg/phpdbg_parser.h" /* Tokens. */ #ifndef YYTOKENTYPE @@ -76,7 +69,8 @@ typedef void* yyscan_t; T_OPCODE = 272, T_ID = 273, T_INPUT = 274, - T_UNEXPECTED = 275 + T_UNEXPECTED = 275, + T_REQ_ID = 276 }; #endif /* Tokens. */ @@ -98,6 +92,8 @@ typedef void* yyscan_t; #define T_ID 273 #define T_INPUT 274 #define T_UNEXPECTED 275 +#define T_REQ_ID 276 + @@ -109,18 +105,5 @@ 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 *tsrm_ls); -#else -int phpdbg_parse (); -#endif -#endif /* ! YYPARSE_PARAM */ -#endif /* !PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H */ + diff --git a/phpdbg_parser.y b/phpdbg_parser.y index 702bf78455..e4353976f3 100644 --- a/phpdbg_parser.y +++ b/phpdbg_parser.y @@ -59,6 +59,7 @@ typedef void* yyscan_t; %token T_ID "identifier (command or function name)" %token T_INPUT "input (input string or data)" %token T_UNEXPECTED "input" +%token T_REQ_ID "request id (-r %d)" %% /* Rules */ @@ -71,6 +72,7 @@ input parameters : parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); } | parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); } + | parameters req_id { $$ = $1; } ; parameter @@ -135,32 +137,37 @@ parameter | T_ID { $$ = $1; } ; +req_id + : T_REQ_ID { PHPDBG_G(req_id) = $1.num; } + | /* empty */ +; + full_expression - : T_EVAL T_INPUT { + : T_EVAL req_id T_INPUT { $$.type = EVAL_PARAM; - $$.str = $2.str; - $$.len = $2.len; + $$.str = $3.str; + $$.len = $3.len; } - | T_SHELL T_INPUT { + | T_SHELL req_id T_INPUT { $$.type = SHELL_PARAM; - $$.str = $2.str; - $$.len = $2.len; + $$.str = $3.str; + $$.len = $3.len; } - | T_RUN { + | T_RUN req_id { $$.type = RUN_PARAM; $$.len = 0; } - | T_RUN T_INPUT { + | T_RUN req_id T_INPUT { $$.type = RUN_PARAM; - $$.str = $2.str; - $$.len = $2.len; + $$.str = $3.str; + $$.len = $3.len; } ; %% static int yyerror(void ***tsrm_ls, const char *msg) { - phpdbg_error("Parse Error: %s", msg); + phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg); { const phpdbg_param_t *top = PHPDBG_G(parser_stack); diff --git a/phpdbg_print.c b/phpdbg_print.c index 76321a5042..80eeddb39d 100644 --- a/phpdbg_print.c +++ b/phpdbg_print.c @@ -26,16 +26,16 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9]) +#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[9], flags) const phpdbg_command_t phpdbg_print_commands[] = { - PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0), - PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0), - PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s"), - PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m"), - PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s"), - PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0), + PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m", PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0, PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; @@ -44,7 +44,7 @@ PHPDBG_PRINT(opline) /* {{{ */ if (EG(in_execution) && EG(current_execute_data)) { phpdbg_print_opline(EG(current_execute_data), 1 TSRMLS_CC); } else { - phpdbg_error("Not Executing!"); + phpdbg_error("inactive", "type=\"execution\"", "Not Executing!"); } return SUCCESS; @@ -56,21 +56,22 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) case ZEND_USER_FUNCTION: { zend_op_array* op_array = &(method->op_array); HashTable vars; - + if (op_array) { zend_op *opline = &(op_array->opcodes[0]); zend_uint opcode = 0, end = op_array->last-1; if (method->common.scope) { - phpdbg_writeln("\tL%d-%d %s::%s() %s", - op_array->line_start, op_array->line_end, + phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" method=\"%s::%s\" file=\"%s\"", "\tL%d-%d %s::%s() %s", + op_array->line_start, + op_array->line_end, method->common.scope->name, method->common.function_name, op_array->filename ? op_array->filename : "unknown"); } else { - phpdbg_writeln("\tL%d-%d %s() %s", - method->common.function_name ? op_array->line_start : 0, + phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" function=\"%s\" file=\"%s\"", "\tL%d-%d %s() %s", + method->common.function_name ? op_array->line_start : 0, method->common.function_name ? op_array->line_end : 0, method->common.function_name ? method->common.function_name : "{main}", op_array->filename ? op_array->filename : "unknown"); @@ -80,14 +81,14 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) do { char *decode = phpdbg_decode_opline(op_array, opline, &vars TSRMLS_CC); if (decode != NULL) { - phpdbg_writeln("\t\tL%u\t%p %-30s %s", + phpdbg_writeln("print", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\"", "\t\tL%u\t%p %-30s %s", opline->lineno, - opline, + opline, phpdbg_decode_opcode(opline->opcode), decode); free(decode); } else { - phpdbg_error("\tFailed to decode opline %16p", opline); + phpdbg_error("print", "type=\"decodefailure\" opline=\"%16p\"", "\tFailed to decode opline %16p", opline); } opline++; } while (opcode++ < end); @@ -97,9 +98,9 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) default: { if (method->common.scope) { - phpdbg_writeln("\tInternal %s::%s()", method->common.scope->name, method->common.function_name); + phpdbg_writeln("printoplineinfo", "type=\"Internal\" method=\"%s::%s\"", "Internal %s::%s()", method->common.scope->name, method->common.function_name); } else { - phpdbg_writeln("\tInternal %s()", method->common.function_name); + phpdbg_writeln("printoplineinfo", "type=\"Internal\" function=\"%s\"", "\tInternal %s()", method->common.function_name); } } } @@ -108,17 +109,17 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) PHPDBG_PRINT(exec) /* {{{ */ { if (PHPDBG_G(exec)) { - if (!PHPDBG_G(ops)) { + if (!PHPDBG_G(ops) && !(PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER)) { phpdbg_compile(TSRMLS_C); } if (PHPDBG_G(ops)) { - phpdbg_notice("Context %s", PHPDBG_G(exec)); + phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Context %s (%d ops)", PHPDBG_G(exec), PHPDBG_G(ops)->last); phpdbg_print_function_helper((zend_function*) PHPDBG_G(ops) TSRMLS_CC); } } else { - phpdbg_error("No execution context set"); + phpdbg_error("inactive", "type=\"nocontext\"", "No execution context set"); } return SUCCESS; @@ -127,24 +128,24 @@ return SUCCESS; PHPDBG_PRINT(stack) /* {{{ */ { zend_op_array *ops = EG(active_op_array); - + if (EG(in_execution) && ops) { if (ops->function_name) { if (ops->scope) { - phpdbg_notice("Stack in %s::%s()", ops->scope->name, ops->function_name); + phpdbg_notice("printinfo", "method=\"%s::%s\" num=\"%d\"", "Stack in %s::%s() (%d ops)", ops->scope->name, ops->function_name, ops->last); } else { - phpdbg_notice("Stack in %s()", ops->function_name); + phpdbg_notice("printinfo", "function=\"%s\" num=\"%d\"", "Stack in %s() (%d ops)", ops->function_name, ops->last); } } else { if (ops->filename) { - phpdbg_notice("Stack in %s", ops->filename); + phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Stack in %s (%d ops)", ops->filename, ops->last); } else { - phpdbg_notice("Stack @ %p", ops); + phpdbg_notice("printinfo", "opline=\"%p\" num=\"%d\"", "Stack @ %p (%d ops)", ops, ops->last); } } phpdbg_print_function_helper((zend_function*) ops TSRMLS_CC); } else { - phpdbg_error("Not Executing!"); + phpdbg_error("inactive", "type=\"execution\"", "Not Executing!"); } return SUCCESS; @@ -154,8 +155,8 @@ PHPDBG_PRINT(class) /* {{{ */ { zend_class_entry **ce; - if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { - phpdbg_notice("%s %s: %s", + if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + phpdbg_notice("printinfo", "type=\"%s\" flag=\"%s\" class=\"%s\" num=\"%d\"", "%s %s: %s (%d methods)", ((*ce)->type == ZEND_USER_CLASS) ? "User" : "Internal", ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? @@ -163,9 +164,11 @@ PHPDBG_PRINT(class) /* {{{ */ ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? "Abstract Class" : "Class", - (*ce)->name); + (*ce)->name, + zend_hash_num_elements(&(*ce)->function_table)); + + phpdbg_xml(""); - phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table)); if (zend_hash_num_elements(&(*ce)->function_table)) { HashPosition position; zend_function *method; @@ -176,8 +179,10 @@ PHPDBG_PRINT(class) /* {{{ */ phpdbg_print_function_helper(method TSRMLS_CC); } } + + phpdbg_xml(""); } else { - phpdbg_error("The class %s could not be found", param->str); + phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->str); } return SUCCESS; @@ -187,23 +192,24 @@ PHPDBG_PRINT(method) /* {{{ */ { zend_class_entry **ce; - if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { zend_function *fbc; char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { - phpdbg_notice("%s Method %s", + phpdbg_notice("printinfo", "type=\"%s\" flags=\"Method\" symbol=\"%s\" num=\"%d\"", "%s Method %s (%d ops)", (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", - fbc->common.function_name); + fbc->common.function_name, + (fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0); phpdbg_print_function_helper(fbc TSRMLS_CC); } else { - phpdbg_error("The method %s could not be found", param->method.name); + phpdbg_error("print", "type=\"nomethod\" method=\"%s::%s\"", "The method %s::%s could not be found", param->method.class, param->method.name); } efree(lcname); } else { - phpdbg_error("The class %s could not be found", param->method.class); + phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->method.class); } return SUCCESS; @@ -224,28 +230,33 @@ PHPDBG_PRINT(func) /* {{{ */ func_table = &EG(scope)->function_table; } else { - phpdbg_error("No active class"); + phpdbg_error("inactive", "type=\"noclasses\"", "No active class"); return SUCCESS; } } else if (!EG(function_table)) { - phpdbg_error("No function table loaded"); + phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded"); return SUCCESS; } else { func_table = EG(function_table); } - lcname = zend_str_tolower_dup(func_name, func_name_len); + lcname = zend_str_tolower_dup(func_name, func_name_len); - if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { - phpdbg_notice("%s %s %s", - (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", - (fbc->common.scope) ? "Method" : "Function", - fbc->common.function_name); + phpdbg_try_access { + if (zend_hash_find(func_table, lcname, func_name_len + 1, (void **) &fbc) == SUCCESS) { + phpdbg_notice("printinfo", "type=\"%s\" flags=\"%s\" symbol=\"%s\" num=\"%d\"", "%s %s %s (%d ops)", + (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", + (fbc->common.scope) ? "Method" : "Function", + fbc->common.function_name, + (fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0); - phpdbg_print_function_helper(fbc TSRMLS_CC); - } else { - phpdbg_error("The function %s could not be found", func_name); - } + phpdbg_print_function_helper(fbc TSRMLS_CC); + } else { + phpdbg_error("print", "type=\"nofunction\" function=\"%s\"", "The function %s could not be found", func_name); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "function=\"%.*s\"", "Couldn't fetch function %.*s, invalid data source", (int) func_name_len, func_name); + } phpdbg_end_try_access(); efree(lcname); diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index d91ef3f3f5..82444fbf1d 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -23,6 +23,7 @@ #include "zend.h" #include "zend_compile.h" #include "phpdbg.h" + #include "phpdbg_help.h" #include "phpdbg_print.h" #include "phpdbg_info.h" @@ -37,56 +38,76 @@ #include "phpdbg_frame.h" #include "phpdbg_lexer.h" #include "phpdbg_parser.h" +#include "phpdbg_wait.h" +#include "phpdbg_eol.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +#ifdef HAVE_LIBDL +#ifdef PHP_WIN32 +#include "win32/param.h" +#include "win32/winutil.h" +#define GET_DL_ERROR() php_win_err() +#elif defined(NETWARE) +#include +#define GET_DL_ERROR() dlerror() +#else +#include +#define GET_DL_ERROR() DL_ERROR() +#endif +#endif /* {{{ command declarations */ const phpdbg_command_t phpdbg_prompt_commands[] = { - PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s"), - PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0), - PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0), - PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s"), - PHPDBG_COMMAND_D(ev, "evaluate some code", 0, NULL, "i"), - PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0), - PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0), - PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0), - PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 0), - PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c"), - PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n"), - PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n"), - PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*"), - PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s"), - PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0), - PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0), - PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s"), - PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s"), - PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s"), - PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s"), - PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s"), - PHPDBG_COMMAND_D(sh, "shell a command", 0, NULL, "i"), - PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0), - PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss"), + 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, 0, 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(eol, "set EOL", 'E', NULL, "|s", 0), PHPDBG_END_COMMAND }; /* }}} */ -ZEND_EXTERN_MODULE_GLOBALS(phpdbg); - static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ */ { phpdbg_param_t *name = NULL; if (stack->type == STACK_PARAM) { + char *lc_name; + name = stack->next; - + if (!name || name->type != STR_PARAM) { return FAILURE; } - - if (zend_hash_exists( - &PHPDBG_G(registered), name->str, name->len+1)) { + lc_name = zend_str_tolower_dup(name->str, name->len); + + if (zend_hash_exists(&PHPDBG_G(registered), lc_name, name->len+1)) { zval fname, *fretval; zend_fcall_info fci; - ZVAL_STRINGL(&fname, name->str, name->len, 1); + ZVAL_STRINGL(&fname, lc_name, name->len, 1); memset(&fci, 0, sizeof(zend_fcall_info)); @@ -101,62 +122,59 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ * if (name->next) { zval params; phpdbg_param_t *next = name->next; - + array_init(¶ms); while (next) { char *buffered = NULL; - + switch (next->type) { case OP_PARAM: case COND_PARAM: case STR_PARAM: - add_next_index_stringl( - ¶ms, - next->str, - next->len, 1); + add_next_index_stringl(¶ms, next->str, next->len, 1); break; - + case NUMERIC_PARAM: add_next_index_long(¶ms, next->num); break; - + case METHOD_PARAM: spprintf(&buffered, 0, "%s::%s", next->method.class, next->method.name); add_next_index_string(¶ms, buffered, 0); break; - + case NUMERIC_METHOD_PARAM: spprintf(&buffered, 0, "%s::%s#%ld", next->method.class, next->method.name, next->num); add_next_index_string(¶ms, buffered, 0); break; - + case NUMERIC_FUNCTION_PARAM: spprintf(&buffered, 0, "%s#%ld", next->str, next->num); add_next_index_string(¶ms, buffered, 0); break; - + case FILE_PARAM: - spprintf(&buffered, 0, "%s:%ld", + spprintf(&buffered, 0, "%s:%ld", next->file.name, next->file.line); add_next_index_string(¶ms, buffered, 0); break; - + case NUMERIC_FILE_PARAM: - spprintf(&buffered, 0, "%s:#%ld", + spprintf(&buffered, 0, "%s:#%ld", next->file.name, next->file.line); add_next_index_string(¶ms, buffered, 0); break; - + default: { /* not yet */ } } - - next = next->next; + + next = next->next; } zend_fcall_info_args(&fci, ¶ms TSRMLS_CC); @@ -165,22 +183,25 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ * fci.param_count = 0; } - phpdbg_debug( - "created %d params from arguments", - fci.param_count); + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); + + phpdbg_debug("created %d params from arguments", fci.param_count); zend_call_function(&fci, NULL TSRMLS_CC); if (fretval) { - zend_print_zval_r( - fretval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); + zend_print_zval_r(fretval, 0 TSRMLS_CC); + phpdbg_out("\n"); } zval_dtor(&fname); + efree(lc_name); return SUCCESS; - } + } + + efree(lc_name); } return FAILURE; @@ -189,7 +210,7 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ * void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */ { struct stat sb; - + if (init_file && VCWD_STAT(init_file, &sb) != -1) { FILE *fp = fopen(init_file, "r"); if (fp) { @@ -219,8 +240,7 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ in_code = 0; code[code_len] = '\0'; { - zend_eval_stringl( - code, code_len, NULL, "phpdbginit code" TSRMLS_CC); + zend_eval_stringl(code, code_len, NULL, "phpdbginit code" TSRMLS_CC); } free(code); code = NULL; @@ -243,30 +263,26 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ } { - char *why = NULL; char *input = phpdbg_read_input(cmd TSRMLS_CC); phpdbg_param_t stack; phpdbg_init_param(&stack, STACK_PARAM); + phpdbg_activate_err_buf(1 TSRMLS_CC); + if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { - switch (phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */ TSRMLS_CC)) { case FAILURE: -// if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { - phpdbg_error( - "Unrecognized command in %s:%d: %s, %s!", - init_file, line, input, why); - } -// } + phpdbg_activate_err_buf(0 TSRMLS_CC); + if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + phpdbg_output_err_buf("initfailure", "%b file=\"%s\" line=\"%d\" input=\"%s\"", "Unrecognized command in %s:%d: %s, %b!" TSRMLS_CC, init_file, line, input); + } break; } } - if (why) { - free(why); - why = NULL; - } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); @@ -282,8 +298,7 @@ next_line: fclose(fp); } else { - phpdbg_error( - "Failed to open %s for initialization", init_file); + phpdbg_error("initfailure", "type=\"openfile\" file=\"%s\"", "Failed to open %s for initialization", init_file); } if (free_init) { @@ -315,8 +330,7 @@ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TS scan_dir[i] = 0; } - asprintf( - &init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME); + asprintf(&init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME); phpdbg_try_file_init(init_file, strlen(init_file), 1 TSRMLS_CC); if (i == -1) { break; @@ -342,36 +356,38 @@ PHPDBG_COMMAND(exec) /* {{{ */ if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { if (PHPDBG_G(exec)) { - phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec)); + phpdbg_notice("exec", "type=\"unset\" context=\"%s\"", "Unsetting old execution context: %s", PHPDBG_G(exec)); efree(PHPDBG_G(exec)); PHPDBG_G(exec) = NULL; PHPDBG_G(exec_len) = 0L; } if (PHPDBG_G(ops)) { - phpdbg_notice("Destroying compiled opcodes"); + phpdbg_notice("exec", "type=\"unsetops\"", "Destroying compiled opcodes"); phpdbg_clean(0 TSRMLS_CC); } PHPDBG_G(exec) = res; PHPDBG_G(exec_len) = res_len; - + + VCWD_CHDIR_FILE(res); + *SG(request_info).argv = PHPDBG_G(exec); php_hash_environment(TSRMLS_C); - phpdbg_notice("Set execution context: %s", PHPDBG_G(exec)); + phpdbg_notice("exec", "type=\"set\" context=\"%s\"", "Set execution context: %s", PHPDBG_G(exec)); if (phpdbg_compile(TSRMLS_C) == FAILURE) { - phpdbg_error("Failed to compile %s", PHPDBG_G(exec)); + phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s", PHPDBG_G(exec)); } } else { - phpdbg_notice("Execution context not changed"); + phpdbg_notice("exec", "type=\"unchanged\"", "Execution context not changed"); } } else { - phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str); + phpdbg_error("exec", "type=\"invalid\" context=\"%s\"", "Cannot use %s as execution context, not a valid file or symlink", param->str); } } else { - phpdbg_error("Cannot stat %s, ensure the file exists", param->str); + phpdbg_error("exec", "type=\"notfound\" context=\"%s\"", "Cannot stat %s, ensure the file exists", param->str); } return SUCCESS; } /* }}} */ @@ -381,27 +397,24 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ zend_file_handle fh; if (!PHPDBG_G(exec)) { - phpdbg_error("No execution context"); + phpdbg_error("inactive", "type=\"nocontext\"", "No execution context"); return SUCCESS; } if (EG(in_execution)) { - phpdbg_error("Cannot compile while in execution"); + phpdbg_error("inactive", "type=\"isrunning\"", "Cannot compile while in execution"); return FAILURE; } - phpdbg_notice("Attempting compilation of %s", PHPDBG_G(exec)); - - if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, - USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC) == SUCCESS) { + if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC) == SUCCESS) { PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE TSRMLS_CC); zend_destroy_file_handle(&fh TSRMLS_CC); - phpdbg_notice("Success"); + phpdbg_notice("compile", "context=\"%s\"", "Successful compilation of %s", PHPDBG_G(exec)); return SUCCESS; } else { - phpdbg_error("Could not open file %s", PHPDBG_G(exec)); + phpdbg_error("compile", "type=\"openfailure\" context=\"%s\"", "Could not open file %s", PHPDBG_G(exec)); } return FAILURE; @@ -424,23 +437,18 @@ PHPDBG_COMMAND(continue) /* {{{ */ PHPDBG_COMMAND(until) /* {{{ */ { if (!EG(in_execution)) { - phpdbg_error("Not executing"); + phpdbg_error("inactive", "type=\"noexec\"", "Not executing"); return SUCCESS; } PHPDBG_G(flags) |= PHPDBG_IN_UNTIL; { - zend_uint next = 0, - self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); + zend_uint next = 0, self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); zend_op *opline = &EG(active_op_array)->opcodes[self]; for (next = self; next < EG(active_op_array)->last; next++) { if (EG(active_op_array)->opcodes[next].lineno != opline->lineno) { - zend_hash_index_update( - &PHPDBG_G(seek), - (zend_ulong) &EG(active_op_array)->opcodes[next], - &EG(active_op_array)->opcodes[next], - sizeof(zend_op), NULL); + zend_hash_index_update(&PHPDBG_G(seek), (zend_ulong) &EG(active_op_array)->opcodes[next], &EG(active_op_array)->opcodes[next], sizeof(zend_op), NULL); break; } } @@ -452,14 +460,13 @@ PHPDBG_COMMAND(until) /* {{{ */ PHPDBG_COMMAND(finish) /* {{{ */ { if (!EG(in_execution)) { - phpdbg_error("Not executing"); + phpdbg_error("inactive", "type=\"noexec\"", "Not executing"); return SUCCESS; } PHPDBG_G(flags) |= PHPDBG_IN_FINISH; { - zend_uint next = 0, - self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); + zend_uint next = 0, self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); for (next = self; next < EG(active_op_array)->last; next++) { switch (EG(active_op_array)->opcodes[next].opcode) { @@ -469,11 +476,7 @@ PHPDBG_COMMAND(finish) /* {{{ */ #ifdef ZEND_YIELD case ZEND_YIELD: #endif - zend_hash_index_update( - &PHPDBG_G(seek), - (zend_ulong) &EG(active_op_array)->opcodes[next], - &EG(active_op_array)->opcodes[next], - sizeof(zend_op), NULL); + zend_hash_index_update(&PHPDBG_G(seek), (zend_ulong) &EG(active_op_array)->opcodes[next], &EG(active_op_array)->opcodes[next], sizeof(zend_op), NULL); break; } } @@ -485,14 +488,13 @@ PHPDBG_COMMAND(finish) /* {{{ */ PHPDBG_COMMAND(leave) /* {{{ */ { if (!EG(in_execution)) { - phpdbg_error("Not executing"); + phpdbg_error("inactive", "type=\"noexec\"", "Not executing"); return SUCCESS; } PHPDBG_G(flags) |= PHPDBG_IN_LEAVE; { - zend_uint next = 0, - self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); + zend_uint next = 0, self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); for (next = self; next < EG(active_op_array)->last; next++) { switch (EG(active_op_array)->opcodes[next].opcode) { @@ -502,11 +504,7 @@ PHPDBG_COMMAND(leave) /* {{{ */ #ifdef ZEND_YIELD case ZEND_YIELD: #endif - zend_hash_index_update( - &PHPDBG_G(seek), - (zend_ulong) &EG(active_op_array)->opcodes[next], - &EG(active_op_array)->opcodes[next], - sizeof(zend_op), NULL); + zend_hash_index_update(&PHPDBG_G(seek), (zend_ulong) &EG(active_op_array)->opcodes[next], &EG(active_op_array)->opcodes[next], sizeof(zend_op), NULL); break; } } @@ -518,8 +516,10 @@ PHPDBG_COMMAND(leave) /* {{{ */ PHPDBG_COMMAND(frame) /* {{{ */ { if (!param) { - phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num); - } else phpdbg_switch_frame(param->num TSRMLS_CC); + phpdbg_notice("frame", "id=\"%d\"", "Currently in frame #%d", PHPDBG_G(frame).num); + } else { + phpdbg_switch_frame(param->num TSRMLS_CC); + } return SUCCESS; } /* }}} */ @@ -528,9 +528,7 @@ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */ { zend_fcall_info fci; - zval fname, - *trace, - exception; + zval fname, *trace, exception; /* get filename and linenumber before unsetting exception */ const char *filename = zend_get_executed_filename(TSRMLS_C); @@ -541,10 +539,6 @@ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */ zval_copy_ctor(&exception); EG(exception) = NULL; - phpdbg_error( - "Uncaught %s!", - Z_OBJCE(exception)->name); - /* call __toString */ ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring")-1, 1); fci.size = sizeof(fci); @@ -559,16 +553,15 @@ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */ zend_call_function(&fci, NULL TSRMLS_CC); if (trace) { - phpdbg_writeln( - "Uncaught %s", Z_STRVAL_P(trace)); - /* remember to dtor trace */ + phpdbg_writeln("exception", "name=\"%s\" trace=\"%.*s\"", "Uncaught %s!\n%.*s", Z_OBJCE(exception)->name, Z_STRLEN_P(trace), Z_STRVAL_P(trace)); + zval_ptr_dtor(&trace); + } else { + phpdbg_error("exception", "name=\"%s\"", "Uncaught %s!", Z_OBJCE(exception)->name); } /* output useful information about address */ - phpdbg_writeln( - "Stacked entered at %p in %s on line %u", - EG(active_op_array)->opcodes, filename, lineno); + phpdbg_writeln("exception", "opline=\"%p\" file=\"%s\" line=\"%u\"", "Stack entered at %p in %s on line %u", EG(active_op_array)->opcodes, filename, lineno); zval_dtor(&fname); zval_dtor(&exception); @@ -577,7 +570,7 @@ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */ PHPDBG_COMMAND(run) /* {{{ */ { if (EG(in_execution)) { - phpdbg_error("Cannot start another execution while one is in progress"); + phpdbg_error("inactive", "type=\"isrunning\"", "Cannot start another execution while one is in progress"); return SUCCESS; } @@ -587,10 +580,10 @@ PHPDBG_COMMAND(run) /* {{{ */ zval **orig_retval_ptr = EG(return_value_ptr_ptr); zend_bool restore = 1; zend_execute_data *ex = EG(current_execute_data); - + if (!PHPDBG_G(ops)) { if (phpdbg_compile(TSRMLS_C) == FAILURE) { - phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec)); + phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s, cannot run", PHPDBG_G(exec)); goto out; } } @@ -619,7 +612,7 @@ PHPDBG_COMMAND(run) /* {{{ */ int argc = 0; int i; char *argv_str = strtok(param->str, " "); - + while (argv_str) { if (argc >= 4 && argc == (argc & -argc)) { argv = erealloc(argv, (argc * 2 + 1) * sizeof(char *)); @@ -635,27 +628,31 @@ PHPDBG_COMMAND(run) /* {{{ */ efree(SG(request_info).argv); SG(request_info).argv = erealloc(argv, ++argc * sizeof(char *)); SG(request_info).argc = argc; - + php_hash_environment(TSRMLS_C); } zend_try { - php_output_activate(TSRMLS_C); PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; zend_execute(EG(active_op_array) TSRMLS_CC); PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; - php_output_deactivate(TSRMLS_C); + phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); } zend_catch { EG(active_op_array) = orig_op_array; EG(opline_ptr) = orig_opline; EG(return_value_ptr_ptr) = orig_retval_ptr; if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - phpdbg_error("Caught exit/error from VM"); + phpdbg_error("stop", "type=\"bailout\"", "Caught exit/error from VM"); restore = 0; } } zend_end_try(); + if (PHPDBG_G(socket_fd) != -1) { + close(PHPDBG_G(socket_fd)); + PHPDBG_G(socket_fd) = -1; + } + if (restore) { if (EG(exception)) { phpdbg_handle_exception(TSRMLS_C); @@ -666,7 +663,7 @@ PHPDBG_COMMAND(run) /* {{{ */ EG(return_value_ptr_ptr) = orig_retval_ptr; } } else { - phpdbg_error("Nothing to execute!"); + phpdbg_error("inactive", "type=\"nocontext\"", "Nothing to execute!"); } out: @@ -674,31 +671,56 @@ out: return SUCCESS; } /* }}} */ +int phpdbg_output_ev_variable(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv TSRMLS_DC) { + phpdbg_notice("eval", "variable=\"%.*s\"", "Printing variable %.*s", (int) len, name); + phpdbg_xml(""); + zend_print_zval_r(*zv, 0 TSRMLS_CC); + phpdbg_xml(""); + phpdbg_out("\n"); + + efree(name); + efree(keyname); + + return SUCCESS; +} + PHPDBG_COMMAND(ev) /* {{{ */ { - zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING); + zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING) == PHPDBG_IS_STEPPING); zval retval; + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + phpdbg_try_access { + phpdbg_parse_variable(param->str, param->len, &EG(symbol_table), 0, phpdbg_output_ev_variable, 0 TSRMLS_CC); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Could not fetch data, invalid data source"); + } phpdbg_end_try_access(); + return SUCCESS; + } + if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { - PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING; + PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; } /* disable stepping while eval() in progress */ PHPDBG_G(flags) |= PHPDBG_IN_EVAL; zend_try { - if (zend_eval_stringl(param->str, param->len, - &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { - zend_print_zval_r( - &retval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); + if (zend_eval_stringl(param->str, param->len,&retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { + phpdbg_xml(""); + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + zval *zvp = &retval; + phpdbg_xml_var_dump(&zvp TSRMLS_CC); + } + zend_print_zval_r(&retval, 0 TSRMLS_CC); + phpdbg_xml(""); + phpdbg_out("\n"); zval_dtor(&retval); } } zend_end_try(); PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; /* switch stepping back on */ - if (stepping && - !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + if (stepping && !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } @@ -710,7 +732,7 @@ PHPDBG_COMMAND(ev) /* {{{ */ PHPDBG_COMMAND(back) /* {{{ */ { if (!EG(in_execution)) { - phpdbg_error("Not executing!"); + phpdbg_error("inactive", "type=\"noexec\"", "Not executing!"); return SUCCESS; } @@ -725,62 +747,54 @@ PHPDBG_COMMAND(back) /* {{{ */ PHPDBG_COMMAND(print) /* {{{ */ { - phpdbg_writeln(SEPARATE); - phpdbg_notice("Execution Context Information"); + phpdbg_out("Execution Context Information\n\n"); + phpdbg_xml(""); #ifdef HAVE_LIBREADLINE - phpdbg_writeln("Readline\tyes"); + phpdbg_writeln("print", "readline=\"yes\"", "Readline yes"); #else - phpdbg_writeln("Readline\tno"); + phpdbg_writeln("print", "readline=\"no\"", "Readline no"); #endif #ifdef HAVE_LIBEDIT - phpdbg_writeln("Libedit\t\tyes"); + phpdbg_writeln("print", "libedit=\"yes\"", "Libedit yes"); #else - phpdbg_writeln("Libedit\t\tno"); + phpdbg_writeln("print", "libedit=\"no\"", "Libedit no"); #endif - phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); - phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); - phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); - phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); - phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off"); + phpdbg_writeln("print", "context=\"%s\"", "Exec %s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); + phpdbg_writeln("print", "compiled=\"%s\"", "Compiled %s", PHPDBG_G(ops) ? "yes" : "no"); + phpdbg_writeln("print", "stepping=\"%s\"", "Stepping %s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); + phpdbg_writeln("print", "quiet=\"%s\"", "Quietness %s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); + phpdbg_writeln("print", "oplog=\"%s\"", "Oplog %s", PHPDBG_G(oplog) ? "on" : "off"); if (PHPDBG_G(ops)) { - phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last); - - if (PHPDBG_G(ops)->last_var) { - phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1); - } else { - phpdbg_writeln("Variables\tNone"); - } + phpdbg_writeln("print", "ops=\"%d\"", "Opcodes %d", PHPDBG_G(ops)->last); + phpdbg_writeln("print", "vars=\"%d\"", "Variables %d", PHPDBG_G(ops)->last_var ? PHPDBG_G(ops)->last_var - 1 : 0); } - phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no"); + phpdbg_writeln("print", "executing=\"%d\"", "Executing %s", EG(in_execution) ? "yes" : "no"); if (EG(in_execution)) { - phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret)); + phpdbg_writeln("print", "vmret=\"%d\"", "VM Return %d", PHPDBG_G(vmret)); } - phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files))); - - phpdbg_writeln(SEPARATE); + phpdbg_writeln("print", "classes=\"%d\"", "Classes %d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("print", "functions=\"%d\"", "Functions %d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("print", "constants=\"%d\"", "Constants %d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("print", "includes=\"%d\"", "Included %d", zend_hash_num_elements(&EG(included_files))); + phpdbg_xml(""); return SUCCESS; } /* }}} */ PHPDBG_COMMAND(info) /* {{{ */ { - phpdbg_error( - "No information command selected!"); + phpdbg_error("info", "type=\"toofewargs\" expected=\"1\"", "No information command selected!"); return SUCCESS; } /* }}} */ PHPDBG_COMMAND(set) /* {{{ */ { - phpdbg_error( - "No set command selected!"); + phpdbg_error("set", "type=\"toofewargs\" expected=\"1\"", "No set command selected!"); return SUCCESS; } /* }}} */ @@ -789,8 +803,8 @@ PHPDBG_COMMAND(break) /* {{{ */ { if (!param) { phpdbg_set_breakpoint_file( - zend_get_executed_filename(TSRMLS_C), - zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); } else switch (param->type) { case ADDR_PARAM: phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC); @@ -799,7 +813,7 @@ PHPDBG_COMMAND(break) /* {{{ */ if (PHPDBG_G(exec)) { phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC); } else { - phpdbg_error("Execution context not set!"); + phpdbg_error("inactive", "type=\"noexec\"", "Execution context not set!"); } break; case METHOD_PARAM: @@ -837,42 +851,226 @@ PHPDBG_COMMAND(sh) /* {{{ */ { FILE *fd = NULL; if ((fd=VCWD_POPEN((char*)param->str, "w"))) { - /* do something perhaps ?? do we want input ?? */ + /* TODO: do something perhaps ?? do we want input ?? */ fclose(fd); } else { - phpdbg_error( - "Failed to execute %s", param->str); + phpdbg_error("sh", "type=\"failure\" smd=\"%s\"", "Failed to execute %s", param->str); + } + + return SUCCESS; +} /* }}} */ + +static int add_module_info(zend_module_entry *module TSRMLS_DC) { + phpdbg_write("module", "name=\"%s\"", "%s\n", module->name); + return 0; +} + +static int add_zendext_info(zend_extension *ext TSRMLS_DC) { + phpdbg_write("extension", "name=\"%s\"", "%s\n", ext->name); + return 0; +} + +PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, char **name TSRMLS_DC) { + DL_HANDLE handle; + char *extension_dir; + + extension_dir = INI_STR("extension_dir"); + + if (strchr(*path, '/') != NULL || strchr(*path, DEFAULT_SLASH) != NULL) { + /* path is fine */ + } else if (extension_dir && extension_dir[0]) { + char *libpath; + int extension_dir_len = strlen(extension_dir); + if (IS_SLASH(extension_dir[extension_dir_len-1])) { + spprintf(&libpath, 0, "%s%s", extension_dir, *path); /* SAFE */ + } else { + spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, *path); /* SAFE */ + } + efree(*path); + *path = libpath; + } else { + phpdbg_error("dl", "type=\"relpath\"", "Not a full path given or extension_dir ini setting is not set"); + + return NULL; + } + + handle = DL_LOAD(*path); + + if (!handle) { +#if PHP_WIN32 + char *err = GET_DL_ERROR(); + if (err && *err != "") { + phpdbg_error("dl", "type=\"unknown\"", "%s", err); + LocalFree(err); + } else { + phpdbg_error("dl", "type=\"unknown\"", "Unknown reason"); + } +#else + phpdbg_error("dl", "type=\"unknown\"", "%s", GET_DL_ERROR()); +#endif + return NULL; + } + +#if ZEND_EXTENSIONS_SUPPORT + do { + zend_extension *new_extension; + zend_extension_version_info *extension_version_info; + + extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); + if (!extension_version_info) { + extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info"); + } + new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry"); + if (!new_extension) { + new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "_zend_extension_entry"); + } + if (!extension_version_info || !new_extension) { + break; + } + if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { + phpdbg_error("dl", "type=\"wrongapi\" extension=\"%s\" apineeded=\"%d\" apiinstalled=\"%d\"", "%s requires Zend Engine API version %d, which does not match the installed Zend Engine API version %d", new_extension->name, extension_version_info->zend_extension_api_no, ZEND_EXTENSION_API_NO); + + goto quit; + } else if (strcmp(ZEND_EXTENSION_BUILD_ID, extension_version_info->build_id) && (!new_extension->build_id_check || new_extension->build_id_check(ZEND_EXTENSION_BUILD_ID) != SUCCESS)) { + phpdbg_error("dl", "type=\"wrongbuild\" extension=\"%s\" buildneeded=\"%s\" buildinstalled=\"%s\"", "%s was built with configuration %s, whereas running engine is %s", new_extension->name, extension_version_info->build_id, ZEND_EXTENSION_BUILD_ID); + + goto quit; + } + + *name = new_extension->name; + + zend_register_extension(new_extension, handle); + + if (new_extension->startup) { + if (new_extension->startup(new_extension) != SUCCESS) { + phpdbg_error("dl", "type=\"startupfailure\" extension=\"%s\"", "Unable to startup Zend extension %s", new_extension->name); + + goto quit; + } + zend_append_version_info(new_extension); + } + + return "Zend extension"; + } while (0); +#endif + + do { + zend_module_entry *module_entry; + zend_module_entry *(*get_module)(void); + + get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module"); + if (!get_module) { + get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module"); + } + + if (!get_module) { + break; + } + + module_entry = get_module(); + *name = (char *) module_entry->name; + + if (strcmp(ZEND_EXTENSION_BUILD_ID, module_entry->build_id)) { + phpdbg_error("dl", "type=\"wrongbuild\" module=\"%s\" buildneeded=\"%s\" buildinstalled=\"%s\"", "%s was built with configuration %s, whereas running engine is %s", module_entry->name, module_entry->build_id, ZEND_EXTENSION_BUILD_ID); + + goto quit; + } + + module_entry->type = MODULE_PERSISTENT; + module_entry->module_number = zend_next_free_module(); + module_entry->handle = handle; + + if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) { + phpdbg_error("dl", "type=\"registerfailure\" module=\"%s\"", "Unable to register module %s", module_entry->name); + + goto quit; + } + + if (zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) { + phpdbg_error("dl", "type=\"startupfailure\" module=\"%s\"", "Unable to startup module %s", module_entry->name); + + goto quit; + } + + if (module_entry->request_startup_func) { + if (module_entry->request_startup_func(MODULE_PERSISTENT, module_entry->module_number TSRMLS_CC) == FAILURE) { + phpdbg_error("dl", "type=\"initfailure\" module=\"%s\"", "Unable to initialize module %s", module_entry->name); + + goto quit; + } + } + + return "module"; + } while (0); + + phpdbg_error("dl", "type=\"nophpso\"", "This shared object is nor a Zend extension nor a module"); + +quit: + DL_UNLOAD(handle); + return NULL; +} + +PHPDBG_COMMAND(dl) /* {{{ */ +{ + const char *type; + char *name, *path; + + if (!param || param->type == EMPTY_PARAM) { + phpdbg_notice("dl", "extensiontype=\"Zend extension\"", "Zend extensions"); + zend_llist_apply(&zend_extensions, (llist_apply_func_t) add_zendext_info TSRMLS_CC); + phpdbg_out("\n"); + phpdbg_notice("dl", "extensiontype=\"module\"", "Modules"); + zend_hash_apply(&module_registry, (apply_func_t) add_module_info TSRMLS_CC); + } else switch (param->type) { + case STR_PARAM: +#ifdef HAVE_LIBDL + path = estrndup(param->str, param->len); + + phpdbg_activate_err_buf(1 TSRMLS_CC); + if ((type = phpdbg_load_module_or_extension(&path, &name TSRMLS_CC)) == NULL) { + phpdbg_error("dl", "path=\"%s\" %b", "Could not load %s, not found or invalid zend extension / module: %b", path); + efree(name); + } else { + phpdbg_notice("dl", "extensiontype=\"%s\" name=\"%s\" path=\"%s\"", "Successfully loaded the %s %s at path %s", type, name, path); + } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); + efree(path); +#else + phpdbg_error("dl", "type=\"unsupported\" path=\"%.*s\"", "Cannot dynamically load %.*s - dynamic modules are not supported", (int) param->len, param->str); +#endif + break; + + phpdbg_default_switch_case(); } - + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(source) /* {{{ */ { struct stat sb; - + if (VCWD_STAT(param->str, &sb) != -1) { phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC); } else { - phpdbg_error( - "Failed to stat %s, file does not exist", param->str); + phpdbg_error("source", "type=\"notfound\" file=\"%s\"", "Failed to stat %s, file does not exist", param->str); } - + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(export) /* {{{ */ { FILE *handle = VCWD_FOPEN(param->str, "w+"); - + if (handle) { phpdbg_export_breakpoints(handle TSRMLS_CC); fclose(handle); } else { - phpdbg_error( - "Failed to open or create %s, check path and permissions", param->str); + phpdbg_error("export", "type=\"openfailure\" file=\"%s\"", "Failed to open or create %s, check path and permissions", param->str); } - + return SUCCESS; } /* }}} */ @@ -884,18 +1082,15 @@ PHPDBG_COMMAND(register) /* {{{ */ if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) { if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) { - zend_hash_update( - &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); + zend_hash_update(&PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); function_add_ref(function); - phpdbg_notice( - "Registered %s", lcname); + phpdbg_notice("register", "function=\"%s\"", "Registered %s", lcname); } else { - phpdbg_error("The requested function (%s) could not be found", param->str); + phpdbg_error("register", "type=\"notfoundc\" function=\"%s\"", "The requested function (%s) could not be found", param->str); } } else { - phpdbg_error( - "The requested name (%s) is already in use", lcname); + phpdbg_error("register", "type=\"inuse\" function=\"%s\"", "The requested name (%s) is already in use", lcname); } efree(lcname); @@ -916,37 +1111,43 @@ PHPDBG_COMMAND(quit) /* {{{ */ PHPDBG_COMMAND(clean) /* {{{ */ { if (EG(in_execution)) { - phpdbg_error("Cannot clean environment while executing"); + phpdbg_error("inactive", "type=\"isrunning\"", "Cannot clean environment while executing"); return SUCCESS; } - phpdbg_notice("Cleaning Execution Environment"); + phpdbg_out("Cleaning Execution Environment\n"); + phpdbg_xml(""); - phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files))); + phpdbg_writeln("clean", "classes=\"%d\"", "Classes %d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("clean", "functions=\"%d\"", "Functions %d", zend_hash_num_elements(EG(function_table))); + 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_clean(1 TSRMLS_CC); + phpdbg_xml(""); + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(clear) /* {{{ */ { - phpdbg_notice("Clearing Breakpoints"); - - phpdbg_writeln("File\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE])); - phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM])); - phpdbg_writeln("Methods\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD])); - phpdbg_writeln("Oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE])); - phpdbg_writeln("File oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE])); - phpdbg_writeln("Function oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE])); - phpdbg_writeln("Method oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE])); - phpdbg_writeln("Conditionals\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND])); + phpdbg_out("Clearing Breakpoints\n"); + phpdbg_xml(""); + + phpdbg_writeln("clear", "files=\"%d\"", "File %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE])); + phpdbg_writeln("clear", "functions=\"%d\"", "Functions %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM])); + phpdbg_writeln("clear", "methods=\"%d\"", "Methods %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD])); + phpdbg_writeln("clear", "oplines=\"%d\"", "Oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE])); + phpdbg_writeln("clear", "fileoplines=\"%d\"", "File oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE])); + phpdbg_writeln("clear", "functionoplines=\"%d\"", "Function oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE])); + phpdbg_writeln("clear", "methodoplines=\"%d\"", "Method oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE])); + phpdbg_writeln("clear", "eval=\"%d\"", "Conditionals %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND])); phpdbg_clear_breakpoints(TSRMLS_C); + phpdbg_xml(""); + return SUCCESS; } /* }}} */ @@ -981,7 +1182,7 @@ PHPDBG_COMMAND(watch) /* {{{ */ } else switch (param->type) { case STR_PARAM: if (phpdbg_create_var_watchpoint(param->str, param->len TSRMLS_CC) != FAILURE) { - phpdbg_notice("Set watchpoint on %.*s", (int)param->len, param->str); + phpdbg_notice("watch", "variable=\"%.*s\"", "Set watchpoint on %.*s", (int) param->len, param->str); } break; @@ -991,10 +1192,9 @@ PHPDBG_COMMAND(watch) /* {{{ */ return SUCCESS; } /* }}} */ -int phpdbg_interactive(TSRMLS_D) /* {{{ */ +int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */ { int ret = SUCCESS; - char *why = NULL; char *input = NULL; phpdbg_param_t stack; @@ -1007,42 +1207,49 @@ int phpdbg_interactive(TSRMLS_D) /* {{{ */ phpdbg_init_param(&stack, STACK_PARAM); if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { - switch (ret = phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + phpdbg_activate_err_buf(1 TSRMLS_CC); + +#ifdef PHP_WIN32 +#define PARA ((phpdbg_param_t *)stack.next)->type + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { + sigio_watcher_start(); + } +#endif + switch (ret = phpdbg_stack_execute(&stack, allow_async_unsafe TSRMLS_CC)) { case FAILURE: if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { - if (why) { - phpdbg_error("%s", why); - } + if (!allow_async_unsafe || phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + phpdbg_output_err_buf(NULL, "%b", "%b" TSRMLS_CC); } } - - if (why) { - free(why); - why = NULL; - } break; case PHPDBG_LEAVE: case PHPDBG_FINISH: case PHPDBG_UNTIL: case PHPDBG_NEXT: { + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); if (!EG(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - phpdbg_error("Not running"); + phpdbg_error("command", "type=\"noexec\"", "Not running"); } goto out; } } - } - if (why) { - free(why); - why = NULL; + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); +#ifdef PHP_WIN32 + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { + sigio_watcher_stop(); + } +#undef PARA +#endif } phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); - + PHPDBG_G(req_id) = 0; } while ((input = phpdbg_read_input(NULL TSRMLS_CC))); } @@ -1050,10 +1257,7 @@ out: if (input) { phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); - } - - if (why) { - free(why); + PHPDBG_G(req_id) = 0; } if (EG(in_execution)) { @@ -1105,9 +1309,9 @@ static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_ar ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) + ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC); - EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))); - memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var); - EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2))); + EX(CVs) = (zval ***)((char *)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))); + memset(EX(CVs), 0, sizeof(zval **) * op_array->last_var); + EX(Ts) = (temp_variable *)(((char *) EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2))); EX(fbc) = NULL; EX(called_scope) = NULL; EX(object) = NULL; @@ -1125,16 +1329,16 @@ static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_ar if (op_array->this_var != -1 && EG(This)) { Z_ADDREF_P(EG(This)); /* For $this pointer */ if (!EG(active_symbol_table)) { - EX_CV(op_array->this_var) = (zval**)EX_CVs() + (op_array->last_var + op_array->this_var); + EX_CV(op_array->this_var) = (zval**) EX_CVs() + (op_array->last_var + op_array->this_var); *EX_CV(op_array->this_var) = EG(This); } else { - if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX_CV(op_array->this_var))==FAILURE) { + if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void **) &EX_CV(op_array->this_var))==FAILURE) { Z_DELREF_P(EG(This)); } } } - EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; + EX(opline) = op_array->opcodes; EG(opline_ptr) = &EX(opline); EX(function_state).function = (zend_function *) op_array; @@ -1144,6 +1348,27 @@ static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_ar #endif } /* }}} */ +#define DO_INTERACTIVE(allow_async_unsafe) do { \ + if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \ + phpdbg_list_file( \ + zend_get_executed_filename(TSRMLS_C), \ + 3, \ + zend_get_executed_lineno(TSRMLS_C)-1, \ + zend_get_executed_lineno(TSRMLS_C) \ + TSRMLS_CC \ + ); \ + } \ + \ + switch (phpdbg_interactive(allow_async_unsafe TSRMLS_CC)) { \ + case PHPDBG_LEAVE: \ + case PHPDBG_FINISH: \ + case PHPDBG_UNTIL: \ + case PHPDBG_NEXT:{ \ + goto next; \ + } \ + } \ +} while (0) + #if PHP_VERSION_ID >= 50500 void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ { @@ -1180,41 +1405,17 @@ zend_vm_enter: #endif while (1) { - if ((PHPDBG_G(flags) & PHPDBG_BP_RESOLVE_MASK)) { /* resolve nth opline breakpoints */ phpdbg_resolve_op_array_breaks(EG(active_op_array) TSRMLS_CC); } - + #ifdef ZEND_WIN32 if (EG(timed_out)) { zend_timeout(0); } #endif -#define DO_INTERACTIVE() do { \ - if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \ - phpdbg_list_file( \ - zend_get_executed_filename(TSRMLS_C), \ - 3, \ - zend_get_executed_lineno(TSRMLS_C)-1, \ - zend_get_executed_lineno(TSRMLS_C) \ - TSRMLS_CC \ - ); \ - } \ - \ -/* do { */\ - switch (phpdbg_interactive(TSRMLS_C)) { \ - case PHPDBG_LEAVE: \ - case PHPDBG_FINISH: \ - case PHPDBG_UNTIL: \ - case PHPDBG_NEXT:{ \ - goto next; \ - } \ - } \ -/* } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); */\ -} while (0) - /* allow conditional breakpoints and initialization to access the vm uninterrupted */ if ((PHPDBG_G(flags) & PHPDBG_IN_COND_BP) || @@ -1232,8 +1433,7 @@ zend_vm_enter: if (PHPDBG_G(flags) & PHPDBG_IN_UNTIL) { if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { PHPDBG_G(flags) &= ~PHPDBG_IN_UNTIL; - zend_hash_clean( - &PHPDBG_G(seek)); + zend_hash_clean(&PHPDBG_G(seek)); } else { /* skip possible breakpoints */ goto next; @@ -1244,8 +1444,7 @@ zend_vm_enter: if (PHPDBG_G(flags) & PHPDBG_IN_FINISH) { if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { PHPDBG_G(flags) &= ~PHPDBG_IN_FINISH; - zend_hash_clean( - &PHPDBG_G(seek)); + zend_hash_clean(&PHPDBG_G(seek)); } /* skip possible breakpoints */ goto next; @@ -1255,14 +1454,12 @@ zend_vm_enter: if (PHPDBG_G(flags) & PHPDBG_IN_LEAVE) { if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { PHPDBG_G(flags) &= ~PHPDBG_IN_LEAVE; - zend_hash_clean( - &PHPDBG_G(seek)); - phpdbg_notice( - "Breaking for leave at %s:%u", + zend_hash_clean(&PHPDBG_G(seek)); + phpdbg_notice("breakpoint", "id=\"leave\" file=\"%s\" line=\"%u\"", "Breaking for leave at %s:%u", zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C) ); - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } else { /* skip possible breakpoints */ goto next; @@ -1271,18 +1468,17 @@ zend_vm_enter: } /* not while in conditionals */ - phpdbg_print_opline_ex( - execute_data, &vars, 0 TSRMLS_CC); + phpdbg_print_opline_ex(execute_data, &vars, 0 TSRMLS_CC); if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING && (PHPDBG_G(flags) & PHPDBG_STEP_OPCODE || execute_data->opline->lineno != PHPDBG_G(last_line))) { PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } /* check if some watchpoint was hit */ { if (phpdbg_print_changed_zvals(TSRMLS_C) == SUCCESS) { - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } } @@ -1294,21 +1490,36 @@ zend_vm_enter: && (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC)) && (brake->type != PHPDBG_BREAK_FILE || execute_data->opline->lineno != PHPDBG_G(last_line))) { phpdbg_hit_breakpoint(brake, 1 TSRMLS_CC); - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } } -next: if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { - phpdbg_writeln(EMPTY); - phpdbg_notice("Program received signal SIGINT"); PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED; - DO_INTERACTIVE(); + + phpdbg_out("\n"); + phpdbg_notice("signal", "type=\"SIGINT\"", "Program received signal SIGINT"); + DO_INTERACTIVE(1); } +next: + PHPDBG_G(last_line) = execute_data->opline->lineno; + /* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */ + if ((execute_data->opline->opcode == ZEND_DO_FCALL_BY_NAME || execute_data->opline->opcode == ZEND_DO_FCALL) && execute_data->function_state.function->type == ZEND_USER_FUNCTION) { +#if PHP_VERSION_ID < 50500 + zend_execute = execute; +#else + zend_execute_ex = execute_ex; +#endif + } PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC); +#if PHP_VERSION_ID < 50500 + zend_execute = phpdbg_execute_ex; +#else + zend_execute_ex = phpdbg_execute_ex; +#endif if (PHPDBG_G(vmret) > 0) { switch (PHPDBG_G(vmret)) { @@ -1333,3 +1544,47 @@ next: } zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen"); } /* }}} */ + +/* only if *not* interactive and while executing */ +void phpdbg_force_interruption(TSRMLS_D) { + zend_execute_data *data = EG(current_execute_data); /* should be always readable if not NULL */ + + PHPDBG_G(flags) |= PHPDBG_IN_SIGNAL_HANDLER; + + if (data) { + if (data->op_array) { + phpdbg_notice("hardinterrupt", "opline=\"%p\" num=\"%lu\" file=\"%s\" line=\"%u\"", "Current opline: %p (op #%lu) in %s:%u", data->opline, (data->opline - data->op_array->opcodes) / sizeof(data->opline), data->op_array->filename, data->opline->lineno); + } else { + phpdbg_notice("hardinterrupt", "opline=\"%p\"", "Current opline: %p (op_array information unavailable)", data->opline); + } + } else { + phpdbg_notice("hardinterrupt", "", "No information available about executing context"); + } + + DO_INTERACTIVE(0); + +next: + PHPDBG_G(flags) &= ~PHPDBG_IN_SIGNAL_HANDLER; + + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + zend_bailout(); + } +} + +PHPDBG_COMMAND(eol) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_notice("eol", "argument required", "argument required"); + } else switch (param->type) { + case STR_PARAM: + if (FAILURE == phpdbg_eol_global_update(param->str TSRMLS_CC)) { + phpdbg_notice("eol", "unknown EOL name '%s', give crlf, lf, cr", "unknown EOL name '%s', give crlf, lf, cr", param->str); + } + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + diff --git a/phpdbg_prompt.h b/phpdbg_prompt.h index ef648aabeb..94e24df833 100644 --- a/phpdbg_prompt.h +++ b/phpdbg_prompt.h @@ -24,9 +24,11 @@ /* {{{ */ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC); void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC); -int phpdbg_interactive(TSRMLS_D); +int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC); int phpdbg_compile(TSRMLS_D); -void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */ +void phpdbg_clean(zend_bool full TSRMLS_DC); +void phpdbg_force_interruption(TSRMLS_D); +/* }}} */ /* {{{ phpdbg command handlers */ PHPDBG_COMMAND(exec); @@ -47,12 +49,15 @@ PHPDBG_COMMAND(clean); PHPDBG_COMMAND(clear); PHPDBG_COMMAND(help); PHPDBG_COMMAND(sh); +PHPDBG_COMMAND(dl); PHPDBG_COMMAND(set); PHPDBG_COMMAND(source); PHPDBG_COMMAND(export); PHPDBG_COMMAND(register); PHPDBG_COMMAND(quit); -PHPDBG_COMMAND(watch); /* }}} */ +PHPDBG_COMMAND(watch); +PHPDBG_COMMAND(eol); +PHPDBG_COMMAND(wait); /* }}} */ /* {{{ prompt commands */ extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */ diff --git a/phpdbg_rinit_hook.c b/phpdbg_rinit_hook.c new file mode 100644 index 0000000000..049a782d9d --- /dev/null +++ b/phpdbg_rinit_hook.c @@ -0,0 +1,101 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_rinit_hook.h" +#include "php_ini.h" +#include + +ZEND_DECLARE_MODULE_GLOBALS(phpdbg_webhelper); + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("phpdbg.auth", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, auth, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals) + STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, path, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals) +PHP_INI_END() + +static inline void php_phpdbg_webhelper_globals_ctor(zend_phpdbg_webhelper_globals *pg) /* {{{ */ +{ +} /* }}} */ + +static PHP_MINIT_FUNCTION(phpdbg_webhelper) /* {{{ */ +{ + if (!strcmp(sapi_module.name, PHPDBG_NAME)) { + return SUCCESS; + } + + ZEND_INIT_MODULE_GLOBALS(phpdbg_webhelper, php_phpdbg_webhelper_globals_ctor, NULL); + REGISTER_INI_ENTRIES(); + + return SUCCESS; +} /* }}} */ + +static PHP_RINIT_FUNCTION(phpdbg_webhelper) /* {{{ */ +{ + zval *cookies = PG(http_globals)[TRACK_VARS_COOKIE]; + zval **auth; + + if (!cookies || zend_hash_find(Z_ARRVAL_P(cookies), PHPDBG_NAME "_AUTH_COOKIE", sizeof(PHPDBG_NAME "_AUTH_COOKIE"), (void **) &auth) == FAILURE || Z_STRLEN_PP(auth) != strlen(PHPDBG_WG(auth)) || strcmp(Z_STRVAL_PP(auth), PHPDBG_WG(auth))) { + return SUCCESS; + } + +#ifndef _WIN32 + { + struct sockaddr_un sock; + int s = socket(AF_UNIX, SOCK_STREAM, 0); + int len = strlen(PHPDBG_WG(path)) + sizeof(sock.sun_family); + char buf[(1 << 8) + 1]; + int buflen; + sock.sun_family = AF_UNIX; + strcpy(sock.sun_path, PHPDBG_WG(path)); + + if (connect(s, (struct sockaddr *)&sock, len) == -1) { + zend_error(E_ERROR, "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting. Reason: %s", PHPDBG_WG(path), strerror(errno)); + } + + char *msg = NULL; + char msglen[5] = {0}; + phpdbg_webdata_compress(&msg, (int *)msglen TSRMLS_CC); + + send(s, msglen, 4, 0); + send(s, msg, *(int *) msglen, 0); + + while ((buflen = recv(s, buf, sizeof(buf) - 1, 0)) > 0) { + php_write(buf, buflen TSRMLS_CC); + } + + close(s); + + php_output_flush_all(TSRMLS_C); + zend_bailout(); + } +#endif + + return SUCCESS; +} /* }}} */ + +zend_module_entry phpdbg_webhelper_module_entry = { + STANDARD_MODULE_HEADER, + "phpdbg_webhelper", + NULL, + PHP_MINIT(phpdbg_webhelper), + NULL, + PHP_RINIT(phpdbg_webhelper), + NULL, + NULL, + PHPDBG_VERSION, + STANDARD_MODULE_PROPERTIES +}; diff --git a/phpdbg_rinit_hook.h b/phpdbg_rinit_hook.h new file mode 100644 index 0000000000..d28be10f8c --- /dev/null +++ b/phpdbg_rinit_hook.h @@ -0,0 +1,41 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena | + | Authors: Joe Watkins | + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WEBHELPER_H +#define PHPDBG_WEBHELPER_H + +#include "phpdbg_webdata_transfer.h" + +extern zend_module_entry phpdbg_webhelper_module_entry; +#define phpext_phpdbg_webhelper_ptr &phpdbg_webhelper_module_entry + +#ifdef ZTS +# define PHPDBG_WG(v) TSRMG(phpdbg_webhelper_globals_id, zend_phpdbg_webhelper_globals *, v) +#else +# define PHPDBG_WG(v) (phpdbg_webhelper_globals.v) +#endif + +/* {{{ structs */ +ZEND_BEGIN_MODULE_GLOBALS(phpdbg_webhelper) + char *auth; + char *path; +ZEND_END_MODULE_GLOBALS(phpdbg_webhelper) /* }}} */ + +#endif /* PHPDBG_WEBHELPER_H */ diff --git a/phpdbg_set.c b/phpdbg_set.c index 54269a8193..fc7e788fa0 100644 --- a/phpdbg_set.c +++ b/phpdbg_set.c @@ -27,30 +27,32 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[18]) +#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[18], flags) const phpdbg_command_t phpdbg_set_commands[] = { - PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt []", 'p', set_prompt, NULL, "|s"), + PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt []", 'p', set_prompt, NULL, "|s", 0), #ifndef _WIN32 - PHPDBG_SET_COMMAND_D(color, "usage: set color ", 'c', set_color, NULL, "ss"), - PHPDBG_SET_COMMAND_D(colors, "usage: set colors []", 'C', set_colors, NULL, "|b"), + PHPDBG_SET_COMMAND_D(color, "usage: set color ", 'c', set_color, NULL, "ss", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(colors, "usage: set colors []", 'C', set_colors, NULL, "|b", PHPDBG_ASYNC_SAFE), #endif - PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog []", 'O', set_oplog, NULL, "|s"), - PHPDBG_SET_COMMAND_D(break, "usage: set break id []", 'b', set_break, NULL, "l|b"), - PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks []", 'B', set_breaks, NULL, "|b"), - PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet []", 'q', set_quiet, NULL, "|b"), - PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping []", 's', set_stepping, NULL, "|s"), - PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount []", 'r', set_refcount, NULL, "|b"), + PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog []", 'O', set_oplog, NULL, "|s", 0), + PHPDBG_SET_COMMAND_D(break, "usage: set break id []", 'b', set_break, NULL, "l|b", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks []", 'B', set_breaks, NULL, "|b", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet []", 'q', set_quiet, NULL, "|b", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping []", 's', set_stepping, NULL, "|s", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount []", 'r', set_refcount, NULL, "|b", PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; PHPDBG_SET(prompt) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C)); - } else phpdbg_set_prompt(param->str TSRMLS_CC); - + phpdbg_writeln("setprompt", "str=\"%s\"", "Current prompt: %s", phpdbg_get_prompt(TSRMLS_C)); + } else { + phpdbg_set_prompt(param->str TSRMLS_CC); + } + return SUCCESS; } /* }}} */ @@ -61,21 +63,21 @@ PHPDBG_SET(break) /* {{{ */ if (param->next) { if (param->next->num) { phpdbg_enable_breakpoint(param->num TSRMLS_CC); - } else phpdbg_disable_breakpoint(param->num TSRMLS_CC); + } else { + phpdbg_disable_breakpoint(param->num TSRMLS_CC); + } } else { phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC); if (brake) { - phpdbg_writeln( - "%s", brake->disabled ? "off" : "on"); + phpdbg_writeln("setbreak", "id=\"%ld\" active=\"%s\"", "Breakpoint #%ld %s", param->num, brake->disabled ? "off" : "on"); } else { - phpdbg_error("Failed to find breakpoint #%ld", param->num); + phpdbg_error("setbreak", "type=\"nobreak\" id=\"%ld\"", "Failed to find breakpoint #%ld", param->num); } } } break; default: - phpdbg_error( - "set break used incorrectly: set break [id] "); + phpdbg_error("setbreak", "type=\"wrongargs\"", "set break used incorrectly: set break [id] "); } return SUCCESS; @@ -84,18 +86,18 @@ PHPDBG_SET(break) /* {{{ */ PHPDBG_SET(breaks) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("%s", - PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); - } else switch (param->type) { + phpdbg_writeln("setbreaks", "active=\"%s\"", "Breakpoints %s",PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); + } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { phpdbg_enable_breakpoints(TSRMLS_C); - } else phpdbg_disable_breakpoints(TSRMLS_C); + } else { + phpdbg_disable_breakpoints(TSRMLS_C); + } } break; default: - phpdbg_error( - "set break used incorrectly: set break [id] "); + phpdbg_error("setbreaks", "type=\"wrongargs\"", "set breaks used incorrectly: set breaks "); } return SUCCESS; @@ -104,41 +106,35 @@ PHPDBG_SET(breaks) /* {{{ */ #ifndef _WIN32 PHPDBG_SET(color) /* {{{ */ { - const phpdbg_color_t *color = phpdbg_get_color( - param->next->str, param->next->len TSRMLS_CC); - + const phpdbg_color_t *color = phpdbg_get_color(param->next->str, param->next->len TSRMLS_CC); + if (!color) { - phpdbg_error( - "Failed to find the requested color (%s)", param->next->str); + phpdbg_error("setcolor", "type=\"nocolor\"", "Failed to find the requested color (%s)", param->next->str); return SUCCESS; } - + switch (phpdbg_get_element(param->str, param->len TSRMLS_CC)) { case PHPDBG_COLOR_PROMPT: - phpdbg_notice( - "setting prompt color to %s (%s)", color->name, color->code); + phpdbg_notice("setcolor", "type=\"prompt\" color=\"%s\" code=\"%s\"", "setting prompt color to %s (%s)", color->name, color->code); if (PHPDBG_G(prompt)[1]) { free(PHPDBG_G(prompt)[1]); PHPDBG_G(prompt)[1]=NULL; } phpdbg_set_color(PHPDBG_COLOR_PROMPT, color TSRMLS_CC); break; - + case PHPDBG_COLOR_ERROR: - phpdbg_notice( - "setting error color to %s (%s)", color->name, color->code); + phpdbg_notice("setcolor", "type=\"error\" color=\"%s\" code=\"%s\"", "setting error color to %s (%s)", color->name, color->code); phpdbg_set_color(PHPDBG_COLOR_ERROR, color TSRMLS_CC); break; - + case PHPDBG_COLOR_NOTICE: - phpdbg_notice( - "setting notice color to %s (%s)", color->name, color->code); + phpdbg_notice("setcolor", "type=\"notice\" color=\"%s\" code=\"%s\"", "setting notice color to %s (%s)", color->name, color->code); phpdbg_set_color(PHPDBG_COLOR_NOTICE, color TSRMLS_CC); break; - + default: - phpdbg_error( - "Failed to find the requested element (%s)", param->str); + phpdbg_error("setcolor", "type=\"invalidtype\"", "Failed to find the requested element (%s)", param->str); } return SUCCESS; @@ -147,7 +143,7 @@ PHPDBG_SET(color) /* {{{ */ PHPDBG_SET(colors) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); + phpdbg_writeln("setcolors", "active=\"%s\"", "Colors %s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { @@ -156,10 +152,9 @@ PHPDBG_SET(colors) /* {{{ */ PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED; } } break; - + default: - phpdbg_error( - "set colors used incorrectly: set colors "); + phpdbg_error("setcolors", "type=\"wrongargs\"", "set colors used incorrectly: set colors "); } return SUCCESS; @@ -169,7 +164,7 @@ PHPDBG_SET(colors) /* {{{ */ PHPDBG_SET(oplog) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_notice("Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled"); + phpdbg_notice("setoplog", "active=\"%s\"", "Oplog %s", PHPDBG_G(oplog) ? "on" : "off"); } else switch (param->type) { case STR_PARAM: { /* open oplog */ @@ -177,14 +172,15 @@ PHPDBG_SET(oplog) /* {{{ */ PHPDBG_G(oplog) = fopen(param->str, "w+"); if (!PHPDBG_G(oplog)) { - phpdbg_error("Failed to open %s for oplog", param->str); + phpdbg_error("setoplog", "type=\"openfailure\" file=\"%s\"", "Failed to open %s for oplog", param->str); PHPDBG_G(oplog) = old; } else { if (old) { - phpdbg_notice("Closing previously open oplog"); + phpdbg_notice("setoplog", "type=\"closingold\"", "Closing previously open oplog"); fclose(old); } - phpdbg_notice("Successfully opened oplog %s", param->str); + + phpdbg_notice("setoplog", "file=\"%s\"", "Successfully opened oplog %s", param->str); } } break; @@ -197,8 +193,7 @@ PHPDBG_SET(oplog) /* {{{ */ PHPDBG_SET(quiet) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("Quietness %s", - PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); + phpdbg_writeln("setquiet", "active=\"%s\"", "Quietness %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { @@ -217,18 +212,15 @@ PHPDBG_SET(quiet) /* {{{ */ PHPDBG_SET(stepping) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("Stepping %s", - PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line"); + phpdbg_writeln("setstepping", "type=\"%s\"", "Stepping %s", PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line"); } else switch (param->type) { - case STR_PARAM: { - if ((param->len == sizeof("opcode")-1) && - (memcmp(param->str, "opcode", sizeof("opcode")) == SUCCESS)) { + case STR_PARAM: { + if ((param->len == sizeof("opcode") - 1) && memcmp(param->str, "opcode", sizeof("opcode")) == SUCCESS) { PHPDBG_G(flags) |= PHPDBG_STEP_OPCODE; - } else if ((param->len == sizeof("line")-1) && - (memcmp(param->str, "line", sizeof("line")) == SUCCESS)) { + } else if ((param->len == sizeof("line")-1) && memcmp(param->str, "line", sizeof("line")) == SUCCESS) { PHPDBG_G(flags) &= ~PHPDBG_STEP_OPCODE; } else { - phpdbg_error("usage set stepping []"); + phpdbg_error("setstepping", "type=\"wrongargs\"", "usage set stepping []"); } } break; @@ -241,7 +233,7 @@ PHPDBG_SET(stepping) /* {{{ */ PHPDBG_SET(refcount) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("Refcount %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); + phpdbg_writeln("setrefcount", "active=\"%s\"", "Showing refcounts %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { diff --git a/phpdbg_sigio_win32.c b/phpdbg_sigio_win32.c new file mode 100644 index 0000000000..24e9ac0e0a --- /dev/null +++ b/phpdbg_sigio_win32.c @@ -0,0 +1,120 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 7-4 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: Anatol Belski | + +----------------------------------------------------------------------+ +*/ + + +#include + +#include "phpdbg.h" +#include "phpdbg_sigio_win32.h" + + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + + +VOID +SigIoWatcherThread(VOID *p) +{ + zend_uchar sig; + struct win32_sigio_watcher_data *swd = (struct win32_sigio_watcher_data *)p; +#ifdef ZTS + void ***tsrm_ls = swd->tsrm_ls; +top: + (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1, tsrm_ls); +#else +top: + (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1); +#endif + + + if (3 == sig) { + printf("signaled, got %d", sig); + /* XXX completely not sure it is done right here */ + if (swd->flags & PHPDBG_IS_INTERACTIVE) { + if (raise(sig)) { + /* just out*/ + exit(0); + } + } + if (swd->flags & PHPDBG_IS_SIGNALED) { + phpdbg_set_sigsafe_mem(&sig TSRMLS_CC); + zend_try { + phpdbg_force_interruption(TSRMLS_C); + } zend_end_try(); + phpdbg_clear_sigsafe_mem(TSRMLS_C); + } + /* XXX set signaled flag to the caller thread, question is - whether it's needed */ + ExitThread(sig); + } else { + goto top; + } +} + + +/* Start this only for the time of the run or eval command, +for so long that the main thread is busy serving some debug +session. */ +void +sigio_watcher_start(void) +{ + TSRMLS_FETCH(); + + PHPDBG_G(swd).fd = PHPDBG_G(io)[PHPDBG_STDIN].fd; + PHPDBG_G(swd).running = 1; + PHPDBG_G(swd).flags = PHPDBG_G(flags); +#ifdef ZTS + PHPDBG_G(swd).tsrm_ls = tsrm_ls; +#endif + + PHPDBG_G(sigio_watcher_thread) = CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)SigIoWatcherThread, + &PHPDBG_G(swd), + 0, + NULL); +} + +void +sigio_watcher_stop(void) +{ + DWORD waited; + TSRMLS_FETCH(); + + if (INVALID_HANDLE_VALUE == PHPDBG_G(sigio_watcher_thread)) { + /* it probably did bail out already */ + return; + } + + waited = WaitForSingleObject(PHPDBG_G(sigio_watcher_thread), 300); + + if (WAIT_OBJECT_0 != waited) { + if (!CancelSynchronousIo(PHPDBG_G(sigio_watcher_thread))) { + /* error out */ + } + + if (!TerminateThread(PHPDBG_G(sigio_watcher_thread), 0)) { + /* error out */ + } + } + + PHPDBG_G(swd).fd = -1; + PHPDBG_G(swd).running = 0; + PHPDBG_G(swd).flags = 0; + PHPDBG_G(sigio_watcher_thread) = INVALID_HANDLE_VALUE; +} + diff --git a/phpdbg_sigio_win32.h b/phpdbg_sigio_win32.h new file mode 100644 index 0000000000..796b477f93 --- /dev/null +++ b/phpdbg_sigio_win32.h @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 7-4 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: Anatol Belski | + +----------------------------------------------------------------------+ +*/ + + +#ifndef PHPDBG_SIGIO_WIN32_H +#define PHPDBG_SIGIO_WIN32_H + +#include "phpdbg.h" +#include "phpdbg_prompt.h" +#include "phpdbg_io.h" + +struct win32_sigio_watcher_data { + zend_ulong flags; +#ifdef ZTS + void ***tsrm_ls; +#endif + int fd; + zend_uchar running; +}; + +void +sigio_watcher_start(void); + +void +sigio_watcher_stop(void); + +#endif /* PHPDBG_SIGIO_WIN32_H */ diff --git a/phpdbg_sigsafe.c b/phpdbg_sigsafe.c new file mode 100644 index 0000000000..7238ad102f --- /dev/null +++ b/phpdbg_sigsafe.c @@ -0,0 +1,111 @@ +#include "phpdbg_sigsafe.h" +#include "phpdbg.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +static inline void zend_mm_init(zend_mm_heap *heap) { + zend_mm_free_block *p; + int i; + + heap->free_bitmap = 0; + heap->large_free_bitmap = 0; +#if ZEND_MM_CACHE + heap->cached = 0; + memset(heap->cache, 0, sizeof(heap->cache)); +#endif +#if ZEND_MM_CACHE_STAT + for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { + heap->cache_stat[i].count = 0; + } +#endif + p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0); + for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { + p->next_free_block = p; + p->prev_free_block = p; + p = (zend_mm_free_block *)((char *)p + sizeof(zend_mm_free_block *) * 2); + heap->large_free_buckets[i] = NULL; + } + heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap); + heap->rest_count = 0; +} + +static zend_mm_storage* zend_mm_mem_init(void *params) { + TSRMLS_FETCH(); + + return &PHPDBG_G(sigsafe_mem).storage; +} + +static void zend_mm_mem_dummy(zend_mm_storage *storage) { +} + +#define STR(x) #x +#define EXP_STR(x) STR(x) + +static zend_mm_segment* zend_mm_mem_alloc(zend_mm_storage *storage, size_t size) { + TSRMLS_FETCH(); + + if (EXPECTED(size == PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) { + PHPDBG_G(sigsafe_mem).allocated = 1; + return (zend_mm_segment *) PHPDBG_G(sigsafe_mem).mem; + } + + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Tried to allocate more than " EXP_STR(PHPDBG_SIGSAFE_MEM_SIZE) " bytes from stack memory in signal handler ... bailing out of signal handler\n")); + + if (*EG(bailout)) { + LONGJMP(*EG(bailout), FAILURE); + } + + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n")); + + return NULL; +} + +static zend_mm_segment* zend_mm_mem_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size) { + return zend_mm_mem_alloc(storage, size); +} + +static void zend_mm_mem_free(zend_mm_storage *storage, zend_mm_segment *ptr) { +} + +static const zend_mm_mem_handlers phpdbg_handlers_sigsafe_mem = { "stack", zend_mm_mem_init, zend_mm_mem_dummy, zend_mm_mem_dummy, zend_mm_mem_alloc, zend_mm_mem_realloc, zend_mm_mem_free }; + +void phpdbg_set_sigsafe_mem(char *buffer TSRMLS_DC) { + phpdbg_signal_safe_mem *mem = &PHPDBG_G(sigsafe_mem); + mem->old_heap = zend_mm_set_heap(&mem->heap TSRMLS_CC); + mem->mem = buffer; + mem->allocated = 0; + + mem->storage.handlers = &phpdbg_handlers_sigsafe_mem; + mem->heap.storage = &mem->storage; + mem->heap.block_size = PHPDBG_SIGSAFE_MEM_SIZE; + mem->heap.compact_size = 0; + mem->heap.segments_list = NULL; + zend_mm_init(&mem->heap); +#if ZEND_MM_CACHE_STAT + memset(mem->heap.cache_stat, 0, sizeof(mem->heap.cache_stat)); +#endif + mem->heap.use_zend_alloc = 1; + mem->heap.real_size = 0; + mem->heap.overflow = 0; + mem->heap.real_peak = 0; + mem->heap.limit = PHPDBG_SIGSAFE_MEM_SIZE; + mem->heap.size = 0; + mem->heap.peak = 0; + mem->heap.internal = 0; + mem->heap.reserve = NULL; + mem->heap.reserve_size = 0; +} + +zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D) { + return PHPDBG_G(sigsafe_mem).old_heap; +} + +void phpdbg_clear_sigsafe_mem(TSRMLS_D) { + zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC); + PHPDBG_G(sigsafe_mem).mem = NULL; +} + +zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D) { + return !!PHPDBG_G(sigsafe_mem).mem; +} + diff --git a/phpdbg_sigsafe.h b/phpdbg_sigsafe.h new file mode 100644 index 0000000000..6ed74f53db --- /dev/null +++ b/phpdbg_sigsafe.h @@ -0,0 +1,25 @@ +#ifndef PHPDBG_SIGSAFE_H +#define PHPDBG_SIGSAFE_H + +#include "zend_mm_structs.h" + +#define PHPDBG_SIGSAFE_MEM_SIZE (1 << 20) + +typedef struct { + char *mem; + zend_bool allocated; + zend_mm_heap heap; + zend_mm_heap *old_heap; + zend_mm_storage storage; +} phpdbg_signal_safe_mem; + +#include "phpdbg.h" + +zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D); + +void phpdbg_set_sigsafe_mem(char *mem TSRMLS_DC); +void phpdbg_clear_sigsafe_mem(TSRMLS_D); + +zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D); + +#endif diff --git a/phpdbg_utils.c b/phpdbg_utils.c index 3ce2fade17..85b6eeb3b5 100644 --- a/phpdbg_utils.c +++ b/phpdbg_utils.c @@ -18,19 +18,14 @@ +----------------------------------------------------------------------+ */ -#include -#include -#include #include "zend.h" + #include "php.h" -#include "spprintf.h" #include "phpdbg.h" #include "phpdbg_opcode.h" #include "phpdbg_utils.h" -#ifdef _WIN32 -# include "win32/time.h" -#elif defined(HAVE_SYS_IOCTL_H) +#if defined(HAVE_SYS_IOCTL_H) # include "sys/ioctl.h" # ifndef GWINSZ_IN_SYS_IOCTL # include @@ -128,12 +123,12 @@ PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class, } if (class != NULL) { - + if (str[0] == '\\') { str++; len--; } - + *class = estrndup(str, sep - str); (*class)[sep - str] = 0; } @@ -224,103 +219,6 @@ PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{ } /* }}} */ -PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */ -{ - int rc = 0; - char *buffer = NULL; - va_list args; - - if (format != NULL && strlen(format) > 0L) { - va_start(args, format); - vspprintf(&buffer, 0, format, args); - va_end(args); - } - - /* TODO(anyone) colours */ - - switch (type) { - case P_ERROR: - if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { - rc = fprintf(fp, - "\033[%sm[%s]\033[0m\n", - PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer); - } else { - rc = fprintf(fp, "[%s]\n", buffer); - } - break; - - case P_NOTICE: - if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { - rc = fprintf(fp, - "\033[%sm[%s]\033[0m\n", - PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer); - } else { - rc = fprintf(fp, "[%s]\n", buffer); - } - break; - - case P_WRITELN: { - if (buffer) { - rc = fprintf(fp, "%s\n", buffer); - } else { - rc = fprintf(fp, "\n"); - } - } break; - - case P_WRITE: - if (buffer) { - rc = fprintf(fp, "%s", buffer); - } - break; - - /* no formatting on logging output */ - case P_LOG: - if (buffer) { - struct timeval tp; - if (gettimeofday(&tp, NULL) == SUCCESS) { - rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer); - } else { - rc = FAILURE; - } - } - break; - } - - if (buffer) { - efree(buffer); - } - - return rc; -} /* }}} */ - -PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */ - int rc = 0; - - va_list args; - struct timeval tp; - - va_start(args, fmt); - if (gettimeofday(&tp, NULL) == SUCCESS) { - char friendly[100]; - char *format = NULL, *buffer = NULL; - const time_t tt = tp.tv_sec; - - strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt)); - asprintf( - &buffer, friendly, tp.tv_usec/1000); - asprintf( - &format, "[%s]: %s\n", buffer, fmt); - rc = vfprintf( - fp, format, args); - - free(format); - free(buffer); - } - va_end(args); - - return rc; -} /* }}} */ - PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */ { const phpdbg_color_t *color = colors; @@ -328,15 +226,13 @@ PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_ while (color && color->name) { if (name_length == color->name_length && memcmp(name, color->name, name_length) == SUCCESS) { - phpdbg_debug( - "phpdbg_get_color(%s, %lu): %s", name, name_length, color->code); + phpdbg_debug("phpdbg_get_color(%s, %lu): %s", name, name_length, color->code); return color; } ++color; } - phpdbg_debug( - "phpdbg_get_color(%s, %lu): failed", name, name_length); + phpdbg_debug("phpdbg_get_color(%s, %lu): failed", name, name_length); return NULL; } /* }}} */ @@ -362,7 +258,7 @@ PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D) /* {{{ */ PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC) { const phpdbg_element_t *element = elements; - + while (element && element->name) { if (len == element->name_length) { if (strncasecmp(name, element->name, len) == SUCCESS) { @@ -371,7 +267,7 @@ PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC) { } element++; } - + return PHPDBG_COLOR_INVALID; } @@ -420,7 +316,7 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */ int phpdbg_rebuild_symtable(TSRMLS_D) { if (!EG(active_op_array)) { - phpdbg_error("No active op array!"); + phpdbg_error("inactive", "type=\"op_array\"", "No active op array!"); return FAILURE; } @@ -428,7 +324,7 @@ int phpdbg_rebuild_symtable(TSRMLS_D) { zend_rebuild_symbol_table(TSRMLS_C); if (!EG(active_symbol_table)) { - phpdbg_error("No active symbol table!"); + phpdbg_error("inactive", "type=\"symbol_table\"", "No active symbol table!"); return FAILURE; } } @@ -438,13 +334,13 @@ int phpdbg_rebuild_symtable(TSRMLS_D) { PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */ { - int columns; + int columns; #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; -#elif defined(HAVE_SYS_IOCTL_H) && defined (TIOCGWINSZ) +#elif defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) struct winsize w; columns = ioctl(fileno(stdout), TIOCGWINSZ, &w) == 0 ? w.ws_col : 80; @@ -453,3 +349,294 @@ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */ #endif return columns; } /* }}} */ + +PHPDBG_API void phpdbg_set_async_io(int fd) { +#ifndef _WIN32 + int flags; + fcntl(STDIN_FILENO, F_SETOWN, getpid()); + flags = fcntl(STDIN_FILENO, F_GETFL); + fcntl(STDIN_FILENO, F_SETFL, flags | FASYNC); +#endif +} + +int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) { + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + char *lc_name, *lc_free; + int lc_length, ret = FAILURE; + + if (name == NULL || !name_length) { + return FAILURE; + } + + lc_free = lc_name = emalloc(name_length + 1); + zend_str_tolower_copy(lc_name, name, name_length); + lc_length = name_length + 1; + + if (lc_name[0] == '\\') { + lc_name += 1; + lc_length -= 1; + } + + phpdbg_try_access { + ret = zend_hash_find(EG(class_table), lc_name, lc_length, (void **) &ce); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "class=\"%.*s\"", "Could not fetch class %.*s, invalid data source", name_length, name); + } phpdbg_end_try_access(); + + efree(lc_free); + return ret; + } else { + return zend_lookup_class(name, name_length, ce TSRMLS_CC); + } +} + +char *phpdbg_get_property_key(char *key) { + if (*key != 0) { + return key; + } + return strchr(key + 1, 0) + 1; +} + +static int phpdbg_parse_variable_arg_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, phpdbg_parse_var_func callback TSRMLS_DC) { + return callback(name, len, keyname, keylen, parent, zv TSRMLS_CC); +} + +PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC) { + return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_parse_variable_arg_wrapper, silent, callback TSRMLS_CC); +} + +PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC) { + int ret = FAILURE; + zend_bool new_index = 1; + char *last_index; + size_t index_len = 0; + zval **zv; + + if (len < 2 || *input != '$') { + goto error; + } + + while (i++ < len) { + if (i == len) { + new_index = 1; + } else { + switch (input[i]) { + case '[': + new_index = 1; + break; + case ']': + break; + case '>': + if (last_index[index_len - 1] == '-') { + new_index = 1; + index_len--; + } + break; + + default: + if (new_index) { + last_index = input + i; + new_index = 0; + } + if (input[i - 1] == ']') { + goto error; + } + index_len++; + } + } + + if (new_index && index_len == 0) { + HashPosition position; + for (zend_hash_internal_pointer_reset_ex(parent, &position); + zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS; + zend_hash_move_forward_ex(parent, &position)) { + if (i == len || (i == len - 1 && input[len - 1] == ']')) { + zval *key = emalloc(sizeof(zval)); + size_t namelen; + char *name; + char *keyname = estrndup(last_index, index_len); + zend_hash_get_current_key_zval_ex(parent, key, &position); + convert_to_string(key); + name = emalloc(i + Z_STRLEN_P(key) + 2); + namelen = sprintf(name, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":""); + efree(key); + + ret = callback(name, namelen, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; + } else if (Z_TYPE_PP(zv) == IS_OBJECT) { + phpdbg_parse_variable_with_arg(input, len, Z_OBJPROP_PP(zv), i, callback, silent, arg TSRMLS_CC); + } else if (Z_TYPE_PP(zv) == IS_ARRAY) { + phpdbg_parse_variable_with_arg(input, len, Z_ARRVAL_PP(zv), i, callback, silent, arg TSRMLS_CC); + } else { + /* Ignore silently */ + } + } + return ret; + } else if (new_index) { + char last_chr = last_index[index_len]; + last_index[index_len] = 0; + if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) { + if (!silent) { + phpdbg_error("variable", "type=\"undefined\" variable=\"%.*s\"", "%.*s is undefined", (int) i, input); + } + return FAILURE; + } + last_index[index_len] = last_chr; + if (i == len) { + char *name = estrndup(input, len); + char *keyname = estrndup(last_index, index_len); + + ret = callback(name, len, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; + } else if (Z_TYPE_PP(zv) == IS_OBJECT) { + parent = Z_OBJPROP_PP(zv); + } else if (Z_TYPE_PP(zv) == IS_ARRAY) { + parent = Z_ARRVAL_PP(zv); + } else { + phpdbg_error("variable", "type=\"notiterable\" variable=\"%.*s\"", "%.*s is nor an array nor an object", (int) i, input); + return FAILURE; + } + index_len = 0; + } + } + + return ret; + error: + phpdbg_error("variable", "type=\"invalidinput\"", "Malformed input"); + return FAILURE; +} + +static int phpdbg_xml_array_element_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) { + phpdbg_xml("nKeyLength == 0) { /* numeric key */ + phpdbg_xml(" name=\"%ld\"", hash_key->h); + } else { /* string key */ + phpdbg_xml(" name=\"%.*s\"", hash_key->nKeyLength - 1, hash_key->arKey); + } + } phpdbg_catch_access { + phpdbg_xml(" severity=\"error\" >"); + return 0; + } phpdbg_end_try_access(); + + phpdbg_xml(">"); + + phpdbg_xml_var_dump(zv TSRMLS_CC); + + phpdbg_xml(""); + + return 0; +} + +static int phpdbg_xml_object_property_dump(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) { + phpdbg_xml("nKeyLength == 0) { /* numeric key */ + phpdbg_xml(" name=\"%ld\"", hash_key->h); + } else { /* string key */ + const char *prop_name, *class_name; + int unmangle = zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, &class_name, &prop_name); + + if (class_name && unmangle == SUCCESS) { + phpdbg_xml(" name=\"%s\"", prop_name); + if (class_name[0] == '*') { + phpdbg_xml(" protection=\"protected\""); + } else { + phpdbg_xml(" class=\"%s\" protection=\"private\"", class_name); + } + } else { + phpdbg_xml(" name=\"%.*s\" protection=\"public\"", hash_key->nKeyLength - 1, hash_key->arKey); + } + } + } phpdbg_catch_access { + phpdbg_xml(" severity=\"error\" >"); + return 0; + } phpdbg_end_try_access(); + + phpdbg_xml(">"); + + phpdbg_xml_var_dump(zv TSRMLS_CC); + + phpdbg_xml(""); + + return 0; +} + +#define COMMON (Z_ISREF_PP(zv) ? "&" : "") + +PHPDBG_API void phpdbg_xml_var_dump(zval **zv TSRMLS_DC) { + HashTable *myht; + const char *class_name; + zend_uint class_name_len; + int (*element_dump_func)(zval** TSRMLS_DC, int, va_list, zend_hash_key*); + int is_temp; + + phpdbg_try_access { + switch (Z_TYPE_PP(zv)) { + case IS_BOOL: + phpdbg_xml("", COMMON, Z_LVAL_PP(zv) ? "true" : "false"); + break; + case IS_NULL: + phpdbg_xml("", COMMON); + break; + case IS_LONG: + phpdbg_xml("", COMMON, Z_LVAL_PP(zv)); + break; + case IS_DOUBLE: + phpdbg_xml("", COMMON, (int) EG(precision), Z_DVAL_PP(zv)); + break; + case IS_STRING: + phpdbg_xml("", COMMON, Z_STRLEN_PP(zv), Z_STRLEN_PP(zv), Z_STRVAL_PP(zv)); + break; + case IS_ARRAY: + myht = Z_ARRVAL_PP(zv); + if (++myht->nApplyCount > 1) { + phpdbg_xml(""); + --myht->nApplyCount; + break; + } + phpdbg_xml("", COMMON, zend_hash_num_elements(myht)); + element_dump_func = phpdbg_xml_array_element_dump; + is_temp = 0; + goto head_done; + case IS_OBJECT: + myht = Z_OBJDEBUG_PP(zv, is_temp); + if (myht && ++myht->nApplyCount > 1) { + phpdbg_xml(""); + --myht->nApplyCount; + break; + } + + if (Z_OBJ_HANDLER(**zv, get_class_name)) { + Z_OBJ_HANDLER(**zv, get_class_name)(*zv, &class_name, &class_name_len, 0 TSRMLS_CC); + phpdbg_xml("", COMMON, class_name, Z_OBJ_HANDLE_PP(zv), myht ? zend_hash_num_elements(myht) : 0); + efree((char*)class_name); + } else { + phpdbg_xml("", COMMON, Z_OBJ_HANDLE_PP(zv), myht ? zend_hash_num_elements(myht) : 0); + } + element_dump_func = phpdbg_xml_object_property_dump; +head_done: + if (myht) { + zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) element_dump_func, 0); + --myht->nApplyCount; + if (is_temp) { + zend_hash_destroy(myht); + efree(myht); + } + } + if (Z_TYPE_PP(zv) == IS_ARRAY) { + phpdbg_xml(""); + } else { + phpdbg_xml(""); + } + break; + case IS_RESOURCE: { + const char *type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(zv) TSRMLS_CC); + phpdbg_xml("", COMMON, Z_LVAL_PP(zv), type_name ? type_name : "unknown"); + break; + } + default: + break; + } + } phpdbg_end_try_access(); +} diff --git a/phpdbg_utils.h b/phpdbg_utils.h index 56bacfc459..d657dc79fd 100644 --- a/phpdbg_utils.h +++ b/phpdbg_utils.h @@ -33,52 +33,6 @@ PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC); PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*); PHPDBG_API const zend_function *phpdbg_get_function(const char*, const char* TSRMLS_DC); -/** - * Error/notice/formatting helpers - */ -enum { - P_ERROR = 1, - P_NOTICE, - P_WRITELN, - P_WRITE, - P_LOG -}; - -#ifdef ZTS -PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5); -#else -PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -#endif - -PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...); - -#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) - -#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_writeln_ex(out, fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_write_ex(out, fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__) - -#if PHPDBG_DEBUG -# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__) -#else -# define phpdbg_debug(fmt, ...) -#endif - -/* {{{ For writing blank lines */ -#define EMPTY NULL /* }}} */ - -/* {{{ For prompt lines */ -#define PROMPT "phpdbg>" /* }}} */ - -/* {{{ For separation */ -#define SEPARATE "------------------------------------------------" /* }}} */ - /* {{{ Color Management */ #define PHPDBG_COLOR_LEN 12 #define PHPDBG_COLOR_D(color, code) \ @@ -112,7 +66,7 @@ typedef struct _phpdbg_element_t { PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC); PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC); PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC); -PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D); +PHPDBG_API const phpdbg_color_t *phpdbg_get_colors(TSRMLS_D); PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC); /* }}} */ /* {{{ Prompt Management */ @@ -122,6 +76,8 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */ /* {{{ Console Width */ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */ +PHPDBG_API void phpdbg_set_async_io(int fd); + int phpdbg_rebuild_symtable(TSRMLS_D); #if PHP_VERSION_ID < 50500 @@ -144,4 +100,16 @@ static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, Ha } #endif +int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC); + +char *phpdbg_get_property_key(char *key); + +typedef int (*phpdbg_parse_var_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv TSRMLS_DC); +typedef int (*phpdbg_parse_var_with_arg_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, void *arg TSRMLS_DC); + +PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC); +PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC); + +PHPDBG_API void phpdbg_xml_var_dump(zval **zv TSRMLS_DC); + #endif /* PHPDBG_UTILS_H */ diff --git a/phpdbg_wait.c b/phpdbg_wait.c new file mode 100644 index 0000000000..ea506a2d93 --- /dev/null +++ b/phpdbg_wait.c @@ -0,0 +1,419 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_wait.h" +#include "phpdbg_prompt.h" +#include "ext/json/JSON_parser.h" +#include "ext/standard/basic_functions.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +ZEND_EXTERN_MODULE_GLOBALS(json); + +static void phpdbg_rebuild_http_globals_array(int type, const char *name TSRMLS_DC) { + zval **zvpp; + if (PG(http_globals)[type]) { + zval_dtor(PG(http_globals)[type]); + } + if (zend_hash_find(&EG(symbol_table), name, strlen(name) + 1, (void **) &zvpp) == SUCCESS) { + Z_SET_REFCOUNT_PP(zvpp, 2); + PG(http_globals)[type] = *zvpp; + } +} + + +static int phpdbg_dearm_autoglobals(zend_auto_global *auto_global TSRMLS_DC) { + if (auto_global->name_len != sizeof("GLOBALS") - 1 || memcmp(auto_global->name, "GLOBALS", sizeof("GLOBALS") - 1)) { + auto_global->armed = 0; + } + + return ZEND_HASH_APPLY_KEEP; +} + +typedef struct { + HashTable *ht[2]; + HashPosition pos[2]; +} phpdbg_intersect_ptr; + +static int phpdbg_array_data_compare(const void *a, const void *b TSRMLS_DC) { + Bucket *f, *s; + zval result; + zval *first, *second; + + f = *((Bucket **) a); + s = *((Bucket **) b); + + first = *((zval **) f->pData); + second = *((zval **) s->pData); + + if (string_compare_function(&result, first, second TSRMLS_CC) == FAILURE) { + return 0; + } + + if (Z_LVAL(result) < 0) { + return -1; + } else if (Z_LVAL(result) > 0) { + return 1; + } + + return 0; +} + +static void phpdbg_array_intersect_init(phpdbg_intersect_ptr *info, HashTable *ht1, HashTable *ht2 TSRMLS_DC) { + info->ht[0] = ht1; + info->ht[1] = ht2; + + zend_hash_sort(info->ht[0], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC); + zend_hash_sort(info->ht[1], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(info->ht[0], &info->pos[0]); + zend_hash_internal_pointer_reset_ex(info->ht[1], &info->pos[1]); +} + +/* -1 => first array, 0 => both arrays equal, 1 => second array */ +static int phpdbg_array_intersect(phpdbg_intersect_ptr *info, zval ***ptr) { + int ret; + zval **zvpp[2]; + int invalid = !info->ht[0] + !info->ht[1]; + + if (invalid > 0) { + invalid = !info->ht[0]; + + if (zend_hash_get_current_data_ex(info->ht[invalid], (void **) ptr, &info->pos[invalid]) == FAILURE) { + *ptr = NULL; + return 0; + } + + zend_hash_move_forward_ex(info->ht[invalid], &info->pos[invalid]); + + return invalid ? 1 : -1; + } + + if (zend_hash_get_current_data_ex(info->ht[0], (void **) &zvpp[0], &info->pos[0]) == FAILURE) { + info->ht[0] = NULL; + return phpdbg_array_intersect(info, ptr); + } + if (zend_hash_get_current_data_ex(info->ht[1], (void **) &zvpp[1], &info->pos[1]) == FAILURE) { + info->ht[1] = NULL; + return phpdbg_array_intersect(info, ptr); + } + + ret = zend_binary_zval_strcmp(*zvpp[0], *zvpp[1]); + + if (ret <= 0) { + *ptr = zvpp[0]; + zend_hash_move_forward_ex(info->ht[0], &info->pos[0]); + } + if (ret >= 0) { + *ptr = zvpp[1]; + zend_hash_move_forward_ex(info->ht[1], &info->pos[1]); + } + + return ret; +} + +void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC) { +#ifdef HAVE_JSON + zval *free_zv = NULL; + zval zv, **zvpp; + HashTable *ht; + php_json_decode(&zv, msg, len, 1, 1000 /* enough */ TSRMLS_CC); + + if (JSON_G(error_code) != PHP_JSON_ERROR_NONE) { + phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed JSON was sent to this socket, arborting"); + return; + } + + ht = Z_ARRVAL(zv); + + /* Reapply symbol table */ + if (zend_hash_find(ht, "GLOBALS", sizeof("GLOBALS"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) { + { + zval **srv; + if (zend_hash_find(Z_ARRVAL_PP(zvpp), "_SERVER", sizeof("_SERVER"), (void **) &srv) == SUCCESS && Z_TYPE_PP(srv) == IS_ARRAY) { + zval **script; + if (zend_hash_find(Z_ARRVAL_PP(srv), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &script) == SUCCESS && Z_TYPE_PP(script) == IS_STRING) { + phpdbg_param_t param; + param.str = Z_STRVAL_PP(script); + PHPDBG_COMMAND_HANDLER(exec)(¶m TSRMLS_CC); + } + } + } + + PG(auto_globals_jit) = 0; + zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_dearm_autoglobals TSRMLS_CC); + + zend_hash_clean(&EG(symbol_table)); + EG(symbol_table) = *Z_ARRVAL_PP(zvpp); + + /* Rebuild cookies, env vars etc. from GLOBALS (PG(http_globals)) */ + phpdbg_rebuild_http_globals_array(TRACK_VARS_POST, "_POST" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_GET, "_GET" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_COOKIE, "_COOKIE" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_SERVER, "_SERVER" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_ENV, "_ENV" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_FILES, "_FILES" TSRMLS_CC); + + Z_ADDREF_PP(zvpp); + free_zv = *zvpp; + } + + if (zend_hash_find(ht, "input", sizeof("input"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_STRING) { + if (SG(request_info).request_body) { + php_stream_close(SG(request_info).request_body); + } + SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir)); + php_stream_truncate_set_size(SG(request_info).request_body, 0); + php_stream_write(SG(request_info).request_body, Z_STRVAL_PP(zvpp), Z_STRLEN_PP(zvpp)); + } + + if (zend_hash_find(ht, "cwd", sizeof("cwd"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_STRING) { + if (VCWD_CHDIR(Z_STRVAL_PP(zvpp)) == SUCCESS) { + if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) { + efree(BG(CurrentStatFile)); + BG(CurrentStatFile) = NULL; + } + if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) { + efree(BG(CurrentLStatFile)); + BG(CurrentLStatFile) = NULL; + } + } + } + + if (zend_hash_find(ht, "sapi_name", sizeof("sapi_name"), (void **) &zvpp) == SUCCESS && (Z_TYPE_PP(zvpp) == IS_STRING || Z_TYPE_PP(zvpp) == IS_NULL)) { + if (PHPDBG_G(sapi_name_ptr)) { + free(PHPDBG_G(sapi_name_ptr)); + } + if (Z_TYPE_PP(zvpp) == IS_STRING) { + PHPDBG_G(sapi_name_ptr) = sapi_module.name = strdup(Z_STRVAL_PP(zvpp)); + } else { + PHPDBG_G(sapi_name_ptr) = sapi_module.name = NULL; + } + } + + if (zend_hash_find(ht, "modules", sizeof("modules"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) { + HashPosition position; + phpdbg_intersect_ptr pos; + zval **module; + zend_module_entry *mod; + HashTable zv_registry; + + /* intersect modules, unregister modules loaded "too much", announce not yet registered modules (phpdbg_notice) */ + + zend_hash_init(&zv_registry, zend_hash_num_elements(&module_registry), 0, ZVAL_PTR_DTOR, 0); + for (zend_hash_internal_pointer_reset_ex(&module_registry, &position); + zend_hash_get_current_data_ex(&module_registry, (void **) &mod, &position) == SUCCESS; + zend_hash_move_forward_ex(&module_registry, &position)) { + if (mod->name) { + zval **value = emalloc(sizeof(zval *)); + MAKE_STD_ZVAL(*value); + ZVAL_STRING(*value, mod->name, 1); + zend_hash_next_index_insert(&zv_registry, value, sizeof(zval *), NULL); + } + } + + phpdbg_array_intersect_init(&pos, &zv_registry, Z_ARRVAL_PP(zvpp) TSRMLS_CC); + do { + int mode = phpdbg_array_intersect(&pos, &module); + if (mode < 0) { + // loaded module, but not needed + if (strcmp(PHPDBG_NAME, Z_STRVAL_PP(module))) { + zend_hash_del(&module_registry, Z_STRVAL_PP(module), Z_STRLEN_PP(module) + 1); + } + } else if (mode > 0) { + // not loaded module + if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_PP(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_PP(module), Z_STRVAL_PP(module), Z_STRLEN_PP(module), Z_STRVAL_PP(module)); + } + } + } while (module); + + zend_hash_clean(&zv_registry); + } + + if (zend_hash_find(ht, "extensions", sizeof("extensions"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) { + zend_extension *extension; + zend_llist_position pos; + HashPosition hpos; + zval **name, key; + + extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos); + while (extension) { + extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos); + + /* php_serach_array() body should be in some ZEND_API function */ + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &hpos); + zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void **) &name, &hpos) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &hpos)) { + if (Z_TYPE_PP(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_PP(name), Z_STRLEN_PP(name))) { + break; + } + } + + if (zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void **) &zvpp, &hpos) == FAILURE) { + /* sigh, breaking the encapsulation, there aren't any functions manipulating the llist at the place of the zend_llist_position */ + zend_llist_element *elm = pos; + if (elm->prev) { + elm->prev->next = elm->next; + } else { + zend_extensions.head = elm->next; + } + if (elm->next) { + elm->next->prev = elm->prev; + } else { + zend_extensions.tail = elm->prev; + } +#if ZEND_EXTENSIONS_SUPPORT + if (extension->shutdown) { + extension->shutdown(extension); + } +#endif + if (zend_extensions.dtor) { + zend_extensions.dtor(elm->data); + } + 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)); + } + } + + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &hpos); + zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void **) &name, &hpos) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &hpos)) { + 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_PP(name), Z_STRVAL_PP(name)); + } + } + } + + zend_ini_deactivate(TSRMLS_C); + + if (zend_hash_find(ht, "systemini", sizeof("systemini"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) { + HashPosition position; + zval **ini_entry; + zend_ini_entry *original_ini; + zval key; + + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &position); + zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void**) &ini_entry, &position) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &position)) { + zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &position); + if (Z_TYPE(key) == IS_STRING) { + if (Z_TYPE_PP(ini_entry) == IS_STRING) { + if (zend_hash_find(EG(ini_directives), Z_STRVAL(key), Z_STRLEN(key) + 1, (void **) &original_ini) == SUCCESS) { + if (!original_ini->on_modify || original_ini->on_modify(original_ini, Z_STRVAL_PP(ini_entry), Z_STRLEN_PP(ini_entry), original_ini->mh_arg1, original_ini->mh_arg2, original_ini->mh_arg3, ZEND_INI_STAGE_ACTIVATE TSRMLS_CC) == SUCCESS) { + if (original_ini->modified && original_ini->orig_value != original_ini->value) { + efree(original_ini->value); + } + original_ini->value = Z_STRVAL_PP(ini_entry); + original_ini->value_length = Z_STRLEN_PP(ini_entry); + Z_TYPE_PP(ini_entry) = IS_NULL; /* don't free the value */ + } + } + } + efree(Z_STRVAL(key)); + } + } + } + + if (zend_hash_find(ht, "userini", sizeof("userini"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) { + HashPosition position; + zval **ini_entry; + zval key; + + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &position); + zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void**) &ini_entry, &position) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &position)) { + zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &position); + if (Z_TYPE(key) == IS_STRING) { + if (Z_TYPE_PP(ini_entry) == IS_STRING) { + zend_alter_ini_entry_ex(Z_STRVAL(key), Z_STRLEN(key) + 1, Z_STRVAL_PP(ini_entry), Z_STRLEN_PP(ini_entry), ZEND_INI_PERDIR, ZEND_INI_STAGE_HTACCESS, 1 TSRMLS_CC); + } + efree(Z_STRVAL(key)); + } + } + } + + zval_dtor(&zv); + if (free_zv) { + /* separate freeing to not dtor the symtable too, just the container zval... */ + efree(free_zv); + } + + /* Reapply raw input */ + /* ??? */ +#endif +} + +PHPDBG_COMMAND(wait) /* {{{ */ +{ +#ifdef HAVE_JSON + struct sockaddr_un local, remote; + int rlen, sr, sl; + unlink(PHPDBG_G(socket_path)); + if (PHPDBG_G(socket_server_fd) == -1) { + int len; + PHPDBG_G(socket_server_fd) = sl = socket(AF_UNIX, SOCK_STREAM, 0); + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, PHPDBG_G(socket_path)); + 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)); + return FAILURE; + } + + chmod(PHPDBG_G(socket_path), 0666); + + listen(sl, 2); + } else { + sl = PHPDBG_G(socket_server_fd); + } + + rlen = sizeof(remote); + sr = accept(sl, (struct sockaddr *) &remote, (socklen_t *) &rlen); + + char msglen[5]; + int recvd = 4; + + do { + recvd -= recv(sr, &(msglen[4 - recvd]), recvd, 0); + } while (recvd > 0); + + recvd = *(size_t *) msglen; + char *data = emalloc(recvd); + + do { + recvd -= recv(sr, &(data[(*(int *) msglen) - recvd]), recvd, 0); + } while (recvd > 0); + + phpdbg_webdata_decompress(data, *(int *) msglen TSRMLS_CC); + + if (PHPDBG_G(socket_fd) != -1) { + close(PHPDBG_G(socket_fd)); + } + PHPDBG_G(socket_fd) = sr; + + efree(data); + + phpdbg_notice("wait", "import=\"success\"", "Successfully imported request data, stopped before executing"); + + return SUCCESS; +#endif +} /* }}} */ diff --git a/phpdbg_wait.h b/phpdbg_wait.h new file mode 100644 index 0000000000..7cf95919cc --- /dev/null +++ b/phpdbg_wait.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WAIT_H +#define PHPDBG_WAIT_H + +#include "zend.h" +#include "phpdbg.h" + +PHPDBG_COMMAND(wait); + +void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC); + +#endif /* PHPDBG_WAIT_H */ diff --git a/phpdbg_watch.c b/phpdbg_watch.c index e88622444b..de6cddf5b3 100644 --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@ -30,7 +30,6 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); - typedef struct { void *page; size_t size; @@ -138,13 +137,6 @@ static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) return SUCCESS; } -static char *phpdbg_get_property_key(char *key) { - if (*key != 0) { - return key; - } - return strchr(key + 1, 0) + 1; -} - static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { HashTable *ht; @@ -190,7 +182,7 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_ } new_watch->str = NULL; - new_watch->str_len = asprintf(&new_watch->str, "%.*s%s%s%s", (int)watch->str_len, watch->str, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(new_watch->name_in_parent), Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"]":""); + new_watch->str_len = asprintf(&new_watch->str, "%.*s%s%s%s", (int) watch->str_len, watch->str, Z_TYPE_P(watch->addr.zv) == IS_ARRAY ? "[" : "->", phpdbg_get_property_key(new_watch->name_in_parent), Z_TYPE_P(watch->addr.zv) == IS_ARRAY ? "]" : ""); phpdbg_create_zval_watchpoint(*zv, new_watch); phpdbg_create_recursive_watchpoint(new_watch TSRMLS_CC); @@ -236,9 +228,9 @@ static int phpdbg_delete_watchpoint_recursive(phpdbg_watchpoint_t *watch, zend_b zend_hash_get_current_key_zval_ex(ht, &key, &position); str = NULL; if (Z_TYPE(key) == IS_STRING) { - str_len = asprintf(&str, "%.*s%s%s%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(Z_STRVAL(key)), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":""); + str_len = asprintf(&str, "%.*s%s%s%s", (int) watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY ? "[" : "->", phpdbg_get_property_key(Z_STRVAL(key)), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY ? "]" : ""); } else { - str_len = asprintf(&str, "%.*s%s%li%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_LVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":""); + str_len = asprintf(&str, "%.*s%s%li%s", (int) watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY ? "[" : "->", Z_LVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY ? "]" : ""); } if (zend_hash_find(&PHPDBG_G(watchpoints), str, str_len, (void **) &watchpoint) == SUCCESS) { @@ -281,118 +273,37 @@ static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) { ret = zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); } - free(tmp_watch->str); + efree(tmp_watch->str); + efree(tmp_watch->name_in_parent); efree(tmp_watch); return ret; } -static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) { - int ret = FAILURE; - zend_bool new_index = 1; - char *last_index; - int index_len = 0; - zval **zv; - - if (len < 2 || *input != '$') { - goto error; - } - - while (i++ < len) { - if (i == len) { - new_index = 1; - } else { - switch (input[i]) { - case '[': - new_index = 1; - break; - case ']': - break; - case '>': - if (last_index[index_len - 1] == '-') { - new_index = 1; - index_len--; - } - break; - - default: - if (new_index) { - last_index = input + i; - new_index = 0; - } - if (input[i - 1] == ']') { - goto error; - } - index_len++; - } - } - - if (new_index && index_len == 0) { - HashPosition position; - for (zend_hash_internal_pointer_reset_ex(parent, &position); - zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS; - zend_hash_move_forward_ex(parent, &position)) { - if (i == len || (i == len - 1 && input[len - 1] == ']')) { - zval *key = emalloc(sizeof(zval)); - phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); - watch->flags = 0; - zend_hash_get_current_key_zval_ex(parent, key, &position); - convert_to_string(key); - watch->str = malloc(i + Z_STRLEN_P(key) + 2); - watch->str_len = sprintf(watch->str, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":""); - efree(key); - watch->name_in_parent = zend_strndup(last_index, index_len); - watch->name_in_parent_len = index_len; - watch->parent_container = parent; - phpdbg_create_zval_watchpoint(*zv, watch); - - ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; - } else if (Z_TYPE_PP(zv) == IS_OBJECT) { - phpdbg_watchpoint_parse_input(input, len, Z_OBJPROP_PP(zv), i, callback, silent TSRMLS_CC); - } else if (Z_TYPE_PP(zv) == IS_ARRAY) { - phpdbg_watchpoint_parse_input(input, len, Z_ARRVAL_PP(zv), i, callback, silent TSRMLS_CC); - } else { - /* Ignore silently */ - } - } - return ret; - } else if (new_index) { - char last_chr = last_index[index_len]; - last_index[index_len] = 0; - if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) { - if (!silent) { - phpdbg_error("%.*s is undefined", (int)i, input); - } - return FAILURE; - } - last_index[index_len] = last_chr; - if (i == len) { - phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); - watch->flags = 0; - watch->str = zend_strndup(input, len); - watch->str_len = len; - watch->name_in_parent = zend_strndup(last_index, index_len); - watch->name_in_parent_len = index_len; - watch->parent_container = parent; - phpdbg_create_zval_watchpoint(*zv, watch); - - ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; - } else if (Z_TYPE_PP(zv) == IS_OBJECT) { - parent = Z_OBJPROP_PP(zv); - } else if (Z_TYPE_PP(zv) == IS_ARRAY) { - parent = Z_ARRVAL_PP(zv); - } else { - phpdbg_error("%.*s is nor an array nor an object", (int)i, input); - return FAILURE; - } - index_len = 0; - } +static int phpdbg_watchpoint_parse_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) { + int ret; + phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); + watch->flags = 0; + watch->str = name; + watch->str_len = len; + watch->name_in_parent = keyname; + watch->name_in_parent_len = keylen; + watch->parent_container = parent; + phpdbg_create_zval_watchpoint(*zv, watch); + + ret = callback(watch TSRMLS_CC); + + if (ret != SUCCESS) { + efree(watch); + efree(name); + efree(keyname); } return ret; - error: - phpdbg_error("Malformed input"); - return FAILURE; +} + +PHPDBG_API int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) { + return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, 0, callback TSRMLS_CC); } static int phpdbg_watchpoint_parse_symtables(char *input, size_t len, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) { @@ -412,9 +323,9 @@ PHPDBG_WATCH(delete) /* {{{ */ switch (param->type) { case STR_PARAM: if (phpdbg_delete_var_watchpoint(param->str, param->len TSRMLS_CC) == FAILURE) { - phpdbg_error("Nothing was deleted, no corresponding watchpoint found"); + phpdbg_error("watchdelete", "type=\"nowatch\"", "Nothing was deleted, no corresponding watchpoint found"); } else { - phpdbg_notice("Removed watchpoint %.*s", (int)param->len, param->str); + phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Removed watchpoint %.*s", (int) param->len, param->str); } break; @@ -433,7 +344,7 @@ PHPDBG_WATCH(recursive) /* {{{ */ switch (param->type) { case STR_PARAM: if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_recursive_watchpoint TSRMLS_CC) != FAILURE) { - phpdbg_notice("Set recursive watchpoint on %.*s", (int)param->len, param->str); + phpdbg_notice("watchrecursive", "variable=\"%.*s\"", "Set recursive watchpoint on %.*s", (int)param->len, param->str); } break; @@ -452,7 +363,7 @@ PHPDBG_WATCH(array) /* {{{ */ switch (param->type) { case STR_PARAM: if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_array_watchpoint TSRMLS_CC) != FAILURE) { - phpdbg_notice("Set array watchpoint on %.*s", (int)param->len, param->str); + phpdbg_notice("watcharray", "variable=\"%.*s\"", "Set array watchpoint on %.*s", (int)param->len, param->str); } break; @@ -473,7 +384,7 @@ void phpdbg_watch_HashTable_dtor(zval **zv) { PHPDBG_G(watchpoint_hit) = 1; - phpdbg_notice("%.*s was removed, removing watchpoint%s", (int)watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_RECURSIVE)?" recursively":""); + phpdbg_notice("watchdelete", "variable=\"%.*s\" recursive=\"%s\"", "%.*s was removed, removing watchpoint%s", (int)watch->str_len, watch->str, watch->flags & PHPDBG_WATCH_RECURSIVE ? " recursively" : ""); if (watch->flags & PHPDBG_WATCH_RECURSIVE) { phpdbg_delete_watchpoint_recursive(watch, 0 TSRMLS_CC); @@ -550,8 +461,8 @@ static void phpdbg_watch_dtor(void *pDest) { phpdbg_deactivate_watchpoint(watch TSRMLS_CC); phpdbg_remove_watchpoint(watch TSRMLS_CC); - free(watch->str); - free(watch->name_in_parent); + efree(watch->str); + efree(watch->name_in_parent); efree(watch); } @@ -585,7 +496,7 @@ void phpdbg_setup_watchpoints(TSRMLS_D) { static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { /* 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_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), (zend_ulong) dump->page, (zend_ulong) dump->page + dump->size); phpdbg_btree_result *result, *htresult; int elementDiff; void *curTest; @@ -597,7 +508,7 @@ static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { void *oldPtr = (char *)&dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page); char reenable = 1; - if ((size_t)watch->addr.ptr < (size_t)dump->page || (size_t)watch->addr.ptr + watch->size > (size_t)dump->page + dump->size) { + if ((size_t)watch->addr.ptr < (size_t)dump->page || (size_t)watch->addr.ptr + watch->size > (size_t) dump->page + dump->size) { continue; } @@ -629,14 +540,17 @@ static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { /* Show to the user what changed and delete watchpoint upon removal */ if (memcmp(oldPtr, watch->addr.ptr, watch->size) != SUCCESS) { - if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS || (watch->type == WATCH_ON_ZVAL && memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value))) || (watch->type == WATCH_ON_HASHTABLE + zend_bool do_break = PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS || (watch->type == WATCH_ON_ZVAL && memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value))) || (watch->type == WATCH_ON_HASHTABLE #if ZEND_DEBUG && !watch->addr.ht->inconsistent #endif - && zend_hash_num_elements((HashTable *)oldPtr) != zend_hash_num_elements(watch->addr.ht))) { + && zend_hash_num_elements((HashTable *)oldPtr) != zend_hash_num_elements(watch->addr.ht)); + + if (do_break) { PHPDBG_G(watchpoint_hit) = 1; - phpdbg_notice("Breaking on watchpoint %s", watch->str); + phpdbg_notice("watchhit", "variable=\"%s\"", "Breaking on watchpoint %.*s", (int) watch->str_len, watch->str); + phpdbg_xml(""); } switch (watch->type) { @@ -646,26 +560,28 @@ static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { int show_ref = ((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc || ((zval *)oldPtr)->is_ref__gc != watch->addr.zv->is_ref__gc; if (removed || show_value) { - phpdbg_write("Old value: "); if ((Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) && removed) { - phpdbg_writeln("Value inaccessible, HashTable already destroyed"); + phpdbg_writeln("watchvalue", "type=\"old\" inaccessible=\"inaccessible\"", "Old value inaccessible, array or object (HashTable) already destroyed"); } else { - zend_print_flat_zval_r((zval *)oldPtr TSRMLS_CC); - phpdbg_writeln(""); + phpdbg_out("Old value: "); + phpdbg_xml(""); + zend_print_flat_zval_r((zval *) oldPtr TSRMLS_CC); + phpdbg_xml(""); + phpdbg_out("\n"); } } if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && (removed || show_ref)) { - phpdbg_writeln("Old refcount: %d; Old is_ref: %d", ((zval *)oldPtr)->refcount__gc, ((zval *)oldPtr)->is_ref__gc); + phpdbg_write("watchrefcount", "type=\"old\" refcount=\"%d\" isref=\"%d\"", "Old refcount: %d; Old is_ref: %d", ((zval *) oldPtr)->refcount__gc, ((zval *) oldPtr)->is_ref__gc); } /* check if zval was removed */ if (removed) { - phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str); + phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Watchpoint %.*s was unset, removing watchpoint", (int) watch->str_len, watch->str); zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); reenable = 0; - if (Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) { + if (Z_TYPE_P((zval *) oldPtr) == IS_ARRAY || Z_TYPE_P((zval *) oldPtr) == IS_OBJECT) { goto remove_ht_watch; } @@ -673,22 +589,24 @@ static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { } if (show_value) { - phpdbg_write("New value: "); + phpdbg_out("New value: "); + phpdbg_xml(""); zend_print_flat_zval_r(watch->addr.zv TSRMLS_CC); - phpdbg_writeln(""); + phpdbg_xml(""); + phpdbg_out("\n"); } if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && show_ref) { - phpdbg_writeln("New refcount: %d; New is_ref: %d", watch->addr.zv->refcount__gc, watch->addr.zv->is_ref__gc); + phpdbg_writeln("watchrefcount", "type=\"new\" refcount=\"%d\" isref=\"%d\"", "New refcount: %d; New is_ref: %d", watch->addr.zv->refcount__gc, watch->addr.zv->is_ref__gc); } - if ((Z_TYPE_P(watch->addr.zv) == IS_ARRAY && Z_ARRVAL_P(watch->addr.zv) != Z_ARRVAL_P((zval *)oldPtr)) || (Z_TYPE_P(watch->addr.zv) != IS_OBJECT && Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) { + if ((Z_TYPE_P(watch->addr.zv) == IS_ARRAY && Z_ARRVAL_P(watch->addr.zv) != Z_ARRVAL_P((zval *) oldPtr)) || (Z_TYPE_P(watch->addr.zv) != IS_OBJECT && Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *) oldPtr))) { /* add new watchpoints if necessary */ if (watch->flags & PHPDBG_WATCH_RECURSIVE) { phpdbg_create_recursive_watchpoint(watch TSRMLS_CC); } } - if ((Z_TYPE_P((zval *)oldPtr) != IS_ARRAY || Z_ARRVAL_P(watch->addr.zv) == Z_ARRVAL_P((zval *)oldPtr)) && (Z_TYPE_P((zval *)oldPtr) != IS_OBJECT || Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) { + if ((Z_TYPE_P((zval *) oldPtr) != IS_ARRAY || Z_ARRVAL_P(watch->addr.zv) == Z_ARRVAL_P((zval *) oldPtr)) && (Z_TYPE_P((zval *)oldPtr) != IS_OBJECT || Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *) oldPtr))) { break; } @@ -704,7 +622,7 @@ remove_ht_watch: #if ZEND_DEBUG if (watch->addr.ht->inconsistent) { - phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str); + phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Watchpoint %.*s was unset, removing watchpoint", (int) watch->str_len, watch->str); zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); reenable = 0; @@ -713,12 +631,12 @@ remove_ht_watch: } #endif - elementDiff = zend_hash_num_elements((HashTable *)oldPtr) - zend_hash_num_elements(watch->addr.ht); + elementDiff = zend_hash_num_elements((HashTable *) oldPtr) - zend_hash_num_elements(watch->addr.ht); if (elementDiff) { if (elementDiff > 0) { - phpdbg_writeln("%d elements were removed from the array", elementDiff); + phpdbg_writeln("watchsize", "removed=\"%d\"", "%d elements were removed from the array", elementDiff); } else { - phpdbg_writeln("%d elements were added to the array", -elementDiff); + phpdbg_writeln("watchsize", "added=\"%d\"", "%d elements were added to the array", -elementDiff); /* add new watchpoints if necessary */ if (watch->flags & PHPDBG_WATCH_RECURSIVE) { @@ -726,11 +644,15 @@ remove_ht_watch: } } } - if (((HashTable *)oldPtr)->pInternalPointer != watch->addr.ht->pInternalPointer) { - phpdbg_writeln("Internal pointer of array was changed"); + if (((HashTable *) oldPtr)->pInternalPointer != watch->addr.ht->pInternalPointer) { + phpdbg_writeln("watcharrayptr", "", "Internal pointer of array was changed"); } break; } + + if (do_break) { + phpdbg_xml(""); + } } dump->reenable_writing = dump->reenable_writing | reenable; @@ -746,15 +668,15 @@ int phpdbg_print_changed_zvals(TSRMLS_D) { return FAILURE; } - dump = (phpdbg_watch_memdump **)zend_llist_get_last_ex(&PHPDBG_G(watchlist_mem), &pos); + dump = (phpdbg_watch_memdump **) zend_llist_get_last_ex(&PHPDBG_G(watchlist_mem), &pos); do { phpdbg_print_changed_zval(*dump TSRMLS_CC); - } while ((dump = (phpdbg_watch_memdump **)zend_llist_get_prev_ex(&PHPDBG_G(watchlist_mem), &pos))); + } 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; + ret = PHPDBG_G(watchpoint_hit) ? SUCCESS : FAILURE; PHPDBG_G(watchpoint_hit) = 0; return ret; @@ -764,23 +686,27 @@ void phpdbg_list_watchpoints(TSRMLS_D) { HashPosition position; phpdbg_watchpoint_t **watch; + phpdbg_xml(""); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(watchpoints), &position); zend_hash_get_current_data_ex(&PHPDBG_G(watchpoints), (void**) &watch, &position) == SUCCESS; zend_hash_move_forward_ex(&PHPDBG_G(watchpoints), &position)) { - phpdbg_writeln("%.*s", (int)(*watch)->str_len, (*watch)->str); + phpdbg_writeln("watchvariable", "variable=\"%.*s\" on=\"%s\" type=\"%s\"", "%.*s (%s, %s)", (int) (*watch)->str_len, (*watch)->str, (*watch)->type == WATCH_ON_HASHTABLE ? "array" : "variable", (*watch)->flags == PHPDBG_WATCH_RECURSIVE ? "recursive" : "simple"); } + + phpdbg_xml(""); } void phpdbg_watch_efree(void *ptr) { phpdbg_btree_result *result; TSRMLS_FETCH(); - result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong)ptr); + 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 ((size_t)watch->addr.ptr + watch->size > (size_t) ptr) { zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); } } diff --git a/phpdbg_watch.h b/phpdbg_watch.h index d00bcff77e..5c0079057c 100644 --- a/phpdbg_watch.h +++ b/phpdbg_watch.h @@ -42,9 +42,9 @@ PHPDBG_WATCH(recursive); */ static const phpdbg_command_t phpdbg_watch_commands[] = { - PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s"), - PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s"), - PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s"), + PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s", 0), + PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s", 0), + PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s", 0), PHPDBG_END_COMMAND }; diff --git a/phpdbg_webdata_transfer.c b/phpdbg_webdata_transfer.c new file mode 100644 index 0000000000..e7438ea01a --- /dev/null +++ b/phpdbg_webdata_transfer.c @@ -0,0 +1,185 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_webdata_transfer.h" +#include "ext/json/php_json.h" + +PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC) { +#ifdef HAVE_JSON + smart_str buf = {0}; + zval array; + HashTable *ht; + /* I really need to change that to an array of zvals... */ + zval zv1 = {{0}}, *zvp1 = &zv1; + zval zv2 = {{0}}, *zvp2 = &zv2; + zval zv3 = {{0}}, *zvp3 = &zv3; + zval zv4 = {{0}}, *zvp4 = &zv4; + zval zv5 = {{0}}, *zvp5 = &zv5; + zval zv6 = {{0}}, *zvp6 = &zv6; + zval zv7 = {{0}}, *zvp7 = &zv7; + zval zv8 = {{0}}, *zvp8 = &zv8; + + array_init(&array); + ht = Z_ARRVAL(array); + + /* fetch superglobals */ + { + zend_is_auto_global(ZEND_STRL("GLOBALS") TSRMLS_CC); + /* might be JIT */ + zend_is_auto_global(ZEND_STRL("_ENV") TSRMLS_CC); + zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC); + zend_is_auto_global(ZEND_STRL("_REQUEST") TSRMLS_CC); + array_init(&zv1); + zend_hash_copy(Z_ARRVAL(zv1), &EG(symbol_table), NULL, (void *) NULL, sizeof(zval *)); + Z_ARRVAL(zv1)->pDestructor = NULL; /* we're operating on a copy! Don't double free zvals */ + zend_hash_del(Z_ARRVAL(zv1), "GLOBALS", sizeof("GLOBALS")); /* do not use the reference to itself in json */ + zend_hash_add(ht, "GLOBALS", sizeof("GLOBALS"), &zvp1, sizeof(zval *), NULL); + } + + /* save php://input */ + { + php_stream *stream; + int len; + char *contents; + + stream = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir)); + if ((len = php_stream_copy_to_mem(stream, &contents, PHP_STREAM_COPY_ALL, 0)) > 0) { + ZVAL_STRINGL(&zv2, contents, len, 0); + } else { + ZVAL_EMPTY_STRING(&zv2); + } + Z_SET_REFCOUNT(zv2, 2); + zend_hash_add(ht, "input", sizeof("input"), &zvp2, sizeof(zval *), NULL); + } + + /* change sapi name */ + { + if (sapi_module.name) { + ZVAL_STRING(&zv6, sapi_module.name, 0); + } else { + Z_TYPE(zv6) = IS_NULL; + } + Z_SET_REFCOUNT(zv6, 2); + zend_hash_add(ht, "sapi_name", sizeof("sapi_name"), &zvp6, sizeof(zval *), NULL); + } + + /* handle modules / extensions */ + { + HashPosition position; + zend_module_entry *module; + zend_extension *extension; + zend_llist_position pos; + + array_init(&zv7); + for (zend_hash_internal_pointer_reset_ex(&module_registry, &position); + zend_hash_get_current_data_ex(&module_registry, (void**) &module, &position) == SUCCESS; + zend_hash_move_forward_ex(&module_registry, &position)) { + zval **value = emalloc(sizeof(zval *)); + ALLOC_ZVAL(*value); + ZVAL_STRING(*value, module->name, 1); + zend_hash_next_index_insert(Z_ARRVAL(zv7), value, sizeof(zval *), NULL); + } + zend_hash_add(ht, "modules", sizeof("modules"), &zvp7, sizeof(zval *), NULL); + + array_init(&zv8); + extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos); + while (extension) { + zval **value = emalloc(sizeof(zval *)); + ALLOC_ZVAL(*value); + ZVAL_STRING(*value, extension->name, 1); + zend_hash_next_index_insert(Z_ARRVAL(zv8), value, sizeof(zval *), NULL); + extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos); + } + zend_hash_add(ht, "extensions", sizeof("extensions"), &zvp8, sizeof(zval *), NULL); + } + + /* switch cwd */ + if (SG(options) & SAPI_OPTION_NO_CHDIR) { + char *ret = NULL; + char path[MAXPATHLEN]; + +#if HAVE_GETCWD + ret = VCWD_GETCWD(path, MAXPATHLEN); +#elif HAVE_GETWD + ret = VCWD_GETWD(path); +#endif + if (ret) { + ZVAL_STRING(&zv5, path, 1); + Z_SET_REFCOUNT(zv5, 1); + zend_hash_add(ht, "cwd", sizeof("cwd"), &zvp5, sizeof(zval *), NULL); + } + } + + /* get system ini entries */ + { + HashPosition position; + zend_ini_entry *ini_entry; + + array_init(&zv3); + for (zend_hash_internal_pointer_reset_ex(EG(ini_directives), &position); + zend_hash_get_current_data_ex(EG(ini_directives), (void**) &ini_entry, &position) == SUCCESS; + zend_hash_move_forward_ex(EG(ini_directives), &position)) { + zval **value = emalloc(sizeof(zval *)); + if (ini_entry->modified) { + if (!ini_entry->orig_value) { + efree(value); + continue; + } + ALLOC_ZVAL(*value); + ZVAL_STRINGL(*value, ini_entry->orig_value, ini_entry->orig_value_length, 1); + } else { + if (!ini_entry->value) { + efree(value); + continue; + } + ALLOC_ZVAL(*value); + ZVAL_STRINGL(*value, ini_entry->value, ini_entry->value_length, 1); + } + zend_hash_add(Z_ARRVAL(zv3), ini_entry->name, ini_entry->name_length, value, sizeof(zval *), NULL); + } + zend_hash_add(ht, "systemini", sizeof("systemini"), &zvp3, sizeof(zval *), NULL); + } + + /* get perdir ini entries */ + if (EG(modified_ini_directives)) { + HashPosition position; + zend_ini_entry *ini_entry; + + array_init(&zv4); + for (zend_hash_internal_pointer_reset_ex(EG(modified_ini_directives), &position); + zend_hash_get_current_data_ex(EG(modified_ini_directives), (void**) &ini_entry, &position) == SUCCESS; + zend_hash_move_forward_ex(EG(modified_ini_directives), &position)) { + zval **value = emalloc(sizeof(zval *)); + if (!ini_entry->value) { + efree(value); + continue; + } + ALLOC_ZVAL(*value); + ZVAL_STRINGL(*value, ini_entry->value, ini_entry->value_length, 1); + zend_hash_add(Z_ARRVAL(zv4), ini_entry->name, ini_entry->name_length, value, sizeof(zval *), NULL); + } + zend_hash_add(ht, "userini", sizeof("userini"), &zvp4, sizeof(zval *), NULL); + } + + /* encode data */ + php_json_encode(&buf, &array, 0 TSRMLS_CC); + *msg = buf.c; + *len = buf.len; + zval_dtor(&array); +#endif +} diff --git a/phpdbg_webdata_transfer.h b/phpdbg_webdata_transfer.h new file mode 100644 index 0000000000..d70175ad99 --- /dev/null +++ b/phpdbg_webdata_transfer.h @@ -0,0 +1,27 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WEBDATA_TRANSFER_H +#define PHPDBG_WEBDATA_TRANSFER_H + +#include "zend.h" +#include "phpdbg.h" + +PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC); + +#endif /* PHPDBG_WEBDATA_TRANSFER_H */ diff --git a/tests/commands/0002_set.test b/tests/commands/0002_set.test index 468ac6d9ea..6a14a15adc 100644 --- a/tests/commands/0002_set.test +++ b/tests/commands/0002_set.test @@ -8,7 +8,7 @@ # setting error color # setting notice color # Failed to find breakpoint #0 -# oplog disabled +# [Oplog off] # opened oplog test.log # nothing ################################################# diff --git a/tests/commands/0102_print.test b/tests/commands/0102_print.test index de4acb7651..c174564e07 100644 --- a/tests/commands/0102_print.test +++ b/tests/commands/0102_print.test @@ -4,15 +4,14 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[User Class: test] -#Methods (3): +#[User Class: test (3 methods)] #L%d-%d test::testMethod() %s # L%d %s ZEND_RETURN C%d # L%d-%d test::testPrivateMethod() %s # L%d %s ZEND_RETURN C%d # L%d-%d test::testProtectedMethod() %s # L%d %s ZEND_RETURN C%d -#[User Method testMethod] +#[User Method testMethod (1 ops)] # L%d-%d test::testMethod() %s # L%d %s ZEND_RETURN C%d ################################################# diff --git a/tests/commands/0104_clean.test b/tests/commands/0104_clean.test index c7a579be17..d50903c479 100644 --- a/tests/commands/0104_clean.test +++ b/tests/commands/0104_clean.test @@ -4,11 +4,11 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[Cleaning Execution Environment] -#Classes %d -#Functions %d -#Constants %d -#Includes %d +#Cleaning Execution Environment +#Classes %d +#Functions %d +#Constants %d +#Includes %d #[Nothing to execute!] ################################################# clean diff --git a/tests/commands/0105_clear.test b/tests/commands/0105_clear.test index b547b0d6ba..8ce1002491 100644 --- a/tests/commands/0105_clear.test +++ b/tests/commands/0105_clear.test @@ -4,7 +4,7 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[Clearing Breakpoints] +#Clearing Breakpoints #File%w%d #Functions%w%d #Methods%w%d diff --git a/tests/commands/0106_compile.test b/tests/commands/0106_compile.test index 7193600ea3..b4d801670b 100644 --- a/tests/commands/0106_compile.test +++ b/tests/commands/0106_compile.test @@ -4,9 +4,9 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[Attempting compilation of %s] -#[Success] +#[Successful compilation of %s] #Hello World +#[Script ended normally] ################################################# <: define('OUT', diff --git a/xml.md b/xml.md new file mode 100644 index 0000000000..0556fb2415 --- /dev/null +++ b/xml.md @@ -0,0 +1,759 @@ +phpdbg XML format +================= + +Common attributes +================= + +severity +-------- + +- indicates the genre of phpdbg system output +- usually one of these values: + - normal + - notice + - error + +msgout +------ + +- text message output related to the xml data (e.g. <intro severity="normal" help="help" msgout="To get help using phpdbg type &quot;help&quot; and press enter" />) + +req +--- + +- the request id, if one was passed to the last command (via -r %d, where %d is the id) (and the output is related to that message) + +file +---- + +- refers to a filename + +method +------ + +- format classname::methodname +- refers to a method + +function +-------- + +- refers to a function + +symbol +------ + +- either function or method (is method if "::" are present) + +opline +------ + +- in hexadecimal format +- refers to a specific pointer to a (zend_)op + +opcode +------ + +- refers to an opcode (ZEND_*) + +type +---- + +- general attribute for most errors, describes the genre of the error + + +General tags +============ + +intro +----- + +- appears on startup if -q flag wasn't provided as command line arg +- before any input possibility +- attributes may be spread over multiple tags +- wrapped in <intros> tag + +### attributes ### + +- version: current phpdbg version (as string) +- help: command name for help +- report: URL for bug reporting + +prompt +------ + +- msg tag contains the text prompt +- indicates that a new command may be accepted + +phpdbg +------ + +- general text message output from phpdbg system + +stream +------ + +- any output by PHP itself (e.g. <stream type="stdout">test</stream>) + +### attributes ### + +- type: stderr or stdout + +php +--- + +- php error output + +### attributes ### + +- msg: the error message + + +General error tags +================== + +command +------- + +- general errors about commands + +### possible attributes ### + +- type + - toomanyargs: more arguments than allowed + - noarg: argument missing + - wrongarg: wrong type of argument (e.g. letters instead of integer) + - toofewargs: not enough arguments + - notfound: command (or subcommand) doesn't exist + - ambiguous: command was ambiguous + - invalidcommand: command input is totally invalid + - (nostack: should not happen: is an internal error) + - (emptystack: should not happen: is an internal error) +- command: passed command +- subcommand: passed subcommand (present if the error is related to the subcommand) +- expected: count of expected arguments +- got: type of argument for type "wrongarg" +- num: if possible, information about which parameter had a wrong argument + +inactive +-------- + +- by type + - op_array: nothing was yet compiled (probably because no execution context set) + - symbol_table: no symbol table present (not yet initiailized or already destructed) + - noexec: not in execution + - memory_manager: using the native memory manager (malloc, free, realloc) instead of e.g. the Zend MM + - notfound: file not found + - nocontext: execution context was not set (or compilation had failed) + - isrunning: command requires no running script + + +Commands +======== + +export +------ + +- tag: <exportbreakpoint /> +- usually triggered by successful export command +- may appear when cleaning to temporary store breakpoints +- errors by type + - openfailure: could not create file + +### attributes ### + +- count: number of exported breakpoints + +break / info break +------------------ + +- General tag for breakpoint creation, deletion and hits is "<breakpoint />" + +### possible attributes ### + +- id: the breakpoint id (if the leave command was executed, the id has the value "leave") +- num: the nth opline of a function/method/file +- add: has value "success"/"fail": a brekpoint was successfully/not added +- pending: the breakpoint is waiting for resolving (e.g. a file opline on a not yet loaded file) +- deleted: has value "success"/"fail": a breakpoint was successfully/not deleted +- eval: the condition on conditional breakpoints +- file +- opline +- opcode +- symbol +- function +- method +- line + + +- listing breakpoints always in a container element "<breakpoints>" + - Child nodes: + - function + - method + - file + - opline + - methodopline + - functionopline + - fileopline + - evalfunction + - evalfunctionopline + - evalmethod + - evalmethodopline + - evalfile + - evalopline + - eval + - opcode + - attributes: + - name: name of the symbol (function/method/file/opcode) + - disabled: empty value if enabled, non-empty if enabled + +- errors (by type) + - exists: the breakpoint already exists + - maxoplines: tries to break at an opline (usedoplinenum) higher than the number of present oplines (in maxoplinenum) + - nomethod: method doesn't exist + - internalfunction: one cannot break on an opline of an internal function + - notregular: tries to set a breakpoint in not a regular file + - (invalidparameter: should not happen: is an internal error) + +frame +----- + +- General tag for frames is "<frame>" +- always has id attribute; if it only has id attribute, it just indicates current frame number, no other elements follow +- may contain other elements (of type <arg>) when contained in <backtrace> tag +- <arg> always contains a <stream> element, the value of the variable + +### possible attributes ### + +- id: the frame id, current frame has id 0 (frames with internal function calls have the same id than their called frame) +- symbol ("{main}" is root frame) +- file +- line +- internal: has value "internal" when being an internal function call (one cannot inspect that frame) + +- being an error: (by type) + - maxnum: tried to access a frame with a number heigher than existing (or < 0) + +### attributes on <arg> ### + +- variadic: has a non-empty value if the argument is variadic +- name: variable name of parameter + +info (subcommands) +------------------ + +### break ### + +- See above ("break / info break") + +### files ### + +- lists included files +- <includedfileinfo num="" /> with num having an integer value, indicating the number of included files +- <includedfile name=""/>: one per file, with name being the file path of the included file + +### error ### + +- gets last error +- <lasterror error="" (file="" line="") /> +- error attribute contains the last error as a string, is empty if there's no last error + +### constants ### + +- <constantinfo num="" /> with num having an integer value, indicating the number of (local or superglobal) variables +- if info vars was used it'll have also one of these attributes: + - method + - function + - file + - opline +- for each variable there is a <constant> element +- <constant address="" refcount="" type="" name="" /> + - address: pointer to zval (hexadecimal) + - refcount: refcount of zval + - type: the variable type (long, string, ...). If the value is "unknown", the other attributes are meaningless + - name: the name of the variable + - value: the value of primitive types (scalars) => string/int/bool/double + - length: if string, then the length of that string + +### vars / globals ### + +- <variableinfo num="" /> with num having an integer value, indicating the number of (local or superglobal) variables +- if info vars was used it'll have also one of these attributes: + - method + - function + - file + - opline +- for each variable there is a <variable> element +- <variable address="" refcount="" type="" name="" /> + - address: pointer to zval (hexadecimal) + - refcount: refcount of zval + - type: the variable type (long, string, ...). If the value is "unknown", the other attributes are meaningless + - name: the name of the variable + - refstatus: empty if the zval is not a reference + - class: the class the object in the zval is an instance of + - resource: the type of the resource in the zval + - value: the value of primitive types (scalars) => string/int/bool/double + - length: if string, then the length of that string + +### literal ### + +- <literalinfo num="" /> with num having an integer value, indicating the number of literals, optional arguments are: + - method + - function + - file + - opline +- for each literal there is a <literal> followed by a <stream type="stdout"> which prints the value of the literal +- <literal id="" />: where id is the internal identifier of the literal + +### memory ### + +- Format: + + <meminfo /> + <current /> + <used mem="" /> + <real mem="" /> + <peak /> + <used mem="" /> + <real mem="" /> + +- mem is an attribute whose value is a float. The memory is given in kilobytes (1 kB == 1024 bytes) + +### classes ### + +- <classinfo num="" /> with num having an integer value, indicating the number of loaded user-defined classes +- Each class is enumerated with first a <class>, then an optional <parents> container and then a <classsource> element +- The <parents> container contains the <class> elements of the parent of the last <class> element. +- <class type="" flags="" name="" methodcount="" /> + - type: either "User" or "Internal" + - flags: either "Interface", "Class" or "Abstract Class" +- <classsource /> where the class was defined, if there are no attributes, location is unknown, usually defined by + - file + - line + +### funcs ### + +- <functioninfo num="" /> with num having an integer value, indicating the number of loaded user-defined functions +- Each class is enumerated with first a <function> and then a <functionsource> element +- <function name="" /> +- <functionsource /> where the function was defined, if there are no attributes, location is unknown, usually defined by + - file + - line + +list +---- + +- consists of <line> elements wrapped in a <list> container +- <list file=""> is the container element with file being the filename +- <line line="" code="" /> with value of code being the whole line of code in the line specified in the line attribute + - current: this attribute is set to "current" if that line is the line where the executor currently is + +print +----- + +### without a subcommand ### + +- <print> elements are wrapped in a <printinfo> element +- there may be a variable number of <print> elements with a variable count of args inside the <printinfo> element +- possible args are: + - readline: yes/no - readline enabled or disabled + - libedit: yes/no - libedit enabled or disabled + - context: current executing context + - compiled: yes/no - are there actual compiled ops? + - stepping: @@ TODO (meaningless for now) @@ + - quiet: on/off - should it always print the opline being currently executed? + - oplog: on/off - are oplines logged in a file? + - ops: number of opcodes in current executing context + - vars: number of compiled variables (CV) + - executing: yes/no - in executor? + - vmret: the return value of the last executed opcode + - default: continue + - 1: return from vm + - 2: enter stack frame + - 3: leave stack frame + - classes: number of classes + - functions: number of functions + - constants: number of constants + - includes: number of included files + +### with a subcommand ### + +- introduced by <printinfo num="" /> (except for print opline) with num being the number of opcodes and one of these args: + - file + - method + - function + - class (then also type and flags attributes, see info classes command for their meanings) + - symbol (also type and flags attributes; here the value of flags is either "Method" or "Function") +- if there is a class method, the methods are all wrapped in a <printmethods> container +- then comes a <printoplineinfo type="" /> where type is either "User" or "Internal" +- the <printoplineinfo> has either a method or a function attribute +- if the type is "Internal" + - there are no oplines, it's an internal method or function +- if the type is "User" + - it has these attributes + - startline: the first line of code where the method or function is defined + - endline: the lastt line of code where the method or function is defined + - file: the file of code where the method or function is defined + - is followed by the oplines of that method or function (<print> elements) +- <print line="%u" opline="%p" opcode="%s" op="%s" /> +- in case of print opline it emits a single <opline line="" opline="" opcode="" op="" file="" /> + +exec +---- + +- command executing and compiling a given file + - <exec type="unset" context="" />: indicates unsetting of the old context + - <exec type="unsetops" />: indicates unsetting of the old compiled opcodes + - <exec type="unchanged" />: same execution context choosen again + - <exec type="set" context="" />: indicates setting of the new context +- errors by tag + - <compile> + - openfailure: couldn't open file + - compilefailure: The file indicated in context couldn't be compiled + - <exec> + - invalid: given context (attribute) is not matching a valid file or symlink + - notfound: given context (attribute) does not exist + +run / <stop> tag +------------------- + +- runs the script (set via exec command) +- <stop type="end" />: script execution ended normally +- (error) <stop type="bailout" /> the VM bailed out (usually because there was some error) +- compile failures see under exec, errors, <compile> + +step +---- + +- steps by one line or opcode (as defined via set stepping) default is one line +- returns back to the executor + +continue +-------- + +- returns back to the executor + +until +----- + +- temporarily disables all the breakpoints on that line until that line was left once +- returns back to the executor + +finish +------ + +- temporarily disables all the breakpoints until the end of the current frame +- returns back to the executor + +leave +------ + +- temporarily disables all the breakpoints past the end of the current frame and then stops +- returns back to the executor + +back +---- + +- prints backtrace +- see frame command + +ev +-- + +- eval()uates some code +- output wrapped in <eval> tags +- output is here first a dump of xml tags (see "Variable Dump" section), then a dump wrapped in tags +- if there's an error, the tag will be , instead of the usual tag + +sh +-- + +- executes shell command +- still pipes to stdout ... without wrapping <stream> !!! (@@ TODO @@) + +source +------ + +- executes a file in .phpdbginit format +- errors by type + - notfound: file not found + +register +-------- + +- registers a function to be used like a command +- <register function="" />: successfully registered function +- errors by type + - notfound: no such function + - inuse: function already registered + +quit +---- + +- quits phpdbg +- if successful connection will be closed... + +clean +----- + +- cleans environment (basically a shutdown + new startup) +- <clean> tags wrapped in a <cleaninfo> container +- possible attributes of <clean> tag + - classes: number of classes + - functions: number of functions + - constants: number of constants + - includes: number of included files + +clear +----- + +- removes all breakpoints +- <clear> tags wrapped in a <clearinfo> container +- possible attributes of <clear> tag (value is always the number of defined breakpoints of that type) + - files + - functions + - methods + - oplines + - fileoplines + - functionoplines + - methodoplines + - eval + +watch +----- + +- watchpoints generally are identified by a variable (one may need to switch frames first...) +- <watch variable="" />, <watchrecursive variable="" /> and <watcharray variable="" /> (normal, array, recursive) +- <watch> if error, by type: + - undefined: tried to set a watchpoint on a not (yet) defined variable + - notiterable: element which is tried to be accessed as an object or array is nor array nor object + - invalidinput: generally malformed input +- <watchdelete variable="" />: when "watch delete" was used on a watchpoint +- (error) <watchdelete type="nowatch" />: that watchpoint doesn't exist, so couldn't be deleted +- for hit watchpoints etc., see Other tags, <watch*> +- when using watch list, <watchvariable> elements are wrapped in a <watchlist> container + - <watchvariable variable="" on="" type="" /> + - variable: watched variable (may be a variable of another scope!) + - on: values are array or variable, depending on what is watched + - type: values are recursive or simple, depending on whether the watchpoint is checked recursively or not + +set +--- + +- a general error is type="wrongargs" where a wrong argument was passed to a subcommand; tag is then <set*> + +### prompt ### + +- without other args, a <setpromt str="" /> tag is emitted where the value of the str attribue is the value of the prompt +- when there is another arg, the prompt is changed to that arg, no further xml answer + +### break ### + +- enables / disables a given breakpoint silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setbreak id="" active="" /> where active is on or off +- error with type="nobreak", when no breakpoint with the given id exists + +### breaks ### + +- generally enables / disables breakpoint functionality silently with no futher xml answer +- if the boolean switch is omitted, it emits current state in a <setbreaks active="" /> where active is on or off + +### color ### + +- sets the color on prompt, error or notices +- <setcolor type="" color="" code="" />: code is the color code of color, type is either: + - prompt + - error + - notice +- errors by type: + - nocolor: color doesn't exist + - invalidtype: type wasn't one of the three allowed types + +### colors ### + +- generally enables / disables colors silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setcolors active="" /> where active is on or off + +### oplog ### + +- sets oplog +- (error) <setoplog type="openfailure" file="" /> when it couldn't open the passed file path +- <setoplog type="closingold" /> is emitted when there was a previous open oplog (and a file is passed) +- if no further argument is passed, it emits current state in a <setoplog active="" /> where active is on or off + +### quiet ### + +- generally enables / disables quietness silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setquiet active="" /> where active is on or off + +### setpping ### + +- sets stepping to either opcode or line (so a step command will either advance one op or one line) +- if no further argument is passed, it emits current state in a <setoplog type="" /> where active is opcode or line + +### refcount ### + +- generally enables / disables showing of refcount in watchpoint breaks silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setrefcount active="" /> where active is on or off + +wait +---- + +- internally executes exec, so exec will output first (if binding to socket worked) + +### attributes ### + +- import: has value "success"/"fail" +- missingmodule/missingextension: modules/extensions loaded in the target SAPI, but not in phpdbg + +### errors (by type) ### + +- nosocket: couldn't establish socket +- invaliddata: invalid JSON passed to socket + +dl +-- + +- loads a module or Zend extension at a given path +- if a relative path is passed, it's relative to the extension_dir ini setting + +### attributes ### + +- extensiontype: "Zend extension" or "module" +- name: the extension name +- path: the path where it was loaded + +### errors (by type) ### + +- unsupported: dynamic extension loading is unsupported +- relpath: relative path given, but no extension_dir defined +- unknown: general error with internal DL_LOAD() (for message see msg attribute) +- wrongapi: wrong Zend engine version (apineeded / apiinstalled attributes give information about the API versions) +- wrongbuild: unmatched build versions (buildneeded / buildinstalled attributes give information about the build versions) +- registerfailure: registering module failed +- startupfailure: couldn't startup Zend extension / module +- initfailure: couldn't initialize module +- nophpso: passed shared object is not a valid Zend extension nor module + +- errors may have the module or extension attribute when their name is already known at the point of failure + + +Other tags +========== + +<signal> +----------- + +- received caught signal + +### attributes ### + +- type: type of signal (e.g. SIGINT) + +### by type ### + +- SIGINT: interactive mode is entered... + +<watch*> +----------- + +- generally emitted on hit watchpoint +- <watchdelete variable="" />: when a variable was unset, the watchpoint is removed too +- <watchhit variable="" />: when ever a watched variable is changed, followed by a <watchdata> container +- <watchdata> may contain + - for watchpoints on variables: + - each of these <watch*> tags conatins a type attribute whose value is either "old" or "new") + - <watchvalue type="" inaccessible="inaccessible" />: old value is inaccessible + - <watchvalue type=""> may contain a <stream> element which indicates the old/new (type attribute) value of the variable + - <watchrefcount type="" refcount="" isref="" />: old/new (type attribute) refcount and isref, both numbers + - isref: if the value is 0, it's not a reference, else it is one + - for watchpoints on arrays: + - <watchsize> inspects size variations of an array (the sum): + - removed: number of elements removed + - added: number of elements added + - <watcharrayptr>: if this tag appears, the internal pointer of the array way changed + +<signalsegv> +--------------- + +- generally emitted when data couldn't be fetched (e.g. by accessing inconsistent data); only used in hard interrupt mode +- it might mean that data couldn't be fetched at all, or that only incomplete data was fetched (e.g. when a fixed number of following attributes are fetched, this tag will mark a stop of fetching if none or not all tags were printed) + + +Variable Dump +============= + +- all except property and element tags have a refstatus attribute, is set to non-empty if it's a reference + +object properties +----------------- + +- wrapped in a property tag <property name="" protection=""> + - name: name of key + - protection: one of these three values: public / protected / private + - class: only present if protection attribute is set to "private", contains the name of the class to which the property belongs +- if the property tag contains any serverity="error" attribute, there was some crucial error to read it, just skip it + +array elements +-------------- +- wrapped in an element tag <property name="" protection=""> + - name: name of key +- if the element tag contains any serverity="error" attribute, there was some crucial error to read it, jsut skip it + +int +--- + +- <int refstatus="" value="" /> + - value is the integer + +float +----- + +- <float refstatus="" value="" /> + - value is the float + +bool +---- + +- <bool refstatus="" value="" /> + -value: true or false + +string +------ + +- <string refstatus="" length="" value="" /> + - length: length or string + - value: the string + +null +---- + +- <null refstatus="" /> + +array +----- + +- <array refstatus="" num=""> + - num: number of elements + - contains <element> tags + +object +------ + +- <object refstatus="" class="" id="" num=""> + - class: name of the class the object is an instance of (may be empty if unknown) + - id: id of the object + - num: number of properties + - contains <property> tags + +resource +-------- + +- <resource refstatus="" id="" type="" /> + - id: resource id + - type: type of resource + +recursion +--------- + +- <recursion /> +- if that tag appears, there's a recursive reference inside the value to be printed diff --git a/zend_mm_structs.h b/zend_mm_structs.h new file mode 100644 index 0000000000..ca64069e0f --- /dev/null +++ b/zend_mm_structs.h @@ -0,0 +1,102 @@ +#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 -- cgit v1.2.1 From e4e39d852a9dac3e2ee8dc46656ffefa41b6ce25 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sat, 25 Oct 2014 18:59:48 +0200 Subject: Merge phpdbg into PHP-5.6 --- phpdbg.c | 15 ++++++--------- phpdbg_frame.c | 7 +++++++ phpdbg_list.c | 9 +++++++++ phpdbg_prompt.c | 27 +++++++++++++++++++++++++++ phpdbg_utils.h | 25 +++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index f09dc4ee13..aaf1e5f406 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -477,15 +477,7 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ case E_USER_ERROR: case E_PARSE: case E_RECOVERABLE_ERROR: - if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { - phpdbg_list_file( - zend_get_executed_filename(TSRMLS_C), - 3, - zend_get_executed_lineno(TSRMLS_C)-1, - zend_get_executed_lineno(TSRMLS_C) - TSRMLS_CC - ); - } + phpdbg_list_file(zend_get_executed_filename(TSRMLS_C), 3, zend_get_executed_lineno(TSRMLS_C)-1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); do { switch (phpdbg_interactive(1 TSRMLS_CC)) { @@ -1532,6 +1524,11 @@ phpdbg_out: efree(SG(request_info).argv); } +#ifndef _WIN32 + /* reset it... else we risk a stack overflow upon next run (when clean'ing) */ + php_stream_stdio_ops.write = PHPDBG_G(php_stdiop_write); +#endif + #ifndef ZTS /* force cleanup of auto and core globals */ zend_hash_clean(CG(auto_globals)); diff --git a/phpdbg_frame.c b/phpdbg_frame.c index df304e3541..437e6d474a 100644 --- a/phpdbg_frame.c +++ b/phpdbg_frame.c @@ -25,6 +25,7 @@ #include "phpdbg_list.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +ZEND_EXTERN_MODULE_GLOBALS(output); void phpdbg_restore_frame(TSRMLS_D) /* {{{ */ { @@ -198,8 +199,12 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ int i = 0, limit = num; int user_defined; + PHPDBG_OUTPUT_BACKUP(); + if (limit < 0) { phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit); + + PHPDBG_OUTPUT_BACKUP_RESTORE(); return; } @@ -242,4 +247,6 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ phpdbg_xml(""); zval_dtor(&zbacktrace); + + PHPDBG_OUTPUT_BACKUP_RESTORE(); } /* }}} */ diff --git a/phpdbg_list.c b/phpdbg_list.c index 80b5d2b189..7aa8c4f9e0 100644 --- a/phpdbg_list.c +++ b/phpdbg_list.c @@ -128,6 +128,11 @@ void phpdbg_list_file(const char *filename, uint count, int offset, uint highlig { uint line, lastline; phpdbg_file_source **data; + char resolved_path_buf[MAXPATHLEN]; + + if (VCWD_REALPATH(filename, resolved_path_buf)) { + filename = resolved_path_buf; + } if (zend_hash_find(&PHPDBG_G(file_sources), filename, strlen(filename), (void **) &data) == FAILURE) { phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file..."); @@ -232,6 +237,7 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) { char *filename = (char *)(file->opened_path ? file->opened_path : file->filename); uint line; char *bufptr, *endptr; + char resolved_path_buf[MAXPATHLEN]; zend_stream_fixup(file, &data.buf, &data.len TSRMLS_CC); @@ -258,6 +264,9 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) { fake.opened_path = file->opened_path; *(dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * data.len)) = data; + if (VCWD_REALPATH(filename, resolved_path_buf)) { + filename = resolved_path_buf; + } zend_hash_add(&PHPDBG_G(file_sources), filename, strlen(filename), &dataptr, sizeof(phpdbg_file_source *), NULL); for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) { diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 82444fbf1d..2e0c698f05 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -42,6 +42,7 @@ #include "phpdbg_eol.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +ZEND_EXTERN_MODULE_GLOBALS(output); #ifdef HAVE_LIBDL #ifdef PHP_WIN32 @@ -689,12 +690,26 @@ PHPDBG_COMMAND(ev) /* {{{ */ zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING) == PHPDBG_IS_STEPPING); zval retval; + zend_op **orig_opline = EG(opline_ptr); + zend_op_array *orig_op_array = EG(active_op_array); + zval **orig_retval_ptr = EG(return_value_ptr_ptr); + zend_execute_data *ex = EG(current_execute_data); + HashTable *original_active_symbol_table = EG(active_symbol_table); + zval *original_This = EG(This); + zend_class_entry *original_scope = EG(scope); + zend_class_entry *original_called_scope = EG(called_scope); + zend_vm_stack original_stack = EG(argument_stack); + + PHPDBG_OUTPUT_BACKUP(); + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { phpdbg_try_access { phpdbg_parse_variable(param->str, param->len, &EG(symbol_table), 0, phpdbg_output_ev_variable, 0 TSRMLS_CC); } phpdbg_catch_access { phpdbg_error("signalsegv", "", "Could not fetch data, invalid data source"); } phpdbg_end_try_access(); + + PHPDBG_OUTPUT_BACKUP_RESTORE(); return SUCCESS; } @@ -716,6 +731,16 @@ PHPDBG_COMMAND(ev) /* {{{ */ phpdbg_out("\n"); zval_dtor(&retval); } + } zend_catch { + EG(active_op_array) = orig_op_array; + EG(opline_ptr) = orig_opline; + EG(return_value_ptr_ptr) = orig_retval_ptr; + EG(current_execute_data) = ex; + EG(active_symbol_table) = original_active_symbol_table; + EG(This) = original_This; + EG(scope) = original_scope; + EG(called_scope) = original_called_scope; + EG(argument_stack) = original_stack; } zend_end_try(); PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; @@ -726,6 +751,8 @@ PHPDBG_COMMAND(ev) /* {{{ */ CG(unclean_shutdown) = 0; + PHPDBG_OUTPUT_BACKUP_RESTORE(); + return SUCCESS; } /* }}} */ diff --git a/phpdbg_utils.h b/phpdbg_utils.h index d657dc79fd..9038aa7457 100644 --- a/phpdbg_utils.h +++ b/phpdbg_utils.h @@ -112,4 +112,29 @@ PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable PHPDBG_API void phpdbg_xml_var_dump(zval **zv TSRMLS_DC); +#ifdef ZTS +#define PHPDBG_OUTPUT_BACKUP_DEFINES() \ + zend_output_globals *output_globals_ptr; \ + zend_output_globals original_output_globals; \ + output_globals_ptr = (zend_output_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)]; +#else +#define PHPDBG_OUTPUT_BACKUP_DEFINES() \ + zend_output_globals *output_globals_ptr; \ + zend_output_globals original_output_globals; \ + output_globals_ptr = &output_globals; +#endif + +#define PHPDBG_OUTPUT_BACKUP_SWAP() \ + original_output_globals = *output_globals_ptr; \ + memset(output_globals_ptr, 0, sizeof(zend_output_globals)); \ + php_output_activate(TSRMLS_C); + +#define PHPDBG_OUTPUT_BACKUP() \ + PHPDBG_OUTPUT_BACKUP_DEFINES() \ + PHPDBG_OUTPUT_BACKUP_SWAP() + +#define PHPDBG_OUTPUT_BACKUP_RESTORE() \ + php_output_deactivate(TSRMLS_C); \ + *output_globals_ptr = original_output_globals; + #endif /* PHPDBG_UTILS_H */ -- cgit v1.2.1 From 2bcc8d83940408c4a0ff8a55cdc30590bf15f663 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 26 Oct 2014 03:50:28 +0100 Subject: Add question to reset execution in run/exec/clean --- phpdbg.c | 44 +++++++++----------- phpdbg.h | 7 ++-- phpdbg_cmd.c | 82 ++++++++++++------------------------- phpdbg_cmd.h | 1 + phpdbg_io.c | 49 ++++++++++++++++++++++ phpdbg_io.h | 2 + phpdbg_prompt.c | 123 +++++++++++++++++++++++++++++++------------------------- 7 files changed, 170 insertions(+), 138 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index aaf1e5f406..ff03c670d0 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -45,6 +45,8 @@ #endif /* }}} */ ZEND_DECLARE_MODULE_GLOBALS(phpdbg); +int phpdbg_startup_run = 0; +char *phpdbg_exec = NULL; static PHP_INI_MH(OnUpdateEol) { @@ -487,7 +489,7 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ case PHPDBG_NEXT: return; } - } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); + } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)); } } else fprintf(stdout, "%s\n", message); @@ -752,7 +754,7 @@ static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */ phpdbg_writeln("intro", "help=\"help\"", "To get help using phpdbg type \"help\" and press enter"); phpdbg_notice("intro", "report=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES); phpdbg_xml(""); - } else { + } else if (phpdbg_startup_run == 0) { if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) { phpdbg_notice(NULL, NULL, "Clean Execution Environment"); } @@ -776,7 +778,7 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */ if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { /* we quit remote consoles on recv SIGINT */ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { - PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; + PHPDBG_G(flags) |= PHPDBG_IS_STOPPING; zend_bailout(); } } else { @@ -961,8 +963,6 @@ int main(int argc, char **argv) /* {{{ */ zend_ulong zend_extensions_len = 0L; zend_bool ini_ignore; char *ini_override; - char *exec; - size_t exec_len; char *init_file; size_t init_file_len; zend_bool init_file_default; @@ -973,7 +973,6 @@ int main(int argc, char **argv) /* {{{ */ int php_optind, opt, show_banner = 1; long cleaning = 0; zend_bool remote = 0; - int run = 0; int step = 0; #ifdef _WIN32 @@ -1046,8 +1045,6 @@ phpdbg_main: ini_override = NULL; zend_extensions = NULL; zend_extensions_len = 0L; - exec = NULL; - exec_len = 0; init_file = NULL; init_file_len = 0; init_file_default = 1; @@ -1057,14 +1054,13 @@ phpdbg_main: php_optarg = NULL; php_optind = 1; opt = 0; - run = 0; step = 0; sapi_name = NULL; while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) { switch (opt) { case 'r': - run++; + phpdbg_startup_run++; break; case 'n': ini_ignore = 1; @@ -1201,14 +1197,12 @@ phpdbg_main: } /* set exec if present on command line */ - if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS)) - { - exec_len = strlen(argv[php_optind]); - if (exec_len) { - if (exec) { - free(exec); + if (!phpdbg_exec && (argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS)) { + if (strlen(argv[php_optind])) { + if (phpdbg_exec) { + free(phpdbg_exec); } - exec = strdup(argv[php_optind]); + phpdbg_exec = strdup(argv[php_optind]); } php_optind++; } @@ -1331,7 +1325,7 @@ phpdbg_main: for (i = SG(request_info).argc; --i;) { SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]); } - SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup(""); + SG(request_info).argv[i] = phpdbg_exec ? estrdup(phpdbg_exec) : estrdup(""); php_hash_environment(TSRMLS_C); } @@ -1394,11 +1388,12 @@ phpdbg_main: php_stream_stdio_ops.write = phpdbg_stdiop_write; #endif - if (exec) { /* set execution context */ - PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); + if (phpdbg_exec) { /* set execution context */ + PHPDBG_G(exec) = phpdbg_resolve_path(phpdbg_exec TSRMLS_CC); PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec)); - free(exec); + free(phpdbg_exec); + phpdbg_exec = NULL; } if (oplog_file) { /* open oplog */ @@ -1448,13 +1443,14 @@ phpdbg_main: PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } - if (run) { + if (phpdbg_startup_run) { /* no need to try{}, run does it ... */ PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); - if (run > 1) { + if (phpdbg_startup_run > 1) { /* if -r is on the command line more than once just quit */ goto phpdbg_out; } + phpdbg_startup_run = 0; } phpdbg_interact: @@ -1494,7 +1490,7 @@ phpdbg_interact: } } } zend_end_try(); - } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); + } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)); /* this must be forced */ CG(unclean_shutdown) = 0; diff --git a/phpdbg.h b/phpdbg.h index 8c0dbb4afa..688ba7cdfc 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -187,9 +187,10 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); #define PHPDBG_IN_SIGNAL_HANDLER (1<<30) -#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_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) #ifndef _WIN32 # define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED) diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index 30ea48cfbe..ab0755454e 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -796,80 +796,30 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { + char buf[PHPDBG_MAX_CMD]; char *cmd = NULL; char *buffer = NULL; - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) { if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) { fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); } if (buffered == NULL) { - if (0) { -disconnect: - PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); - zend_bailout(); - return NULL; - } - #define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)) - /* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */ - /* strongly assuming to be in blocking mode... */ #if USE_LIB_STAR readline: if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) #endif { - char buf[PHPDBG_MAX_CMD]; - int bytes = PHPDBG_G(input_buflen), len = 0; - if (PHPDBG_G(input_buflen)) { - memcpy(buf, PHPDBG_G(input_buffer), bytes); - } - phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C)); - PHPDBG_G(last_was_newline) = 1; - - do { - int i; - if (bytes <= 0) { - continue; - } - - for (i = len; i < len + bytes; i++) { - if (buf[i] == '\x03') { - if (i != len + bytes - 1) { - memmove(buf + i, buf + i + 1, len + bytes - i - 1); - } - len--; - i--; - continue; - } - if (buf[i] == '\n') { - PHPDBG_G(input_buflen) = len + bytes - 1 - i; - if (PHPDBG_G(input_buflen)) { - memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen)); - } - if (i != PHPDBG_MAX_CMD - 1) { - buf[i + 1] = 0; - } - cmd = buf; - goto end; - } - } - len += bytes; - /* XXX export the timeout through INI??*/ - } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0); - - if (bytes <= 0) { - goto disconnect; - } - - cmd = buf; + phpdbg_consume_stdin_line(cmd = buf TSRMLS_CC); } #if USE_LIB_STAR else { cmd = readline(phpdbg_get_prompt(TSRMLS_C)); + PHPDBG_G(last_was_newline) = 1; } if (!cmd) { @@ -883,8 +833,7 @@ readline: } else { cmd = buffered; } -end: - PHPDBG_G(last_was_newline) = 1; + buffer = estrdup(cmd); #if USE_LIB_STAR @@ -922,3 +871,24 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */ { efree(*input); } /* }}} */ + +PHPDBG_API int phpdbg_ask_user_permission(const char *question TSRMLS_DC) { + if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) { + char buf[PHPDBG_MAX_CMD]; + phpdbg_out("%s", question); + phpdbg_out(" (type y or n): "); + + while (1) { + phpdbg_consume_stdin_line(buf TSRMLS_CC); + if (buf[1] == '\n' && (buf[0] == 'y' || buf[0] == 'n')) { + if (buf[0] == 'y') { + return SUCCESS; + } + return FAILURE; + } + phpdbg_out("Please enter either y (yes) or n (no): "); + } + } + + return SUCCESS; +} diff --git a/phpdbg_cmd.h b/phpdbg_cmd.h index 3896551c9a..4c9e5383d8 100644 --- a/phpdbg_cmd.h +++ b/phpdbg_cmd.h @@ -131,6 +131,7 @@ typedef struct { */ PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC); PHPDBG_API void phpdbg_destroy_input(char** TSRMLS_DC); +PHPDBG_API int phpdbg_ask_user_permission(const char *question TSRMLS_DC); /** * Stack Management diff --git a/phpdbg_io.c b/phpdbg_io.c index 97f0356285..a2a5c5969f 100644 --- a/phpdbg_io.c +++ b/phpdbg_io.c @@ -47,6 +47,55 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +/* is easy to generalize ... but not needed for now */ +PHPDBG_API int phpdbg_consume_stdin_line(char *buf TSRMLS_DC) { + int bytes = PHPDBG_G(input_buflen), len = 0; + + if (PHPDBG_G(input_buflen)) { + memcpy(buf, PHPDBG_G(input_buffer), bytes); + } + + PHPDBG_G(last_was_newline) = 1; + + do { + int i; + if (bytes <= 0) { + continue; + } + + for (i = len; i < len + bytes; i++) { + if (buf[i] == '\x03') { + if (i != len + bytes - 1) { + memmove(buf + i, buf + i + 1, len + bytes - i - 1); + } + len--; + i--; + continue; + } + if (buf[i] == '\n') { + PHPDBG_G(input_buflen) = len + bytes - 1 - i; + if (PHPDBG_G(input_buflen)) { + memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen)); + } + if (i != PHPDBG_MAX_CMD - 1) { + buf[i + 1] = 0; + } + return i; + } + } + + len += bytes; + } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0); + + if (bytes <= 0) { + PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED; + zend_bailout(); + return 0; + } + + return bytes; +} + PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC) { int got_now, i = len, j; char *p = ptr; diff --git a/phpdbg_io.h b/phpdbg_io.h index 3ac8f4112d..a5659e88c6 100644 --- a/phpdbg_io.h +++ b/phpdbg_io.h @@ -21,6 +21,8 @@ #include "phpdbg.h" +PHPDBG_API int phpdbg_consume_stdin_line(char *buf TSRMLS_DC); + PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC); PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len); PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC); diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 2e0c698f05..29c75c583c 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -43,6 +43,8 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); ZEND_EXTERN_MODULE_GLOBALS(output); +extern int phpdbg_startup_run; +extern char *phpdbg_exec; #ifdef HAVE_LIBDL #ifdef PHP_WIN32 @@ -355,6 +357,11 @@ PHPDBG_COMMAND(exec) /* {{{ */ size_t res_len = strlen(res); if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { + if (EG(in_execution)) { + if (phpdbg_ask_user_permission("Do you really want to stop execution to set a new execution context?" TSRMLS_CC) == FAILURE) { + return FAILURE; + } + } if (PHPDBG_G(exec)) { phpdbg_notice("exec", "type=\"unset\" context=\"%s\"", "Unsetting old execution context: %s", PHPDBG_G(exec)); @@ -378,9 +385,11 @@ PHPDBG_COMMAND(exec) /* {{{ */ phpdbg_notice("exec", "type=\"set\" context=\"%s\"", "Set execution context: %s", PHPDBG_G(exec)); - if (phpdbg_compile(TSRMLS_C) == FAILURE) { - phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s", PHPDBG_G(exec)); + if (EG(in_execution)) { + phpdbg_clean(1 TSRMLS_CC); } + + phpdbg_compile(TSRMLS_C); } else { phpdbg_notice("exec", "type=\"unchanged\"", "Execution context not changed"); } @@ -399,20 +408,15 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ if (!PHPDBG_G(exec)) { phpdbg_error("inactive", "type=\"nocontext\"", "No execution context"); - return SUCCESS; - } - - if (EG(in_execution)) { - phpdbg_error("inactive", "type=\"isrunning\"", "Cannot compile while in execution"); return FAILURE; } if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC) == SUCCESS) { - PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE TSRMLS_CC); zend_destroy_file_handle(&fh TSRMLS_CC); phpdbg_notice("compile", "context=\"%s\"", "Successful compilation of %s", PHPDBG_G(exec)); + return SUCCESS; } else { phpdbg_error("compile", "type=\"openfailure\" context=\"%s\"", "Could not open file %s", PHPDBG_G(exec)); @@ -570,11 +574,6 @@ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */ PHPDBG_COMMAND(run) /* {{{ */ { - if (EG(in_execution)) { - phpdbg_error("inactive", "type=\"isrunning\"", "Cannot start another execution while one is in progress"); - return SUCCESS; - } - if (PHPDBG_G(ops) || PHPDBG_G(exec)) { zend_op **orig_opline = EG(opline_ptr); zend_op_array *orig_op_array = EG(active_op_array); @@ -582,6 +581,14 @@ PHPDBG_COMMAND(run) /* {{{ */ zend_bool restore = 1; zend_execute_data *ex = EG(current_execute_data); + if (EG(in_execution)) { + if (phpdbg_ask_user_permission("Do you really want to restart execution?" TSRMLS_CC) == SUCCESS) { + phpdbg_startup_run++; + phpdbg_clean(1 TSRMLS_CC); + } + return SUCCESS; + } + if (!PHPDBG_G(ops)) { if (phpdbg_compile(TSRMLS_C) == FAILURE) { phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s, cannot run", PHPDBG_G(exec)); @@ -643,7 +650,7 @@ PHPDBG_COMMAND(run) /* {{{ */ EG(opline_ptr) = orig_opline; EG(return_value_ptr_ptr) = orig_retval_ptr; - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) { phpdbg_error("stop", "type=\"bailout\"", "Caught exit/error from VM"); restore = 0; } @@ -1127,7 +1134,7 @@ PHPDBG_COMMAND(register) /* {{{ */ PHPDBG_COMMAND(quit) /* {{{ */ { /* don't allow this to loop, ever ... */ - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) { PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; zend_bailout(); } @@ -1138,8 +1145,9 @@ PHPDBG_COMMAND(quit) /* {{{ */ PHPDBG_COMMAND(clean) /* {{{ */ { if (EG(in_execution)) { - phpdbg_error("inactive", "type=\"isrunning\"", "Cannot clean environment while executing"); - return SUCCESS; + if (phpdbg_ask_user_permission("Do you really want to clean your current environment?" TSRMLS_CC) == FAILURE) { + return SUCCESS; + } } phpdbg_out("Cleaning Execution Environment\n"); @@ -1227,60 +1235,64 @@ int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */ PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE; - input = phpdbg_read_input(NULL TSRMLS_CC); + while (1) { + if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) { + zend_bailout(); + } - if (input) { - do { - phpdbg_init_param(&stack, STACK_PARAM); + if (!(input = phpdbg_read_input(NULL TSRMLS_CC))) { + break; + } - if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { - phpdbg_activate_err_buf(1 TSRMLS_CC); + + phpdbg_init_param(&stack, STACK_PARAM); + + if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { + phpdbg_activate_err_buf(1 TSRMLS_CC); #ifdef PHP_WIN32 #define PARA ((phpdbg_param_t *)stack.next)->type - if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { - sigio_watcher_start(); - } + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { + sigio_watcher_start(); + } #endif - switch (ret = phpdbg_stack_execute(&stack, allow_async_unsafe TSRMLS_CC)) { - case FAILURE: - if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (!allow_async_unsafe || phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { - phpdbg_output_err_buf(NULL, "%b", "%b" TSRMLS_CC); - } + switch (ret = phpdbg_stack_execute(&stack, allow_async_unsafe TSRMLS_CC)) { + case FAILURE: + if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) { + if (!allow_async_unsafe || phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + phpdbg_output_err_buf(NULL, "%b", "%b" TSRMLS_CC); } - break; + } + break; - case PHPDBG_LEAVE: - case PHPDBG_FINISH: - case PHPDBG_UNTIL: - case PHPDBG_NEXT: { - phpdbg_activate_err_buf(0 TSRMLS_CC); - phpdbg_free_err_buf(TSRMLS_C); - if (!EG(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - phpdbg_error("command", "type=\"noexec\"", "Not running"); - } - goto out; + case PHPDBG_LEAVE: + case PHPDBG_FINISH: + case PHPDBG_UNTIL: + case PHPDBG_NEXT: { + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); + if (!EG(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) { + phpdbg_error("command", "type=\"noexec\"", "Not running"); } + break; } + } - phpdbg_activate_err_buf(0 TSRMLS_CC); - phpdbg_free_err_buf(TSRMLS_C); + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); #ifdef PHP_WIN32 - if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { - sigio_watcher_stop(); - } + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { + sigio_watcher_stop(); + } #undef PARA #endif - } + } - phpdbg_stack_free(&stack); - phpdbg_destroy_input(&input TSRMLS_CC); - PHPDBG_G(req_id) = 0; - } while ((input = phpdbg_read_input(NULL TSRMLS_CC))); + phpdbg_stack_free(&stack); + phpdbg_destroy_input(&input TSRMLS_CC); + PHPDBG_G(req_id) = 0; } -out: if (input) { phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); @@ -1308,6 +1320,7 @@ void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */ } if (full) { + phpdbg_exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */ PHPDBG_G(flags) |= PHPDBG_IS_CLEANING; zend_bailout(); @@ -1593,7 +1606,7 @@ void phpdbg_force_interruption(TSRMLS_D) { next: PHPDBG_G(flags) &= ~PHPDBG_IN_SIGNAL_HANDLER; - if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) { zend_bailout(); } } -- cgit v1.2.1 From fa3a01374d30a9efb6d455ba952aea2187254420 Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 26 Oct 2014 07:08:29 +0000 Subject: disable output buffering by default --- phpdbg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpdbg.c b/phpdbg.c index ff03c670d0..f8879d77ab 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -730,7 +730,8 @@ const char phpdbg_ini_hardcoded[] = "log_errors=On\n" "max_execution_time=0\n" "max_input_time=-1\n" -"error_log=\n\0"; +"error_log=\n" +"output_buffering=off\0"; /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */ #define INI_DEFAULT(name, value) \ -- cgit v1.2.1 From de656f8a49ee0e8cd67812bac579747df9de98fa Mon Sep 17 00:00:00 2001 From: krakjoe Date: Sun, 26 Oct 2014 07:24:35 +0000 Subject: remove dodgy param parser, bring userland breakpoint api inline with PHP7 --- phpdbg.c | 85 +++++++++--- phpdbg_cmd.c | 73 ----------- phpdbg_cmd.h | 1 - phpdbg_parser.c | 396 ++++++++++++++++++++++++++------------------------------ phpdbg_parser.h | 39 ++++-- 5 files changed, 278 insertions(+), 316 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index f8879d77ab..493d8ec20c 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -301,24 +301,12 @@ static PHP_FUNCTION(phpdbg_exec) } } /* }}} */ -/* {{{ proto void phpdbg_break([integer type, string expression]) +/* {{{ proto void phpdbg_break_next() instructs phpdbg to insert a breakpoint at the next opcode */ -static PHP_FUNCTION(phpdbg_break) +static PHP_FUNCTION(phpdbg_break_next) { - if (ZEND_NUM_ARGS() > 0) { - long type = 0; - char *expr = NULL; - int expr_len = 0; - phpdbg_param_t param; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &type, &expr, &expr_len) == FAILURE) { - return; - } - - phpdbg_parse_param(expr, expr_len, ¶m TSRMLS_CC); - phpdbg_do_break(¶m TSRMLS_CC); - phpdbg_clear_param(¶m TSRMLS_CC); - + if (zend_parse_parameters_none() != SUCCESS) { + return; } else if (EG(current_execute_data) && EG(active_op_array)) { zend_ulong opline_num = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); @@ -328,6 +316,48 @@ static PHP_FUNCTION(phpdbg_break) } } /* }}} */ +/* {{{ proto void phpdbg_break_file(string file, integer line) */ +static PHP_FUNCTION(phpdbg_break_file) +{ + char *file = NULL; + int flen = 0; + long line; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &file, &flen, &line) == FAILURE) { + return; + } + + phpdbg_set_breakpoint_file(file, line TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void phpdbg_break_method(string class, string method) */ +static PHP_FUNCTION(phpdbg_break_method) +{ + char *class = NULL, + *method = NULL; + int clen = 0, + mlen = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &class, &clen, &method, &mlen) == FAILURE) { + return; + } + + phpdbg_set_breakpoint_method(class, method TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void phpdbg_break_function(string function) */ +static PHP_FUNCTION(phpdbg_break_function) +{ + char *function = NULL; + int function_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &function, &function_len) == FAILURE) { + return; + } + + phpdbg_set_breakpoint_symbol(function, function_len TSRMLS_CC); +} /* }}} */ + /* {{{ proto void phpdbg_clear(void) instructs phpdbg to clear breakpoints */ static PHP_FUNCTION(phpdbg_clear) @@ -377,9 +407,21 @@ static PHP_FUNCTION(phpdbg_prompt) phpdbg_set_prompt(prompt TSRMLS_CC); } /* }}} */ -ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_arginfo, 0, 0, 0) - ZEND_ARG_INFO(0, type) - ZEND_ARG_INFO(0, expression) +ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_file_arginfo, 0, 0, 2) + ZEND_ARG_INFO(0, file) + ZEND_ARG_INFO(0, line) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_method_arginfo, 0, 0, 2) + ZEND_ARG_INFO(0, class) + ZEND_ARG_INFO(0, method) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_function_arginfo, 0, 0, 1) + ZEND_ARG_INFO(0, function) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0) @@ -400,7 +442,10 @@ ZEND_END_ARG_INFO() zend_function_entry phpdbg_user_functions[] = { PHP_FE(phpdbg_clear, phpdbg_clear_arginfo) - PHP_FE(phpdbg_break, phpdbg_break_arginfo) + PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo) + PHP_FE(phpdbg_break_file, phpdbg_break_file_arginfo) + PHP_FE(phpdbg_break_method, phpdbg_break_method_arginfo) + PHP_FE(phpdbg_break_function, phpdbg_break_function_arginfo) PHP_FE(phpdbg_exec, phpdbg_exec_arginfo) PHP_FE(phpdbg_color, phpdbg_color_arginfo) PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo) diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index ab0755454e..13d5a0d634 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -70,79 +70,6 @@ PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_ } } -PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char *str, size_t len, phpdbg_param_t *param TSRMLS_DC) /* {{{ */ -{ - char *class_name, *func_name; - - if (len == 0) { - param->type = EMPTY_PARAM; - goto parsed; - } - - if (phpdbg_is_addr(str)) { - param->addr = strtoul(str, 0, 16); - param->type = ADDR_PARAM; - goto parsed; - - } else if (phpdbg_is_numeric(str)) { - param->num = strtol(str, NULL, 0); - param->type = NUMERIC_PARAM; - goto parsed; - - } else if (phpdbg_is_class_method(str, len+1, &class_name, &func_name)) { - param->method.class = class_name; - param->method.name = func_name; - param->type = METHOD_PARAM; - goto parsed; - } else { - char *line_pos = strrchr(str, ':'); - - if (line_pos && phpdbg_is_numeric(line_pos+1)) { - if (strchr(str, ':') == line_pos) { - char path[MAXPATHLEN]; - - memcpy(path, str, line_pos - str); - path[line_pos - str] = 0; - *line_pos = 0; - param->file.name = phpdbg_resolve_path(path TSRMLS_CC); - param->file.line = strtol(line_pos+1, NULL, 0); - param->type = FILE_PARAM; - - goto parsed; - } - } - - line_pos = strrchr(str, '#'); - - if (line_pos && phpdbg_is_numeric(line_pos+1)) { - if (strchr(str, '#') == line_pos) { - param->num = strtol(line_pos + 1, NULL, 0); - - if (phpdbg_is_class_method(str, line_pos - str, &class_name, &func_name)) { - param->method.class = class_name; - param->method.name = func_name; - param->type = NUMERIC_METHOD_PARAM; - } else { - param->len = line_pos - str; - param->str = estrndup(str, param->len); - param->type = NUMERIC_FUNCTION_PARAM; - } - - goto parsed; - } - } - } - - param->str = estrndup(str, len); - param->len = len; - param->type = STR_PARAM; - -parsed: - phpdbg_debug("phpdbg_parse_param(\"%s\", %lu): %s", - str, len, phpdbg_get_param_type(param TSRMLS_CC)); - return param->type; -} /* }}} */ - PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param TSRMLS_DC) /* {{{ */ { if (param) { diff --git a/phpdbg_cmd.h b/phpdbg_cmd.h index 4c9e5383d8..a79641c080 100644 --- a/phpdbg_cmd.h +++ b/phpdbg_cmd.h @@ -145,7 +145,6 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack); /* * Parameter Management */ -PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char*, size_t, phpdbg_param_t* TSRMLS_DC); PHPDBG_API void phpdbg_clear_param(phpdbg_param_t* TSRMLS_DC); PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t*, phpdbg_param_t* TSRMLS_DC); PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *, const phpdbg_param_t * TSRMLS_DC); diff --git a/phpdbg_parser.c b/phpdbg_parser.c index c766868369..433423db87 100644 --- a/phpdbg_parser.c +++ b/phpdbg_parser.c @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.7. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.5" +#define YYBISON_VERSION "2.7" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -58,8 +58,6 @@ /* Pull parsers. */ #define YYPULL 1 -/* Using locations. */ -#define YYLSP_NEEDED 0 /* Substitute the variable and function names. */ #define yyparse phpdbg_parse @@ -70,11 +68,9 @@ #define yydebug phpdbg_debug #define yynerrs phpdbg_nerrs - /* Copy the first part of user declarations. */ - -/* Line 268 of yacc.c */ -#line 1 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 371 of yacc.c */ +#line 1 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" /* @@ -101,14 +97,16 @@ static int yyerror(void ***tsrm_ls, const char *msg); ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +/* Line 371 of yacc.c */ +#line 102 "sapi/phpdbg/phpdbg_parser.c" -/* Line 268 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 @@ -118,15 +116,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 288 of yacc.c */ -#line 31 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 387 of yacc.c */ +#line 31 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -135,9 +138,8 @@ typedef void* yyscan_t; #endif - -/* Line 288 of yacc.c */ -#line 141 "sapi/phpdbg/phpdbg_parser.c" +/* Line 387 of yacc.c */ +#line 143 "sapi/phpdbg/phpdbg_parser.c" /* Tokens. */ #ifndef YYTOKENTYPE @@ -189,7 +191,6 @@ typedef void* yyscan_t; - #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef int YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 @@ -198,11 +199,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 *tsrm_ls); +#else +int phpdbg_parse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */ +/* Copy the second part of user declarations. */ -/* Line 343 of yacc.c */ -#line 206 "sapi/phpdbg/phpdbg_parser.c" +/* Line 390 of yacc.c */ +#line 222 "sapi/phpdbg/phpdbg_parser.c" #ifdef short # undef short @@ -255,24 +271,24 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* 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 /* 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) @@ -308,6 +324,7 @@ YYID (yyi) # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif @@ -399,20 +416,20 @@ union yyalloc #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from FROM to TO. The source and destination do +/* Copy COUNT objects from SRC to DST. 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))) +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ while (YYID (0)) # endif # endif @@ -505,7 +522,7 @@ static const yytype_uint8 yyrline[] = }; #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[] = @@ -519,7 +536,7 @@ static const char *const yytname[] = "\"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 + "req_id", "full_expression", YY_NULL }; #endif @@ -599,10 +616,10 @@ static const yytype_uint8 yytable[] = 32, 36, 39, 40, 0, 0, 41, 42, 27 }; -#define yypact_value_is_default(yystate) \ - ((yystate) == (-16)) +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-16))) -#define yytable_value_is_error(yytable_value) \ +#define yytable_value_is_error(Yytable_value) \ YYID (0) static const yytype_int8 yycheck[] = @@ -652,62 +669,35 @@ static const yytype_uint8 yystos[] = #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - 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 (tsrm_ls, 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 - - /* This macro is provided for backward compatibility. */ - #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ - #ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, YYLEX_PARAM) #else @@ -758,6 +748,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, tsrm_ls) void *tsrm_ls; #endif { + FILE *yyo = yyoutput; + YYUSE (yyo); if (!yyvaluep) return; YYUSE (tsrm_ls); @@ -770,7 +762,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, tsrm_ls) switch (yytype) { default: - break; + break; } } @@ -1012,12 +1004,11 @@ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ - const char *yyformat = 0; + 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 @@ -1077,11 +1068,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, break; } yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } } } } @@ -1101,10 +1094,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, # undef YYCASE_ } - yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } if (*yymsg_alloc < yysize) { @@ -1166,25 +1161,11 @@ yydestruct (yymsg, yytype, yyvaluep, tsrm_ls) { default: - break; + break; } } -/* 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 *tsrm_ls); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ /*----------. @@ -1216,8 +1197,31 @@ yyparse (tsrm_ls) /* The lookahead symbol. */ int yychar; + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +static YYSTYPE yyval_default; +# define YY_INITIAL_VALUE(Value) = Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + /* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; +YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); /* Number of syntax errors so far. */ int yynerrs; @@ -1230,7 +1234,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. */ @@ -1248,7 +1252,7 @@ YYSTYPE yylval; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ - int yytoken; + int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; @@ -1266,9 +1270,8 @@ YYSTYPE yylval; Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); @@ -1277,14 +1280,6 @@ YYSTYPE yylval; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - yyssp = yyss; - yyvsp = yyvs; - goto yysetstate; /*------------------------------------------------------------. @@ -1425,7 +1420,9 @@ yybackup: yychar = YYEMPTY; yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; @@ -1462,37 +1459,32 @@ yyreduce: switch (yyn) { case 3: - -/* Line 1806 of yacc.c */ -#line 68 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 68 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 5: - -/* Line 1806 of yacc.c */ -#line 73 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 73 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 6: - -/* Line 1806 of yacc.c */ -#line 74 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 74 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); } break; case 7: - -/* Line 1806 of yacc.c */ -#line 75 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 75 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (2)]); } break; case 8: - -/* Line 1806 of yacc.c */ -#line 79 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 79 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; (yyval).file.name = (yyvsp[(2) - (3)]).str; @@ -1501,9 +1493,8 @@ yyreduce: break; case 9: - -/* Line 1806 of yacc.c */ -#line 84 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 84 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; (yyval).file.name = (yyvsp[(1) - (4)]).str; @@ -1512,9 +1503,8 @@ yyreduce: break; case 10: - -/* Line 1806 of yacc.c */ -#line 89 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 89 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; (yyval).file.name = malloc((yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len + 1); @@ -1528,9 +1518,8 @@ yyreduce: break; case 11: - -/* Line 1806 of yacc.c */ -#line 99 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 99 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; (yyval).file.name = malloc((yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len + 1); @@ -1544,9 +1533,8 @@ yyreduce: break; case 12: - -/* Line 1806 of yacc.c */ -#line 109 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 109 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (3)]).str; @@ -1555,9 +1543,8 @@ yyreduce: break; case 13: - -/* Line 1806 of yacc.c */ -#line 114 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 114 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (5)]).str; @@ -1567,9 +1554,8 @@ yyreduce: break; case 14: - -/* Line 1806 of yacc.c */ -#line 120 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 120 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FUNCTION_PARAM; (yyval).str = (yyvsp[(1) - (3)]).str; @@ -1579,9 +1565,8 @@ yyreduce: break; case 15: - -/* Line 1806 of yacc.c */ -#line 126 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 126 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = COND_PARAM; (yyval).str = (yyvsp[(2) - (2)]).str; @@ -1590,65 +1575,56 @@ yyreduce: break; case 16: - -/* Line 1806 of yacc.c */ -#line 131 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 131 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 17: - -/* Line 1806 of yacc.c */ -#line 132 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 132 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 18: - -/* Line 1806 of yacc.c */ -#line 133 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 133 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 19: - -/* Line 1806 of yacc.c */ -#line 134 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 134 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 20: - -/* Line 1806 of yacc.c */ -#line 135 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 135 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 21: - -/* Line 1806 of yacc.c */ -#line 136 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 136 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 22: - -/* Line 1806 of yacc.c */ -#line 137 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 137 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 23: - -/* Line 1806 of yacc.c */ -#line 141 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 141 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { PHPDBG_G(req_id) = (yyvsp[(1) - (1)]).num; } break; case 25: - -/* Line 1806 of yacc.c */ -#line 146 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 146 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = EVAL_PARAM; (yyval).str = (yyvsp[(3) - (3)]).str; @@ -1657,9 +1633,8 @@ yyreduce: break; case 26: - -/* Line 1806 of yacc.c */ -#line 151 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 151 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = SHELL_PARAM; (yyval).str = (yyvsp[(3) - (3)]).str; @@ -1668,9 +1643,8 @@ yyreduce: break; case 27: - -/* Line 1806 of yacc.c */ -#line 156 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 156 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = RUN_PARAM; (yyval).len = 0; @@ -1678,9 +1652,8 @@ yyreduce: break; case 28: - -/* Line 1806 of yacc.c */ -#line 160 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 1792 of yacc.c */ +#line 160 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = RUN_PARAM; (yyval).str = (yyvsp[(3) - (3)]).str; @@ -1689,9 +1662,8 @@ yyreduce: break; - -/* Line 1806 of yacc.c */ -#line 1695 "sapi/phpdbg/phpdbg_parser.c" +/* Line 1792 of yacc.c */ +#line 1667 "sapi/phpdbg/phpdbg_parser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1854,7 +1826,9 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ @@ -1878,7 +1852,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -1920,9 +1894,8 @@ yyreturn: } - -/* Line 2067 of yacc.c */ -#line 167 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 2055 of yacc.c */ +#line 167 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" static int yyerror(void ***tsrm_ls, const char *msg) { @@ -1948,4 +1921,3 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) { return yyparse(NULL); #endif } - diff --git a/phpdbg_parser.h b/phpdbg_parser.h index dfa155d718..4cd8ed6d00 100644 --- a/phpdbg_parser.h +++ b/phpdbg_parser.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.7. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,10 +30,18 @@ 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 2068 of yacc.c */ -#line 31 "/root/php-src-xml-data-phpdbg/sapi/phpdbg/phpdbg_parser.y" +/* Line 2058 of yacc.c */ +#line 31 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -42,9 +50,8 @@ typedef void* yyscan_t; #endif - -/* Line 2068 of yacc.c */ -#line 48 "sapi/phpdbg/phpdbg_parser.h" +/* Line 2058 of yacc.c */ +#line 55 "sapi/phpdbg/phpdbg_parser.h" /* Tokens. */ #ifndef YYTOKENTYPE @@ -96,7 +103,6 @@ typedef void* yyscan_t; - #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef int YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 @@ -105,5 +111,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 *tsrm_ls); +#else +int phpdbg_parse (); +#endif +#endif /* ! YYPARSE_PARAM */ - +#endif /* !YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */ -- cgit v1.2.1 From af9c6afa6f3465ae5b287af298fb148792f83d06 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 26 Oct 2014 10:48:45 +0100 Subject: Fix nullptr dereference in clean without exec context --- phpdbg_prompt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 29c75c583c..eca4c6ac2b 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -1320,7 +1320,10 @@ void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */ } if (full) { - phpdbg_exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */ + if (PHPDBG_G(exec)) { + phpdbg_exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */ + } + PHPDBG_G(flags) |= PHPDBG_IS_CLEANING; zend_bailout(); -- cgit v1.2.1 From 510676fbbf6391b3f1931e99c2c043db79d3326d Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 26 Oct 2014 20:43:49 +0100 Subject: Stabilize execution, always run destructors and extended file breakpoints --- phpdbg.c | 104 +++++++++++++++++++++++++++++---------- phpdbg.h | 92 ++++++++++++++++------------------- phpdbg_bp.c | 148 ++++++++++++++++++++++++++++++++++++++++++++------------ phpdbg_bp.h | 26 +++++----- phpdbg_cmd.c | 2 +- phpdbg_list.c | 2 + phpdbg_out.c | 2 + phpdbg_prompt.c | 21 ++++---- 8 files changed, 268 insertions(+), 129 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index 493d8ec20c..3e31f76898 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -46,7 +46,6 @@ ZEND_DECLARE_MODULE_GLOBALS(phpdbg); int phpdbg_startup_run = 0; -char *phpdbg_exec = NULL; static PHP_INI_MH(OnUpdateEol) { @@ -186,7 +185,8 @@ static void php_phpdbg_destroy_registered(void *data) /* {{{ */ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */ { - zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0); + zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], 8, NULL, php_phpdbg_destroy_bp_file, 0); zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0); zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0); zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0); @@ -216,8 +216,8 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]); zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]); zend_hash_destroy(&PHPDBG_G(seek)); - zend_hash_destroy(&PHPDBG_G(registered)); zend_hash_destroy(&PHPDBG_G(file_sources)); + zend_hash_destroy(&PHPDBG_G(registered)); zend_hash_destroy(&PHPDBG_G(watchpoints)); zend_llist_destroy(&PHPDBG_G(watchlist_mem)); @@ -363,6 +363,7 @@ static PHP_FUNCTION(phpdbg_break_function) static PHP_FUNCTION(phpdbg_clear) { zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]); @@ -543,11 +544,27 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */ { + if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) { + zend_phpdbg_globals *pg = PHPDBG_G(backup) = calloc(1, sizeof(zend_phpdbg_globals)); + + php_phpdbg_globals_ctor(pg); + + pg->exec = 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]; + memset(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; } /* }}} */ @@ -1009,6 +1026,7 @@ int main(int argc, char **argv) /* {{{ */ zend_ulong zend_extensions_len = 0L; zend_bool ini_ignore; char *ini_override; + char *exec = NULL; char *init_file; size_t init_file_len; zend_bool init_file_default; @@ -1020,6 +1038,7 @@ int main(int argc, char **argv) /* {{{ */ long cleaning = 0; zend_bool remote = 0; int step = 0; + zend_phpdbg_globals *settings = NULL; #ifdef _WIN32 char *bp_tmp_file = NULL; @@ -1102,6 +1121,9 @@ phpdbg_main: opt = 0; step = 0; sapi_name = NULL; + if (settings) { + exec = settings->exec; + } while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) { switch (opt) { @@ -1243,12 +1265,12 @@ phpdbg_main: } /* set exec if present on command line */ - if (!phpdbg_exec && (argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS)) { + if (!exec && (argc > php_optind) && (strcmp(argv[php_optind-1], "--") != SUCCESS)) { if (strlen(argv[php_optind])) { - if (phpdbg_exec) { - free(phpdbg_exec); + if (exec) { + free(exec); } - phpdbg_exec = strdup(argv[php_optind]); + exec = strdup(argv[php_optind]); } php_optind++; } @@ -1309,20 +1331,31 @@ phpdbg_main: #endif zend_mm_heap *mm_heap; - /* setup remote server if necessary */ - if (!cleaning && listen > 0) { - server = phpdbg_open_socket(address, listen TSRMLS_CC); - if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) { - exit(0); + /* set flags from command line */ + PHPDBG_G(flags) = flags; + + if (settings) { +#ifdef ZTS + *((zend_phpdbg_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings; +#else + phpdbg_globals = *settings; +#endif } + /* setup remote server if necessary */ + if (!cleaning && listen > 0) { + server = phpdbg_open_socket(address, listen TSRMLS_CC); + if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) { + exit(0); + } + #ifndef _WIN32 - sigaction(SIGIO, &sigio_struct, NULL); + sigaction(SIGIO, &sigio_struct, NULL); #endif - /* set remote flag to stop service shutting down upon quit */ - remote = 1; - } + /* set remote flag to stop service shutting down upon quit */ + remote = 1; + } mm_heap = phpdbg_mm_get_heap(); @@ -1371,7 +1404,7 @@ phpdbg_main: for (i = SG(request_info).argc; --i;) { SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]); } - SG(request_info).argv[i] = phpdbg_exec ? estrdup(phpdbg_exec) : estrdup(""); + SG(request_info).argv[i] = exec ? estrdup(exec) : estrdup(""); php_hash_environment(TSRMLS_C); } @@ -1392,9 +1425,6 @@ phpdbg_main: PG(modules_activated) = 0; - /* set flags from command line */ - PHPDBG_G(flags) = flags; - /* setup io here */ if (remote) { PHPDBG_G(flags) |= PHPDBG_IS_REMOTE; @@ -1434,12 +1464,12 @@ phpdbg_main: php_stream_stdio_ops.write = phpdbg_stdiop_write; #endif - if (phpdbg_exec) { /* set execution context */ - PHPDBG_G(exec) = phpdbg_resolve_path(phpdbg_exec TSRMLS_CC); + if (exec) { /* set execution context */ + PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec)); - free(phpdbg_exec); - phpdbg_exec = NULL; + free(exec); + exec = NULL; } if (oplog_file) { /* open oplog */ @@ -1537,7 +1567,12 @@ phpdbg_interact: } } zend_end_try(); } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)); - + + + if (PHPDBG_G(exec) && (PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { + exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */ + } + /* this must be forced */ CG(unclean_shutdown) = 0; @@ -1590,7 +1625,24 @@ phpdbg_out: /* this is just helpful */ PG(report_memleaks) = 0; - php_request_shutdown((void*)0); + if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) { + php_free_shutdown_functions(TSRMLS_C); + zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC); + } + + /* sapi_module.deactivate is where to backup things, last chance before mm_shutdown... */ + + zend_try { + php_request_shutdown(NULL); + } zend_end_try(); + + if ((PHPDBG_G(flags) & (PHPDBG_IS_QUITTING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_RUNNING) { + phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); + } + + if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) { + settings = PHPDBG_G(backup); + } php_output_deactivate(TSRMLS_C); diff --git a/phpdbg.h b/phpdbg.h index 688ba7cdfc..57ea7ee570 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -116,6 +116,7 @@ #include "phpdbg_utils.h" #include "phpdbg_btree.h" #include "phpdbg_watch.h" +#include "phpdbg_bp.h" #ifdef PHP_WIN32 # include "phpdbg_sigio_win32.h" #endif @@ -131,71 +132,62 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE */ -/* {{{ tables */ -#define PHPDBG_BREAK_FILE 0 -#define PHPDBG_BREAK_SYM 1 -#define PHPDBG_BREAK_OPLINE 2 -#define PHPDBG_BREAK_METHOD 3 -#define PHPDBG_BREAK_COND 4 -#define PHPDBG_BREAK_OPCODE 5 -#define PHPDBG_BREAK_FUNCTION_OPLINE 6 -#define PHPDBG_BREAK_METHOD_OPLINE 7 -#define PHPDBG_BREAK_FILE_OPLINE 8 -#define PHPDBG_BREAK_MAP 9 -#define PHPDBG_BREAK_TABLES 10 /* }}} */ - /* {{{ flags */ -#define PHPDBG_HAS_FILE_BP (1<<1) -#define PHPDBG_HAS_SYM_BP (1<<2) -#define PHPDBG_HAS_OPLINE_BP (1<<3) -#define PHPDBG_HAS_METHOD_BP (1<<4) -#define PHPDBG_HAS_COND_BP (1<<5) -#define PHPDBG_HAS_OPCODE_BP (1<<6) -#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1<<7) -#define PHPDBG_HAS_METHOD_OPLINE_BP (1<<8) -#define PHPDBG_HAS_FILE_OPLINE_BP (1<<9) /* }}} */ +#define PHPDBG_HAS_FILE_BP (1ULL<<1) +#define PHPDBG_HAS_PENDING_FILE_BP (1ULL<<2) +#define PHPDBG_HAS_SYM_BP (1ULL<<3) +#define PHPDBG_HAS_OPLINE_BP (1ULL<<4) +#define PHPDBG_HAS_METHOD_BP (1ULL<<5) +#define PHPDBG_HAS_COND_BP (1ULL<<6) +#define PHPDBG_HAS_OPCODE_BP (1ULL<<7) +#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1ULL<<8) +#define PHPDBG_HAS_METHOD_OPLINE_BP (1ULL<<9) +#define PHPDBG_HAS_FILE_OPLINE_BP (1ULL<<10) /* }}} */ /* END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE */ -#define PHPDBG_IN_COND_BP (1<<10) -#define PHPDBG_IN_EVAL (1<<11) +#define PHPDBG_IN_COND_BP (1ULL<<11) +#define PHPDBG_IN_EVAL (1ULL<<12) -#define PHPDBG_IS_STEPPING (1<<12) -#define PHPDBG_STEP_OPCODE (1<<13) -#define PHPDBG_IS_QUIET (1<<14) -#define PHPDBG_IS_QUITTING (1<<15) -#define PHPDBG_IS_COLOURED (1<<16) -#define PHPDBG_IS_CLEANING (1<<17) +#define PHPDBG_IS_STEPPING (1ULL<<13) +#define PHPDBG_STEP_OPCODE (1ULL<<14) +#define PHPDBG_IS_QUIET (1ULL<<15) +#define PHPDBG_IS_QUITTING (1ULL<<16) +#define PHPDBG_IS_COLOURED (1ULL<<17) +#define PHPDBG_IS_CLEANING (1ULL<<18) +#define PHPDBG_IS_RUNNING (1ULL<<19) -#define PHPDBG_IN_UNTIL (1<<18) -#define PHPDBG_IN_FINISH (1<<19) -#define PHPDBG_IN_LEAVE (1<<20) +#define PHPDBG_IN_UNTIL (1ULL<<20) +#define PHPDBG_IN_FINISH (1ULL<<21) +#define PHPDBG_IN_LEAVE (1ULL<<22) -#define PHPDBG_IS_REGISTERED (1<<21) -#define PHPDBG_IS_STEPONEVAL (1<<22) -#define PHPDBG_IS_INITIALIZING (1<<23) -#define PHPDBG_IS_SIGNALED (1<<24) -#define PHPDBG_IS_INTERACTIVE (1<<25) -#define PHPDBG_IS_BP_ENABLED (1<<26) -#define PHPDBG_IS_REMOTE (1<<27) -#define PHPDBG_IS_DISCONNECTED (1<<28) -#define PHPDBG_WRITE_XML (1<<29) +#define PHPDBG_IS_REGISTERED (1ULL<<23) +#define PHPDBG_IS_STEPONEVAL (1ULL<<24) +#define PHPDBG_IS_INITIALIZING (1ULL<<25) +#define PHPDBG_IS_SIGNALED (1ULL<<26) +#define PHPDBG_IS_INTERACTIVE (1ULL<<27) +#define PHPDBG_IS_BP_ENABLED (1ULL<<28) +#define PHPDBG_IS_REMOTE (1ULL<<29) +#define PHPDBG_IS_DISCONNECTED (1ULL<<30) +#define PHPDBG_WRITE_XML (1ULL<<31) -#define PHPDBG_SHOW_REFCOUNTS (1<<30) +#define PHPDBG_SHOW_REFCOUNTS (1ULL<<32) -#define PHPDBG_IN_SIGNAL_HANDLER (1<<30) +#define PHPDBG_IN_SIGNAL_HANDLER (1ULL<<33) #define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL | PHPDBG_IN_FINISH | PHPDBG_IN_LEAVE) #define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP) #define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP | PHPDBG_HAS_SYM_BP | PHPDBG_HAS_METHOD_BP | PHPDBG_HAS_OPLINE_BP | PHPDBG_HAS_COND_BP | PHPDBG_HAS_OPCODE_BP | PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP) #define PHPDBG_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) + #ifndef _WIN32 -# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED) +# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED) #else -# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED) +# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_BP_ENABLED) #endif /* }}} */ /* {{{ output descriptors */ @@ -256,6 +248,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) FILE *ptr; int fd; } io[PHPDBG_IO_FDS]; /* io */ + int eol; /* type of line ending to use */ size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC); int in_script_xml; /* in output mode */ struct { @@ -281,17 +274,18 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) JMP_BUF *sigsegv_bailout; /* bailout address for accesibility probing */ - zend_ulong flags; /* phpdbg flags */ + uint64_t flags; /* phpdbg flags */ char *socket_path; /* phpdbg.path ini setting */ char *sapi_name_ptr; /* store sapi name to free it if necessary to not leak memory */ int socket_fd; /* file descriptor to socket (wait command) (-1 if unused) */ int socket_server_fd; /* file descriptor to master socket (wait command) (-1 if unused) */ #ifdef PHP_WIN32 - HANDLE sigio_watcher_thread; /* sigio watcher thread handle */ + HANDLE sigio_watcher_thread; /* sigio watcher thread handle */ struct win32_sigio_watcher_data swd; #endif - int8_t eol; + + struct _zend_phpdbg_globals *backup; /* backup of data to store */ ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ #endif diff --git a/phpdbg_bp.c b/phpdbg_bp.c index 81674a0daf..9333b353ce 100644 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@ -220,51 +220,119 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML { php_stream_statbuf ssb; char realpath[MAXPATHLEN]; + const char *original_path = path; + zend_bool pending; - if (php_stream_stat_path(path, &ssb) != FAILURE) { - if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) { - HashTable *broken; - phpdbg_breakfile_t new_break; - size_t path_len = 0L; + HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE]; + phpdbg_breakfile_t new_break; + size_t path_len = 0L; - if (VCWD_REALPATH(path, realpath)) { - path = realpath; + if (VCWD_REALPATH(path, realpath)) { + path = realpath; + } + path_len = strlen(path); + + if (!zend_hash_exists(&PHPDBG_G(file_sources), path, path_len)) { + if (php_stream_stat_path(path, &ssb) == FAILURE) { + if (original_path[0] == '/') { + phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", original_path); + return; } + + file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]; + path = original_path; path_len = strlen(path); + pending = 1; + } else if (!(ssb.sb.st_mode & (S_IFREG|S_IFLNK))) { + phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path); + return; + } + } - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], - path, path_len, (void**)&broken) == FAILURE) { - HashTable breaks; + if (zend_hash_find(file_breaks, path, path_len, (void **) &broken) == FAILURE) { + HashTable breaks; + zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0); - zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0); + zend_hash_add(file_breaks, path, path_len, &breaks, sizeof(HashTable), (void **) &broken); + } - zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], - path, path_len, &breaks, sizeof(HashTable), - (void**)&broken); - } + if (!zend_hash_index_exists(broken, line_num)) { + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE); + new_break.filename = estrndup(path, path_len); + new_break.line = line_num; - if (!zend_hash_index_exists(broken, line_num)) { - PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + zend_hash_index_update(broken, line_num, (void **) &new_break, sizeof(phpdbg_breakfile_t), NULL); - PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE); - new_break.filename = estrndup(path, path_len); - new_break.line = line_num; + if (pending) { + PHPDBG_G(flags) |= PHPDBG_HAS_PENDING_FILE_BP; - zend_hash_index_update( broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL); + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\" pending=\"pending\"", "Pending breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); + } else { + PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; - phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", - new_break.id, new_break.filename, new_break.line); + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); + } - PHPDBG_BREAK_MAPPING(new_break.id, broken); - } else { - phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); + PHPDBG_BREAK_MAPPING(new_break.id, broken); + } else { + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); + } +} /* }}} */ + +PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* {{{ */ +{ + HashPosition position[2]; + HashTable *fileht; + uint filelen = strlen(file); + + zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]); + while (zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (void**) &fileht, &position[0]) == SUCCESS) { + const char *cur; + uint curlen; + + zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (char **) &cur, &curlen, NULL, 0, &position[0]); + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]); + + if (curlen < filelen && file[filelen - curlen - 1] == '/' && !memcmp(file + filelen - curlen, cur, curlen)) { + phpdbg_breakfile_t *brake, new_brake; + HashTable *master = NULL; + dtor_func_t dtor; + + PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, (void **) &master) == FAILURE) { + dtor = PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor; + PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = NULL; + zend_hash_add(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, fileht, sizeof(HashTable), (void **) &fileht); } - } else { - phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path); + for (zend_hash_internal_pointer_reset_ex(fileht, &position[1]); + zend_hash_get_current_data_ex(fileht, (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex(fileht, &position[1])) { + new_brake = *brake; + new_brake.filename = estrndup(file, filelen); + PHPDBG_BREAK_UNMAPPING(brake->id); + + if (master) { + zend_hash_index_update(master, brake->line, (void **) &new_brake, sizeof(phpdbg_breakfile_t), NULL); + PHPDBG_BREAK_MAPPING(brake->id, master); + } else { + efree((char *) brake->filename); + *brake = new_brake; + PHPDBG_BREAK_MAPPING(brake->id, fileht); + } + } + + zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur, curlen); + + if (!master) { + PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = dtor; + } + + if (!zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING])) { + PHPDBG_G(flags) &= ~PHPDBG_HAS_PENDING_FILE_BP; + } } - } else { - phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", path); } } /* }}} */ @@ -1141,6 +1209,7 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D) /* {{{ */ { zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]); @@ -1398,6 +1467,25 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); } } + } if ((PHPDBG_G(flags) & PHPDBG_HAS_PENDING_FILE_BP)) { + HashPosition position[2]; + HashTable *points; + + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Pending File Breakpoints:\n"); + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]); + zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (void**) &points, &position[0]) == SUCCESS; + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0])) { + phpdbg_breakfile_t *brake; + + for (zend_hash_internal_pointer_reset_ex(points, &position[1]); + zend_hash_get_current_data_ex(points, (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex(points, &position[1])) { + phpdbg_writeln("file", "id=\"%d\" name=\"%s\" line=\"%lu\" disabled=\"%s\" pending=\"pending\"", "#%d\t\t%s:%lu%s", + brake->id, brake->filename, brake->line, + ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + } + } } break; diff --git a/phpdbg_bp.h b/phpdbg_bp.h index a6227cba6c..606085ddcf 100644 --- a/phpdbg_bp.h +++ b/phpdbg_bp.h @@ -23,16 +23,17 @@ /* {{{ defines */ #define PHPDBG_BREAK_FILE 0 -#define PHPDBG_BREAK_SYM 1 -#define PHPDBG_BREAK_OPLINE 2 -#define PHPDBG_BREAK_METHOD 3 -#define PHPDBG_BREAK_COND 4 -#define PHPDBG_BREAK_OPCODE 5 -#define PHPDBG_BREAK_FUNCTION_OPLINE 6 -#define PHPDBG_BREAK_METHOD_OPLINE 7 -#define PHPDBG_BREAK_FILE_OPLINE 8 -#define PHPDBG_BREAK_MAP 9 -#define PHPDBG_BREAK_TABLES 10 /* }}} */ +#define PHPDBG_BREAK_FILE_PENDING 1 +#define PHPDBG_BREAK_SYM 2 +#define PHPDBG_BREAK_OPLINE 3 +#define PHPDBG_BREAK_METHOD 4 +#define PHPDBG_BREAK_COND 5 +#define PHPDBG_BREAK_OPCODE 6 +#define PHPDBG_BREAK_FUNCTION_OPLINE 7 +#define PHPDBG_BREAK_METHOD_OPLINE 8 +#define PHPDBG_BREAK_FILE_OPLINE 9 +#define PHPDBG_BREAK_MAP 10 +#define PHPDBG_BREAK_TABLES 11 /* }}} */ /* {{{ */ typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */ @@ -116,10 +117,11 @@ typedef struct _phpdbg_breakcond_t { zend_op_array *ops; } phpdbg_breakcond_t; -/* {{{ Opline breaks API */ +/* {{{ Resolving breaks API */ PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC); PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC); -PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */ +PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); +PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC); /* }}} */ /* {{{ Breakpoint Creation API */ PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC); diff --git a/phpdbg_cmd.c b/phpdbg_cmd.c index 13d5a0d634..a170d52955 100644 --- a/phpdbg_cmd.c +++ b/phpdbg_cmd.c @@ -727,7 +727,7 @@ PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ char *cmd = NULL; char *buffer = NULL; - if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) { + if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) != PHPDBG_IS_STOPPING) { if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) { fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); } diff --git a/phpdbg_list.c b/phpdbg_list.c index 7aa8c4f9e0..8ab4c8922a 100644 --- a/phpdbg_list.c +++ b/phpdbg_list.c @@ -278,6 +278,8 @@ zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) { dataptr->line[line] = endptr - data.buf; dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line); + phpdbg_resolve_pending_file_break(filename TSRMLS_CC); + ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC); fake.opened_path = NULL; diff --git a/phpdbg_out.c b/phpdbg_out.c index a4793f144f..365708c71e 100644 --- a/phpdbg_out.c +++ b/phpdbg_out.c @@ -1117,6 +1117,8 @@ PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, int fd, const char *tag, const } if (PHPDBG_G(err_buf).active && type != P_STDOUT && type != P_STDERR) { + phpdbg_free_err_buf(TSRMLS_C); + PHPDBG_G(err_buf).type = type; PHPDBG_G(err_buf).fd = fd; PHPDBG_G(err_buf).tag = estrdup(tag); diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index eca4c6ac2b..a2e4d41042 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -28,7 +28,6 @@ #include "phpdbg_print.h" #include "phpdbg_info.h" #include "phpdbg_break.h" -#include "phpdbg_bp.h" #include "phpdbg_opcode.h" #include "phpdbg_list.h" #include "phpdbg_utils.h" @@ -44,7 +43,6 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); ZEND_EXTERN_MODULE_GLOBALS(output); extern int phpdbg_startup_run; -extern char *phpdbg_exec; #ifdef HAVE_LIBDL #ifdef PHP_WIN32 @@ -641,10 +639,10 @@ PHPDBG_COMMAND(run) /* {{{ */ } zend_try { - PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; + PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE; + PHPDBG_G(flags) |= PHPDBG_IS_RUNNING; zend_execute(EG(active_op_array) TSRMLS_CC); - PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; - phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); + PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE; } zend_catch { EG(active_op_array) = orig_op_array; EG(opline_ptr) = orig_opline; @@ -669,7 +667,11 @@ PHPDBG_COMMAND(run) /* {{{ */ EG(active_op_array) = orig_op_array; EG(opline_ptr) = orig_opline; EG(return_value_ptr_ptr) = orig_retval_ptr; + + phpdbg_clean(1 TSRMLS_CC); } + + PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING; } else { phpdbg_error("inactive", "type=\"nocontext\"", "Nothing to execute!"); } @@ -1235,8 +1237,8 @@ int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */ PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE; - while (1) { - if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) { + while (ret == SUCCESS || ret == FAILURE) { + if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_STOPPING) { zend_bailout(); } @@ -1291,6 +1293,7 @@ int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */ phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); PHPDBG_G(req_id) = 0; + input = NULL; } if (input) { @@ -1320,10 +1323,6 @@ void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */ } if (full) { - if (PHPDBG_G(exec)) { - phpdbg_exec = strdup(PHPDBG_G(exec)); /* preserve exec, don't reparse that from cmd */ - } - PHPDBG_G(flags) |= PHPDBG_IS_CLEANING; zend_bailout(); -- cgit v1.2.1 From 26babfb3576907c03caa8aa9698344754a09c7fc Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 26 Oct 2014 22:21:18 +0100 Subject: Fix last commit, and do not output unnecessary information --- phpdbg.c | 44 ++++++++++++++++++++++++++++-------------- phpdbg.h | 4 +++- phpdbg_io.c | 4 ++++ phpdbg_prompt.c | 11 +++++++++-- tests/commands/0104_clean.test | 1 - 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index 3e31f76898..b7fb5e5afc 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -544,7 +544,7 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */ { - if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) { + 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); @@ -554,7 +554,7 @@ static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */ pg->oplog = PHPDBG_G(oplog); pg->prompt[0] = PHPDBG_G(prompt)[0]; pg->prompt[1] = PHPDBG_G(prompt)[1]; - memset(pg->colors, PHPDBG_G(colors), sizeof(pg->colors)); + memcpy(pg->colors, PHPDBG_G(colors), sizeof(pg->colors)); pg->eol = PHPDBG_G(eol); pg->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK; } @@ -1035,7 +1035,7 @@ int main(int argc, char **argv) /* {{{ */ zend_ulong flags; char *php_optarg; int php_optind, opt, show_banner = 1; - long cleaning = 0; + long cleaning = -1; zend_bool remote = 0; int step = 0; zend_phpdbg_globals *settings = NULL; @@ -1491,21 +1491,20 @@ phpdbg_main: /* Make stdin, stdout and stderr accessible from PHP scripts */ phpdbg_register_file_handles(TSRMLS_C); - if (show_banner) { + if (show_banner && cleaning < 2) { /* print blurb */ - phpdbg_welcome((cleaning > 0) TSRMLS_CC); + phpdbg_welcome(cleaning == 1 TSRMLS_CC); } - /* auto compile */ - if (PHPDBG_G(exec)) { - phpdbg_compile(TSRMLS_C); - } + cleaning = -1; /* initialize from file */ PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; zend_try { phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC); + PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC); + PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; } zend_end_try(); PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; @@ -1514,14 +1513,24 @@ phpdbg_main: goto phpdbg_out; } + /* auto compile */ + if (PHPDBG_G(exec)) { + if (settings) { + PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; + } + phpdbg_compile(TSRMLS_C); + PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; + } + /* step from here, not through init */ if (step) { PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } if (phpdbg_startup_run) { - /* no need to try{}, run does it ... */ - PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); + zend_try { + PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); + } zend_end_try(); if (phpdbg_startup_run > 1) { /* if -r is on the command line more than once just quit */ goto phpdbg_out; @@ -1537,7 +1546,9 @@ phpdbg_interact: } zend_catch { if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { FILE *bp_tmp_fp = fopen(bp_tmp_file, "w"); + PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC); + PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; fclose(bp_tmp_fp); cleaning = 1; } else { @@ -1589,9 +1600,13 @@ phpdbg_out: } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) { phpdbg_error("segfault", "", "Access violation (Segementation fault) encountered\ntrying to abort cleanly..."); } -/* phpdbg_out: */ #endif + if (cleaning <= 0) { + PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING; + cleaning = -1; + } + { int i; /* free argv */ @@ -1638,9 +1653,10 @@ phpdbg_out: if ((PHPDBG_G(flags) & (PHPDBG_IS_QUITTING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_RUNNING) { phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); + cleaning++; } - if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) { + if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) == PHPDBG_IS_CLEANING) { settings = PHPDBG_G(backup); } @@ -1654,7 +1670,7 @@ phpdbg_out: } - if (cleaning || remote) { + if (cleaning > 0 || remote) { goto phpdbg_main; } diff --git a/phpdbg.h b/phpdbg.h index 57ea7ee570..65bdcd0d6f 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -177,12 +177,14 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); #define PHPDBG_IN_SIGNAL_HANDLER (1ULL<<33) +#define PHPDBG_DISCARD_OUTPUT (1ULL<<34) + #define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL | PHPDBG_IN_FINISH | PHPDBG_IN_LEAVE) #define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP) #define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP | PHPDBG_HAS_SYM_BP | PHPDBG_HAS_METHOD_BP | PHPDBG_HAS_OPLINE_BP | PHPDBG_HAS_COND_BP | PHPDBG_HAS_OPCODE_BP | PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP) #define PHPDBG_IS_STOPPING (PHPDBG_IS_QUITTING | PHPDBG_IS_CLEANING) -#define PHPDBG_PRESERVE_FLAGS_MASK (PHPDBG_SHOW_REFCOUNTS | PHPDBG_IS_STEPONEVAL | PHPDBG_IS_BP_ENABLED | PHPDBG_STEP_OPCODE) +#define PHPDBG_PRESERVE_FLAGS_MASK (PHPDBG_SHOW_REFCOUNTS | PHPDBG_IS_STEPONEVAL | PHPDBG_IS_BP_ENABLED | PHPDBG_STEP_OPCODE | PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED) #ifndef _WIN32 # define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED) diff --git a/phpdbg_io.c b/phpdbg_io.c index a2a5c5969f..6908a687d7 100644 --- a/phpdbg_io.c +++ b/phpdbg_io.c @@ -187,6 +187,10 @@ PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC) { + if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) { + return 0; + } + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { return phpdbg_send_bytes(sock, ptr, len); } diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index a2e4d41042..fd4af2c3cd 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -263,7 +263,7 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ goto next_line; } - { + zend_try { char *input = phpdbg_read_input(cmd TSRMLS_CC); phpdbg_param_t stack; @@ -287,7 +287,12 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); - } + } zend_catch { + PHPDBG_G(flags) &= ~(PHPDBG_IS_RUNNING | PHPDBG_IS_CLEANING); + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + zend_bailout(); + } + } zend_end_try(); } next_line: line++; @@ -1160,6 +1165,8 @@ PHPDBG_COMMAND(clean) /* {{{ */ phpdbg_writeln("clean", "constants=\"%d\"", "Constants %d", zend_hash_num_elements(EG(zend_constants))); phpdbg_writeln("clean", "includes=\"%d\"", "Includes %d", zend_hash_num_elements(&EG(included_files))); + PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING; + phpdbg_clean(1 TSRMLS_CC); phpdbg_xml(""); diff --git a/tests/commands/0104_clean.test b/tests/commands/0104_clean.test index d50903c479..2c7660ad60 100644 --- a/tests/commands/0104_clean.test +++ b/tests/commands/0104_clean.test @@ -9,7 +9,6 @@ #Functions %d #Constants %d #Includes %d -#[Nothing to execute!] ################################################# clean quit -- cgit v1.2.1 From e7ddcbcb865ad03a3ad5e500d4ac6d271019473c Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 26 Oct 2014 23:33:54 +0100 Subject: Do not execute anything after quit or clean command --- phpdbg_prompt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index fd4af2c3cd..5e2cc03d50 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -1438,6 +1438,10 @@ void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC) /* {{{ */ } #endif + if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_STOPPING) { + zend_bailout(); + } + EG(in_execution) = 1; #if PHP_VERSION_ID >= 50500 -- cgit v1.2.1 From 35d90d3858be64b83196b194492f25945666088e Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 27 Oct 2014 13:11:13 +0100 Subject: Merge phpdbg into PHP-5.6 Conflicts: sapi/phpdbg/phpdbg.c sapi/phpdbg/phpdbg_prompt.c --- phpdbg.c | 4 ++-- phpdbg.h | 9 ++++++--- phpdbg_prompt.c | 7 ++++++- phpdbg_sigio_win32.c | 25 +++++++++++-------------- phpdbg_sigio_win32.h | 2 -- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index b7fb5e5afc..9c56b1d7bc 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -1343,7 +1343,7 @@ phpdbg_main: } /* setup remote server if necessary */ - if (!cleaning && listen > 0) { + if (cleaning <= 0 && listen > 0) { server = phpdbg_open_socket(address, listen TSRMLS_CC); if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) { exit(0); @@ -1466,7 +1466,7 @@ phpdbg_main: if (exec) { /* set execution context */ PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); - PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec)); + PHPDBG_G(exec_len) = strlen(exec); free(exec); exec = NULL; diff --git a/phpdbg.h b/phpdbg.h index 65bdcd0d6f..2aae533d84 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -29,8 +29,12 @@ # define PHPDBG_API #endif -#include -#include +#ifndef PHP_WIN32 +# include +# include +#else +# include "win32/php_stdint.h" +#endif #include "php.h" #include "php_globals.h" #include "php_variables.h" @@ -50,7 +54,6 @@ #if defined(_WIN32) && !defined(__MINGW32__) # include # include "config.w32.h" -# include "win32/php_stdint.h" # undef strcasecmp # undef strncasecmp # define strcasecmp _stricmp diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 5e2cc03d50..73ecbcb892 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -653,6 +653,10 @@ PHPDBG_COMMAND(run) /* {{{ */ EG(opline_ptr) = orig_opline; EG(return_value_ptr_ptr) = orig_retval_ptr; + 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; @@ -1143,6 +1147,7 @@ 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(); } @@ -1438,7 +1443,7 @@ void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC) /* {{{ */ } #endif - if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_STOPPING) { + if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) && !(PHPDBG_G(flags) & PHPDBG_IS_RUNNING)) { zend_bailout(); } diff --git a/phpdbg_sigio_win32.c b/phpdbg_sigio_win32.c index 24e9ac0e0a..158e034872 100644 --- a/phpdbg_sigio_win32.c +++ b/phpdbg_sigio_win32.c @@ -33,30 +33,31 @@ SigIoWatcherThread(VOID *p) struct win32_sigio_watcher_data *swd = (struct win32_sigio_watcher_data *)p; #ifdef ZTS void ***tsrm_ls = swd->tsrm_ls; -top: - (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1, tsrm_ls); -#else -top: - (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1); #endif +top: + (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1 TSRMLS_CC); + if (3 == sig) { - printf("signaled, got %d", sig); /* XXX completely not sure it is done right here */ - if (swd->flags & PHPDBG_IS_INTERACTIVE) { + if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { if (raise(sig)) { - /* just out*/ - exit(0); + goto top; } } - if (swd->flags & PHPDBG_IS_SIGNALED) { + if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { phpdbg_set_sigsafe_mem(&sig TSRMLS_CC); zend_try { phpdbg_force_interruption(TSRMLS_C); } zend_end_try(); phpdbg_clear_sigsafe_mem(TSRMLS_C); + goto end; + } + if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { + PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; } +end: /* XXX set signaled flag to the caller thread, question is - whether it's needed */ ExitThread(sig); } else { @@ -74,8 +75,6 @@ sigio_watcher_start(void) TSRMLS_FETCH(); PHPDBG_G(swd).fd = PHPDBG_G(io)[PHPDBG_STDIN].fd; - PHPDBG_G(swd).running = 1; - PHPDBG_G(swd).flags = PHPDBG_G(flags); #ifdef ZTS PHPDBG_G(swd).tsrm_ls = tsrm_ls; #endif @@ -113,8 +112,6 @@ sigio_watcher_stop(void) } PHPDBG_G(swd).fd = -1; - PHPDBG_G(swd).running = 0; - PHPDBG_G(swd).flags = 0; PHPDBG_G(sigio_watcher_thread) = INVALID_HANDLE_VALUE; } diff --git a/phpdbg_sigio_win32.h b/phpdbg_sigio_win32.h index 796b477f93..8c8a381d64 100644 --- a/phpdbg_sigio_win32.h +++ b/phpdbg_sigio_win32.h @@ -25,12 +25,10 @@ #include "phpdbg_io.h" struct win32_sigio_watcher_data { - zend_ulong flags; #ifdef ZTS void ***tsrm_ls; #endif int fd; - zend_uchar running; }; void -- cgit v1.2.1 From 44079a0c820e08de1709d8dff2682ba4b2c03965 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 27 Oct 2014 14:07:26 +0100 Subject: Merge phpdbg into PHP-5.6 --- phpdbg.h | 2 +- phpdbg_bp.c | 119 +++++++++++++++++++++++++++++++++++++----------------------- phpdbg_bp.h | 1 + 3 files changed, 75 insertions(+), 47 deletions(-) diff --git a/phpdbg.h b/phpdbg.h index 2aae533d84..a9be80436e 100644 --- a/phpdbg.h +++ b/phpdbg.h @@ -187,7 +187,7 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); #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) +#define PHPDBG_PRESERVE_FLAGS_MASK (PHPDBG_SHOW_REFCOUNTS | PHPDBG_IS_STEPONEVAL | PHPDBG_IS_BP_ENABLED | PHPDBG_STEP_OPCODE | PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_REMOTE | PHPDBG_WRITE_XML | PHPDBG_IS_DISCONNECTED) #ifndef _WIN32 # define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED) diff --git a/phpdbg_bp.c b/phpdbg_bp.c index 9333b353ce..cf28a33885 100644 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@ -257,12 +257,31 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML } if (!zend_hash_index_exists(broken, line_num)) { + HashPosition position; + char *file; + uint filelen; + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE); new_break.filename = estrndup(path, path_len); new_break.line = line_num; zend_hash_index_update(broken, line_num, (void **) &new_break, sizeof(phpdbg_breakfile_t), NULL); + PHPDBG_BREAK_MAPPING(new_break.id, broken); + + if (pending) { + for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(file_sources), &position); + zend_hash_get_current_key_ex(&PHPDBG_G(file_sources), &file, &filelen, NULL, 0, &position) == HASH_KEY_IS_STRING; + zend_hash_move_forward_ex(&PHPDBG_G(file_sources), &position)) { + if (!(pending = ((broken = phpdbg_resolve_pending_file_break_ex(file, filelen, path, path_len, broken TSRMLS_CC)) == NULL))) { + phpdbg_breakfile_t *brake; + zend_hash_index_find(broken, line_num, (void **) &brake); + new_break = *brake; + break; + } + } + } + if (pending) { PHPDBG_G(flags) |= PHPDBG_HAS_PENDING_FILE_BP; @@ -272,69 +291,77 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); } - - PHPDBG_BREAK_MAPPING(new_break.id, broken); } else { phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); } } /* }}} */ -PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* {{{ */ +PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, const char *cur, uint curlen, HashTable *fileht TSRMLS_DC) /* {{{ */ { - HashPosition position[2]; - HashTable *fileht; - uint filelen = strlen(file); + if (curlen < filelen && file[filelen - curlen - 1] == '/' && !memcmp(file + filelen - curlen, cur, curlen)) { + phpdbg_breakfile_t *brake, new_brake; + HashTable *master = NULL; + HashPosition position; + dtor_func_t dtor; + + PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, (void **) &master) == FAILURE) { + dtor = PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor; + PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = NULL; + zend_hash_add(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, fileht, sizeof(HashTable), (void **) &fileht); + } - zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]); - while (zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (void**) &fileht, &position[0]) == SUCCESS) { - const char *cur; - uint curlen; + for (zend_hash_internal_pointer_reset_ex(fileht, &position); + zend_hash_get_current_data_ex(fileht, (void**)&brake, &position) == SUCCESS; + zend_hash_move_forward_ex(fileht, &position)) { + new_brake = *brake; + new_brake.filename = estrndup(file, filelen); + PHPDBG_BREAK_UNMAPPING(brake->id); - zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (char **) &cur, &curlen, NULL, 0, &position[0]); - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position[0]); + if (master) { + zend_hash_index_update(master, brake->line, (void **) &new_brake, sizeof(phpdbg_breakfile_t), NULL); + PHPDBG_BREAK_MAPPING(brake->id, master); + } else { + efree((char *) brake->filename); + *brake = new_brake; + PHPDBG_BREAK_MAPPING(brake->id, fileht); + } + } - if (curlen < filelen && file[filelen - curlen - 1] == '/' && !memcmp(file + filelen - curlen, cur, curlen)) { - phpdbg_breakfile_t *brake, new_brake; - HashTable *master = NULL; - dtor_func_t dtor; + zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur, curlen); - PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + if (!master) { + PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = dtor; + } - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, (void **) &master) == FAILURE) { - dtor = PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor; - PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = NULL; - zend_hash_add(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, fileht, sizeof(HashTable), (void **) &fileht); - } + if (!zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING])) { + PHPDBG_G(flags) &= ~PHPDBG_HAS_PENDING_FILE_BP; + } - for (zend_hash_internal_pointer_reset_ex(fileht, &position[1]); - zend_hash_get_current_data_ex(fileht, (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex(fileht, &position[1])) { - new_brake = *brake; - new_brake.filename = estrndup(file, filelen); - PHPDBG_BREAK_UNMAPPING(brake->id); + return fileht; + } - if (master) { - zend_hash_index_update(master, brake->line, (void **) &new_brake, sizeof(phpdbg_breakfile_t), NULL); - PHPDBG_BREAK_MAPPING(brake->id, master); - } else { - efree((char *) brake->filename); - *brake = new_brake; - PHPDBG_BREAK_MAPPING(brake->id, fileht); - } - } + return NULL; +} /* }}} */ - zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur, curlen); +PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* {{{ */ +{ + HashPosition position; + HashTable *fileht; + uint filelen = strlen(file); - if (!master) { - PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = dtor; - } + zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position); + while (zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (void**) &fileht, &position) == SUCCESS) { + const char *cur; + uint curlen; - if (!zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING])) { - PHPDBG_G(flags) &= ~PHPDBG_HAS_PENDING_FILE_BP; - } - } + zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (char **) &cur, &curlen, NULL, 0, &position); + zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position); + + phpdbg_resolve_pending_file_break_ex(file, filelen, cur, curlen, fileht TSRMLS_CC); } -} /* }}} */ +} PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len TSRMLS_DC) /* {{{ */ { diff --git a/phpdbg_bp.h b/phpdbg_bp.h index 606085ddcf..eca595321b 100644 --- a/phpdbg_bp.h +++ b/phpdbg_bp.h @@ -121,6 +121,7 @@ typedef struct _phpdbg_breakcond_t { PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC); PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC); PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); +PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, const char *cur, uint curlen, HashTable *fileht TSRMLS_DC); PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC); /* }}} */ /* {{{ Breakpoint Creation API */ -- cgit v1.2.1 From 64774c7ddbdef3844558898a50104ec6dc758b55 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 28 Oct 2014 12:27:19 +0100 Subject: *Always* clean up and run destructors --- phpdbg_prompt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 73ecbcb892..262b265a2e 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -676,10 +676,10 @@ PHPDBG_COMMAND(run) /* {{{ */ EG(active_op_array) = orig_op_array; EG(opline_ptr) = orig_opline; EG(return_value_ptr_ptr) = orig_retval_ptr; - - phpdbg_clean(1 TSRMLS_CC); } + phpdbg_clean(1 TSRMLS_CC); + PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING; } else { phpdbg_error("inactive", "type=\"nocontext\"", "Nothing to execute!"); -- cgit v1.2.1 From 9990089f2821fc9892533e97cf5dbbd75c6cca2f Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 28 Oct 2014 12:38:07 +0100 Subject: Fix potential segfaults and unresolved breaks --- phpdbg_bp.c | 56 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/phpdbg_bp.c b/phpdbg_bp.c index cf28a33885..93902f0052 100644 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@ -232,6 +232,8 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML } path_len = strlen(path); + phpdbg_debug("file path: %s, resolved path: %s, was compiled: %d\n", original_path, path, zend_hash_exists(&PHPDBG_G(file_sources), path, path_len)); + if (!zend_hash_exists(&PHPDBG_G(file_sources), path, path_len)) { if (php_stream_stat_path(path, &ssb) == FAILURE) { if (original_path[0] == '/') { @@ -246,6 +248,8 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML } else if (!(ssb.sb.st_mode & (S_IFREG|S_IFLNK))) { phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path); return; + } else { + phpdbg_debug("File exists, but not compiled\n"); } } @@ -273,9 +277,13 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(file_sources), &position); zend_hash_get_current_key_ex(&PHPDBG_G(file_sources), &file, &filelen, NULL, 0, &position) == HASH_KEY_IS_STRING; zend_hash_move_forward_ex(&PHPDBG_G(file_sources), &position)) { - if (!(pending = ((broken = phpdbg_resolve_pending_file_break_ex(file, filelen, path, path_len, broken TSRMLS_CC)) == NULL))) { + HashTable *fileht; + + phpdbg_debug("Compare against loaded %s\n", file); + + if (!(pending = ((fileht = phpdbg_resolve_pending_file_break_ex(file, filelen, path, path_len, broken TSRMLS_CC)) == NULL))) { phpdbg_breakfile_t *brake; - zend_hash_index_find(broken, line_num, (void **) &brake); + zend_hash_index_find(fileht, line_num, (void **) &brake); new_break = *brake; break; } @@ -298,18 +306,19 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, const char *cur, uint curlen, HashTable *fileht TSRMLS_DC) /* {{{ */ { - if (curlen < filelen && file[filelen - curlen - 1] == '/' && !memcmp(file + filelen - curlen, cur, curlen)) { + phpdbg_debug("file: %s, filelen: %u, cur: %s, curlen %u, pos: %c, memcmp: %d\n", file, filelen, cur, curlen, filelen > curlen ? file[filelen - curlen - 1] : '?', filelen > curlen ? memcmp(file + filelen - curlen, cur, curlen) : 0); + + if (((curlen < filelen && file[filelen - curlen - 1] == '/') || filelen == curlen) && !memcmp(file + filelen - curlen, cur, curlen)) { phpdbg_breakfile_t *brake, new_brake; HashTable *master = NULL; HashPosition position; - dtor_func_t dtor; PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, (void **) &master) == FAILURE) { - dtor = PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor; - PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = NULL; - zend_hash_add(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, fileht, sizeof(HashTable), (void **) &fileht); + HashTable new_ht; + zend_hash_init(&new_ht, 8, NULL, phpdbg_file_breaks_dtor, 0); + zend_hash_add(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, &new_ht, sizeof(HashTable), (void **) &master); } for (zend_hash_internal_pointer_reset_ex(fileht, &position); @@ -322,24 +331,18 @@ PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uin if (master) { zend_hash_index_update(master, brake->line, (void **) &new_brake, sizeof(phpdbg_breakfile_t), NULL); PHPDBG_BREAK_MAPPING(brake->id, master); - } else { - efree((char *) brake->filename); - *brake = new_brake; - PHPDBG_BREAK_MAPPING(brake->id, fileht); } } zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur, curlen); - if (!master) { - PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING].pDestructor = dtor; - } - if (!zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING])) { PHPDBG_G(flags) &= ~PHPDBG_HAS_PENDING_FILE_BP; } - return fileht; + phpdbg_debug("compiled file: %s, cur bp file: %s\n", file, cur); + + return master; } return NULL; @@ -351,6 +354,8 @@ PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* HashTable *fileht; uint filelen = strlen(file); + phpdbg_debug("was compiled: %s\n", file); + zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position); while (zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (void**) &fileht, &position) == SUCCESS) { const char *cur; @@ -359,6 +364,8 @@ PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], (char **) &cur, &curlen, NULL, 0, &position); zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], &position); + phpdbg_debug("check bp: %s\n", cur); + phpdbg_resolve_pending_file_break_ex(file, filelen, cur, curlen, fileht TSRMLS_CC); } } @@ -877,10 +884,21 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_ { HashTable *breaks; phpdbg_breakbase_t *brake; - size_t name_len = strlen(op_array->filename); + size_t path_len; + char realpath[MAXPATHLEN]; + const char *path = 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); +#endif - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename, - name_len, (void**)&breaks) == FAILURE) { + if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len, (void**)&breaks) == FAILURE) { return NULL; } -- cgit v1.2.1 From a8ac22452df4289d5d6acfd84f0cc616504d1112 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 28 Oct 2014 13:20:43 +0100 Subject: Fix possibly unclosed tags --- phpdbg_io.c | 4 ---- phpdbg_out.c | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/phpdbg_io.c b/phpdbg_io.c index 6908a687d7..a2a5c5969f 100644 --- a/phpdbg_io.c +++ b/phpdbg_io.c @@ -187,10 +187,6 @@ PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC) { - if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) { - return 0; - } - if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { return phpdbg_send_bytes(sock, ptr, len); } diff --git a/phpdbg_out.c b/phpdbg_out.c index 365708c71e..7e1dc7b744 100644 --- a/phpdbg_out.c +++ b/phpdbg_out.c @@ -1168,6 +1168,10 @@ PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const va_list args; int errbuf_active = PHPDBG_G(err_buf).active; + if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) { + return 0; + } + PHPDBG_G(err_buf).active = 0; #ifdef ZTS @@ -1188,6 +1192,10 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *tag, const c va_list args; int len; + if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) { + return 0; + } + va_start(args, strfmt); len = phpdbg_vprint(type TSRMLS_CC, fd, tag, xmlfmt, strfmt, args); va_end(args); @@ -1198,6 +1206,10 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *tag, const c PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) { int len = 0; + if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) { + return 0; + } + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { va_list args; char *buffer; @@ -1243,6 +1255,10 @@ PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) { int buflen; int len = 0; + if (PHPDBG_G(flags) & PHPDBG_DISCARD_OUTPUT) { + return 0; + } + va_start(args, fmt); buflen = phpdbg_xml_vasprintf(&buffer, fmt, 0, args TSRMLS_CC); va_end(args); -- cgit v1.2.1 From b7d83ff8a69f60820ac45ffc02d903482c40399f Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 28 Oct 2014 13:27:20 +0100 Subject: Fix wrong exec length on relative paths --- phpdbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpdbg.c b/phpdbg.c index 9c56b1d7bc..4bfbf4c1e9 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -1466,7 +1466,7 @@ phpdbg_main: if (exec) { /* set execution context */ PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); - PHPDBG_G(exec_len) = strlen(exec); + PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0; free(exec); exec = NULL; -- cgit v1.2.1 From c895fbea22cb0d7bedfa9e3429a073c8eefca84a Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 28 Oct 2014 13:55:14 +0100 Subject: Fix quitting on a second run --- phpdbg.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index 4bfbf4c1e9..87bfb85834 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -1527,21 +1527,20 @@ phpdbg_main: PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } - if (phpdbg_startup_run) { - zend_try { - PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); - } zend_end_try(); - if (phpdbg_startup_run > 1) { - /* if -r is on the command line more than once just quit */ - goto phpdbg_out; - } - phpdbg_startup_run = 0; - } - phpdbg_interact: /* phpdbg main() */ do { zend_try { + if (phpdbg_startup_run) { + PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); + if (phpdbg_startup_run > 1) { + /* if -r is on the command line more than once just quit */ + EG(bailout) = __orig_bailout; /* reset zend_try */ + break; + } + phpdbg_startup_run = 0; + } + phpdbg_interactive(1 TSRMLS_CC); } zend_catch { if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { -- cgit v1.2.1 From 82640b7363d9fcf0283a4fbe2ff131570254a61e Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 28 Oct 2014 13:55:56 +0100 Subject: Typo (notfoundc => notfound) --- phpdbg_prompt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 262b265a2e..733d3cbe48 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -1132,7 +1132,7 @@ PHPDBG_COMMAND(register) /* {{{ */ phpdbg_notice("register", "function=\"%s\"", "Registered %s", lcname); } else { - phpdbg_error("register", "type=\"notfoundc\" function=\"%s\"", "The requested function (%s) could not be found", param->str); + phpdbg_error("register", "type=\"notfound\" function=\"%s\"", "The requested function (%s) could not be found", param->str); } } else { phpdbg_error("register", "type=\"inuse\" function=\"%s\"", "The requested name (%s) is already in use", lcname); -- cgit v1.2.1 From 7561e6b6e32134c6af669cb048eb4bbcb5f5cc4b Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 28 Oct 2014 17:20:21 +0100 Subject: Remove the ugly hack via a temp file to store breakpoints --- phpdbg.c | 61 ++++++------------- phpdbg_bp.c | 67 +++++++++++++-------- phpdbg_bp.h | 3 +- phpdbg_prompt.c | 184 ++++++++++++++++++++++++++++++++------------------------ phpdbg_prompt.h | 1 + 5 files changed, 170 insertions(+), 146 deletions(-) diff --git a/phpdbg.c b/phpdbg.c index 87bfb85834..5ebc203529 100644 --- a/phpdbg.c +++ b/phpdbg.c @@ -1039,13 +1039,7 @@ int main(int argc, char **argv) /* {{{ */ zend_bool remote = 0; int step = 0; zend_phpdbg_globals *settings = NULL; - -#ifdef _WIN32 - char *bp_tmp_file = NULL; -#else - char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX"; -#endif - + char *bp_tmp = NULL; char *address; int listen = -1; int server = -1; @@ -1081,29 +1075,6 @@ int main(int argc, char **argv) /* {{{ */ #endif phpdbg_main: - if (!cleaning) { - -#ifdef _WIN32 - bp_tmp_file = malloc(L_tmpnam); - - if (bp_tmp_file) { - if (!tmpnam(bp_tmp_file)) { - free(bp_tmp_file); - bp_tmp_file = NULL; - } - } - - if (!bp_tmp_file) { - phpdbg_error("tmpfile", "", "Unable to create temporary file"); - return 1; - } -#else - if (!mkstemp(bp_tmp_file)) { - memset(bp_tmp_file, 0, sizeof(bp_tmp_file)); - } -#endif - - } ini_entries = NULL; ini_entries_len = 0; ini_ignore = 0; @@ -1502,9 +1473,13 @@ phpdbg_main: PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING; zend_try { phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC); - PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; - phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC); - PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; + if (bp_tmp) { + PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; + phpdbg_string_init(bp_tmp TSRMLS_CC); + free(bp_tmp); + bp_tmp = NULL; + PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; + } } zend_end_try(); PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING; @@ -1532,23 +1507,27 @@ phpdbg_interact: do { zend_try { if (phpdbg_startup_run) { + zend_bool quit_immediately = phpdbg_startup_run > 1; + phpdbg_startup_run = 0; PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC); - if (phpdbg_startup_run > 1) { + if (quit_immediately) { /* if -r is on the command line more than once just quit */ EG(bailout) = __orig_bailout; /* reset zend_try */ break; } - phpdbg_startup_run = 0; } phpdbg_interactive(1 TSRMLS_CC); } zend_catch { if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { - FILE *bp_tmp_fp = fopen(bp_tmp_file, "w"); + char *bp_tmp_str; PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT; - phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC); + phpdbg_export_breakpoints_to_string(&bp_tmp_str TSRMLS_CC); PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; - fclose(bp_tmp_fp); + if (bp_tmp_str) { + bp_tmp = strdup(bp_tmp_str); + efree(bp_tmp_str); + } cleaning = 1; } else { cleaning = 0; @@ -1688,11 +1667,5 @@ phpdbg_out: free(PHPDBG_G(sapi_name_ptr)); } -#ifdef _WIN32 - free(bp_tmp_file); -#else - unlink(bp_tmp_file); -#endif - return 0; } /* }}} */ diff --git a/phpdbg_bp.c b/phpdbg_bp.c index 93902f0052..33824d4fec 100644 --- a/phpdbg_bp.c +++ b/phpdbg_bp.c @@ -110,11 +110,20 @@ PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */ } /* }}} */ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ +{ + char *string; + phpdbg_export_breakpoints_to_string(&string TSRMLS_CC); + fputs(string, handle); +} + +PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str TSRMLS_DC) /* {{{ */ { HashPosition position[2]; HashTable **table = NULL; zend_ulong id = 0L; + *str = ""; + if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) { phpdbg_notice("exportbreakpoint", "count=\"%d\"", "Exporting %d breakpoints", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])); /* this only looks like magic, it isn't */ @@ -126,55 +135,57 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], NULL, NULL, &id, 0, &position[0]); for (zend_hash_internal_pointer_reset_ex((*table), &position[1]); - zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex((*table), &position[1])) { + zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS; + zend_hash_move_forward_ex((*table), &position[1])) { if (brake->id == id) { + char *new_str = NULL; + switch (brake->type) { case PHPDBG_BREAK_FILE: { - fprintf(handle, - "break %s:%lu\n", + phpdbg_asprintf(&new_str, + "%sbreak %s:%lu\n", *str, ((phpdbg_breakfile_t*)brake)->filename, ((phpdbg_breakfile_t*)brake)->line); } break; case PHPDBG_BREAK_SYM: { - fprintf(handle, - "break %s\n", + phpdbg_asprintf(&new_str, + "%sbreak %s\n", *str, ((phpdbg_breaksymbol_t*)brake)->symbol); } break; case PHPDBG_BREAK_METHOD: { - fprintf(handle, - "break %s::%s\n", + phpdbg_asprintf(&new_str, + "%sbreak %s::%s\n", *str, ((phpdbg_breakmethod_t*)brake)->class_name, ((phpdbg_breakmethod_t*)brake)->func_name); } break; case PHPDBG_BREAK_METHOD_OPLINE: { - fprintf(handle, - "break %s::%s#%ld\n", + phpdbg_asprintf(&new_str, + "%sbreak %s::%s#%ld\n", *str, ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_FUNCTION_OPLINE: { - fprintf(handle, - "break %s#%ld\n", + phpdbg_asprintf(&new_str, + "%sbreak %s#%ld\n", *str, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_FILE_OPLINE: { - fprintf(handle, - "break %s:#%ld\n", + phpdbg_asprintf(&new_str, + "%sbreak %s:#%ld\n", *str, ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_OPCODE: { - fprintf(handle, - "break %s\n", + phpdbg_asprintf(&new_str, + "%sbreak %s\n", *str, ((phpdbg_breakop_t*)brake)->name); } break; @@ -184,20 +195,20 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ if (conditional->paramed) { switch (conditional->param.type) { case STR_PARAM: - fprintf(handle, - "break at %s if %s\n", conditional->param.str, conditional->code); + phpdbg_asprintf(&new_str, + "%sbreak at %s if %s\n", *str, conditional->param.str, conditional->code); break; case METHOD_PARAM: - fprintf(handle, - "break at %s::%s if %s\n", + phpdbg_asprintf(&new_str, + "%sbreak at %s::%s if %s\n", *str, conditional->param.method.class, conditional->param.method.name, conditional->code); break; case FILE_PARAM: - fprintf(handle, - "break at %s:%lu if %s\n", + phpdbg_asprintf(&new_str, + "%sbreak at %s:%lu if %s\n", *str, conditional->param.file.name, conditional->param.file.line, conditional->code); break; @@ -205,15 +216,23 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ default: { /* do nothing */ } break; } } else { - fprintf( - handle, "break if %s\n", conditional->code); + phpdbg_asprintf(&new_str, "%sbreak if %s\n", str, conditional->code); } } break; } + + if ((*str)[0]) { + efree(*str); + } + *str = new_str; } } } } + + if (!(*str)[0]) { + *str = NULL; + } } /* }}} */ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRMLS_DC) /* {{{ */ diff --git a/phpdbg_bp.h b/phpdbg_bp.h index eca595321b..63a9961d2a 100644 --- a/phpdbg_bp.h +++ b/phpdbg_bp.h @@ -157,6 +157,7 @@ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC); PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC); /* }}} */ /* {{{ Breakpoint Exportation API */ -PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */ +PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); +PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str TSRMLS_DC); /* }}} */ #endif /* PHPDBG_BP_H */ diff --git a/phpdbg_prompt.c b/phpdbg_prompt.c index 733d3cbe48..c1fcb59a08 100644 --- a/phpdbg_prompt.c +++ b/phpdbg_prompt.c @@ -208,98 +208,128 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ * return FAILURE; } /* }}} */ -void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */ -{ - struct stat sb; +struct phpdbg_init_state { + int line; + zend_bool in_code; + char *code; + size_t code_len; + const char *init_file; +}; - if (init_file && VCWD_STAT(init_file, &sb) != -1) { - FILE *fp = fopen(init_file, "r"); - if (fp) { - int line = 1; +static void phpdbg_line_init(char *cmd, struct phpdbg_init_state *state TSRMLS_DC) { + size_t cmd_len = strlen(cmd); - char cmd[PHPDBG_MAX_CMD]; - size_t cmd_len = 0L; - char *code = NULL; - size_t code_len = 0L; - zend_bool in_code = 0; + state->line++; - while (fgets(cmd, PHPDBG_MAX_CMD, fp) != NULL) { - cmd_len = strlen(cmd)-1; - - while (cmd_len > 0L && isspace(cmd[cmd_len-1])) - cmd_len--; - - cmd[cmd_len] = '\0'; - - if (*cmd && cmd_len > 0L && cmd[0] != '#') { - if (cmd_len == 2) { - if (memcmp(cmd, "<:", sizeof("<:")-1) == SUCCESS) { - in_code = 1; - goto next_line; - } else { - if (memcmp(cmd, ":>", sizeof(":>")-1) == SUCCESS) { - in_code = 0; - code[code_len] = '\0'; - { - zend_eval_stringl(code, code_len, NULL, "phpdbginit code" TSRMLS_CC); - } - free(code); - code = NULL; - goto next_line; - } - } - } + while (cmd_len > 0L && isspace(cmd[cmd_len-1])) { + cmd_len--; + } - if (in_code) { - if (code == NULL) { - code = malloc(cmd_len + 1); - } else code = realloc(code, code_len + cmd_len + 1); + cmd[cmd_len] = '\0'; - if (code) { - memcpy( - &code[code_len], cmd, cmd_len); - code_len += cmd_len; - } - goto next_line; - } + if (*cmd && cmd_len > 0L && cmd[0] != '#') { + if (cmd_len == 2) { + if (memcmp(cmd, "<:", sizeof("<:")-1) == SUCCESS) { + state->in_code = 1; + return; + } else { + if (memcmp(cmd, ":>", sizeof(":>")-1) == SUCCESS) { + state->in_code = 0; + state->code[state->code_len] = '\0'; + zend_eval_stringl(state->code, state->code_len, NULL, "phpdbginit code" TSRMLS_CC); + free(state->code); + state->code = NULL; + return; + } + } + } - zend_try { - char *input = phpdbg_read_input(cmd TSRMLS_CC); - phpdbg_param_t stack; + if (state->in_code) { + if (state->code == NULL) { + state->code = malloc(cmd_len + 1); + } else { + state->code = realloc(state->code, state->code_len + cmd_len + 1); + } - phpdbg_init_param(&stack, STACK_PARAM); + if (state->code) { + memcpy(&state->code[state->code_len], cmd, cmd_len); + state->code_len += cmd_len; + } - phpdbg_activate_err_buf(1 TSRMLS_CC); + return; + } - if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { - switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */ TSRMLS_CC)) { - case FAILURE: - phpdbg_activate_err_buf(0 TSRMLS_CC); - if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { - phpdbg_output_err_buf("initfailure", "%b file=\"%s\" line=\"%d\" input=\"%s\"", "Unrecognized command in %s:%d: %s, %b!" TSRMLS_CC, init_file, line, input); - } - break; - } - } + zend_try { + char *input = phpdbg_read_input(cmd TSRMLS_CC); + phpdbg_param_t stack; + + phpdbg_init_param(&stack, STACK_PARAM); + + phpdbg_activate_err_buf(1 TSRMLS_CC); + if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { + switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */ TSRMLS_CC)) { + case FAILURE: phpdbg_activate_err_buf(0 TSRMLS_CC); - phpdbg_free_err_buf(TSRMLS_C); - - phpdbg_stack_free(&stack); - phpdbg_destroy_input(&input TSRMLS_CC); - } zend_catch { - PHPDBG_G(flags) &= ~(PHPDBG_IS_RUNNING | PHPDBG_IS_CLEANING); - if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { - zend_bailout(); + if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + if (state->init_file) { + phpdbg_output_err_buf("initfailure", "%b file=\"%s\" line=\"%d\" input=\"%s\"", "Unrecognized command in %s:%d: %s, %b!" TSRMLS_CC, state->init_file, state->line, input); + } else { + phpdbg_output_err_buf("initfailure", "%b line=\"%d\" input=\"%s\"", "Unrecognized command on line %d: %s, %b!" TSRMLS_CC, state->line, input); + } } - } zend_end_try(); + break; } -next_line: - line++; } - if (code) { - free(code); + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); + + phpdbg_stack_free(&stack); + phpdbg_destroy_input(&input TSRMLS_CC); + } zend_catch { + PHPDBG_G(flags) &= ~(PHPDBG_IS_RUNNING | PHPDBG_IS_CLEANING); + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + zend_bailout(); + } + } zend_end_try(); + } + +} + +void phpdbg_string_init(char *buffer TSRMLS_DC) { + struct phpdbg_init_state state = {0}; + char *str = strtok(buffer, "\n"); + + while (str) { + phpdbg_line_init(str, &state TSRMLS_CC); + + str = strtok(NULL, "\n"); + } + + if (state.code) { + free(state.code); + } +} + +void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */ +{ + struct stat sb; + + if (init_file && VCWD_STAT(init_file, &sb) != -1) { + FILE *fp = fopen(init_file, "r"); + if (fp) { + char cmd[PHPDBG_MAX_CMD]; + struct phpdbg_init_state state = {0}; + + state.init_file = init_file; + + while (fgets(cmd, PHPDBG_MAX_CMD, fp) != NULL) { + phpdbg_line_init(cmd, &state TSRMLS_CC); + } + + if (state.code) { + free(state.code); } fclose(fp); diff --git a/phpdbg_prompt.h b/phpdbg_prompt.h index 94e24df833..f583f2cdcd 100644 --- a/phpdbg_prompt.h +++ b/phpdbg_prompt.h @@ -22,6 +22,7 @@ #define PHPDBG_PROMPT_H /* {{{ */ +void phpdbg_string_init(char *buffer TSRMLS_DC); void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC); void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC); int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC); -- cgit v1.2.1 From 36fef6dcd9d9e95127726fcfb231303ca59749b9 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 28 Oct 2014 19:10:53 +0100 Subject: fix phpdbg build when src tree != build tree --- config.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.m4 b/config.m4 index 528abb5822..b8aa8526c5 100644 --- a/config.m4 +++ b/config.m4 @@ -22,8 +22,8 @@ if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then fi if test "$PHP_PHPDBG_WEBHELPER" != "no"; then - if ! test -d ext/phpdbg_webhelper; then - ln -s ../sapi/phpdbg ext/phpdbg_webhelper + if ! test -d $abs_srcdir/ext/phpdbg_webhelper; then + ln -s ../sapi/phpdbg $abs_srcdir/ext/phpdbg_webhelper fi if test "$PHP_JSON" != "no"; then PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared) -- cgit v1.2.1