├── .gdbinit ├── .gitignore ├── .phpdbginit ├── .travis.yml ├── CREDITS ├── Changelog.md ├── Makefile.frag ├── README.md ├── config.m4 ├── config.w32 ├── phpdbg.1 ├── phpdbg.c ├── phpdbg.h ├── phpdbg.init.d ├── phpdbg_bp.c ├── phpdbg_bp.h ├── phpdbg_break.c ├── phpdbg_break.h ├── phpdbg_btree.c ├── phpdbg_btree.h ├── phpdbg_cmd.c ├── phpdbg_cmd.h ├── phpdbg_eol.c ├── phpdbg_eol.h ├── phpdbg_frame.c ├── phpdbg_frame.h ├── phpdbg_help.c ├── phpdbg_help.h ├── phpdbg_info.c ├── phpdbg_info.h ├── phpdbg_io.c ├── phpdbg_io.h ├── phpdbg_lexer.c ├── phpdbg_lexer.h ├── phpdbg_lexer.l ├── phpdbg_list.c ├── phpdbg_list.h ├── phpdbg_opcode.c ├── phpdbg_opcode.h ├── phpdbg_out.c ├── phpdbg_out.h ├── phpdbg_parser.c ├── phpdbg_parser.h ├── phpdbg_parser.y ├── phpdbg_print.c ├── phpdbg_print.h ├── phpdbg_prompt.c ├── phpdbg_prompt.h ├── phpdbg_rinit_hook.c ├── phpdbg_rinit_hook.h ├── phpdbg_set.c ├── phpdbg_set.h ├── phpdbg_sigio_win32.c ├── phpdbg_sigio_win32.h ├── phpdbg_sigsafe.c ├── phpdbg_sigsafe.h ├── phpdbg_utils.c ├── phpdbg_utils.h ├── phpdbg_wait.c ├── phpdbg_wait.h ├── phpdbg_watch.c ├── phpdbg_watch.h ├── phpdbg_webdata_transfer.c ├── phpdbg_webdata_transfer.h ├── phpdbg_win.c ├── phpdbg_win.h ├── test.php ├── tests ├── commands │ ├── 0001_basic.test │ ├── 0002_set.test │ ├── 0101_info.test │ ├── 0102_print.test │ ├── 0103_register.test │ ├── 0104_clean.test │ ├── 0105_clear.test │ └── 0106_compile.test └── run-tests.php ├── travis └── ci.sh ├── web-bootstrap.php ├── xml.md └── zend_mm_structs.h /.gdbinit: -------------------------------------------------------------------------------- 1 | define ____phpdbg_globals 2 | if basic_functions_module.zts 3 | if !$tsrm_ls 4 | set $tsrm_ls = ts_resource_ex(0, 0) 5 | end 6 | set $phpdbg = ((zend_phpdbg_globals*) (*((void ***) $tsrm_ls))[phpdbg_globals_id-1]) 7 | else 8 | set $phpdbg = phpdbg_globals 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .libs/ 2 | phpdbg 3 | *.lo 4 | *.o 5 | *.output 6 | build 7 | -------------------------------------------------------------------------------- /.phpdbginit: -------------------------------------------------------------------------------- 1 | ########################################################## 2 | # .phpdbginit 3 | # 4 | # Lines starting with # are ignored 5 | # Code must start and end with <: and :> respectively 6 | ########################################################## 7 | # Place initialization commands one per line 8 | ########################################################## 9 | # exec sapi/phpdbg/test.php 10 | # set color prompt white-bold 11 | # set color notice green 12 | # set color error red 13 | 14 | ########################################################## 15 | # Embedding code in .phpdbginit 16 | ########################################################## 17 | <: 18 | /* 19 | * This embedded PHP is executed at init time 20 | */ 21 | 22 | /* 23 | * Functions defined and registered by init 24 | * will persist across cleans 25 | */ 26 | 27 | /* 28 | function my_debugging_function() 29 | { 30 | var_dump(func_get_args()); 31 | } 32 | */ 33 | 34 | /* phpdbg_break(PHPDBG_METHOD, "phpdbg::method"); */ 35 | /* phpdbg_break(PHPDBG_FUNC, "my_global_function"); */ 36 | /* phpdbg_break(PHPDBG_FILE, "/path/to/file.php:10"); */ 37 | 38 | /* 39 | If readline is loaded, you might want to setup completion: 40 | */ 41 | if (function_exists('readline_completion_function')) { 42 | readline_completion_function(function(){ 43 | return array_merge( 44 | get_defined_functions()['user'], 45 | array_keys(get_defined_constants()) 46 | ); 47 | }); 48 | } 49 | 50 | /* 51 | Setting argv made trivial ... 52 | 53 | argv 1 2 3 4 54 | ^ set argv for next execution 55 | 56 | argv 57 | ^ unset argv for next execution 58 | 59 | */ 60 | function argv() 61 | { 62 | $argv = func_get_args(); 63 | 64 | if (!$argv) { 65 | $_SERVER['argv'] = array(); 66 | $_SERVER['argc'] = 0; 67 | return; 68 | } 69 | 70 | $_SERVER['argv'] = array_merge 71 | ( 72 | array("phpdbg"), 73 | $argv 74 | ); 75 | $_SERVER['argc'] = count($_SERVER['argv']); 76 | 77 | return $_SERVER['argv']; 78 | } 79 | :> 80 | ########################################################## 81 | # Now carry on initializing phpdbg ... 82 | ########################################################## 83 | # R my_debugging_function 84 | # R argv 85 | 86 | ########################################################## 87 | # PHP has many functions that might be useful 88 | # ... you choose ... 89 | ########################################################## 90 | # R touch 91 | # R unlink 92 | # R scandir 93 | # R glob 94 | 95 | ########################################################## 96 | # Remember: *you have access to the shell* 97 | ########################################################## 98 | # The output of registered function calls is not, 99 | # by default, very pretty (unless you implement 100 | # and register a new implementation for phpdbg) 101 | # The output of shell commands will usually be more 102 | # readable on the console 103 | ########################################################## 104 | # TLDR; if you have a good shell, use it ... 105 | ########################################################## 106 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | env: 4 | - PHP="PHP-5.4" 5 | - PHP="PHP-5.5" 6 | - PHP="PHP-5.6" 7 | 8 | before_script: ./travis/ci.sh 9 | 10 | script: 11 | - ./php-src/sapi/cli/php php-src/sapi/phpdbg/tests/run-tests.php -diff2stdout --phpdbg php-src/sapi/phpdbg/phpdbg 12 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | phpdbg 2 | Felipe Pena, Joe Watkins, Bob Weinand 3 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | ChangeLog for phpdbg 2 | ==================== 3 | 4 | Version 0.3.0 2013-00-00 5 | ------------------------ 6 | 7 | 1. Added ability to disable an enable a single breakpoint 8 | 2. Added ability to override SAPI name 9 | 3. Added extended conditional breakpoint support "break at" 10 | 4. Fix loading of zend extnsions with -z 11 | 5. Fix crash when loading .phpdbginit with command line switch 12 | 6. Fix crash on startup errors 13 | 7. Added init.d for remote console (redhat) 14 | 8. Added phpdbg_exec userland function 15 | 9. Added testing facilities 16 | 10. Added break on n-th opline support 17 | 11. Improved trace output 18 | 19 | Version 0.2.0 2013-11-31 20 | ------------------------ 21 | 22 | 1. Added "break delete " command 23 | 2. Added "break opcode " command 24 | 3. Added "set" command - control prompt and console colors 25 | 4. .phpdbginit now searched in (additional) ini dirs 26 | 5. Added source command - load additional .phpdbginit script during session 27 | 6. Added remote console mode 28 | 7. Added info memory command 29 | 30 | Version 0.1.0 2013-11-23 31 | ------------------------ 32 | 33 | 1. New commands: 34 | - until (continue until the current line is executed) 35 | - frame (switch to a frame in the current stack for inspection) 36 | - info (quick access to useful information on the console) 37 | - finish (continue until the current function has returned) 38 | - leave (continue until the current function is returning) 39 | - shell (shell a command) 40 | - register (register a function for use as a command) 41 | 2. Added printers for class and method 42 | 3. Make uniform commands and aliases where possible 43 | 4. Include all alias information and sub-command information in help 44 | 5. Added signal handling to break execution (ctrl-c) 45 | 6. Fixed #13 (Output Buffering Control seems fail) 46 | 7. Fixed #14 (Fixed typo in Makefile.frag) 47 | 48 | 49 | Version 0.0.1 2013-11-15 50 | ------------------------ 51 | 52 | 1. Initial features 53 | -------------------------------------------------------------------------------- /Makefile.frag: -------------------------------------------------------------------------------- 1 | phpdbg: $(BUILD_BINARY) 2 | 3 | phpdbg-shared: $(BUILD_SHARED) 4 | 5 | $(BUILD_SHARED): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) 6 | $(BUILD_PHPDBG_SHARED) 7 | 8 | $(BUILD_BINARY): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS) 9 | $(BUILD_PHPDBG) 10 | 11 | %.c: %.y 12 | %.c: %.l 13 | 14 | $(builddir)/phpdbg_lexer.lo: $(srcdir)/phpdbg_parser.h 15 | 16 | $(srcdir)/phpdbg_lexer.c: $(srcdir)/phpdbg_lexer.l 17 | @(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date -cbdFo $(srcdir)/phpdbg_lexer.c $(srcdir)/phpdbg_lexer.l) 18 | 19 | $(srcdir)/phpdbg_parser.h: $(srcdir)/phpdbg_parser.c 20 | $(srcdir)/phpdbg_parser.c: $(srcdir)/phpdbg_parser.y 21 | @$(YACC) -p phpdbg_ -v -d $(srcdir)/phpdbg_parser.y -o $@ 22 | 23 | install-phpdbg: $(BUILD_BINARY) 24 | @echo "Installing phpdbg binary: $(INSTALL_ROOT)$(bindir)/" 25 | @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir) 26 | @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log 27 | @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run 28 | @$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT) 29 | @echo "Installing phpdbg man page: $(INSTALL_ROOT)$(mandir)/man1/" 30 | @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 31 | @$(INSTALL_DATA) $(srcdir)/phpdbg.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)phpdbg$(program_suffix).1 32 | 33 | clean-phpdbg: 34 | @echo "Cleaning phpdbg object files ..." 35 | find sapi/phpdbg/ -name *.lo -o -name *.o | xargs rm -f 36 | 37 | test-phpdbg: 38 | @echo "Running phpdbg tests ..." 39 | @$(top_builddir)/sapi/cli/php sapi/phpdbg/tests/run-tests.php --phpdbg sapi/phpdbg/phpdbg 40 | 41 | .PHONY: clean-phpdbg test-phpdbg 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The interactive PHP debugger 2 | ============================ 3 | 4 | Implemented as a SAPI module, phpdbg can exert complete control over the environment without impacting the functionality or performance of your code. 5 | 6 | phpdbg aims to be a lightweight, powerful, easy to use debugging platform for PHP 5.4+ 7 | 8 | [![phpdbg on travis-ci](https://travis-ci.org/krakjoe/phpdbg.png?branch=master)](https://travis-ci.org/krakjoe/phpdbg) 9 | 10 | Historical Repository 11 | ===================== 12 | 13 | phpdbg was developed here, then merged into [php-src](https://github.com/php/php-src): This repository is no longer used. 14 | 15 | __Please open issues on [bugsnet](http://bugs.php.net), and send pull requests directly to [php-src](https://github.com/php/php-src).__ 16 | 17 | Features 18 | ======== 19 | 20 | - Stepthrough Debugging 21 | - Flexible Breakpoints (Class Method, Function, File:Line, Address, Opcode) 22 | - Easy Access to PHP with built-in eval() 23 | - Easy Access to Currently Executing Code 24 | - Userland API 25 | - SAPI Agnostic - Easily Integrated 26 | - PHP Configuration File Support 27 | - JIT Super Globals - Set Your Own!! 28 | - Optional readline Support - Comfortable Terminal Operation 29 | - Remote Debugging Support - Bundled Java GUI 30 | - Easy Operation - See Help :) 31 | 32 | Planned 33 | ======= 34 | 35 | - Improve Everything :) 36 | 37 | Installation 38 | ============ 39 | 40 | To install **phpdbg**, you must compile the source against your PHP installation sources, and enable the SAPI with the configure command. 41 | 42 | ``` 43 | cd /usr/src/php-src/sapi 44 | git clone https://github.com/krakjoe/phpdbg 45 | cd ../ 46 | ./buildconf --force 47 | ./configure --enable-phpdbg 48 | make -j8 49 | make install-phpdbg 50 | ``` 51 | 52 | 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 53 | parameters as were used by the last execution of *configure*. 54 | 55 | **Note:** PHP must be configured with the switch --with-readline for phpdbg to support history, autocompletion, tab-listing etc. 56 | 57 | Command Line Options 58 | ==================== 59 | 60 | The following switches are implemented (just like cli SAPI): 61 | 62 | - -n ignore php ini 63 | - -c search for php ini in path 64 | - -z load zend extension 65 | - -d define php ini entry 66 | 67 | The following switches change the default behaviour of phpdbg: 68 | 69 | - -v disables quietness 70 | - -s enabled stepping 71 | - -e sets execution context 72 | - -b boring - disables use of colour on the console 73 | - -I ignore .phpdbginit (default init file) 74 | - -i override .phpgdbinit location (implies -I) 75 | - -O set oplog output file 76 | - -q do not print banner on startup 77 | - -r jump straight to run 78 | - -E enable step through eval() 79 | - -l listen ports for remote mode 80 | - -a listen address for remote mode 81 | - -S override SAPI name 82 | 83 | **Note:** Passing -rr will cause phpdbg to quit after execution, rather than returning to the console. 84 | 85 | Getting Started 86 | =============== 87 | 88 | See the website for tutorials/documentation 89 | 90 | http://php.net/phpdbg 91 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl 2 | dnl $Id$ 3 | dnl 4 | 5 | PHP_ARG_ENABLE(phpdbg, for phpdbg support, 6 | [ --enable-phpdbg Build phpdbg], no, no) 7 | 8 | PHP_ARG_ENABLE(phpdbg-webhelper, for phpdbg web SAPI support, 9 | [ --enable-phpdbg-webhelper Build phpdbg web SAPI support], yes, yes) 10 | 11 | PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build, 12 | [ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) 13 | 14 | if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then 15 | AC_HEADER_TIOCGWINSZ 16 | AC_DEFINE(HAVE_PHPDBG, 1, [ ]) 17 | 18 | if test "$PHP_PHPDBG_DEBUG" != "no"; then 19 | AC_DEFINE(PHPDBG_DEBUG, 1, [ ]) 20 | else 21 | AC_DEFINE(PHPDBG_DEBUG, 0, [ ]) 22 | fi 23 | 24 | if test "$PHP_PHPDBG_WEBHELPER" != "no"; then 25 | if ! test -d $abs_srcdir/ext/phpdbg_webhelper; then 26 | ln -s ../sapi/phpdbg $abs_srcdir/ext/phpdbg_webhelper 27 | fi 28 | PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared) 29 | fi 30 | 31 | PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE" 32 | 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" 33 | 34 | if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then 35 | PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS" 36 | fi 37 | 38 | PHP_SUBST(PHP_PHPDBG_CFLAGS) 39 | PHP_SUBST(PHP_PHPDBG_FILES) 40 | PHP_SUBST(PHPDBG_EXTRA_LIBS) 41 | 42 | PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/phpdbg/Makefile.frag], [$abs_srcdir/sapi/phpdbg], [$abs_builddir/sapi/phpdbg]) 43 | PHP_SELECT_SAPI(phpdbg, program, $PHP_PHPDBG_FILES, $PHP_PHPDBG_CFLAGS, [$(SAPI_PHPDBG_PATH)]) 44 | 45 | BUILD_BINARY="sapi/phpdbg/phpdbg" 46 | BUILD_SHARED="sapi/phpdbg/libphpdbg.la" 47 | 48 | BUILD_PHPDBG="\$(LIBTOOL) --mode=link \ 49 | \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \ 50 | \$(PHP_GLOBAL_OBJS) \ 51 | \$(PHP_BINARY_OBJS) \ 52 | \$(PHP_PHPDBG_OBJS) \ 53 | \$(EXTRA_LIBS) \ 54 | \$(PHPDBG_EXTRA_LIBS) \ 55 | \$(ZEND_EXTRA_LIBS) \ 56 | -o \$(BUILD_BINARY)" 57 | 58 | BUILD_PHPDBG_SHARED="\$(LIBTOOL) --mode=link \ 59 | \$(CC) -shared -Wl,-soname,libphpdbg.so -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \ 60 | \$(PHP_GLOBAL_OBJS) \ 61 | \$(PHP_BINARY_OBJS) \ 62 | \$(PHP_PHPDBG_OBJS) \ 63 | \$(EXTRA_LIBS) \ 64 | \$(PHPDBG_EXTRA_LIBS) \ 65 | \$(ZEND_EXTRA_LIBS) \ 66 | \-DPHPDBG_SHARED \ 67 | -o \$(BUILD_SHARED)" 68 | 69 | PHP_SUBST(BUILD_BINARY) 70 | PHP_SUBST(BUILD_SHARED) 71 | PHP_SUBST(BUILD_PHPDBG) 72 | PHP_SUBST(BUILD_PHPDBG_SHARED) 73 | fi 74 | 75 | dnl ## Local Variables: 76 | dnl ## tab-width: 4 77 | dnl ## End: 78 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | ARG_ENABLE('phpdbg', 'Build phpdbg', 'no'); 2 | ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); 3 | ARG_ENABLE('phpdbg-webhelper', 'Build phpdbg webhelper', 'yes'); 4 | 5 | PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c ' + 6 | 'phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c ' + 7 | 'phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c '+ 8 | 'phpdbg_parser.c phpdbg_lexer.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c ' + 9 | 'phpdbg_sigio_win32.c phpdbg_eol.c phpdbg_out.c'; 10 | PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; 11 | PHPDBG_EXE='phpdbg.exe'; 12 | 13 | if (PHP_PHPDBG == "yes") { 14 | SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); 15 | ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); 16 | ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H"); 17 | ADD_FLAG("LDFLAGS_PHPDBG", "/stack:8388608"); 18 | 19 | if (PHP_PHPDBG_WEBHELPER == "yes") { 20 | EXTENSION('phpdbg_webhelper', 'phpdbg_rinit_hook.c phpdbg_webdata_transfer.c'); 21 | } 22 | } 23 | 24 | if (PHP_PHPDBGS == "yes") { 25 | SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32'); 26 | ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib"); 27 | ADD_FLAG("CFLAGS_PHPDBGS", "/D YY_NO_UNISTD_H"); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /phpdbg.1: -------------------------------------------------------------------------------- 1 | .TH PHPDBG 1 2 | .SH NAME 3 | phpdbg \- The interactive PHP debugger 4 | .SH SYNOPSIS 5 | .B phpdbg 6 | [OPTION] 7 | [\fB\-e\fIFILE\fR] 8 | .SH DESCRIPTION 9 | .B phpdbg 10 | a lightweight, powerful, easy to use debugging platform for PHP5. 11 | .SH OPTIONS 12 | The following switches are implemented (just like cli SAPI): 13 | .TP 14 | .BR \-n 15 | No \fBphp.ini\fR file will be used 16 | .TP 17 | .BR \-c \fIpath\fB|\fIfile\fR 18 | Look for \fBphp.ini\fR file in the directory \fIpath\fR or use the specified \fIfile\fR 19 | .TP 20 | .BR \-z \fIfile\fR 21 | Load Zend extension \fIfile\fR 22 | .TP 23 | .BR \-d \fIfoo\fB[=\fIbar\fB]\fR 24 | Define INI entry \fIfoo\fR with value \fIbar\fR 25 | .PP The following switches change the default behaviour of phpdbg: 26 | .TP 27 | .BR \-v 28 | Disables quietness 29 | .TP 30 | .BR \-s 31 | Enabled stepping 32 | .TP 33 | .BR -e \fIfile\fR 34 | Sets execution context 35 | .TP 36 | .BR \-b 37 | Disables use of colour on the console 38 | .TP 39 | .BR \-I 40 | Ignore .phpdbginit (default init file) 41 | .TP 42 | .BR \-i \fIpath\fB|\ffile\fR 43 | Override .phpgdbinit location (implies -I) 44 | .TP 45 | .BR \-O \fIfile\fR 46 | Set oplog output to \fIfile\fR 47 | .TP 48 | .BR \-q 49 | Do not print banner on startup 50 | .TP 51 | .BR \-r 52 | Jump straight to run 53 | .TP 54 | .BR \-E 55 | Enable step through eval() 56 | .SH NOTES 57 | Passing -rr will cause phpdbg to quit after execution, rather than returning to the console 58 | .SH AUTHOR 59 | Written by Felipe Pena, Joe Watkins and Bob Weinand, formatted by Ondřej Surý for Debian project. 60 | -------------------------------------------------------------------------------- /phpdbg.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_H 22 | #define PHPDBG_H 23 | 24 | #ifdef PHP_WIN32 25 | # define PHPDBG_API __declspec(dllexport) 26 | #elif defined(__GNUC__) && __GNUC__ >= 4 27 | # define PHPDBG_API __attribute__ ((visibility("default"))) 28 | #else 29 | # define PHPDBG_API 30 | #endif 31 | 32 | #ifndef PHP_WIN32 33 | # include 34 | # include 35 | #else 36 | # include "win32/php_stdint.h" 37 | #endif 38 | #include "php.h" 39 | #include "php_globals.h" 40 | #include "php_variables.h" 41 | #include "php_getopt.h" 42 | #include "zend_builtin_functions.h" 43 | #include "zend_extensions.h" 44 | #include "zend_modules.h" 45 | #include "zend_globals.h" 46 | #include "zend_ini_scanner.h" 47 | #include "zend_stream.h" 48 | #ifndef _WIN32 49 | # include "zend_signal.h" 50 | #endif 51 | #include "SAPI.h" 52 | #include 53 | #include 54 | #if defined(_WIN32) && !defined(__MINGW32__) 55 | # include 56 | # include "config.w32.h" 57 | # undef strcasecmp 58 | # undef strncasecmp 59 | # define strcasecmp _stricmp 60 | # define strncasecmp _strnicmp 61 | #else 62 | # include "php_config.h" 63 | #endif 64 | #ifndef O_BINARY 65 | # define O_BINARY 0 66 | #endif 67 | #include "php_main.h" 68 | 69 | #ifdef ZTS 70 | # include "TSRM.h" 71 | #endif 72 | 73 | #ifdef HAVE_LIBREADLINE 74 | # include 75 | # include 76 | #endif 77 | #ifdef HAVE_LIBEDIT 78 | # include 79 | #endif 80 | 81 | /* {{{ remote console headers */ 82 | #ifndef _WIN32 83 | # include 84 | # include 85 | # include 86 | # include 87 | # include 88 | #endif /* }}} */ 89 | 90 | /* {{{ strings */ 91 | #define PHPDBG_NAME "phpdbg" 92 | #define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ 93 | #define PHPDBG_URL "http://phpdbg.com" 94 | #define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" 95 | #define PHPDBG_VERSION "0.4.0" 96 | #define PHPDBG_INIT_FILENAME ".phpdbginit" 97 | #define PHPDBG_DEFAULT_PROMPT "prompt>" 98 | /* }}} */ 99 | 100 | /* Hey, apple. One shouldn't define *functions* from the standard C library as marcos. */ 101 | #ifdef memcpy 102 | #define memcpy_tmp(...) memcpy(__VA_ARGS__) 103 | #undef memcpy 104 | #define memcpy(...) memcpy_tmp(__VA_ARGS__) 105 | #endif 106 | 107 | #if !defined(PHPDBG_WEBDATA_TRANSFER_H) && !defined(PHPDBG_WEBHELPER_H) 108 | 109 | #ifdef ZTS 110 | # define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) 111 | #else 112 | # define PHPDBG_G(v) (phpdbg_globals.v) 113 | #endif 114 | 115 | #include "phpdbg_sigsafe.h" 116 | #include "phpdbg_out.h" 117 | #include "phpdbg_lexer.h" 118 | #include "phpdbg_cmd.h" 119 | #include "phpdbg_utils.h" 120 | #include "phpdbg_btree.h" 121 | #include "phpdbg_watch.h" 122 | #include "phpdbg_bp.h" 123 | #ifdef PHP_WIN32 124 | # include "phpdbg_sigio_win32.h" 125 | #endif 126 | 127 | int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); 128 | 129 | #define PHPDBG_NEXT 2 130 | #define PHPDBG_UNTIL 3 131 | #define PHPDBG_FINISH 4 132 | #define PHPDBG_LEAVE 5 133 | 134 | /* 135 | BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE 136 | */ 137 | 138 | /* {{{ flags */ 139 | #define PHPDBG_HAS_FILE_BP (1ULL<<1) 140 | #define PHPDBG_HAS_PENDING_FILE_BP (1ULL<<2) 141 | #define PHPDBG_HAS_SYM_BP (1ULL<<3) 142 | #define PHPDBG_HAS_OPLINE_BP (1ULL<<4) 143 | #define PHPDBG_HAS_METHOD_BP (1ULL<<5) 144 | #define PHPDBG_HAS_COND_BP (1ULL<<6) 145 | #define PHPDBG_HAS_OPCODE_BP (1ULL<<7) 146 | #define PHPDBG_HAS_FUNCTION_OPLINE_BP (1ULL<<8) 147 | #define PHPDBG_HAS_METHOD_OPLINE_BP (1ULL<<9) 148 | #define PHPDBG_HAS_FILE_OPLINE_BP (1ULL<<10) /* }}} */ 149 | 150 | /* 151 | END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE 152 | */ 153 | 154 | #define PHPDBG_IN_COND_BP (1ULL<<11) 155 | #define PHPDBG_IN_EVAL (1ULL<<12) 156 | 157 | #define PHPDBG_IS_STEPPING (1ULL<<13) 158 | #define PHPDBG_STEP_OPCODE (1ULL<<14) 159 | #define PHPDBG_IS_QUIET (1ULL<<15) 160 | #define PHPDBG_IS_QUITTING (1ULL<<16) 161 | #define PHPDBG_IS_COLOURED (1ULL<<17) 162 | #define PHPDBG_IS_CLEANING (1ULL<<18) 163 | #define PHPDBG_IS_RUNNING (1ULL<<19) 164 | 165 | #define PHPDBG_IN_UNTIL (1ULL<<20) 166 | #define PHPDBG_IN_FINISH (1ULL<<21) 167 | #define PHPDBG_IN_LEAVE (1ULL<<22) 168 | 169 | #define PHPDBG_IS_REGISTERED (1ULL<<23) 170 | #define PHPDBG_IS_STEPONEVAL (1ULL<<24) 171 | #define PHPDBG_IS_INITIALIZING (1ULL<<25) 172 | #define PHPDBG_IS_SIGNALED (1ULL<<26) 173 | #define PHPDBG_IS_INTERACTIVE (1ULL<<27) 174 | #define PHPDBG_IS_BP_ENABLED (1ULL<<28) 175 | #define PHPDBG_IS_REMOTE (1ULL<<29) 176 | #define PHPDBG_IS_DISCONNECTED (1ULL<<30) 177 | #define PHPDBG_WRITE_XML (1ULL<<31) 178 | 179 | #define PHPDBG_SHOW_REFCOUNTS (1ULL<<32) 180 | 181 | #define PHPDBG_IN_SIGNAL_HANDLER (1ULL<<33) 182 | 183 | #define PHPDBG_DISCARD_OUTPUT (1ULL<<34) 184 | 185 | #define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL | PHPDBG_IN_FINISH | PHPDBG_IN_LEAVE) 186 | #define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP) 187 | #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) 188 | #define PHPDBG_IS_STOPPING (PHPDBG_IS_QUITTING | PHPDBG_IS_CLEANING) 189 | 190 | #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) 191 | 192 | #ifndef _WIN32 193 | # define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED) 194 | #else 195 | # define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_BP_ENABLED) 196 | #endif /* }}} */ 197 | 198 | /* {{{ output descriptors */ 199 | #define PHPDBG_STDIN 0 200 | #define PHPDBG_STDOUT 1 201 | #define PHPDBG_STDERR 2 202 | #define PHPDBG_IO_FDS 3 /* }}} */ 203 | 204 | #define phpdbg_try_access \ 205 | { \ 206 | JMP_BUF *__orig_bailout = PHPDBG_G(sigsegv_bailout); \ 207 | JMP_BUF __bailout; \ 208 | \ 209 | PHPDBG_G(sigsegv_bailout) = &__bailout; \ 210 | if (SETJMP(__bailout) == 0) { 211 | #define phpdbg_catch_access \ 212 | } else { \ 213 | PHPDBG_G(sigsegv_bailout) = __orig_bailout; 214 | #define phpdbg_end_try_access() \ 215 | } \ 216 | PHPDBG_G(sigsegv_bailout) = __orig_bailout; \ 217 | } 218 | 219 | 220 | /* {{{ structs */ 221 | ZEND_BEGIN_MODULE_GLOBALS(phpdbg) 222 | HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */ 223 | HashTable registered; /* registered */ 224 | HashTable seek; /* seek oplines */ 225 | phpdbg_frame_t frame; /* frame */ 226 | zend_uint last_line; /* last executed line */ 227 | 228 | phpdbg_lexer_data lexer; /* lexer data */ 229 | phpdbg_param_t *parser_stack; /* param stack during lexer / parser phase */ 230 | 231 | #ifndef _WIN32 232 | struct sigaction old_sigsegv_signal; /* segv signal handler */ 233 | #endif 234 | phpdbg_btree watchpoint_tree; /* tree with watchpoints */ 235 | phpdbg_btree watch_HashTables; /* tree with original dtors of watchpoints */ 236 | HashTable watchpoints; /* watchpoints */ 237 | zend_llist watchlist_mem; /* triggered watchpoints */ 238 | zend_bool watchpoint_hit; /* a watchpoint was hit */ 239 | void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */ 240 | 241 | char *exec; /* file to execute */ 242 | size_t exec_len; /* size of exec */ 243 | zend_op_array *ops; /* op_array */ 244 | zval *retval; /* return value */ 245 | int bp_count; /* breakpoint count */ 246 | int vmret; /* return from last opcode handler execution */ 247 | 248 | zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); 249 | HashTable file_sources; 250 | 251 | FILE *oplog; /* opline log */ 252 | struct { 253 | FILE *ptr; 254 | int fd; 255 | } io[PHPDBG_IO_FDS]; /* io */ 256 | int eol; /* type of line ending to use */ 257 | size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC); 258 | int in_script_xml; /* in output mode */ 259 | struct { 260 | zend_bool active; 261 | int type; 262 | int fd; 263 | char *tag; 264 | char *msg; 265 | int msglen; 266 | char *xml; 267 | int xmllen; 268 | } err_buf; /* error buffer */ 269 | zend_ulong req_id; /* "request id" to keep track of commands */ 270 | 271 | char *prompt[2]; /* prompt */ 272 | const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */ 273 | char *buffer; /* buffer */ 274 | zend_bool last_was_newline; /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */ 275 | 276 | char input_buffer[PHPDBG_MAX_CMD]; /* stdin input buffer */ 277 | int input_buflen; /* length of stdin input buffer */ 278 | phpdbg_signal_safe_mem sigsafe_mem; /* memory to use in async safe environment (only once!) */ 279 | 280 | JMP_BUF *sigsegv_bailout; /* bailout address for accesibility probing */ 281 | 282 | uint64_t flags; /* phpdbg flags */ 283 | 284 | char *socket_path; /* phpdbg.path ini setting */ 285 | char *sapi_name_ptr; /* store sapi name to free it if necessary to not leak memory */ 286 | php_stream *socket_client_stream; /* client stream (wait command) (NULL if unused) */ 287 | php_stream *socket_server_stream; /* server stream (wait command) (NULL if unused) */ 288 | 289 | #ifdef PHP_WIN32 290 | HANDLE sigio_watcher_thread; /* sigio watcher thread handle */ 291 | struct win32_sigio_watcher_data swd; 292 | #endif 293 | 294 | struct _zend_phpdbg_globals *backup; /* backup of data to store */ 295 | ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ 296 | 297 | #endif 298 | 299 | #endif /* PHPDBG_H */ 300 | -------------------------------------------------------------------------------- /phpdbg.init.d: -------------------------------------------------------------------------------- 1 | ################################################################ 2 | # File: /etc/init.d/phpdbg # 3 | # Author: krakjoe # 4 | # Purpose: Daemonize phpdbg automatically on boot # 5 | # chkconfig: 2345 07 09 # 6 | # description: Starts, stops and restarts phpdbg daemon # 7 | ################################################################ 8 | LOCKFILE=/var/lock/subsys/phpdbg 9 | PIDFILE=/var/run/phpdbg.pid 10 | STDIN=4000 11 | STDOUT=8000 12 | ################################################################ 13 | # Either set path to phpdbg here or rely on phpdbg in ENV/PATH # 14 | ################################################################ 15 | if [ "x${PHPDBG}" == "x" ]; then 16 | PHPDBG=$(which phpdbg 2>/dev/null) 17 | fi 18 | ################################################################ 19 | # Options to pass to phpdbg upon boot # 20 | ################################################################ 21 | OPTIONS= 22 | LOGFILE=/var/log/phpdbg.log 23 | ################################################################ 24 | # STOP EDITING STOP EDITING STOP EDITING STOP EDITING # 25 | ################################################################ 26 | . /etc/rc.d/init.d/functions 27 | RETVAL=1 28 | ################################################################ 29 | insanity() 30 | { 31 | if [ "x${PHPDBG}" == "x" ]; then 32 | PHPDBG=$(which phpdbg 2>>/dev/null) 33 | if [ $? != 0 ]; then 34 | echo -n $"Fatal: cannot find phpdbg ${PHPDBG}" 35 | echo_failure 36 | echo 37 | return 1 38 | fi 39 | else 40 | if [ ! -x ${PHPDBG} ]; then 41 | echo -n $"Fatal: cannot execute phpdbg ${PHPDBG}" 42 | echo_failure 43 | echo 44 | return 1 45 | fi 46 | fi 47 | 48 | return 0 49 | } 50 | 51 | start() 52 | { 53 | insanity 54 | 55 | if [ $? -eq 1 ]; then 56 | return $RETVAL 57 | fi 58 | 59 | echo -n $"Starting: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} " 60 | nohup ${PHPDBG} -l${STDIN}/${STDOUT} ${OPTIONS} 2>>${LOGFILE} 1>/dev/null $PIDFILE 65 | echo_success 66 | else 67 | echo_failure 68 | fi 69 | echo 70 | [ $RETVAL = 0 ] && touch ${LOCKFILE} 71 | return $RETVAL 72 | } 73 | 74 | stop() 75 | { 76 | insanity 77 | 78 | if [ $? -eq 1 ]; then 79 | return $RETVAL 80 | fi 81 | 82 | if [ -f ${LOCKFILE} ] && [ -f ${PIDFILE} ] 83 | then 84 | echo -n $"Stopping: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} " 85 | kill -s TERM $(cat $PIDFILE) 86 | RETVAL=$? 87 | if [ $RETVAL -eq 0 ]; then 88 | echo_success 89 | else 90 | echo_failure 91 | fi 92 | echo 93 | [ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE} 94 | else 95 | echo -n $"Error: phpdbg not running" 96 | echo_failure 97 | echo 98 | [ $RETVAL = 1 ] 99 | fi 100 | return $RETVAL 101 | } 102 | ################################################################## 103 | case "$1" in 104 | start) 105 | start 106 | ;; 107 | stop) 108 | stop 109 | ;; 110 | status) 111 | status $PHPDBG 112 | ;; 113 | restart) 114 | $0 stop 115 | $0 start 116 | ;; 117 | *) 118 | echo "usage: $0 start|stop|restart|status" 119 | ;; 120 | esac 121 | ################################################################### 122 | exit $RETVAL 123 | -------------------------------------------------------------------------------- /phpdbg_bp.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_BP_H 22 | #define PHPDBG_BP_H 23 | 24 | /* {{{ defines */ 25 | #define PHPDBG_BREAK_FILE 0 26 | #define PHPDBG_BREAK_FILE_PENDING 1 27 | #define PHPDBG_BREAK_SYM 2 28 | #define PHPDBG_BREAK_OPLINE 3 29 | #define PHPDBG_BREAK_METHOD 4 30 | #define PHPDBG_BREAK_COND 5 31 | #define PHPDBG_BREAK_OPCODE 6 32 | #define PHPDBG_BREAK_FUNCTION_OPLINE 7 33 | #define PHPDBG_BREAK_METHOD_OPLINE 8 34 | #define PHPDBG_BREAK_FILE_OPLINE 9 35 | #define PHPDBG_BREAK_MAP 10 36 | #define PHPDBG_BREAK_TABLES 11 /* }}} */ 37 | 38 | /* {{{ */ 39 | typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */ 40 | 41 | /* {{{ breakpoint base structure */ 42 | #define phpdbg_breakbase(name) \ 43 | int id; \ 44 | zend_uchar type; \ 45 | zend_ulong hits; \ 46 | zend_bool disabled; \ 47 | const char *name /* }}} */ 48 | 49 | /* {{{ breakpoint base */ 50 | typedef struct _phpdbg_breakbase_t { 51 | phpdbg_breakbase(name); 52 | } phpdbg_breakbase_t; /* }}} */ 53 | 54 | /** 55 | * Breakpoint file-based representation 56 | */ 57 | typedef struct _phpdbg_breakfile_t { 58 | phpdbg_breakbase(filename); 59 | long line; 60 | } phpdbg_breakfile_t; 61 | 62 | /** 63 | * Breakpoint symbol-based representation 64 | */ 65 | typedef struct _phpdbg_breaksymbol_t { 66 | phpdbg_breakbase(symbol); 67 | } phpdbg_breaksymbol_t; 68 | 69 | /** 70 | * Breakpoint method based representation 71 | */ 72 | typedef struct _phpdbg_breakmethod_t { 73 | phpdbg_breakbase(class_name); 74 | size_t class_len; 75 | const char *func_name; 76 | size_t func_len; 77 | } phpdbg_breakmethod_t; 78 | 79 | /** 80 | * Breakpoint opline num based representation 81 | */ 82 | typedef struct _phpdbg_breakopline_t { 83 | phpdbg_breakbase(func_name); 84 | size_t func_len; 85 | const char *class_name; 86 | size_t class_len; 87 | zend_ulong opline_num; 88 | zend_ulong opline; 89 | } phpdbg_breakopline_t; 90 | 91 | /** 92 | * Breakpoint opline based representation 93 | */ 94 | typedef struct _phpdbg_breakline_t { 95 | phpdbg_breakbase(name); 96 | zend_ulong opline; 97 | phpdbg_breakopline_t *base; 98 | } phpdbg_breakline_t; 99 | 100 | /** 101 | * Breakpoint opcode based representation 102 | */ 103 | typedef struct _phpdbg_breakop_t { 104 | phpdbg_breakbase(name); 105 | zend_ulong hash; 106 | } phpdbg_breakop_t; 107 | 108 | /** 109 | * Breakpoint condition based representation 110 | */ 111 | typedef struct _phpdbg_breakcond_t { 112 | phpdbg_breakbase(code); 113 | size_t code_len; 114 | zend_bool paramed; 115 | phpdbg_param_t param; 116 | zend_ulong hash; 117 | zend_op_array *ops; 118 | } phpdbg_breakcond_t; 119 | 120 | /* {{{ Resolving breaks API */ 121 | PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC); 122 | PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC); 123 | PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); 124 | PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, const char *cur, uint curlen, HashTable *fileht TSRMLS_DC); 125 | PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC); /* }}} */ 126 | 127 | /* {{{ Breakpoint Creation API */ 128 | PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC); 129 | PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len TSRMLS_DC); 130 | PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name TSRMLS_DC); 131 | PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len TSRMLS_DC); 132 | PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC); 133 | PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC); 134 | PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC); 135 | PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC); 136 | PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC); 137 | PHPDBG_API void phpdbg_set_breakpoint_expression(const char* expression, size_t expression_len TSRMLS_DC); 138 | PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param TSRMLS_DC); /* }}} */ 139 | 140 | /* {{{ Breakpoint Detection API */ 141 | PHPDBG_API phpdbg_breakbase_t* phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC); /* }}} */ 142 | 143 | /* {{{ Misc Breakpoint API */ 144 | PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t* brake, zend_bool output TSRMLS_DC); 145 | PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC); 146 | PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t* brake TSRMLS_DC); 147 | PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D); 148 | PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D); 149 | PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC); 150 | PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D); 151 | PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC); 152 | PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC); 153 | PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D); /* }}} */ 154 | 155 | /* {{{ Breakbase API */ 156 | PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC); 157 | PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC); /* }}} */ 158 | 159 | /* {{{ Breakpoint Exportation API */ 160 | PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); 161 | PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str TSRMLS_DC); /* }}} */ 162 | 163 | #endif /* PHPDBG_BP_H */ 164 | -------------------------------------------------------------------------------- /phpdbg_break.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include "phpdbg.h" 22 | #include "phpdbg_print.h" 23 | #include "phpdbg_utils.h" 24 | #include "phpdbg_opcode.h" 25 | #include "phpdbg_break.h" 26 | #include "phpdbg_bp.h" 27 | #include "phpdbg_prompt.h" 28 | 29 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 30 | 31 | #define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s, flags) \ 32 | PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[10], flags) 33 | 34 | /** 35 | * Commands 36 | */ 37 | const phpdbg_command_t phpdbg_break_commands[] = { 38 | PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c", 0), 39 | PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n", 0), 40 | PHPDBG_END_COMMAND 41 | }; 42 | 43 | PHPDBG_BREAK(at) /* {{{ */ 44 | { 45 | phpdbg_set_breakpoint_at(param TSRMLS_CC); 46 | 47 | return SUCCESS; 48 | } /* }}} */ 49 | 50 | PHPDBG_BREAK(del) /* {{{ */ 51 | { 52 | phpdbg_delete_breakpoint(param->num TSRMLS_CC); 53 | 54 | return SUCCESS; 55 | } /* }}} */ 56 | -------------------------------------------------------------------------------- /phpdbg_break.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_BREAK_H 22 | #define PHPDBG_BREAK_H 23 | 24 | #include "TSRM.h" 25 | #include "phpdbg_cmd.h" 26 | 27 | #define PHPDBG_BREAK(name) PHPDBG_COMMAND(break_##name) 28 | 29 | /** 30 | * Printer Forward Declarations 31 | */ 32 | PHPDBG_BREAK(at); 33 | PHPDBG_BREAK(del); 34 | 35 | extern const phpdbg_command_t phpdbg_break_commands[]; 36 | 37 | #endif /* PHPDBG_BREAK_H */ 38 | -------------------------------------------------------------------------------- /phpdbg_btree.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include "phpdbg_btree.h" 22 | #include "phpdbg.h" 23 | 24 | #define CHOOSE_BRANCH(n) \ 25 | branch = branch->branches[!!(n)]; 26 | 27 | #ifdef _Win32 28 | # define emalloc malloc 29 | # define efree free 30 | #endif 31 | 32 | /* depth in bits */ 33 | void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth) { 34 | tree->depth = depth; 35 | tree->branch = NULL; 36 | tree->count = 0; 37 | } 38 | 39 | phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx) { 40 | phpdbg_btree_branch *branch = tree->branch; 41 | int i = tree->depth - 1; 42 | 43 | if (branch == NULL) { 44 | return NULL; 45 | } 46 | 47 | do { 48 | if ((idx >> i) % 2 == 1) { 49 | if (branch->branches[1]) { 50 | CHOOSE_BRANCH(1); 51 | } else { 52 | return NULL; 53 | } 54 | } else { 55 | if (branch->branches[0]) { 56 | CHOOSE_BRANCH(0); 57 | } else { 58 | return NULL; 59 | } 60 | } 61 | } while (i--); 62 | 63 | return &branch->result; 64 | } 65 | 66 | phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong idx) { 67 | phpdbg_btree_branch *branch = tree->branch; 68 | int i = tree->depth - 1, last_superior_i = -1; 69 | zend_bool had_alternative_branch = 0; 70 | 71 | if (branch == NULL) { 72 | return NULL; 73 | } 74 | 75 | /* find nearest watchpoint */ 76 | do { 77 | /* an impossible branch was found if: */ 78 | if (!had_alternative_branch && (idx >> i) % 2 == 0 && !branch->branches[0]) { 79 | /* there's no lower branch than idx */ 80 | if (last_superior_i == -1) { 81 | /* failure */ 82 | return NULL; 83 | } 84 | /* reset state */ 85 | branch = tree->branch; 86 | i = tree->depth - 1; 87 | /* follow branch according to bits in idx until the last lower branch before the impossible branch */ 88 | do { 89 | CHOOSE_BRANCH((idx >> i) % 2 == 1 && branch->branches[1]); 90 | } while (--i > last_superior_i); 91 | /* use now the lower branch of which we can be sure that it contains only branches lower than idx */ 92 | CHOOSE_BRANCH(0); 93 | /* and choose the highest possible branch in the branch containing only branches lower than idx */ 94 | while (i--) { 95 | CHOOSE_BRANCH(branch->branches[1]); 96 | } 97 | break; 98 | } 99 | /* follow branch according to bits in idx until having found an impossible branch */ 100 | if (had_alternative_branch || (idx >> i) % 2 == 1) { 101 | if (branch->branches[1]) { 102 | if (branch->branches[0]) { 103 | last_superior_i = i; 104 | } 105 | CHOOSE_BRANCH(1); 106 | } else { 107 | CHOOSE_BRANCH(0); 108 | had_alternative_branch = 1; 109 | } 110 | } else { 111 | CHOOSE_BRANCH(0); 112 | } 113 | } while (i--); 114 | 115 | return &branch->result; 116 | } 117 | 118 | phpdbg_btree_position phpdbg_btree_find_between(phpdbg_btree *tree, zend_ulong lower_idx, zend_ulong higher_idx) { 119 | phpdbg_btree_position pos; 120 | 121 | pos.tree = tree; 122 | pos.end = lower_idx; 123 | pos.cur = higher_idx; 124 | 125 | return pos; 126 | } 127 | 128 | phpdbg_btree_result *phpdbg_btree_next(phpdbg_btree_position *pos) { 129 | phpdbg_btree_result *result = phpdbg_btree_find_closest(pos->tree, pos->cur); 130 | 131 | if (result == NULL || result->idx < pos->end) { 132 | return NULL; 133 | } 134 | 135 | pos->cur = result->idx - 1; 136 | 137 | return result; 138 | } 139 | 140 | int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, int flags) { 141 | int i = tree->depth - 1; 142 | phpdbg_btree_branch **branch = &tree->branch; 143 | 144 | do { 145 | if (*branch == NULL) { 146 | break; 147 | } 148 | branch = &(*branch)->branches[(idx >> i) % 2]; 149 | } while (i--); 150 | 151 | if (*branch == NULL) { 152 | if (!(flags & PHPDBG_BTREE_INSERT)) { 153 | return FAILURE; 154 | } 155 | 156 | { 157 | phpdbg_btree_branch *memory = *branch = emalloc((i + 2) * sizeof(phpdbg_btree_branch)); 158 | do { 159 | (*branch)->branches[!((idx >> i) % 2)] = NULL; 160 | branch = &(*branch)->branches[(idx >> i) % 2]; 161 | *branch = ++memory; 162 | } while (i--); 163 | tree->count++; 164 | } 165 | } else if (!(flags & PHPDBG_BTREE_UPDATE)) { 166 | return FAILURE; 167 | } 168 | 169 | (*branch)->result.idx = idx; 170 | (*branch)->result.ptr = ptr; 171 | 172 | return SUCCESS; 173 | } 174 | 175 | int phpdbg_btree_delete(phpdbg_btree *tree, zend_ulong idx) { 176 | int i = tree->depth; 177 | phpdbg_btree_branch *branch = tree->branch; 178 | int i_last_dual_branch = -1, last_dual_branch_branch; 179 | phpdbg_btree_branch *last_dual_branch = NULL; 180 | 181 | goto check_branch_existence; 182 | do { 183 | if (branch->branches[0] && branch->branches[1]) { 184 | last_dual_branch = branch; 185 | i_last_dual_branch = i; 186 | last_dual_branch_branch = (idx >> i) % 2; 187 | } 188 | branch = branch->branches[(idx >> i) % 2]; 189 | 190 | check_branch_existence: 191 | if (branch == NULL) { 192 | return FAILURE; 193 | } 194 | } while (i--); 195 | 196 | tree->count--; 197 | 198 | if (i_last_dual_branch == -1) { 199 | efree(tree->branch); 200 | tree->branch = NULL; 201 | } else { 202 | if (last_dual_branch->branches[last_dual_branch_branch] == last_dual_branch + 1) { 203 | phpdbg_btree_branch *original_branch = last_dual_branch->branches[!last_dual_branch_branch]; 204 | 205 | memcpy(last_dual_branch + 1, last_dual_branch->branches[!last_dual_branch_branch], (i_last_dual_branch + 1) * sizeof(phpdbg_btree_branch)); 206 | efree(last_dual_branch->branches[!last_dual_branch_branch]); 207 | last_dual_branch->branches[!last_dual_branch_branch] = last_dual_branch + 1; 208 | 209 | branch = last_dual_branch->branches[!last_dual_branch_branch]; 210 | for (i = i_last_dual_branch; i--;) { 211 | branch = (branch->branches[branch->branches[1] == ++original_branch] = last_dual_branch + i_last_dual_branch - i + 1); 212 | } 213 | } else { 214 | efree(last_dual_branch->branches[last_dual_branch_branch]); 215 | } 216 | 217 | last_dual_branch->branches[last_dual_branch_branch] = NULL; 218 | } 219 | 220 | return SUCCESS; 221 | } 222 | -------------------------------------------------------------------------------- /phpdbg_btree.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_BTREE_H 22 | #define PHPDBG_BTREE_H 23 | 24 | #include "zend.h" 25 | 26 | typedef struct { 27 | zend_ulong idx; 28 | void *ptr; 29 | } phpdbg_btree_result; 30 | 31 | typedef union _phpdbg_btree_branch phpdbg_btree_branch; 32 | union _phpdbg_btree_branch { 33 | phpdbg_btree_branch *branches[2]; 34 | phpdbg_btree_result result; 35 | }; 36 | 37 | typedef struct { 38 | zend_ulong count; 39 | zend_ulong depth; 40 | phpdbg_btree_branch *branch; 41 | } phpdbg_btree; 42 | 43 | typedef struct { 44 | phpdbg_btree *tree; 45 | zend_ulong cur; 46 | zend_ulong end; 47 | } phpdbg_btree_position; 48 | 49 | void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth); 50 | phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx); 51 | phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong idx); 52 | phpdbg_btree_position phpdbg_btree_find_between(phpdbg_btree *tree, zend_ulong lower_idx, zend_ulong higher_idx); 53 | phpdbg_btree_result *phpdbg_btree_next(phpdbg_btree_position *pos); 54 | int phpdbg_btree_delete(phpdbg_btree *tree, zend_ulong idx); 55 | 56 | #define PHPDBG_BTREE_INSERT 1 57 | #define PHPDBG_BTREE_UPDATE 2 58 | #define PHPDBG_BTREE_OVERWRITE (PHPDBG_BTREE_INSERT | PHPDBG_BTREE_UPDATE) 59 | 60 | int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, int flags); 61 | #define phpdbg_btree_insert(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_INSERT) 62 | #define phpdbg_btree_update(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_UPDATE) 63 | #define phpdbg_btree_overwrite(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_OWERWRITE) 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /phpdbg_cmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_CMD_H 22 | #define PHPDBG_CMD_H 23 | 24 | #include "TSRM.h" 25 | 26 | /* {{{ Command and Parameter */ 27 | enum { 28 | NO_ARG = 0, 29 | REQUIRED_ARG, 30 | OPTIONAL_ARG 31 | }; 32 | 33 | typedef enum { 34 | EMPTY_PARAM = 0, 35 | ADDR_PARAM, 36 | FILE_PARAM, 37 | NUMERIC_FILE_PARAM, 38 | METHOD_PARAM, 39 | STR_PARAM, 40 | NUMERIC_PARAM, 41 | NUMERIC_FUNCTION_PARAM, 42 | NUMERIC_METHOD_PARAM, 43 | STACK_PARAM, 44 | EVAL_PARAM, 45 | SHELL_PARAM, 46 | COND_PARAM, 47 | OP_PARAM, 48 | ORIG_PARAM, 49 | RUN_PARAM 50 | } phpdbg_param_type; 51 | 52 | typedef struct _phpdbg_param phpdbg_param_t; 53 | struct _phpdbg_param { 54 | phpdbg_param_type type; 55 | long num; 56 | zend_ulong addr; 57 | struct { 58 | char *name; 59 | long line; 60 | } file; 61 | struct { 62 | char *class; 63 | char *name; 64 | } method; 65 | char *str; 66 | size_t len; 67 | phpdbg_param_t *next; 68 | phpdbg_param_t *top; 69 | }; 70 | 71 | #define phpdbg_init_param(v, t) do{ \ 72 | (v)->type = (t); \ 73 | (v)->addr = 0; \ 74 | (v)->num = 0; \ 75 | (v)->file.name = NULL; \ 76 | (v)->file.line = 0; \ 77 | (v)->method.class = NULL; \ 78 | (v)->method.name = NULL; \ 79 | (v)->str = NULL; \ 80 | (v)->len = 0; \ 81 | (v)->next = NULL; \ 82 | (v)->top = NULL; \ 83 | } while(0) 84 | 85 | #ifndef YYSTYPE 86 | #define YYSTYPE phpdbg_param_t 87 | #endif 88 | 89 | #define PHPDBG_ASYNC_SAFE 1 90 | 91 | typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t* TSRMLS_DC); 92 | 93 | typedef struct _phpdbg_command_t phpdbg_command_t; 94 | struct _phpdbg_command_t { 95 | const char *name; /* Command name */ 96 | size_t name_len; /* Command name length */ 97 | const char *tip; /* Menu tip */ 98 | size_t tip_len; /* Menu tip length */ 99 | char alias; /* Alias */ 100 | phpdbg_command_handler_t handler; /* Command handler */ 101 | const phpdbg_command_t *subs; /* Sub Commands */ 102 | char *args; /* Argument Spec */ 103 | const phpdbg_command_t *parent; /* Parent Command */ 104 | zend_bool flags; /* General flags */ 105 | }; 106 | /* }}} */ 107 | 108 | /* {{{ misc */ 109 | #define PHPDBG_STRL(s) s, sizeof(s)-1 110 | #define PHPDBG_MAX_CMD 500 111 | #define PHPDBG_FRAME(v) (PHPDBG_G(frame).v) 112 | #define PHPDBG_EX(v) (EG(current_execute_data)->v) 113 | 114 | typedef struct { 115 | int num; 116 | zend_execute_data *execute_data; 117 | } phpdbg_frame_t; 118 | /* }}} */ 119 | 120 | /* 121 | * Workflow: 122 | * 1) the lexer/parser creates a stack of commands and arguments from input 123 | * 2) the commands at the top of the stack are resolved sensibly using aliases, abbreviations and case insensitive matching 124 | * 3) the remaining arguments in the stack are verified (optionally) against the handlers declared argument specification 125 | * 4) the handler is called passing the top of the stack as the only parameter 126 | * 5) the stack is destroyed upon return from the handler 127 | */ 128 | 129 | /* 130 | * Input Management 131 | */ 132 | PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC); 133 | PHPDBG_API void phpdbg_destroy_input(char** TSRMLS_DC); 134 | PHPDBG_API int phpdbg_ask_user_permission(const char *question TSRMLS_DC); 135 | 136 | /** 137 | * Stack Management 138 | */ 139 | PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param); 140 | 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); 141 | PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC); 142 | PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC); 143 | PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack); 144 | 145 | /* 146 | * Parameter Management 147 | */ 148 | PHPDBG_API void phpdbg_clear_param(phpdbg_param_t* TSRMLS_DC); 149 | PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t*, phpdbg_param_t* TSRMLS_DC); 150 | PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *, const phpdbg_param_t * TSRMLS_DC); 151 | PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t * TSRMLS_DC); 152 | PHPDBG_API const char* phpdbg_get_param_type(const phpdbg_param_t* TSRMLS_DC); 153 | PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC); 154 | PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg); 155 | 156 | /** 157 | * Command Declarators 158 | */ 159 | #define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name 160 | 161 | #define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent, flags) \ 162 | {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent, flags} 163 | 164 | #define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args, flags) \ 165 | {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL, flags} 166 | 167 | #define PHPDBG_COMMAND_D(name, tip, alias, children, args, flags) \ 168 | {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL, flags} 169 | 170 | #define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param TSRMLS_DC) 171 | 172 | #define PHPDBG_COMMAND_ARGS param TSRMLS_CC 173 | 174 | #define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, NULL, NULL, 0} 175 | 176 | /* 177 | * Default Switch Case 178 | */ 179 | #define phpdbg_default_switch_case() \ 180 | default: \ 181 | phpdbg_error("command", "type=\"wrongarg\" got=\"%s\"", "Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \ 182 | break 183 | 184 | #endif /* PHPDBG_CMD_H */ 185 | -------------------------------------------------------------------------------- /phpdbg_eol.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Anatol Belski | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | # include "config.h" 21 | #endif 22 | 23 | #include "phpdbg.h" 24 | #include "phpdbg_eol.h" 25 | 26 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 27 | 28 | #define EOL_LIST_LEN 4 29 | struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = { 30 | {"CRLF", "\r\n", PHPDBG_EOL_CRLF}, 31 | /* {"LFCR", "\n\r", PHPDBG_EOL_LFCR},*/ 32 | {"LF", "\n", PHPDBG_EOL_LF}, 33 | {"CR", "\r", PHPDBG_EOL_CR}, 34 | }; 35 | 36 | int phpdbg_eol_global_update(char *name TSRMLS_DC) 37 | { 38 | 39 | if (0 == memcmp(name, "CRLF", 4) || 0 == memcmp(name, "crlf", 4) || 0 == memcmp(name, "DOS", 3) || 0 == memcmp(name, "dos", 3)) { 40 | PHPDBG_G(eol) = PHPDBG_EOL_CRLF; 41 | } else if (0 == memcmp(name, "LF", 2) || 0 == memcmp(name, "lf", 2) || 0 == memcmp(name, "UNIX", 4) || 0 == memcmp(name, "unix", 4)) { 42 | PHPDBG_G(eol) = PHPDBG_EOL_LF; 43 | } else if (0 == memcmp(name, "CR", 2) || 0 == memcmp(name, "cr", 2) || 0 == memcmp(name, "MAC", 3) || 0 == memcmp(name, "mac", 3)) { 44 | PHPDBG_G(eol) = PHPDBG_EOL_CR; 45 | } else { 46 | return FAILURE; 47 | } 48 | 49 | return SUCCESS; 50 | } 51 | 52 | char *phpdbg_eol_name(int id) 53 | { 54 | size_t i = 0; 55 | 56 | while (i < EOL_LIST_LEN) { 57 | 58 | if (id == phpdbg_eol_list[i].id) { 59 | return phpdbg_eol_list[i].name; 60 | } 61 | 62 | i++; 63 | } 64 | 65 | return NULL; 66 | } 67 | 68 | char *phpdbg_eol_rep(int id) 69 | { 70 | size_t i = 0; 71 | 72 | while (i < EOL_LIST_LEN) { 73 | 74 | if (id == phpdbg_eol_list[i].id) { 75 | return phpdbg_eol_list[i].rep; 76 | } 77 | 78 | i++; 79 | } 80 | 81 | return NULL; 82 | } 83 | 84 | 85 | /* Inspired by https://ccrma.stanford.edu/~craig/utility/flip/flip.cpp */ 86 | void phpdbg_eol_convert(char **str, int *len TSRMLS_DC) 87 | { 88 | char *in = *str, *out ; 89 | int in_len = *len, out_len, cursor, i; 90 | char last, cur; 91 | 92 | if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) != PHPDBG_IS_REMOTE) { 93 | return; 94 | } 95 | 96 | out_len = *len; 97 | if (PHPDBG_EOL_CRLF == PHPDBG_G(eol)) { /* XXX add LFCR case if it's gonna be needed */ 98 | /* depending on the source EOL the out str will have all CR/LF duplicated */ 99 | for (i = 0; i < in_len; i++) { 100 | if (0x0a == in[i] || 0x0d == in[i]) { 101 | out_len++; 102 | } 103 | } 104 | out = (char *)emalloc(out_len); 105 | 106 | last = cur = in[0]; 107 | i = cursor = 0; 108 | for (; i < in_len;) { 109 | if (0x0a == cur && last != 0x0d) { 110 | out[cursor] = 0x0d; 111 | cursor++; 112 | out[cursor] = cur; 113 | } else if(0x0d == cur) { 114 | if (i + 1 < in_len && 0x0a != in[i+1]) { 115 | out[cursor] = cur; 116 | cursor++; 117 | out[cursor] = 0x0a; 118 | last = 0x0a; 119 | } else { 120 | out[cursor] = 0x0d; 121 | last = 0x0d; 122 | } 123 | } else { 124 | out[cursor] = cur; 125 | last = cur; 126 | } 127 | 128 | i++; 129 | cursor++; 130 | cur = in[i]; 131 | } 132 | 133 | } else if (PHPDBG_EOL_LF == PHPDBG_G(eol) || PHPDBG_EOL_CR == PHPDBG_G(eol)) { 134 | char want, kick; 135 | 136 | if (PHPDBG_EOL_LF == PHPDBG_G(eol)) { 137 | want = 0x0a; 138 | kick = 0x0d; 139 | } else { 140 | want = 0x0d; 141 | kick = 0x0a; 142 | } 143 | 144 | /* We gonna have a smaller or equally long string, estimation is almost neglecting */ 145 | out = (char *)emalloc(out_len); 146 | 147 | last = cur = in[0]; 148 | i = cursor = 0; 149 | for (; cursor < in_len;) { 150 | if (kick == cur) { 151 | out[cursor] = want; 152 | } else if (want == cur) { 153 | if (kick != last) { 154 | out[cursor] = want; 155 | } 156 | } else { 157 | out[cursor] = cur; 158 | } 159 | 160 | last = cur; 161 | cursor++; 162 | cur = in[cursor]; 163 | } 164 | } else { 165 | return; 166 | } 167 | 168 | efree(*str); 169 | *str = erealloc(out, cursor); 170 | *len = cursor; 171 | in = NULL; 172 | } 173 | -------------------------------------------------------------------------------- /phpdbg_eol.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Anatol Belski | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef PHPDBG_EOL_H 20 | #define PHPDBG_EOL_H 21 | 22 | #include "phpdbg.h" 23 | 24 | struct phpdbg_eol_rep { 25 | char *name; 26 | char *rep; 27 | int id; 28 | }; 29 | 30 | enum { 31 | PHPDBG_EOL_CRLF, /* DOS */ 32 | /*PHPDBG_EOL_LFCR,*/ /* for Risc OS? */ 33 | PHPDBG_EOL_LF, /* UNIX */ 34 | PHPDBG_EOL_CR /* MAC */ 35 | }; 36 | 37 | int phpdbg_eol_global_update(char *name TSRMLS_DC); 38 | 39 | char *phpdbg_eol_name(int id); 40 | 41 | char *phpdbg_eol_rep(int id); 42 | 43 | void phpdbg_eol_convert(char **str, int *len TSRMLS_DC); 44 | 45 | #endif /* PHPDBG_EOL_H */ 46 | 47 | -------------------------------------------------------------------------------- /phpdbg_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include "zend.h" 22 | #include "phpdbg.h" 23 | #include "phpdbg_utils.h" 24 | #include "phpdbg_frame.h" 25 | #include "phpdbg_list.h" 26 | 27 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 28 | 29 | #if PHP_VERSION_ID < 50600 30 | ZEND_EXTERN_MODULE_GLOBALS(output); 31 | #endif 32 | 33 | void phpdbg_restore_frame(TSRMLS_D) /* {{{ */ 34 | { 35 | if (PHPDBG_FRAME(num) == 0) { 36 | return; 37 | } 38 | 39 | PHPDBG_FRAME(num) = 0; 40 | 41 | /* move things back */ 42 | EG(current_execute_data) = PHPDBG_FRAME(execute_data); 43 | 44 | EG(opline_ptr) = &PHPDBG_EX(opline); 45 | EG(active_op_array) = PHPDBG_EX(op_array); 46 | EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value); 47 | EG(active_symbol_table) = PHPDBG_EX(symbol_table); 48 | EG(This) = PHPDBG_EX(current_this); 49 | EG(scope) = PHPDBG_EX(current_scope); 50 | EG(called_scope) = PHPDBG_EX(current_called_scope); 51 | } /* }}} */ 52 | 53 | void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ 54 | { 55 | zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data); 56 | int i = 0; 57 | 58 | if (PHPDBG_FRAME(num) == frame) { 59 | phpdbg_notice("frame", "id=\"%d\"", "Already in frame #%d", frame); 60 | return; 61 | } 62 | 63 | phpdbg_try_access { 64 | while (execute_data) { 65 | if (i++ == frame) { 66 | break; 67 | } 68 | 69 | do { 70 | execute_data = execute_data->prev_execute_data; 71 | } while (execute_data && execute_data->opline == NULL); 72 | } 73 | } phpdbg_catch_access { 74 | phpdbg_error("signalsegv", "", "Couldn't switch frames, invalid data source"); 75 | return; 76 | } phpdbg_end_try_access(); 77 | 78 | if (execute_data == NULL) { 79 | phpdbg_error("frame", "type=\"maxnum\" id=\"%d\"", "No frame #%d", frame); 80 | return; 81 | } 82 | 83 | phpdbg_restore_frame(TSRMLS_C); 84 | 85 | if (frame > 0) { 86 | PHPDBG_FRAME(num) = frame; 87 | 88 | /* backup things and jump back */ 89 | PHPDBG_FRAME(execute_data) = EG(current_execute_data); 90 | EG(current_execute_data) = execute_data; 91 | 92 | EG(opline_ptr) = &PHPDBG_EX(opline); 93 | EG(active_op_array) = PHPDBG_EX(op_array); 94 | PHPDBG_FRAME(execute_data)->original_return_value = EG(return_value_ptr_ptr); 95 | EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value); 96 | EG(active_symbol_table) = PHPDBG_EX(symbol_table); 97 | EG(This) = PHPDBG_EX(current_this); 98 | EG(scope) = PHPDBG_EX(current_scope); 99 | EG(called_scope) = PHPDBG_EX(current_called_scope); 100 | } 101 | 102 | phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame); 103 | phpdbg_list_file( 104 | zend_get_executed_filename(TSRMLS_C), 105 | 3, 106 | zend_get_executed_lineno(TSRMLS_C)-1, 107 | zend_get_executed_lineno(TSRMLS_C) 108 | TSRMLS_CC 109 | ); 110 | } /* }}} */ 111 | 112 | static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */ 113 | { 114 | zval **funcname, **class, **type, **args, **argstmp; 115 | char is_class; 116 | int has_args = FAILURE; 117 | int name_len; 118 | zval **file = NULL; 119 | 120 | zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"), (void **) &funcname); 121 | 122 | zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **) &file); 123 | 124 | if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "object", sizeof("object"), (void **) &class)) == FAILURE) { 125 | is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"), (void **)&class); 126 | } else { 127 | zend_get_object_classname(*class, (const char **) &Z_STRVAL_PP(class), (zend_uint *) &Z_STRLEN_PP(class) TSRMLS_CC); 128 | } 129 | 130 | if (is_class == SUCCESS) { 131 | zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type); 132 | } 133 | 134 | has_args = zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"), (void **)&args) == SUCCESS; 135 | 136 | phpdbg_xml(" symbol=\"%s%s%s\"", 137 | is_class == FAILURE?"":Z_STRVAL_PP(class), 138 | is_class == FAILURE?"":Z_STRVAL_PP(type), 139 | Z_STRVAL_PP(funcname) 140 | ); 141 | if (has_args) { 142 | phpdbg_xml(">"); 143 | } else { 144 | phpdbg_xml(" />"); 145 | } 146 | 147 | name_len = phpdbg_out("%s%s%s(", 148 | is_class == FAILURE?"":Z_STRVAL_PP(class), 149 | is_class == FAILURE?"":Z_STRVAL_PP(type), 150 | Z_STRVAL_PP(funcname) 151 | ); 152 | 153 | if (has_args) { 154 | HashPosition iterator; 155 | const zend_function *func = NULL; 156 | const zend_arg_info *arginfo = NULL; 157 | int j = 0, m; 158 | int termwidth = phpdbg_get_terminal_width(TSRMLS_C); 159 | int arglen; 160 | zend_bool is_variadic = 0; 161 | 162 | if (termwidth < 120) { 163 | termwidth = 120; 164 | } 165 | 166 | phpdbg_try_access { 167 | /* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */ 168 | if ((func = phpdbg_get_function(Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC))) { 169 | arginfo = func->common.arg_info; 170 | } 171 | } phpdbg_end_try_access(); 172 | 173 | m = func ? func->common.num_args : 0; 174 | 175 | if (m) { 176 | arglen = (termwidth - name_len - 20 - (file ? Z_STRLEN_PP(file) : 0)) / m - 10; 177 | if (arglen < 20) { 178 | arglen = 20; 179 | } 180 | } 181 | 182 | zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator); 183 | while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args), (void **) &argstmp, &iterator) == SUCCESS) { 184 | if (j) { 185 | phpdbg_out(", "); 186 | } 187 | phpdbg_xml("= 50600 190 | is_variadic = arginfo ? arginfo[j].is_variadic : 0; 191 | #endif 192 | phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arginfo ? arginfo[j].name : ""); 193 | phpdbg_out("%s=%s", arginfo ? arginfo[j].name : "?", is_variadic ? "[": ""); 194 | 195 | } else { 196 | phpdbg_xml(">"); 197 | } 198 | ++j; 199 | 200 | phpdbg_xml_var_dump(argstmp TSRMLS_CC); 201 | /* zend_print_flat_zval_r(*argstmp TSRMLS_CC);*/ 202 | phpdbg_print_flat_zval_r(argstmp, arglen TSRMLS_CC); 203 | 204 | zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator); 205 | 206 | phpdbg_xml(""); 207 | } 208 | if (is_variadic) { 209 | phpdbg_out("]"); 210 | } 211 | phpdbg_xml(""); 212 | } 213 | phpdbg_out(")"); 214 | } 215 | 216 | void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ 217 | { 218 | zval zbacktrace; 219 | zval **tmp; 220 | zval **file, **line; 221 | HashPosition position; 222 | int i = 0, limit = num; 223 | int user_defined; 224 | 225 | PHPDBG_OUTPUT_BACKUP(); 226 | 227 | if (limit < 0) { 228 | phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit); 229 | 230 | PHPDBG_OUTPUT_BACKUP_RESTORE(); 231 | return; 232 | } 233 | 234 | phpdbg_try_access { 235 | zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit TSRMLS_CC); 236 | } phpdbg_catch_access { 237 | phpdbg_error("signalsegv", "", "Couldn't fetch backtrace, invalid data source"); 238 | return; 239 | } phpdbg_end_try_access(); 240 | 241 | phpdbg_xml(""); 242 | 243 | zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position); 244 | zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void **) &tmp, &position); 245 | while (1) { 246 | user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **) &file); 247 | zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **) &line); 248 | zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position); 249 | 250 | if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void **) &tmp, &position) == FAILURE) { 251 | 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)); 252 | break; 253 | } 254 | 255 | if (user_defined == SUCCESS) { 256 | phpdbg_out("frame #%d: ", i); 257 | phpdbg_xml(" "); 263 | phpdbg_xml(""); 271 | 272 | zval_dtor(&zbacktrace); 273 | 274 | PHPDBG_OUTPUT_BACKUP_RESTORE(); 275 | } /* }}} */ 276 | -------------------------------------------------------------------------------- /phpdbg_frame.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_FRAME_H 22 | #define PHPDBG_FRAME_H 23 | 24 | #include "TSRM.h" 25 | 26 | void phpdbg_restore_frame(TSRMLS_D); 27 | void phpdbg_switch_frame(int TSRMLS_DC); 28 | void phpdbg_dump_backtrace(size_t TSRMLS_DC); 29 | 30 | #endif /* PHPDBG_FRAME_H */ 31 | -------------------------------------------------------------------------------- /phpdbg_help.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_HELP_H 22 | #define PHPDBG_HELP_H 23 | 24 | #include "TSRM.h" 25 | #include "phpdbg.h" 26 | #include "phpdbg_cmd.h" 27 | 28 | #define PHPDBG_HELP(name) PHPDBG_COMMAND(help_##name) 29 | 30 | /** 31 | * Helper Forward Declarations 32 | */ 33 | PHPDBG_HELP(aliases); 34 | 35 | extern const phpdbg_command_t phpdbg_help_commands[]; 36 | 37 | #define phpdbg_help_header() \ 38 | phpdbg_notice("version", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); 39 | #define phpdbg_help_footer() \ 40 | phpdbg_notice("issues", "url=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES); 41 | 42 | typedef struct _phpdbg_help_text_t { 43 | char *key; 44 | char *text; 45 | } phpdbg_help_text_t; 46 | 47 | extern phpdbg_help_text_t phpdbg_help_text[]; 48 | #endif /* PHPDBG_HELP_H */ 49 | -------------------------------------------------------------------------------- /phpdbg_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_INFO_H 22 | #define PHPDBG_INFO_H 23 | 24 | #include "phpdbg_cmd.h" 25 | 26 | #define PHPDBG_INFO(name) PHPDBG_COMMAND(info_##name) 27 | 28 | PHPDBG_INFO(files); 29 | PHPDBG_INFO(break); 30 | PHPDBG_INFO(classes); 31 | PHPDBG_INFO(funcs); 32 | PHPDBG_INFO(error); 33 | PHPDBG_INFO(constants); 34 | PHPDBG_INFO(vars); 35 | PHPDBG_INFO(globals); 36 | PHPDBG_INFO(literal); 37 | PHPDBG_INFO(memory); 38 | 39 | extern const phpdbg_command_t phpdbg_info_commands[]; 40 | 41 | #endif /* PHPDBG_INFO_H */ 42 | -------------------------------------------------------------------------------- /phpdbg_io.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Anatol Belski | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | #include "config.h" 21 | #endif 22 | 23 | #include "phpdbg_io.h" 24 | 25 | #ifdef PHP_WIN32 26 | #undef UNICODE 27 | #include "win32/inet.h" 28 | #include 29 | #include 30 | #include 31 | #include "win32/sockets.h" 32 | 33 | #else 34 | 35 | #if HAVE_SYS_TYPES_H 36 | #include 37 | #endif 38 | #include 39 | #include 40 | #if HAVE_ARPA_INET_H 41 | #include 42 | #endif 43 | #include 44 | #include 45 | #include 46 | #endif 47 | 48 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 49 | 50 | /* is easy to generalize ... but not needed for now */ 51 | PHPDBG_API int phpdbg_consume_stdin_line(char *buf TSRMLS_DC) { 52 | int bytes = PHPDBG_G(input_buflen), len = 0; 53 | 54 | if (PHPDBG_G(input_buflen)) { 55 | memcpy(buf, PHPDBG_G(input_buffer), bytes); 56 | } 57 | 58 | PHPDBG_G(last_was_newline) = 1; 59 | 60 | do { 61 | int i; 62 | if (bytes <= 0) { 63 | continue; 64 | } 65 | 66 | for (i = len; i < len + bytes; i++) { 67 | if (buf[i] == '\x03') { 68 | if (i != len + bytes - 1) { 69 | memmove(buf + i, buf + i + 1, len + bytes - i - 1); 70 | } 71 | len--; 72 | i--; 73 | continue; 74 | } 75 | if (buf[i] == '\n') { 76 | PHPDBG_G(input_buflen) = len + bytes - 1 - i; 77 | if (PHPDBG_G(input_buflen)) { 78 | memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen)); 79 | } 80 | if (i != PHPDBG_MAX_CMD - 1) { 81 | buf[i + 1] = 0; 82 | } 83 | return i; 84 | } 85 | } 86 | 87 | len += bytes; 88 | } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0); 89 | 90 | if (bytes <= 0) { 91 | PHPDBG_G(flags) |= PHPDBG_IS_QUITTING | PHPDBG_IS_DISCONNECTED; 92 | zend_bailout(); 93 | return 0; 94 | } 95 | 96 | return bytes; 97 | } 98 | 99 | PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC) { 100 | int got_now, i = len, j; 101 | char *p = ptr; 102 | #ifndef PHP_WIN32 103 | struct pollfd pfd; 104 | 105 | if (tmo < 0) goto recv_once; 106 | pfd.fd = sock; 107 | pfd.events = POLLIN; 108 | 109 | j = poll(&pfd, 1, tmo); 110 | 111 | if (j == 0) { 112 | #else 113 | struct fd_set readfds; 114 | struct timeval ttmo; 115 | 116 | if (tmo < 0) goto recv_once; 117 | FD_ZERO(&readfds); 118 | FD_SET(sock, &readfds); 119 | 120 | ttmo.tv_sec = 0; 121 | ttmo.tv_usec = tmo*1000; 122 | 123 | j = select(0, &readfds, NULL, NULL, &ttmo); 124 | 125 | if (j <= 0) { 126 | #endif 127 | return -1; 128 | } 129 | 130 | recv_once: 131 | while(i > 0) { 132 | if (tmo < 0) { 133 | /* There's something to read. Read what's available and proceed 134 | disregarding whether len could be exhausted or not.*/ 135 | int can_read = recv(sock, p, i, MSG_PEEK); 136 | #ifndef _WIN32 137 | if (can_read == -1 && errno == EINTR) { 138 | continue; 139 | } 140 | #endif 141 | i = can_read; 142 | } 143 | 144 | #ifdef _WIN32 145 | got_now = recv(sock, p, i, 0); 146 | #else 147 | do { 148 | got_now = recv(sock, p, i, 0); 149 | } while (got_now == -1 && errno == EINTR); 150 | #endif 151 | 152 | if (got_now == -1) { 153 | write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Read operation timed out!\n")); 154 | return -1; 155 | } 156 | i -= got_now; 157 | p += got_now; 158 | } 159 | 160 | return p - ptr; 161 | } 162 | 163 | PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len) { 164 | int sent, i = len; 165 | const char *p = ptr; 166 | /* XXX poll/select needed here? */ 167 | while(i > 0) { 168 | sent = send(sock, p, i, 0); 169 | if (sent == -1) { 170 | return -1; 171 | } 172 | i -= sent; 173 | p += sent; 174 | } 175 | 176 | return len; 177 | } 178 | 179 | 180 | PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC) { 181 | if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { 182 | return phpdbg_consume_bytes(sock, ptr, len, tmo TSRMLS_CC); 183 | } 184 | 185 | return read(sock, ptr, len); 186 | } 187 | 188 | 189 | PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC) { 190 | if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { 191 | return phpdbg_send_bytes(sock, ptr, len); 192 | } 193 | 194 | return write(sock, ptr, len); 195 | } 196 | 197 | 198 | PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC) { 199 | struct addrinfo res; 200 | int fd = phpdbg_create_listenable_socket(interface, port, &res TSRMLS_CC); 201 | 202 | if (fd == -1) { 203 | return -1; 204 | } 205 | 206 | if (bind(fd, res.ai_addr, res.ai_addrlen) == -1) { 207 | phpdbg_close_socket(fd); 208 | return -4; 209 | } 210 | 211 | listen(fd, 5); 212 | 213 | return fd; 214 | } 215 | 216 | 217 | PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *addr_res TSRMLS_DC) { 218 | int sock = -1, rc; 219 | int reuse = 1; 220 | struct in6_addr serveraddr; 221 | struct addrinfo hints, *res = NULL; 222 | char port_buf[8]; 223 | int8_t any_addr = *addr == '*'; 224 | 225 | do { 226 | memset(&hints, 0, sizeof hints); 227 | if (any_addr) { 228 | hints.ai_flags = AI_PASSIVE; 229 | } else { 230 | hints.ai_flags = AI_NUMERICSERV; 231 | } 232 | hints.ai_family = AF_UNSPEC; 233 | hints.ai_socktype = SOCK_STREAM; 234 | 235 | rc = inet_pton(AF_INET, addr, &serveraddr); 236 | if (1 == rc) { 237 | hints.ai_family = AF_INET; 238 | if (!any_addr) { 239 | hints.ai_flags |= AI_NUMERICHOST; 240 | } 241 | } else { 242 | rc = inet_pton(AF_INET6, addr, &serveraddr); 243 | if (1 == rc) { 244 | hints.ai_family = AF_INET6; 245 | if (!any_addr) { 246 | hints.ai_flags |= AI_NUMERICHOST; 247 | } 248 | } else { 249 | /* XXX get host by name ??? */ 250 | } 251 | } 252 | 253 | snprintf(port_buf, 7, "%u", port); 254 | if (!any_addr) { 255 | rc = getaddrinfo(addr, port_buf, &hints, &res); 256 | } else { 257 | rc = getaddrinfo(NULL, port_buf, &hints, &res); 258 | } 259 | 260 | if (0 != rc) { 261 | #ifndef PHP_WIN32 262 | if (rc == EAI_SYSTEM) { 263 | char buf[128]; 264 | int wrote; 265 | 266 | wrote = snprintf(buf, 128, "Could not translate address '%s'", addr); 267 | buf[wrote] = '\0'; 268 | write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); 269 | 270 | return sock; 271 | } else { 272 | #endif 273 | char buf[256]; 274 | int wrote; 275 | 276 | wrote = snprintf(buf, 256, "Host '%s' not found. %s", addr, estrdup(gai_strerror(rc))); 277 | buf[wrote] = '\0'; 278 | write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); 279 | 280 | return sock; 281 | #ifndef PHP_WIN32 282 | } 283 | #endif 284 | return sock; 285 | } 286 | 287 | if((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { 288 | char buf[128]; 289 | int wrote; 290 | 291 | wrote = sprintf(buf, "Unable to create socket"); 292 | buf[wrote] = '\0'; 293 | write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); 294 | 295 | return sock; 296 | } 297 | 298 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)) == -1) { 299 | phpdbg_close_socket(sock); 300 | return sock; 301 | } 302 | 303 | 304 | } while (0); 305 | 306 | *addr_res = *res; 307 | 308 | return sock; 309 | } 310 | 311 | PHPDBG_API void phpdbg_close_socket(int sock) { 312 | if (socket >= 0) { 313 | #ifdef _WIN32 314 | closesocket(sock); 315 | #else 316 | shutdown(sock, SHUT_RDWR); 317 | close(sock); 318 | #endif 319 | } 320 | } 321 | 322 | -------------------------------------------------------------------------------- /phpdbg_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Anatol Belski | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef PHPDBG_IO_H 20 | #define PHPDBG_IO_H 21 | 22 | #include "phpdbg.h" 23 | 24 | PHPDBG_API int phpdbg_consume_stdin_line(char *buf TSRMLS_DC); 25 | 26 | PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC); 27 | PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len); 28 | PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC); 29 | PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC); 30 | 31 | PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *res TSRMLS_DC); 32 | PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC); 33 | PHPDBG_API void phpdbg_close_socket(int sock); 34 | 35 | #endif /* PHPDBG_IO_H */ 36 | 37 | -------------------------------------------------------------------------------- /phpdbg_lexer.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_LEXER_H 22 | #define PHPDBG_LEXER_H 23 | 24 | #include "phpdbg_cmd.h" 25 | 26 | typedef struct { 27 | unsigned int len; 28 | unsigned char *text; 29 | unsigned char *cursor; 30 | unsigned char *marker; 31 | int state; 32 | } phpdbg_lexer_data; 33 | 34 | #define yyparse phpdbg_parse 35 | #define yylex phpdbg_lex 36 | 37 | void phpdbg_init_lexer (phpdbg_param_t *stack, char *input TSRMLS_DC); 38 | 39 | int phpdbg_lex (phpdbg_param_t* yylval); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /phpdbg_lexer.l: -------------------------------------------------------------------------------- 1 | /* 2 | * phpdbg_lexer.l 3 | */ 4 | 5 | #include "phpdbg.h" 6 | #include "phpdbg_cmd.h" 7 | 8 | #include "phpdbg_parser.h" 9 | 10 | #define LEX(v) (PHPDBG_G(lexer).v) 11 | 12 | #define YYCTYPE unsigned char 13 | #define YYSETCONDITION(x) LEX(state) = x; 14 | #define YYGETCONDITION() LEX(state) 15 | #define YYCURSOR LEX(cursor) 16 | #define YYMARKER LEX(marker) 17 | #define yyleng LEX(len) 18 | #define yytext ((char*) LEX(text)) 19 | #undef YYDEBUG 20 | #define YYDEBUG(a, b) 21 | #define YYFILL(n) 22 | 23 | #define NORMAL 0 24 | #define PRE_RAW 1 25 | #define RAW 2 26 | #define INITIAL 3 27 | 28 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 29 | 30 | void phpdbg_init_lexer (phpdbg_param_t *stack, char *input TSRMLS_DC) { 31 | PHPDBG_G(parser_stack) = stack; 32 | 33 | YYSETCONDITION(INITIAL); 34 | 35 | LEX(text) = YYCURSOR = (unsigned char *) input; 36 | LEX(len) = strlen(input); 37 | } 38 | 39 | int phpdbg_lex (phpdbg_param_t* yylval) { 40 | TSRMLS_FETCH(); /* Slow, but this is not a major problem here. TODO: Use TSRMLS_DC */ 41 | 42 | restart: 43 | LEX(text) = YYCURSOR; 44 | 45 | /*!re2c 46 | re2c:yyfill:check = 0; 47 | T_TRUE 'true' 48 | T_YES 'yes' 49 | T_ON 'on' 50 | T_ENABLED 'enabled' 51 | T_FALSE 'false' 52 | T_NO 'no' 53 | T_OFF 'off' 54 | T_DISABLED 'disabled' 55 | T_EVAL 'ev' 56 | T_SHELL 'sh' 57 | T_IF 'if' 58 | T_RUN 'run' 59 | T_RUN_SHORT "r" 60 | WS [ \r\n\t]+ 61 | DIGITS [-]?[0-9\.]+ 62 | ID [^ \r\n\t:#\000]+ 63 | ADDR [0][x][a-fA-F0-9]+ 64 | OPCODE (ZEND_|zend_)([A-Za-z])+ 65 | INPUT [^\n\000]+ 66 | 67 | := yyleng = (size_t) YYCURSOR - (size_t) yytext; 68 | 69 | <*>{WS}?[\n\000] { 70 | return 0; 71 | } 72 | 73 | [-][r]{WS}?{DIGITS} { 74 | char *text = yytext + 2; 75 | while (*++text < '0'); 76 | yylval->num = atoi(text); 77 | return T_REQ_ID; 78 | } 79 | 80 | {T_IF}{WS} { 81 | YYSETCONDITION(RAW); 82 | phpdbg_init_param(yylval, EMPTY_PARAM); 83 | return T_IF; 84 | } 85 | 86 | {ID}[:]{1}[//]{2} { 87 | phpdbg_init_param(yylval, STR_PARAM); 88 | yylval->str = zend_strndup(yytext, yyleng); 89 | yylval->len = yyleng; 90 | return T_PROTO; 91 | } 92 | [#]{1} { 93 | return T_POUND; 94 | } 95 | [:]{2} { 96 | return T_DCOLON; 97 | } 98 | [:]{1} { 99 | return T_COLON; 100 | } 101 | 102 | ({T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE}){WS} { 103 | phpdbg_init_param(yylval, NUMERIC_PARAM); 104 | yylval->num = 1; 105 | return T_TRUTHY; 106 | } 107 | 108 | ({T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE}){WS} { 109 | phpdbg_init_param(yylval, NUMERIC_PARAM); 110 | yylval->num = 0; 111 | return T_FALSY; 112 | } 113 | 114 | {DIGITS} { 115 | phpdbg_init_param(yylval, NUMERIC_PARAM); 116 | yylval->num = atoi(yytext); 117 | return T_DIGITS; 118 | } 119 | 120 | {ADDR} { 121 | phpdbg_init_param(yylval, ADDR_PARAM); 122 | yylval->addr = strtoul(yytext, 0, 16); 123 | return T_ADDR; 124 | } 125 | 126 | {OPCODE} { 127 | phpdbg_init_param(yylval, OP_PARAM); 128 | yylval->str = zend_strndup(yytext, yyleng); 129 | yylval->len = yyleng; 130 | return T_OPCODE; 131 | } 132 | 133 | {ID} { 134 | phpdbg_init_param(yylval, STR_PARAM); 135 | yylval->str = zend_strndup(yytext, yyleng); 136 | yylval->len = yyleng; 137 | return T_ID; 138 | } 139 | 140 | {INPUT} { 141 | phpdbg_init_param(yylval, STR_PARAM); 142 | yylval->str = zend_strndup(yytext, yyleng); 143 | yylval->len = yyleng; 144 | return T_INPUT; 145 | } 146 | 147 | <*>{WS} { 148 | /* ignore whitespace */ 149 | 150 | goto restart; 151 | } 152 | 153 | {T_EVAL}{WS} { 154 | YYSETCONDITION(PRE_RAW); 155 | phpdbg_init_param(yylval, EMPTY_PARAM); 156 | return T_EVAL; 157 | } 158 | {T_SHELL}{WS} { 159 | YYSETCONDITION(PRE_RAW); 160 | phpdbg_init_param(yylval, EMPTY_PARAM); 161 | return T_SHELL; 162 | } 163 | ({T_RUN}|{T_RUN_SHORT}){WS} { 164 | YYSETCONDITION(PRE_RAW); 165 | phpdbg_init_param(yylval, EMPTY_PARAM); 166 | return T_RUN; 167 | } 168 | 169 | . { 170 | YYSETCONDITION(RAW); 171 | 172 | YYCURSOR = LEX(text); 173 | goto restart; 174 | } 175 | 176 | . { 177 | YYSETCONDITION(NORMAL); 178 | 179 | YYCURSOR = LEX(text); 180 | goto restart; 181 | } 182 | 183 | */ 184 | } 185 | -------------------------------------------------------------------------------- /phpdbg_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #ifndef _WIN32 25 | # include 26 | # include 27 | #endif 28 | #include 29 | #include "phpdbg.h" 30 | #include "phpdbg_list.h" 31 | #include "phpdbg_utils.h" 32 | #include "phpdbg_prompt.h" 33 | #include "php_streams.h" 34 | 35 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 36 | 37 | #define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s, flags) \ 38 | PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13], flags) 39 | 40 | const phpdbg_command_t phpdbg_list_commands[] = { 41 | PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l", PHPDBG_ASYNC_SAFE), 42 | PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s", PHPDBG_ASYNC_SAFE), 43 | PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m", PHPDBG_ASYNC_SAFE), 44 | PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s", PHPDBG_ASYNC_SAFE), 45 | PHPDBG_END_COMMAND 46 | }; 47 | 48 | PHPDBG_LIST(lines) /* {{{ */ 49 | { 50 | if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) { 51 | phpdbg_error("inactive", "type=\"execution\"", "Not executing, and execution context not set"); 52 | return SUCCESS; 53 | } 54 | 55 | switch (param->type) { 56 | case NUMERIC_PARAM: 57 | phpdbg_list_file(phpdbg_current_file(TSRMLS_C), 58 | (param->num < 0 ? 1 - param->num : param->num), 59 | (param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), 60 | 0 TSRMLS_CC); 61 | break; 62 | 63 | case FILE_PARAM: 64 | phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC); 65 | break; 66 | 67 | phpdbg_default_switch_case(); 68 | } 69 | 70 | return SUCCESS; 71 | } /* }}} */ 72 | 73 | PHPDBG_LIST(func) /* {{{ */ 74 | { 75 | phpdbg_list_function_byname(param->str, param->len TSRMLS_CC); 76 | 77 | return SUCCESS; 78 | } /* }}} */ 79 | 80 | PHPDBG_LIST(method) /* {{{ */ 81 | { 82 | zend_class_entry **ce; 83 | 84 | if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { 85 | zend_function *function; 86 | char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); 87 | 88 | if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) { 89 | phpdbg_list_function(function TSRMLS_CC); 90 | } else { 91 | phpdbg_error("list", "type=\"notfound\" method=\"%s::%s\"", "Could not find %s::%s", param->method.class, param->method.name); 92 | } 93 | 94 | efree(lcname); 95 | } else { 96 | phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "Could not find the class %s", param->method.class); 97 | } 98 | 99 | return SUCCESS; 100 | } /* }}} */ 101 | 102 | PHPDBG_LIST(class) /* {{{ */ 103 | { 104 | zend_class_entry **ce; 105 | 106 | if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { 107 | if ((*ce)->type == ZEND_USER_CLASS) { 108 | if ((*ce)->info.user.filename) { 109 | phpdbg_list_file( 110 | (*ce)->info.user.filename, 111 | (*ce)->info.user.line_end - (*ce)->info.user.line_start + 1, 112 | (*ce)->info.user.line_start, 0 TSRMLS_CC 113 | ); 114 | } else { 115 | phpdbg_error("list", "type=\"nosource\" class=\"%s\"", "The source of the requested class (%s) cannot be found", (*ce)->name); 116 | } 117 | } else { 118 | phpdbg_error("list", "type=\"internalclass\" class=\"%s\"", "The class requested (%s) is not user defined", (*ce)->name); 119 | } 120 | } else { 121 | phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "The requested class (%s) could not be found", param->str); 122 | } 123 | 124 | return SUCCESS; 125 | } /* }}} */ 126 | 127 | void phpdbg_list_file(const char *filename, uint count, int offset, uint highlight TSRMLS_DC) /* {{{ */ 128 | { 129 | uint line, lastline; 130 | phpdbg_file_source **data; 131 | char resolved_path_buf[MAXPATHLEN]; 132 | 133 | if (VCWD_REALPATH(filename, resolved_path_buf)) { 134 | filename = resolved_path_buf; 135 | } 136 | 137 | if (zend_hash_find(&PHPDBG_G(file_sources), filename, strlen(filename), (void **) &data) == FAILURE) { 138 | phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file..."); 139 | return; 140 | } 141 | 142 | if (offset < 0) { 143 | count += offset; 144 | offset = 0; 145 | } 146 | 147 | lastline = offset + count; 148 | 149 | if (lastline > (*data)->lines) { 150 | lastline = (*data)->lines; 151 | } 152 | 153 | phpdbg_xml("", filename); 154 | 155 | for (line = offset; line < lastline;) { 156 | uint linestart = (*data)->line[line++]; 157 | uint linelen = (*data)->line[line] - linestart; 158 | char *buffer = (*data)->buf + linestart; 159 | 160 | if (!highlight) { 161 | phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer); 162 | } else { 163 | if (highlight != line) { 164 | phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer); 165 | } else { 166 | phpdbg_write("line", "line=\"%u\" code=\"%.*s\" current=\"current\"", ">%05u: %.*s", line, linelen, buffer); 167 | } 168 | } 169 | 170 | if (*(buffer + linelen - 1) != '\n' || !linelen) { 171 | phpdbg_out("\n"); 172 | } 173 | } 174 | 175 | phpdbg_xml(""); 176 | } /* }}} */ 177 | 178 | void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */ 179 | { 180 | const zend_op_array *ops; 181 | 182 | if (fbc->type != ZEND_USER_FUNCTION) { 183 | phpdbg_error("list", "type=\"internalfunction\" function=\"%s\"", "The function requested (%s) is not user defined", fbc->common.function_name); 184 | return; 185 | } 186 | 187 | ops = (zend_op_array *)fbc; 188 | 189 | phpdbg_list_file(ops->filename, ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC); 190 | } /* }}} */ 191 | 192 | void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */ 193 | { 194 | HashTable *func_table = EG(function_table); 195 | zend_function* fbc; 196 | char *func_name = (char*) str; 197 | size_t func_name_len = len; 198 | 199 | /* search active scope if begins with period */ 200 | if (func_name[0] == '.') { 201 | if (EG(scope)) { 202 | func_name++; 203 | func_name_len--; 204 | 205 | func_table = &EG(scope)->function_table; 206 | } else { 207 | phpdbg_error("inactive", "type=\"noclasses\"", "No active class"); 208 | return; 209 | } 210 | } else if (!EG(function_table)) { 211 | phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded"); 212 | return; 213 | } else { 214 | func_table = EG(function_table); 215 | } 216 | 217 | /* use lowercase names, case insensitive */ 218 | func_name = zend_str_tolower_dup(func_name, func_name_len); 219 | 220 | phpdbg_try_access { 221 | if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) { 222 | phpdbg_list_function(fbc TSRMLS_CC); 223 | } else { 224 | phpdbg_error("list", "type=\"nofunction\" function=\"%s\"", "Function %s not found", func_name); 225 | } 226 | } phpdbg_catch_access { 227 | phpdbg_error("signalsegv", "function=\"%s\"", "Could not list function %s, invalid data source", func_name); 228 | } phpdbg_end_try_access(); 229 | 230 | efree(func_name); 231 | } /* }}} */ 232 | 233 | zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) { 234 | phpdbg_file_source data, *dataptr; 235 | zend_file_handle fake = {0}; 236 | zend_op_array *ret; 237 | char *filename = (char *)(file->opened_path ? file->opened_path : file->filename); 238 | uint line; 239 | char *bufptr, *endptr; 240 | char resolved_path_buf[MAXPATHLEN]; 241 | 242 | zend_stream_fixup(file, &data.buf, &data.len TSRMLS_CC); 243 | 244 | data.filename = filename; 245 | data.line[0] = 0; 246 | 247 | if (file->handle.stream.mmap.old_closer) { 248 | /* do not unmap */ 249 | file->handle.stream.closer = file->handle.stream.mmap.old_closer; 250 | } 251 | 252 | #if HAVE_MMAP 253 | if (file->handle.stream.mmap.map) { 254 | data.map = file->handle.stream.mmap.map; 255 | } 256 | #endif 257 | 258 | fake.type = ZEND_HANDLE_MAPPED; 259 | fake.handle.stream.mmap.buf = data.buf; 260 | fake.handle.stream.mmap.len = data.len; 261 | fake.free_filename = 0; 262 | fake.opened_path = file->opened_path; 263 | fake.filename = filename; 264 | fake.opened_path = file->opened_path; 265 | 266 | *(dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * data.len)) = data; 267 | if (VCWD_REALPATH(filename, resolved_path_buf)) { 268 | filename = resolved_path_buf; 269 | } 270 | zend_hash_add(&PHPDBG_G(file_sources), filename, strlen(filename), &dataptr, sizeof(phpdbg_file_source *), NULL); 271 | 272 | for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) { 273 | if (*bufptr == '\n') { 274 | dataptr->line[++line] = (uint)(bufptr - data.buf) + 1; 275 | } 276 | } 277 | dataptr->lines = ++line; 278 | dataptr->line[line] = endptr - data.buf; 279 | dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line); 280 | 281 | phpdbg_resolve_pending_file_break(filename TSRMLS_CC); 282 | 283 | ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC); 284 | 285 | fake.opened_path = NULL; 286 | zend_file_handle_dtor(&fake TSRMLS_CC); 287 | 288 | return ret; 289 | } 290 | 291 | void phpdbg_free_file_source(phpdbg_file_source *data) { 292 | #if HAVE_MMAP 293 | if (data->map) { 294 | munmap(data->map, data->len + ZEND_MMAP_AHEAD); 295 | } else 296 | #endif 297 | if (data->buf) { 298 | efree(data->buf); 299 | } 300 | 301 | efree(data); 302 | } 303 | 304 | void phpdbg_init_list(TSRMLS_D) { 305 | PHPDBG_G(compile_file) = zend_compile_file; 306 | zend_hash_init(&PHPDBG_G(file_sources), 1, NULL, (dtor_func_t) phpdbg_free_file_source, 0); 307 | zend_compile_file = phpdbg_compile_file; 308 | } 309 | -------------------------------------------------------------------------------- /phpdbg_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_LIST_H 22 | #define PHPDBG_LIST_H 23 | 24 | #include "TSRM.h" 25 | #include "phpdbg_cmd.h" 26 | 27 | #define PHPDBG_LIST(name) PHPDBG_COMMAND(list_##name) 28 | #define PHPDBG_LIST_HANDLER(name) PHPDBG_COMMAND_HANDLER(list_##name) 29 | 30 | PHPDBG_LIST(lines); 31 | PHPDBG_LIST(class); 32 | PHPDBG_LIST(method); 33 | PHPDBG_LIST(func); 34 | 35 | void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC); 36 | void phpdbg_list_function(const zend_function* TSRMLS_DC); 37 | void phpdbg_list_file(const char*, uint, int, uint TSRMLS_DC); 38 | 39 | extern const phpdbg_command_t phpdbg_list_commands[]; 40 | 41 | void phpdbg_init_list(TSRMLS_D); 42 | 43 | typedef struct { 44 | char *filename; 45 | char *buf; 46 | size_t len; 47 | #if HAVE_MMAP 48 | void *map; 49 | #endif 50 | uint lines; 51 | uint line[1]; 52 | } phpdbg_file_source; 53 | 54 | #endif /* PHPDBG_LIST_H */ 55 | -------------------------------------------------------------------------------- /phpdbg_opcode.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include "phpdbg.h" 22 | #include "zend_vm_opcodes.h" 23 | #include "zend_compile.h" 24 | #include "phpdbg_opcode.h" 25 | #include "phpdbg_utils.h" 26 | 27 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 28 | 29 | static inline zend_uint phpdbg_decode_literal(zend_op_array *ops, zend_literal *literal TSRMLS_DC) /* {{{ */ 30 | { 31 | int iter = 0; 32 | 33 | while (iter < ops->last_literal) { 34 | if (literal == &ops->literals[iter]) { 35 | return iter; 36 | } 37 | iter++; 38 | } 39 | 40 | return 0; 41 | } /* }}} */ 42 | 43 | static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint type, HashTable *vars TSRMLS_DC) /* {{{ */ 44 | { 45 | char *decode = NULL; 46 | 47 | switch (type &~ EXT_TYPE_UNUSED) { 48 | case IS_CV: 49 | asprintf(&decode, "$%s", ops->vars[op->var].name); 50 | break; 51 | 52 | case IS_VAR: 53 | case IS_TMP_VAR: { 54 | zend_ulong id = 0, *pid = NULL; 55 | if (vars != NULL) { 56 | if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) { 57 | id = zend_hash_num_elements(vars); 58 | zend_hash_index_update( 59 | vars, (zend_ulong) ops->vars - op->var, 60 | (void**) &id, 61 | sizeof(zend_ulong), NULL); 62 | } else id = *pid; 63 | } 64 | asprintf(&decode, "@%lu", id); 65 | } break; 66 | 67 | case IS_CONST: 68 | asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->literal TSRMLS_CC)); 69 | break; 70 | 71 | case IS_UNUSED: 72 | asprintf(&decode, ""); 73 | break; 74 | } 75 | return decode; 76 | } /* }}} */ 77 | 78 | char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC) /*{{{ */ 79 | { 80 | char *decode[4] = {NULL, NULL, NULL, NULL}; 81 | 82 | switch (op->opcode) { 83 | case ZEND_JMP: 84 | #ifdef ZEND_GOTO 85 | case ZEND_GOTO: 86 | #endif 87 | #ifdef ZEND_FAST_CALL 88 | case ZEND_FAST_CALL: 89 | #endif 90 | asprintf(&decode[1], "J%ld", op->op1.jmp_addr - ops->opcodes); 91 | goto format; 92 | 93 | case ZEND_JMPZNZ: 94 | decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); 95 | asprintf(&decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value); 96 | goto result; 97 | 98 | case ZEND_JMPZ: 99 | case ZEND_JMPNZ: 100 | case ZEND_JMPZ_EX: 101 | case ZEND_JMPNZ_EX: 102 | 103 | #ifdef ZEND_JMP_SET 104 | case ZEND_JMP_SET: 105 | #endif 106 | decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); 107 | asprintf(&decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes); 108 | goto result; 109 | 110 | case ZEND_RECV_INIT: 111 | goto result; 112 | 113 | default: { 114 | decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); 115 | decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars TSRMLS_CC); 116 | result: 117 | decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC); 118 | format: 119 | asprintf(&decode[0], 120 | "%-20s %-20s %-20s", 121 | decode[1] ? decode[1] : "", 122 | decode[2] ? decode[2] : "", 123 | decode[3] ? decode[3] : ""); 124 | } 125 | } 126 | 127 | if (decode[1]) 128 | free(decode[1]); 129 | if (decode[2]) 130 | free(decode[2]); 131 | if (decode[3]) 132 | free(decode[3]); 133 | 134 | return decode[0]; 135 | } /* }}} */ 136 | 137 | void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC) /* {{{ */ 138 | { 139 | /* force out a line while stepping so the user knows what is happening */ 140 | if (ignore_flags || 141 | (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || 142 | (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) || 143 | (PHPDBG_G(oplog)))) { 144 | 145 | zend_op *opline = execute_data->opline; 146 | char *decode = phpdbg_decode_opline(execute_data->op_array, opline, vars TSRMLS_CC); 147 | 148 | if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) { 149 | /* output line info */ 150 | phpdbg_notice("opline", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\" file=\"%s\"", "L%-5u %16p %-30s %s %s", 151 | opline->lineno, 152 | opline, 153 | phpdbg_decode_opcode(opline->opcode), 154 | decode, 155 | execute_data->op_array->filename ? execute_data->op_array->filename : "unknown"); 156 | } 157 | 158 | if (!ignore_flags && PHPDBG_G(oplog)) { 159 | phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %-30s %s %s", 160 | opline->lineno, 161 | opline, 162 | phpdbg_decode_opcode(opline->opcode), 163 | decode, 164 | execute_data->op_array->filename ? execute_data->op_array->filename : "unknown"); 165 | } 166 | 167 | if (decode) { 168 | free(decode); 169 | } 170 | } 171 | } /* }}} */ 172 | 173 | void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC) /* {{{ */ 174 | { 175 | phpdbg_print_opline_ex(execute_data, NULL, ignore_flags TSRMLS_CC); 176 | } /* }}} */ 177 | 178 | const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */ 179 | { 180 | #if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO 181 | #define CASE(s) case s: return #s 182 | switch (opcode) { 183 | CASE(ZEND_NOP); 184 | CASE(ZEND_ADD); 185 | CASE(ZEND_SUB); 186 | CASE(ZEND_MUL); 187 | CASE(ZEND_DIV); 188 | CASE(ZEND_MOD); 189 | CASE(ZEND_SL); 190 | CASE(ZEND_SR); 191 | CASE(ZEND_CONCAT); 192 | CASE(ZEND_BW_OR); 193 | CASE(ZEND_BW_AND); 194 | CASE(ZEND_BW_XOR); 195 | CASE(ZEND_BW_NOT); 196 | CASE(ZEND_BOOL_NOT); 197 | CASE(ZEND_BOOL_XOR); 198 | CASE(ZEND_IS_IDENTICAL); 199 | CASE(ZEND_IS_NOT_IDENTICAL); 200 | CASE(ZEND_IS_EQUAL); 201 | CASE(ZEND_IS_NOT_EQUAL); 202 | CASE(ZEND_IS_SMALLER); 203 | CASE(ZEND_IS_SMALLER_OR_EQUAL); 204 | CASE(ZEND_CAST); 205 | CASE(ZEND_QM_ASSIGN); 206 | CASE(ZEND_ASSIGN_ADD); 207 | CASE(ZEND_ASSIGN_SUB); 208 | CASE(ZEND_ASSIGN_MUL); 209 | CASE(ZEND_ASSIGN_DIV); 210 | CASE(ZEND_ASSIGN_MOD); 211 | CASE(ZEND_ASSIGN_SL); 212 | CASE(ZEND_ASSIGN_SR); 213 | CASE(ZEND_ASSIGN_CONCAT); 214 | CASE(ZEND_ASSIGN_BW_OR); 215 | CASE(ZEND_ASSIGN_BW_AND); 216 | CASE(ZEND_ASSIGN_BW_XOR); 217 | CASE(ZEND_PRE_INC); 218 | CASE(ZEND_PRE_DEC); 219 | CASE(ZEND_POST_INC); 220 | CASE(ZEND_POST_DEC); 221 | CASE(ZEND_ASSIGN); 222 | CASE(ZEND_ASSIGN_REF); 223 | CASE(ZEND_ECHO); 224 | CASE(ZEND_PRINT); 225 | CASE(ZEND_JMP); 226 | CASE(ZEND_JMPZ); 227 | CASE(ZEND_JMPNZ); 228 | CASE(ZEND_JMPZNZ); 229 | CASE(ZEND_JMPZ_EX); 230 | CASE(ZEND_JMPNZ_EX); 231 | CASE(ZEND_CASE); 232 | CASE(ZEND_SWITCH_FREE); 233 | CASE(ZEND_BRK); 234 | CASE(ZEND_CONT); 235 | CASE(ZEND_BOOL); 236 | CASE(ZEND_INIT_STRING); 237 | CASE(ZEND_ADD_CHAR); 238 | CASE(ZEND_ADD_STRING); 239 | CASE(ZEND_ADD_VAR); 240 | CASE(ZEND_BEGIN_SILENCE); 241 | CASE(ZEND_END_SILENCE); 242 | CASE(ZEND_INIT_FCALL_BY_NAME); 243 | CASE(ZEND_DO_FCALL); 244 | CASE(ZEND_DO_FCALL_BY_NAME); 245 | CASE(ZEND_RETURN); 246 | CASE(ZEND_RECV); 247 | CASE(ZEND_RECV_INIT); 248 | CASE(ZEND_SEND_VAL); 249 | CASE(ZEND_SEND_VAR); 250 | CASE(ZEND_SEND_REF); 251 | CASE(ZEND_NEW); 252 | CASE(ZEND_INIT_NS_FCALL_BY_NAME); 253 | CASE(ZEND_FREE); 254 | CASE(ZEND_INIT_ARRAY); 255 | CASE(ZEND_ADD_ARRAY_ELEMENT); 256 | CASE(ZEND_INCLUDE_OR_EVAL); 257 | CASE(ZEND_UNSET_VAR); 258 | CASE(ZEND_UNSET_DIM); 259 | CASE(ZEND_UNSET_OBJ); 260 | CASE(ZEND_FE_RESET); 261 | CASE(ZEND_FE_FETCH); 262 | CASE(ZEND_EXIT); 263 | CASE(ZEND_FETCH_R); 264 | CASE(ZEND_FETCH_DIM_R); 265 | CASE(ZEND_FETCH_OBJ_R); 266 | CASE(ZEND_FETCH_W); 267 | CASE(ZEND_FETCH_DIM_W); 268 | CASE(ZEND_FETCH_OBJ_W); 269 | CASE(ZEND_FETCH_RW); 270 | CASE(ZEND_FETCH_DIM_RW); 271 | CASE(ZEND_FETCH_OBJ_RW); 272 | CASE(ZEND_FETCH_IS); 273 | CASE(ZEND_FETCH_DIM_IS); 274 | CASE(ZEND_FETCH_OBJ_IS); 275 | CASE(ZEND_FETCH_FUNC_ARG); 276 | CASE(ZEND_FETCH_DIM_FUNC_ARG); 277 | CASE(ZEND_FETCH_OBJ_FUNC_ARG); 278 | CASE(ZEND_FETCH_UNSET); 279 | CASE(ZEND_FETCH_DIM_UNSET); 280 | CASE(ZEND_FETCH_OBJ_UNSET); 281 | CASE(ZEND_FETCH_DIM_TMP_VAR); 282 | CASE(ZEND_FETCH_CONSTANT); 283 | CASE(ZEND_GOTO); 284 | CASE(ZEND_EXT_STMT); 285 | CASE(ZEND_EXT_FCALL_BEGIN); 286 | CASE(ZEND_EXT_FCALL_END); 287 | CASE(ZEND_EXT_NOP); 288 | CASE(ZEND_TICKS); 289 | CASE(ZEND_SEND_VAR_NO_REF); 290 | CASE(ZEND_CATCH); 291 | CASE(ZEND_THROW); 292 | CASE(ZEND_FETCH_CLASS); 293 | CASE(ZEND_CLONE); 294 | CASE(ZEND_RETURN_BY_REF); 295 | CASE(ZEND_INIT_METHOD_CALL); 296 | CASE(ZEND_INIT_STATIC_METHOD_CALL); 297 | CASE(ZEND_ISSET_ISEMPTY_VAR); 298 | CASE(ZEND_ISSET_ISEMPTY_DIM_OBJ); 299 | CASE(ZEND_PRE_INC_OBJ); 300 | CASE(ZEND_PRE_DEC_OBJ); 301 | CASE(ZEND_POST_INC_OBJ); 302 | CASE(ZEND_POST_DEC_OBJ); 303 | CASE(ZEND_ASSIGN_OBJ); 304 | CASE(ZEND_INSTANCEOF); 305 | CASE(ZEND_DECLARE_CLASS); 306 | CASE(ZEND_DECLARE_INHERITED_CLASS); 307 | CASE(ZEND_DECLARE_FUNCTION); 308 | CASE(ZEND_RAISE_ABSTRACT_ERROR); 309 | CASE(ZEND_DECLARE_CONST); 310 | CASE(ZEND_ADD_INTERFACE); 311 | CASE(ZEND_DECLARE_INHERITED_CLASS_DELAYED); 312 | CASE(ZEND_VERIFY_ABSTRACT_CLASS); 313 | CASE(ZEND_ASSIGN_DIM); 314 | CASE(ZEND_ISSET_ISEMPTY_PROP_OBJ); 315 | CASE(ZEND_HANDLE_EXCEPTION); 316 | CASE(ZEND_USER_OPCODE); 317 | #ifdef ZEND_JMP_SET 318 | CASE(ZEND_JMP_SET); 319 | #endif 320 | CASE(ZEND_DECLARE_LAMBDA_FUNCTION); 321 | #ifdef ZEND_ADD_TRAIT 322 | CASE(ZEND_ADD_TRAIT); 323 | #endif 324 | #ifdef ZEND_BIND_TRAITS 325 | CASE(ZEND_BIND_TRAITS); 326 | #endif 327 | #ifdef ZEND_SEPARATE 328 | CASE(ZEND_SEPARATE); 329 | #endif 330 | #ifdef ZEND_DISCARD_EXCEPTION 331 | CASE(ZEND_DISCARD_EXCEPTION); 332 | #endif 333 | #ifdef ZEND_YIELD 334 | CASE(ZEND_YIELD); 335 | #endif 336 | #ifdef ZEND_GENERATOR_RETURN 337 | CASE(ZEND_GENERATOR_RETURN); 338 | #endif 339 | #ifdef ZEND_FAST_CALL 340 | CASE(ZEND_FAST_CALL); 341 | #endif 342 | #ifdef ZEND_FAST_RET 343 | CASE(ZEND_FAST_RET); 344 | #endif 345 | #ifdef ZEND_RECV_VARIADIC 346 | CASE(ZEND_RECV_VARIADIC); 347 | #endif 348 | CASE(ZEND_OP_DATA); 349 | default: 350 | return "UNKNOWN"; 351 | } 352 | #else 353 | const char *ret = zend_get_opcode_name(opcode); 354 | return ret?ret:"UNKNOWN"; 355 | #endif 356 | } /* }}} */ 357 | -------------------------------------------------------------------------------- /phpdbg_opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_OPCODE_H 22 | #define PHPDBG_OPCODE_H 23 | 24 | #include "zend_types.h" 25 | 26 | const char *phpdbg_decode_opcode(zend_uchar); 27 | char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC); 28 | void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC); 29 | void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC); 30 | 31 | #endif /* PHPDBG_OPCODE_H */ 32 | -------------------------------------------------------------------------------- /phpdbg_out.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_OUT_H 22 | #define PHPDBG_OUT_H 23 | 24 | /** 25 | * Error/notice/formatting helpers 26 | */ 27 | enum { 28 | P_ERROR = 1, 29 | P_NOTICE, 30 | P_WRITELN, 31 | P_WRITE, 32 | P_STDOUT, 33 | P_STDERR, 34 | P_LOG 35 | }; 36 | 37 | #ifdef ZTS 38 | 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); 39 | PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); 40 | PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); 41 | PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); 42 | PHPDBG_API int phpdbg_rlog_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); 43 | #else 44 | PHPDBG_API int phpdbg_print(int severity, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6); 45 | PHPDBG_API int phpdbg_xml_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); 46 | PHPDBG_API int phpdbg_log_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); 47 | PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); 48 | PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); 49 | #endif 50 | 51 | 52 | #define phpdbg_error(tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) 53 | #define phpdbg_notice(tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) 54 | #define phpdbg_writeln(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) 55 | #define phpdbg_write(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) 56 | #define phpdbg_script(type, fmt, ...) phpdbg_print(type TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, NULL, NULL, fmt, ##__VA_ARGS__) 57 | #define phpdbg_log(fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) 58 | #define phpdbg_xml(fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) 59 | #define phpdbg_out(fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) 60 | 61 | #define phpdbg_error_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) 62 | #define phpdbg_notice_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) 63 | #define phpdbg_writeln_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) 64 | #define phpdbg_write_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) 65 | #define phpdbg_script_ex(out, type, fmt, ...) phpdbg_print(type TSRMLS_CC, out, NULL, NULL, fmt, ##__VA_ARGS__) 66 | #define phpdbg_log_ex(out, fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) 67 | #define phpdbg_xml_ex(out, fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) 68 | #define phpdbg_out_ex(out, fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) 69 | 70 | #define phpdbg_rlog(fd, fmt, ...) phpdbg_rlog_internal(fd TSRMLS_CC, fmt, ##__VA_ARGS__) 71 | 72 | #define phpdbg_xml_asprintf(buf, ...) _phpdbg_xml_asprintf(buf TSRMLS_CC, ##__VA_ARGS__) 73 | PHPDBG_API int _phpdbg_xml_asprintf(char **buf TSRMLS_DC, const char *format, zend_bool escape_xml, ...); 74 | 75 | #define phpdbg_asprintf(buf, ...) _phpdbg_asprintf(buf TSRMLS_CC, ##__VA_ARGS__) 76 | PHPDBG_API int _phpdbg_asprintf(char **buf TSRMLS_DC, const char *format, ...); 77 | 78 | 79 | #if PHPDBG_DEBUG 80 | # define phpdbg_debug(fmt, ...) phpdbg_log_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd TSRMLS_CC, fmt, ##__VA_ARGS__) 81 | #else 82 | # define phpdbg_debug(fmt, ...) 83 | #endif 84 | 85 | PHPDBG_API void phpdbg_free_err_buf(TSRMLS_D); 86 | PHPDBG_API void phpdbg_activate_err_buf(zend_bool active TSRMLS_DC); 87 | PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const char *strfmt TSRMLS_DC, ...); 88 | 89 | 90 | /* {{{ For separation */ 91 | #define SEPARATE "------------------------------------------------" /* }}} */ 92 | 93 | #endif /* PHPDBG_OUT_H */ 94 | -------------------------------------------------------------------------------- /phpdbg_parser.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 2.7. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . */ 19 | 20 | /* As a special exception, you may create a larger work that contains 21 | part or all of the Bison parser skeleton and distribute that work 22 | under terms of your choice, so long as that work isn't itself a 23 | parser generator using the skeleton or a modified version thereof 24 | as a parser skeleton. Alternatively, if you modify or redistribute 25 | the parser skeleton itself, you may (at your option) remove this 26 | special exception, which will cause the skeleton and the resulting 27 | Bison output files to be licensed under the GNU General Public 28 | License without this special exception. 29 | 30 | This special exception was added by the Free Software Foundation in 31 | version 2.2 of Bison. */ 32 | 33 | #ifndef YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED 34 | # define YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED 35 | /* Enabling traces. */ 36 | #ifndef YYDEBUG 37 | # define YYDEBUG 0 38 | #endif 39 | #if YYDEBUG 40 | extern int phpdbg_debug; 41 | #endif 42 | /* "%code requires" blocks. */ 43 | /* Line 2058 of yacc.c */ 44 | #line 31 "/usr/src/php-src/sapi/phpdbg/phpdbg_parser.y" 45 | 46 | #include "phpdbg.h" 47 | #ifndef YY_TYPEDEF_YY_SCANNER_T 48 | #define YY_TYPEDEF_YY_SCANNER_T 49 | typedef void* yyscan_t; 50 | #endif 51 | 52 | 53 | /* Line 2058 of yacc.c */ 54 | #line 55 "sapi/phpdbg/phpdbg_parser.h" 55 | 56 | /* Tokens. */ 57 | #ifndef YYTOKENTYPE 58 | # define YYTOKENTYPE 59 | /* Put the tokens into the symbol table, so that GDB and other debuggers 60 | know about them. */ 61 | enum yytokentype { 62 | T_EVAL = 258, 63 | T_RUN = 259, 64 | T_SHELL = 260, 65 | T_IF = 261, 66 | T_TRUTHY = 262, 67 | T_FALSY = 263, 68 | T_STRING = 264, 69 | T_COLON = 265, 70 | T_DCOLON = 266, 71 | T_POUND = 267, 72 | T_PROTO = 268, 73 | T_DIGITS = 269, 74 | T_LITERAL = 270, 75 | T_ADDR = 271, 76 | T_OPCODE = 272, 77 | T_ID = 273, 78 | T_INPUT = 274, 79 | T_UNEXPECTED = 275, 80 | T_REQ_ID = 276 81 | }; 82 | #endif 83 | /* Tokens. */ 84 | #define T_EVAL 258 85 | #define T_RUN 259 86 | #define T_SHELL 260 87 | #define T_IF 261 88 | #define T_TRUTHY 262 89 | #define T_FALSY 263 90 | #define T_STRING 264 91 | #define T_COLON 265 92 | #define T_DCOLON 266 93 | #define T_POUND 267 94 | #define T_PROTO 268 95 | #define T_DIGITS 269 96 | #define T_LITERAL 270 97 | #define T_ADDR 271 98 | #define T_OPCODE 272 99 | #define T_ID 273 100 | #define T_INPUT 274 101 | #define T_UNEXPECTED 275 102 | #define T_REQ_ID 276 103 | 104 | 105 | 106 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 107 | typedef int YYSTYPE; 108 | # define YYSTYPE_IS_TRIVIAL 1 109 | # define yystype YYSTYPE /* obsolescent; will be withdrawn */ 110 | # define YYSTYPE_IS_DECLARED 1 111 | #endif 112 | 113 | 114 | #ifdef YYPARSE_PARAM 115 | #if defined __STDC__ || defined __cplusplus 116 | int phpdbg_parse (void *YYPARSE_PARAM); 117 | #else 118 | int phpdbg_parse (); 119 | #endif 120 | #else /* ! YYPARSE_PARAM */ 121 | #if defined __STDC__ || defined __cplusplus 122 | int phpdbg_parse (void *tsrm_ls); 123 | #else 124 | int phpdbg_parse (); 125 | #endif 126 | #endif /* ! YYPARSE_PARAM */ 127 | 128 | #endif /* !YY_PHPDBG_SAPI_PHPDBG_PHPDBG_PARSER_H_INCLUDED */ 129 | -------------------------------------------------------------------------------- /phpdbg_parser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | 3 | /* 4 | * phpdbg_parser.y 5 | * (from php-src root) 6 | * flex sapi/phpdbg/dev/phpdbg_lexer.l 7 | * bison sapi/phpdbg/dev/phpdbg_parser.y 8 | */ 9 | 10 | #include "phpdbg.h" 11 | #include "phpdbg_cmd.h" 12 | #include "phpdbg_utils.h" 13 | #include "phpdbg_cmd.h" 14 | #include "phpdbg_prompt.h" 15 | 16 | #define YYSTYPE phpdbg_param_t 17 | 18 | #include "phpdbg_parser.h" 19 | #include "phpdbg_lexer.h" 20 | 21 | #undef yyerror 22 | static int yyerror(void ***tsrm_ls, const char *msg); 23 | 24 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 25 | 26 | %} 27 | 28 | %pure-parser 29 | %error-verbose 30 | 31 | %code requires { 32 | #include "phpdbg.h" 33 | #ifndef YY_TYPEDEF_YY_SCANNER_T 34 | #define YY_TYPEDEF_YY_SCANNER_T 35 | typedef void* yyscan_t; 36 | #endif 37 | } 38 | 39 | %parse-param { void *tsrm_ls } 40 | 41 | %output "sapi/phpdbg/phpdbg_parser.c" 42 | %defines "sapi/phpdbg/phpdbg_parser.h" 43 | 44 | %token T_EVAL "eval" 45 | %token T_RUN "run" 46 | %token T_SHELL "shell" 47 | %token T_IF "if (condition)" 48 | %token T_TRUTHY "truthy (true, on, yes or enabled)" 49 | %token T_FALSY "falsy (false, off, no or disabled)" 50 | %token T_STRING "string (some input, perhaps)" 51 | %token T_COLON ": (colon)" 52 | %token T_DCOLON ":: (double colon)" 53 | %token T_POUND "# (pound sign)" 54 | %token T_PROTO "protocol (file://)" 55 | %token T_DIGITS "digits (numbers)" 56 | %token T_LITERAL "literal (string)" 57 | %token T_ADDR "address" 58 | %token T_OPCODE "opcode" 59 | %token T_ID "identifier (command or function name)" 60 | %token T_INPUT "input (input string or data)" 61 | %token T_UNEXPECTED "input" 62 | %token T_REQ_ID "request id (-r %d)" 63 | 64 | %% /* Rules */ 65 | 66 | input 67 | : parameters 68 | | full_expression { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); } 69 | | /* nothing */ 70 | ; 71 | 72 | parameters 73 | : parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); } 74 | | parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); } 75 | | parameters req_id { $$ = $1; } 76 | ; 77 | 78 | parameter 79 | : T_ID T_COLON T_DIGITS { 80 | $$.type = FILE_PARAM; 81 | $$.file.name = $2.str; 82 | $$.file.line = $3.num; 83 | } 84 | | T_ID T_COLON T_POUND T_DIGITS { 85 | $$.type = NUMERIC_FILE_PARAM; 86 | $$.file.name = $1.str; 87 | $$.file.line = $4.num; 88 | } 89 | | T_PROTO T_ID T_COLON T_DIGITS { 90 | $$.type = FILE_PARAM; 91 | $$.file.name = malloc($1.len + $2.len + 1); 92 | if ($$.file.name) { 93 | memcpy(&$$.file.name[0], $1.str, $1.len); 94 | memcpy(&$$.file.name[$1.len], $2.str, $2.len); 95 | $$.file.name[$1.len + $2.len] = '\0'; 96 | } 97 | $$.file.line = $4.num; 98 | } 99 | | T_PROTO T_ID T_COLON T_POUND T_DIGITS { 100 | $$.type = NUMERIC_FILE_PARAM; 101 | $$.file.name = malloc($1.len + $2.len + 1); 102 | if ($$.file.name) { 103 | memcpy(&$$.file.name[0], $1.str, $1.len); 104 | memcpy(&$$.file.name[$1.len], $2.str, $2.len); 105 | $$.file.name[$1.len + $2.len] = '\0'; 106 | } 107 | $$.file.line = $5.num; 108 | } 109 | | T_ID T_DCOLON T_ID { 110 | $$.type = METHOD_PARAM; 111 | $$.method.class = $1.str; 112 | $$.method.name = $3.str; 113 | } 114 | | T_ID T_DCOLON T_ID T_POUND T_DIGITS { 115 | $$.type = NUMERIC_METHOD_PARAM; 116 | $$.method.class = $1.str; 117 | $$.method.name = $3.str; 118 | $$.num = $5.num; 119 | } 120 | | T_ID T_POUND T_DIGITS { 121 | $$.type = NUMERIC_FUNCTION_PARAM; 122 | $$.str = $1.str; 123 | $$.len = $1.len; 124 | $$.num = $3.num; 125 | } 126 | | T_IF T_INPUT { 127 | $$.type = COND_PARAM; 128 | $$.str = $2.str; 129 | $$.len = $2.len; 130 | } 131 | | T_OPCODE { $$ = $1; } 132 | | T_ADDR { $$ = $1; } 133 | | T_LITERAL { $$ = $1; } 134 | | T_TRUTHY { $$ = $1; } 135 | | T_FALSY { $$ = $1; } 136 | | T_DIGITS { $$ = $1; } 137 | | T_ID { $$ = $1; } 138 | ; 139 | 140 | req_id 141 | : T_REQ_ID { PHPDBG_G(req_id) = $1.num; } 142 | | /* empty */ 143 | ; 144 | 145 | full_expression 146 | : T_EVAL req_id T_INPUT { 147 | $$.type = EVAL_PARAM; 148 | $$.str = $3.str; 149 | $$.len = $3.len; 150 | } 151 | | T_SHELL req_id T_INPUT { 152 | $$.type = SHELL_PARAM; 153 | $$.str = $3.str; 154 | $$.len = $3.len; 155 | } 156 | | T_RUN req_id { 157 | $$.type = RUN_PARAM; 158 | $$.len = 0; 159 | } 160 | | T_RUN req_id T_INPUT { 161 | $$.type = RUN_PARAM; 162 | $$.str = $3.str; 163 | $$.len = $3.len; 164 | } 165 | ; 166 | 167 | %% 168 | 169 | static int yyerror(void ***tsrm_ls, const char *msg) { 170 | phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg); 171 | 172 | { 173 | const phpdbg_param_t *top = PHPDBG_G(parser_stack); 174 | 175 | while (top) { 176 | phpdbg_param_debug(top, "--> "); 177 | top = top->next; 178 | } 179 | } 180 | return 0; 181 | } 182 | 183 | int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) { 184 | phpdbg_init_lexer(stack, input TSRMLS_CC); 185 | 186 | #ifdef ZTS 187 | return yyparse(TSRMLS_C); 188 | #else 189 | return yyparse(NULL); 190 | #endif 191 | } 192 | -------------------------------------------------------------------------------- /phpdbg_print.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include "phpdbg.h" 22 | #include "phpdbg_print.h" 23 | #include "phpdbg_utils.h" 24 | #include "phpdbg_opcode.h" 25 | #include "phpdbg_prompt.h" 26 | 27 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 28 | 29 | #define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s, flags) \ 30 | PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9], flags) 31 | 32 | const phpdbg_command_t phpdbg_print_commands[] = { 33 | PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0, PHPDBG_ASYNC_SAFE), 34 | PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0, PHPDBG_ASYNC_SAFE), 35 | PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s", PHPDBG_ASYNC_SAFE), 36 | PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m", PHPDBG_ASYNC_SAFE), 37 | PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s", PHPDBG_ASYNC_SAFE), 38 | PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0, PHPDBG_ASYNC_SAFE), 39 | PHPDBG_END_COMMAND 40 | }; 41 | 42 | PHPDBG_PRINT(opline) /* {{{ */ 43 | { 44 | if (EG(in_execution) && EG(current_execute_data)) { 45 | phpdbg_print_opline(EG(current_execute_data), 1 TSRMLS_CC); 46 | } else { 47 | phpdbg_error("inactive", "type=\"execution\"", "Not Executing!"); 48 | } 49 | 50 | return SUCCESS; 51 | } /* }}} */ 52 | 53 | static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) /* {{{ */ 54 | { 55 | switch (method->type) { 56 | case ZEND_USER_FUNCTION: { 57 | zend_op_array* op_array = &(method->op_array); 58 | HashTable vars; 59 | 60 | if (op_array) { 61 | zend_op *opline = &(op_array->opcodes[0]); 62 | zend_uint opcode = 0, 63 | end = op_array->last-1; 64 | 65 | if (method->common.scope) { 66 | phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" method=\"%s::%s\" file=\"%s\"", "\tL%d-%d %s::%s() %s", 67 | op_array->line_start, 68 | op_array->line_end, 69 | method->common.scope->name, 70 | method->common.function_name, 71 | op_array->filename ? op_array->filename : "unknown"); 72 | } else { 73 | phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" function=\"%s\" file=\"%s\"", "\tL%d-%d %s() %s", 74 | method->common.function_name ? op_array->line_start : 0, 75 | method->common.function_name ? op_array->line_end : 0, 76 | method->common.function_name ? method->common.function_name : "{main}", 77 | op_array->filename ? op_array->filename : "unknown"); 78 | } 79 | 80 | zend_hash_init(&vars, op_array->last, NULL, NULL, 0); 81 | do { 82 | char *decode = phpdbg_decode_opline(op_array, opline, &vars TSRMLS_CC); 83 | if (decode != NULL) { 84 | phpdbg_writeln("print", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\"", "\t\tL%u\t%p %-30s %s", 85 | opline->lineno, 86 | opline, 87 | phpdbg_decode_opcode(opline->opcode), 88 | decode); 89 | free(decode); 90 | } else { 91 | phpdbg_error("print", "type=\"decodefailure\" opline=\"%16p\"", "\tFailed to decode opline %16p", opline); 92 | } 93 | opline++; 94 | } while (opcode++ < end); 95 | zend_hash_destroy(&vars); 96 | } 97 | } break; 98 | 99 | default: { 100 | if (method->common.scope) { 101 | phpdbg_writeln("printoplineinfo", "type=\"Internal\" method=\"%s::%s\"", "Internal %s::%s()", method->common.scope->name, method->common.function_name); 102 | } else { 103 | phpdbg_writeln("printoplineinfo", "type=\"Internal\" function=\"%s\"", "\tInternal %s()", method->common.function_name); 104 | } 105 | } 106 | } 107 | } /* }}} */ 108 | 109 | PHPDBG_PRINT(exec) /* {{{ */ 110 | { 111 | if (PHPDBG_G(exec)) { 112 | if (!PHPDBG_G(ops) && !(PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER)) { 113 | phpdbg_compile(TSRMLS_C); 114 | } 115 | 116 | if (PHPDBG_G(ops)) { 117 | phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Context %s (%d ops)", PHPDBG_G(exec), PHPDBG_G(ops)->last); 118 | 119 | phpdbg_print_function_helper((zend_function*) PHPDBG_G(ops) TSRMLS_CC); 120 | } 121 | } else { 122 | phpdbg_error("inactive", "type=\"nocontext\"", "No execution context set"); 123 | } 124 | 125 | return SUCCESS; 126 | } /* }}} */ 127 | 128 | PHPDBG_PRINT(stack) /* {{{ */ 129 | { 130 | zend_op_array *ops = EG(active_op_array); 131 | 132 | if (EG(in_execution) && ops) { 133 | if (ops->function_name) { 134 | if (ops->scope) { 135 | phpdbg_notice("printinfo", "method=\"%s::%s\" num=\"%d\"", "Stack in %s::%s() (%d ops)", ops->scope->name, ops->function_name, ops->last); 136 | } else { 137 | phpdbg_notice("printinfo", "function=\"%s\" num=\"%d\"", "Stack in %s() (%d ops)", ops->function_name, ops->last); 138 | } 139 | } else { 140 | if (ops->filename) { 141 | phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Stack in %s (%d ops)", ops->filename, ops->last); 142 | } else { 143 | phpdbg_notice("printinfo", "opline=\"%p\" num=\"%d\"", "Stack @ %p (%d ops)", ops, ops->last); 144 | } 145 | } 146 | phpdbg_print_function_helper((zend_function*) ops TSRMLS_CC); 147 | } else { 148 | phpdbg_error("inactive", "type=\"execution\"", "Not Executing!"); 149 | } 150 | 151 | return SUCCESS; 152 | } /* }}} */ 153 | 154 | PHPDBG_PRINT(class) /* {{{ */ 155 | { 156 | zend_class_entry **ce; 157 | 158 | if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { 159 | phpdbg_notice("printinfo", "type=\"%s\" flag=\"%s\" class=\"%s\" num=\"%d\"", "%s %s: %s (%d methods)", 160 | ((*ce)->type == ZEND_USER_CLASS) ? 161 | "User" : "Internal", 162 | ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? 163 | "Interface" : 164 | ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? 165 | "Abstract Class" : 166 | "Class", 167 | (*ce)->name, 168 | zend_hash_num_elements(&(*ce)->function_table)); 169 | 170 | phpdbg_xml(""); 171 | 172 | if (zend_hash_num_elements(&(*ce)->function_table)) { 173 | HashPosition position; 174 | zend_function *method; 175 | 176 | for (zend_hash_internal_pointer_reset_ex(&(*ce)->function_table, &position); 177 | zend_hash_get_current_data_ex(&(*ce)->function_table, (void**) &method, &position) == SUCCESS; 178 | zend_hash_move_forward_ex(&(*ce)->function_table, &position)) { 179 | phpdbg_print_function_helper(method TSRMLS_CC); 180 | } 181 | } 182 | 183 | phpdbg_xml(""); 184 | } else { 185 | phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->str); 186 | } 187 | 188 | return SUCCESS; 189 | } /* }}} */ 190 | 191 | PHPDBG_PRINT(method) /* {{{ */ 192 | { 193 | zend_class_entry **ce; 194 | 195 | if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { 196 | zend_function *fbc; 197 | char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); 198 | 199 | if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { 200 | phpdbg_notice("printinfo", "type=\"%s\" flags=\"Method\" symbol=\"%s\" num=\"%d\"", "%s Method %s (%d ops)", 201 | (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", 202 | fbc->common.function_name, 203 | (fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0); 204 | 205 | phpdbg_print_function_helper(fbc TSRMLS_CC); 206 | } else { 207 | phpdbg_error("print", "type=\"nomethod\" method=\"%s::%s\"", "The method %s::%s could not be found", param->method.class, param->method.name); 208 | } 209 | 210 | efree(lcname); 211 | } else { 212 | phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->method.class); 213 | } 214 | 215 | return SUCCESS; 216 | } /* }}} */ 217 | 218 | PHPDBG_PRINT(func) /* {{{ */ 219 | { 220 | HashTable *func_table = EG(function_table); 221 | zend_function* fbc; 222 | const char *func_name = param->str; 223 | size_t func_name_len = param->len; 224 | char *lcname; 225 | /* search active scope if begins with period */ 226 | if (func_name[0] == '.') { 227 | if (EG(scope)) { 228 | func_name++; 229 | func_name_len--; 230 | 231 | func_table = &EG(scope)->function_table; 232 | } else { 233 | phpdbg_error("inactive", "type=\"noclasses\"", "No active class"); 234 | return SUCCESS; 235 | } 236 | } else if (!EG(function_table)) { 237 | phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded"); 238 | return SUCCESS; 239 | } else { 240 | func_table = EG(function_table); 241 | } 242 | 243 | lcname = zend_str_tolower_dup(func_name, func_name_len); 244 | 245 | phpdbg_try_access { 246 | if (zend_hash_find(func_table, lcname, func_name_len + 1, (void **) &fbc) == SUCCESS) { 247 | phpdbg_notice("printinfo", "type=\"%s\" flags=\"%s\" symbol=\"%s\" num=\"%d\"", "%s %s %s (%d ops)", 248 | (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", 249 | (fbc->common.scope) ? "Method" : "Function", 250 | fbc->common.function_name, 251 | (fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0); 252 | 253 | phpdbg_print_function_helper(fbc TSRMLS_CC); 254 | } else { 255 | phpdbg_error("print", "type=\"nofunction\" function=\"%s\"", "The function %s could not be found", func_name); 256 | } 257 | } phpdbg_catch_access { 258 | phpdbg_error("signalsegv", "function=\"%.*s\"", "Couldn't fetch function %.*s, invalid data source", (int) func_name_len, func_name); 259 | } phpdbg_end_try_access(); 260 | 261 | efree(lcname); 262 | 263 | return SUCCESS; 264 | } /* }}} */ 265 | -------------------------------------------------------------------------------- /phpdbg_print.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_PRINT_H 22 | #define PHPDBG_PRINT_H 23 | 24 | #include "phpdbg_cmd.h" 25 | 26 | #define PHPDBG_PRINT(name) PHPDBG_COMMAND(print_##name) 27 | 28 | /** 29 | * Printer Forward Declarations 30 | */ 31 | PHPDBG_PRINT(exec); 32 | PHPDBG_PRINT(opline); 33 | PHPDBG_PRINT(class); 34 | PHPDBG_PRINT(method); 35 | PHPDBG_PRINT(func); 36 | PHPDBG_PRINT(stack); 37 | 38 | extern const phpdbg_command_t phpdbg_print_commands[]; 39 | 40 | #endif /* PHPDBG_PRINT_H */ 41 | -------------------------------------------------------------------------------- /phpdbg_prompt.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_PROMPT_H 22 | #define PHPDBG_PROMPT_H 23 | 24 | /* {{{ */ 25 | void phpdbg_string_init(char *buffer TSRMLS_DC); 26 | void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC); 27 | void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC); 28 | int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC); 29 | int phpdbg_compile(TSRMLS_D); 30 | void phpdbg_clean(zend_bool full TSRMLS_DC); 31 | void phpdbg_force_interruption(TSRMLS_D); 32 | /* }}} */ 33 | 34 | /* {{{ phpdbg command handlers */ 35 | PHPDBG_COMMAND(exec); 36 | PHPDBG_COMMAND(step); 37 | PHPDBG_COMMAND(continue); 38 | PHPDBG_COMMAND(run); 39 | PHPDBG_COMMAND(ev); 40 | PHPDBG_COMMAND(until); 41 | PHPDBG_COMMAND(finish); 42 | PHPDBG_COMMAND(leave); 43 | PHPDBG_COMMAND(frame); 44 | PHPDBG_COMMAND(print); 45 | PHPDBG_COMMAND(break); 46 | PHPDBG_COMMAND(back); 47 | PHPDBG_COMMAND(list); 48 | PHPDBG_COMMAND(info); 49 | PHPDBG_COMMAND(clean); 50 | PHPDBG_COMMAND(clear); 51 | PHPDBG_COMMAND(help); 52 | PHPDBG_COMMAND(sh); 53 | PHPDBG_COMMAND(dl); 54 | PHPDBG_COMMAND(set); 55 | PHPDBG_COMMAND(source); 56 | PHPDBG_COMMAND(export); 57 | PHPDBG_COMMAND(register); 58 | PHPDBG_COMMAND(quit); 59 | PHPDBG_COMMAND(watch); 60 | PHPDBG_COMMAND(eol); 61 | PHPDBG_COMMAND(wait); /* }}} */ 62 | 63 | /* {{{ prompt commands */ 64 | extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */ 65 | 66 | /* {{{ */ 67 | #if PHP_VERSION_ID >= 50500 68 | void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC); 69 | #else 70 | void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC); 71 | #endif /* }}} */ 72 | 73 | #endif /* PHPDBG_PROMPT_H */ 74 | -------------------------------------------------------------------------------- /phpdbg_rinit_hook.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Bob Weinand | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #include "phpdbg_rinit_hook.h" 20 | #include "php_ini.h" 21 | #include "ext/standard/file.h" 22 | 23 | ZEND_DECLARE_MODULE_GLOBALS(phpdbg_webhelper); 24 | 25 | PHP_INI_BEGIN() 26 | STD_PHP_INI_ENTRY("phpdbg.auth", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, auth, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals) 27 | STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, path, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals) 28 | PHP_INI_END() 29 | 30 | static inline void php_phpdbg_webhelper_globals_ctor(zend_phpdbg_webhelper_globals *pg) /* {{{ */ 31 | { 32 | } /* }}} */ 33 | 34 | static PHP_MINIT_FUNCTION(phpdbg_webhelper) /* {{{ */ 35 | { 36 | if (!strcmp(sapi_module.name, PHPDBG_NAME)) { 37 | return SUCCESS; 38 | } 39 | 40 | ZEND_INIT_MODULE_GLOBALS(phpdbg_webhelper, php_phpdbg_webhelper_globals_ctor, NULL); 41 | REGISTER_INI_ENTRIES(); 42 | 43 | return SUCCESS; 44 | } /* }}} */ 45 | 46 | static PHP_RINIT_FUNCTION(phpdbg_webhelper) /* {{{ */ 47 | { 48 | zval *cookies = PG(http_globals)[TRACK_VARS_COOKIE]; 49 | zval **auth; 50 | 51 | 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))) { 52 | return SUCCESS; 53 | } 54 | 55 | { 56 | char *host = PHPDBG_WG(path); 57 | int host_len = strlen(host); 58 | struct timeval tv; 59 | php_stream *stream; 60 | int err; 61 | char *errstr = NULL; 62 | 63 | char *msg = NULL; 64 | char msglen[5] = {0}; 65 | 66 | tv.tv_sec = 60; 67 | tv.tv_usec = 0; 68 | 69 | stream = php_stream_xport_create(host, host_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, &tv, NULL, &errstr, &err); 70 | 71 | if (stream == NULL) { 72 | /* 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)); */ 73 | return SUCCESS; 74 | } 75 | 76 | phpdbg_webdata_compress(&msg, (int *) msglen TSRMLS_CC); 77 | 78 | php_stream_write(stream, msglen, 4); 79 | php_stream_write(stream, msg, *(int *) msglen); 80 | 81 | php_stream_passthru(stream); 82 | php_stream_close(stream); 83 | 84 | php_output_flush_all(TSRMLS_C); 85 | zend_bailout(); 86 | } 87 | 88 | return SUCCESS; 89 | } /* }}} */ 90 | 91 | zend_module_entry phpdbg_webhelper_module_entry = { 92 | STANDARD_MODULE_HEADER, 93 | "phpdbg_webhelper", 94 | NULL, 95 | PHP_MINIT(phpdbg_webhelper), 96 | NULL, 97 | PHP_RINIT(phpdbg_webhelper), 98 | NULL, 99 | NULL, 100 | PHPDBG_VERSION, 101 | STANDARD_MODULE_PROPERTIES 102 | }; 103 | 104 | #ifdef COMPILE_DL_PHPDBG_WEBHELPER 105 | ZEND_GET_MODULE(phpdbg_webhelper) 106 | #endif 107 | -------------------------------------------------------------------------------- /phpdbg_rinit_hook.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_WEBHELPER_H 22 | #define PHPDBG_WEBHELPER_H 23 | 24 | #include "phpdbg_webdata_transfer.h" 25 | 26 | extern zend_module_entry phpdbg_webhelper_module_entry; 27 | #define phpext_phpdbg_webhelper_ptr &phpdbg_webhelper_module_entry 28 | 29 | #ifdef ZTS 30 | # define PHPDBG_WG(v) TSRMG(phpdbg_webhelper_globals_id, zend_phpdbg_webhelper_globals *, v) 31 | #else 32 | # define PHPDBG_WG(v) (phpdbg_webhelper_globals.v) 33 | #endif 34 | 35 | /* {{{ structs */ 36 | ZEND_BEGIN_MODULE_GLOBALS(phpdbg_webhelper) 37 | char *auth; 38 | char *path; 39 | ZEND_END_MODULE_GLOBALS(phpdbg_webhelper) /* }}} */ 40 | 41 | #endif /* PHPDBG_WEBHELPER_H */ 42 | -------------------------------------------------------------------------------- /phpdbg_set.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include "phpdbg.h" 22 | #include "phpdbg_cmd.h" 23 | #include "phpdbg_set.h" 24 | #include "phpdbg_utils.h" 25 | #include "phpdbg_bp.h" 26 | #include "phpdbg_prompt.h" 27 | 28 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 29 | 30 | #define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s, flags) \ 31 | PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[18], flags) 32 | 33 | const phpdbg_command_t phpdbg_set_commands[] = { 34 | PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt []", 'p', set_prompt, NULL, "|s", 0), 35 | #ifndef _WIN32 36 | PHPDBG_SET_COMMAND_D(color, "usage: set color ", 'c', set_color, NULL, "ss", PHPDBG_ASYNC_SAFE), 37 | PHPDBG_SET_COMMAND_D(colors, "usage: set colors []", 'C', set_colors, NULL, "|b", PHPDBG_ASYNC_SAFE), 38 | #endif 39 | PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog []", 'O', set_oplog, NULL, "|s", 0), 40 | PHPDBG_SET_COMMAND_D(break, "usage: set break id []", 'b', set_break, NULL, "l|b", PHPDBG_ASYNC_SAFE), 41 | PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks []", 'B', set_breaks, NULL, "|b", PHPDBG_ASYNC_SAFE), 42 | PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet []", 'q', set_quiet, NULL, "|b", PHPDBG_ASYNC_SAFE), 43 | PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping []", 's', set_stepping, NULL, "|s", PHPDBG_ASYNC_SAFE), 44 | PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount []", 'r', set_refcount, NULL, "|b", PHPDBG_ASYNC_SAFE), 45 | PHPDBG_END_COMMAND 46 | }; 47 | 48 | PHPDBG_SET(prompt) /* {{{ */ 49 | { 50 | if (!param || param->type == EMPTY_PARAM) { 51 | phpdbg_writeln("setprompt", "str=\"%s\"", "Current prompt: %s", phpdbg_get_prompt(TSRMLS_C)); 52 | } else { 53 | phpdbg_set_prompt(param->str TSRMLS_CC); 54 | } 55 | 56 | return SUCCESS; 57 | } /* }}} */ 58 | 59 | PHPDBG_SET(break) /* {{{ */ 60 | { 61 | switch (param->type) { 62 | case NUMERIC_PARAM: { 63 | if (param->next) { 64 | if (param->next->num) { 65 | phpdbg_enable_breakpoint(param->num TSRMLS_CC); 66 | } else { 67 | phpdbg_disable_breakpoint(param->num TSRMLS_CC); 68 | } 69 | } else { 70 | phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC); 71 | if (brake) { 72 | phpdbg_writeln("setbreak", "id=\"%ld\" active=\"%s\"", "Breakpoint #%ld %s", param->num, brake->disabled ? "off" : "on"); 73 | } else { 74 | phpdbg_error("setbreak", "type=\"nobreak\" id=\"%ld\"", "Failed to find breakpoint #%ld", param->num); 75 | } 76 | } 77 | } break; 78 | 79 | default: 80 | phpdbg_error("setbreak", "type=\"wrongargs\"", "set break used incorrectly: set break [id] "); 81 | } 82 | 83 | return SUCCESS; 84 | } /* }}} */ 85 | 86 | PHPDBG_SET(breaks) /* {{{ */ 87 | { 88 | if (!param || param->type == EMPTY_PARAM) { 89 | phpdbg_writeln("setbreaks", "active=\"%s\"", "Breakpoints %s",PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); 90 | } else switch (param->type) { 91 | case NUMERIC_PARAM: { 92 | if (param->num) { 93 | phpdbg_enable_breakpoints(TSRMLS_C); 94 | } else { 95 | phpdbg_disable_breakpoints(TSRMLS_C); 96 | } 97 | } break; 98 | 99 | default: 100 | phpdbg_error("setbreaks", "type=\"wrongargs\"", "set breaks used incorrectly: set breaks "); 101 | } 102 | 103 | return SUCCESS; 104 | } /* }}} */ 105 | 106 | #ifndef _WIN32 107 | PHPDBG_SET(color) /* {{{ */ 108 | { 109 | const phpdbg_color_t *color = phpdbg_get_color(param->next->str, param->next->len TSRMLS_CC); 110 | 111 | if (!color) { 112 | phpdbg_error("setcolor", "type=\"nocolor\"", "Failed to find the requested color (%s)", param->next->str); 113 | return SUCCESS; 114 | } 115 | 116 | switch (phpdbg_get_element(param->str, param->len TSRMLS_CC)) { 117 | case PHPDBG_COLOR_PROMPT: 118 | phpdbg_notice("setcolor", "type=\"prompt\" color=\"%s\" code=\"%s\"", "setting prompt color to %s (%s)", color->name, color->code); 119 | if (PHPDBG_G(prompt)[1]) { 120 | free(PHPDBG_G(prompt)[1]); 121 | PHPDBG_G(prompt)[1]=NULL; 122 | } 123 | phpdbg_set_color(PHPDBG_COLOR_PROMPT, color TSRMLS_CC); 124 | break; 125 | 126 | case PHPDBG_COLOR_ERROR: 127 | phpdbg_notice("setcolor", "type=\"error\" color=\"%s\" code=\"%s\"", "setting error color to %s (%s)", color->name, color->code); 128 | phpdbg_set_color(PHPDBG_COLOR_ERROR, color TSRMLS_CC); 129 | break; 130 | 131 | case PHPDBG_COLOR_NOTICE: 132 | phpdbg_notice("setcolor", "type=\"notice\" color=\"%s\" code=\"%s\"", "setting notice color to %s (%s)", color->name, color->code); 133 | phpdbg_set_color(PHPDBG_COLOR_NOTICE, color TSRMLS_CC); 134 | break; 135 | 136 | default: 137 | phpdbg_error("setcolor", "type=\"invalidtype\"", "Failed to find the requested element (%s)", param->str); 138 | } 139 | 140 | return SUCCESS; 141 | } /* }}} */ 142 | 143 | PHPDBG_SET(colors) /* {{{ */ 144 | { 145 | if (!param || param->type == EMPTY_PARAM) { 146 | phpdbg_writeln("setcolors", "active=\"%s\"", "Colors %s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); 147 | } else switch (param->type) { 148 | case NUMERIC_PARAM: { 149 | if (param->num) { 150 | PHPDBG_G(flags) |= PHPDBG_IS_COLOURED; 151 | } else { 152 | PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED; 153 | } 154 | } break; 155 | 156 | default: 157 | phpdbg_error("setcolors", "type=\"wrongargs\"", "set colors used incorrectly: set colors "); 158 | } 159 | 160 | return SUCCESS; 161 | } /* }}} */ 162 | #endif 163 | 164 | PHPDBG_SET(oplog) /* {{{ */ 165 | { 166 | if (!param || param->type == EMPTY_PARAM) { 167 | phpdbg_notice("setoplog", "active=\"%s\"", "Oplog %s", PHPDBG_G(oplog) ? "on" : "off"); 168 | } else switch (param->type) { 169 | case STR_PARAM: { 170 | /* open oplog */ 171 | FILE *old = PHPDBG_G(oplog); 172 | 173 | PHPDBG_G(oplog) = fopen(param->str, "w+"); 174 | if (!PHPDBG_G(oplog)) { 175 | phpdbg_error("setoplog", "type=\"openfailure\" file=\"%s\"", "Failed to open %s for oplog", param->str); 176 | PHPDBG_G(oplog) = old; 177 | } else { 178 | if (old) { 179 | phpdbg_notice("setoplog", "type=\"closingold\"", "Closing previously open oplog"); 180 | fclose(old); 181 | } 182 | 183 | phpdbg_notice("setoplog", "file=\"%s\"", "Successfully opened oplog %s", param->str); 184 | } 185 | } break; 186 | 187 | phpdbg_default_switch_case(); 188 | } 189 | 190 | return SUCCESS; 191 | } /* }}} */ 192 | 193 | PHPDBG_SET(quiet) /* {{{ */ 194 | { 195 | if (!param || param->type == EMPTY_PARAM) { 196 | phpdbg_writeln("setquiet", "active=\"%s\"", "Quietness %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); 197 | } else switch (param->type) { 198 | case NUMERIC_PARAM: { 199 | if (param->num) { 200 | PHPDBG_G(flags) |= PHPDBG_IS_QUIET; 201 | } else { 202 | PHPDBG_G(flags) &= ~PHPDBG_IS_QUIET; 203 | } 204 | } break; 205 | 206 | phpdbg_default_switch_case(); 207 | } 208 | 209 | return SUCCESS; 210 | } /* }}} */ 211 | 212 | PHPDBG_SET(stepping) /* {{{ */ 213 | { 214 | if (!param || param->type == EMPTY_PARAM) { 215 | phpdbg_writeln("setstepping", "type=\"%s\"", "Stepping %s", PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line"); 216 | } else switch (param->type) { 217 | case STR_PARAM: { 218 | if ((param->len == sizeof("opcode") - 1) && memcmp(param->str, "opcode", sizeof("opcode")) == SUCCESS) { 219 | PHPDBG_G(flags) |= PHPDBG_STEP_OPCODE; 220 | } else if ((param->len == sizeof("line")-1) && memcmp(param->str, "line", sizeof("line")) == SUCCESS) { 221 | PHPDBG_G(flags) &= ~PHPDBG_STEP_OPCODE; 222 | } else { 223 | phpdbg_error("setstepping", "type=\"wrongargs\"", "usage set stepping []"); 224 | } 225 | } break; 226 | 227 | phpdbg_default_switch_case(); 228 | } 229 | 230 | return SUCCESS; 231 | } /* }}} */ 232 | 233 | PHPDBG_SET(refcount) /* {{{ */ 234 | { 235 | if (!param || param->type == EMPTY_PARAM) { 236 | phpdbg_writeln("setrefcount", "active=\"%s\"", "Showing refcounts %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); 237 | } else switch (param->type) { 238 | case NUMERIC_PARAM: { 239 | if (param->num) { 240 | PHPDBG_G(flags) |= PHPDBG_SHOW_REFCOUNTS; 241 | } else { 242 | PHPDBG_G(flags) &= ~PHPDBG_SHOW_REFCOUNTS; 243 | } 244 | } break; 245 | 246 | phpdbg_default_switch_case(); 247 | } 248 | 249 | return SUCCESS; 250 | } /* }}} */ 251 | -------------------------------------------------------------------------------- /phpdbg_set.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_SET_H 22 | #define PHPDBG_SET_H 23 | 24 | #include "phpdbg_cmd.h" 25 | 26 | #define PHPDBG_SET(name) PHPDBG_COMMAND(set_##name) 27 | 28 | PHPDBG_SET(prompt); 29 | #ifndef _WIN32 30 | PHPDBG_SET(color); 31 | PHPDBG_SET(colors); 32 | #endif 33 | PHPDBG_SET(oplog); 34 | PHPDBG_SET(break); 35 | PHPDBG_SET(breaks); 36 | PHPDBG_SET(quiet); 37 | PHPDBG_SET(stepping); 38 | PHPDBG_SET(refcount); 39 | 40 | extern const phpdbg_command_t phpdbg_set_commands[]; 41 | 42 | #endif /* PHPDBG_SET_H */ 43 | -------------------------------------------------------------------------------- /phpdbg_sigio_win32.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 7-4 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Anatol Belski | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | 20 | #include 21 | 22 | #include "phpdbg.h" 23 | #include "phpdbg_sigio_win32.h" 24 | 25 | 26 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 27 | 28 | 29 | VOID 30 | SigIoWatcherThread(VOID *p) 31 | { 32 | zend_uchar sig; 33 | struct win32_sigio_watcher_data *swd = (struct win32_sigio_watcher_data *)p; 34 | #ifdef ZTS 35 | void ***tsrm_ls = swd->tsrm_ls; 36 | #endif 37 | 38 | top: 39 | (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1 TSRMLS_CC); 40 | 41 | 42 | if (3 == sig) { 43 | /* XXX completely not sure it is done right here */ 44 | if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { 45 | if (raise(sig)) { 46 | goto top; 47 | } 48 | } 49 | if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { 50 | phpdbg_set_sigsafe_mem(&sig TSRMLS_CC); 51 | zend_try { 52 | phpdbg_force_interruption(TSRMLS_C); 53 | } zend_end_try(); 54 | phpdbg_clear_sigsafe_mem(TSRMLS_C); 55 | goto end; 56 | } 57 | if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { 58 | PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; 59 | } 60 | end: 61 | /* XXX set signaled flag to the caller thread, question is - whether it's needed */ 62 | ExitThread(sig); 63 | } else { 64 | goto top; 65 | } 66 | } 67 | 68 | 69 | /* Start this only for the time of the run or eval command, 70 | for so long that the main thread is busy serving some debug 71 | session. */ 72 | void 73 | sigio_watcher_start(void) 74 | { 75 | TSRMLS_FETCH(); 76 | 77 | PHPDBG_G(swd).fd = PHPDBG_G(io)[PHPDBG_STDIN].fd; 78 | #ifdef ZTS 79 | PHPDBG_G(swd).tsrm_ls = tsrm_ls; 80 | #endif 81 | 82 | PHPDBG_G(sigio_watcher_thread) = CreateThread( 83 | NULL, 84 | 0, 85 | (LPTHREAD_START_ROUTINE)SigIoWatcherThread, 86 | &PHPDBG_G(swd), 87 | 0, 88 | NULL); 89 | } 90 | 91 | void 92 | sigio_watcher_stop(void) 93 | { 94 | DWORD waited; 95 | TSRMLS_FETCH(); 96 | 97 | if (INVALID_HANDLE_VALUE == PHPDBG_G(sigio_watcher_thread)) { 98 | /* it probably did bail out already */ 99 | return; 100 | } 101 | 102 | waited = WaitForSingleObject(PHPDBG_G(sigio_watcher_thread), 300); 103 | 104 | if (WAIT_OBJECT_0 != waited) { 105 | if (!CancelSynchronousIo(PHPDBG_G(sigio_watcher_thread))) { 106 | /* error out */ 107 | } 108 | 109 | if (!TerminateThread(PHPDBG_G(sigio_watcher_thread), 0)) { 110 | /* error out */ 111 | } 112 | } 113 | 114 | PHPDBG_G(swd).fd = -1; 115 | PHPDBG_G(sigio_watcher_thread) = INVALID_HANDLE_VALUE; 116 | } 117 | 118 | -------------------------------------------------------------------------------- /phpdbg_sigio_win32.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 7-4 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Anatol Belski | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | 20 | #ifndef PHPDBG_SIGIO_WIN32_H 21 | #define PHPDBG_SIGIO_WIN32_H 22 | 23 | #include "phpdbg.h" 24 | #include "phpdbg_prompt.h" 25 | #include "phpdbg_io.h" 26 | 27 | struct win32_sigio_watcher_data { 28 | #ifdef ZTS 29 | void ***tsrm_ls; 30 | #endif 31 | int fd; 32 | }; 33 | 34 | void 35 | sigio_watcher_start(void); 36 | 37 | void 38 | sigio_watcher_stop(void); 39 | 40 | #endif /* PHPDBG_SIGIO_WIN32_H */ 41 | -------------------------------------------------------------------------------- /phpdbg_sigsafe.c: -------------------------------------------------------------------------------- 1 | #include "phpdbg_sigsafe.h" 2 | #include "phpdbg.h" 3 | 4 | ZEND_EXTERN_MODULE_GLOBALS(phpdbg); 5 | 6 | static inline void zend_mm_init(zend_mm_heap *heap) { 7 | zend_mm_free_block *p; 8 | int i; 9 | 10 | heap->free_bitmap = 0; 11 | heap->large_free_bitmap = 0; 12 | #if ZEND_MM_CACHE 13 | heap->cached = 0; 14 | memset(heap->cache, 0, sizeof(heap->cache)); 15 | #endif 16 | #if ZEND_MM_CACHE_STAT 17 | for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { 18 | heap->cache_stat[i].count = 0; 19 | } 20 | #endif 21 | p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0); 22 | for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { 23 | p->next_free_block = p; 24 | p->prev_free_block = p; 25 | p = (zend_mm_free_block *)((char *)p + sizeof(zend_mm_free_block *) * 2); 26 | heap->large_free_buckets[i] = NULL; 27 | } 28 | heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap); 29 | heap->rest_count = 0; 30 | } 31 | 32 | static zend_mm_storage* zend_mm_mem_init(void *params) { 33 | TSRMLS_FETCH(); 34 | 35 | return &PHPDBG_G(sigsafe_mem).storage; 36 | } 37 | 38 | static void zend_mm_mem_dummy(zend_mm_storage *storage) { 39 | } 40 | 41 | #define STR(x) #x 42 | #define EXP_STR(x) STR(x) 43 | 44 | static zend_mm_segment* zend_mm_mem_alloc(zend_mm_storage *storage, size_t size) { 45 | TSRMLS_FETCH(); 46 | 47 | if (EXPECTED(size == PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) { 48 | PHPDBG_G(sigsafe_mem).allocated = 1; 49 | return (zend_mm_segment *) PHPDBG_G(sigsafe_mem).mem; 50 | } 51 | 52 | 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")); 53 | 54 | if (*EG(bailout)) { 55 | LONGJMP(*EG(bailout), FAILURE); 56 | } 57 | 58 | write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n")); 59 | 60 | return NULL; 61 | } 62 | 63 | static zend_mm_segment* zend_mm_mem_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size) { 64 | return zend_mm_mem_alloc(storage, size); 65 | } 66 | 67 | static void zend_mm_mem_free(zend_mm_storage *storage, zend_mm_segment *ptr) { 68 | } 69 | 70 | 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 }; 71 | 72 | void phpdbg_set_sigsafe_mem(char *buffer TSRMLS_DC) { 73 | phpdbg_signal_safe_mem *mem = &PHPDBG_G(sigsafe_mem); 74 | mem->old_heap = zend_mm_set_heap(&mem->heap TSRMLS_CC); 75 | mem->mem = buffer; 76 | mem->allocated = 0; 77 | 78 | mem->storage.handlers = &phpdbg_handlers_sigsafe_mem; 79 | mem->heap.storage = &mem->storage; 80 | mem->heap.block_size = PHPDBG_SIGSAFE_MEM_SIZE; 81 | mem->heap.compact_size = 0; 82 | mem->heap.segments_list = NULL; 83 | zend_mm_init(&mem->heap); 84 | #if ZEND_MM_CACHE_STAT 85 | memset(mem->heap.cache_stat, 0, sizeof(mem->heap.cache_stat)); 86 | #endif 87 | mem->heap.use_zend_alloc = 1; 88 | mem->heap.real_size = 0; 89 | mem->heap.overflow = 0; 90 | mem->heap.real_peak = 0; 91 | mem->heap.limit = PHPDBG_SIGSAFE_MEM_SIZE; 92 | mem->heap.size = 0; 93 | mem->heap.peak = 0; 94 | mem->heap.internal = 0; 95 | mem->heap.reserve = NULL; 96 | mem->heap.reserve_size = 0; 97 | } 98 | 99 | zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D) { 100 | return PHPDBG_G(sigsafe_mem).old_heap; 101 | } 102 | 103 | void phpdbg_clear_sigsafe_mem(TSRMLS_D) { 104 | zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC); 105 | PHPDBG_G(sigsafe_mem).mem = NULL; 106 | } 107 | 108 | zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D) { 109 | return !!PHPDBG_G(sigsafe_mem).mem; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /phpdbg_sigsafe.h: -------------------------------------------------------------------------------- 1 | #ifndef PHPDBG_SIGSAFE_H 2 | #define PHPDBG_SIGSAFE_H 3 | 4 | #include "zend_mm_structs.h" 5 | 6 | #define PHPDBG_SIGSAFE_MEM_SIZE (1 << 20) 7 | 8 | typedef struct { 9 | char *mem; 10 | zend_bool allocated; 11 | zend_mm_heap heap; 12 | zend_mm_heap *old_heap; 13 | zend_mm_storage storage; 14 | } phpdbg_signal_safe_mem; 15 | 16 | #include "phpdbg.h" 17 | 18 | zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D); 19 | 20 | void phpdbg_set_sigsafe_mem(char *mem TSRMLS_DC); 21 | void phpdbg_clear_sigsafe_mem(TSRMLS_D); 22 | 23 | zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /phpdbg_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_UTILS_H 22 | #define PHPDBG_UTILS_H 23 | 24 | /** 25 | * Input scan functions 26 | */ 27 | PHPDBG_API int phpdbg_is_numeric(const char*); 28 | PHPDBG_API int phpdbg_is_empty(const char*); 29 | PHPDBG_API int phpdbg_is_addr(const char*); 30 | PHPDBG_API int phpdbg_is_class_method(const char*, size_t, char**, char**); 31 | PHPDBG_API const char *phpdbg_current_file(TSRMLS_D); 32 | PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC); 33 | PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*); 34 | PHPDBG_API const zend_function *phpdbg_get_function(const char*, const char* TSRMLS_DC); 35 | 36 | /* {{{ Color Management */ 37 | #define PHPDBG_COLOR_LEN 12 38 | #define PHPDBG_COLOR_D(color, code) \ 39 | {color, sizeof(color)-1, code} 40 | #define PHPDBG_COLOR_END \ 41 | {NULL, 0L, {0}} 42 | #define PHPDBG_ELEMENT_LEN 3 43 | #define PHPDBG_ELEMENT_D(name, id) \ 44 | {name, sizeof(name)-1, id} 45 | #define PHPDBG_ELEMENT_END \ 46 | {NULL, 0L, 0} 47 | 48 | #define PHPDBG_COLOR_INVALID -1 49 | #define PHPDBG_COLOR_PROMPT 0 50 | #define PHPDBG_COLOR_ERROR 1 51 | #define PHPDBG_COLOR_NOTICE 2 52 | #define PHPDBG_COLORS 3 53 | 54 | typedef struct _phpdbg_color_t { 55 | char *name; 56 | size_t name_length; 57 | const char code[PHPDBG_COLOR_LEN]; 58 | } phpdbg_color_t; 59 | 60 | typedef struct _phpdbg_element_t { 61 | char *name; 62 | size_t name_length; 63 | int id; 64 | } phpdbg_element_t; 65 | 66 | PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC); 67 | PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC); 68 | PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC); 69 | PHPDBG_API const phpdbg_color_t *phpdbg_get_colors(TSRMLS_D); 70 | PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC); /* }}} */ 71 | 72 | /* {{{ Prompt Management */ 73 | PHPDBG_API void phpdbg_set_prompt(const char* TSRMLS_DC); 74 | PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */ 75 | 76 | /* {{{ Console Width */ 77 | PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */ 78 | 79 | PHPDBG_API void phpdbg_set_async_io(int fd); 80 | 81 | int phpdbg_rebuild_symtable(TSRMLS_D); 82 | 83 | #if PHP_VERSION_ID < 50500 84 | /* copy from zend_hash.c PHP 5.5 for 5.4 compatibility */ 85 | static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) { 86 | Bucket *p; 87 | 88 | p = pos ? (*pos) : ht->pInternalPointer; 89 | 90 | if (!p) { 91 | Z_TYPE_P(key) = IS_NULL; 92 | } else if (p->nKeyLength) { 93 | Z_TYPE_P(key) = IS_STRING; 94 | Z_STRVAL_P(key) = IS_INTERNED(p->arKey) ? (char*)p->arKey : estrndup(p->arKey, p->nKeyLength - 1); 95 | Z_STRLEN_P(key) = p->nKeyLength - 1; 96 | } else { 97 | Z_TYPE_P(key) = IS_LONG; 98 | Z_LVAL_P(key) = p->h; 99 | } 100 | } 101 | #endif 102 | 103 | int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC); 104 | 105 | char *phpdbg_get_property_key(char *key); 106 | 107 | typedef int (*phpdbg_parse_var_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv TSRMLS_DC); 108 | 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); 109 | 110 | 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); 111 | 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); 112 | 113 | PHPDBG_API void phpdbg_xml_var_dump(zval **zv TSRMLS_DC); 114 | PHPDBG_API int phpdbg_print_flat_zval_r(zval **zv, int len TSRMLS_DC); 115 | 116 | #ifdef ZTS 117 | #define PHPDBG_OUTPUT_BACKUP_DEFINES() \ 118 | zend_output_globals *output_globals_ptr; \ 119 | zend_output_globals original_output_globals; \ 120 | output_globals_ptr = (zend_output_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)]; 121 | #else 122 | #define PHPDBG_OUTPUT_BACKUP_DEFINES() \ 123 | zend_output_globals *output_globals_ptr; \ 124 | zend_output_globals original_output_globals; \ 125 | output_globals_ptr = &output_globals; 126 | #endif 127 | 128 | #define PHPDBG_OUTPUT_BACKUP_SWAP() \ 129 | original_output_globals = *output_globals_ptr; \ 130 | memset(output_globals_ptr, 0, sizeof(zend_output_globals)); \ 131 | php_output_activate(TSRMLS_C); 132 | 133 | #define PHPDBG_OUTPUT_BACKUP() \ 134 | PHPDBG_OUTPUT_BACKUP_DEFINES() \ 135 | PHPDBG_OUTPUT_BACKUP_SWAP() 136 | 137 | #define PHPDBG_OUTPUT_BACKUP_RESTORE() \ 138 | php_output_deactivate(TSRMLS_C); \ 139 | *output_globals_ptr = original_output_globals; 140 | 141 | #endif /* PHPDBG_UTILS_H */ 142 | -------------------------------------------------------------------------------- /phpdbg_wait.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Bob Weinand | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef PHPDBG_WAIT_H 20 | #define PHPDBG_WAIT_H 21 | 22 | #include "zend.h" 23 | #include "phpdbg.h" 24 | 25 | PHPDBG_COMMAND(wait); 26 | 27 | void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC); 28 | 29 | #endif /* PHPDBG_WAIT_H */ 30 | -------------------------------------------------------------------------------- /phpdbg_watch.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_WATCH_H 22 | #define PHPDBG_WATCH_H 23 | 24 | #include "TSRM.h" 25 | #include "phpdbg_cmd.h" 26 | 27 | #ifdef _WIN32 28 | # include "phpdbg_win.h" 29 | #endif 30 | 31 | #define PHPDBG_WATCH(name) PHPDBG_COMMAND(watch_##name) 32 | 33 | /** 34 | * Printer Forward Declarations 35 | */ 36 | PHPDBG_WATCH(array); 37 | PHPDBG_WATCH(delete); 38 | PHPDBG_WATCH(recursive); 39 | 40 | /** 41 | * Commands 42 | */ 43 | 44 | static const phpdbg_command_t phpdbg_watch_commands[] = { 45 | PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s", 0), 46 | PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s", 0), 47 | PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s", 0), 48 | PHPDBG_END_COMMAND 49 | }; 50 | 51 | /* Watchpoint functions/typedefs */ 52 | 53 | typedef enum { 54 | WATCH_ON_ZVAL, 55 | WATCH_ON_HASHTABLE, 56 | } phpdbg_watchtype; 57 | 58 | 59 | #define PHPDBG_WATCH_SIMPLE 0x0 60 | #define PHPDBG_WATCH_RECURSIVE 0x1 61 | 62 | typedef struct _phpdbg_watchpoint_t phpdbg_watchpoint_t; 63 | 64 | struct _phpdbg_watchpoint_t { 65 | phpdbg_watchpoint_t *parent; 66 | HashTable *parent_container; 67 | char *name_in_parent; 68 | size_t name_in_parent_len; 69 | char *str; 70 | size_t str_len; 71 | union { 72 | zval *zv; 73 | HashTable *ht; 74 | void *ptr; 75 | } addr; 76 | size_t size; 77 | phpdbg_watchtype type; 78 | char flags; 79 | }; 80 | 81 | void phpdbg_setup_watchpoints(TSRMLS_D); 82 | 83 | #ifndef _WIN32 84 | int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC); 85 | #else 86 | int phpdbg_watchpoint_segfault_handler(void *addr TSRMLS_DC); 87 | #endif 88 | 89 | void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch); 90 | void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch); 91 | 92 | int phpdbg_delete_var_watchpoint(char *input, size_t len TSRMLS_DC); 93 | int phpdbg_create_var_watchpoint(char *input, size_t len TSRMLS_DC); 94 | 95 | int phpdbg_print_changed_zvals(TSRMLS_D); 96 | 97 | void phpdbg_list_watchpoints(TSRMLS_D); 98 | 99 | void phpdbg_watch_efree(void *ptr); 100 | 101 | 102 | static long phpdbg_pagesize; 103 | 104 | static zend_always_inline void *phpdbg_get_page_boundary(void *addr) { 105 | return (void *)((size_t)addr & ~(phpdbg_pagesize - 1)); 106 | } 107 | 108 | static zend_always_inline size_t phpdbg_get_total_page_size(void *addr, size_t size) { 109 | return (size_t)phpdbg_get_page_boundary((void *)((size_t)addr + size - 1)) - (size_t)phpdbg_get_page_boundary(addr) + phpdbg_pagesize; 110 | } 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /phpdbg_webdata_transfer.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Bob Weinand | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #include "phpdbg_webdata_transfer.h" 20 | #include "ext/standard/php_var.h" 21 | 22 | PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC) { 23 | zval array; 24 | HashTable *ht; 25 | /* I really need to change that to an array of zvals... */ 26 | zval zv1 = {{0}}, *zvp1 = &zv1; 27 | zval zv2 = {{0}}, *zvp2 = &zv2; 28 | zval zv3 = {{0}}, *zvp3 = &zv3; 29 | zval zv4 = {{0}}, *zvp4 = &zv4; 30 | zval zv5 = {{0}}, *zvp5 = &zv5; 31 | zval zv6 = {{0}}, *zvp6 = &zv6; 32 | zval zv7 = {{0}}, *zvp7 = &zv7; 33 | zval zv8 = {{0}}, *zvp8 = &zv8; 34 | zval zv9 = {{0}}, *zvp9 = &zv9; 35 | 36 | array_init(&array); 37 | ht = Z_ARRVAL(array); 38 | 39 | /* fetch superglobals */ 40 | { 41 | zend_is_auto_global(ZEND_STRL("GLOBALS") TSRMLS_CC); 42 | /* might be JIT */ 43 | zend_is_auto_global(ZEND_STRL("_ENV") TSRMLS_CC); 44 | zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC); 45 | zend_is_auto_global(ZEND_STRL("_REQUEST") TSRMLS_CC); 46 | array_init(&zv1); 47 | zend_hash_copy(Z_ARRVAL(zv1), &EG(symbol_table), NULL, (void *) NULL, sizeof(zval *)); 48 | Z_ARRVAL(zv1)->pDestructor = NULL; /* we're operating on a copy! Don't double free zvals */ 49 | zend_hash_del(Z_ARRVAL(zv1), "GLOBALS", sizeof("GLOBALS")); /* do not use the reference to itself in json */ 50 | zend_hash_add(ht, "GLOBALS", sizeof("GLOBALS"), &zvp1, sizeof(zval *), NULL); 51 | } 52 | 53 | #if PHP_VERSION_ID >= 50600 54 | /* save php://input */ 55 | { 56 | php_stream *stream; 57 | int len; 58 | char *contents; 59 | 60 | stream = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir)); 61 | if ((len = php_stream_copy_to_mem(stream, &contents, PHP_STREAM_COPY_ALL, 0)) > 0) { 62 | ZVAL_STRINGL(&zv2, contents, len, 0); 63 | } else { 64 | ZVAL_EMPTY_STRING(&zv2); 65 | } 66 | Z_SET_REFCOUNT(zv2, 2); 67 | zend_hash_add(ht, "input", sizeof("input"), &zvp2, sizeof(zval *), NULL); 68 | } 69 | #endif 70 | 71 | /* change sapi name */ 72 | { 73 | if (sapi_module.name) { 74 | ZVAL_STRING(&zv6, sapi_module.name, 0); 75 | } else { 76 | Z_TYPE(zv6) = IS_NULL; 77 | } 78 | Z_SET_REFCOUNT(zv6, 2); 79 | zend_hash_add(ht, "sapi_name", sizeof("sapi_name"), &zvp6, sizeof(zval *), NULL); 80 | } 81 | 82 | /* print phpinfo() as text? */ 83 | { 84 | Z_LVAL(zv9) = sapi_module.phpinfo_as_text; 85 | Z_TYPE(zv9) = IS_LONG; 86 | zend_hash_add(ht, "phpinfo_as_text", sizeof("phpinfo_as_text"), &zvp9, sizeof(zval *), NULL); 87 | } 88 | 89 | /* handle modules / extensions */ 90 | { 91 | HashPosition position; 92 | zend_module_entry *module; 93 | zend_extension *extension; 94 | zend_llist_position pos; 95 | 96 | array_init(&zv7); 97 | for (zend_hash_internal_pointer_reset_ex(&module_registry, &position); 98 | zend_hash_get_current_data_ex(&module_registry, (void**) &module, &position) == SUCCESS; 99 | zend_hash_move_forward_ex(&module_registry, &position)) { 100 | zval **value = emalloc(sizeof(zval *)); 101 | ALLOC_ZVAL(*value); 102 | ZVAL_STRING(*value, module->name, 1); 103 | zend_hash_next_index_insert(Z_ARRVAL(zv7), value, sizeof(zval *), NULL); 104 | } 105 | zend_hash_add(ht, "modules", sizeof("modules"), &zvp7, sizeof(zval *), NULL); 106 | 107 | array_init(&zv8); 108 | extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos); 109 | while (extension) { 110 | zval **value = emalloc(sizeof(zval *)); 111 | ALLOC_ZVAL(*value); 112 | ZVAL_STRING(*value, extension->name, 1); 113 | zend_hash_next_index_insert(Z_ARRVAL(zv8), value, sizeof(zval *), NULL); 114 | extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos); 115 | } 116 | zend_hash_add(ht, "extensions", sizeof("extensions"), &zvp8, sizeof(zval *), NULL); 117 | } 118 | 119 | /* switch cwd */ 120 | if (SG(options) & SAPI_OPTION_NO_CHDIR) { 121 | char *ret = NULL; 122 | char path[MAXPATHLEN]; 123 | 124 | #if HAVE_GETCWD 125 | ret = VCWD_GETCWD(path, MAXPATHLEN); 126 | #elif HAVE_GETWD 127 | ret = VCWD_GETWD(path); 128 | #endif 129 | if (ret) { 130 | ZVAL_STRING(&zv5, path, 1); 131 | Z_SET_REFCOUNT(zv5, 1); 132 | zend_hash_add(ht, "cwd", sizeof("cwd"), &zvp5, sizeof(zval *), NULL); 133 | } 134 | } 135 | 136 | /* get system ini entries */ 137 | { 138 | HashPosition position; 139 | zend_ini_entry *ini_entry; 140 | 141 | array_init(&zv3); 142 | for (zend_hash_internal_pointer_reset_ex(EG(ini_directives), &position); 143 | zend_hash_get_current_data_ex(EG(ini_directives), (void**) &ini_entry, &position) == SUCCESS; 144 | zend_hash_move_forward_ex(EG(ini_directives), &position)) { 145 | zval **value = emalloc(sizeof(zval *)); 146 | if (ini_entry->modified) { 147 | if (!ini_entry->orig_value) { 148 | efree(value); 149 | continue; 150 | } 151 | ALLOC_ZVAL(*value); 152 | ZVAL_STRINGL(*value, ini_entry->orig_value, ini_entry->orig_value_length, 1); 153 | } else { 154 | if (!ini_entry->value) { 155 | efree(value); 156 | continue; 157 | } 158 | ALLOC_ZVAL(*value); 159 | ZVAL_STRINGL(*value, ini_entry->value, ini_entry->value_length, 1); 160 | } 161 | zend_hash_add(Z_ARRVAL(zv3), ini_entry->name, ini_entry->name_length, value, sizeof(zval *), NULL); 162 | } 163 | zend_hash_add(ht, "systemini", sizeof("systemini"), &zvp3, sizeof(zval *), NULL); 164 | } 165 | 166 | /* get perdir ini entries */ 167 | if (EG(modified_ini_directives)) { 168 | HashPosition position; 169 | zend_ini_entry *ini_entry; 170 | 171 | array_init(&zv4); 172 | for (zend_hash_internal_pointer_reset_ex(EG(modified_ini_directives), &position); 173 | zend_hash_get_current_data_ex(EG(modified_ini_directives), (void**) &ini_entry, &position) == SUCCESS; 174 | zend_hash_move_forward_ex(EG(modified_ini_directives), &position)) { 175 | zval **value = emalloc(sizeof(zval *)); 176 | if (!ini_entry->value) { 177 | efree(value); 178 | continue; 179 | } 180 | ALLOC_ZVAL(*value); 181 | ZVAL_STRINGL(*value, ini_entry->value, ini_entry->value_length, 1); 182 | zend_hash_add(Z_ARRVAL(zv4), ini_entry->name, ini_entry->name_length, value, sizeof(zval *), NULL); 183 | } 184 | zend_hash_add(ht, "userini", sizeof("userini"), &zvp4, sizeof(zval *), NULL); 185 | } 186 | 187 | /* encode data */ 188 | { 189 | php_serialize_data_t var_hash; 190 | smart_str buf = {0}; 191 | zval *arrayptr = &array; 192 | 193 | PHP_VAR_SERIALIZE_INIT(var_hash); 194 | php_var_serialize(&buf, &arrayptr, &var_hash TSRMLS_CC); 195 | PHP_VAR_SERIALIZE_DESTROY(var_hash); 196 | *msg = buf.c; 197 | *len = buf.len; 198 | } 199 | 200 | zval_dtor(&array); 201 | } 202 | -------------------------------------------------------------------------------- /phpdbg_webdata_transfer.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Bob Weinand | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef PHPDBG_WEBDATA_TRANSFER_H 20 | #define PHPDBG_WEBDATA_TRANSFER_H 21 | 22 | #include "zend.h" 23 | #include "phpdbg.h" 24 | 25 | PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC); 26 | 27 | #endif /* PHPDBG_WEBDATA_TRANSFER_H */ 28 | -------------------------------------------------------------------------------- /phpdbg_win.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #include "zend.h" 22 | #include "phpdbg.h" 23 | 24 | int mprotect(void *addr, size_t size, int protection) { 25 | int var; 26 | return (int)VirtualProtect(addr, size, protection == (PROT_READ | PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, &var); 27 | } 28 | 29 | int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp) { 30 | EXCEPTION_RECORD *xr = xp->ExceptionRecord; 31 | CONTEXT *xc = xp->ContextRecord; 32 | 33 | if(xr->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { 34 | TSRMLS_FETCH(); 35 | 36 | if (phpdbg_watchpoint_segfault_handler((void *)xr->ExceptionInformation[1] TSRMLS_CC) == SUCCESS) { 37 | return EXCEPTION_CONTINUE_EXECUTION; 38 | } 39 | } 40 | 41 | return EXCEPTION_CONTINUE_SEARCH; 42 | } 43 | -------------------------------------------------------------------------------- /phpdbg_win.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2014 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Felipe Pena | 16 | | Authors: Joe Watkins | 17 | | Authors: Bob Weinand | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHPDBG_WIN_H 22 | #define PHPDBG_WIN_H 23 | 24 | #include "winbase.h" 25 | #include "windows.h" 26 | #include "excpt.h" 27 | 28 | #define PROT_READ 1 29 | #define PROT_WRITE 2 30 | 31 | int mprotect(void *addr, size_t size, int protection); 32 | 33 | void phpdbg_win_set_mm_heap(zend_mm_heap *heap); 34 | 35 | int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp); 36 | 37 | #endif -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | sprintf, __METHOD__, $greeting); 13 | return $this; 14 | } 15 | } 16 | 17 | function mine() { 18 | var_dump(func_get_args()); 19 | } 20 | 21 | function test($x, $y = 0) { 22 | $var = $x + 1; 23 | $var += 2; 24 | $var <<= 3; 25 | 26 | $foo = function () { 27 | echo "bar!\n"; 28 | }; 29 | 30 | $foo(); 31 | 32 | yield $var; 33 | } 34 | 35 | $dbg = new phpdbg(); 36 | 37 | var_dump( 38 | $dbg->isGreat("PHP Rocks!!")); 39 | 40 | foreach (test(1,2) as $gen) 41 | continue; 42 | 43 | echo "it works!\n"; 44 | 45 | if (isset($dump)) 46 | var_dump($_SERVER); 47 | 48 | function phpdbg_test_ob() 49 | { 50 | echo 'Start'; 51 | ob_start(); 52 | echo 'Hello'; 53 | $b = ob_get_clean(); 54 | echo 'End'; 55 | echo $b; 56 | } 57 | 58 | $array = [ 59 | 1, 60 | 2, 61 | [3, 4], 62 | [5, 6], 63 | ]; 64 | 65 | $array[] = 7; 66 | 67 | array_walk($array, function (&$item) { 68 | if (is_array($item)) 69 | $item[0] += 2; 70 | else 71 | $item -= 1; 72 | }); 73 | 74 | class testClass { 75 | public $a = 2; 76 | protected $b = [1, 3]; 77 | private $c = 7; 78 | } 79 | 80 | $obj = new testClass; 81 | 82 | $test = $obj->a; 83 | 84 | $obj->a += 2; 85 | $test -= 2; 86 | 87 | unset($obj); 88 | -------------------------------------------------------------------------------- /tests/commands/0001_basic.test: -------------------------------------------------------------------------------- 1 | ####################################################### 2 | # name: basic 3 | # purpose: check basic functionality of phpdbg console 4 | # expect: TEST::EXACT 5 | # options: -rr 6 | ####################################################### 7 | # [Nothing to execute!] 8 | ####################################################### 9 | -------------------------------------------------------------------------------- /tests/commands/0002_set.test: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # name: set 3 | # purpose: tests for set commands 4 | # expect: TEST::CISTRING 5 | # options: -rr 6 | ################################################# 7 | # setting prompt color 8 | # setting error color 9 | # setting notice color 10 | # Failed to find breakpoint #0 11 | # [Oplog off] 12 | # opened oplog test.log 13 | # nothing 14 | ################################################# 15 | set color prompt none 16 | set color error none 17 | set color notice none 18 | set prompt promot> 19 | set break 0 20 | set oplog 21 | set oplog test.log 22 | -------------------------------------------------------------------------------- /tests/commands/0101_info.test: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # name: info 3 | # purpose: test info commands 4 | # expect: TEST::FORMAT 5 | # options: -rr 6 | ################################################# 7 | #[User Classes (%d)] 8 | #User Class test (3) 9 | #|---- in phpdbginit code on line %d 10 | ################################################# 11 | <: 12 | class test { 13 | public function testMethod(){} 14 | private function testPrivateMethod(){} 15 | protected function testProtectedMethod(){} 16 | } 17 | :> 18 | info classes 19 | q 20 | -------------------------------------------------------------------------------- /tests/commands/0102_print.test: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # name: print 3 | # purpose: test print commands 4 | # expect: TEST::FORMAT 5 | # options: -rr 6 | ################################################# 7 | #[User Class: test (3 methods)] 8 | #L%d-%d test::testMethod() %s 9 | # L%d %s ZEND_RETURN C%d 10 | # L%d-%d test::testPrivateMethod() %s 11 | # L%d %s ZEND_RETURN C%d 12 | # L%d-%d test::testProtectedMethod() %s 13 | # L%d %s ZEND_RETURN C%d 14 | #[User Method testMethod (1 ops)] 15 | # L%d-%d test::testMethod() %s 16 | # L%d %s ZEND_RETURN C%d 17 | ################################################# 18 | <: 19 | class test { 20 | public function testMethod(){} 21 | private function testPrivateMethod(){} 22 | protected function testProtectedMethod(){} 23 | } 24 | :> 25 | print class test 26 | print method test::testMethod 27 | q 28 | -------------------------------------------------------------------------------- /tests/commands/0103_register.test: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # name: register 3 | # purpose: test registration functions 4 | # expect: TEST::FORMAT 5 | # options: -rr 6 | ################################################# 7 | #[Registered test_function] 8 | #array(5) { 9 | # [0]=> 10 | # int(1) 11 | # [1]=> 12 | # int(2) 13 | # [2]=> 14 | # int(3) 15 | # [3]=> 16 | # int(4) 17 | # [4]=> 18 | # int(5) 19 | #} 20 | ################################################# 21 | <: 22 | function test_function() { 23 | var_dump(func_get_args()); 24 | } 25 | :> 26 | R test_function 27 | test_function 1 2 3 4 5 28 | q 29 | -------------------------------------------------------------------------------- /tests/commands/0104_clean.test: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # name: clean 3 | # purpose: test cleaning environment 4 | # expect: TEST::FORMAT 5 | # options: -rr 6 | ################################################# 7 | #Cleaning Execution Environment 8 | #Classes %d 9 | #Functions %d 10 | #Constants %d 11 | #Includes %d 12 | ################################################# 13 | clean 14 | quit 15 | -------------------------------------------------------------------------------- /tests/commands/0105_clear.test: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # name: clear 3 | # purpose: test clearing breakpoints 4 | # expect: TEST::FORMAT 5 | # options: -rr 6 | ################################################# 7 | #Clearing Breakpoints 8 | #File%w%d 9 | #Functions%w%d 10 | #Methods%w%d 11 | #Oplines%w%d 12 | #File oplines%w%d 13 | #Function oplines%w%d 14 | #Method oplines%w%d 15 | #Conditionals%w%d 16 | ################################################# 17 | clear 18 | quit 19 | -------------------------------------------------------------------------------- /tests/commands/0106_compile.test: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # name: compile 3 | # purpose: test compiling code 4 | # expect: TEST::FORMAT 5 | # options: -rr 6 | ################################################# 7 | #[Successful compilation of %s] 8 | #Hello World 9 | #[Script ended normally] 10 | ################################################# 11 | <: 12 | define('OUT', 13 | tempnam(null, "phpdbg")); 14 | file_put_contents(OUT, ""); 15 | phpdbg_exec(OUT); 16 | :> 17 | run 18 | quit 19 | -------------------------------------------------------------------------------- /travis/ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | git clone https://github.com/php/php-src 3 | cd php-src 4 | git checkout $PHP 5 | cd sapi 6 | rm -rf phpdbg 7 | git clone https://github.com/krakjoe/phpdbg.git 8 | cd ../ 9 | ./buildconf --force 10 | ./configure --disable-all --enable-phpdbg --enable-maintainer-zts 11 | make 12 | -------------------------------------------------------------------------------- /web-bootstrap.php: -------------------------------------------------------------------------------- 1 | 'localhost', 26 | 'HTTP_CONNECTION' => 'keep-alive', 27 | 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 28 | 'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.65 Safari/537.36', 29 | 'HTTP_ACCEPT_ENCODING' => 'gzip,deflate,sdch', 30 | 'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8', 31 | '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)', 32 | 'PATH' => '/usr/local/bin:/usr/bin:/bin', 33 | 'SERVER_SIGNATURE' => '
Apache/2.4.6 (Ubuntu) Server at phpdbg.com Port 80
', 34 | 'SERVER_SOFTWARE' => 'Apache/2.4.6 (Ubuntu)', 35 | 'SERVER_NAME' => 'localhost', 36 | 'SERVER_ADDR' => '127.0.0.1', 37 | 'SERVER_PORT' => '80', 38 | 'REMOTE_ADDR' => '127.0.0.1', 39 | 'DOCUMENT_ROOT' => PHPDBG_BOOTPATH, 40 | 'REQUEST_SCHEME' => 'http', 41 | 'CONTEXT_PREFIX' => '', 42 | 'CONTEXT_DOCUMENT_ROOT' => PHPDBG_BOOTPATH, 43 | 'SERVER_ADMIN' => '[no address given]', 44 | 'SCRIPT_FILENAME' => sprintf( 45 | '%s/%s', PHPDBG_BOOTPATH, PHPDBG_BOOTSTRAP 46 | ), 47 | 'REMOTE_PORT' => '47931', 48 | 'GATEWAY_INTERFACE' => 'CGI/1.1', 49 | 'SERVER_PROTOCOL' => 'HTTP/1.1', 50 | 'REQUEST_METHOD' => 'GET', 51 | 'QUERY_STRING' => '', 52 | 'REQUEST_URI' => PHPDBG_BOOTSTRAPPED, 53 | 'SCRIPT_NAME' => PHPDBG_BOOTSTRAPPED, 54 | 'PHP_SELF' => PHPDBG_BOOTSTRAPPED, 55 | 'REQUEST_TIME' => time(), 56 | ); 57 | 58 | $_GET = array(); 59 | $_REQUEST = array(); 60 | $_POST = array(); 61 | $_COOKIE = array(); 62 | $_FILES = array(); 63 | 64 | chdir(PHPDBG_BOOTPATH); 65 | -------------------------------------------------------------------------------- /zend_mm_structs.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEND_MM_STRUCTS_H 2 | #define ZEND_MM_STRUCTS_H 3 | 4 | /* structs and macros defined in Zend/zend_alloc.c 5 | Needed for realizing watchpoints and sigsafe memory */ 6 | 7 | #include "zend.h" 8 | 9 | #ifndef ZEND_MM_COOKIES 10 | # define ZEND_MM_COOKIES ZEND_DEBUG 11 | #endif 12 | 13 | #define ZEND_MM_CACHE 1 14 | #ifndef ZEND_MM_CACHE_STAT 15 | # define ZEND_MM_CACHE_STAT 0 16 | #endif 17 | 18 | typedef struct _zend_mm_block_info { 19 | #if ZEND_MM_COOKIES 20 | size_t _cookie; 21 | #endif 22 | size_t _size; 23 | size_t _prev; 24 | } zend_mm_block_info; 25 | 26 | typedef struct _zend_mm_small_free_block { 27 | zend_mm_block_info info; 28 | #if ZEND_DEBUG 29 | unsigned int magic; 30 | #ifdef ZTS 31 | THREAD_T thread_id; 32 | #endif 33 | #endif 34 | struct _zend_mm_free_block *prev_free_block; 35 | struct _zend_mm_free_block *next_free_block; 36 | } zend_mm_small_free_block; 37 | 38 | typedef struct _zend_mm_free_block { 39 | zend_mm_block_info info; 40 | #if ZEND_DEBUG 41 | unsigned int magic; 42 | #ifdef ZTS 43 | THREAD_T thread_id; 44 | #endif 45 | #endif 46 | struct _zend_mm_free_block *prev_free_block; 47 | struct _zend_mm_free_block *next_free_block; 48 | 49 | struct _zend_mm_free_block **parent; 50 | struct _zend_mm_free_block *child[2]; 51 | } zend_mm_free_block; 52 | 53 | #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \ 54 | (zend_mm_free_block *) ((char *)&heap->free_buckets[index * 2] + \ 55 | sizeof(zend_mm_free_block *) * 2 - \ 56 | sizeof(zend_mm_small_free_block)) 57 | 58 | #define ZEND_MM_REST_BUCKET(heap) \ 59 | (zend_mm_free_block *)((char *)&heap->rest_buckets[0] + \ 60 | sizeof(zend_mm_free_block *) * 2 - \ 61 | sizeof(zend_mm_small_free_block)) 62 | 63 | #define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3) 64 | struct _zend_mm_heap { 65 | int use_zend_alloc; 66 | void *(*_malloc)(size_t); 67 | void (*_free)(void *); 68 | void *(*_realloc)(void *, size_t); 69 | size_t free_bitmap; 70 | size_t large_free_bitmap; 71 | size_t block_size; 72 | size_t compact_size; 73 | zend_mm_segment *segments_list; 74 | zend_mm_storage *storage; 75 | size_t real_size; 76 | size_t real_peak; 77 | size_t limit; 78 | size_t size; 79 | size_t peak; 80 | size_t reserve_size; 81 | void *reserve; 82 | int overflow; 83 | int internal; 84 | #if ZEND_MM_CACHE 85 | unsigned int cached; 86 | zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS]; 87 | #endif 88 | zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2]; 89 | zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS]; 90 | zend_mm_free_block *rest_buckets[2]; 91 | int rest_count; 92 | #if ZEND_MM_CACHE_STAT 93 | struct { 94 | int count; 95 | int max_count; 96 | int hit; 97 | int miss; 98 | } cache_stat[ZEND_MM_NUM_BUCKETS+1]; 99 | #endif 100 | }; 101 | 102 | #endif 103 | --------------------------------------------------------------------------------