mirror of
https://github.com/php/php-src.git
synced 2024-11-25 02:44:58 +08:00
Merge branch 'master' of sapi/phpdbg into PHP-5.6
Including phpdbg.
This commit is contained in:
commit
cee72c13d7
10
sapi/phpdbg/.gdbinit
Normal file
10
sapi/phpdbg/.gdbinit
Normal file
@ -0,0 +1,10 @@
|
||||
define ____phpdbg_globals
|
||||
if basic_functions_module.zts
|
||||
if !$tsrm_ls
|
||||
set $tsrm_ls = ts_resource_ex(0, 0)
|
||||
end
|
||||
set $phpdbg = ((zend_phpdbg_globals*) (*((void ***) $tsrm_ls))[phpdbg_globals_id-1])
|
||||
else
|
||||
set $phpdbg = phpdbg_globals
|
||||
end
|
||||
end
|
5
sapi/phpdbg/.gitignore
vendored
Normal file
5
sapi/phpdbg/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.libs/
|
||||
./phpdbg
|
||||
*.lo
|
||||
*.o
|
||||
build
|
105
sapi/phpdbg/.phpdbginit
Normal file
105
sapi/phpdbg/.phpdbginit
Normal file
@ -0,0 +1,105 @@
|
||||
##########################################################
|
||||
# .phpdbginit
|
||||
#
|
||||
# Lines starting with # are ignored
|
||||
# Code must start and end with <: and :> respectively
|
||||
##########################################################
|
||||
# Place initialization commands one per line
|
||||
##########################################################
|
||||
# exec sapi/phpdbg/test.php
|
||||
# set color prompt white-bold
|
||||
# set color notice green
|
||||
# set color error red
|
||||
|
||||
##########################################################
|
||||
# Embedding code in .phpdbginit
|
||||
##########################################################
|
||||
<:
|
||||
/*
|
||||
* This embedded PHP is executed at init time
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions defined and registered by init
|
||||
* will persist across cleans
|
||||
*/
|
||||
|
||||
/*
|
||||
function my_debugging_function()
|
||||
{
|
||||
var_dump(func_get_args());
|
||||
}
|
||||
*/
|
||||
|
||||
/* phpdbg_break(PHPDBG_METHOD, "phpdbg::method"); */
|
||||
/* phpdbg_break(PHPDBG_FUNC, "my_global_function"); */
|
||||
/* phpdbg_break(PHPDBG_FILE, "/path/to/file.php:10"); */
|
||||
|
||||
/*
|
||||
If readline is loaded, you might want to setup completion:
|
||||
*/
|
||||
if (function_exists('readline_completion_function')) {
|
||||
readline_completion_function(function(){
|
||||
return array_merge(
|
||||
get_defined_functions()['user'],
|
||||
array_keys(get_defined_constants())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Setting argv made trivial ...
|
||||
|
||||
argv 1 2 3 4
|
||||
^ set argv for next execution
|
||||
|
||||
argv
|
||||
^ unset argv for next execution
|
||||
|
||||
*/
|
||||
function argv()
|
||||
{
|
||||
$argv = func_get_args();
|
||||
|
||||
if (!$argv) {
|
||||
$_SERVER['argv'] = array();
|
||||
$_SERVER['argc'] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
$_SERVER['argv'] = array_merge
|
||||
(
|
||||
array("phpdbg"),
|
||||
$argv
|
||||
);
|
||||
$_SERVER['argc'] = count($_SERVER['argv']);
|
||||
|
||||
return $_SERVER['argv'];
|
||||
}
|
||||
:>
|
||||
##########################################################
|
||||
# Now carry on initializing phpdbg ...
|
||||
##########################################################
|
||||
# R my_debugging_function
|
||||
# R argv
|
||||
|
||||
##########################################################
|
||||
# PHP has many functions that might be useful
|
||||
# ... you choose ...
|
||||
##########################################################
|
||||
# R touch
|
||||
# R unlink
|
||||
# R scandir
|
||||
# R glob
|
||||
|
||||
##########################################################
|
||||
# Remember: *you have access to the shell*
|
||||
##########################################################
|
||||
# The output of registered function calls is not,
|
||||
# by default, very pretty (unless you implement
|
||||
# and register a new implementation for phpdbg)
|
||||
# The output of shell commands will usually be more
|
||||
# readable on the console
|
||||
##########################################################
|
||||
# TLDR; if you have a good shell, use it ...
|
||||
##########################################################
|
3
sapi/phpdbg/.travis.yml
Normal file
3
sapi/phpdbg/.travis.yml
Normal file
@ -0,0 +1,3 @@
|
||||
language: c
|
||||
|
||||
script: ./travis/ci.sh
|
52
sapi/phpdbg/Changelog.md
Normal file
52
sapi/phpdbg/Changelog.md
Normal file
@ -0,0 +1,52 @@
|
||||
ChangeLog for phpdbg
|
||||
====================
|
||||
|
||||
Version 0.3.0 2013-00-00
|
||||
------------------------
|
||||
|
||||
1. Added ability to disable an enable a single breakpoint
|
||||
2. Added ability to override SAPI name
|
||||
3. Added extended conditional breakpoint support "break at"
|
||||
4. Fix loading of zend extnsions with -z
|
||||
5. Fix crash when loading .phpdbginit with command line switch
|
||||
6. Fix crash on startup errors
|
||||
7. Added init.d for remote console (redhat)
|
||||
8. Added phpdbg_exec userland function
|
||||
9. Added testing facilities
|
||||
10. Added break on n-th opline support
|
||||
11. Improved trace output
|
||||
|
||||
Version 0.2.0 2013-11-31
|
||||
------------------------
|
||||
|
||||
1. Added "break delete <id>" command
|
||||
2. Added "break opcode <opcode>" command
|
||||
3. Added "set" command - control prompt and console colors
|
||||
4. .phpdbginit now searched in (additional) ini dirs
|
||||
5. Added source command - load additional .phpdbginit script during session
|
||||
6. Added remote console mode
|
||||
7. Added info memory command
|
||||
|
||||
Version 0.1.0 2013-11-23
|
||||
------------------------
|
||||
|
||||
1. New commands:
|
||||
- until (continue until the current line is executed)
|
||||
- frame (switch to a frame in the current stack for inspection)
|
||||
- info (quick access to useful information on the console)
|
||||
- finish (continue until the current function has returned)
|
||||
- leave (continue until the current function is returning)
|
||||
- shell (shell a command)
|
||||
- register (register a function for use as a command)
|
||||
2. Added printers for class and method
|
||||
3. Make uniform commands and aliases where possible
|
||||
4. Include all alias information and sub-command information in help
|
||||
5. Added signal handling to break execution (ctrl-c)
|
||||
6. Fixed #13 (Output Buffering Control seems fail)
|
||||
7. Fixed #14 (Fixed typo in Makefile.frag)
|
||||
|
||||
|
||||
Version 0.0.1 2013-11-15
|
||||
------------------------
|
||||
|
||||
1. Initial features
|
28
sapi/phpdbg/Makefile.frag
Normal file
28
sapi/phpdbg/Makefile.frag
Normal file
@ -0,0 +1,28 @@
|
||||
phpdbg: $(BUILD_BINARY)
|
||||
|
||||
phpdbg-shared: $(BUILD_SHARED)
|
||||
|
||||
$(BUILD_SHARED): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS)
|
||||
$(BUILD_PHPDBG_SHARED)
|
||||
|
||||
$(BUILD_BINARY): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_PHPDBG_OBJS)
|
||||
$(BUILD_PHPDBG)
|
||||
|
||||
install-phpdbg: $(BUILD_BINARY)
|
||||
@echo "Installing phpdbg binary: $(INSTALL_ROOT)$(bindir)/"
|
||||
@$(mkinstalldirs) $(INSTALL_ROOT)$(bindir)
|
||||
@$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log
|
||||
@$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run
|
||||
@$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT)
|
||||
|
||||
clean-phpdbg:
|
||||
@echo "Cleaning phpdbg object files ..."
|
||||
find sapi/phpdbg/ -name *.lo -o -name *.o | xargs rm -f
|
||||
|
||||
test-phpdbg:
|
||||
@echo "Running phpdbg tests ..."
|
||||
@$(top_builddir)/sapi/cli/php sapi/phpdbg/tests/run-tests.php --phpdbg sapi/phpdbg/phpdbg
|
||||
|
||||
.PHONY: clean-phpdbg test-phpdbg
|
||||
|
||||
|
83
sapi/phpdbg/README.md
Normal file
83
sapi/phpdbg/README.md
Normal file
@ -0,0 +1,83 @@
|
||||
The interactive PHP debugger
|
||||
============================
|
||||
|
||||
Implemented as a SAPI module, phpdbg can excert complete control over the environment without impacting the functionality or performance of your code.
|
||||
|
||||
phpdbg aims to be a lightweight, powerful, easy to use debugging platform for PHP 5.4+
|
||||
|
||||
[![phpdbg on travis-ci](https://travis-ci.org/krakjoe/phpdbg.png?branch=master)](https://travis-ci.org/krakjoe/phpdbg)
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
- Stepthrough Debugging
|
||||
- Flexible Breakpoints (Class Method, Function, File:Line, Address, Opcode)
|
||||
- Easy Access to PHP with built-in eval()
|
||||
- Easy Access to Currently Executing Code
|
||||
- Userland API
|
||||
- SAPI Agnostic - Easily Integrated
|
||||
- PHP Configuration File Support
|
||||
- JIT Super Globals - Set Your Own!!
|
||||
- Optional readline Support - Comfortable Terminal Operation
|
||||
- Remote Debugging Support - Bundled Java GUI
|
||||
- Easy Operation - See Help :)
|
||||
|
||||
Planned
|
||||
=======
|
||||
|
||||
- Improve Everything :)
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
To install **phpdbg**, you must compile the source against your PHP installation sources, and enable the SAPI with the configure command.
|
||||
|
||||
```
|
||||
cd /usr/src/php-src/sapi
|
||||
git clone https://github.com/krakjoe/phpdbg
|
||||
cd ../
|
||||
./buildconf --force
|
||||
./configure --enable-phpdbg
|
||||
make -j8
|
||||
make install-phpdbg
|
||||
```
|
||||
|
||||
Where the source directory has been used previously to build PHP, there exists a file named *config.nice* which can be used to invoke configure with the same
|
||||
parameters as were used by the last execution of *configure*.
|
||||
|
||||
**Note:** PHP must be configured with the switch --with-readline for phpdbg to support history, autocompletion, tab-listing etc.
|
||||
|
||||
Command Line Options
|
||||
====================
|
||||
|
||||
The following switches are implemented (just like cli SAPI):
|
||||
|
||||
- -n ignore php ini
|
||||
- -c search for php ini in path
|
||||
- -z load zend extension
|
||||
- -d define php ini entry
|
||||
|
||||
The following switches change the default behaviour of phpdbg:
|
||||
|
||||
- -v disables quietness
|
||||
- -s enabled stepping
|
||||
- -e sets execution context
|
||||
- -b boring - disables use of colour on the console
|
||||
- -I ignore .phpdbginit (default init file)
|
||||
- -i override .phpgdbinit location (implies -I)
|
||||
- -O set oplog output file
|
||||
- -q do not print banner on startup
|
||||
- -r jump straight to run
|
||||
- -E enable step through eval()
|
||||
- -l listen ports for remote mode
|
||||
- -a listen address for remote mode
|
||||
- -S override SAPI name
|
||||
|
||||
**Note:** Passing -rr will cause phpdbg to quit after execution, rather than returning to the console.
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
See the website for tutorials/documentation
|
||||
|
||||
http://phpdbg.com
|
61
sapi/phpdbg/config.m4
Normal file
61
sapi/phpdbg/config.m4
Normal file
@ -0,0 +1,61 @@
|
||||
dnl
|
||||
dnl $Id$
|
||||
dnl
|
||||
|
||||
PHP_ARG_ENABLE(phpdbg, for phpdbg support,
|
||||
[ --enable-phpdbg Build phpdbg], yes, yes)
|
||||
|
||||
PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build,
|
||||
[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no)
|
||||
|
||||
if test "$PHP_PHPDBG" != "no"; then
|
||||
AC_DEFINE(HAVE_PHPDBG, 1, [ ])
|
||||
|
||||
if test "$PHP_PHPDBG_DEBUG" != "no"; then
|
||||
AC_DEFINE(PHPDBG_DEBUG, 1, [ ])
|
||||
else
|
||||
AC_DEFINE(PHPDBG_DEBUG, 0, [ ])
|
||||
fi
|
||||
|
||||
PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
|
||||
PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c"
|
||||
|
||||
PHP_SUBST(PHP_PHPDBG_CFLAGS)
|
||||
PHP_SUBST(PHP_PHPDBG_FILES)
|
||||
|
||||
PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/phpdbg/Makefile.frag])
|
||||
PHP_SELECT_SAPI(phpdbg, program, $PHP_PHPDBG_FILES, $PHP_PHPDBG_CFLAGS, [$(SAPI_PHPDBG_PATH)])
|
||||
|
||||
BUILD_BINARY="sapi/phpdbg/phpdbg"
|
||||
BUILD_SHARED="sapi/phpdbg/libphpdbg.la"
|
||||
|
||||
BUILD_PHPDBG="\$(LIBTOOL) --mode=link \
|
||||
\$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \
|
||||
\$(PHP_GLOBAL_OBJS) \
|
||||
\$(PHP_BINARY_OBJS) \
|
||||
\$(PHP_PHPDBG_OBJS) \
|
||||
\$(EXTRA_LIBS) \
|
||||
\$(PHPDBG_EXTRA_LIBS) \
|
||||
\$(ZEND_EXTRA_LIBS) \
|
||||
-o \$(BUILD_BINARY)"
|
||||
|
||||
BUILD_PHPDBG_SHARED="\$(LIBTOOL) --mode=link \
|
||||
\$(CC) -shared -Wl,-soname,libphpdbg.so -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \
|
||||
\$(PHP_GLOBAL_OBJS) \
|
||||
\$(PHP_BINARY_OBJS) \
|
||||
\$(PHP_PHPDBG_OBJS) \
|
||||
\$(EXTRA_LIBS) \
|
||||
\$(PHPDBG_EXTRA_LIBS) \
|
||||
\$(ZEND_EXTRA_LIBS) \
|
||||
\-DPHPDBG_SHARED \
|
||||
-o \$(BUILD_SHARED)"
|
||||
|
||||
PHP_SUBST(BUILD_BINARY)
|
||||
PHP_SUBST(BUILD_SHARED)
|
||||
PHP_SUBST(BUILD_PHPDBG)
|
||||
PHP_SUBST(BUILD_PHPDBG_SHARED)
|
||||
fi
|
||||
|
||||
dnl ## Local Variables:
|
||||
dnl ## tab-width: 4
|
||||
dnl ## End:
|
19
sapi/phpdbg/config.w32
Normal file
19
sapi/phpdbg/config.w32
Normal file
@ -0,0 +1,19 @@
|
||||
ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes');
|
||||
ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no');
|
||||
|
||||
PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c';
|
||||
PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll';
|
||||
PHPDBG_EXE='phpdbg.exe';
|
||||
|
||||
if (PHP_PHPDBG == "yes") {
|
||||
/* build phpdbg binary */
|
||||
SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE);
|
||||
ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib");
|
||||
}
|
||||
|
||||
if (PHP_PHPDBGS == "yes") {
|
||||
SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32');
|
||||
ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib");
|
||||
}
|
||||
|
||||
|
1308
sapi/phpdbg/phpdbg.c
Normal file
1308
sapi/phpdbg/phpdbg.c
Normal file
File diff suppressed because it is too large
Load Diff
187
sapi/phpdbg/phpdbg.h
Normal file
187
sapi/phpdbg/phpdbg.h
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_H
|
||||
#define PHPDBG_H
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
# define PHPDBG_API __declspec(dllexport)
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
# define PHPDBG_API __attribute__ ((visibility("default")))
|
||||
#else
|
||||
# define PHPDBG_API
|
||||
#endif
|
||||
|
||||
#include "php.h"
|
||||
#include "php_globals.h"
|
||||
#include "php_variables.h"
|
||||
#include "php_getopt.h"
|
||||
#include "zend_builtin_functions.h"
|
||||
#include "zend_extensions.h"
|
||||
#include "zend_modules.h"
|
||||
#include "zend_globals.h"
|
||||
#include "zend_ini_scanner.h"
|
||||
#include "zend_stream.h"
|
||||
#include "SAPI.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
# include <windows.h>
|
||||
# include "config.w32.h"
|
||||
# undef strcasecmp
|
||||
# undef strncasecmp
|
||||
# define strcasecmp _stricmp
|
||||
# define strncasecmp _strnicmp
|
||||
#else
|
||||
# include "php_config.h"
|
||||
#endif
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
#include "php_main.h"
|
||||
|
||||
#ifdef ZTS
|
||||
# include "TSRM.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_utils.h"
|
||||
|
||||
#ifdef ZTS
|
||||
# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
|
||||
#else
|
||||
# define PHPDBG_G(v) (phpdbg_globals.v)
|
||||
#endif
|
||||
|
||||
#define PHPDBG_NEXT 2
|
||||
#define PHPDBG_UNTIL 3
|
||||
#define PHPDBG_FINISH 4
|
||||
#define PHPDBG_LEAVE 5
|
||||
|
||||
/*
|
||||
BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
|
||||
*/
|
||||
|
||||
/* {{{ tables */
|
||||
#define PHPDBG_BREAK_FILE 0
|
||||
#define PHPDBG_BREAK_SYM 1
|
||||
#define PHPDBG_BREAK_OPLINE 2
|
||||
#define PHPDBG_BREAK_METHOD 3
|
||||
#define PHPDBG_BREAK_COND 4
|
||||
#define PHPDBG_BREAK_OPCODE 5
|
||||
#define PHPDBG_BREAK_FUNCTION_OPLINE 6
|
||||
#define PHPDBG_BREAK_METHOD_OPLINE 7
|
||||
#define PHPDBG_BREAK_FILE_OPLINE 8
|
||||
#define PHPDBG_BREAK_MAP 9
|
||||
#define PHPDBG_BREAK_TABLES 10 /* }}} */
|
||||
|
||||
/* {{{ flags */
|
||||
#define PHPDBG_HAS_FILE_BP (1<<1)
|
||||
#define PHPDBG_HAS_SYM_BP (1<<2)
|
||||
#define PHPDBG_HAS_OPLINE_BP (1<<3)
|
||||
#define PHPDBG_HAS_METHOD_BP (1<<4)
|
||||
#define PHPDBG_HAS_COND_BP (1<<5)
|
||||
#define PHPDBG_HAS_OPCODE_BP (1<<6)
|
||||
#define PHPDBG_HAS_FUNCTION_OPLINE_BP (1<<7)
|
||||
#define PHPDBG_HAS_METHOD_OPLINE_BP (1<<8)
|
||||
#define PHPDBG_HAS_FILE_OPLINE_BP (1<<9) /* }}} */
|
||||
|
||||
/*
|
||||
END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
|
||||
*/
|
||||
|
||||
#define PHPDBG_IN_COND_BP (1<<10)
|
||||
#define PHPDBG_IN_EVAL (1<<11)
|
||||
|
||||
#define PHPDBG_IS_STEPPING (1<<12)
|
||||
#define PHPDBG_IS_QUIET (1<<13)
|
||||
#define PHPDBG_IS_QUITTING (1<<14)
|
||||
#define PHPDBG_IS_COLOURED (1<<15)
|
||||
#define PHPDBG_IS_CLEANING (1<<16)
|
||||
|
||||
#define PHPDBG_IN_UNTIL (1<<17)
|
||||
#define PHPDBG_IN_FINISH (1<<18)
|
||||
#define PHPDBG_IN_LEAVE (1<<19)
|
||||
|
||||
#define PHPDBG_IS_REGISTERED (1<<20)
|
||||
#define PHPDBG_IS_STEPONEVAL (1<<21)
|
||||
#define PHPDBG_IS_INITIALIZING (1<<22)
|
||||
#define PHPDBG_IS_SIGNALED (1<<23)
|
||||
#define PHPDBG_IS_INTERACTIVE (1<<24)
|
||||
#define PHPDBG_IS_BP_ENABLED (1<<25)
|
||||
#define PHPDBG_IS_REMOTE (1<<26)
|
||||
#define PHPDBG_IS_DISCONNECTED (1<<27)
|
||||
|
||||
#define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL|PHPDBG_IN_FINISH|PHPDBG_IN_LEAVE)
|
||||
#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
|
||||
#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP|PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
|
||||
|
||||
#ifndef _WIN32
|
||||
# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED)
|
||||
#else
|
||||
# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED)
|
||||
#endif /* }}} */
|
||||
|
||||
/* {{{ strings */
|
||||
#define PHPDBG_NAME "phpdbg"
|
||||
#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
|
||||
#define PHPDBG_URL "http://phpdbg.com"
|
||||
#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
|
||||
#define PHPDBG_VERSION "0.3.0"
|
||||
#define PHPDBG_INIT_FILENAME ".phpdbginit"
|
||||
/* }}} */
|
||||
|
||||
/* {{{ output descriptors */
|
||||
#define PHPDBG_STDIN 0
|
||||
#define PHPDBG_STDOUT 1
|
||||
#define PHPDBG_STDERR 2
|
||||
#define PHPDBG_IO_FDS 3 /* }}} */
|
||||
|
||||
/* {{{ structs */
|
||||
ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
||||
HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */
|
||||
HashTable registered; /* registered */
|
||||
HashTable seek; /* seek oplines */
|
||||
phpdbg_frame_t frame; /* frame */
|
||||
|
||||
char *exec; /* file to execute */
|
||||
size_t exec_len; /* size of exec */
|
||||
zend_op_array *ops; /* op_array */
|
||||
zval *retval; /* return value */
|
||||
int bp_count; /* breakpoint count */
|
||||
int vmret; /* return from last opcode handler execution */
|
||||
|
||||
FILE *oplog; /* opline log */
|
||||
FILE *io[PHPDBG_IO_FDS]; /* io */
|
||||
|
||||
char *prompt[2]; /* prompt */
|
||||
const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */
|
||||
|
||||
phpdbg_command_t *lcmd; /* last command */
|
||||
phpdbg_param_t lparam; /* last param */
|
||||
|
||||
zend_ulong flags; /* phpdbg flags */
|
||||
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
|
||||
|
||||
#endif /* PHPDBG_H */
|
122
sapi/phpdbg/phpdbg.init.d
Executable file
122
sapi/phpdbg/phpdbg.init.d
Executable file
@ -0,0 +1,122 @@
|
||||
################################################################
|
||||
# File: /etc/init.d/phpdbg #
|
||||
# Author: krakjoe #
|
||||
# Purpose: Daemonize phpdbg automatically on boot #
|
||||
# chkconfig: 2345 07 09 #
|
||||
# description: Starts, stops and restarts phpdbg daemon #
|
||||
################################################################
|
||||
LOCKFILE=/var/lock/subsys/phpdbg
|
||||
PIDFILE=/var/run/phpdbg.pid
|
||||
STDIN=4000
|
||||
STDOUT=8000
|
||||
################################################################
|
||||
# Either set path to phpdbg here or rely on phpdbg in ENV/PATH #
|
||||
################################################################
|
||||
if [ "x${PHPDBG}" == "x" ]; then
|
||||
PHPDBG=$(which phpdbg 2>/dev/null)
|
||||
fi
|
||||
################################################################
|
||||
# Options to pass to phpdbg upon boot #
|
||||
################################################################
|
||||
OPTIONS=
|
||||
LOGFILE=/var/log/phpdbg.log
|
||||
################################################################
|
||||
# STOP EDITING STOP EDITING STOP EDITING STOP EDITING #
|
||||
################################################################
|
||||
. /etc/rc.d/init.d/functions
|
||||
RETVAL=1
|
||||
################################################################
|
||||
insanity()
|
||||
{
|
||||
if [ "x${PHPDBG}" == "x" ]; then
|
||||
PHPDBG=$(which phpdbg 2>>/dev/null)
|
||||
if [ $? != 0 ]; then
|
||||
echo -n $"Fatal: cannot find phpdbg ${PHPDBG}"
|
||||
echo_failure
|
||||
echo
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
if [ ! -x ${PHPDBG} ]; then
|
||||
echo -n $"Fatal: cannot execute phpdbg ${PHPDBG}"
|
||||
echo_failure
|
||||
echo
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
insanity
|
||||
|
||||
if [ $? -eq 1 ]; then
|
||||
return $RETVAL
|
||||
fi
|
||||
|
||||
echo -n $"Starting: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} "
|
||||
nohup ${PHPDBG} -l${STDIN}/${STDOUT} ${OPTIONS} 2>>${LOGFILE} 1>/dev/null </dev/null &
|
||||
PID=$!
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -eq 0 ]; then
|
||||
echo $PID > $PIDFILE
|
||||
echo_success
|
||||
else
|
||||
echo_failure
|
||||
fi
|
||||
echo
|
||||
[ $RETVAL = 0 ] && touch ${LOCKFILE}
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
insanity
|
||||
|
||||
if [ $? -eq 1 ]; then
|
||||
return $RETVAL
|
||||
fi
|
||||
|
||||
if [ -f ${LOCKFILE} ] && [ -f ${PIDFILE} ]
|
||||
then
|
||||
echo -n $"Stopping: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} "
|
||||
kill -s TERM $(cat $PIDFILE)
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -eq 0 ]; then
|
||||
echo_success
|
||||
else
|
||||
echo_failure
|
||||
fi
|
||||
echo
|
||||
[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
|
||||
else
|
||||
echo -n $"Error: phpdbg not running"
|
||||
echo_failure
|
||||
echo
|
||||
[ $RETVAL = 1 ]
|
||||
fi
|
||||
return $RETVAL
|
||||
}
|
||||
##################################################################
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status $PHPDBG
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 start|stop|restart|status"
|
||||
;;
|
||||
esac
|
||||
###################################################################
|
||||
exit $RETVAL
|
1661
sapi/phpdbg/phpdbg_bp.c
Normal file
1661
sapi/phpdbg/phpdbg_bp.c
Normal file
File diff suppressed because it is too large
Load Diff
146
sapi/phpdbg/phpdbg_bp.h
Normal file
146
sapi/phpdbg/phpdbg_bp.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_BP_H
|
||||
#define PHPDBG_BP_H
|
||||
|
||||
/* {{{ */
|
||||
typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */
|
||||
|
||||
/* {{{ breakpoint base structure */
|
||||
#define phpdbg_breakbase(name) \
|
||||
int id; \
|
||||
zend_uchar type; \
|
||||
zend_ulong hits; \
|
||||
zend_bool disabled; \
|
||||
const char *name /* }}} */
|
||||
|
||||
/* {{{ breakpoint base */
|
||||
typedef struct _phpdbg_breakbase_t {
|
||||
phpdbg_breakbase(name);
|
||||
} phpdbg_breakbase_t; /* }}} */
|
||||
|
||||
/**
|
||||
* Breakpoint file-based representation
|
||||
*/
|
||||
typedef struct _phpdbg_breakfile_t {
|
||||
phpdbg_breakbase(filename);
|
||||
long line;
|
||||
} phpdbg_breakfile_t;
|
||||
|
||||
/**
|
||||
* Breakpoint symbol-based representation
|
||||
*/
|
||||
typedef struct _phpdbg_breaksymbol_t {
|
||||
phpdbg_breakbase(symbol);
|
||||
} phpdbg_breaksymbol_t;
|
||||
|
||||
/**
|
||||
* Breakpoint method based representation
|
||||
*/
|
||||
typedef struct _phpdbg_breakmethod_t {
|
||||
phpdbg_breakbase(class_name);
|
||||
size_t class_len;
|
||||
const char *func_name;
|
||||
size_t func_len;
|
||||
} phpdbg_breakmethod_t;
|
||||
|
||||
/**
|
||||
* Breakpoint opline num based representation
|
||||
*/
|
||||
typedef struct _phpdbg_breakopline_t {
|
||||
phpdbg_breakbase(func_name);
|
||||
size_t func_len;
|
||||
const char *class_name;
|
||||
size_t class_len;
|
||||
zend_ulong opline_num;
|
||||
zend_ulong opline;
|
||||
} phpdbg_breakopline_t;
|
||||
|
||||
/**
|
||||
* Breakpoint opline based representation
|
||||
*/
|
||||
typedef struct _phpdbg_breakline_t {
|
||||
phpdbg_breakbase(name);
|
||||
zend_ulong opline;
|
||||
phpdbg_breakopline_t *base;
|
||||
} phpdbg_breakline_t;
|
||||
|
||||
/**
|
||||
* Breakpoint opcode based representation
|
||||
*/
|
||||
typedef struct _phpdbg_breakop_t {
|
||||
phpdbg_breakbase(name);
|
||||
zend_ulong hash;
|
||||
} phpdbg_breakop_t;
|
||||
|
||||
/**
|
||||
* Breakpoint condition based representation
|
||||
*/
|
||||
typedef struct _phpdbg_breakcond_t {
|
||||
phpdbg_breakbase(code);
|
||||
size_t code_len;
|
||||
zend_bool paramed;
|
||||
phpdbg_param_t param;
|
||||
zend_ulong hash;
|
||||
zend_op_array *ops;
|
||||
} phpdbg_breakcond_t;
|
||||
|
||||
/* {{{ Opline breaks API */
|
||||
PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */
|
||||
|
||||
/* {{{ Breakpoint Creation API */
|
||||
PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_expression(const char* expression, size_t expression_len TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC); /* }}} */
|
||||
|
||||
/* {{{ Breakpoint Detection API */
|
||||
PHPDBG_API phpdbg_breakbase_t* phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC); /* }}} */
|
||||
|
||||
/* {{{ Misc Breakpoint API */
|
||||
PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t* brake, zend_bool output TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t* brake TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D);
|
||||
PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D);
|
||||
PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D);
|
||||
PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D); /* }}} */
|
||||
|
||||
/* {{{ Breakbase API */
|
||||
PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC);
|
||||
PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC); /* }}} */
|
||||
|
||||
/* {{{ Breakpoint Exportation API */
|
||||
PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */
|
||||
|
||||
#endif /* PHPDBG_BP_H */
|
155
sapi/phpdbg/phpdbg_break.c
Normal file
155
sapi/phpdbg/phpdbg_break.c
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_print.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_opcode.h"
|
||||
#include "phpdbg_break.h"
|
||||
#include "phpdbg_bp.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_BREAK(file) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case FILE_PARAM:
|
||||
phpdbg_set_breakpoint_file(param->file.name, param->file.line TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(method) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case METHOD_PARAM:
|
||||
phpdbg_set_breakpoint_method(param->method.class, param->method.name TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(address) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case ADDR_PARAM:
|
||||
phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC);
|
||||
break;
|
||||
|
||||
case NUMERIC_METHOD_PARAM:
|
||||
phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num TSRMLS_CC);
|
||||
break;
|
||||
|
||||
case NUMERIC_FUNCTION_PARAM:
|
||||
phpdbg_set_breakpoint_function_opline(param->str, param->num TSRMLS_CC);
|
||||
break;
|
||||
|
||||
case FILE_PARAM:
|
||||
phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(on) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
phpdbg_set_breakpoint_expression(param->str, param->len TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(at) /* {{{ */
|
||||
{
|
||||
phpdbg_set_breakpoint_at(param, input TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(lineno) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case NUMERIC_PARAM: {
|
||||
if (PHPDBG_G(exec)) {
|
||||
phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Execution context not set!");
|
||||
}
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(func) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
phpdbg_set_breakpoint_symbol(param->str, param->len TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(op) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
phpdbg_set_breakpoint_opcode(param->str, param->len TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_BREAK(del) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case NUMERIC_PARAM: {
|
||||
phpdbg_delete_breakpoint(param->num TSRMLS_CC);
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
58
sapi/phpdbg/phpdbg_break.h
Normal file
58
sapi/phpdbg/phpdbg_break.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_BREAK_H
|
||||
#define PHPDBG_BREAK_H
|
||||
|
||||
#include "TSRM.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
|
||||
#define PHPDBG_BREAK(name) PHPDBG_COMMAND(break_##name)
|
||||
|
||||
/**
|
||||
* Printer Forward Declarations
|
||||
*/
|
||||
PHPDBG_BREAK(file);
|
||||
PHPDBG_BREAK(func);
|
||||
PHPDBG_BREAK(method);
|
||||
PHPDBG_BREAK(address);
|
||||
PHPDBG_BREAK(at);
|
||||
PHPDBG_BREAK(op);
|
||||
PHPDBG_BREAK(on);
|
||||
PHPDBG_BREAK(lineno);
|
||||
PHPDBG_BREAK(del);
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
static const phpdbg_command_t phpdbg_break_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(file, "specify breakpoint by file:line", 'F', break_file, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(method, "specify breakpoint by class::method", 'm', break_method, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(address, "specify breakpoint by address", 'a', break_address, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(op, "specify breakpoint by opcode", 'O', break_op, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(on, "specify breakpoint by condition", 'o', break_on, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(at, "specify breakpoint by location and condition", 'A', break_at, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(lineno, "specify breakpoint by line of currently executing file", 'l', break_lineno, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(del, "delete breakpoint by identifier number", 'd', break_del, NULL, 1),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
#endif /* PHPDBG_BREAK_H */
|
669
sapi/phpdbg/phpdbg_cmd.c
Normal file
669
sapi/phpdbg/phpdbg_cmd.c
Normal file
@ -0,0 +1,669 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_set.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case EMPTY_PARAM:
|
||||
return "empty";
|
||||
case ADDR_PARAM:
|
||||
return "address";
|
||||
case NUMERIC_PARAM:
|
||||
return "numeric";
|
||||
case METHOD_PARAM:
|
||||
return "method";
|
||||
case NUMERIC_FUNCTION_PARAM:
|
||||
return "function opline";
|
||||
case NUMERIC_METHOD_PARAM:
|
||||
return "method opline";
|
||||
case FILE_PARAM:
|
||||
return "file or file opline";
|
||||
case STR_PARAM:
|
||||
return "string";
|
||||
default: /* this is bad */
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char *str, size_t len, phpdbg_param_t *param TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
char *class_name, *func_name;
|
||||
|
||||
if (len == 0) {
|
||||
param->type = EMPTY_PARAM;
|
||||
goto parsed;
|
||||
}
|
||||
|
||||
if (phpdbg_is_addr(str)) {
|
||||
param->addr = strtoul(str, 0, 16);
|
||||
param->type = ADDR_PARAM;
|
||||
goto parsed;
|
||||
|
||||
} else if (phpdbg_is_numeric(str)) {
|
||||
param->num = strtol(str, NULL, 0);
|
||||
param->type = NUMERIC_PARAM;
|
||||
goto parsed;
|
||||
|
||||
} else if (phpdbg_is_class_method(str, len+1, &class_name, &func_name)) {
|
||||
param->method.class = class_name;
|
||||
param->method.name = func_name;
|
||||
param->type = METHOD_PARAM;
|
||||
goto parsed;
|
||||
} else {
|
||||
char *line_pos = strrchr(str, ':');
|
||||
|
||||
if (line_pos && phpdbg_is_numeric(line_pos+1)) {
|
||||
if (strchr(str, ':') == line_pos) {
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
memcpy(path, str, line_pos - str);
|
||||
path[line_pos - str] = 0;
|
||||
*line_pos = 0;
|
||||
param->file.name = phpdbg_resolve_path(path TSRMLS_CC);
|
||||
param->file.line = strtol(line_pos+1, NULL, 0);
|
||||
param->type = FILE_PARAM;
|
||||
|
||||
goto parsed;
|
||||
}
|
||||
}
|
||||
|
||||
line_pos = strrchr(str, '#');
|
||||
|
||||
if (line_pos && phpdbg_is_numeric(line_pos+1)) {
|
||||
if (strchr(str, '#') == line_pos) {
|
||||
param->num = strtol(line_pos + 1, NULL, 0);
|
||||
|
||||
if (phpdbg_is_class_method(str, line_pos - str, &class_name, &func_name)) {
|
||||
param->method.class = class_name;
|
||||
param->method.name = func_name;
|
||||
param->type = NUMERIC_METHOD_PARAM;
|
||||
} else {
|
||||
param->len = line_pos - str;
|
||||
param->str = estrndup(str, param->len);
|
||||
param->type = NUMERIC_FUNCTION_PARAM;
|
||||
}
|
||||
|
||||
goto parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
param->str = estrndup(str, len);
|
||||
param->len = len;
|
||||
param->type = STR_PARAM;
|
||||
|
||||
parsed:
|
||||
phpdbg_debug("phpdbg_parse_param(\"%s\", %lu): %s",
|
||||
str, len, phpdbg_get_param_type(param TSRMLS_CC));
|
||||
return param->type;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (param) {
|
||||
switch (param->type) {
|
||||
case FILE_PARAM:
|
||||
efree(param->file.name);
|
||||
break;
|
||||
case METHOD_PARAM:
|
||||
efree(param->method.class);
|
||||
efree(param->method.name);
|
||||
break;
|
||||
case STR_PARAM:
|
||||
efree(param->str);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
asprintf(pointer,
|
||||
"%s", param->str);
|
||||
break;
|
||||
|
||||
case ADDR_PARAM:
|
||||
asprintf(pointer,
|
||||
"%#lx", param->addr);
|
||||
break;
|
||||
|
||||
case NUMERIC_PARAM:
|
||||
asprintf(pointer,
|
||||
"%li",
|
||||
param->num);
|
||||
break;
|
||||
|
||||
case METHOD_PARAM:
|
||||
asprintf(pointer,
|
||||
"%s::%s",
|
||||
param->method.class,
|
||||
param->method.name);
|
||||
break;
|
||||
|
||||
case FILE_PARAM:
|
||||
if (param->num) {
|
||||
asprintf(pointer,
|
||||
"%s:%lu#%lu",
|
||||
param->file.name,
|
||||
param->file.line,
|
||||
param->num);
|
||||
} else {
|
||||
asprintf(pointer,
|
||||
"%s:%lu",
|
||||
param->file.name,
|
||||
param->file.line);
|
||||
}
|
||||
break;
|
||||
|
||||
case NUMERIC_FUNCTION_PARAM:
|
||||
asprintf(pointer,
|
||||
"%s#%lu", param->str, param->num);
|
||||
break;
|
||||
|
||||
case NUMERIC_METHOD_PARAM:
|
||||
asprintf(pointer,
|
||||
"%s::%s#%lu",
|
||||
param->method.class,
|
||||
param->method.name,
|
||||
param->num);
|
||||
break;
|
||||
|
||||
default:
|
||||
asprintf(pointer,
|
||||
"%s", "unknown");
|
||||
}
|
||||
|
||||
return *pointer;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
switch ((dest->type = src->type)) {
|
||||
case STR_PARAM:
|
||||
dest->str = estrndup(src->str, src->len);
|
||||
dest->len = src->len;
|
||||
break;
|
||||
|
||||
case ADDR_PARAM:
|
||||
dest->addr = src->addr;
|
||||
break;
|
||||
|
||||
case NUMERIC_PARAM:
|
||||
dest->num = src->num;
|
||||
break;
|
||||
|
||||
case METHOD_PARAM:
|
||||
dest->method.class = estrdup(src->method.class);
|
||||
dest->method.name = estrdup(src->method.name);
|
||||
break;
|
||||
|
||||
case FILE_PARAM:
|
||||
dest->file.name = estrdup(src->file.name);
|
||||
dest->file.line = src->file.line;
|
||||
if (src->num)
|
||||
dest->num = src->num;
|
||||
break;
|
||||
|
||||
case NUMERIC_FUNCTION_PARAM:
|
||||
dest->str = estrndup(src->str, src->len);
|
||||
dest->num = src->num;
|
||||
dest->len = src->len;
|
||||
break;
|
||||
|
||||
case NUMERIC_METHOD_PARAM:
|
||||
dest->method.class = estrdup(src->method.class);
|
||||
dest->method.name = estrdup(src->method.name);
|
||||
dest->num = src->num;
|
||||
break;
|
||||
|
||||
case EMPTY_PARAM: { /* do nothing */ } break;
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_ulong hash = param->type;
|
||||
|
||||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
hash += zend_inline_hash_func(param->str, param->len);
|
||||
break;
|
||||
|
||||
case METHOD_PARAM:
|
||||
hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
|
||||
hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
|
||||
break;
|
||||
|
||||
case FILE_PARAM:
|
||||
hash += zend_inline_hash_func(param->file.name, strlen(param->file.name));
|
||||
hash += param->file.line;
|
||||
if (param->num)
|
||||
hash += param->num;
|
||||
break;
|
||||
|
||||
case ADDR_PARAM:
|
||||
hash += param->addr;
|
||||
break;
|
||||
|
||||
case NUMERIC_PARAM:
|
||||
hash += param->num;
|
||||
break;
|
||||
|
||||
case NUMERIC_FUNCTION_PARAM:
|
||||
hash += zend_inline_hash_func(param->str, param->len);
|
||||
hash += param->num;
|
||||
break;
|
||||
|
||||
case NUMERIC_METHOD_PARAM:
|
||||
hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
|
||||
hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
|
||||
if (param->num)
|
||||
hash+= param->num;
|
||||
break;
|
||||
|
||||
case EMPTY_PARAM: { /* do nothing */ } break;
|
||||
}
|
||||
|
||||
return hash;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_param_t *r TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (l && r) {
|
||||
if (l->type == r->type) {
|
||||
switch (l->type) {
|
||||
|
||||
case NUMERIC_FUNCTION_PARAM:
|
||||
if (l->num != r->num) {
|
||||
break;
|
||||
}
|
||||
/* break intentionally omitted */
|
||||
|
||||
case STR_PARAM:
|
||||
return (l->len == r->len) &&
|
||||
(memcmp(l->str, r->str, l->len) == SUCCESS);
|
||||
|
||||
case NUMERIC_PARAM:
|
||||
return (l->num == r->num);
|
||||
|
||||
case ADDR_PARAM:
|
||||
return (l->addr == r->addr);
|
||||
|
||||
case FILE_PARAM: {
|
||||
if (l->file.line == r->file.line) {
|
||||
size_t lengths[2] = {
|
||||
strlen(l->file.name), strlen(r->file.name)};
|
||||
|
||||
if (lengths[0] == lengths[1]) {
|
||||
if ((!l->num && !r->num) || (l->num == r->num)) {
|
||||
return (memcmp(
|
||||
l->file.name, r->file.name, lengths[0]) == SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case NUMERIC_METHOD_PARAM:
|
||||
if (l->num != r->num) {
|
||||
break;
|
||||
}
|
||||
/* break intentionally omitted */
|
||||
|
||||
case METHOD_PARAM: {
|
||||
size_t lengths[2] = {
|
||||
strlen(l->method.class), strlen(r->method.class)};
|
||||
if (lengths[0] == lengths[1]) {
|
||||
if (memcmp(l->method.class, r->method.class, lengths[0]) == SUCCESS) {
|
||||
lengths[0] = strlen(l->method.name);
|
||||
lengths[1] = strlen(r->method.name);
|
||||
|
||||
if (lengths[0] == lengths[1]) {
|
||||
return (memcmp(
|
||||
l->method.name, r->method.name, lengths[0]) == SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case EMPTY_PARAM:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API phpdbg_input_t **phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
char *p;
|
||||
char b[PHPDBG_MAX_CMD];
|
||||
int l=0;
|
||||
enum states {
|
||||
IN_BETWEEN,
|
||||
IN_WORD,
|
||||
IN_STRING
|
||||
} state = IN_BETWEEN;
|
||||
phpdbg_input_t **argv = NULL;
|
||||
|
||||
argv = (phpdbg_input_t**) emalloc(sizeof(phpdbg_input_t*));
|
||||
(*argc) = 0;
|
||||
|
||||
#define RESET_STATE() do { \
|
||||
phpdbg_input_t *arg = emalloc(sizeof(phpdbg_input_t)); \
|
||||
if (arg) { \
|
||||
b[l]=0; \
|
||||
arg->length = l; \
|
||||
arg->string = estrndup(b, arg->length); \
|
||||
arg->argv = NULL; \
|
||||
arg->argc = 0; \
|
||||
argv = (phpdbg_input_t**) erealloc(argv, sizeof(phpdbg_input_t*) * ((*argc)+1)); \
|
||||
argv[(*argc)++] = arg; \
|
||||
l = 0; \
|
||||
} \
|
||||
state = IN_BETWEEN; \
|
||||
} while (0)
|
||||
|
||||
for (p = buffer; *p != '\0'; p++) {
|
||||
int c = (unsigned char) *p;
|
||||
switch (state) {
|
||||
case IN_BETWEEN:
|
||||
if (isspace(c)) {
|
||||
continue;
|
||||
}
|
||||
if (c == '"') {
|
||||
state = IN_STRING;
|
||||
continue;
|
||||
}
|
||||
state = IN_WORD;
|
||||
b[l++]=c;
|
||||
continue;
|
||||
|
||||
case IN_STRING:
|
||||
if (c == '"') {
|
||||
if (buffer[(p - buffer)-1] == '\\') {
|
||||
b[l-1]=c;
|
||||
continue;
|
||||
}
|
||||
RESET_STATE();
|
||||
} else {
|
||||
b[l++]=c;
|
||||
}
|
||||
continue;
|
||||
|
||||
case IN_WORD:
|
||||
if (isspace(c)) {
|
||||
RESET_STATE();
|
||||
} else {
|
||||
b[l++]=c;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case IN_WORD: {
|
||||
RESET_STATE();
|
||||
} break;
|
||||
|
||||
case IN_STRING:
|
||||
phpdbg_error(
|
||||
"Malformed command line (unclosed quote) @ %ld: %s!",
|
||||
(p - buffer)-1, &buffer[(p - buffer)-1]);
|
||||
break;
|
||||
|
||||
case IN_BETWEEN:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*argc) == 0) {
|
||||
/* not needed */
|
||||
efree(argv);
|
||||
|
||||
/* to be sure */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return argv;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
phpdbg_input_t *buffer = NULL;
|
||||
char *cmd = NULL;
|
||||
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) &&
|
||||
(buffered == NULL)) {
|
||||
fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
|
||||
}
|
||||
|
||||
if (buffered == NULL) {
|
||||
#ifndef HAVE_LIBREADLINE
|
||||
char buf[PHPDBG_MAX_CMD];
|
||||
if ((!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && !phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) ||
|
||||
!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
|
||||
/* the user has gone away */
|
||||
phpdbg_error("Failed to read console!");
|
||||
PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
|
||||
zend_bailout();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmd = buf;
|
||||
#else
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
char buf[PHPDBG_MAX_CMD];
|
||||
if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
|
||||
cmd = buf;
|
||||
} else cmd = NULL;
|
||||
} else cmd = readline(phpdbg_get_prompt(TSRMLS_C));
|
||||
|
||||
if (!cmd) {
|
||||
/* the user has gone away */
|
||||
phpdbg_error("Failed to read console!");
|
||||
PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
|
||||
zend_bailout();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
add_history(cmd);
|
||||
}
|
||||
#endif
|
||||
} else cmd = buffered;
|
||||
|
||||
/* allocate and sanitize buffer */
|
||||
buffer = (phpdbg_input_t*) ecalloc(1, sizeof(phpdbg_input_t));
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer->string = phpdbg_trim(cmd, strlen(cmd), &buffer->length);
|
||||
|
||||
/* store constant pointer to start of buffer */
|
||||
buffer->start = (char* const*) buffer->string;
|
||||
|
||||
buffer->argv = phpdbg_read_argv(
|
||||
buffer->string, &buffer->argc TSRMLS_CC);
|
||||
|
||||
#ifdef PHPDBG_DEBUG
|
||||
if (buffer->argc) {
|
||||
int arg = 0;
|
||||
|
||||
while (arg < buffer->argc) {
|
||||
phpdbg_debug(
|
||||
"argv %d=%s", arg, buffer->argv[arg]->string);
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (!buffered && cmd &&
|
||||
!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
free(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (argv) {
|
||||
if (argc) {
|
||||
int arg;
|
||||
for (arg=0; arg<argc; arg++) {
|
||||
phpdbg_destroy_input(
|
||||
&argv[arg] TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
efree(argv);
|
||||
}
|
||||
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t **input TSRMLS_DC) /*{{{ */
|
||||
{
|
||||
if (*input) {
|
||||
if ((*input)->string) {
|
||||
efree((*input)->string);
|
||||
}
|
||||
|
||||
phpdbg_destroy_argv(
|
||||
(*input)->argv, (*input)->argc TSRMLS_CC);
|
||||
|
||||
efree(*input);
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *input TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
int rc = FAILURE;
|
||||
|
||||
if (input->argc > 0) {
|
||||
while (command && command->name && command->handler) {
|
||||
if (((command->name_len == input->argv[0]->length) &&
|
||||
(memcmp(command->name, input->argv[0]->string, command->name_len) == SUCCESS)) ||
|
||||
(command->alias &&
|
||||
(input->argv[0]->length == 1) &&
|
||||
(command->alias == *input->argv[0]->string))) {
|
||||
|
||||
phpdbg_param_t param;
|
||||
|
||||
param.type = EMPTY_PARAM;
|
||||
|
||||
if (input->argc > 1) {
|
||||
if (command->subs) {
|
||||
phpdbg_input_t sub = *input;
|
||||
|
||||
sub.string += input->argv[0]->length;
|
||||
sub.length -= input->argv[0]->length;
|
||||
|
||||
sub.string = phpdbg_trim(
|
||||
sub.string, sub.length, &sub.length);
|
||||
|
||||
sub.argc--;
|
||||
sub.argv++;
|
||||
|
||||
phpdbg_debug(
|
||||
"trying sub commands in \"%s\" for \"%s\" with %d arguments",
|
||||
command->name, sub.argv[0]->string, sub.argc-1);
|
||||
|
||||
if (phpdbg_do_cmd(command->subs, &sub TSRMLS_CC) == SUCCESS) {
|
||||
efree(sub.string);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
efree(sub.string);
|
||||
}
|
||||
|
||||
/* no sub command found */
|
||||
{
|
||||
char *store = input->string;
|
||||
|
||||
input->string += input->argv[0]->length;
|
||||
input->length -= input->argv[0]->length;
|
||||
|
||||
input->string = phpdbg_trim(
|
||||
input->string, input->length, &input->length);
|
||||
|
||||
efree(store);
|
||||
}
|
||||
|
||||
/* pass parameter on */
|
||||
phpdbg_parse_param(
|
||||
input->string,
|
||||
input->length,
|
||||
¶m TSRMLS_CC);
|
||||
}
|
||||
|
||||
phpdbg_debug(
|
||||
"found command %s for %s with %d arguments",
|
||||
command->name, input->argv[0]->string, input->argc-1);
|
||||
{
|
||||
int arg;
|
||||
for (arg=1; arg<input->argc; arg++) {
|
||||
phpdbg_debug(
|
||||
"\t#%d: [%s=%zu]",
|
||||
arg,
|
||||
input->argv[arg]->string,
|
||||
input->argv[arg]->length);
|
||||
}
|
||||
}
|
||||
|
||||
rc = command->handler(¶m, input TSRMLS_CC);
|
||||
|
||||
/* only set last command when it is worth it! */
|
||||
if ((rc != FAILURE) &&
|
||||
!(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) {
|
||||
PHPDBG_G(lcmd) = (phpdbg_command_t*) command;
|
||||
phpdbg_clear_param(
|
||||
&PHPDBG_G(lparam) TSRMLS_CC);
|
||||
PHPDBG_G(lparam) = param;
|
||||
}
|
||||
break;
|
||||
}
|
||||
command++;
|
||||
}
|
||||
} else {
|
||||
/* this should NEVER happen */
|
||||
phpdbg_error(
|
||||
"No function executed!!");
|
||||
}
|
||||
|
||||
return rc;
|
||||
} /* }}} */
|
||||
|
169
sapi/phpdbg/phpdbg_cmd.h
Normal file
169
sapi/phpdbg/phpdbg_cmd.h
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_CMD_H
|
||||
#define PHPDBG_CMD_H
|
||||
|
||||
#include "TSRM.h"
|
||||
|
||||
typedef struct _phpdbg_command_t phpdbg_command_t;
|
||||
|
||||
/* {{{ Command and Parameter */
|
||||
enum {
|
||||
NO_ARG = 0,
|
||||
REQUIRED_ARG,
|
||||
OPTIONAL_ARG
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
EMPTY_PARAM = 0,
|
||||
ADDR_PARAM,
|
||||
FILE_PARAM,
|
||||
METHOD_PARAM,
|
||||
STR_PARAM,
|
||||
NUMERIC_PARAM,
|
||||
NUMERIC_FUNCTION_PARAM,
|
||||
NUMERIC_METHOD_PARAM
|
||||
} phpdbg_param_type;
|
||||
|
||||
typedef struct _phpdbg_input_t phpdbg_input_t;
|
||||
|
||||
struct _phpdbg_input_t {
|
||||
char * const *start;
|
||||
char *string;
|
||||
size_t length;
|
||||
phpdbg_input_t **argv;
|
||||
int argc;
|
||||
};
|
||||
|
||||
typedef struct _phpdbg_param {
|
||||
phpdbg_param_type type;
|
||||
long num;
|
||||
zend_ulong addr;
|
||||
struct {
|
||||
char *name;
|
||||
long line;
|
||||
} file;
|
||||
struct {
|
||||
char *class;
|
||||
char *name;
|
||||
} method;
|
||||
char *str;
|
||||
size_t len;
|
||||
} phpdbg_param_t;
|
||||
|
||||
typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t*, const phpdbg_input_t* TSRMLS_DC);
|
||||
|
||||
struct _phpdbg_command_t {
|
||||
const char *name; /* Command name */
|
||||
size_t name_len; /* Command name length */
|
||||
const char *tip; /* Menu tip */
|
||||
size_t tip_len; /* Menu tip length */
|
||||
char alias; /* Alias */
|
||||
phpdbg_command_handler_t handler; /* Command handler */
|
||||
const phpdbg_command_t *subs; /* Sub Commands */
|
||||
char arg_type; /* Accept args? */
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
/* {{{ misc */
|
||||
#define PHPDBG_STRL(s) s, sizeof(s)-1
|
||||
#define PHPDBG_MAX_CMD 500
|
||||
#define PHPDBG_FRAME(v) (PHPDBG_G(frame).v)
|
||||
#define PHPDBG_EX(v) (EG(current_execute_data)->v)
|
||||
|
||||
typedef struct {
|
||||
int num;
|
||||
zend_execute_data *execute_data;
|
||||
} phpdbg_frame_t;
|
||||
/* }}} */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Workflow:
|
||||
* 1) read input
|
||||
* input takes the line from console, creates argc/argv
|
||||
* 2) parse parameters into suitable types based on arg_type
|
||||
* takes input from 1) and arg_type and creates parameters
|
||||
* 3) do command
|
||||
* executes commands
|
||||
* 4) destroy parameters
|
||||
* cleans up what was allocated by creation of parameters
|
||||
* 5) destroy input
|
||||
* cleans up what was allocated by creation of input
|
||||
*/
|
||||
|
||||
/*
|
||||
* Input Management
|
||||
*/
|
||||
PHPDBG_API phpdbg_input_t* phpdbg_read_input(char *buffered TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t** TSRMLS_DC);
|
||||
|
||||
/*
|
||||
* Argument Management
|
||||
*/
|
||||
PHPDBG_API phpdbg_input_t** phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC);
|
||||
#define phpdbg_argv_is(n, s) \
|
||||
(memcmp(input->argv[n]->string, s, input->argv[n]->length) == SUCCESS)
|
||||
|
||||
/*
|
||||
* Parameter Management
|
||||
*/
|
||||
PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char*, size_t, phpdbg_param_t* TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_clear_param(phpdbg_param_t* TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t*, phpdbg_param_t* TSRMLS_DC);
|
||||
PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *, const phpdbg_param_t * TSRMLS_DC);
|
||||
PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t * TSRMLS_DC);
|
||||
PHPDBG_API const char* phpdbg_get_param_type(const phpdbg_param_t* TSRMLS_DC);
|
||||
PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **pointer TSRMLS_DC);
|
||||
|
||||
/*
|
||||
* Command Executor
|
||||
*/
|
||||
PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t*, phpdbg_input_t* TSRMLS_DC);
|
||||
|
||||
/**
|
||||
* Command Declarators
|
||||
*/
|
||||
#define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name
|
||||
|
||||
#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, has_args) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, has_args}
|
||||
|
||||
#define PHPDBG_COMMAND_D(name, tip, alias, children, has_args) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, has_args}
|
||||
|
||||
#define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC)
|
||||
|
||||
#define PHPDBG_COMMAND_ARGS param, input TSRMLS_CC
|
||||
|
||||
#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0'}
|
||||
|
||||
/*
|
||||
* Default Switch Case
|
||||
*/
|
||||
#define phpdbg_default_switch_case() \
|
||||
default: \
|
||||
phpdbg_error("Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \
|
||||
break
|
||||
|
||||
#endif /* PHPDBG_CMD_H */
|
206
sapi/phpdbg/phpdbg_frame.c
Normal file
206
sapi/phpdbg/phpdbg_frame.c
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "zend.h"
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_frame.h"
|
||||
#include "phpdbg_list.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
void phpdbg_restore_frame(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
if (PHPDBG_FRAME(num) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PHPDBG_FRAME(num) = 0;
|
||||
|
||||
/* move things back */
|
||||
EG(current_execute_data) = PHPDBG_FRAME(execute_data);
|
||||
|
||||
EG(opline_ptr) = &PHPDBG_EX(opline);
|
||||
EG(active_op_array) = PHPDBG_EX(op_array);
|
||||
EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
|
||||
EG(active_symbol_table) = PHPDBG_EX(symbol_table);
|
||||
EG(This) = PHPDBG_EX(current_this);
|
||||
EG(scope) = PHPDBG_EX(current_scope);
|
||||
EG(called_scope) = PHPDBG_EX(current_called_scope);
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data);
|
||||
int i = 0;
|
||||
|
||||
if (PHPDBG_FRAME(num) == frame) {
|
||||
phpdbg_notice("Already in frame #%d", frame);
|
||||
return;
|
||||
}
|
||||
|
||||
while (execute_data) {
|
||||
if (i++ == frame) {
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
execute_data = execute_data->prev_execute_data;
|
||||
} while (execute_data && execute_data->opline == NULL);
|
||||
}
|
||||
|
||||
if (execute_data == NULL) {
|
||||
phpdbg_error("No frame #%d", frame);
|
||||
return;
|
||||
}
|
||||
|
||||
phpdbg_restore_frame(TSRMLS_C);
|
||||
|
||||
if (frame > 0) {
|
||||
PHPDBG_FRAME(num) = frame;
|
||||
|
||||
/* backup things and jump back */
|
||||
PHPDBG_FRAME(execute_data) = EG(current_execute_data);
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
EG(opline_ptr) = &PHPDBG_EX(opline);
|
||||
EG(active_op_array) = PHPDBG_EX(op_array);
|
||||
PHPDBG_FRAME(execute_data)->original_return_value = EG(return_value_ptr_ptr);
|
||||
EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
|
||||
EG(active_symbol_table) = PHPDBG_EX(symbol_table);
|
||||
EG(This) = PHPDBG_EX(current_this);
|
||||
EG(scope) = PHPDBG_EX(current_scope);
|
||||
EG(called_scope) = PHPDBG_EX(current_called_scope);
|
||||
}
|
||||
|
||||
phpdbg_notice("Switched to frame #%d", frame);
|
||||
phpdbg_list_file(
|
||||
zend_get_executed_filename(TSRMLS_C),
|
||||
3,
|
||||
zend_get_executed_lineno(TSRMLS_C)-1,
|
||||
zend_get_executed_lineno(TSRMLS_C)
|
||||
TSRMLS_CC
|
||||
);
|
||||
} /* }}} */
|
||||
|
||||
static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval **funcname, **class, **type, **args, **argstmp;
|
||||
char is_class;
|
||||
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"),
|
||||
(void **)&funcname);
|
||||
|
||||
if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp),
|
||||
"object", sizeof("object"), (void **)&class)) == FAILURE) {
|
||||
is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"),
|
||||
(void **)&class);
|
||||
} else {
|
||||
zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class),
|
||||
(zend_uint *)&Z_STRLEN_PP(class) TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (is_class == SUCCESS) {
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type);
|
||||
}
|
||||
|
||||
phpdbg_write("%s%s%s(",
|
||||
is_class == FAILURE?"":Z_STRVAL_PP(class),
|
||||
is_class == FAILURE?"":Z_STRVAL_PP(type),
|
||||
Z_STRVAL_PP(funcname)
|
||||
);
|
||||
|
||||
if (zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"),
|
||||
(void **)&args) == SUCCESS) {
|
||||
HashPosition iterator;
|
||||
const zend_function *func = phpdbg_get_function(
|
||||
Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC);
|
||||
const zend_arg_info *arginfo = func ? func->common.arg_info : NULL;
|
||||
int j = 0, m = func ? func->common.num_args : 0;
|
||||
zend_bool is_variadic = 0;
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator);
|
||||
while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args),
|
||||
(void **) &argstmp, &iterator) == SUCCESS) {
|
||||
if (j) {
|
||||
phpdbg_write(", ");
|
||||
}
|
||||
if (m && j < m) {
|
||||
#if PHP_VERSION_ID >= 50600
|
||||
is_variadic = arginfo[j].is_variadic;
|
||||
#endif
|
||||
phpdbg_write("%s=%s",
|
||||
arginfo[j].name, is_variadic ? "[": "");
|
||||
}
|
||||
++j;
|
||||
|
||||
zend_print_flat_zval_r(*argstmp TSRMLS_CC);
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator);
|
||||
}
|
||||
if (is_variadic) {
|
||||
phpdbg_write("]");
|
||||
}
|
||||
}
|
||||
phpdbg_write(")");
|
||||
}
|
||||
|
||||
void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval zbacktrace;
|
||||
zval **tmp;
|
||||
zval **file, **line;
|
||||
HashPosition position;
|
||||
int i = 1, limit = num;
|
||||
int user_defined;
|
||||
|
||||
if (limit < 0) {
|
||||
phpdbg_error("Invalid backtrace size %d", limit);
|
||||
}
|
||||
|
||||
zend_fetch_debug_backtrace(
|
||||
&zbacktrace, 0, 0, limit TSRMLS_CC);
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position);
|
||||
while (1) {
|
||||
user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file);
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line);
|
||||
zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
|
||||
|
||||
if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace),
|
||||
(void**)&tmp, &position) == FAILURE) {
|
||||
phpdbg_write("frame #0: {main} at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line));
|
||||
break;
|
||||
}
|
||||
|
||||
if (user_defined == SUCCESS) {
|
||||
phpdbg_write("frame #%d: ", i++);
|
||||
phpdbg_dump_prototype(tmp TSRMLS_CC);
|
||||
phpdbg_writeln(" at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line));
|
||||
} else {
|
||||
phpdbg_write(" => ");
|
||||
phpdbg_dump_prototype(tmp TSRMLS_CC);
|
||||
phpdbg_writeln(" (internal function)");
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_writeln(EMPTY);
|
||||
zval_dtor(&zbacktrace);
|
||||
} /* }}} */
|
30
sapi/phpdbg/phpdbg_frame.h
Normal file
30
sapi/phpdbg/phpdbg_frame.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_FRAME_H
|
||||
#define PHPDBG_FRAME_H
|
||||
|
||||
#include "TSRM.h"
|
||||
|
||||
void phpdbg_restore_frame(TSRMLS_D);
|
||||
void phpdbg_switch_frame(int TSRMLS_DC);
|
||||
void phpdbg_dump_backtrace(size_t TSRMLS_DC);
|
||||
|
||||
#endif /* PHPDBG_FRAME_H */
|
603
sapi/phpdbg/phpdbg_help.c
Normal file
603
sapi/phpdbg/phpdbg_help.c
Normal file
@ -0,0 +1,603 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_help.h"
|
||||
#include "phpdbg_print.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_break.h"
|
||||
#include "phpdbg_list.h"
|
||||
#include "phpdbg_info.h"
|
||||
#include "phpdbg_set.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_HELP(exec) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("\tWill attempt execution, if compilation has not yet taken place, it occurs now");
|
||||
phpdbg_writeln("The execution context must be set before execution can take place");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(step) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("You can enable and disable stepping at any phpdbg prompt during execution");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sstepping 1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%ss 1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill enable stepping");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("While stepping is enabled you are presented with a prompt after the execution of each opcode");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(next) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_write("Step back into the vm and execute the next opcode");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%snext", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sn", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: is only useful while executing");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(until) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Step back into the vm, skipping breakpoints until the next source line");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%suntil", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%su", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: is only useful while executing");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(finish) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Step back into the vm, skipping breakpoints until past the end of the current stack");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sfinish", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sF", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill cause control to be passed back to the vm, continuing execution");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: this allows all breakpoints that would otherwise break execution in the current scope to be skipped");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(leave) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Step back into the vm, skipping breakpoints until the current stack is returning");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sleave", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sL", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill cause a break when instructed to leave the current context");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: this allows inspection of the return value before it is returned");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(compile) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Pre-compilation of the execution context provides the opportunity to inspect opcodes before execution");
|
||||
phpdbg_writeln("The execution context must be set for compilation to succeed");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%scompile", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sc", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill compile the current execution context, populating class/function/constant/etc tables");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: It is a good idea to clean the environment between each compilation");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(print) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("By default, print will show information about the current execution context");
|
||||
phpdbg_writeln("Other printing commands give access to instruction information");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sprint class \\my\\class", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sp c \\my\\class", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the instructions for the methods in \\my\\class");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sprint method \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sp m \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the instructions for \\my\\class::method");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sprint func .getSomething", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sp f .getSomething", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the instructions for ::getSomething in the active scope");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sprint func my_function", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sp f my_function", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the instructions for the global function my_function");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sprint opline", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sp o", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the instruction for the current opline");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sprint exec", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sp e", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the instructions for the execution context");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sprint stack", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sp s", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the instructions for the current stack");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Specific printers loaded are show below:");
|
||||
phpdbg_notice("Commands");
|
||||
{
|
||||
const phpdbg_command_t *print_command = phpdbg_print_commands;
|
||||
|
||||
phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
|
||||
while (print_command && print_command->name) {
|
||||
if (print_command->alias) {
|
||||
phpdbg_writeln("\t[%c]\t%s\t\t%s", print_command->alias, print_command->name, print_command->tip);
|
||||
} else {
|
||||
phpdbg_writeln("\t[ ]\t%s\t\t%s", print_command->name, print_command->tip);
|
||||
}
|
||||
++print_command;
|
||||
}
|
||||
}
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(run) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Execute the current context inside the phpdbg vm");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%srun", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sr", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill cause execution of the context, if it is set.");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: The execution context must be set, but not necessarily compiled before execution occurs");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(eval) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Access to eval() allows you to change the environment during execution, careful though!!");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%seval $variable", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sE $variable", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print_r($variable) on the console, if it is defined");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%seval $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sE $variable = \"Hello phpdbg :)\"", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill set $variable in the current scope");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: eval() will always show the result; do not prefix the code with \"return\"");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(break) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Setting a breakpoint stops execution at a specific stage");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sbreak [file] test.php:1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb [F] test.php:1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break execution on line 1 of test.php");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak [func] my_function", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb [f] my_function", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break execution on entry to my_function");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak [method] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb [m] \\my\\class::method", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break execution on entry to \\my\\class::method");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak [address] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb [a] 0x7ff68f570e08", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break at the opline with the address provided");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak [address] my_function#1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb [a] my_function#1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break at the opline number 1 of the function my_function");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak [address] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb [a] \\my\\class::method#2", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break at the opline number 2 of the method \\my\\class::method");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak address test.php:3", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb a test.php:3", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break at the opline number 3 of test.php");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak [lineno] 200", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb [l] 200", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break at line 200 of the currently executing file");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak on ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb on ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break when the condition evaluates to true");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak at phpdbg::isGreat if ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break at every opcode in phpdbg::isGreat when the condition evaluates to true");
|
||||
phpdbg_writeln("\t%sbreak at test.php:20 if ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break at every opcode on line 20 of test.php when the condition evaluates to true");
|
||||
phpdbg_write("\t");
|
||||
phpdbg_notice("The location can be anything accepted by file, func, method, or address break commands");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak op ZEND_ADD", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb O ZEND_ADD", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill break on every occurence of the opcode provided");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%sbreak del 1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sb d 1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill remove the breakpoint with the given identifier");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: An address is only valid for the current compilation");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Specific breakers loaded are show below:");
|
||||
phpdbg_notice("Commands");
|
||||
{
|
||||
const phpdbg_command_t *break_command = phpdbg_break_commands;
|
||||
|
||||
phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
|
||||
while (break_command && break_command->name) {
|
||||
if (break_command->alias) {
|
||||
phpdbg_writeln("\t[%c]\t%s\t\t%s", break_command->alias, break_command->name, break_command->tip);
|
||||
} else {
|
||||
phpdbg_writeln("\t[ ]\t%s\t\t%s", break_command->name, break_command->tip);
|
||||
}
|
||||
++break_command;
|
||||
}
|
||||
}
|
||||
phpdbg_writeln("Note: Conditional breaks are costly, use them sparingly!");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(clean) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("While debugging you may experience errors because of attempts to redeclare classes, constants or functions");
|
||||
phpdbg_writeln("Cleaning the environment cleans these tables, so that files can be recompiled without exiting phpdbg");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(clear) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Clearing breakpoints means you can once again run code without interruption");
|
||||
phpdbg_writeln("Note: all breakpoints are lost; be sure debugging is complete before clearing");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(info) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("info commands provide quick access to various types of information about the PHP environment");
|
||||
phpdbg_writeln("Specific info commands are show below:");
|
||||
phpdbg_notice("Commands");
|
||||
{
|
||||
const phpdbg_command_t *info_command = phpdbg_info_commands;
|
||||
|
||||
phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
|
||||
while (info_command && info_command->name) {
|
||||
if (info_command->alias) {
|
||||
phpdbg_writeln("\t[%c]\t%s\t\t%s", info_command->alias, info_command->name, info_command->tip);
|
||||
} else {
|
||||
phpdbg_writeln("\t[ ]\t%s\t\t%s", info_command->name, info_command->tip);
|
||||
}
|
||||
++info_command;
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(quiet) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Setting quietness on will stop the OPLINE output during execution");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%squiet 1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sQ 1", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill silence OPLINE output, while");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%squiet 0", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sQ 0", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill enable OPLINE output again");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: Quietness is disabled automatically while stepping");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(back) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("The backtrace is built with the default debug backtrace functionality");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sback 5", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%st 5", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill limit the number of frames to 5, the default is no limit");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: it is not necessary for an exception to be thrown to show a backtrace");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(frame) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("When viewing a backtrace, it is sometimes useful to jump to a frame in that trace");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sframe 2", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sf 2", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill go to frame 2, temporarily affecting scope and allowing access to the variables in that frame");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: the current frame is restored when execution continues");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(list) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("The list command displays source code for the given argument");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%slist [lines] 2", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sl [l] 2", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print next 2 lines from the current file");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%slist [func] my_function", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sl [f] my_function", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the source of the global function \"my_function\"");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%slist [func] .mine", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sl [f] .mine", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the source of the method \"mine\" from the active scope");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%slist [method] my::method", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sl [m] my::method", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the source of \"my::method\"");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%slist c myClass", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sl c myClass", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill print the source of \"myClass\"");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: before listing functions you must have a populated function table, try compile!!");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("The parameters enclosed by [] are usually optional, but help avoid ambigious commands");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Specific listers loaded are show below:");
|
||||
phpdbg_notice("Commands");
|
||||
{
|
||||
const phpdbg_command_t *list_command = phpdbg_list_commands;
|
||||
|
||||
phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
|
||||
while (list_command && list_command->name) {
|
||||
if (list_command->alias) {
|
||||
phpdbg_writeln("\t[%c]\t%s\t\t%s", list_command->alias, list_command->name, list_command->tip);
|
||||
} else {
|
||||
phpdbg_writeln("\t[ ]\t%s\t\t%s", list_command->name, list_command->tip);
|
||||
}
|
||||
++list_command;
|
||||
}
|
||||
}
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(oplog) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Even when quietness is enabled you may wish to save opline logs to a file");
|
||||
phpdbg_writeln("Setting a new oplog closes the previously open log");
|
||||
phpdbg_writeln("The log includes a high resolution timestamp on each entry");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%soplog /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sO /path/to/my.oplog", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill open the file /path/to/my.oplog for writing, creating it if it does not exist");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("\t%soplog 0", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sO 0", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill close the currently open log file, disabling oplog");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: upon failure to open a new oplog, the last oplog is held open");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(set) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Configure how phpdbg looks and behaves with the set command");
|
||||
phpdbg_writeln("Specific set commands are show below:");
|
||||
phpdbg_notice("Commands");
|
||||
{
|
||||
const phpdbg_command_t *set_command = phpdbg_set_commands;
|
||||
|
||||
phpdbg_writeln("\tAlias\tCommand\t\tPurpose");
|
||||
while (set_command && set_command->name) {
|
||||
if (set_command->alias) {
|
||||
phpdbg_writeln("\t[%c]\t%s\t\t%s", set_command->alias, set_command->name, set_command->tip);
|
||||
} else {
|
||||
phpdbg_writeln("\t[ ]\t%s\t\t%s", set_command->name, set_command->tip);
|
||||
}
|
||||
++set_command;
|
||||
}
|
||||
}
|
||||
#ifndef _WIN32
|
||||
phpdbg_notice("Colors");
|
||||
{
|
||||
const phpdbg_color_t *color = phpdbg_get_colors(TSRMLS_C);
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
phpdbg_writeln("\t%-20s\t\tExample", "Name");
|
||||
} else {
|
||||
phpdbg_writeln("\tName");
|
||||
}
|
||||
|
||||
while (color && color->name) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
phpdbg_writeln(
|
||||
"\t%-20s\t\t\033[%smphpdbg rocks :)\033[0m", color->name, color->code);
|
||||
} else {
|
||||
phpdbg_writeln("\t%s", color->name);
|
||||
}
|
||||
++color;
|
||||
}
|
||||
}
|
||||
phpdbg_writeln("The <element> for set color can be \"prompt\", \"notice\", or \"error\"");
|
||||
#endif
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(register) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Register any global function for use as a command in phpdbg console");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sregister scandir", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%sR scandir", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill register the scandir function for use in phpdbg");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: arguments passed as strings, return (if present) print_r'd on console");
|
||||
if (zend_hash_num_elements(&PHPDBG_G(registered))) {
|
||||
HashPosition position;
|
||||
char *name = NULL;
|
||||
zend_uint name_len = 0;
|
||||
|
||||
phpdbg_notice("Registered Functions (%d)", zend_hash_num_elements(&PHPDBG_G(registered)));
|
||||
for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(registered), &position);
|
||||
zend_hash_get_current_key_ex(&PHPDBG_G(registered), &name, &name_len, NULL, 1, &position) == HASH_KEY_IS_STRING;
|
||||
zend_hash_move_forward_ex(&PHPDBG_G(registered), &position)) {
|
||||
phpdbg_writeln("|-------> %s", name);
|
||||
efree(name);
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(source) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Sourcing a phpdbginit during your debugging session might save some time");
|
||||
phpdbg_writeln("The source command can also be used to export breakpoints to a phpdbginit file");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%ssource /my/init", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%s. /my/init", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill execute the phpdbginit file at /my/init");
|
||||
phpdbg_writeln("\t%ssource export /my/init", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%s. export /my/init", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill export breakpoints to /my/init in phpdbginit file format");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(shell) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Direct access to shell commands saves having to switch windows/consoles");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_notice("Examples");
|
||||
phpdbg_writeln("\t%sshell ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\t%s- ls /usr/src/php-src", phpdbg_get_prompt(TSRMLS_C));
|
||||
phpdbg_writeln("\tWill execute ls /usr/src/php-src, displaying the output in the console");
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("Note: read only commands please!");
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_HELP(options) /* {{{ */
|
||||
{
|
||||
phpdbg_help_header();
|
||||
phpdbg_writeln("Below are the command line options supported by phpdbg");
|
||||
phpdbg_notice("Command Line Options and Flags");
|
||||
phpdbg_writeln(" -c\t-c/my/php.ini\t\tSet php.ini file to load");
|
||||
phpdbg_writeln(" -d\t-dmemory_limit=4G\tSet a php.ini directive");
|
||||
phpdbg_writeln(" -n\tN/A\t\t\tDisable default php.ini");
|
||||
phpdbg_writeln(" -q\tN/A\t\t\tSupress welcome banner");
|
||||
phpdbg_writeln(" -e\t-emytest.php\t\tSet execution context");
|
||||
phpdbg_writeln(" -v\tN/A\t\t\tEnable oplog output");
|
||||
phpdbg_writeln(" -s\tN/A\t\t\tEnable stepping");
|
||||
phpdbg_writeln(" -b\tN/A\t\t\tDisable colour");
|
||||
phpdbg_writeln(" -i\t-imy.init\t\tSet .phpdbginit file");
|
||||
phpdbg_writeln(" -I\tN/A\t\t\tIgnore default .phpdbginit");
|
||||
phpdbg_writeln(" -O\t-Omy.oplog\t\tSets oplog output file");
|
||||
phpdbg_writeln(" -r\tN/A\t\t\tRun execution context");
|
||||
phpdbg_writeln(" -E\tN/A\t\t\tEnable step through eval, careful!");
|
||||
phpdbg_writeln(" -S\t-Scli\t\t\tOverride SAPI name, careful!");
|
||||
#ifndef _WIN32
|
||||
phpdbg_writeln(" -l\t-l4000\t\t\tSetup remote console ports");
|
||||
phpdbg_writeln(" -a\t-a192.168.0.3\t\tSetup remote console bind address");
|
||||
#endif
|
||||
phpdbg_writeln(" -V\tN/A\t\t\tVersion number");
|
||||
phpdbg_notice("Passing -rr will quit automatically after execution");
|
||||
#ifndef _WIN32
|
||||
phpdbg_writeln("Remote Console Mode");
|
||||
phpdbg_notice("For security, phpdbg will bind only to the loopback interface by default");
|
||||
phpdbg_writeln("-a without an argument implies all; phpdbg will bind to all available interfaces.");
|
||||
phpdbg_writeln("specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2.");
|
||||
phpdbg_notice("Steps should be taken to secure this service if bound to a public interface/port");
|
||||
#endif
|
||||
phpdbg_help_footer();
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
92
sapi/phpdbg/phpdbg_help.h
Normal file
92
sapi/phpdbg/phpdbg_help.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_HELP_H
|
||||
#define PHPDBG_HELP_H
|
||||
|
||||
#include "TSRM.h"
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
|
||||
#define PHPDBG_HELP(name) PHPDBG_COMMAND(help_##name)
|
||||
|
||||
/**
|
||||
* Helper Forward Declarations
|
||||
*/
|
||||
PHPDBG_HELP(exec);
|
||||
PHPDBG_HELP(compile);
|
||||
PHPDBG_HELP(step);
|
||||
PHPDBG_HELP(next);
|
||||
PHPDBG_HELP(run);
|
||||
PHPDBG_HELP(eval);
|
||||
PHPDBG_HELP(until);
|
||||
PHPDBG_HELP(finish);
|
||||
PHPDBG_HELP(leave);
|
||||
PHPDBG_HELP(print);
|
||||
PHPDBG_HELP(break);
|
||||
PHPDBG_HELP(clean);
|
||||
PHPDBG_HELP(clear);
|
||||
PHPDBG_HELP(info);
|
||||
PHPDBG_HELP(back);
|
||||
PHPDBG_HELP(frame);
|
||||
PHPDBG_HELP(quiet);
|
||||
PHPDBG_HELP(list);
|
||||
PHPDBG_HELP(set);
|
||||
PHPDBG_HELP(register);
|
||||
PHPDBG_HELP(options);
|
||||
PHPDBG_HELP(source);
|
||||
PHPDBG_HELP(shell);
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
static const phpdbg_command_t phpdbg_help_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(exec, "the execution context should be a valid path", 'e', help_exec, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(compile, "allow inspection of code before execution", 'c', help_compile, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(step, "step through execution to break at every opcode", 's', help_step, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(next, "continue executing while stepping or after breaking", 'n', help_next, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(run, "execute inside the phpdbg vm", 'r', help_run, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(eval, "access to eval() allows affecting the environment", 'E', help_eval, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(until, "continue until the current line is executed", 'u', help_until, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(finish, "continue until the current function has returned", 'F', help_finish, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(leave, "continue until the current function is returning", 'L', help_leave, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(print, "print context information or instructions", 'p', help_print, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(break, "breakpoints allow execution interruption", 'b', help_break, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(clean, "resetting the environment is useful while debugging", 'X', help_clean, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(clear, "reset breakpoints to execute without interruption", 'c', help_clear, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(info, "quick access to useful information on the console", 'i', help_info, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(back, "show debug backtrace information during execution", 't', help_back, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(frame, "switch to a frame in the current stack for inspection", 'f', help_frame, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(quiet, "be quiet during execution", 'Q', help_quiet, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(list, "list code gives you quick access to code", 'l', help_list, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(set, "configure how phpdbg looks and behaves", 'S', help_set, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(register, "register a function for use as a command", 'R', help_register,NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(options, "show information about command line options", 'o', help_options, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(source, "load a phpdbginit file at the console", '.', help_source, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(shell, "execute system commands with direct shell access", '-', help_shell, NULL, 0),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
#define phpdbg_help_header() \
|
||||
phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
|
||||
#define phpdbg_help_footer() \
|
||||
phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
|
||||
|
||||
#endif /* PHPDBG_HELP_H */
|
355
sapi/phpdbg/phpdbg_info.c
Normal file
355
sapi/phpdbg/phpdbg_info.c
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "php.h"
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_info.h"
|
||||
#include "phpdbg_bp.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_INFO(break) /* {{{ */
|
||||
{
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_FILE TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_SYM TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_OPLINE TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_FILE_OPLINE TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_FUNCTION_OPLINE TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_METHOD_OPLINE TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_COND TSRMLS_CC);
|
||||
phpdbg_print_breakpoints(PHPDBG_BREAK_OPCODE TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(files) /* {{{ */
|
||||
{
|
||||
HashPosition pos;
|
||||
char *fname;
|
||||
|
||||
phpdbg_notice("Included files: %d",
|
||||
zend_hash_num_elements(&EG(included_files)));
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos);
|
||||
while (zend_hash_get_current_key_ex(&EG(included_files), &fname,
|
||||
NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
|
||||
phpdbg_writeln("File: %s", fname);
|
||||
zend_hash_move_forward_ex(&EG(included_files), &pos);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(error) /* {{{ */
|
||||
{
|
||||
if (PG(last_error_message)) {
|
||||
phpdbg_writeln("Last error: %s at %s line %d",
|
||||
PG(last_error_message), PG(last_error_file), PG(last_error_lineno));
|
||||
} else {
|
||||
phpdbg_notice("No error found!");
|
||||
}
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(vars) /* {{{ */
|
||||
{
|
||||
HashTable vars;
|
||||
HashPosition pos;
|
||||
char *var;
|
||||
zval **data;
|
||||
|
||||
if (!EG(active_op_array)) {
|
||||
phpdbg_error("No active op array!");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (!EG(active_symbol_table)) {
|
||||
zend_rebuild_symbol_table(TSRMLS_C);
|
||||
|
||||
if (!EG(active_symbol_table)) {
|
||||
phpdbg_error("No active symbol table!");
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
zend_hash_init(&vars, 8, NULL, NULL, 0);
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(EG(active_symbol_table), &pos);
|
||||
while (zend_hash_get_current_key_ex(EG(active_symbol_table), &var,
|
||||
NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
|
||||
zend_hash_get_current_data_ex(EG(active_symbol_table), (void **)&data, &pos);
|
||||
if (*var != '_') {
|
||||
zend_hash_update(
|
||||
&vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL);
|
||||
}
|
||||
zend_hash_move_forward_ex(EG(active_symbol_table), &pos);
|
||||
}
|
||||
|
||||
{
|
||||
zend_op_array *ops = EG(active_op_array);
|
||||
|
||||
if (ops->function_name) {
|
||||
if (ops->scope) {
|
||||
phpdbg_notice(
|
||||
"Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars));
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars));
|
||||
}
|
||||
} else {
|
||||
if (ops->filename) {
|
||||
phpdbg_notice(
|
||||
"Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars));
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Variables @ %p (%d)", ops, zend_hash_num_elements(&vars));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zend_hash_num_elements(&vars)) {
|
||||
phpdbg_writeln("Address\t\tRefs\tType\t\tVariable");
|
||||
for (zend_hash_internal_pointer_reset_ex(&vars, &pos);
|
||||
zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&vars, &pos)) {
|
||||
char *var;
|
||||
|
||||
zend_hash_get_current_key_ex(&vars, &var, NULL, NULL, 0, &pos);
|
||||
|
||||
if (*data) {
|
||||
phpdbg_write(
|
||||
"%p\t%d\t",
|
||||
*data,
|
||||
Z_REFCOUNT_PP(data));
|
||||
|
||||
switch (Z_TYPE_PP(data)) {
|
||||
case IS_STRING: phpdbg_write("(string)\t"); break;
|
||||
case IS_LONG: phpdbg_write("(integer)\t"); break;
|
||||
case IS_DOUBLE: phpdbg_write("(float)\t"); break;
|
||||
case IS_RESOURCE: phpdbg_write("(resource)\t"); break;
|
||||
case IS_ARRAY: phpdbg_write("(array)\t"); break;
|
||||
case IS_OBJECT: phpdbg_write("(object)\t"); break;
|
||||
case IS_NULL: phpdbg_write("(null)\t"); break;
|
||||
}
|
||||
|
||||
if (Z_TYPE_PP(data) == IS_RESOURCE) {
|
||||
int type;
|
||||
|
||||
phpdbg_writeln(
|
||||
"%s$%s", Z_ISREF_PP(data) ? "&": "", var);
|
||||
if (zend_list_find(Z_RESVAL_PP(data), &type)) {
|
||||
phpdbg_write(
|
||||
"|-------(typeof)------> (%s)",
|
||||
zend_rsrc_list_get_rsrc_type(type TSRMLS_CC));
|
||||
} else {
|
||||
phpdbg_write(
|
||||
"|-------(typeof)------> (unknown)");
|
||||
}
|
||||
phpdbg_writeln(EMPTY);
|
||||
} else if (Z_TYPE_PP(data) == IS_OBJECT) {
|
||||
phpdbg_writeln(
|
||||
"%s$%s", Z_ISREF_PP(data) ? "&": "", var);
|
||||
phpdbg_write(
|
||||
"|-----(instanceof)----> (%s)", Z_OBJCE_PP(data)->name);
|
||||
phpdbg_writeln(EMPTY);
|
||||
} else {
|
||||
phpdbg_write(
|
||||
"%s$%s", Z_ISREF_PP(data) ? "&": "", var);
|
||||
}
|
||||
} else {
|
||||
phpdbg_write(
|
||||
"n/a\tn/a\tn/a\t$%s", var);
|
||||
}
|
||||
phpdbg_writeln(EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
zend_hash_destroy(&vars);
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(literal) /* {{{ */
|
||||
{
|
||||
if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) {
|
||||
zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops);
|
||||
int literal = 0, count = ops->last_literal-1;
|
||||
|
||||
if (ops->function_name) {
|
||||
if (ops->scope) {
|
||||
phpdbg_notice(
|
||||
"Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count);
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Literal Constants in %s() (%d)", ops->function_name, count);
|
||||
}
|
||||
} else {
|
||||
if (ops->filename) {
|
||||
phpdbg_notice(
|
||||
"Literal Constants in %s (%d)", ops->filename, count);
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Literal Constants @ %p (%d)", ops, count);
|
||||
}
|
||||
}
|
||||
|
||||
while (literal < ops->last_literal) {
|
||||
if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) {
|
||||
phpdbg_write("|-------- C%u -------> [", literal);
|
||||
zend_print_zval(
|
||||
&ops->literals[literal].constant, 0);
|
||||
phpdbg_write("]");
|
||||
phpdbg_writeln(EMPTY);
|
||||
}
|
||||
literal++;
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("Not executing!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(memory) /* {{{ */
|
||||
{
|
||||
if (is_zend_mm(TSRMLS_C)) {
|
||||
phpdbg_notice("Memory Manager Information");
|
||||
phpdbg_notice("Current");
|
||||
phpdbg_writeln("|-------> Used:\t%.3f kB",
|
||||
(float) (zend_memory_usage(0 TSRMLS_CC)/1024));
|
||||
phpdbg_writeln("|-------> Real:\t%.3f kB",
|
||||
(float) (zend_memory_usage(1 TSRMLS_CC)/1024));
|
||||
phpdbg_notice("Peak");
|
||||
phpdbg_writeln("|-------> Used:\t%.3f kB",
|
||||
(float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024));
|
||||
phpdbg_writeln("|-------> Real:\t%.3f kB",
|
||||
(float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024));
|
||||
} else {
|
||||
phpdbg_error("Memory Manager Disabled!");
|
||||
}
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
phpdbg_write(
|
||||
"%s %s %s (%d)",
|
||||
((*ce)->type == ZEND_USER_CLASS) ?
|
||||
"User" : "Internal",
|
||||
((*ce)->ce_flags & ZEND_ACC_INTERFACE) ?
|
||||
"Interface" :
|
||||
((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ?
|
||||
"Abstract Class" :
|
||||
"Class",
|
||||
(*ce)->name, zend_hash_num_elements(&(*ce)->function_table));
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(classes) /* {{{ */
|
||||
{
|
||||
HashPosition position;
|
||||
zend_class_entry **ce;
|
||||
HashTable classes;
|
||||
|
||||
zend_hash_init(&classes, 8, NULL, NULL, 0);
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position);
|
||||
zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(class_table), &position)) {
|
||||
|
||||
if ((*ce)->type == ZEND_USER_CLASS) {
|
||||
zend_hash_next_index_insert(
|
||||
&classes, ce, sizeof(ce), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_notice("User Classes (%d)",
|
||||
zend_hash_num_elements(&classes));
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(&classes, &position);
|
||||
zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&classes, &position)) {
|
||||
|
||||
phpdbg_print_class_name(ce TSRMLS_CC);
|
||||
phpdbg_writeln(EMPTY);
|
||||
|
||||
if ((*ce)->parent) {
|
||||
zend_class_entry *pce = (*ce)->parent;
|
||||
do {
|
||||
phpdbg_write("|-------- ");
|
||||
phpdbg_print_class_name(&pce TSRMLS_CC);
|
||||
phpdbg_writeln(EMPTY);
|
||||
} while ((pce = pce->parent));
|
||||
}
|
||||
|
||||
if ((*ce)->info.user.filename) {
|
||||
phpdbg_writeln(
|
||||
"|---- in %s on line %u",
|
||||
(*ce)->info.user.filename,
|
||||
(*ce)->info.user.line_start);
|
||||
} else {
|
||||
phpdbg_writeln("|---- no source code");
|
||||
}
|
||||
phpdbg_writeln(EMPTY);
|
||||
}
|
||||
|
||||
zend_hash_destroy(&classes);
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(funcs) /* {{{ */
|
||||
{
|
||||
HashPosition position;
|
||||
zend_function *zf, **pzf;
|
||||
HashTable functions;
|
||||
|
||||
zend_hash_init(&functions, 8, NULL, NULL, 0);
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position);
|
||||
zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(function_table), &position)) {
|
||||
|
||||
if (zf->type == ZEND_USER_FUNCTION) {
|
||||
zend_hash_next_index_insert(
|
||||
&functions, (void**) &zf, sizeof(zend_function), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_notice("User Functions (%d)",
|
||||
zend_hash_num_elements(&functions));
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(&functions, &position);
|
||||
zend_hash_get_current_data_ex(&functions, (void**)&pzf, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&functions, &position)) {
|
||||
zend_op_array *op_array = &((*pzf)->op_array);
|
||||
|
||||
phpdbg_writeln(
|
||||
"|-------- %s in %s on line %d",
|
||||
op_array->function_name ? op_array->function_name : "{main}",
|
||||
op_array->filename ? op_array->filename : "(no source code)",
|
||||
op_array->line_start);
|
||||
}
|
||||
|
||||
zend_hash_destroy(&functions);
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
49
sapi/phpdbg/phpdbg_info.h
Normal file
49
sapi/phpdbg/phpdbg_info.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_INFO_H
|
||||
#define PHPDBG_INFO_H
|
||||
|
||||
#include "phpdbg_cmd.h"
|
||||
|
||||
#define PHPDBG_INFO(name) PHPDBG_COMMAND(info_##name)
|
||||
|
||||
PHPDBG_INFO(files);
|
||||
PHPDBG_INFO(break);
|
||||
PHPDBG_INFO(classes);
|
||||
PHPDBG_INFO(funcs);
|
||||
PHPDBG_INFO(error);
|
||||
PHPDBG_INFO(vars);
|
||||
PHPDBG_INFO(literal);
|
||||
PHPDBG_INFO(memory);
|
||||
|
||||
static const phpdbg_command_t phpdbg_info_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(break, "show breakpoints", 'b', info_break, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(files, "show included files", 'F', info_files, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(classes, "show loaded classes", 'c', info_classes, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(funcs, "show loaded classes", 'f', info_funcs, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(error, "show last error", 'e', info_error, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(vars, "show active variables", 'v', info_vars, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(literal, "show active literal constants", 'l', info_literal, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(memory, "show memory manager stats", 'm', info_memory, NULL, 0),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
#endif /* PHPDBG_INFO_H */
|
279
sapi/phpdbg/phpdbg_list.c
Normal file
279
sapi/phpdbg/phpdbg_list.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef _WIN32
|
||||
# include <sys/mman.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_list.h"
|
||||
#include "phpdbg_utils.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_LIST(lines) /* {{{ */
|
||||
{
|
||||
if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) {
|
||||
phpdbg_error("Not executing, and execution context not set");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (param->type) {
|
||||
case NUMERIC_PARAM:
|
||||
case EMPTY_PARAM:
|
||||
phpdbg_list_file(phpdbg_current_file(TSRMLS_C),
|
||||
param->type == EMPTY_PARAM ? 0 : (param->num < 0 ? 1 - param->num : param->num),
|
||||
(param->type != EMPTY_PARAM && param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C),
|
||||
0 TSRMLS_CC);
|
||||
break;
|
||||
case FILE_PARAM:
|
||||
phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_LIST(func) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
phpdbg_list_function_byname(
|
||||
param->str, param->len TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_LIST(method) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case METHOD_PARAM: {
|
||||
zend_class_entry **ce;
|
||||
|
||||
if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
zend_function *function;
|
||||
char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
|
||||
|
||||
if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) {
|
||||
phpdbg_list_function(function TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Could not find %s::%s", param->method.class, param->method.name);
|
||||
}
|
||||
|
||||
efree(lcname);
|
||||
} else {
|
||||
phpdbg_error("Could not find the class %s", param->method.class);
|
||||
}
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_LIST(class) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM: {
|
||||
zend_class_entry **ce;
|
||||
|
||||
if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
if ((*ce)->type == ZEND_USER_CLASS) {
|
||||
if ((*ce)->info.user.filename) {
|
||||
phpdbg_list_file(
|
||||
(*ce)->info.user.filename,
|
||||
(*ce)->info.user.line_end - (*ce)->info.user.line_start + 1,
|
||||
(*ce)->info.user.line_start, 0 TSRMLS_CC
|
||||
);
|
||||
} else {
|
||||
phpdbg_error("The source of the requested class (%s) cannot be found", (*ce)->name);
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("The class requested (%s) is not user defined", (*ce)->name);
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("The requested class (%s) could not be found", param->str);
|
||||
}
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
unsigned char *mem, *pos, *last_pos, *end_pos;
|
||||
struct stat st;
|
||||
#ifndef _WIN32
|
||||
int fd;
|
||||
#else
|
||||
HANDLE fd, map;
|
||||
#endif
|
||||
int all_content = (count == 0);
|
||||
int line = 0, displayed = 0;
|
||||
|
||||
if (VCWD_STAT(filename, &st) == FAILURE) {
|
||||
phpdbg_error("Failed to stat file %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if ((fd = VCWD_OPEN(filename, O_RDONLY)) == FAILURE) {
|
||||
phpdbg_error("Failed to open file %s to list", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = last_pos = mem = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
end_pos = mem + st.st_size;
|
||||
#else
|
||||
|
||||
fd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fd == INVALID_HANDLE_VALUE) {
|
||||
phpdbg_error("Failed to open file!");
|
||||
return;
|
||||
}
|
||||
|
||||
map = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (map == NULL) {
|
||||
phpdbg_error("Failed to map file!");
|
||||
CloseHandle(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = last_pos = mem = (char*) MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
|
||||
if (mem == NULL) {
|
||||
phpdbg_error("Failed to map file in memory");
|
||||
CloseHandle(map);
|
||||
CloseHandle(fd);
|
||||
return;
|
||||
}
|
||||
end_pos = mem + st.st_size;
|
||||
#endif
|
||||
while (1) {
|
||||
if (pos == end_pos) {
|
||||
break;
|
||||
}
|
||||
|
||||
pos = memchr(last_pos, '\n', end_pos - last_pos);
|
||||
|
||||
if (!pos) {
|
||||
/* No more line breaks */
|
||||
pos = end_pos;
|
||||
}
|
||||
|
||||
++line;
|
||||
|
||||
if (!offset || offset <= line) {
|
||||
/* Without offset, or offset reached */
|
||||
if (!highlight) {
|
||||
phpdbg_writeln("%05u: %.*s", line, (int)(pos - last_pos), last_pos);
|
||||
} else {
|
||||
if (highlight != line) {
|
||||
phpdbg_writeln(" %05u: %.*s", line, (int)(pos - last_pos), last_pos);
|
||||
} else {
|
||||
phpdbg_writeln(">%05u: %.*s", line, (int)(pos - last_pos), last_pos);
|
||||
}
|
||||
}
|
||||
++displayed;
|
||||
}
|
||||
|
||||
last_pos = pos + 1;
|
||||
|
||||
if (!all_content && displayed == count) {
|
||||
/* Reached max line to display */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
#else
|
||||
UnmapViewOfFile(mem);
|
||||
CloseHandle(map);
|
||||
CloseHandle(fd);
|
||||
#endif
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
const zend_op_array *ops;
|
||||
|
||||
if (fbc->type != ZEND_USER_FUNCTION) {
|
||||
phpdbg_error("The function requested (%s) is not user defined", fbc->common.function_name);
|
||||
return;
|
||||
}
|
||||
|
||||
ops = (zend_op_array*)fbc;
|
||||
|
||||
phpdbg_list_file(ops->filename,
|
||||
ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC);
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
HashTable *func_table = EG(function_table);
|
||||
zend_function* fbc;
|
||||
char *func_name = (char*) str;
|
||||
size_t func_name_len = len;
|
||||
|
||||
/* search active scope if begins with period */
|
||||
if (func_name[0] == '.') {
|
||||
if (EG(scope)) {
|
||||
func_name++;
|
||||
func_name_len--;
|
||||
|
||||
func_table = &EG(scope)->function_table;
|
||||
} else {
|
||||
phpdbg_error("No active class");
|
||||
return;
|
||||
}
|
||||
} else if (!EG(function_table)) {
|
||||
phpdbg_error("No function table loaded");
|
||||
return;
|
||||
} else {
|
||||
func_table = EG(function_table);
|
||||
}
|
||||
|
||||
/* use lowercase names, case insensitive */
|
||||
func_name = zend_str_tolower_dup(func_name, func_name_len);
|
||||
|
||||
if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_list_function(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Function %s not found", func_name);
|
||||
}
|
||||
|
||||
efree(func_name);
|
||||
} /* }}} */
|
||||
|
47
sapi/phpdbg/phpdbg_list.h
Normal file
47
sapi/phpdbg/phpdbg_list.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_LIST_H
|
||||
#define PHPDBG_LIST_H
|
||||
|
||||
#include "TSRM.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
|
||||
#define PHPDBG_LIST(name) PHPDBG_COMMAND(list_##name)
|
||||
#define PHPDBG_LIST_HANDLER(name) PHPDBG_COMMAND_HANDLER(list_##name)
|
||||
|
||||
PHPDBG_LIST(lines);
|
||||
PHPDBG_LIST(class);
|
||||
PHPDBG_LIST(method);
|
||||
PHPDBG_LIST(func);
|
||||
|
||||
void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC);
|
||||
void phpdbg_list_function(const zend_function* TSRMLS_DC);
|
||||
void phpdbg_list_file(const char*, long, long, int TSRMLS_DC);
|
||||
|
||||
static const phpdbg_command_t phpdbg_list_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(lines, "lists the specified lines", 'l', list_lines, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(class, "lists the specified class", 'c', list_class, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(method, "lists the specified method", 'm', list_method, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(func, "lists the specified function", 'f', list_func, NULL, 1),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
#endif /* PHPDBG_LIST_H */
|
361
sapi/phpdbg/phpdbg_opcode.c
Normal file
361
sapi/phpdbg/phpdbg_opcode.c
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "zend_vm_opcodes.h"
|
||||
#include "zend_compile.h"
|
||||
#include "phpdbg_opcode.h"
|
||||
#include "phpdbg_utils.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
static inline zend_uint phpdbg_decode_literal(zend_op_array *ops, zend_literal *literal TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
int iter = 0;
|
||||
|
||||
while (iter < ops->last_literal) {
|
||||
if (literal == &ops->literals[iter]) {
|
||||
return iter;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* }}} */
|
||||
|
||||
static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint type, HashTable *vars TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
char *decode = NULL;
|
||||
|
||||
switch (type &~ EXT_TYPE_UNUSED) {
|
||||
case IS_CV:
|
||||
asprintf(&decode, "$%s", ops->vars[op->var].name);
|
||||
break;
|
||||
|
||||
case IS_VAR:
|
||||
case IS_TMP_VAR: {
|
||||
zend_ulong id = 0, *pid = NULL;
|
||||
if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) {
|
||||
id = zend_hash_num_elements(vars);
|
||||
zend_hash_index_update(
|
||||
vars, (zend_ulong) ops->vars - op->var,
|
||||
(void**) &id,
|
||||
sizeof(zend_ulong), NULL);
|
||||
} else id = *pid;
|
||||
asprintf(&decode, "@%lu", id);
|
||||
} break;
|
||||
|
||||
case IS_CONST:
|
||||
asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->literal TSRMLS_CC));
|
||||
break;
|
||||
|
||||
case IS_UNUSED:
|
||||
asprintf(&decode, "<unused>");
|
||||
break;
|
||||
}
|
||||
return decode;
|
||||
} /* }}} */
|
||||
|
||||
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC) /*{{{ */
|
||||
{
|
||||
char *decode[4] = {NULL, NULL, NULL, NULL};
|
||||
|
||||
switch (op->opcode) {
|
||||
case ZEND_JMP:
|
||||
#ifdef ZEND_GOTO
|
||||
case ZEND_GOTO:
|
||||
#endif
|
||||
#ifdef ZEND_FAST_CALL
|
||||
case ZEND_FAST_CALL:
|
||||
#endif
|
||||
asprintf(&decode[1], "J%ld", op->op1.jmp_addr - ops->opcodes);
|
||||
goto format;
|
||||
|
||||
case ZEND_JMPZNZ:
|
||||
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||
asprintf(
|
||||
&decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value);
|
||||
goto result;
|
||||
|
||||
case ZEND_JMPZ:
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
|
||||
#ifdef ZEND_JMP_SET
|
||||
case ZEND_JMP_SET:
|
||||
#endif
|
||||
#ifdef ZEND_JMP_SET_VAR
|
||||
case ZEND_JMP_SET_VAR:
|
||||
#endif
|
||||
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||
asprintf(
|
||||
&decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes);
|
||||
goto result;
|
||||
|
||||
case ZEND_RECV_INIT:
|
||||
goto result;
|
||||
|
||||
default: {
|
||||
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||
decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars TSRMLS_CC);
|
||||
result:
|
||||
decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC);
|
||||
format:
|
||||
asprintf(
|
||||
&decode[0],
|
||||
"%-20s %-20s %-20s",
|
||||
decode[1] ? decode[1] : "",
|
||||
decode[2] ? decode[2] : "",
|
||||
decode[3] ? decode[3] : "");
|
||||
}
|
||||
}
|
||||
|
||||
if (decode[1])
|
||||
free(decode[1]);
|
||||
if (decode[2])
|
||||
free(decode[2]);
|
||||
if (decode[3])
|
||||
free(decode[3]);
|
||||
|
||||
return decode[0];
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
/* force out a line while stepping so the user knows what is happening */
|
||||
if (ignore_flags ||
|
||||
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
|
||||
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ||
|
||||
(PHPDBG_G(oplog)))) {
|
||||
|
||||
zend_op *opline = execute_data->opline;
|
||||
char *decode = phpdbg_decode_opline(execute_data->op_array, opline, vars TSRMLS_CC);
|
||||
|
||||
if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
|
||||
/* output line info */
|
||||
phpdbg_notice("L%-5u %16p %-30s %s %s",
|
||||
opline->lineno,
|
||||
opline,
|
||||
phpdbg_decode_opcode(opline->opcode),
|
||||
decode,
|
||||
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
||||
}
|
||||
|
||||
if (!ignore_flags && PHPDBG_G(oplog)) {
|
||||
phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s",
|
||||
opline->lineno,
|
||||
opline,
|
||||
phpdbg_decode_opcode(opline->opcode),
|
||||
decode,
|
||||
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
||||
}
|
||||
|
||||
if (decode) {
|
||||
free(decode);
|
||||
}
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
phpdbg_print_opline_ex(execute_data, NULL, ignore_flags TSRMLS_CC);
|
||||
} /* }}} */
|
||||
|
||||
const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
|
||||
{
|
||||
#define CASE(s) case s: return #s
|
||||
switch (opcode) {
|
||||
CASE(ZEND_NOP);
|
||||
CASE(ZEND_ADD);
|
||||
CASE(ZEND_SUB);
|
||||
CASE(ZEND_MUL);
|
||||
CASE(ZEND_DIV);
|
||||
CASE(ZEND_MOD);
|
||||
CASE(ZEND_SL);
|
||||
CASE(ZEND_SR);
|
||||
CASE(ZEND_CONCAT);
|
||||
CASE(ZEND_BW_OR);
|
||||
CASE(ZEND_BW_AND);
|
||||
CASE(ZEND_BW_XOR);
|
||||
CASE(ZEND_BW_NOT);
|
||||
CASE(ZEND_BOOL_NOT);
|
||||
CASE(ZEND_BOOL_XOR);
|
||||
CASE(ZEND_IS_IDENTICAL);
|
||||
CASE(ZEND_IS_NOT_IDENTICAL);
|
||||
CASE(ZEND_IS_EQUAL);
|
||||
CASE(ZEND_IS_NOT_EQUAL);
|
||||
CASE(ZEND_IS_SMALLER);
|
||||
CASE(ZEND_IS_SMALLER_OR_EQUAL);
|
||||
CASE(ZEND_CAST);
|
||||
CASE(ZEND_QM_ASSIGN);
|
||||
CASE(ZEND_ASSIGN_ADD);
|
||||
CASE(ZEND_ASSIGN_SUB);
|
||||
CASE(ZEND_ASSIGN_MUL);
|
||||
CASE(ZEND_ASSIGN_DIV);
|
||||
CASE(ZEND_ASSIGN_MOD);
|
||||
CASE(ZEND_ASSIGN_SL);
|
||||
CASE(ZEND_ASSIGN_SR);
|
||||
CASE(ZEND_ASSIGN_CONCAT);
|
||||
CASE(ZEND_ASSIGN_BW_OR);
|
||||
CASE(ZEND_ASSIGN_BW_AND);
|
||||
CASE(ZEND_ASSIGN_BW_XOR);
|
||||
CASE(ZEND_PRE_INC);
|
||||
CASE(ZEND_PRE_DEC);
|
||||
CASE(ZEND_POST_INC);
|
||||
CASE(ZEND_POST_DEC);
|
||||
CASE(ZEND_ASSIGN);
|
||||
CASE(ZEND_ASSIGN_REF);
|
||||
CASE(ZEND_ECHO);
|
||||
CASE(ZEND_PRINT);
|
||||
CASE(ZEND_JMP);
|
||||
CASE(ZEND_JMPZ);
|
||||
CASE(ZEND_JMPNZ);
|
||||
CASE(ZEND_JMPZNZ);
|
||||
CASE(ZEND_JMPZ_EX);
|
||||
CASE(ZEND_JMPNZ_EX);
|
||||
CASE(ZEND_CASE);
|
||||
CASE(ZEND_SWITCH_FREE);
|
||||
CASE(ZEND_BRK);
|
||||
CASE(ZEND_CONT);
|
||||
CASE(ZEND_BOOL);
|
||||
CASE(ZEND_INIT_STRING);
|
||||
CASE(ZEND_ADD_CHAR);
|
||||
CASE(ZEND_ADD_STRING);
|
||||
CASE(ZEND_ADD_VAR);
|
||||
CASE(ZEND_BEGIN_SILENCE);
|
||||
CASE(ZEND_END_SILENCE);
|
||||
CASE(ZEND_INIT_FCALL_BY_NAME);
|
||||
CASE(ZEND_DO_FCALL);
|
||||
CASE(ZEND_DO_FCALL_BY_NAME);
|
||||
CASE(ZEND_RETURN);
|
||||
CASE(ZEND_RECV);
|
||||
CASE(ZEND_RECV_INIT);
|
||||
CASE(ZEND_SEND_VAL);
|
||||
CASE(ZEND_SEND_VAR);
|
||||
CASE(ZEND_SEND_REF);
|
||||
CASE(ZEND_NEW);
|
||||
CASE(ZEND_INIT_NS_FCALL_BY_NAME);
|
||||
CASE(ZEND_FREE);
|
||||
CASE(ZEND_INIT_ARRAY);
|
||||
CASE(ZEND_ADD_ARRAY_ELEMENT);
|
||||
CASE(ZEND_INCLUDE_OR_EVAL);
|
||||
CASE(ZEND_UNSET_VAR);
|
||||
CASE(ZEND_UNSET_DIM);
|
||||
CASE(ZEND_UNSET_OBJ);
|
||||
CASE(ZEND_FE_RESET);
|
||||
CASE(ZEND_FE_FETCH);
|
||||
CASE(ZEND_EXIT);
|
||||
CASE(ZEND_FETCH_R);
|
||||
CASE(ZEND_FETCH_DIM_R);
|
||||
CASE(ZEND_FETCH_OBJ_R);
|
||||
CASE(ZEND_FETCH_W);
|
||||
CASE(ZEND_FETCH_DIM_W);
|
||||
CASE(ZEND_FETCH_OBJ_W);
|
||||
CASE(ZEND_FETCH_RW);
|
||||
CASE(ZEND_FETCH_DIM_RW);
|
||||
CASE(ZEND_FETCH_OBJ_RW);
|
||||
CASE(ZEND_FETCH_IS);
|
||||
CASE(ZEND_FETCH_DIM_IS);
|
||||
CASE(ZEND_FETCH_OBJ_IS);
|
||||
CASE(ZEND_FETCH_FUNC_ARG);
|
||||
CASE(ZEND_FETCH_DIM_FUNC_ARG);
|
||||
CASE(ZEND_FETCH_OBJ_FUNC_ARG);
|
||||
CASE(ZEND_FETCH_UNSET);
|
||||
CASE(ZEND_FETCH_DIM_UNSET);
|
||||
CASE(ZEND_FETCH_OBJ_UNSET);
|
||||
CASE(ZEND_FETCH_DIM_TMP_VAR);
|
||||
CASE(ZEND_FETCH_CONSTANT);
|
||||
CASE(ZEND_GOTO);
|
||||
CASE(ZEND_EXT_STMT);
|
||||
CASE(ZEND_EXT_FCALL_BEGIN);
|
||||
CASE(ZEND_EXT_FCALL_END);
|
||||
CASE(ZEND_EXT_NOP);
|
||||
CASE(ZEND_TICKS);
|
||||
CASE(ZEND_SEND_VAR_NO_REF);
|
||||
CASE(ZEND_CATCH);
|
||||
CASE(ZEND_THROW);
|
||||
CASE(ZEND_FETCH_CLASS);
|
||||
CASE(ZEND_CLONE);
|
||||
CASE(ZEND_RETURN_BY_REF);
|
||||
CASE(ZEND_INIT_METHOD_CALL);
|
||||
CASE(ZEND_INIT_STATIC_METHOD_CALL);
|
||||
CASE(ZEND_ISSET_ISEMPTY_VAR);
|
||||
CASE(ZEND_ISSET_ISEMPTY_DIM_OBJ);
|
||||
CASE(ZEND_PRE_INC_OBJ);
|
||||
CASE(ZEND_PRE_DEC_OBJ);
|
||||
CASE(ZEND_POST_INC_OBJ);
|
||||
CASE(ZEND_POST_DEC_OBJ);
|
||||
CASE(ZEND_ASSIGN_OBJ);
|
||||
CASE(ZEND_INSTANCEOF);
|
||||
CASE(ZEND_DECLARE_CLASS);
|
||||
CASE(ZEND_DECLARE_INHERITED_CLASS);
|
||||
CASE(ZEND_DECLARE_FUNCTION);
|
||||
CASE(ZEND_RAISE_ABSTRACT_ERROR);
|
||||
CASE(ZEND_DECLARE_CONST);
|
||||
CASE(ZEND_ADD_INTERFACE);
|
||||
CASE(ZEND_DECLARE_INHERITED_CLASS_DELAYED);
|
||||
CASE(ZEND_VERIFY_ABSTRACT_CLASS);
|
||||
CASE(ZEND_ASSIGN_DIM);
|
||||
CASE(ZEND_ISSET_ISEMPTY_PROP_OBJ);
|
||||
CASE(ZEND_HANDLE_EXCEPTION);
|
||||
CASE(ZEND_USER_OPCODE);
|
||||
#ifdef ZEND_JMP_SET
|
||||
CASE(ZEND_JMP_SET);
|
||||
#endif
|
||||
CASE(ZEND_DECLARE_LAMBDA_FUNCTION);
|
||||
#ifdef ZEND_ADD_TRAIT
|
||||
CASE(ZEND_ADD_TRAIT);
|
||||
#endif
|
||||
#ifdef ZEND_BIND_TRAITS
|
||||
CASE(ZEND_BIND_TRAITS);
|
||||
#endif
|
||||
#ifdef ZEND_SEPARATE
|
||||
CASE(ZEND_SEPARATE);
|
||||
#endif
|
||||
#ifdef ZEND_QM_ASSIGN_VAR
|
||||
CASE(ZEND_QM_ASSIGN_VAR);
|
||||
#endif
|
||||
#ifdef ZEND_JMP_SET_VAR
|
||||
CASE(ZEND_JMP_SET_VAR);
|
||||
#endif
|
||||
#ifdef ZEND_DISCARD_EXCEPTION
|
||||
CASE(ZEND_DISCARD_EXCEPTION);
|
||||
#endif
|
||||
#ifdef ZEND_YIELD
|
||||
CASE(ZEND_YIELD);
|
||||
#endif
|
||||
#ifdef ZEND_GENERATOR_RETURN
|
||||
CASE(ZEND_GENERATOR_RETURN);
|
||||
#endif
|
||||
#ifdef ZEND_FAST_CALL
|
||||
CASE(ZEND_FAST_CALL);
|
||||
#endif
|
||||
#ifdef ZEND_FAST_RET
|
||||
CASE(ZEND_FAST_RET);
|
||||
#endif
|
||||
#ifdef ZEND_RECV_VARIADIC
|
||||
CASE(ZEND_RECV_VARIADIC);
|
||||
#endif
|
||||
CASE(ZEND_OP_DATA);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
} /* }}} */
|
31
sapi/phpdbg/phpdbg_opcode.h
Normal file
31
sapi/phpdbg/phpdbg_opcode.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_OPCODE_H
|
||||
#define PHPDBG_OPCODE_H
|
||||
|
||||
#include "zend_types.h"
|
||||
|
||||
const char *phpdbg_decode_opcode(zend_uchar);
|
||||
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC);
|
||||
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC);
|
||||
void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC);
|
||||
|
||||
#endif /* PHPDBG_OPCODE_H */
|
258
sapi/phpdbg/phpdbg_print.c
Normal file
258
sapi/phpdbg/phpdbg_print.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_print.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_opcode.h"
|
||||
#include "phpdbg_prompt.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_PRINT(opline) /* {{{ */
|
||||
{
|
||||
if (EG(in_execution) && EG(current_execute_data)) {
|
||||
phpdbg_print_opline(EG(current_execute_data), 1 TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Not Executing!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
switch (method->type) {
|
||||
case ZEND_USER_FUNCTION: {
|
||||
zend_op_array* op_array = &(method->op_array);
|
||||
HashTable vars;
|
||||
|
||||
if (op_array) {
|
||||
zend_op *opline = &(op_array->opcodes[0]);
|
||||
zend_uint opcode = 0,
|
||||
end = op_array->last-1;
|
||||
|
||||
if (method->common.scope) {
|
||||
phpdbg_writeln("\tL%d-%d %s::%s() %s",
|
||||
op_array->line_start, op_array->line_end,
|
||||
method->common.scope->name,
|
||||
method->common.function_name,
|
||||
op_array->filename ? op_array->filename : "unknown");
|
||||
} else {
|
||||
phpdbg_writeln("\tL%d-%d %s() %s",
|
||||
method->common.function_name ? op_array->line_start : 0,
|
||||
method->common.function_name ? op_array->line_end : 0,
|
||||
method->common.function_name ? method->common.function_name : "{main}",
|
||||
op_array->filename ? op_array->filename : "unknown");
|
||||
}
|
||||
|
||||
zend_hash_init(&vars, op_array->last, NULL, NULL, 0);
|
||||
do {
|
||||
char *decode = phpdbg_decode_opline(op_array, opline, &vars TSRMLS_CC);
|
||||
if (decode != NULL) {
|
||||
phpdbg_writeln("\t\tL%u\t%p %-30s %s",
|
||||
opline->lineno,
|
||||
opline,
|
||||
phpdbg_decode_opcode(opline->opcode),
|
||||
decode);
|
||||
free(decode);
|
||||
} else {
|
||||
phpdbg_error("\tFailed to decode opline %16p", opline);
|
||||
}
|
||||
opline++;
|
||||
} while (++opcode < end);
|
||||
zend_hash_destroy(&vars);
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
if (method->common.scope) {
|
||||
phpdbg_writeln("\tInternal %s::%s()", method->common.scope->name, method->common.function_name);
|
||||
} else {
|
||||
phpdbg_writeln("\tInternal %s()", method->common.function_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_PRINT(exec) /* {{{ */
|
||||
{
|
||||
if (PHPDBG_G(exec)) {
|
||||
if (!PHPDBG_G(ops)) {
|
||||
phpdbg_compile(TSRMLS_C);
|
||||
}
|
||||
|
||||
if (PHPDBG_G(ops)) {
|
||||
phpdbg_notice("Context %s", PHPDBG_G(exec));
|
||||
|
||||
phpdbg_print_function_helper((zend_function*) PHPDBG_G(ops) TSRMLS_CC);
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("No execution context set");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_PRINT(stack) /* {{{ */
|
||||
{
|
||||
zend_op_array *ops = EG(active_op_array);
|
||||
|
||||
if (EG(in_execution) && ops) {
|
||||
if (ops->function_name) {
|
||||
if (ops->scope) {
|
||||
phpdbg_notice("Stack in %s::%s()", ops->scope->name, ops->function_name);
|
||||
} else {
|
||||
phpdbg_notice("Stack in %s()", ops->function_name);
|
||||
}
|
||||
} else {
|
||||
if (ops->filename) {
|
||||
phpdbg_notice("Stack in %s", ops->filename);
|
||||
} else {
|
||||
phpdbg_notice("Stack @ %p", ops);
|
||||
}
|
||||
}
|
||||
phpdbg_print_function_helper((zend_function*) ops TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Not Executing!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_PRINT(class) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
|
||||
switch (param->type) {
|
||||
case STR_PARAM: {
|
||||
if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
phpdbg_notice("%s %s: %s",
|
||||
((*ce)->type == ZEND_USER_CLASS) ?
|
||||
"User" : "Internal",
|
||||
((*ce)->ce_flags & ZEND_ACC_INTERFACE) ?
|
||||
"Interface" :
|
||||
((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ?
|
||||
"Abstract Class" :
|
||||
"Class",
|
||||
(*ce)->name);
|
||||
|
||||
phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table));
|
||||
if (zend_hash_num_elements(&(*ce)->function_table)) {
|
||||
HashPosition position;
|
||||
zend_function *method;
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(&(*ce)->function_table, &position);
|
||||
zend_hash_get_current_data_ex(&(*ce)->function_table, (void**) &method, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&(*ce)->function_table, &position)) {
|
||||
phpdbg_print_function_helper(method TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("The class %s could not be found", param->str);
|
||||
}
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_PRINT(method) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case METHOD_PARAM: {
|
||||
zend_class_entry **ce;
|
||||
|
||||
if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
zend_function *fbc;
|
||||
char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
|
||||
|
||||
if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_notice("%s Method %s",
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
|
||||
fbc->common.function_name);
|
||||
|
||||
phpdbg_print_function_helper(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("The method %s could not be found", param->method.name);
|
||||
}
|
||||
|
||||
efree(lcname);
|
||||
} else {
|
||||
phpdbg_error("The class %s could not be found", param->method.class);
|
||||
}
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_PRINT(func) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM: {
|
||||
HashTable *func_table = EG(function_table);
|
||||
zend_function* fbc;
|
||||
const char *func_name = param->str;
|
||||
size_t func_name_len = param->len;
|
||||
char *lcname;
|
||||
/* search active scope if begins with period */
|
||||
if (func_name[0] == '.') {
|
||||
if (EG(scope)) {
|
||||
func_name++;
|
||||
func_name_len--;
|
||||
|
||||
func_table = &EG(scope)->function_table;
|
||||
} else {
|
||||
phpdbg_error("No active class");
|
||||
return SUCCESS;
|
||||
}
|
||||
} else if (!EG(function_table)) {
|
||||
phpdbg_error("No function table loaded");
|
||||
return SUCCESS;
|
||||
} else {
|
||||
func_table = EG(function_table);
|
||||
}
|
||||
|
||||
lcname = zend_str_tolower_dup(func_name, func_name_len);
|
||||
|
||||
if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_notice("%s %s %s",
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
|
||||
(fbc->common.scope) ? "Method" : "Function",
|
||||
fbc->common.function_name);
|
||||
|
||||
phpdbg_print_function_helper(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("The function %s could not be found", func_name);
|
||||
}
|
||||
|
||||
efree(lcname);
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
51
sapi/phpdbg/phpdbg_print.h
Normal file
51
sapi/phpdbg/phpdbg_print.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_PRINT_H
|
||||
#define PHPDBG_PRINT_H
|
||||
|
||||
#include "phpdbg_cmd.h"
|
||||
|
||||
#define PHPDBG_PRINT(name) PHPDBG_COMMAND(print_##name)
|
||||
|
||||
/**
|
||||
* Printer Forward Declarations
|
||||
*/
|
||||
PHPDBG_PRINT(exec);
|
||||
PHPDBG_PRINT(opline);
|
||||
PHPDBG_PRINT(class);
|
||||
PHPDBG_PRINT(method);
|
||||
PHPDBG_PRINT(func);
|
||||
PHPDBG_PRINT(stack);
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
static const phpdbg_command_t phpdbg_print_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(class, "print out the instructions in the specified class", 'c', print_class, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(method, "print out the instructions in the specified method", 'm', print_method, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(func, "print out the instructions in the specified function", 'f', print_func, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
#endif /* PHPDBG_PRINT_H */
|
1328
sapi/phpdbg/phpdbg_prompt.c
Normal file
1328
sapi/phpdbg/phpdbg_prompt.c
Normal file
File diff suppressed because it is too large
Load Diff
68
sapi/phpdbg/phpdbg_prompt.h
Normal file
68
sapi/phpdbg/phpdbg_prompt.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_PROMPT_H
|
||||
#define PHPDBG_PROMPT_H
|
||||
|
||||
/* {{{ */
|
||||
void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC);
|
||||
void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC);
|
||||
int phpdbg_interactive(TSRMLS_D);
|
||||
int phpdbg_compile(TSRMLS_D);
|
||||
void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */
|
||||
|
||||
/* {{{ phpdbg command handlers */
|
||||
PHPDBG_COMMAND(exec);
|
||||
PHPDBG_COMMAND(compile);
|
||||
PHPDBG_COMMAND(step);
|
||||
PHPDBG_COMMAND(next);
|
||||
PHPDBG_COMMAND(run);
|
||||
PHPDBG_COMMAND(eval);
|
||||
PHPDBG_COMMAND(until);
|
||||
PHPDBG_COMMAND(finish);
|
||||
PHPDBG_COMMAND(leave);
|
||||
PHPDBG_COMMAND(frame);
|
||||
PHPDBG_COMMAND(print);
|
||||
PHPDBG_COMMAND(break);
|
||||
PHPDBG_COMMAND(back);
|
||||
PHPDBG_COMMAND(list);
|
||||
PHPDBG_COMMAND(info);
|
||||
PHPDBG_COMMAND(clean);
|
||||
PHPDBG_COMMAND(clear);
|
||||
PHPDBG_COMMAND(help);
|
||||
PHPDBG_COMMAND(quiet);
|
||||
PHPDBG_COMMAND(aliases);
|
||||
PHPDBG_COMMAND(shell);
|
||||
PHPDBG_COMMAND(set);
|
||||
PHPDBG_COMMAND(source);
|
||||
PHPDBG_COMMAND(register);
|
||||
PHPDBG_COMMAND(quit); /* }}} */
|
||||
|
||||
/* {{{ prompt commands */
|
||||
extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */
|
||||
|
||||
/* {{{ */
|
||||
#if PHP_VERSION_ID >= 50500
|
||||
void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC);
|
||||
#else
|
||||
void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC);
|
||||
#endif /* }}} */
|
||||
|
||||
#endif /* PHPDBG_PROMPT_H */
|
208
sapi/phpdbg/phpdbg_set.c
Normal file
208
sapi/phpdbg/phpdbg_set.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_set.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_bp.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_SET(prompt) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case EMPTY_PARAM:
|
||||
phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C));
|
||||
break;
|
||||
|
||||
case STR_PARAM:
|
||||
phpdbg_set_prompt(param->str TSRMLS_CC);
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_SET(break) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case EMPTY_PARAM:
|
||||
phpdbg_writeln("%s",
|
||||
PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off");
|
||||
break;
|
||||
|
||||
case STR_PARAM:
|
||||
if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) {
|
||||
phpdbg_enable_breakpoints(TSRMLS_C);
|
||||
} else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) {
|
||||
phpdbg_disable_breakpoints(TSRMLS_C);
|
||||
}
|
||||
break;
|
||||
|
||||
case NUMERIC_PARAM: {
|
||||
if (input->argc > 2) {
|
||||
if (phpdbg_argv_is(2, "on")) {
|
||||
phpdbg_enable_breakpoint(param->num TSRMLS_CC);
|
||||
} else if (phpdbg_argv_is(2, "off")) {
|
||||
phpdbg_disable_breakpoint(param->num TSRMLS_CC);
|
||||
}
|
||||
} else {
|
||||
phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC);
|
||||
if (brake) {
|
||||
phpdbg_writeln(
|
||||
"%s", brake->disabled ? "off" : "on");
|
||||
} else {
|
||||
phpdbg_error("Failed to find breakpoint #%lx", param->num);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
phpdbg_error(
|
||||
"set break used incorrectly: set break [id] <on|off>");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
#ifndef _WIN32
|
||||
PHPDBG_SET(color) /* {{{ */
|
||||
{
|
||||
if ((param->type == STR_PARAM) && (input->argc == 3)) {
|
||||
const phpdbg_color_t *color = phpdbg_get_color(
|
||||
input->argv[2]->string, input->argv[2]->length TSRMLS_CC);
|
||||
int element = PHPDBG_COLOR_INVALID;
|
||||
|
||||
/* @TODO(anyone) make this consistent with other set commands */
|
||||
if (color) {
|
||||
if (phpdbg_argv_is(1, "prompt")) {
|
||||
phpdbg_notice(
|
||||
"setting prompt color to %s (%s)", color->name, color->code);
|
||||
element = PHPDBG_COLOR_PROMPT;
|
||||
if (PHPDBG_G(prompt)[1]) {
|
||||
free(PHPDBG_G(prompt)[1]);
|
||||
PHPDBG_G(prompt)[1]=NULL;
|
||||
}
|
||||
} else if (phpdbg_argv_is(1, "error")) {
|
||||
phpdbg_notice(
|
||||
"setting error color to %s (%s)", color->name, color->code);
|
||||
element = PHPDBG_COLOR_ERROR;
|
||||
|
||||
} else if (phpdbg_argv_is(1, "notice")) {
|
||||
phpdbg_notice(
|
||||
"setting notice color to %s (%s)", color->name, color->code);
|
||||
element = PHPDBG_COLOR_NOTICE;
|
||||
|
||||
} else goto usage;
|
||||
|
||||
/* set color for element */
|
||||
phpdbg_set_color(element, color TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error(
|
||||
"Failed to find the requested color (%s)", input->argv[2]->string);
|
||||
}
|
||||
} else {
|
||||
usage:
|
||||
phpdbg_error(
|
||||
"set color used incorrectly: set color <prompt|error|notice> <color>");
|
||||
}
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_SET(colors) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case EMPTY_PARAM: {
|
||||
phpdbg_writeln(
|
||||
"%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off");
|
||||
goto done;
|
||||
}
|
||||
|
||||
case STR_PARAM: {
|
||||
if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) {
|
||||
PHPDBG_G(flags) |= PHPDBG_IS_COLOURED;
|
||||
goto done;
|
||||
} else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) {
|
||||
PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
phpdbg_error(
|
||||
"set colors used incorrectly: set colors <on|off>");
|
||||
}
|
||||
|
||||
done:
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
#endif
|
||||
|
||||
PHPDBG_SET(oplog) /* {{{ */
|
||||
{
|
||||
switch (param->type) {
|
||||
case EMPTY_PARAM:
|
||||
phpdbg_notice(
|
||||
"Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled");
|
||||
break;
|
||||
|
||||
case NUMERIC_PARAM: switch (param->num) {
|
||||
case 1:
|
||||
phpdbg_error(
|
||||
"An output file must be provided to enable oplog");
|
||||
break;
|
||||
|
||||
case 0: {
|
||||
if (PHPDBG_G(oplog)) {
|
||||
phpdbg_notice("Disabling oplog");
|
||||
fclose(
|
||||
PHPDBG_G(oplog));
|
||||
} else {
|
||||
phpdbg_error("Oplog is not enabled!");
|
||||
}
|
||||
} break;
|
||||
} break;
|
||||
|
||||
case STR_PARAM: {
|
||||
/* open oplog */
|
||||
FILE *old = PHPDBG_G(oplog);
|
||||
|
||||
PHPDBG_G(oplog) = fopen(param->str, "w+");
|
||||
if (!PHPDBG_G(oplog)) {
|
||||
phpdbg_error("Failed to open %s for oplog", param->str);
|
||||
PHPDBG_G(oplog) = old;
|
||||
} else {
|
||||
if (old) {
|
||||
phpdbg_notice("Closing previously open oplog");
|
||||
fclose(old);
|
||||
}
|
||||
phpdbg_notice("Successfully opened oplog %s", param->str);
|
||||
}
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
47
sapi/phpdbg/phpdbg_set.h
Normal file
47
sapi/phpdbg/phpdbg_set.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_SET_H
|
||||
#define PHPDBG_SET_H
|
||||
|
||||
#include "phpdbg_cmd.h"
|
||||
|
||||
#define PHPDBG_SET(name) PHPDBG_COMMAND(set_##name)
|
||||
|
||||
PHPDBG_SET(prompt);
|
||||
#ifndef _WIN32
|
||||
PHPDBG_SET(color);
|
||||
PHPDBG_SET(colors);
|
||||
#endif
|
||||
PHPDBG_SET(oplog);
|
||||
PHPDBG_SET(break);
|
||||
|
||||
static const phpdbg_command_t phpdbg_set_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(prompt, "usage: set prompt <string>", 'p', set_prompt, NULL, 0),
|
||||
#ifndef _WIN32
|
||||
PHPDBG_COMMAND_D_EX(color, "usage: set color <element> <color>", 'c', set_color, NULL, 1),
|
||||
PHPDBG_COMMAND_D_EX(colors, "usage: set colors <on|off>", 'C', set_colors, NULL, 1),
|
||||
#endif
|
||||
PHPDBG_COMMAND_D_EX(oplog, "usage: set oplog <output>", 'O', set_oplog, NULL, 0),
|
||||
PHPDBG_COMMAND_D_EX(break, "usage: set break [id] <on|off>", 'b', set_break, NULL, 0),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
#endif /* PHPDBG_SET_H */
|
386
sapi/phpdbg/phpdbg_utils.c
Normal file
386
sapi/phpdbg/phpdbg_utils.c
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "zend.h"
|
||||
#include "php.h"
|
||||
#include "spprintf.h"
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_opcode.h"
|
||||
#include "phpdbg_utils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "win32/time.h"
|
||||
#endif
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
/* {{{ color structures */
|
||||
const static phpdbg_color_t colors[] = {
|
||||
PHPDBG_COLOR_D("none", "0;0"),
|
||||
|
||||
PHPDBG_COLOR_D("white", "0;64"),
|
||||
PHPDBG_COLOR_D("white-bold", "1;64"),
|
||||
PHPDBG_COLOR_D("white-underline", "4;64"),
|
||||
PHPDBG_COLOR_D("red", "0;31"),
|
||||
PHPDBG_COLOR_D("red-bold", "1;31"),
|
||||
PHPDBG_COLOR_D("red-underline", "4;31"),
|
||||
PHPDBG_COLOR_D("green", "0;32"),
|
||||
PHPDBG_COLOR_D("green-bold", "1;32"),
|
||||
PHPDBG_COLOR_D("green-underline", "4;32"),
|
||||
PHPDBG_COLOR_D("yellow", "0;33"),
|
||||
PHPDBG_COLOR_D("yellow-bold", "1;33"),
|
||||
PHPDBG_COLOR_D("yellow-underline", "4;33"),
|
||||
PHPDBG_COLOR_D("blue", "0;34"),
|
||||
PHPDBG_COLOR_D("blue-bold", "1;34"),
|
||||
PHPDBG_COLOR_D("blue-underline", "4;34"),
|
||||
PHPDBG_COLOR_D("purple", "0;35"),
|
||||
PHPDBG_COLOR_D("purple-bold", "1;35"),
|
||||
PHPDBG_COLOR_D("purple-underline", "4;35"),
|
||||
PHPDBG_COLOR_D("cyan", "0;36"),
|
||||
PHPDBG_COLOR_D("cyan-bold", "1;36"),
|
||||
PHPDBG_COLOR_D("cyan-underline", "4;36"),
|
||||
PHPDBG_COLOR_D("black", "0;30"),
|
||||
PHPDBG_COLOR_D("black-bold", "1;30"),
|
||||
PHPDBG_COLOR_D("black-underline", "4;30"),
|
||||
PHPDBG_COLOR_END
|
||||
}; /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_is_numeric(const char *str) /* {{{ */
|
||||
{
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
for (; *str; str++) {
|
||||
if (isspace(*str) || *str == '-') {
|
||||
continue;
|
||||
}
|
||||
return isdigit(*str);
|
||||
}
|
||||
return 0;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_is_empty(const char *str) /* {{{ */
|
||||
{
|
||||
if (!str)
|
||||
return 1;
|
||||
|
||||
for (; *str; str++) {
|
||||
if (isspace(*str)) {
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_is_addr(const char *str) /* {{{ */
|
||||
{
|
||||
return str[0] && str[1] && memcmp(str, "0x", 2) == 0;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class, char **method) /* {{{ */
|
||||
{
|
||||
char *sep = NULL;
|
||||
|
||||
if (strstr(str, "#") != NULL)
|
||||
return 0;
|
||||
|
||||
if (strstr(str, " ") != NULL)
|
||||
return 0;
|
||||
|
||||
sep = strstr(str, "::");
|
||||
|
||||
if (!sep || sep == str || sep+2 == str+len-1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (class != NULL) {
|
||||
|
||||
if (str[0] == '\\') {
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
|
||||
*class = estrndup(str, sep - str);
|
||||
(*class)[sep - str] = 0;
|
||||
}
|
||||
|
||||
if (method != NULL) {
|
||||
*method = estrndup(sep+2, str + len - (sep + 2));
|
||||
}
|
||||
|
||||
return 1;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API char *phpdbg_resolve_path(const char *path TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
char resolved_name[MAXPATHLEN];
|
||||
|
||||
if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return estrdup(resolved_name);
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API const char *phpdbg_current_file(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
const char *file = zend_get_executed_filename(TSRMLS_C);
|
||||
|
||||
if (memcmp(file, "[no active file]", sizeof("[no active file]")) == 0) {
|
||||
return PHPDBG_G(exec);
|
||||
}
|
||||
|
||||
return file;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API const zend_function *phpdbg_get_function(const char *fname, const char *cname TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_function *func = NULL;
|
||||
size_t fname_len = strlen(fname);
|
||||
char *lcname = zend_str_tolower_dup(fname, fname_len);
|
||||
|
||||
if (cname) {
|
||||
zend_class_entry **ce;
|
||||
size_t cname_len = strlen(cname);
|
||||
char *lc_cname = zend_str_tolower_dup(cname, cname_len);
|
||||
int ret = zend_lookup_class(lc_cname, cname_len, &ce TSRMLS_CC);
|
||||
|
||||
efree(lc_cname);
|
||||
|
||||
if (ret == SUCCESS) {
|
||||
zend_hash_find(&(*ce)->function_table, lcname, fname_len+1,
|
||||
(void**)&func);
|
||||
}
|
||||
} else {
|
||||
zend_hash_find(EG(function_table), lcname, fname_len+1,
|
||||
(void**)&func);
|
||||
}
|
||||
|
||||
efree(lcname);
|
||||
return func;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{{ */
|
||||
{
|
||||
const char *p = str;
|
||||
char *new = NULL;
|
||||
|
||||
while (p && isspace(*p)) {
|
||||
++p;
|
||||
--len;
|
||||
}
|
||||
|
||||
while (*p && isspace(*(p + len -1))) {
|
||||
--len;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
new = estrndup("", sizeof(""));
|
||||
*new_len = 0;
|
||||
} else {
|
||||
new = estrndup(p, len);
|
||||
*(new + len) = '\0';
|
||||
|
||||
if (new_len) {
|
||||
*new_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
return new;
|
||||
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */
|
||||
{
|
||||
int rc = 0;
|
||||
char *buffer = NULL;
|
||||
va_list args;
|
||||
|
||||
if (format != NULL && strlen(format) > 0L) {
|
||||
va_start(args, format);
|
||||
vspprintf(&buffer, 0, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* TODO(anyone) colours */
|
||||
|
||||
switch (type) {
|
||||
case P_ERROR:
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
rc = fprintf(fp,
|
||||
"\033[%sm[%s]\033[0m\n",
|
||||
PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer);
|
||||
} else {
|
||||
rc = fprintf(fp, "[%s]\n", buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case P_NOTICE:
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
rc = fprintf(fp,
|
||||
"\033[%sm[%s]\033[0m\n",
|
||||
PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer);
|
||||
} else {
|
||||
rc = fprintf(fp, "[%s]\n", buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case P_WRITELN: {
|
||||
if (buffer) {
|
||||
rc = fprintf(fp, "%s\n", buffer);
|
||||
} else {
|
||||
rc = fprintf(fp, "\n");
|
||||
}
|
||||
} break;
|
||||
|
||||
case P_WRITE:
|
||||
if (buffer) {
|
||||
rc = fprintf(fp, "%s", buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
/* no formatting on logging output */
|
||||
case P_LOG:
|
||||
if (buffer) {
|
||||
struct timeval tp;
|
||||
if (gettimeofday(&tp, NULL) == SUCCESS) {
|
||||
rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer);
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
efree(buffer);
|
||||
}
|
||||
|
||||
return rc;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
|
||||
int rc = 0;
|
||||
|
||||
va_list args;
|
||||
struct timeval tp;
|
||||
|
||||
va_start(args, fmt);
|
||||
if (gettimeofday(&tp, NULL) == SUCCESS) {
|
||||
char friendly[100];
|
||||
char *format = NULL, *buffer = NULL;
|
||||
|
||||
strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tp.tv_sec));
|
||||
asprintf(
|
||||
&buffer, friendly, tp.tv_usec/1000);
|
||||
asprintf(
|
||||
&format, "[%s]: %s\n", buffer, fmt);
|
||||
rc = vfprintf(
|
||||
fp, format, args);
|
||||
|
||||
free(format);
|
||||
free(buffer);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return rc;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
const phpdbg_color_t *color = colors;
|
||||
|
||||
while (color && color->name) {
|
||||
if (name_length == color->name_length &&
|
||||
memcmp(name, color->name, name_length) == SUCCESS) {
|
||||
phpdbg_debug(
|
||||
"phpdbg_get_color(%s, %lu): %s", name, name_length, color->code);
|
||||
return color;
|
||||
}
|
||||
++color;
|
||||
}
|
||||
|
||||
phpdbg_debug(
|
||||
"phpdbg_get_color(%s, %lu): failed", name, name_length);
|
||||
|
||||
return NULL;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
PHPDBG_G(colors)[element] = color;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
const phpdbg_color_t *color = phpdbg_get_color(name, name_length TSRMLS_CC);
|
||||
|
||||
if (color) {
|
||||
phpdbg_set_color(element, color TSRMLS_CC);
|
||||
} else PHPDBG_G(colors)[element] = colors;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
return colors;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_set_prompt(const char *prompt TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
/* free formatted prompt */
|
||||
if (PHPDBG_G(prompt)[1]) {
|
||||
free(PHPDBG_G(prompt)[1]);
|
||||
PHPDBG_G(prompt)[1] = NULL;
|
||||
}
|
||||
/* free old prompt */
|
||||
if (PHPDBG_G(prompt)[0]) {
|
||||
free(PHPDBG_G(prompt)[0]);
|
||||
PHPDBG_G(prompt)[0] = NULL;
|
||||
}
|
||||
|
||||
/* copy new prompt */
|
||||
PHPDBG_G(prompt)[0] = strdup(prompt);
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
/* find cached prompt */
|
||||
if (PHPDBG_G(prompt)[1]) {
|
||||
return PHPDBG_G(prompt)[1];
|
||||
}
|
||||
|
||||
/* create cached prompt */
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED)) {
|
||||
asprintf(
|
||||
&PHPDBG_G(prompt)[1], "\033[%sm%s\033[0m ",
|
||||
PHPDBG_G(colors)[PHPDBG_COLOR_PROMPT]->code,
|
||||
PHPDBG_G(prompt)[0]);
|
||||
} else {
|
||||
asprintf(
|
||||
&PHPDBG_G(prompt)[1], "%s ",
|
||||
PHPDBG_G(prompt)[0]);
|
||||
}
|
||||
|
||||
return PHPDBG_G(prompt)[1];
|
||||
} /* }}} */
|
110
sapi/phpdbg/phpdbg_utils.h
Normal file
110
sapi/phpdbg/phpdbg_utils.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2013 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_UTILS_H
|
||||
#define PHPDBG_UTILS_H
|
||||
|
||||
/**
|
||||
* Input scan functions
|
||||
*/
|
||||
PHPDBG_API int phpdbg_is_numeric(const char*);
|
||||
PHPDBG_API int phpdbg_is_empty(const char*);
|
||||
PHPDBG_API int phpdbg_is_addr(const char*);
|
||||
PHPDBG_API int phpdbg_is_class_method(const char*, size_t, char**, char**);
|
||||
PHPDBG_API const char *phpdbg_current_file(TSRMLS_D);
|
||||
PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC);
|
||||
PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*);
|
||||
PHPDBG_API const zend_function *phpdbg_get_function(const char*, const char* TSRMLS_DC);
|
||||
|
||||
/**
|
||||
* Error/notice/formatting helpers
|
||||
*/
|
||||
enum {
|
||||
P_ERROR = 1,
|
||||
P_NOTICE,
|
||||
P_WRITELN,
|
||||
P_WRITE,
|
||||
P_LOG
|
||||
};
|
||||
|
||||
#ifdef ZTS
|
||||
PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5);
|
||||
#else
|
||||
PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
|
||||
#endif
|
||||
|
||||
PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...);
|
||||
|
||||
#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
|
||||
#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_writeln_ex(out, fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_write_ex(out, fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
|
||||
#if PHPDBG_DEBUG
|
||||
# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define phpdbg_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* {{{ For writing blank lines */
|
||||
#define EMPTY NULL /* }}} */
|
||||
|
||||
/* {{{ For prompt lines */
|
||||
#define PROMPT "phpdbg>" /* }}} */
|
||||
|
||||
/* {{{ For separation */
|
||||
#define SEPARATE "------------------------------------------------" /* }}} */
|
||||
|
||||
/* {{{ Color Management */
|
||||
#define PHPDBG_COLOR_LEN 12
|
||||
#define PHPDBG_COLOR_D(color, code) \
|
||||
{color, sizeof(color)-1, code}
|
||||
#define PHPDBG_COLOR_END \
|
||||
{NULL, 0L, {0}}
|
||||
|
||||
#define PHPDBG_COLOR_INVALID -1
|
||||
#define PHPDBG_COLOR_PROMPT 0
|
||||
#define PHPDBG_COLOR_ERROR 1
|
||||
#define PHPDBG_COLOR_NOTICE 2
|
||||
#define PHPDBG_COLORS 3
|
||||
|
||||
typedef struct _phpdbg_color_t {
|
||||
char *name;
|
||||
size_t name_length;
|
||||
const char code[PHPDBG_COLOR_LEN];
|
||||
} phpdbg_color_t;
|
||||
|
||||
PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC);
|
||||
PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D); /* }}} */
|
||||
|
||||
/* {{{ Prompt Management */
|
||||
PHPDBG_API void phpdbg_set_prompt(const char* TSRMLS_DC);
|
||||
PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */
|
||||
|
||||
#endif /* PHPDBG_UTILS_H */
|
51
sapi/phpdbg/test.php
Normal file
51
sapi/phpdbg/test.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
if (isset($include)) {
|
||||
include (sprintf("%s/web-bootstrap.php", dirname(__FILE__)));
|
||||
}
|
||||
|
||||
$stdout = fopen("php://stdout", "w+");
|
||||
|
||||
class phpdbg {
|
||||
public function isGreat($greeting = null) {
|
||||
printf(
|
||||
"%s: %s\n", __METHOD__, $greeting);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
function test($x, $y = 0) {
|
||||
$var = $x + 1;
|
||||
$var += 2;
|
||||
$var <<= 3;
|
||||
|
||||
$foo = function () {
|
||||
echo "bar!\n";
|
||||
};
|
||||
|
||||
$foo();
|
||||
|
||||
yield $var;
|
||||
}
|
||||
|
||||
$dbg = new phpdbg();
|
||||
|
||||
var_dump(
|
||||
$dbg->isGreat("PHP Rocks!!"));
|
||||
|
||||
foreach (test(1,2) as $gen)
|
||||
continue;
|
||||
|
||||
echo "it works!\n";
|
||||
|
||||
if (isset($dump))
|
||||
var_dump($_SERVER);
|
||||
|
||||
function phpdbg_test_ob()
|
||||
{
|
||||
echo 'Start';
|
||||
ob_start();
|
||||
echo 'Hello';
|
||||
$b = ob_get_clean();
|
||||
echo 'End';
|
||||
echo $b;
|
||||
}
|
8
sapi/phpdbg/tests/commands/0001_basic.test
Normal file
8
sapi/phpdbg/tests/commands/0001_basic.test
Normal file
@ -0,0 +1,8 @@
|
||||
#######################################################
|
||||
# name: basic
|
||||
# purpose: check basic functionality of phpdbg console
|
||||
# expect: TEST::EXACT
|
||||
# options: -rr
|
||||
#######################################################
|
||||
# [Nothing to execute!]
|
||||
#######################################################
|
23
sapi/phpdbg/tests/commands/0002_set.test
Normal file
23
sapi/phpdbg/tests/commands/0002_set.test
Normal file
@ -0,0 +1,23 @@
|
||||
#################################################
|
||||
# name: set
|
||||
# purpose: tests for set commands
|
||||
# expect: TEST::CISTRING
|
||||
# options: -rr
|
||||
#################################################
|
||||
# setting prompt color
|
||||
# setting error color
|
||||
# setting notice color
|
||||
# Failed to find breakpoint #0
|
||||
# oplog disabled
|
||||
# not enabled
|
||||
# opened oplog test.log
|
||||
# nothing
|
||||
#################################################
|
||||
set color prompt none
|
||||
set color error none
|
||||
set color notice none
|
||||
set prompt promot>
|
||||
set break 0
|
||||
set oplog
|
||||
set oplog 0
|
||||
set oplog test.log
|
19
sapi/phpdbg/tests/commands/0101_info.test
Normal file
19
sapi/phpdbg/tests/commands/0101_info.test
Normal file
@ -0,0 +1,19 @@
|
||||
#################################################
|
||||
# name: info
|
||||
# purpose: test info commands
|
||||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[User Classes (%d)]
|
||||
#User Class test (3)
|
||||
#|---- in phpdbginit code on line %d
|
||||
#################################################
|
||||
<:
|
||||
class test {
|
||||
public function testMethod(){}
|
||||
private function testPrivateMethod(){}
|
||||
protected function testProtectedMethod(){}
|
||||
}
|
||||
:>
|
||||
info classes
|
||||
q
|
28
sapi/phpdbg/tests/commands/0102_print.test
Normal file
28
sapi/phpdbg/tests/commands/0102_print.test
Normal file
@ -0,0 +1,28 @@
|
||||
#################################################
|
||||
# name: print
|
||||
# purpose: test print commands
|
||||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[User Class: test]
|
||||
#Methods (3):
|
||||
#L%d-%d test::testMethod() %s
|
||||
# L%d %s ZEND_RETURN C%d <unused> <unused>
|
||||
# L%d-%d test::testPrivateMethod() %s
|
||||
# L%d %s ZEND_RETURN C%d <unused> <unused>
|
||||
# L%d-%d test::testProtectedMethod() %s
|
||||
# L%d %s ZEND_RETURN C%d <unused> <unused>
|
||||
#[User Method testMethod]
|
||||
# L%d-%d test::testMethod() %s
|
||||
# L%d %s ZEND_RETURN C%d <unused> <unused>
|
||||
#################################################
|
||||
<:
|
||||
class test {
|
||||
public function testMethod(){}
|
||||
private function testPrivateMethod(){}
|
||||
protected function testProtectedMethod(){}
|
||||
}
|
||||
:>
|
||||
print class test
|
||||
print method test::testMethod
|
||||
q
|
28
sapi/phpdbg/tests/commands/0103_register.test
Normal file
28
sapi/phpdbg/tests/commands/0103_register.test
Normal file
@ -0,0 +1,28 @@
|
||||
#################################################
|
||||
# name: register
|
||||
# purpose: test registration functions
|
||||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[Registered test_function]
|
||||
#array(5) {
|
||||
# [0]=>
|
||||
# string(1) "1"
|
||||
# [1]=>
|
||||
# string(1) "2"
|
||||
# [2]=>
|
||||
# string(1) "3"
|
||||
# [3]=>
|
||||
# string(1) "4"
|
||||
# [4]=>
|
||||
# string(1) "5"
|
||||
#}
|
||||
#################################################
|
||||
<:
|
||||
function test_function() {
|
||||
var_dump(func_get_args());
|
||||
}
|
||||
:>
|
||||
R test_function
|
||||
test_function 1 2 3 4 5
|
||||
q
|
15
sapi/phpdbg/tests/commands/0104_clean.test
Normal file
15
sapi/phpdbg/tests/commands/0104_clean.test
Normal file
@ -0,0 +1,15 @@
|
||||
#################################################
|
||||
# name: clean
|
||||
# purpose: test cleaning environment
|
||||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[Cleaning Execution Environment]
|
||||
#Classes %d
|
||||
#Functions %d
|
||||
#Constants %d
|
||||
#Includes %d
|
||||
#[Nothing to execute!]
|
||||
#################################################
|
||||
clean
|
||||
quit
|
18
sapi/phpdbg/tests/commands/0105_clear.test
Normal file
18
sapi/phpdbg/tests/commands/0105_clear.test
Normal file
@ -0,0 +1,18 @@
|
||||
#################################################
|
||||
# name: clear
|
||||
# purpose: test clearing breakpoints
|
||||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[Clearing Breakpoints]
|
||||
#File%w%d
|
||||
#Functions%w%d
|
||||
#Methods%w%d
|
||||
#Oplines%w%d
|
||||
#File oplines%w%d
|
||||
#Function oplines%w%d
|
||||
#Method oplines%w%d
|
||||
#Conditionals%w%d
|
||||
#################################################
|
||||
clear
|
||||
quit
|
19
sapi/phpdbg/tests/commands/0106_compile.test
Normal file
19
sapi/phpdbg/tests/commands/0106_compile.test
Normal file
@ -0,0 +1,19 @@
|
||||
#################################################
|
||||
# name: compile
|
||||
# purpose: test compiling code
|
||||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[Attempting compilation of %s]
|
||||
#[Success]
|
||||
#Hello World
|
||||
#################################################
|
||||
<:
|
||||
define('OUT',
|
||||
tempnam(null, "phpdbg"));
|
||||
file_put_contents(OUT, "<?php echo \"Hello World\"; ?>");
|
||||
phpdbg_exec(OUT);
|
||||
:>
|
||||
compile
|
||||
run
|
||||
quit
|
583
sapi/phpdbg/tests/run-tests.php
Normal file
583
sapi/phpdbg/tests/run-tests.php
Normal file
@ -0,0 +1,583 @@
|
||||
<?php
|
||||
namespace phpdbg\testing {
|
||||
|
||||
/*
|
||||
* Workaround ...
|
||||
*/
|
||||
if (!defined('DIR_SEP'))
|
||||
define('DIR_SEP', '\\' . DIRECTORY_SEPARATOR);
|
||||
|
||||
/**
|
||||
* TestConfigurationExceptions are thrown
|
||||
* when the configuration prohibits tests executing
|
||||
*
|
||||
* @package phpdbg
|
||||
* @subpackage testing
|
||||
*/
|
||||
class TestConfigurationException extends \Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array Tests confguration
|
||||
* @param message Exception message
|
||||
* @param ... formatting parameters
|
||||
*/
|
||||
public function __construct() {
|
||||
$argv = func_get_args();
|
||||
|
||||
if (count($argv)) {
|
||||
|
||||
$this->config = array_shift($argv);
|
||||
$this->message = vsprintf(
|
||||
array_shift($argv), $argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @package phpdbg
|
||||
* @subpackage testing
|
||||
*/
|
||||
class TestsConfiguration implements \ArrayAccess {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array basic configuration
|
||||
* @param array argv
|
||||
*/
|
||||
public function __construct($config, $cmd) {
|
||||
$this->options = $config;
|
||||
while (($key = array_shift($cmd))) {
|
||||
switch (substr($key, 0, 1)) {
|
||||
case '-': switch(substr($key, 1, 1)) {
|
||||
case '-': {
|
||||
$arg = substr($key, 2);
|
||||
if (($e=strpos($arg, '=')) !== false) {
|
||||
$key = substr($arg, 0, $e);
|
||||
$value = substr($arg, $e+1);
|
||||
} else {
|
||||
$key = $arg;
|
||||
$value = array_shift($cmd);
|
||||
}
|
||||
|
||||
if (isset($key) && isset($value)) {
|
||||
switch ($key) {
|
||||
case 'phpdbg':
|
||||
case 'width':
|
||||
$this->options[$key] = $value;
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (isset($config[$key])) {
|
||||
if (is_array($config[$key])) {
|
||||
$this->options[$key][] = $value;
|
||||
} else {
|
||||
$this->options[$key] = array($config[$key], $value);
|
||||
}
|
||||
} else {
|
||||
$this->options[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
$this->flags[] = substr($key, 1);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_executable($this->options['phpdbg'])) {
|
||||
throw new TestConfigurationException(
|
||||
$this->options, 'phpdbg could not be found at the specified path (%s)', $this->options['phpdbg']);
|
||||
} else $this->options['phpdbg'] = realpath($this->options['phpdbg']);
|
||||
|
||||
$this->options['width'] = (integer) $this->options['width'];
|
||||
|
||||
/* display properly, all the time */
|
||||
if ($this->options['width'] < 50) {
|
||||
$this->options['width'] = 50;
|
||||
}
|
||||
|
||||
/* calculate column widths */
|
||||
$this->options['lwidth'] = ceil($this->options['width'] / 3);
|
||||
$this->options['rwidth'] = ceil($this->options['width'] - $this->options['lwidth']) - 5;
|
||||
}
|
||||
|
||||
public function hasFlag($flag) {
|
||||
return in_array(
|
||||
$flag, $this->flags);
|
||||
}
|
||||
|
||||
public function offsetExists($offset) { return isset($this->options[$offset]); }
|
||||
public function offsetGet($offset) { return $this->options[$offset]; }
|
||||
public function offsetUnset($offset) { unset($this->options[$offset]); }
|
||||
public function offsetSet($offset, $data) { $this->options[$offset] = $data; }
|
||||
|
||||
protected $options = array();
|
||||
protected $flags = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests is the console programming API for the test suite
|
||||
*
|
||||
* @package phpdbg
|
||||
* @subpackage testing
|
||||
*/
|
||||
class Tests {
|
||||
|
||||
/**
|
||||
* Construct the console object
|
||||
*
|
||||
* @param array basic configuration
|
||||
* @param array command line
|
||||
*/
|
||||
public function __construct(TestsConfiguration &$config) {
|
||||
$this->config = &$config;
|
||||
|
||||
if ($this->config->hasFlag('help') ||
|
||||
$this->config->hasFlag('h')) {
|
||||
$this->showUsage();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find valid paths as specified by configuration
|
||||
*
|
||||
*/
|
||||
public function findPaths($in = null) {
|
||||
$paths = array();
|
||||
$where = ($in != null) ? array($in) : $this->config['path'];
|
||||
|
||||
foreach ($where as &$path) {
|
||||
if ($path) {
|
||||
if (is_dir($path)) {
|
||||
$paths[] = $path;
|
||||
foreach (scandir($path) as $child) {
|
||||
if ($child != '.' && $child != '..') {
|
||||
$paths = array_merge(
|
||||
$paths, $this->findPaths("$path/$child"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string the path to log
|
||||
*/
|
||||
public function logPath($path) {
|
||||
printf(
|
||||
'%s [%s]%s',
|
||||
str_repeat(
|
||||
'-', $this->config['width'] - strlen($path)),
|
||||
$path, PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string the path to log
|
||||
*/
|
||||
public function logPathStats($path) {
|
||||
if (!isset($this->stats[$path])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$total = array_sum($this->stats[$path]);
|
||||
|
||||
if ($total) {
|
||||
@$this->totals[true] += $this->stats[$path][true];
|
||||
@$this->totals[false] += $this->stats[$path][false];
|
||||
|
||||
$stats = @sprintf(
|
||||
"%d/%d %%%d",
|
||||
$this->stats[$path][true],
|
||||
$this->stats[$path][false],
|
||||
(100 / $total) * $this->stats[$path][true]);
|
||||
|
||||
printf(
|
||||
'%s [%s]%s',
|
||||
str_repeat(
|
||||
' ', $this->config['width'] - strlen($stats)),
|
||||
$stats, PHP_EOL);
|
||||
|
||||
printf("%s%s", str_repeat('-', $this->config['width']+3), PHP_EOL);
|
||||
printf("%s", PHP_EOL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function logStats() {
|
||||
$total = array_sum($this->totals);
|
||||
$stats = @sprintf(
|
||||
"%d/%d %%%d",
|
||||
$this->totals[true],
|
||||
$this->totals[false],
|
||||
(100 / $total) * $this->totals[true]);
|
||||
printf(
|
||||
'%s [%s]%s',
|
||||
str_repeat(
|
||||
' ', $this->config['width'] - strlen($stats)),
|
||||
$stats, PHP_EOL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function showUsage() {
|
||||
printf('usage: php %s [flags] [options]%s', $this->config['exec'], PHP_EOL);
|
||||
printf('[options]:%s', PHP_EOL);
|
||||
printf("\t--path\t\tadd a path to scan outside of tests directory%s", PHP_EOL);
|
||||
printf("\t--width\t\tset line width%s", PHP_EOL);
|
||||
printf("\t--options\toptions to pass to phpdbg%s", PHP_EOL);
|
||||
printf("\t--phpdbg\tpath to phpdbg binary%s", PHP_EOL);
|
||||
printf('[flags]:%s', PHP_EOL);
|
||||
printf("\t-nodiff\t\tdo not write diffs on failure%s", PHP_EOL);
|
||||
printf("\t-nolog\t\tdo not write logs on failure%s", PHP_EOL);
|
||||
printf('[examples]:%s', PHP_EOL);
|
||||
printf("\tphp %s --phpdbg=/usr/local/bin/phpdbg --path=/usr/src/phpdbg/tests --options -n%s",
|
||||
$this->config['exec'], PHP_EOL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find valid tests at the specified path (assumed valid)
|
||||
*
|
||||
* @param string a valid path
|
||||
*/
|
||||
public function findTests($path) {
|
||||
$tests = array();
|
||||
|
||||
foreach (scandir($path) as $file) {
|
||||
if ($file == '.' || $file == '..')
|
||||
continue;
|
||||
|
||||
$test = sprintf('%s/%s', $path, $file);
|
||||
|
||||
if (preg_match('~\.test$~', $test)) {
|
||||
yield new Test($this->config, $test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Test the test to log
|
||||
*/
|
||||
public function logTest($path, Test $test) {
|
||||
@$this->stats[$path][($result=$test->getResult())]++;
|
||||
|
||||
printf(
|
||||
"%-{$this->config['lwidth']}s %-{$this->config['rwidth']}s [%s]%s",
|
||||
$test->name,
|
||||
$test->purpose,
|
||||
$result ? "PASS" : "FAIL",
|
||||
PHP_EOL);
|
||||
}
|
||||
|
||||
protected $config;
|
||||
}
|
||||
|
||||
class Test {
|
||||
/*
|
||||
* Expect exact line for line match
|
||||
*/
|
||||
const EXACT = 0x00000001;
|
||||
|
||||
/*
|
||||
* Expect strpos() !== false
|
||||
*/
|
||||
const STRING = 0x00000010;
|
||||
|
||||
/*
|
||||
* Expect stripos() !== false
|
||||
*/
|
||||
const CISTRING = 0x00000100;
|
||||
|
||||
/*
|
||||
* Formatted output
|
||||
*/
|
||||
const FORMAT = 0x00001000;
|
||||
|
||||
/**
|
||||
* Format specifiers
|
||||
*/
|
||||
private static $format = array(
|
||||
'search' => array(
|
||||
'%e',
|
||||
'%s',
|
||||
'%S',
|
||||
'%a',
|
||||
'%A',
|
||||
'%w',
|
||||
'%i',
|
||||
'%d',
|
||||
'%x',
|
||||
'%f',
|
||||
'%c',
|
||||
'%t',
|
||||
'%T'
|
||||
),
|
||||
'replace' => array(
|
||||
DIR_SEP,
|
||||
'[^\r\n]+',
|
||||
'[^\r\n]*',
|
||||
'.+',
|
||||
'.*',
|
||||
'\s*',
|
||||
'[+-]?\d+',
|
||||
'\d+',
|
||||
'[0-9a-fA-F]+',
|
||||
'[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
|
||||
'.',
|
||||
'\t',
|
||||
'\t+'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructs a new Test object given a specilized phpdbginit file
|
||||
*
|
||||
* @param array configuration
|
||||
* @param string file
|
||||
*/
|
||||
public function __construct(TestsConfiguration &$config, &$file) {
|
||||
if (($handle = fopen($file, 'r'))) {
|
||||
while (($line = fgets($handle))) {
|
||||
$trim = trim($line);
|
||||
|
||||
switch (substr($trim, 0, 1)) {
|
||||
case '#': if (($chunks = array_map('trim', preg_split('~:~', substr($trim, 1), 2)))) {
|
||||
if (property_exists($this, $chunks[0])) {
|
||||
switch ($chunks[0]) {
|
||||
case 'expect': {
|
||||
if ($chunks[1]) {
|
||||
switch (strtoupper($chunks[1])) {
|
||||
case 'TEST::EXACT':
|
||||
case 'EXACT': { $this->expect = TEST::EXACT; } break;
|
||||
|
||||
case 'TEST::STRING':
|
||||
case 'STRING': { $this->expect = TEST::STRING; } break;
|
||||
|
||||
case 'TEST::CISTRING':
|
||||
case 'CISTRING': { $this->expect = TEST::CISTRING; } break;
|
||||
|
||||
case 'TEST::FORMAT':
|
||||
case 'FORMAT': { $this->expect = TEST::FORMAT; } break;
|
||||
|
||||
default:
|
||||
throw new TestConfigurationException(
|
||||
$this->config, "unknown type of expectation (%s)", $chunks[1]);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
$this->$chunks[0] = $chunks[1];
|
||||
}
|
||||
}
|
||||
} else switch(substr($trim, 1, 1)) {
|
||||
case '#': { /* do nothing */ } break;
|
||||
|
||||
default: {
|
||||
$line = preg_replace(
|
||||
"~(\r\n)~", "\n", substr($trim, 1));
|
||||
|
||||
$line = trim($line);
|
||||
|
||||
switch ($this->expect) {
|
||||
case TEST::FORMAT:
|
||||
$this->match[] = str_replace(
|
||||
self::$format['search'],
|
||||
self::$format['replace'], preg_quote($line));
|
||||
break;
|
||||
|
||||
default: $this->match[] = $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
fclose($handle);
|
||||
|
||||
$this->config = &$config;
|
||||
$this->file = &$file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obvious!!
|
||||
*
|
||||
*/
|
||||
public function getResult() {
|
||||
$options = sprintf(
|
||||
'-i%s -qb', $this->file);
|
||||
|
||||
if ($this->options) {
|
||||
$options = sprintf(
|
||||
'%s %s %s',
|
||||
$options,
|
||||
$this->config['options'],
|
||||
$this->options
|
||||
);
|
||||
} else {
|
||||
$options = sprintf(
|
||||
'%s %s', $options, $this->config['options']
|
||||
);
|
||||
}
|
||||
|
||||
$result = `{$this->config['phpdbg']} {$options}`;
|
||||
|
||||
if ($result) {
|
||||
foreach (preg_split('~(\r|\n)~', $result) as $num => $line) {
|
||||
if (!$line && !isset($this->match[$num]))
|
||||
continue;
|
||||
|
||||
switch ($this->expect) {
|
||||
case TEST::EXACT: {
|
||||
if (strcmp($line, $this->match[$num]) !== 0) {
|
||||
$this->diff['wants'][$num] = &$this->match[$num];
|
||||
$this->diff['gets'][$num] = $line;
|
||||
}
|
||||
} continue 2;
|
||||
|
||||
case TEST::STRING: {
|
||||
if (strpos($line, $this->match[$num]) === false) {
|
||||
$this->diff['wants'][$num] = &$this->match[$num];
|
||||
$this->diff['gets'][$num] = $line;
|
||||
}
|
||||
} continue 2;
|
||||
|
||||
case TEST::CISTRING: {
|
||||
if (stripos($line, $this->match[$num]) === false) {
|
||||
$this->diff['wants'][$num] = &$this->match[$num];
|
||||
$this->diff['gets'][$num] = $line;
|
||||
}
|
||||
} continue 2;
|
||||
|
||||
case TEST::FORMAT: {
|
||||
$line = trim($line);
|
||||
if (!preg_match("/^{$this->match[$num]}\$/s", $line)) {
|
||||
$this->diff['wants'][$num] = &$this->match[$num];
|
||||
$this->diff['gets'][$num] = $line;
|
||||
}
|
||||
} continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeLog($result);
|
||||
$this->writeDiff();
|
||||
|
||||
return (count($this->diff) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write diff to disk if configuration allows it
|
||||
*
|
||||
*/
|
||||
protected function writeDiff() {
|
||||
$diff = sprintf(
|
||||
'%s/%s.diff',
|
||||
dirname($this->file), basename($this->file));
|
||||
|
||||
if (count($this->diff['wants'])) {
|
||||
if (!in_array('nodiff', $this->config['flags'])) {
|
||||
if (($diff = fopen($diff, 'w+'))) {
|
||||
|
||||
foreach ($this->diff['wants'] as $line => $want) {
|
||||
$got = $this->diff['gets'][$line];
|
||||
|
||||
fprintf(
|
||||
$diff, '(%d) -%s%s', $line+1, $want, PHP_EOL);
|
||||
fprintf(
|
||||
$diff, '(%d) +%s%s', $line+1, $got, PHP_EOL);
|
||||
}
|
||||
|
||||
fclose($diff);
|
||||
}
|
||||
}
|
||||
} else unlink($diff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write log to disk if configuration allows it
|
||||
*
|
||||
*/
|
||||
protected function writeLog(&$result = null) {
|
||||
$log = sprintf(
|
||||
'%s/%s.log',
|
||||
dirname($this->file), basename($this->file));
|
||||
|
||||
if (count($this->diff) && $result) {
|
||||
if (!in_array('nolog', $this->config['flags'])) {
|
||||
@file_put_contents(
|
||||
$log, $result);
|
||||
}
|
||||
} else unlink($log);
|
||||
}
|
||||
|
||||
public $name;
|
||||
public $purpose;
|
||||
public $file;
|
||||
public $options;
|
||||
public $expect;
|
||||
|
||||
protected $match;
|
||||
protected $diff;
|
||||
protected $stats;
|
||||
protected $totals;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
use \phpdbg\Testing\Test;
|
||||
use \phpdbg\Testing\Tests;
|
||||
use \phpdbg\Testing\TestsConfiguration;
|
||||
|
||||
$cwd = dirname(__FILE__);
|
||||
$cmd = $_SERVER['argv'];
|
||||
{
|
||||
$config = new TestsConfiguration(array(
|
||||
'exec' => realpath(array_shift($cmd)),
|
||||
'phpdbg' => realpath(sprintf(
|
||||
'%s/../phpdbg', $cwd
|
||||
)),
|
||||
'path' => array(
|
||||
realpath(dirname(__FILE__))
|
||||
),
|
||||
'flags' => array(),
|
||||
'width' => 75
|
||||
), $cmd);
|
||||
|
||||
$tests = new Tests($config);
|
||||
|
||||
foreach ($tests->findPaths() as $path) {
|
||||
$tests->logPath($path);
|
||||
|
||||
foreach ($tests->findTests($path) as $test) {
|
||||
$tests->logTest($path, $test);
|
||||
}
|
||||
|
||||
$tests->logPathStats($path);
|
||||
}
|
||||
|
||||
$tests->logStats();
|
||||
}
|
||||
}
|
||||
?>
|
9
sapi/phpdbg/travis/ci.sh
Executable file
9
sapi/phpdbg/travis/ci.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env sh
|
||||
git clone https://github.com/php/php-src
|
||||
cd php-src/sapi
|
||||
git clone https://github.com/krakjoe/phpdbg.git
|
||||
cd ../
|
||||
./buildconf --force
|
||||
./configure --disable-all --enable-phpdbg --enable-maintainer-zts
|
||||
make
|
||||
make test-phpdbg
|
64
sapi/phpdbg/web-bootstrap.php
Normal file
64
sapi/phpdbg/web-bootstrap.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* The following file shows how to bootstrap phpdbg so that you can mock specific server environments
|
||||
*
|
||||
* eval include("web-bootstrap.php")
|
||||
* exec index.php
|
||||
* compile
|
||||
* break ...
|
||||
* run
|
||||
*/
|
||||
if (!defined('PHPDBG_BOOTSTRAPPED'))
|
||||
{
|
||||
/* define these once */
|
||||
define("PHPDBG_BOOTPATH", "/opt/php-zts/htdocs");
|
||||
define("PHPDBG_BOOTSTRAP", "index.php");
|
||||
define("PHPDBG_BOOTSTRAPPED", sprintf("/%s", PHPDBG_BOOTSTRAP));
|
||||
}
|
||||
|
||||
/*
|
||||
* Superglobals are JIT, phpdbg will not over-write whatever you set during bootstrap
|
||||
*/
|
||||
|
||||
$_SERVER = array
|
||||
(
|
||||
'HTTP_HOST' => 'localhost',
|
||||
'HTTP_CONNECTION' => 'keep-alive',
|
||||
'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.65 Safari/537.36',
|
||||
'HTTP_ACCEPT_ENCODING' => 'gzip,deflate,sdch',
|
||||
'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
|
||||
'HTTP_COOKIE' => 'tz=Europe%2FLondon; __utma=1.347100075.1384196523.1384196523.1384196523.1; __utmc=1; __utmz=1.1384196523.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)',
|
||||
'PATH' => '/usr/local/bin:/usr/bin:/bin',
|
||||
'SERVER_SIGNATURE' => '<address>Apache/2.4.6 (Ubuntu) Server at phpdbg.com Port 80</address>',
|
||||
'SERVER_SOFTWARE' => 'Apache/2.4.6 (Ubuntu)',
|
||||
'SERVER_NAME' => 'localhost',
|
||||
'SERVER_ADDR' => '127.0.0.1',
|
||||
'SERVER_PORT' => '80',
|
||||
'REMOTE_ADDR' => '127.0.0.1',
|
||||
'DOCUMENT_ROOT' => PHPDBG_BOOTPATH,
|
||||
'REQUEST_SCHEME' => 'http',
|
||||
'CONTEXT_PREFIX' => '',
|
||||
'CONTEXT_DOCUMENT_ROOT' => PHPDBG_BOOTPATH,
|
||||
'SERVER_ADMIN' => '[no address given]',
|
||||
'SCRIPT_FILENAME' => sprintf(
|
||||
'%s/%s', PHPDBG_BOOTPATH, PHPDBG_BOOTSTRAP
|
||||
),
|
||||
'REMOTE_PORT' => '47931',
|
||||
'GATEWAY_INTERFACE' => 'CGI/1.1',
|
||||
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'QUERY_STRING' => '',
|
||||
'REQUEST_URI' => PHPDBG_BOOTSTRAPPED,
|
||||
'SCRIPT_NAME' => PHPDBG_BOOTSTRAPPED,
|
||||
'PHP_SELF' => PHPDBG_BOOTSTRAPPED,
|
||||
'REQUEST_TIME' => time(),
|
||||
);
|
||||
|
||||
$_GET = array();
|
||||
$_REQUEST = array();
|
||||
$_POST = array();
|
||||
$_COOKIE = array();
|
||||
$_FILES = array();
|
||||
|
||||
chdir(PHPDBG_BOOTPATH);
|
Loading…
Reference in New Issue
Block a user