mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Made phpdbg compatible with new engine
This commit is contained in:
commit
2bcac53bca
65 changed files with 8154 additions and 3653 deletions
|
@ -5,10 +5,13 @@ dnl
|
|||
PHP_ARG_ENABLE(phpdbg, for phpdbg support,
|
||||
[ --enable-phpdbg Build phpdbg], no, no)
|
||||
|
||||
PHP_ARG_ENABLE(phpdbg-webhelper, for phpdbg web SAPI support,
|
||||
[ --enable-phpdbg-webhelper Build phpdbg web SAPI support], yes, yes)
|
||||
|
||||
PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build,
|
||||
[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no)
|
||||
|
||||
if test "$PHP_PHPDBG" != "no"; then
|
||||
if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then
|
||||
AC_HEADER_TIOCGWINSZ
|
||||
AC_DEFINE(HAVE_PHPDBG, 1, [ ])
|
||||
|
||||
|
@ -18,8 +21,19 @@ if test "$PHP_PHPDBG" != "no"; then
|
|||
AC_DEFINE(PHPDBG_DEBUG, 0, [ ])
|
||||
fi
|
||||
|
||||
if test "$PHP_PHPDBG_WEBHELPER" != "no"; then
|
||||
if ! test -d ext/phpdbg_webhelper; then
|
||||
ln -s ../sapi/phpdbg ext/phpdbg_webhelper
|
||||
fi
|
||||
if test "$PHP_JSON" != "no"; then
|
||||
PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared)
|
||||
else
|
||||
AC_MSG_ERROR(Webhelper extension of phpdbg needs json enabled)
|
||||
fi
|
||||
fi
|
||||
|
||||
PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
|
||||
PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c"
|
||||
PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c phpdbg_eol.c phpdbg_out.c"
|
||||
|
||||
if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then
|
||||
PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS"
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
ARG_ENABLE('phpdbg', 'Build phpdbg', 'no');
|
||||
ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no');
|
||||
|
||||
PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c phpdbg_parser.c phpdbg_lexer.c';
|
||||
PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c ' +
|
||||
'phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c ' +
|
||||
'phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c '+
|
||||
'phpdbg_parser.c phpdbg_lexer.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c ' +
|
||||
'phpdbg_sigio_win32.c phpdbg_eol.c phpdbg_out.c';
|
||||
PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll';
|
||||
PHPDBG_EXE='phpdbg.exe';
|
||||
|
||||
|
@ -9,6 +13,7 @@ if (PHP_PHPDBG == "yes") {
|
|||
SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE);
|
||||
ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib");
|
||||
ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H");
|
||||
ADD_FLAG("LDFLAGS_PHPDBG", "/stack:8388608");
|
||||
}
|
||||
|
||||
if (PHP_PHPDBGS == "yes") {
|
||||
|
|
|
@ -7,7 +7,7 @@ phpdbg \- The interactive PHP debugger
|
|||
[\fB\-e\fIFILE\fR]
|
||||
.SH DESCRIPTION
|
||||
.B phpdbg
|
||||
a lightweight, powerful, easy to use debugging platform for PHP7.
|
||||
a lightweight, powerful, easy to use debugging platform for PHP5.
|
||||
.SH OPTIONS
|
||||
The following switches are implemented (just like cli SAPI):
|
||||
.TP
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -29,6 +29,8 @@
|
|||
# define PHPDBG_API
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "php.h"
|
||||
#include "php_globals.h"
|
||||
#include "php_variables.h"
|
||||
|
@ -48,6 +50,7 @@
|
|||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
# include <windows.h>
|
||||
# include "config.w32.h"
|
||||
# include "win32/php_stdint.h"
|
||||
# undef strcasecmp
|
||||
# undef strncasecmp
|
||||
# define strcasecmp _stricmp
|
||||
|
@ -64,7 +67,30 @@
|
|||
# include "TSRM.h"
|
||||
#endif
|
||||
|
||||
#ifdef LIBREADLINE
|
||||
#define ZEND_HASH_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
|
||||
ZEND_HASH_FOREACH(ht, 0); \
|
||||
_h = _p->h; \
|
||||
_ptr = Z_PTR_P(_z);
|
||||
|
||||
#undef zend_hash_str_add
|
||||
#define zend_hash_str_add_tmp(ht, key, len, pData) \
|
||||
_zend_hash_str_add(ht, key, len, pData ZEND_FILE_LINE_CC)
|
||||
#define zend_hash_str_add(...) zend_hash_str_add_tmp(__VA_ARGS__)
|
||||
|
||||
static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
|
||||
{
|
||||
zval tmp, *zv;
|
||||
|
||||
ZVAL_PTR(&tmp, NULL);
|
||||
if ((zv = zend_hash_index_add(ht, h, &tmp))) {
|
||||
Z_PTR_P(zv) = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT);
|
||||
memcpy(Z_PTR_P(zv), pData, size);
|
||||
return Z_PTR_P(zv);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
|
@ -72,13 +98,33 @@
|
|||
# include <editline/readline.h>
|
||||
#endif
|
||||
|
||||
#include "phpdbg_lexer.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_btree.h"
|
||||
#include "phpdbg_watch.h"
|
||||
/* {{{ remote console headers */
|
||||
#ifndef _WIN32
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
# include <sys/select.h>
|
||||
# include <sys/types.h>
|
||||
# include <netdb.h>
|
||||
#endif /* }}} */
|
||||
|
||||
int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
||||
/* {{{ strings */
|
||||
#define PHPDBG_NAME "phpdbg"
|
||||
#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
|
||||
#define PHPDBG_URL "http://phpdbg.com"
|
||||
#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
|
||||
#define PHPDBG_VERSION "0.4.0"
|
||||
#define PHPDBG_INIT_FILENAME ".phpdbginit"
|
||||
#define PHPDBG_DEFAULT_PROMPT "prompt>"
|
||||
/* }}} */
|
||||
|
||||
/* Hey, apple. One shouldn't define *functions* from the standard C library as marcos. */
|
||||
#ifdef memcpy
|
||||
#define memcpy_tmp(...) memcpy(__VA_ARGS__)
|
||||
#undef memcpy
|
||||
#define memcpy(...) memcpy_tmp(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if !defined(PHPDBG_WEBDATA_TRANSFER_H) && !defined(PHPDBG_WEBHELPER_H)
|
||||
|
||||
#ifdef ZTS
|
||||
# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
|
||||
|
@ -86,6 +132,19 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
|||
# define PHPDBG_G(v) (phpdbg_globals.v)
|
||||
#endif
|
||||
|
||||
#include "phpdbg_sigsafe.h"
|
||||
#include "phpdbg_out.h"
|
||||
#include "phpdbg_lexer.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_btree.h"
|
||||
#include "phpdbg_watch.h"
|
||||
#ifdef PHP_WIN32
|
||||
# include "phpdbg_sigio_win32.h"
|
||||
#endif
|
||||
|
||||
int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
||||
|
||||
#define PHPDBG_NEXT 2
|
||||
#define PHPDBG_UNTIL 3
|
||||
#define PHPDBG_FINISH 4
|
||||
|
@ -145,8 +204,11 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
|||
#define PHPDBG_IS_BP_ENABLED (1<<26)
|
||||
#define PHPDBG_IS_REMOTE (1<<27)
|
||||
#define PHPDBG_IS_DISCONNECTED (1<<28)
|
||||
#define PHPDBG_WRITE_XML (1<<29)
|
||||
|
||||
#define PHPDBG_SHOW_REFCOUNTS (1<<29)
|
||||
#define PHPDBG_SHOW_REFCOUNTS (1<<30)
|
||||
|
||||
#define PHPDBG_IN_SIGNAL_HANDLER (1<<30)
|
||||
|
||||
#define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL|PHPDBG_IN_FINISH|PHPDBG_IN_LEAVE)
|
||||
#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
|
||||
|
@ -158,21 +220,27 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
|||
# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED)
|
||||
#endif /* }}} */
|
||||
|
||||
/* {{{ strings */
|
||||
#define PHPDBG_NAME "phpdbg"
|
||||
#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
|
||||
#define PHPDBG_URL "http://phpdbg.com"
|
||||
#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
|
||||
#define PHPDBG_VERSION "0.4.0"
|
||||
#define PHPDBG_INIT_FILENAME ".phpdbginit"
|
||||
/* }}} */
|
||||
|
||||
/* {{{ output descriptors */
|
||||
#define PHPDBG_STDIN 0
|
||||
#define PHPDBG_STDOUT 1
|
||||
#define PHPDBG_STDERR 2
|
||||
#define PHPDBG_IO_FDS 3 /* }}} */
|
||||
|
||||
#define phpdbg_try_access \
|
||||
{ \
|
||||
JMP_BUF *__orig_bailout = PHPDBG_G(sigsegv_bailout); \
|
||||
JMP_BUF __bailout; \
|
||||
\
|
||||
PHPDBG_G(sigsegv_bailout) = &__bailout; \
|
||||
if (SETJMP(__bailout) == 0) {
|
||||
#define phpdbg_catch_access \
|
||||
} else { \
|
||||
PHPDBG_G(sigsegv_bailout) = __orig_bailout;
|
||||
#define phpdbg_end_try_access() \
|
||||
} \
|
||||
PHPDBG_G(sigsegv_bailout) = __orig_bailout; \
|
||||
}
|
||||
|
||||
|
||||
/* {{{ structs */
|
||||
ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
||||
|
@ -191,6 +259,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
|||
phpdbg_btree watchpoint_tree; /* tree with watchpoints */
|
||||
phpdbg_btree watch_HashTables; /* tree with original dtors of watchpoints */
|
||||
HashTable watchpoints; /* watchpoints */
|
||||
HashTable watch_collisions; /* collision table to check if multiple watches share the same recursive watchpoint */
|
||||
zend_llist watchlist_mem; /* triggered watchpoints */
|
||||
zend_bool watchpoint_hit; /* a watchpoint was hit */
|
||||
void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */
|
||||
|
@ -198,33 +267,57 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
|||
char *exec; /* file to execute */
|
||||
size_t exec_len; /* size of exec */
|
||||
zend_op_array *ops; /* op_array */
|
||||
zval *retval; /* return value */
|
||||
zval retval; /* return value */
|
||||
int bp_count; /* breakpoint count */
|
||||
int vmret; /* return from last opcode handler execution */
|
||||
zend_bool in_execution; /* in execution? */
|
||||
|
||||
zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
|
||||
HashTable file_sources;
|
||||
|
||||
FILE *oplog; /* opline log */
|
||||
FILE *io[PHPDBG_IO_FDS]; /* io */
|
||||
struct {
|
||||
FILE *ptr;
|
||||
int fd;
|
||||
} io[PHPDBG_IO_FDS]; /* io */
|
||||
size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC);
|
||||
int in_script_xml; /* in <stream> output mode */
|
||||
struct {
|
||||
zend_bool active;
|
||||
int type;
|
||||
int fd;
|
||||
char *tag;
|
||||
char *msg;
|
||||
int msglen;
|
||||
char *xml;
|
||||
int xmllen;
|
||||
} err_buf; /* error buffer */
|
||||
zend_ulong req_id; /* "request id" to keep track of commands */
|
||||
|
||||
char *prompt[2]; /* prompt */
|
||||
const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */
|
||||
char *buffer; /* buffer */
|
||||
zend_bool last_was_newline; /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */
|
||||
|
||||
char input_buffer[PHPDBG_MAX_CMD]; /* stdin input buffer */
|
||||
int input_buflen; /* length of stdin input buffer */
|
||||
phpdbg_signal_safe_mem sigsafe_mem; /* memory to use in async safe environment (only once!) */
|
||||
|
||||
JMP_BUF *sigsegv_bailout; /* bailout address for accesibility probing */
|
||||
|
||||
zend_ulong flags; /* phpdbg flags */
|
||||
|
||||
char *socket_path; /* phpdbg.path ini setting */
|
||||
char *sapi_name_ptr; /* store sapi name to free it if necessary to not leak memory */
|
||||
int socket_fd; /* file descriptor to socket (wait command) (-1 if unused) */
|
||||
int socket_server_fd; /* file descriptor to master socket (wait command) (-1 if unused) */
|
||||
#ifdef PHP_WIN32
|
||||
HANDLE sigio_watcher_thread; /* sigio watcher thread handle */
|
||||
struct win32_sigio_watcher_data swd;
|
||||
#endif
|
||||
int8_t eol;
|
||||
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
|
||||
|
||||
/* the beginning (= the important part) of the _zend_mm_heap struct defined in Zend/zend_alloc.c
|
||||
Needed for realizing watchpoints */
|
||||
struct _zend_mm_heap {
|
||||
int use_zend_alloc;
|
||||
void *(*_malloc)(size_t);
|
||||
void (*_free)(void *);
|
||||
void *(*_realloc)(void *, size_t);
|
||||
size_t free_bitmap;
|
||||
size_t large_free_bitmap;
|
||||
size_t block_size;
|
||||
size_t compact_size;
|
||||
zend_mm_segment *segments_list;
|
||||
zend_mm_storage *storage;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* PHPDBG_H */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -21,6 +21,19 @@
|
|||
#ifndef PHPDBG_BP_H
|
||||
#define PHPDBG_BP_H
|
||||
|
||||
/* {{{ defines */
|
||||
#define PHPDBG_BREAK_FILE 0
|
||||
#define PHPDBG_BREAK_SYM 1
|
||||
#define PHPDBG_BREAK_OPLINE 2
|
||||
#define PHPDBG_BREAK_METHOD 3
|
||||
#define PHPDBG_BREAK_COND 4
|
||||
#define PHPDBG_BREAK_OPCODE 5
|
||||
#define PHPDBG_BREAK_FUNCTION_OPLINE 6
|
||||
#define PHPDBG_BREAK_METHOD_OPLINE 7
|
||||
#define PHPDBG_BREAK_FILE_OPLINE 8
|
||||
#define PHPDBG_BREAK_MAP 9
|
||||
#define PHPDBG_BREAK_TABLES 10 /* }}} */
|
||||
|
||||
/* {{{ */
|
||||
typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */
|
||||
|
||||
|
@ -138,7 +151,7 @@ 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); /* }}} */
|
||||
PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable **table, zend_ulong *numkey, zend_string **strkey TSRMLS_DC); /* }}} */
|
||||
|
||||
/* {{{ Breakpoint Exportation API */
|
||||
PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -28,15 +28,15 @@
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[10])
|
||||
#define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s, flags) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[10], flags)
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
const phpdbg_command_t phpdbg_break_commands[] = {
|
||||
PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c"),
|
||||
PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n"),
|
||||
PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c", 0),
|
||||
PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n", 0),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -219,3 +219,18 @@ check_branch_existence:
|
|||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void phpdbg_btree_branch_dump(phpdbg_btree_branch *branch, zend_ulong depth) {
|
||||
if (branch) {
|
||||
if (depth--) {
|
||||
phpdbg_btree_branch_dump(branch->branches[0], depth);
|
||||
phpdbg_btree_branch_dump(branch->branches[1], depth);
|
||||
} else {
|
||||
fprintf(stderr, "%p: %p\n", (void *) branch->result.idx, branch->result.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void phpdbg_btree_dump(phpdbg_btree *tree) {
|
||||
phpdbg_btree_branch_dump(tree->branch, tree->depth);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -62,4 +62,9 @@ int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr,
|
|||
#define phpdbg_btree_update(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_UPDATE)
|
||||
#define phpdbg_btree_overwrite(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_OWERWRITE)
|
||||
|
||||
|
||||
/* debugging functions */
|
||||
void phpdbg_btree_branch_dump(phpdbg_btree_branch *branch, zend_ulong depth);
|
||||
void phpdbg_btree_dump(phpdbg_btree *tree);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -23,6 +23,7 @@
|
|||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_set.h"
|
||||
#include "phpdbg_prompt.h"
|
||||
#include "phpdbg_io.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
|
@ -167,59 +168,39 @@ PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **point
|
|||
{
|
||||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
asprintf(pointer,
|
||||
"%s", param->str);
|
||||
asprintf(pointer, "%s", param->str);
|
||||
break;
|
||||
|
||||
case ADDR_PARAM:
|
||||
asprintf(pointer,
|
||||
"%#lx", param->addr);
|
||||
asprintf(pointer, "%#llx", param->addr);
|
||||
break;
|
||||
|
||||
case NUMERIC_PARAM:
|
||||
asprintf(pointer,
|
||||
"%li",
|
||||
param->num);
|
||||
asprintf(pointer, "%li", param->num);
|
||||
break;
|
||||
|
||||
case METHOD_PARAM:
|
||||
asprintf(pointer,
|
||||
"%s::%s",
|
||||
param->method.class,
|
||||
param->method.name);
|
||||
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);
|
||||
asprintf(pointer, "%s:%lu#%lu", param->file.name, param->file.line, param->num);
|
||||
} else {
|
||||
asprintf(pointer,
|
||||
"%s:%lu",
|
||||
param->file.name,
|
||||
param->file.line);
|
||||
asprintf(pointer, "%s:%lu", param->file.name, param->file.line);
|
||||
}
|
||||
break;
|
||||
|
||||
case NUMERIC_FUNCTION_PARAM:
|
||||
asprintf(pointer,
|
||||
"%s#%lu", param->str, param->num);
|
||||
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);
|
||||
asprintf(pointer, "%s::%s#%lu", param->method.class, param->method.name, param->num);
|
||||
break;
|
||||
|
||||
default:
|
||||
asprintf(pointer,
|
||||
"%s", "unknown");
|
||||
*pointer = strdup("unknown");
|
||||
}
|
||||
|
||||
return *pointer;
|
||||
|
@ -421,7 +402,7 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)
|
|||
break;
|
||||
|
||||
case ADDR_PARAM:
|
||||
fprintf(stderr, "%s ADDR_PARAM(%lu)\n", msg, param->addr);
|
||||
fprintf(stderr, "%s ADDR_PARAM(%llu)\n", msg, param->addr);
|
||||
break;
|
||||
|
||||
case NUMERIC_FILE_PARAM:
|
||||
|
@ -510,6 +491,7 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
stack->next = NULL;
|
||||
} /* }}} */
|
||||
|
||||
|
@ -537,7 +519,7 @@ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param)
|
|||
stack->len++;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC) {
|
||||
PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC) {
|
||||
if (command) {
|
||||
char buffer[128] = {0,};
|
||||
const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL;
|
||||
|
@ -553,8 +535,7 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
asprintf(why,
|
||||
"The command \"%s\" expected no arguments",
|
||||
phpdbg_error("command", "type=\"toomanyargs\" command=\"%s\" expected=\"0\"", "The command \"%s\" expected no arguments",
|
||||
phpdbg_command_name(command, buffer));
|
||||
return FAILURE;
|
||||
}
|
||||
|
@ -574,16 +555,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
|
|||
|
||||
#define verify_arg(e, a, t) if (!(a)) { \
|
||||
if (!optional) { \
|
||||
asprintf(why, \
|
||||
"The command \"%s\" expected %s and got nothing at parameter %lu", \
|
||||
phpdbg_error("command", "type=\"noarg\" command=\"%s\" expected=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got nothing at parameter %lu", \
|
||||
phpdbg_command_name(command, buffer), \
|
||||
(e), \
|
||||
current); \
|
||||
return FAILURE;\
|
||||
} \
|
||||
} else if ((a)->type != (t)) { \
|
||||
asprintf(why, \
|
||||
"The command \"%s\" expected %s and got %s at parameter %lu", \
|
||||
phpdbg_error("command", "type=\"wrongarg\" command=\"%s\" expected=\"%s\" got=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got %s at parameter %lu", \
|
||||
phpdbg_command_name(command, buffer), \
|
||||
(e),\
|
||||
phpdbg_get_param_type((a) TSRMLS_CC), \
|
||||
|
@ -625,8 +604,7 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
|
|||
#undef verify_arg
|
||||
|
||||
if ((received < least)) {
|
||||
asprintf(why,
|
||||
"The command \"%s\" expected at least %lu arguments (%s) and received %lu",
|
||||
phpdbg_error("command", "type=\"toofewargs\" command=\"%s\" expected=\"%d\" argtypes=\"%s\" got=\"%d\"", "The command \"%s\" expected at least %lu arguments (%s) and received %lu",
|
||||
phpdbg_command_name(command, buffer),
|
||||
least,
|
||||
command->args,
|
||||
|
@ -639,14 +617,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param
|
|||
}
|
||||
|
||||
/* {{{ */
|
||||
PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why) {
|
||||
PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC) {
|
||||
const phpdbg_command_t *command = commands;
|
||||
phpdbg_param_t *name = *top;
|
||||
const phpdbg_command_t *matched[3] = {NULL, NULL, NULL};
|
||||
ulong matches = 0L;
|
||||
|
||||
while (command && command->name && command->handler) {
|
||||
if ((name->len == 1) || (command->name_len >= name->len)) {
|
||||
if (name->len == 1 || command->name_len >= name->len) {
|
||||
/* match single letter alias */
|
||||
if (command->alias && (name->len == 1)) {
|
||||
if (command->alias == (*name->str)) {
|
||||
|
@ -654,23 +632,22 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
|||
matches++;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* match full, case insensitive, command name */
|
||||
if (strncasecmp(command->name, name->str, name->len) == SUCCESS) {
|
||||
if (matches < 3) {
|
||||
|
||||
/* only allow abbreviating commands that can be aliased */
|
||||
if (((name->len != command->name_len) && command->alias) ||
|
||||
(name->len == command->name_len)) {
|
||||
if ((name->len != command->name_len && command->alias) || name->len == command->name_len) {
|
||||
matched[matches] = command;
|
||||
matches++;
|
||||
}
|
||||
|
||||
|
||||
/* exact match */
|
||||
if (name->len == command->name_len)
|
||||
if (name->len == command->name_len) {
|
||||
break;
|
||||
} else break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -679,23 +656,19 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
|||
}
|
||||
|
||||
switch (matches) {
|
||||
case 0: {
|
||||
case 0:
|
||||
if (parent) {
|
||||
asprintf(
|
||||
why,
|
||||
"The command \"%s %s\" could not be found",
|
||||
parent->name, name->str);
|
||||
} else asprintf(
|
||||
why,
|
||||
"The command \"%s\" could not be found",
|
||||
name->str);
|
||||
} return parent;
|
||||
phpdbg_error("command", "type=\"notfound\" command=\"%s\" subcommand=\"%s\"", "The command \"%s %s\" could not be found", parent->name, name->str);
|
||||
} else {
|
||||
phpdbg_error("command", "type=\"notfound\" command=\"%s\"", "The command \"%s\" could not be found", name->str);
|
||||
}
|
||||
return parent;
|
||||
|
||||
case 1: {
|
||||
case 1:
|
||||
(*top) = (*top)->next;
|
||||
|
||||
command = matched[0];
|
||||
} break;
|
||||
break;
|
||||
|
||||
default: {
|
||||
char *list = NULL;
|
||||
|
@ -704,13 +677,9 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
|||
|
||||
while (it < matches) {
|
||||
if (!list) {
|
||||
list = malloc(
|
||||
matched[it]->name_len + 1 +
|
||||
((it+1) < matches ? sizeof(", ")-1 : 0));
|
||||
list = emalloc(matched[it]->name_len + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0));
|
||||
} else {
|
||||
list = realloc(list,
|
||||
(pos + matched[it]->name_len) + 1 +
|
||||
((it+1) < matches ? sizeof(", ")-1 : 0));
|
||||
list = erealloc(list, (pos + matched[it]->name_len) + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0));
|
||||
}
|
||||
memcpy(&list[pos], matched[it]->name, matched[it]->name_len);
|
||||
pos += matched[it]->name_len;
|
||||
|
@ -723,16 +692,16 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
|||
it++;
|
||||
}
|
||||
|
||||
asprintf(
|
||||
why,
|
||||
"The command \"%s\" is ambigious, matching %lu commands (%s)",
|
||||
name->str, matches, list);
|
||||
free(list);
|
||||
} return NULL;
|
||||
/* ", " separated matches */
|
||||
phpdbg_error("command", "type=\"ambiguous\" command=\"%s\" matches=\"%lu\" matched=\"%s\"", "The command \"%s\" is ambigious, matching %lu commands (%s)", name->str, matches, list);
|
||||
efree(list);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (command->subs && (*top) && ((*top)->type == STR_PARAM)) {
|
||||
return phpdbg_stack_resolve(command->subs, command, top, why);
|
||||
return phpdbg_stack_resolve(command->subs, command, top TSRMLS_CC);
|
||||
} else {
|
||||
return command;
|
||||
}
|
||||
|
@ -741,19 +710,17 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
|||
} /* }}} */
|
||||
|
||||
/* {{{ */
|
||||
PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) {
|
||||
PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC) {
|
||||
phpdbg_param_t *top = NULL;
|
||||
const phpdbg_command_t *handler = NULL;
|
||||
|
||||
if (stack->type != STACK_PARAM) {
|
||||
asprintf(
|
||||
why, "The passed argument was not a stack !!");
|
||||
phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (!stack->len) {
|
||||
asprintf(
|
||||
why, "The stack contains nothing !!");
|
||||
phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -761,28 +728,46 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC)
|
|||
|
||||
switch (top->type) {
|
||||
case EVAL_PARAM:
|
||||
phpdbg_activate_err_buf(0 TSRMLS_CC);
|
||||
phpdbg_free_err_buf(TSRMLS_C);
|
||||
return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC);
|
||||
|
||||
case RUN_PARAM:
|
||||
if (!allow_async_unsafe) {
|
||||
phpdbg_error("signalsegv", "command=\"run\"", "run command is disallowed during hard interrupt");
|
||||
}
|
||||
phpdbg_activate_err_buf(0 TSRMLS_CC);
|
||||
phpdbg_free_err_buf(TSRMLS_C);
|
||||
return PHPDBG_COMMAND_HANDLER(run)(top TSRMLS_CC);
|
||||
|
||||
case SHELL_PARAM:
|
||||
if (!allow_async_unsafe) {
|
||||
phpdbg_error("signalsegv", "command=\"sh\"", "sh command is disallowed during hard interrupt");
|
||||
return FAILURE;
|
||||
}
|
||||
phpdbg_activate_err_buf(0 TSRMLS_CC);
|
||||
phpdbg_free_err_buf(TSRMLS_C);
|
||||
return PHPDBG_COMMAND_HANDLER(sh)(top TSRMLS_CC);
|
||||
|
||||
case STR_PARAM: {
|
||||
handler = phpdbg_stack_resolve(
|
||||
phpdbg_prompt_commands, NULL, &top, why);
|
||||
handler = phpdbg_stack_resolve(phpdbg_prompt_commands, NULL, &top TSRMLS_CC);
|
||||
|
||||
if (handler) {
|
||||
if (phpdbg_stack_verify(handler, &top, why TSRMLS_CC) == SUCCESS) {
|
||||
if (!allow_async_unsafe && !(handler->flags & PHPDBG_ASYNC_SAFE)) {
|
||||
phpdbg_error("signalsegv", "command=\"%s\"", "%s command is disallowed during hard interrupt", handler->name);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (phpdbg_stack_verify(handler, &top TSRMLS_CC) == SUCCESS) {
|
||||
phpdbg_activate_err_buf(0 TSRMLS_CC);
|
||||
phpdbg_free_err_buf(TSRMLS_C);
|
||||
return handler->handler(top TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
} return FAILURE;
|
||||
|
||||
default:
|
||||
asprintf(
|
||||
why, "The first parameter makes no sense !!");
|
||||
phpdbg_error("command", "type=\"invalidcommand\"", "The first parameter makes no sense !");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -792,51 +777,80 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC)
|
|||
PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
char *cmd = NULL;
|
||||
#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT)
|
||||
char buf[PHPDBG_MAX_CMD];
|
||||
#endif
|
||||
char *buffer = NULL;
|
||||
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) &&
|
||||
(buffered == NULL)) {
|
||||
fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) {
|
||||
fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
|
||||
}
|
||||
|
||||
if (buffered == NULL) {
|
||||
disconnect:
|
||||
if (0) {
|
||||
disconnect:
|
||||
PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
|
||||
zend_bailout();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT)
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) {
|
||||
goto disconnect;
|
||||
}
|
||||
}
|
||||
#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT))
|
||||
|
||||
/* note: EOF is ignored */
|
||||
/* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */
|
||||
/* strongly assuming to be in blocking mode... */
|
||||
#if USE_LIB_STAR
|
||||
readline:
|
||||
if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
|
||||
/* the user has gone away */
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
goto disconnect;
|
||||
} else goto readline;
|
||||
}
|
||||
|
||||
cmd = buf;
|
||||
#else
|
||||
/* note: EOF makes readline write prompt again in local console mode */
|
||||
readline:
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE)
|
||||
#endif
|
||||
{
|
||||
char buf[PHPDBG_MAX_CMD];
|
||||
if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
|
||||
int bytes = PHPDBG_G(input_buflen), len = 0;
|
||||
if (PHPDBG_G(input_buflen)) {
|
||||
memcpy(buf, PHPDBG_G(input_buffer), bytes);
|
||||
}
|
||||
|
||||
phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C));
|
||||
PHPDBG_G(last_was_newline) = 1;
|
||||
|
||||
do {
|
||||
int i;
|
||||
if (bytes <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = len; i < len + bytes; i++) {
|
||||
if (buf[i] == '\x03') {
|
||||
if (i != len + bytes - 1) {
|
||||
memmove(buf + i, buf + i + 1, len + bytes - i - 1);
|
||||
}
|
||||
len--;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
if (buf[i] == '\n') {
|
||||
PHPDBG_G(input_buflen) = len + bytes - 1 - i;
|
||||
if (PHPDBG_G(input_buflen)) {
|
||||
memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen));
|
||||
}
|
||||
if (i != PHPDBG_MAX_CMD - 1) {
|
||||
buf[i + 1] = 0;
|
||||
}
|
||||
cmd = buf;
|
||||
} else goto disconnect;
|
||||
} else cmd = readline(phpdbg_get_prompt(TSRMLS_C));
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
len += bytes;
|
||||
/* XXX export the timeout through INI??*/
|
||||
} while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0);
|
||||
|
||||
if (bytes <= 0) {
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
cmd = buf;
|
||||
}
|
||||
#if USE_LIB_STAR
|
||||
else {
|
||||
cmd = readline(phpdbg_get_prompt(TSRMLS_C));
|
||||
}
|
||||
|
||||
if (!cmd) {
|
||||
goto readline;
|
||||
|
@ -846,13 +860,15 @@ readline:
|
|||
add_history(cmd);
|
||||
}
|
||||
#endif
|
||||
} else cmd = buffered;
|
||||
|
||||
} else {
|
||||
cmd = buffered;
|
||||
}
|
||||
end:
|
||||
PHPDBG_G(last_was_newline) = 1;
|
||||
buffer = estrdup(cmd);
|
||||
|
||||
#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
|
||||
if (!buffered && cmd &&
|
||||
!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
#if USE_LIB_STAR
|
||||
if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
free(cmd);
|
||||
}
|
||||
#endif
|
||||
|
@ -886,4 +902,3 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */
|
|||
{
|
||||
efree(*input);
|
||||
} /* }}} */
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -86,6 +86,8 @@ struct _phpdbg_param {
|
|||
#define YYSTYPE phpdbg_param_t
|
||||
#endif
|
||||
|
||||
#define PHPDBG_ASYNC_SAFE 1
|
||||
|
||||
typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t* TSRMLS_DC);
|
||||
|
||||
typedef struct _phpdbg_command_t phpdbg_command_t;
|
||||
|
@ -99,6 +101,7 @@ struct _phpdbg_command_t {
|
|||
const phpdbg_command_t *subs; /* Sub Commands */
|
||||
char *args; /* Argument Spec */
|
||||
const phpdbg_command_t *parent; /* Parent Command */
|
||||
zend_bool flags; /* General flags */
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
|
@ -133,9 +136,9 @@ PHPDBG_API void phpdbg_destroy_input(char** TSRMLS_DC);
|
|||
* Stack Management
|
||||
*/
|
||||
PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param);
|
||||
PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why);
|
||||
PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC);
|
||||
PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack);
|
||||
|
||||
/*
|
||||
|
@ -155,27 +158,27 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg)
|
|||
*/
|
||||
#define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name
|
||||
|
||||
#define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent}
|
||||
#define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent, flags) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent, flags}
|
||||
|
||||
#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL}
|
||||
#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args, flags) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL, flags}
|
||||
|
||||
#define PHPDBG_COMMAND_D(name, tip, alias, children, args) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL}
|
||||
#define PHPDBG_COMMAND_D(name, tip, alias, children, args, flags) \
|
||||
{PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL, flags}
|
||||
|
||||
#define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param TSRMLS_DC)
|
||||
|
||||
#define PHPDBG_COMMAND_ARGS param TSRMLS_CC
|
||||
|
||||
#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0', NULL}
|
||||
#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, NULL, NULL, 0}
|
||||
|
||||
/*
|
||||
* Default Switch Case
|
||||
*/
|
||||
#define phpdbg_default_switch_case() \
|
||||
default: \
|
||||
phpdbg_error("Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \
|
||||
phpdbg_error("command", "type=\"wrongarg\" got=\"%s\"", "Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \
|
||||
break
|
||||
|
||||
#endif /* PHPDBG_CMD_H */
|
||||
|
|
172
sapi/phpdbg/phpdbg_eol.c
Normal file
172
sapi/phpdbg/phpdbg_eol.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anatol Belski <ab@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_eol.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define EOL_LIST_LEN 4
|
||||
struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = {
|
||||
{"CRLF", "\r\n", PHPDBG_EOL_CRLF},
|
||||
/* {"LFCR", "\n\r", PHPDBG_EOL_LFCR},*/
|
||||
{"LF", "\n", PHPDBG_EOL_LF},
|
||||
{"CR", "\r", PHPDBG_EOL_CR},
|
||||
};
|
||||
|
||||
int phpdbg_eol_global_update(char *name TSRMLS_DC)
|
||||
{
|
||||
|
||||
if (0 == memcmp(name, "CRLF", 4) || 0 == memcmp(name, "crlf", 4) || 0 == memcmp(name, "DOS", 3) || 0 == memcmp(name, "dos", 3)) {
|
||||
PHPDBG_G(eol) = PHPDBG_EOL_CRLF;
|
||||
} else if (0 == memcmp(name, "LF", 2) || 0 == memcmp(name, "lf", 2) || 0 == memcmp(name, "UNIX", 4) || 0 == memcmp(name, "unix", 4)) {
|
||||
PHPDBG_G(eol) = PHPDBG_EOL_LF;
|
||||
} else if (0 == memcmp(name, "CR", 2) || 0 == memcmp(name, "cr", 2) || 0 == memcmp(name, "MAC", 3) || 0 == memcmp(name, "mac", 3)) {
|
||||
PHPDBG_G(eol) = PHPDBG_EOL_CR;
|
||||
} else {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
char *phpdbg_eol_name(int id)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (i < EOL_LIST_LEN) {
|
||||
|
||||
if (id == phpdbg_eol_list[i].id) {
|
||||
return phpdbg_eol_list[i].name;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *phpdbg_eol_rep(int id)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (i < EOL_LIST_LEN) {
|
||||
|
||||
if (id == phpdbg_eol_list[i].id) {
|
||||
return phpdbg_eol_list[i].rep;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Inspired by https://ccrma.stanford.edu/~craig/utility/flip/flip.cpp */
|
||||
void phpdbg_eol_convert(char **str, int *len TSRMLS_DC)
|
||||
{
|
||||
char *in = *str, *out ;
|
||||
int in_len = *len, out_len, cursor, i;
|
||||
char last, cur;
|
||||
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) != PHPDBG_IS_REMOTE) {
|
||||
return;
|
||||
}
|
||||
|
||||
out_len = *len;
|
||||
if (PHPDBG_EOL_CRLF == PHPDBG_G(eol)) { /* XXX add LFCR case if it's gonna be needed */
|
||||
/* depending on the source EOL the out str will have all CR/LF duplicated */
|
||||
for (i = 0; i < in_len; i++) {
|
||||
if (0x0a == in[i] || 0x0d == in[i]) {
|
||||
out_len++;
|
||||
}
|
||||
}
|
||||
out = (char *)emalloc(out_len);
|
||||
|
||||
last = cur = in[0];
|
||||
i = cursor = 0;
|
||||
for (; i < in_len;) {
|
||||
if (0x0a == cur && last != 0x0d) {
|
||||
out[cursor] = 0x0d;
|
||||
cursor++;
|
||||
out[cursor] = cur;
|
||||
} else if(0x0d == cur) {
|
||||
if (i + 1 < in_len && 0x0a != in[i+1]) {
|
||||
out[cursor] = cur;
|
||||
cursor++;
|
||||
out[cursor] = 0x0a;
|
||||
last = 0x0a;
|
||||
} else {
|
||||
out[cursor] = 0x0d;
|
||||
last = 0x0d;
|
||||
}
|
||||
} else {
|
||||
out[cursor] = cur;
|
||||
last = cur;
|
||||
}
|
||||
|
||||
i++;
|
||||
cursor++;
|
||||
cur = in[i];
|
||||
}
|
||||
|
||||
} else if (PHPDBG_EOL_LF == PHPDBG_G(eol) || PHPDBG_EOL_CR == PHPDBG_G(eol)) {
|
||||
char want, kick;
|
||||
|
||||
if (PHPDBG_EOL_LF == PHPDBG_G(eol)) {
|
||||
want = 0x0a;
|
||||
kick = 0x0d;
|
||||
} else {
|
||||
want = 0x0d;
|
||||
kick = 0x0a;
|
||||
}
|
||||
|
||||
/* We gonna have a smaller or equally long string, estimation is almost neglecting */
|
||||
out = (char *)emalloc(out_len);
|
||||
|
||||
last = cur = in[0];
|
||||
i = cursor = 0;
|
||||
for (; cursor < in_len;) {
|
||||
if (kick == cur) {
|
||||
out[cursor] = want;
|
||||
} else if (want == cur) {
|
||||
if (kick != last) {
|
||||
out[cursor] = want;
|
||||
}
|
||||
} else {
|
||||
out[cursor] = cur;
|
||||
}
|
||||
|
||||
last = cur;
|
||||
cursor++;
|
||||
cur = in[cursor];
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
efree(*str);
|
||||
*str = erealloc(out, cursor);
|
||||
*len = cursor;
|
||||
in = NULL;
|
||||
}
|
46
sapi/phpdbg/phpdbg_eol.h
Normal file
46
sapi/phpdbg/phpdbg_eol.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anatol Belski <ab@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_EOL_H
|
||||
#define PHPDBG_EOL_H
|
||||
|
||||
#include "phpdbg.h"
|
||||
|
||||
struct phpdbg_eol_rep {
|
||||
char *name;
|
||||
char *rep;
|
||||
int id;
|
||||
};
|
||||
|
||||
enum {
|
||||
PHPDBG_EOL_CRLF, /* DOS */
|
||||
/*PHPDBG_EOL_LFCR,*/ /* for Risc OS? */
|
||||
PHPDBG_EOL_LF, /* UNIX */
|
||||
PHPDBG_EOL_CR /* MAC */
|
||||
};
|
||||
|
||||
int phpdbg_eol_global_update(char *name TSRMLS_DC);
|
||||
|
||||
char *phpdbg_eol_name(int id);
|
||||
|
||||
char *phpdbg_eol_rep(int id);
|
||||
|
||||
void phpdbg_eol_convert(char **str, int *len TSRMLS_DC);
|
||||
|
||||
#endif /* PHPDBG_EOL_H */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -37,13 +37,7 @@ void phpdbg_restore_frame(TSRMLS_D) /* {{{ */
|
|||
/* 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);
|
||||
EG(scope) = PHPDBG_EX(scope);
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
|
||||
|
@ -52,10 +46,11 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
|
|||
int i = 0;
|
||||
|
||||
if (PHPDBG_FRAME(num) == frame) {
|
||||
phpdbg_notice("Already in frame #%d", frame);
|
||||
phpdbg_notice("frame", "id=\"%d\"", "Already in frame #%d", frame);
|
||||
return;
|
||||
}
|
||||
|
||||
phpdbg_try_access {
|
||||
while (execute_data) {
|
||||
if (i++ == frame) {
|
||||
break;
|
||||
|
@ -65,9 +60,13 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
|
|||
execute_data = execute_data->prev_execute_data;
|
||||
} while (execute_data && execute_data->opline == NULL);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Couldn't switch frames, invalid data source");
|
||||
return;
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
if (execute_data == NULL) {
|
||||
phpdbg_error("No frame #%d", frame);
|
||||
phpdbg_error("frame", "type=\"maxnum\" id=\"%d\"", "No frame #%d", frame);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -80,127 +79,143 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
|
|||
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);
|
||||
EG(scope) = PHPDBG_EX(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
|
||||
);
|
||||
phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame);
|
||||
|
||||
{
|
||||
const char *file_chr = zend_get_executed_filename(TSRMLS_C);
|
||||
zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
|
||||
phpdbg_list_file(file, 3, zend_get_executed_lineno(TSRMLS_C) - 1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
|
||||
efree(file);
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */
|
||||
static void phpdbg_dump_prototype(zval *tmp TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval **funcname, **class, **type, **args, **argstmp;
|
||||
char is_class;
|
||||
zval *funcname, *class, class_zv, *type, *args, *argstmp;
|
||||
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"),
|
||||
(void **)&funcname);
|
||||
funcname = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("function"));
|
||||
|
||||
if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp),
|
||||
"object", sizeof("object"), (void **)&class)) == FAILURE) {
|
||||
is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"),
|
||||
(void **)&class);
|
||||
if ((class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("object")))) {
|
||||
ZVAL_NEW_STR(&class_zv, Z_OBJCE_P(class)->name);
|
||||
class = &class_zv;
|
||||
} else {
|
||||
zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class),
|
||||
(uint32_t *)&Z_STRLEN_PP(class) TSRMLS_CC);
|
||||
class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("class"));
|
||||
}
|
||||
|
||||
if (is_class == SUCCESS) {
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type);
|
||||
if (class) {
|
||||
type = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("type"));
|
||||
}
|
||||
|
||||
phpdbg_write("%s%s%s(",
|
||||
is_class == FAILURE?"":Z_STRVAL_PP(class),
|
||||
is_class == FAILURE?"":Z_STRVAL_PP(type),
|
||||
Z_STRVAL_PP(funcname)
|
||||
);
|
||||
args = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("args"));
|
||||
|
||||
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;
|
||||
phpdbg_xml(" symbol=\"%s%s%s\"", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname));
|
||||
|
||||
if (args) {
|
||||
phpdbg_xml(">");
|
||||
} else {
|
||||
phpdbg_xml(" />");
|
||||
}
|
||||
|
||||
phpdbg_out("%s%s%s(", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname));
|
||||
|
||||
if (args) {
|
||||
const zend_function *func = NULL;
|
||||
const zend_arg_info *arginfo = NULL;
|
||||
zend_bool is_variadic = 0;
|
||||
int j = 0, m;
|
||||
|
||||
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(", ");
|
||||
phpdbg_try_access {
|
||||
/* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */
|
||||
if ((func = phpdbg_get_function(Z_STRVAL_P(funcname), class ? Z_STRVAL_P(class) : NULL TSRMLS_CC))) {
|
||||
arginfo = func->common.arg_info;
|
||||
}
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
m = func ? func->common.num_args : 0;
|
||||
|
||||
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), argstmp) {
|
||||
if (j) {
|
||||
phpdbg_out(", ");
|
||||
}
|
||||
phpdbg_xml("<arg %r");
|
||||
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 ? "[": "");
|
||||
if (!is_variadic) {
|
||||
is_variadic = arginfo ? arginfo[j].is_variadic : 0;
|
||||
}
|
||||
phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arginfo ? arginfo[j].name : "");
|
||||
phpdbg_out("%s=%s", arginfo ? arginfo[j].name : "?", is_variadic ? "[": "");
|
||||
|
||||
} else {
|
||||
phpdbg_xml(">");
|
||||
}
|
||||
++j;
|
||||
|
||||
zend_print_flat_zval_r(*argstmp TSRMLS_CC);
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator);
|
||||
}
|
||||
zend_print_flat_zval_r(argstmp TSRMLS_CC);
|
||||
|
||||
phpdbg_xml("</arg>");
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
if (is_variadic) {
|
||||
phpdbg_write("]");
|
||||
phpdbg_out("]");
|
||||
}
|
||||
phpdbg_xml("</frame>");
|
||||
}
|
||||
phpdbg_write(")");
|
||||
phpdbg_out(")");
|
||||
}
|
||||
|
||||
void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval zbacktrace;
|
||||
zval **tmp;
|
||||
zval **file, **line;
|
||||
HashPosition position;
|
||||
zval zbacktrace;
|
||||
zval *tmp;
|
||||
zval *file, *line;
|
||||
int i = 0, limit = num;
|
||||
int user_defined;
|
||||
|
||||
if (limit < 0) {
|
||||
phpdbg_error("Invalid backtrace size %d", limit);
|
||||
phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit);
|
||||
return;
|
||||
}
|
||||
|
||||
zend_fetch_debug_backtrace(
|
||||
&zbacktrace, 0, 0, limit TSRMLS_CC);
|
||||
phpdbg_try_access {
|
||||
zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit TSRMLS_CC);
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Couldn't fetch backtrace, invalid data source");
|
||||
return;
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
phpdbg_xml("<backtrace %r>");
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position);
|
||||
tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &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);
|
||||
file = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("file"));
|
||||
line = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("line"));
|
||||
zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
|
||||
|
||||
if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace),
|
||||
(void**)&tmp, &position) == FAILURE) {
|
||||
phpdbg_write("frame #%d: {main} at %s:%ld", i, Z_STRVAL_PP(file), Z_LVAL_PP(line));
|
||||
if (!(tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) {
|
||||
phpdbg_write("frame", "id=\"%d\" symbol=\"{main}\" file=\"%s\" line=\"%d\"", "frame #%d: {main} at %s:%ld", i, Z_STRVAL_P(file), Z_LVAL_P(line));
|
||||
break;
|
||||
}
|
||||
|
||||
if (user_defined == SUCCESS) {
|
||||
phpdbg_write("frame #%d: ", i++);
|
||||
if (file) { /* userland */
|
||||
phpdbg_out("frame #%d: ", i);
|
||||
phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"%d\"", i, Z_STRVAL_P(file), Z_LVAL_P(line));
|
||||
phpdbg_dump_prototype(tmp TSRMLS_CC);
|
||||
phpdbg_writeln(" at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line));
|
||||
phpdbg_out(" at %s:%ld\n", Z_STRVAL_P(file), Z_LVAL_P(line));
|
||||
i++;
|
||||
} else {
|
||||
phpdbg_write(" => ");
|
||||
phpdbg_out(" => ");
|
||||
phpdbg_xml("<frame %r id=\"%d\" internal=\"internal\"", i);
|
||||
phpdbg_dump_prototype(tmp TSRMLS_CC);
|
||||
phpdbg_writeln(" (internal function)");
|
||||
phpdbg_out(" (internal function)\n");
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_out("\n");
|
||||
phpdbg_xml("</backtrace>");
|
||||
|
||||
zval_dtor(&zbacktrace);
|
||||
} /* }}} */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -22,6 +22,7 @@
|
|||
#include "phpdbg.h"
|
||||
#include "phpdbg_help.h"
|
||||
#include "phpdbg_prompt.h"
|
||||
#include "phpdbg_eol.h"
|
||||
#include "zend.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
@ -61,6 +62,11 @@ void pretty_print(char *text TSRMLS_DC)
|
|||
unsigned int last_blank_count = 0; /* printable char offset of last blank char */
|
||||
unsigned int line_count = 0; /* number printable chars on current line */
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
|
||||
phpdbg_xml("<help %r msg=\"%s\" />", text);
|
||||
return;
|
||||
}
|
||||
|
||||
/* First pass calculates a safe size for the pretty print version */
|
||||
for (p = text; *p; p++) {
|
||||
if (UNEXPECTED(p[0] == '*') && p[1] == '*') {
|
||||
|
@ -128,10 +134,10 @@ void pretty_print(char *text TSRMLS_DC)
|
|||
*q++ = '\0';
|
||||
|
||||
if ((q-new)>size) {
|
||||
phpdbg_error("Output overrun of %lu bytes", ((q-new) - size));
|
||||
phpdbg_error("help", "overrun=\"%lu\"", "Output overrun of %lu bytes", ((q - new) - size));
|
||||
}
|
||||
|
||||
phpdbg_write("%s\n", new);
|
||||
phpdbg_out("%s\n", new);
|
||||
efree(new);
|
||||
} /* }}} */
|
||||
|
||||
|
@ -231,7 +237,7 @@ PHPDBG_COMMAND(help) /* {{{ */
|
|||
pretty_print(get_help("duplicate!" TSRMLS_CC) TSRMLS_CC);
|
||||
return SUCCESS;
|
||||
} else {
|
||||
phpdbg_error("Internal help error, non-unique alias \"%c\"", param->str[0]);
|
||||
phpdbg_error("help", "type=\"ambiguousalias\" alias=\"%s\"", "Internal help error, non-unique alias \"%c\"", param->str[0]);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -259,34 +265,41 @@ PHPDBG_HELP(aliases) /* {{{ */
|
|||
int len;
|
||||
|
||||
/* Print out aliases for all commands except help as this one comes last */
|
||||
phpdbg_writeln("Below are the aliased, short versions of all supported commands");
|
||||
phpdbg_writeln("help", "", "Below are the aliased, short versions of all supported commands");
|
||||
phpdbg_xml("<helpcommands %r>");
|
||||
for(c = phpdbg_prompt_commands; c->name; c++) {
|
||||
if (c->alias && c->alias != 'h') {
|
||||
phpdbg_writeln(" %c %-20s %s", c->alias, c->name, c->tip);
|
||||
phpdbg_writeln("command", "alias=\"%c\" name=\"%s\" tip=\"%s\"", " %c %-20s %s", c->alias, c->name, c->tip);
|
||||
if (c->subs) {
|
||||
len = 20 - 1 - c->name_len;
|
||||
for(c_sub = c->subs; c_sub->alias; c_sub++) {
|
||||
if (c_sub->alias) {
|
||||
phpdbg_writeln(" %c %c %s %-*s %s",
|
||||
c->alias, c_sub->alias, (char *)c->name, len, c_sub->name, c_sub->tip);
|
||||
phpdbg_writeln("subcommand", "parent_alias=\"%c\" alias=\"%c\" parent=\"%s\" name=\"%-*s\" tip=\"%s\"", " %c %c %s %-*s %s",
|
||||
c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_xml("</helpcommands>");
|
||||
|
||||
/* Print out aliases for help as this one comes last, with the added text on how aliases are used */
|
||||
get_command("h", 1, &c, phpdbg_prompt_commands TSRMLS_CC);
|
||||
phpdbg_writeln(" %c %-20s %s\n", c->alias, c->name, c->tip);
|
||||
phpdbg_writeln("aliasinfo", "alias=\"%c\" name=\"%s\" tip=\"%s\"", " %c %-20s %s\n", c->alias, c->name, c->tip);
|
||||
|
||||
phpdbg_xml("<helpaliases>");
|
||||
|
||||
len = 20 - 1 - c->name_len;
|
||||
for(c_sub = c->subs; c_sub->alias; c_sub++) {
|
||||
if (c_sub->alias) {
|
||||
phpdbg_writeln(" %c %c %s %-*s %s",
|
||||
phpdbg_writeln("alias", "parent_alias=\"%c\" alias=\"%c\" parent=\"%s\" name=\"%-*s\" tip=\"%s\"", " %c %c %s %-*s %s",
|
||||
c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip);
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_xml("</helpaliases>");
|
||||
|
||||
pretty_print(get_help("aliases!" TSRMLS_CC) TSRMLS_CC);
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
@ -375,6 +388,7 @@ phpdbg_help_text_t phpdbg_help_text[] = {
|
|||
" **-S** **-S**cli Override SAPI name, careful!" CR
|
||||
" **-l** **-l**4000 Setup remote console ports" CR
|
||||
" **-a** **-a**192.168.0.3 Setup remote console bind address" CR
|
||||
" **-x** Enable xml output (instead of normal text output)" CR
|
||||
" **-V** Print version number" CR
|
||||
" **--** **--** arg1 arg2 Use to delimit phpdbg arguments and php $argv; append any $argv "
|
||||
"argument after it" CR CR
|
||||
|
@ -386,9 +400,7 @@ phpdbg_help_text_t phpdbg_help_text[] = {
|
|||
"bind address using the **-a** option. If **-a** is specied without an argument, then phpdbg "
|
||||
"will bind to all available interfaces. You should be aware of the security implications of "
|
||||
"doing this, so measures should be taken to secure this service if bound to a publicly accessible "
|
||||
"interface/port." CR CR
|
||||
|
||||
"Specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2."
|
||||
"interface/port."
|
||||
},
|
||||
|
||||
{"phpdbginit", CR
|
||||
|
@ -645,9 +657,11 @@ phpdbg_help_text_t phpdbg_help_text[] = {
|
|||
" **break** **b** show current breakpoints" CR
|
||||
" **files** **F** show included files" CR
|
||||
" **classes** **c** show loaded classes" CR
|
||||
" **funcs** **f** show loaded classes" CR
|
||||
" **funcs** **f** show loaded functions" CR
|
||||
" **error** **e** show last error" CR
|
||||
" **constants** **d** show user-defined constants" CR
|
||||
" **vars** **v** show active variables" CR
|
||||
" **globals** **g** show superglobal variables" CR
|
||||
" **literal** **l** show active literal constants" CR
|
||||
" **memory** **m** show memory manager stats"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -35,9 +35,9 @@ PHPDBG_HELP(aliases);
|
|||
extern const phpdbg_command_t phpdbg_help_commands[];
|
||||
|
||||
#define phpdbg_help_header() \
|
||||
phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
|
||||
phpdbg_notice("version", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
|
||||
#define phpdbg_help_footer() \
|
||||
phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
|
||||
phpdbg_notice("issues", "url=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES);
|
||||
|
||||
typedef struct _phpdbg_help_text_t {
|
||||
char *key;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -27,18 +27,20 @@
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[14])
|
||||
#define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s, flags) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[14], flags)
|
||||
|
||||
const phpdbg_command_t phpdbg_info_commands[] = {
|
||||
PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0),
|
||||
PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(constants, "show user defined constants", 'd', info_constants, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(globals, "show superglobals", 'g', info_globals, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
|
@ -59,18 +61,22 @@ PHPDBG_INFO(break) /* {{{ */
|
|||
|
||||
PHPDBG_INFO(files) /* {{{ */
|
||||
{
|
||||
HashPosition pos;
|
||||
char *fname;
|
||||
zend_string *fname;
|
||||
|
||||
phpdbg_notice("Included files: %d",
|
||||
zend_hash_num_elements(&EG(included_files)));
|
||||
phpdbg_try_access {
|
||||
phpdbg_notice("includedfilecount", "num=\"%d\"", "Included files: %d", zend_hash_num_elements(&EG(included_files)));
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Could not fetch included file count, invalid data source");
|
||||
return SUCCESS;
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos);
|
||||
while (zend_hash_get_current_key_ex(&EG(included_files), &fname,
|
||||
NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
|
||||
phpdbg_writeln("File: %s", fname);
|
||||
zend_hash_move_forward_ex(&EG(included_files), &pos);
|
||||
}
|
||||
phpdbg_try_access {
|
||||
ZEND_HASH_FOREACH_STR_KEY(&EG(included_files), fname) {
|
||||
phpdbg_writeln("includedfile", "name=\"%s\"", "File: %s", fname);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Could not fetch file name, invalid data source, aborting included file listing");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
@ -78,125 +84,189 @@ PHPDBG_INFO(files) /* {{{ */
|
|||
PHPDBG_INFO(error) /* {{{ */
|
||||
{
|
||||
if (PG(last_error_message)) {
|
||||
phpdbg_writeln("Last error: %s at %s line %d",
|
||||
PG(last_error_message), PG(last_error_file), PG(last_error_lineno));
|
||||
phpdbg_try_access {
|
||||
phpdbg_writeln("lasterror", "error=\"%s\" file=\"%s\" line=\"%d\"", "Last error: %s at %s line %d", PG(last_error_message), PG(last_error_file), PG(last_error_lineno));
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_notice("lasterror", "error=\"\"", "No error found!");
|
||||
} phpdbg_end_try_access();
|
||||
} else {
|
||||
phpdbg_notice("No error found!");
|
||||
phpdbg_notice("lasterror", "error=\"\"", "No error found!");
|
||||
}
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(vars) /* {{{ */
|
||||
PHPDBG_INFO(constants) /* {{{ */
|
||||
{
|
||||
HashTable consts;
|
||||
zend_constant *data;
|
||||
|
||||
zend_hash_init(&consts, 8, NULL, NULL, 0);
|
||||
|
||||
if (EG(zend_constants)) {
|
||||
phpdbg_try_access {
|
||||
ZEND_HASH_FOREACH_PTR(EG(zend_constants), data) {
|
||||
if (data->module_number == PHP_USER_CONSTANT) {
|
||||
zend_hash_update_ptr(&consts, data->name, data);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Cannot fetch all the constants, invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
}
|
||||
|
||||
phpdbg_notice("constantinfo", "num=\"%d\"", "User-defined constants (%d)", zend_hash_num_elements(&consts));
|
||||
|
||||
if (zend_hash_num_elements(&consts)) {
|
||||
phpdbg_out("Address Refs Type Constant\n");
|
||||
ZEND_HASH_FOREACH_PTR(&consts, data) {
|
||||
|
||||
#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("constant", "address=\"%p\" refcount=\"%d\" type=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %.*s" msg, &data->value, Z_REFCOUNT(data->value), zend_zval_type_name(&data->value), data->name->len, data->name->val, ##__VA_ARGS__)
|
||||
|
||||
switch (Z_TYPE(data->value)) {
|
||||
case IS_STRING:
|
||||
phpdbg_try_access {
|
||||
VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN(data->value), Z_STRLEN(data->value) < 255 ? Z_STRLEN(data->value) : 255, Z_STRVAL(data->value), Z_STRLEN(data->value) > 255 ? "..." : "");
|
||||
} phpdbg_catch_access {
|
||||
VARIABLEINFO("", "");
|
||||
} phpdbg_end_try_access();
|
||||
break;
|
||||
case IS_TRUE:
|
||||
VARIABLEINFO("value=\"true\"", "\nbool (true)");
|
||||
break;
|
||||
case IS_FALSE:
|
||||
VARIABLEINFO("value=\"false\"", "\nbool (false)");
|
||||
break;
|
||||
case IS_LONG:
|
||||
VARIABLEINFO("value=\"%ld\"", "\nint (%ld)", Z_LVAL(data->value));
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
VARIABLEINFO("value=\"%lf\"", "\ndouble (%lf)", Z_DVAL(data->value));
|
||||
break;
|
||||
default:
|
||||
VARIABLEINFO("", "");
|
||||
|
||||
#undef VARIABLEINFO
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
static int phpdbg_arm_auto_global(zend_auto_global *auto_global TSRMLS_DC) {
|
||||
if (auto_global->armed) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
|
||||
phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", auto_global->name->len, auto_global->name->val);
|
||||
} else {
|
||||
auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phpdbg_print_symbols(zend_bool show_globals TSRMLS_DC) {
|
||||
HashTable vars;
|
||||
HashPosition pos;
|
||||
char *var;
|
||||
zval **data;
|
||||
zend_array *symtable;
|
||||
zend_string *var;
|
||||
zval *data;
|
||||
|
||||
if (!EG(active_op_array)) {
|
||||
phpdbg_error("No active op array!");
|
||||
if (!EG(current_execute_data) || !EG(current_execute_data)->func) {
|
||||
phpdbg_error("inactive", "type=\"op_array\"", "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!");
|
||||
if (show_globals) {
|
||||
/* that array should only be manipulated during init, so safe for async access during execution */
|
||||
zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_arm_auto_global TSRMLS_CC);
|
||||
symtable = &EG(symbol_table);
|
||||
} else if (!(symtable = zend_rebuild_symbol_table(TSRMLS_C))) {
|
||||
phpdbg_error("inactive", "type=\"symbol_table\"", "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);
|
||||
phpdbg_try_access {
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(&symtable->ht, var, data) {
|
||||
if (zend_is_auto_global(var TSRMLS_CC) ^ !show_globals) {
|
||||
zend_hash_update(&vars, var, data);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Cannot fetch all data from the symbol table, invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
{
|
||||
zend_op_array *ops = EG(active_op_array);
|
||||
if (show_globals) {
|
||||
phpdbg_notice("variableinfo", "num=\"%d\"", "Superglobal variables (%d)", zend_hash_num_elements(&vars));
|
||||
} else {
|
||||
zend_op_array *ops = &EG(current_execute_data)->func->op_array;
|
||||
|
||||
if (ops->function_name) {
|
||||
if (ops->scope) {
|
||||
phpdbg_notice(
|
||||
"Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars));
|
||||
phpdbg_notice("variableinfo", "method=\"%s::%s\" num=\"%d\"", "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars));
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars));
|
||||
phpdbg_notice("variableinfo", "function=\"%s\" num=\"%d\"", "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars));
|
||||
}
|
||||
} else {
|
||||
if (ops->filename) {
|
||||
phpdbg_notice(
|
||||
"Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars));
|
||||
phpdbg_notice("variableinfo", "file=\"%s\" num=\"%d\"", "Variables in %s (%d)", ops->filename->val, zend_hash_num_elements(&vars));
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Variables @ %p (%d)", ops, zend_hash_num_elements(&vars));
|
||||
phpdbg_notice("variableinfo", "opline=\"%p\" num=\"%d\"", "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zend_hash_num_elements(&vars)) {
|
||||
phpdbg_writeln("Address\t\tRefs\tType\t\tVariable");
|
||||
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;
|
||||
phpdbg_out("Address Refs Type Variable\n");
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(&vars, var, data) {
|
||||
phpdbg_try_access {
|
||||
#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("variable", "address=\"%p\" refcount=\"%d\" type=\"%s\" refstatus=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %s$%.*s" msg, data, Z_REFCOUNT_P(data), zend_zval_type_name(data), Z_ISREF_P(data) ? "&": "", var->len, var->val, ##__VA_ARGS__)
|
||||
|
||||
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;
|
||||
switch (Z_TYPE_P(data)) {
|
||||
case IS_RESOURCE:
|
||||
phpdbg_try_access {
|
||||
const char *type = zend_rsrc_list_get_rsrc_type(Z_RES_P(data) TSRMLS_CC);
|
||||
VARIABLEINFO("type=\"%s\"", "\n|-------(typeof)------> (%s)\n", type ? type : "unknown");
|
||||
} phpdbg_catch_access {
|
||||
VARIABLEINFO("type=\"unknown\"", "\n|-------(typeof)------> (unknown)\n");
|
||||
} phpdbg_end_try_access();
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
phpdbg_try_access {
|
||||
VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (%s)\n", Z_OBJCE_P(data)->name);
|
||||
} phpdbg_catch_access {
|
||||
VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (unknown)\n");
|
||||
} phpdbg_end_try_access();
|
||||
break;
|
||||
case IS_STRING:
|
||||
phpdbg_try_access {
|
||||
VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN_P(data), Z_STRLEN_P(data) < 255 ? Z_STRLEN_P(data) : 255, Z_STRVAL_P(data), Z_STRLEN_P(data) > 255 ? "..." : "");
|
||||
} phpdbg_catch_access {
|
||||
VARIABLEINFO("", "");
|
||||
} phpdbg_end_try_access();
|
||||
break;
|
||||
case IS_TRUE:
|
||||
VARIABLEINFO("value=\"true\"", "\nbool (true)");
|
||||
break;
|
||||
case IS_FALSE:
|
||||
VARIABLEINFO("value=\"false\"", "\nbool (false)");
|
||||
break;
|
||||
case IS_LONG:
|
||||
VARIABLEINFO("value=\"%ld\"", "\nint (%ld)", Z_LVAL_P(data));
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
VARIABLEINFO("value=\"%lf\"", "\ndouble (%lf)", Z_DVAL_P(data));
|
||||
break;
|
||||
default:
|
||||
VARIABLEINFO("", "");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#undef VARIABLEINFO
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_writeln("variable", "address=\"%p\" name=\"%s\"", "%p\tn/a\tn/a\t$%s", data, var);
|
||||
} phpdbg_end_try_access();
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
zend_hash_destroy(&vars);
|
||||
|
@ -204,42 +274,48 @@ PHPDBG_INFO(vars) /* {{{ */
|
|||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(vars) /* {{{ */
|
||||
{
|
||||
return phpdbg_print_symbols(0 TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHPDBG_INFO(globals) /* {{{ */
|
||||
{
|
||||
return phpdbg_print_symbols(1 TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHPDBG_INFO(literal) /* {{{ */
|
||||
{
|
||||
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);
|
||||
/* literals are assumed to not be manipulated during executing of their op_array and as such async safe */
|
||||
zend_bool in_executor = PHPDBG_G(in_execution) && EG(current_execute_data) && EG(current_execute_data)->func;
|
||||
if (in_executor || PHPDBG_G(ops)) {
|
||||
zend_op_array *ops = in_executor ? &EG(current_execute_data)->func->op_array : PHPDBG_G(ops);
|
||||
int literal = 0, count = ops->last_literal-1;
|
||||
|
||||
if (ops->function_name) {
|
||||
if (ops->scope) {
|
||||
phpdbg_notice(
|
||||
"Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count);
|
||||
phpdbg_notice("literalinfo", "method=\"%s::%s\" num=\"%d\"", "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count);
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Literal Constants in %s() (%d)", ops->function_name, count);
|
||||
phpdbg_notice("literalinfo", "function=\"%s\" num=\"%d\"", "Literal Constants in %s() (%d)", ops->function_name, count);
|
||||
}
|
||||
} else {
|
||||
if (ops->filename) {
|
||||
phpdbg_notice(
|
||||
"Literal Constants in %s (%d)", ops->filename, count);
|
||||
phpdbg_notice("literalinfo", "file=\"%s\" num=\"%d\"", "Literal Constants in %s (%d)", ops->filename->val, count);
|
||||
} else {
|
||||
phpdbg_notice(
|
||||
"Literal Constants @ %p (%d)", ops, count);
|
||||
phpdbg_notice("literalinfo", "opline=\"%p\" num=\"%d\"", "Literal Constants @ %p (%d)", ops, count);
|
||||
}
|
||||
}
|
||||
|
||||
while (literal < ops->last_literal) {
|
||||
if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) {
|
||||
phpdbg_write("|-------- C%u -------> [", literal);
|
||||
zend_print_zval(
|
||||
&ops->literals[literal].constant, 0);
|
||||
phpdbg_write("]");
|
||||
phpdbg_writeln(EMPTY);
|
||||
if (Z_TYPE(ops->literals[literal]) != IS_NULL) {
|
||||
phpdbg_write("literal", "id=\"%u\"", "|-------- C%u -------> [", literal);
|
||||
zend_print_zval(&ops->literals[literal], 0 TSRMLS_CC);
|
||||
phpdbg_out("]\n");
|
||||
}
|
||||
literal++;
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("Not executing!");
|
||||
phpdbg_error("inactive", "type=\"execution\"", "Not executing!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -247,85 +323,84 @@ PHPDBG_INFO(literal) /* {{{ */
|
|||
|
||||
PHPDBG_INFO(memory) /* {{{ */
|
||||
{
|
||||
if (is_zend_mm(TSRMLS_C)) {
|
||||
phpdbg_notice("Memory Manager Information");
|
||||
phpdbg_notice("Current");
|
||||
phpdbg_writeln("|-------> Used:\t%.3f kB",
|
||||
(float) (zend_memory_usage(0 TSRMLS_CC)/1024));
|
||||
phpdbg_writeln("|-------> Real:\t%.3f kB",
|
||||
(float) (zend_memory_usage(1 TSRMLS_CC)/1024));
|
||||
phpdbg_notice("Peak");
|
||||
phpdbg_writeln("|-------> Used:\t%.3f kB",
|
||||
(float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024));
|
||||
phpdbg_writeln("|-------> Real:\t%.3f kB",
|
||||
(float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024));
|
||||
size_t used, real, peak_used, peak_real;
|
||||
zend_mm_heap *heap;
|
||||
zend_bool is_mm;
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
|
||||
heap = zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC);
|
||||
}
|
||||
if ((is_mm = is_zend_mm(TSRMLS_C))) {
|
||||
used = zend_memory_usage(0 TSRMLS_CC);
|
||||
real = zend_memory_usage(1 TSRMLS_CC);
|
||||
peak_used = zend_memory_peak_usage(0 TSRMLS_CC);
|
||||
peak_real = zend_memory_peak_usage(1 TSRMLS_CC);
|
||||
}
|
||||
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
|
||||
zend_mm_set_heap(heap TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (is_mm) {
|
||||
phpdbg_notice("meminfo", "", "Memory Manager Information");
|
||||
phpdbg_notice("current", "", "Current");
|
||||
phpdbg_writeln("used", "mem=\"%.3f\"", "|-------> Used:\t%.3f kB", (float) (used / 1024));
|
||||
phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (real / 1024));
|
||||
phpdbg_notice("peak", "", "Peak");
|
||||
phpdbg_writeln("used", "mem=\"%.3f\"", "|-------> Used:\t%.3f kB", (float) (peak_used / 1024));
|
||||
phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (peak_real / 1024));
|
||||
} else {
|
||||
phpdbg_error("Memory Manager Disabled!");
|
||||
phpdbg_error("inactive", "type=\"memory_manager\"", "Memory Manager Disabled!");
|
||||
}
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */
|
||||
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));
|
||||
const char *visibility = ce->type == ZEND_USER_CLASS ? "User" : "Internal";
|
||||
const char *type = (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : (ce->ce_flags & ZEND_ACC_ABSTRACT) ? "Abstract Class" : "Class";
|
||||
|
||||
phpdbg_writeln("class", "type=\"%s\" flags=\"%s\" name=\"%.*s\" methodcount=\"%d\"", "%s %s %.*s (%d)", visibility, type, ce->name->len, ce->name->val, zend_hash_num_elements(&ce->function_table));
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_INFO(classes) /* {{{ */
|
||||
{
|
||||
HashPosition position;
|
||||
zend_class_entry **ce;
|
||||
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_try_access {
|
||||
ZEND_HASH_FOREACH_PTR(EG(class_table), ce) {
|
||||
if (ce->type == ZEND_USER_CLASS) {
|
||||
zend_hash_next_index_insert_ptr(&classes, ce);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_notice("signalsegv", "", "Not all classes could be fetched, possibly invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
phpdbg_notice("User Classes (%d)",
|
||||
zend_hash_num_elements(&classes));
|
||||
|
||||
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_notice("classinfo", "num=\"%d\"", "User Classes (%d)", zend_hash_num_elements(&classes));
|
||||
|
||||
/* once added, assume that classes are stable... until shutdown. */
|
||||
ZEND_HASH_FOREACH_PTR(&classes, ce) {
|
||||
phpdbg_print_class_name(ce TSRMLS_CC);
|
||||
phpdbg_writeln(EMPTY);
|
||||
|
||||
if ((*ce)->parent) {
|
||||
zend_class_entry *pce = (*ce)->parent;
|
||||
if (ce->parent) {
|
||||
phpdbg_xml("<parents %r>");
|
||||
zend_class_entry *pce = ce->parent;
|
||||
do {
|
||||
phpdbg_write("|-------- ");
|
||||
phpdbg_print_class_name(&pce TSRMLS_CC);
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_out("|-------- ");
|
||||
phpdbg_print_class_name(pce TSRMLS_CC);
|
||||
} while ((pce = pce->parent));
|
||||
phpdbg_xml("</parents>");
|
||||
}
|
||||
|
||||
if ((*ce)->info.user.filename) {
|
||||
phpdbg_writeln(
|
||||
"|---- in %s on line %u",
|
||||
(*ce)->info.user.filename,
|
||||
(*ce)->info.user.line_start);
|
||||
if (ce->info.user.filename) {
|
||||
phpdbg_writeln("classsource", "file=\"%s\" line=\"%u\"", "|---- in %s on line %u", ce->info.user.filename->val, ce->info.user.line_start);
|
||||
} else {
|
||||
phpdbg_writeln("|---- no source code");
|
||||
}
|
||||
phpdbg_writeln(EMPTY);
|
||||
phpdbg_writeln("classsource", "", "|---- no source code");
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
zend_hash_destroy(&classes);
|
||||
|
||||
|
@ -334,36 +409,34 @@ PHPDBG_INFO(classes) /* {{{ */
|
|||
|
||||
PHPDBG_INFO(funcs) /* {{{ */
|
||||
{
|
||||
HashPosition position;
|
||||
zend_function *zf, **pzf;
|
||||
zend_function *zf;
|
||||
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)) {
|
||||
|
||||
phpdbg_try_access {
|
||||
ZEND_HASH_FOREACH_PTR(EG(function_table), zf) {
|
||||
if (zf->type == ZEND_USER_FUNCTION) {
|
||||
zend_hash_next_index_insert(
|
||||
&functions, (void**) &zf, sizeof(zend_function), NULL);
|
||||
zend_hash_next_index_insert_ptr(&functions, zf);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_notice("signalsegv", "", "Not all functions could be fetched, possibly invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
phpdbg_notice("functioninfo", "num=\"%d\"", "User Functions (%d)", zend_hash_num_elements(&functions));
|
||||
|
||||
ZEND_HASH_FOREACH_PTR(&functions, zf) {
|
||||
zend_op_array *op_array = &zf->op_array;
|
||||
|
||||
phpdbg_write("function", "name=\"%s\"", "|-------- %s", op_array->function_name ? op_array->function_name->val : "{main}");
|
||||
|
||||
if (op_array->filename) {
|
||||
phpdbg_writeln("functionsource", "file=\"%s\" line=\"%d\"", " in %s on line %d", op_array->filename->val, op_array->line_start);
|
||||
} else {
|
||||
phpdbg_writeln("functionsource", "", " (no source code)");
|
||||
}
|
||||
|
||||
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_FOREACH_END();
|
||||
|
||||
zend_hash_destroy(&functions);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -30,7 +30,9 @@ PHPDBG_INFO(break);
|
|||
PHPDBG_INFO(classes);
|
||||
PHPDBG_INFO(funcs);
|
||||
PHPDBG_INFO(error);
|
||||
PHPDBG_INFO(constants);
|
||||
PHPDBG_INFO(vars);
|
||||
PHPDBG_INFO(globals);
|
||||
PHPDBG_INFO(literal);
|
||||
PHPDBG_INFO(memory);
|
||||
|
||||
|
|
272
sapi/phpdbg/phpdbg_io.c
Normal file
272
sapi/phpdbg/phpdbg_io.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anatol Belski <ab@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "phpdbg_io.h"
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#undef UNICODE
|
||||
#include "win32/inet.h"
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include "win32/sockets.h"
|
||||
|
||||
#else
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#if HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC) {
|
||||
int got_now, i = len, j;
|
||||
char *p = ptr;
|
||||
#ifndef PHP_WIN32
|
||||
struct pollfd pfd;
|
||||
|
||||
if (tmo < 0) goto recv_once;
|
||||
pfd.fd = sock;
|
||||
pfd.events = POLLIN;
|
||||
|
||||
j = poll(&pfd, 1, tmo);
|
||||
|
||||
if (j == 0) {
|
||||
#else
|
||||
struct fd_set readfds;
|
||||
struct timeval ttmo;
|
||||
|
||||
if (tmo < 0) goto recv_once;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(sock, &readfds);
|
||||
|
||||
ttmo.tv_sec = 0;
|
||||
ttmo.tv_usec = tmo*1000;
|
||||
|
||||
j = select(0, &readfds, NULL, NULL, &ttmo);
|
||||
|
||||
if (j <= 0) {
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
recv_once:
|
||||
while(i > 0) {
|
||||
if (tmo < 0) {
|
||||
/* There's something to read. Read what's available and proceed
|
||||
disregarding whether len could be exhausted or not.*/
|
||||
int can_read = recv(sock, p, i, MSG_PEEK);
|
||||
#ifndef _WIN32
|
||||
if (can_read == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
i = can_read;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
got_now = recv(sock, p, i, 0);
|
||||
#else
|
||||
do {
|
||||
got_now = recv(sock, p, i, 0);
|
||||
} while (got_now == -1 && errno == EINTR);
|
||||
#endif
|
||||
|
||||
if (got_now == -1) {
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Read operation timed out!\n"));
|
||||
return -1;
|
||||
}
|
||||
i -= got_now;
|
||||
p += got_now;
|
||||
}
|
||||
|
||||
return p - ptr;
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len) {
|
||||
int sent, i = len;
|
||||
const char *p = ptr;
|
||||
/* XXX poll/select needed here? */
|
||||
while(i > 0) {
|
||||
sent = send(sock, p, i, 0);
|
||||
if (sent == -1) {
|
||||
return -1;
|
||||
}
|
||||
i -= sent;
|
||||
p += sent;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
|
||||
return phpdbg_consume_bytes(sock, ptr, len, tmo TSRMLS_CC);
|
||||
}
|
||||
|
||||
return read(sock, ptr, len);
|
||||
}
|
||||
|
||||
|
||||
PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
|
||||
return phpdbg_send_bytes(sock, ptr, len);
|
||||
}
|
||||
|
||||
return write(sock, ptr, len);
|
||||
}
|
||||
|
||||
|
||||
PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC) {
|
||||
struct addrinfo res;
|
||||
int fd = phpdbg_create_listenable_socket(interface, port, &res TSRMLS_CC);
|
||||
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(fd, res.ai_addr, res.ai_addrlen) == -1) {
|
||||
phpdbg_close_socket(fd);
|
||||
return -4;
|
||||
}
|
||||
|
||||
listen(fd, 5);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *addr_res TSRMLS_DC) {
|
||||
int sock = -1, rc;
|
||||
int reuse = 1;
|
||||
struct in6_addr serveraddr;
|
||||
struct addrinfo hints, *res = NULL;
|
||||
char port_buf[8];
|
||||
int8_t any_addr = *addr == '*';
|
||||
|
||||
do {
|
||||
memset(&hints, 0, sizeof hints);
|
||||
if (any_addr) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
} else {
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
}
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
rc = inet_pton(AF_INET, addr, &serveraddr);
|
||||
if (1 == rc) {
|
||||
hints.ai_family = AF_INET;
|
||||
if (!any_addr) {
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
} else {
|
||||
rc = inet_pton(AF_INET6, addr, &serveraddr);
|
||||
if (1 == rc) {
|
||||
hints.ai_family = AF_INET6;
|
||||
if (!any_addr) {
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
} else {
|
||||
/* XXX get host by name ??? */
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(port_buf, 7, "%u", port);
|
||||
if (!any_addr) {
|
||||
rc = getaddrinfo(addr, port_buf, &hints, &res);
|
||||
} else {
|
||||
rc = getaddrinfo(NULL, port_buf, &hints, &res);
|
||||
}
|
||||
|
||||
if (0 != rc) {
|
||||
#ifndef PHP_WIN32
|
||||
if (rc == EAI_SYSTEM) {
|
||||
char buf[128];
|
||||
int wrote;
|
||||
|
||||
wrote = snprintf(buf, 128, "Could not translate address '%s'", addr);
|
||||
buf[wrote] = '\0';
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
|
||||
|
||||
return sock;
|
||||
} else {
|
||||
#endif
|
||||
char buf[256];
|
||||
int wrote;
|
||||
|
||||
wrote = snprintf(buf, 256, "Host '%s' not found. %s", addr, estrdup(gai_strerror(rc)));
|
||||
buf[wrote] = '\0';
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
|
||||
|
||||
return sock;
|
||||
#ifndef PHP_WIN32
|
||||
}
|
||||
#endif
|
||||
return sock;
|
||||
}
|
||||
|
||||
if((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
|
||||
char buf[128];
|
||||
int wrote;
|
||||
|
||||
wrote = sprintf(buf, "Unable to create socket");
|
||||
buf[wrote] = '\0';
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)) == -1) {
|
||||
phpdbg_close_socket(sock);
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
} while (0);
|
||||
|
||||
*addr_res = *res;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
PHPDBG_API void phpdbg_close_socket(int sock) {
|
||||
if (socket >= 0) {
|
||||
#ifdef _WIN32
|
||||
closesocket(sock);
|
||||
#else
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
34
sapi/phpdbg/phpdbg_io.h
Normal file
34
sapi/phpdbg/phpdbg_io.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anatol Belski <ab@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_IO_H
|
||||
#define PHPDBG_IO_H
|
||||
|
||||
#include "phpdbg.h"
|
||||
|
||||
PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len);
|
||||
PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC);
|
||||
|
||||
PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *res TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC);
|
||||
PHPDBG_API void phpdbg_close_socket(int sock);
|
||||
|
||||
#endif /* PHPDBG_IO_H */
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
#define YYFILL(n)
|
||||
|
||||
#define NORMAL 0
|
||||
#define RAW 1
|
||||
#define INITIAL 2
|
||||
#define PRE_RAW 1
|
||||
#define RAW 2
|
||||
#define INITIAL 3
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
|
@ -65,10 +66,17 @@ INPUT [^\n\000]+
|
|||
|
||||
<!*> := yyleng = (size_t) YYCURSOR - (size_t) yytext;
|
||||
|
||||
<*>[\n\000] {
|
||||
<*>{WS}?[\n\000] {
|
||||
return 0;
|
||||
}
|
||||
|
||||
<PRE_RAW, NORMAL>[-][r]{WS}?{DIGITS} {
|
||||
char *text = yytext + 2;
|
||||
while (*++text < '0');
|
||||
yylval->num = atoi(text);
|
||||
return T_REQ_ID;
|
||||
}
|
||||
|
||||
<NORMAL>{T_IF}{WS} {
|
||||
YYSETCONDITION(RAW);
|
||||
phpdbg_init_param(yylval, EMPTY_PARAM);
|
||||
|
@ -143,21 +151,28 @@ INPUT [^\n\000]+
|
|||
}
|
||||
|
||||
<INITIAL>{T_EVAL}{WS} {
|
||||
YYSETCONDITION(RAW);
|
||||
YYSETCONDITION(PRE_RAW);
|
||||
phpdbg_init_param(yylval, EMPTY_PARAM);
|
||||
return T_EVAL;
|
||||
}
|
||||
<INITIAL>{T_SHELL}{WS} {
|
||||
YYSETCONDITION(RAW);
|
||||
YYSETCONDITION(PRE_RAW);
|
||||
phpdbg_init_param(yylval, EMPTY_PARAM);
|
||||
return T_SHELL;
|
||||
}
|
||||
<INITIAL>({T_RUN}|{T_RUN_SHORT}){WS} {
|
||||
YYSETCONDITION(RAW);
|
||||
YYSETCONDITION(PRE_RAW);
|
||||
phpdbg_init_param(yylval, EMPTY_PARAM);
|
||||
return T_RUN;
|
||||
}
|
||||
|
||||
<PRE_RAW>. {
|
||||
YYSETCONDITION(RAW);
|
||||
|
||||
YYCURSOR = LEX(text);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
<INITIAL>. {
|
||||
YYSETCONDITION(NORMAL);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -34,35 +34,37 @@
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13])
|
||||
#define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s, flags) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13], flags)
|
||||
|
||||
const phpdbg_command_t phpdbg_list_commands[] = {
|
||||
PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l"),
|
||||
PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s"),
|
||||
PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m"),
|
||||
PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s"),
|
||||
PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
PHPDBG_LIST(lines) /* {{{ */
|
||||
{
|
||||
if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) {
|
||||
phpdbg_error("Not executing, and execution context not set");
|
||||
phpdbg_error("inactive", "type=\"execution\"", "Not executing, and execution context not set");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (param->type) {
|
||||
case NUMERIC_PARAM:
|
||||
phpdbg_list_file(phpdbg_current_file(TSRMLS_C),
|
||||
(param->num < 0 ? 1 - param->num : param->num),
|
||||
(param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C),
|
||||
0 TSRMLS_CC);
|
||||
break;
|
||||
case NUMERIC_PARAM: {
|
||||
const char *char_file = phpdbg_current_file(TSRMLS_C);
|
||||
zend_string *file = zend_string_init(char_file, strlen(char_file), 0);
|
||||
phpdbg_list_file(file, param->num < 0 ? 1 - param->num : param->num, (param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), 0 TSRMLS_CC);
|
||||
efree(file);
|
||||
} break;
|
||||
|
||||
case FILE_PARAM:
|
||||
phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC);
|
||||
break;
|
||||
case FILE_PARAM: {
|
||||
zend_string *file = zend_string_init(param->file.name, strlen(param->file.name), 0);
|
||||
phpdbg_list_file(file, param->file.line, 0, 0 TSRMLS_CC);
|
||||
efree(file);
|
||||
} break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
@ -79,21 +81,21 @@ PHPDBG_LIST(func) /* {{{ */
|
|||
|
||||
PHPDBG_LIST(method) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
zend_class_entry *ce;
|
||||
|
||||
if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
zend_function *function;
|
||||
char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
|
||||
|
||||
if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) {
|
||||
if ((function = zend_hash_str_find_ptr(&ce->function_table, lcname, strlen(lcname)))) {
|
||||
phpdbg_list_function(function TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Could not find %s::%s", param->method.class, param->method.name);
|
||||
phpdbg_error("list", "type=\"notfound\" method=\"%s::%s\"", "Could not find %s::%s", param->method.class, param->method.name);
|
||||
}
|
||||
|
||||
efree(lcname);
|
||||
} else {
|
||||
phpdbg_error("Could not find the class %s", param->method.class);
|
||||
phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "Could not find the class %s", param->method.class);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -101,47 +103,32 @@ PHPDBG_LIST(method) /* {{{ */
|
|||
|
||||
PHPDBG_LIST(class) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
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
|
||||
);
|
||||
if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
if (ce->type == ZEND_USER_CLASS) {
|
||||
if (ce->info.user.filename) {
|
||||
phpdbg_list_file(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);
|
||||
phpdbg_error("list", "type=\"nosource\" class=\"%s\"", "The source of the requested class (%s) cannot be found", ce->name);
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("The class requested (%s) is not user defined", (*ce)->name);
|
||||
phpdbg_error("list", "type=\"internalclass\" class=\"%s\"", "The class requested (%s) is not user defined", ce->name);
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("The requested class (%s) could not be found", param->str);
|
||||
phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "The requested class (%s) could not be found", param->str);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */
|
||||
void phpdbg_list_file(zend_string *filename, uint count, int offset, uint highlight TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
struct stat st;
|
||||
char *opened = NULL;
|
||||
char buffer[8096] = {0,};
|
||||
long line = 0;
|
||||
uint line, lastline;
|
||||
phpdbg_file_source *data;
|
||||
|
||||
php_stream *stream = NULL;
|
||||
|
||||
if (VCWD_STAT(filename, &st) == FAILURE) {
|
||||
phpdbg_error("Failed to stat file %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = php_stream_open_wrapper(filename, "rb", USE_PATH, &opened);
|
||||
|
||||
if (!stream) {
|
||||
phpdbg_error("Failed to open file %s to list", filename);
|
||||
if (!(data = zend_hash_find_ptr(&PHPDBG_G(file_sources), filename))) {
|
||||
phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -150,33 +137,35 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig
|
|||
offset = 0;
|
||||
}
|
||||
|
||||
while (php_stream_gets(stream, buffer, sizeof(buffer)) != NULL) {
|
||||
long linelen = strlen(buffer);
|
||||
lastline = offset + count;
|
||||
|
||||
++line;
|
||||
if (lastline > data->lines) {
|
||||
lastline = data->lines;
|
||||
}
|
||||
|
||||
phpdbg_xml("<list %r file=\"%s\">", filename);
|
||||
|
||||
for (line = offset; line < lastline;) {
|
||||
uint linestart = data->line[line++];
|
||||
uint linelen = data->line[line] - linestart;
|
||||
char *buffer = data->buf + linestart;
|
||||
|
||||
if (offset <= line) {
|
||||
if (!highlight) {
|
||||
phpdbg_write("%05ld: %s", line, buffer);
|
||||
phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer);
|
||||
} else {
|
||||
if (highlight != line) {
|
||||
phpdbg_write(" %05ld: %s", line, buffer);
|
||||
phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer);
|
||||
} else {
|
||||
phpdbg_write(">%05ld: %s", line, buffer);
|
||||
phpdbg_write("line", "line=\"%u\" code=\"%.*s\" current=\"current\"", ">%05u: %.*s", line, linelen, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer[linelen - 1] != '\n') {
|
||||
phpdbg_write("\n");
|
||||
if (*(buffer + linelen - 1) != '\n' || !linelen) {
|
||||
phpdbg_out("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0 && count + offset - 1 < line) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
php_stream_close(stream);
|
||||
phpdbg_xml("</list>");
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */
|
||||
|
@ -184,14 +173,13 @@ void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */
|
|||
const zend_op_array *ops;
|
||||
|
||||
if (fbc->type != ZEND_USER_FUNCTION) {
|
||||
phpdbg_error("The function requested (%s) is not user defined", fbc->common.function_name);
|
||||
phpdbg_error("list", "type=\"internalfunction\" function=\"%s\"", "The function requested (%s) is not user defined", fbc->common.function_name);
|
||||
return;
|
||||
}
|
||||
|
||||
ops = (zend_op_array *) fbc;
|
||||
|
||||
phpdbg_list_file(ops->filename,
|
||||
ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC);
|
||||
phpdbg_list_file(ops->filename, ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC);
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */
|
||||
|
@ -209,11 +197,11 @@ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ *
|
|||
|
||||
func_table = &EG(scope)->function_table;
|
||||
} else {
|
||||
phpdbg_error("No active class");
|
||||
phpdbg_error("inactive", "type=\"noclasses\"", "No active class");
|
||||
return;
|
||||
}
|
||||
} else if (!EG(function_table)) {
|
||||
phpdbg_error("No function table loaded");
|
||||
phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded");
|
||||
return;
|
||||
} else {
|
||||
func_table = EG(function_table);
|
||||
|
@ -222,12 +210,87 @@ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ *
|
|||
/* use lowercase names, case insensitive */
|
||||
func_name = zend_str_tolower_dup(func_name, func_name_len);
|
||||
|
||||
if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_try_access {
|
||||
if ((fbc = zend_hash_str_find_ptr(func_table, func_name, func_name_len))) {
|
||||
phpdbg_list_function(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Function %s not found", func_name);
|
||||
phpdbg_error("list", "type=\"nofunction\" function=\"%s\"", "Function %s not found", func_name);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "function=\"%s\"", "Could not list function %s, invalid data source", func_name);
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
efree(func_name);
|
||||
} /* }}} */
|
||||
|
||||
zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) {
|
||||
phpdbg_file_source data, *dataptr;
|
||||
zend_file_handle fake = {{0}};
|
||||
zend_op_array *ret;
|
||||
char *filename = (char *)(file->opened_path ? file->opened_path : file->filename);
|
||||
uint line;
|
||||
char *bufptr, *endptr;
|
||||
|
||||
zend_stream_fixup(file, &data.buf, &data.len TSRMLS_CC);
|
||||
|
||||
data.filename = filename;
|
||||
data.line[0] = 0;
|
||||
|
||||
if (file->handle.stream.mmap.old_closer) {
|
||||
/* do not unmap */
|
||||
file->handle.stream.closer = file->handle.stream.mmap.old_closer;
|
||||
}
|
||||
|
||||
#if HAVE_MMAP
|
||||
if (file->handle.stream.mmap.map) {
|
||||
data.map = file->handle.stream.mmap.map;
|
||||
}
|
||||
#endif
|
||||
|
||||
fake.type = ZEND_HANDLE_MAPPED;
|
||||
fake.handle.stream.mmap.buf = data.buf;
|
||||
fake.handle.stream.mmap.len = data.len;
|
||||
fake.free_filename = 0;
|
||||
fake.opened_path = file->opened_path;
|
||||
fake.filename = filename;
|
||||
fake.opened_path = file->opened_path;
|
||||
|
||||
*(dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * data.len)) = data;
|
||||
|
||||
for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) {
|
||||
if (*bufptr == '\n') {
|
||||
dataptr->line[++line] = (uint)(bufptr - data.buf) + 1;
|
||||
}
|
||||
}
|
||||
dataptr->lines = ++line;
|
||||
dataptr->line[line] = endptr - data.buf;
|
||||
dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
|
||||
|
||||
zend_hash_str_add_ptr(&PHPDBG_G(file_sources), filename, strlen(filename), dataptr);
|
||||
|
||||
ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC);
|
||||
|
||||
fake.opened_path = NULL;
|
||||
zend_file_handle_dtor(&fake TSRMLS_CC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void phpdbg_free_file_source(phpdbg_file_source *data) {
|
||||
#if HAVE_MMAP
|
||||
if (data->map) {
|
||||
munmap(data->map, data->len + ZEND_MMAP_AHEAD);
|
||||
} else
|
||||
#endif
|
||||
if (data->buf) {
|
||||
efree(data->buf);
|
||||
}
|
||||
|
||||
efree(data);
|
||||
}
|
||||
|
||||
void phpdbg_init_list(TSRMLS_D) {
|
||||
PHPDBG_G(compile_file) = zend_compile_file;
|
||||
zend_hash_init(&PHPDBG_G(file_sources), 1, NULL, (dtor_func_t) phpdbg_free_file_source, 0);
|
||||
zend_compile_file = phpdbg_compile_file;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -34,8 +34,21 @@ PHPDBG_LIST(func);
|
|||
|
||||
void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC);
|
||||
void phpdbg_list_function(const zend_function * TSRMLS_DC);
|
||||
void phpdbg_list_file(const char*, long, long, int TSRMLS_DC);
|
||||
void phpdbg_list_file(zend_string *, uint, int, uint TSRMLS_DC);
|
||||
|
||||
extern const phpdbg_command_t phpdbg_list_commands[];
|
||||
|
||||
void phpdbg_init_list(TSRMLS_D);
|
||||
|
||||
typedef struct {
|
||||
char *filename;
|
||||
char *buf;
|
||||
size_t len;
|
||||
#if HAVE_MMAP
|
||||
void *map;
|
||||
#endif
|
||||
uint lines;
|
||||
uint line[1];
|
||||
} phpdbg_file_source;
|
||||
|
||||
#endif /* PHPDBG_LIST_H */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
static inline uint32_t phpdbg_decode_literal(zend_op_array *ops, zend_literal *literal TSRMLS_DC) /* {{{ */
|
||||
static inline uint32_t phpdbg_decode_literal(zend_op_array *ops, zval *literal TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
int iter = 0;
|
||||
|
||||
|
@ -46,26 +46,25 @@ static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, uint32_t
|
|||
|
||||
switch (type &~ EXT_TYPE_UNUSED) {
|
||||
case IS_CV:
|
||||
asprintf(&decode, "$%s", ops->vars[op->var].name);
|
||||
asprintf(&decode, "$%s", ops->vars[EX_VAR_TO_NUM(op->var)]->val);
|
||||
break;
|
||||
|
||||
case IS_VAR:
|
||||
case IS_TMP_VAR: {
|
||||
zend_ulong id = 0, *pid = NULL;
|
||||
if (vars != NULL) {
|
||||
if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) {
|
||||
if ((pid = zend_hash_index_find_ptr(vars, (zend_ulong) ops->vars - op->var))) {
|
||||
id = *pid;
|
||||
} else {
|
||||
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;
|
||||
zend_hash_index_update_mem(vars, (zend_ulong) ops->vars - op->var, &id, sizeof(zend_ulong));
|
||||
}
|
||||
asprintf(&decode, "@%lu", id);
|
||||
}
|
||||
asprintf(&decode, "@%llu", id);
|
||||
} break;
|
||||
|
||||
case IS_CONST:
|
||||
asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->literal TSRMLS_CC));
|
||||
asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->zv TSRMLS_CC));
|
||||
break;
|
||||
|
||||
case IS_UNUSED:
|
||||
|
@ -92,8 +91,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM
|
|||
|
||||
case ZEND_JMPZNZ:
|
||||
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||
asprintf(
|
||||
&decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value);
|
||||
asprintf(&decode[2], "J%u or J%llu", op->op2.opline_num, op->extended_value);
|
||||
goto result;
|
||||
|
||||
case ZEND_JMPZ:
|
||||
|
@ -105,8 +103,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM
|
|||
case ZEND_JMP_SET:
|
||||
#endif
|
||||
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||
asprintf(
|
||||
&decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes);
|
||||
asprintf(&decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes);
|
||||
goto result;
|
||||
|
||||
case ZEND_RECV_INIT:
|
||||
|
@ -118,8 +115,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM
|
|||
result:
|
||||
decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC);
|
||||
format:
|
||||
asprintf(
|
||||
&decode[0],
|
||||
asprintf(&decode[0],
|
||||
"%-20s %-20s %-20s",
|
||||
decode[1] ? decode[1] : "",
|
||||
decode[2] ? decode[2] : "",
|
||||
|
@ -145,26 +141,26 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, ze
|
|||
(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);
|
||||
zend_op *opline = (zend_op *) execute_data->opline;
|
||||
char *decode = phpdbg_decode_opline(&execute_data->func->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",
|
||||
phpdbg_notice("opline", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\" file=\"%s\"", "L%-5u %16p %-30s %s %s",
|
||||
opline->lineno,
|
||||
opline,
|
||||
phpdbg_decode_opcode(opline->opcode),
|
||||
decode,
|
||||
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
||||
execute_data->func->op_array.filename ? execute_data->func->op_array.filename->val : "unknown");
|
||||
}
|
||||
|
||||
if (!ignore_flags && PHPDBG_G(oplog)) {
|
||||
phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s",
|
||||
phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %-30s %s %s",
|
||||
opline->lineno,
|
||||
opline,
|
||||
phpdbg_decode_opcode(opline->opcode),
|
||||
decode,
|
||||
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
||||
execute_data->func->op_array.filename ? execute_data->func->op_array.filename->val : "unknown");
|
||||
}
|
||||
|
||||
if (decode) {
|
||||
|
@ -180,179 +176,6 @@ void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags
|
|||
|
||||
const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
|
||||
{
|
||||
#if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO
|
||||
#define CASE(s) case s: return #s
|
||||
switch (opcode) {
|
||||
CASE(ZEND_NOP);
|
||||
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_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_LIST);
|
||||
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_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";
|
||||
}
|
||||
#else
|
||||
const char *ret = zend_get_opcode_name(opcode);
|
||||
return ret?ret:"UNKNOWN";
|
||||
#endif
|
||||
} /* }}} */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
1306
sapi/phpdbg/phpdbg_out.c
Normal file
1306
sapi/phpdbg/phpdbg_out.c
Normal file
File diff suppressed because it is too large
Load diff
93
sapi/phpdbg/phpdbg_out.h
Normal file
93
sapi/phpdbg/phpdbg_out.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_OUT_H
|
||||
#define PHPDBG_OUT_H
|
||||
|
||||
/**
|
||||
* Error/notice/formatting helpers
|
||||
*/
|
||||
enum {
|
||||
P_ERROR = 1,
|
||||
P_NOTICE,
|
||||
P_WRITELN,
|
||||
P_WRITE,
|
||||
P_STDOUT,
|
||||
P_STDERR,
|
||||
P_LOG
|
||||
};
|
||||
|
||||
#ifdef ZTS
|
||||
PHPDBG_API int phpdbg_print(int severity TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 6, 7);
|
||||
PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
|
||||
PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
|
||||
PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
|
||||
PHPDBG_API int phpdbg_rlog_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
|
||||
#else
|
||||
PHPDBG_API int phpdbg_print(int severity, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6);
|
||||
PHPDBG_API int phpdbg_xml_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
|
||||
PHPDBG_API int phpdbg_log_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
|
||||
PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
|
||||
PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
|
||||
#endif
|
||||
|
||||
|
||||
#define phpdbg_error(tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_notice(tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_writeln(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_write(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_script(type, fmt, ...) phpdbg_print(type TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, NULL, NULL, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_log(fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_xml(fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_out(fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define phpdbg_error_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_notice_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_writeln_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_write_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_script_ex(out, type, fmt, ...) phpdbg_print(type TSRMLS_CC, out, NULL, NULL, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_log_ex(out, fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_xml_ex(out, fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_out_ex(out, fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define phpdbg_rlog(fd, fmt, ...) phpdbg_rlog_internal(fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define phpdbg_xml_asprintf(buf, ...) _phpdbg_xml_asprintf(buf TSRMLS_CC, ##__VA_ARGS__)
|
||||
PHPDBG_API int _phpdbg_xml_asprintf(char **buf TSRMLS_DC, const char *format, zend_bool escape_xml, ...);
|
||||
|
||||
#define phpdbg_asprintf(buf, ...) _phpdbg_asprintf(buf TSRMLS_CC, ##__VA_ARGS__)
|
||||
PHPDBG_API int _phpdbg_asprintf(char **buf TSRMLS_DC, const char *format, ...);
|
||||
|
||||
|
||||
#if PHPDBG_DEBUG
|
||||
# define phpdbg_debug(fmt, ...) phpdbg_log_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define phpdbg_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
PHPDBG_API void phpdbg_free_err_buf(TSRMLS_D);
|
||||
PHPDBG_API void phpdbg_activate_err_buf(zend_bool active TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const char *strfmt TSRMLS_DC, ...);
|
||||
|
||||
|
||||
/* {{{ For separation */
|
||||
#define SEPARATE "------------------------------------------------" /* }}} */
|
||||
|
||||
#endif /* PHPDBG_OUT_H */
|
|
@ -1,4 +1,4 @@
|
|||
/* A Bison parser, made by GNU Bison 2.6.2. */
|
||||
/* A Bison parser, made by GNU Bison 2.6. */
|
||||
|
||||
/* Bison implementation for Yacc-like parsers in C
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
|||
#define YYBISON 1
|
||||
|
||||
/* Bison version. */
|
||||
#define YYBISON_VERSION "2.6.2"
|
||||
#define YYBISON_VERSION "2.6"
|
||||
|
||||
/* Skeleton name. */
|
||||
#define YYSKELETON_NAME "yacc.c"
|
||||
|
@ -69,8 +69,9 @@
|
|||
#define yynerrs phpdbg_nerrs
|
||||
|
||||
/* Copy the first part of user declarations. */
|
||||
|
||||
/* Line 336 of yacc.c */
|
||||
#line 1 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
#line 1 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -97,8 +98,9 @@ static int yyerror(void ***tsrm_ls, const char *msg);
|
|||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
|
||||
|
||||
/* Line 336 of yacc.c */
|
||||
#line 102 "sapi/phpdbg/phpdbg_parser.c"
|
||||
#line 104 "sapi/phpdbg/phpdbg_parser.c"
|
||||
|
||||
# ifndef YY_NULL
|
||||
# if defined __cplusplus && 201103L <= __cplusplus
|
||||
|
@ -128,8 +130,9 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
|||
extern int phpdbg_debug;
|
||||
#endif
|
||||
/* "%code requires" blocks. */
|
||||
|
||||
/* Line 350 of yacc.c */
|
||||
#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
#line 31 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
#include "phpdbg.h"
|
||||
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||
|
@ -138,8 +141,9 @@ typedef void* yyscan_t;
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
/* Line 350 of yacc.c */
|
||||
#line 143 "sapi/phpdbg/phpdbg_parser.c"
|
||||
#line 147 "sapi/phpdbg/phpdbg_parser.c"
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
|
@ -164,7 +168,8 @@ typedef void* yyscan_t;
|
|||
T_OPCODE = 272,
|
||||
T_ID = 273,
|
||||
T_INPUT = 274,
|
||||
T_UNEXPECTED = 275
|
||||
T_UNEXPECTED = 275,
|
||||
T_REQ_ID = 276
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
|
@ -186,6 +191,7 @@ typedef void* yyscan_t;
|
|||
#define T_ID 273
|
||||
#define T_INPUT 274
|
||||
#define T_UNEXPECTED 275
|
||||
#define T_REQ_ID 276
|
||||
|
||||
|
||||
|
||||
|
@ -215,8 +221,9 @@ int phpdbg_parse ();
|
|||
|
||||
/* Copy the second part of user declarations. */
|
||||
|
||||
|
||||
/* Line 353 of yacc.c */
|
||||
#line 220 "sapi/phpdbg/phpdbg_parser.c"
|
||||
#line 227 "sapi/phpdbg/phpdbg_parser.c"
|
||||
|
||||
#ifdef short
|
||||
# undef short
|
||||
|
@ -434,22 +441,22 @@ union yyalloc
|
|||
#endif /* !YYCOPY_NEEDED */
|
||||
|
||||
/* YYFINAL -- State number of the termination state. */
|
||||
#define YYFINAL 25
|
||||
#define YYFINAL 26
|
||||
/* YYLAST -- Last index in YYTABLE. */
|
||||
#define YYLAST 42
|
||||
#define YYLAST 48
|
||||
|
||||
/* YYNTOKENS -- Number of terminals. */
|
||||
#define YYNTOKENS 21
|
||||
#define YYNTOKENS 22
|
||||
/* YYNNTS -- Number of nonterminals. */
|
||||
#define YYNNTS 5
|
||||
#define YYNNTS 6
|
||||
/* YYNRULES -- Number of rules. */
|
||||
#define YYNRULES 25
|
||||
#define YYNRULES 28
|
||||
/* YYNRULES -- Number of states. */
|
||||
#define YYNSTATES 38
|
||||
#define YYNSTATES 43
|
||||
|
||||
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
|
||||
#define YYUNDEFTOK 2
|
||||
#define YYMAXUTOK 275
|
||||
#define YYMAXUTOK 276
|
||||
|
||||
#define YYTRANSLATE(YYX) \
|
||||
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
|
||||
|
@ -484,7 +491,7 @@ static const yytype_uint8 yytranslate[] =
|
|||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
|
||||
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20
|
||||
15, 16, 17, 18, 19, 20, 21
|
||||
};
|
||||
|
||||
#if YYDEBUG
|
||||
|
@ -492,30 +499,31 @@ static const yytype_uint8 yytranslate[] =
|
|||
YYRHS. */
|
||||
static const yytype_uint8 yyprhs[] =
|
||||
{
|
||||
0, 0, 3, 5, 7, 8, 10, 13, 17, 22,
|
||||
27, 33, 37, 43, 47, 50, 52, 54, 56, 58,
|
||||
60, 62, 64, 67, 70, 72
|
||||
0, 0, 3, 5, 7, 8, 10, 13, 16, 20,
|
||||
25, 30, 36, 40, 46, 50, 53, 55, 57, 59,
|
||||
61, 63, 65, 67, 69, 70, 74, 78, 81
|
||||
};
|
||||
|
||||
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
|
||||
static const yytype_int8 yyrhs[] =
|
||||
{
|
||||
22, 0, -1, 23, -1, 25, -1, -1, 24, -1,
|
||||
23, 24, -1, 18, 10, 14, -1, 18, 10, 12,
|
||||
14, -1, 13, 18, 10, 14, -1, 13, 18, 10,
|
||||
12, 14, -1, 18, 11, 18, -1, 18, 11, 18,
|
||||
12, 14, -1, 18, 12, 14, -1, 6, 19, -1,
|
||||
17, -1, 16, -1, 15, -1, 7, -1, 8, -1,
|
||||
14, -1, 18, -1, 3, 19, -1, 5, 19, -1,
|
||||
4, -1, 4, 19, -1
|
||||
23, 0, -1, 24, -1, 27, -1, -1, 25, -1,
|
||||
24, 25, -1, 24, 26, -1, 18, 10, 14, -1,
|
||||
18, 10, 12, 14, -1, 13, 18, 10, 14, -1,
|
||||
13, 18, 10, 12, 14, -1, 18, 11, 18, -1,
|
||||
18, 11, 18, 12, 14, -1, 18, 12, 14, -1,
|
||||
6, 19, -1, 17, -1, 16, -1, 15, -1, 7,
|
||||
-1, 8, -1, 14, -1, 18, -1, 21, -1, -1,
|
||||
3, 26, 19, -1, 5, 26, 19, -1, 4, 26,
|
||||
-1, 4, 26, 19, -1
|
||||
};
|
||||
|
||||
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
|
||||
static const yytype_uint8 yyrline[] =
|
||||
{
|
||||
0, 66, 66, 67, 68, 72, 73, 77, 82, 87,
|
||||
97, 107, 112, 118, 124, 129, 130, 131, 132, 133,
|
||||
134, 135, 139, 144, 149, 153
|
||||
0, 67, 67, 68, 69, 73, 74, 75, 79, 84,
|
||||
89, 99, 109, 114, 120, 126, 131, 132, 133, 134,
|
||||
135, 136, 137, 141, 142, 146, 151, 156, 160
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -531,8 +539,9 @@ static const char *const yytname[] =
|
|||
"\":: (double colon)\"", "\"# (pound sign)\"", "\"protocol (file://)\"",
|
||||
"\"digits (numbers)\"", "\"literal (string)\"", "\"address\"",
|
||||
"\"opcode\"", "\"identifier (command or function name)\"",
|
||||
"\"input (input string or data)\"", "\"input\"", "$accept", "input",
|
||||
"parameters", "parameter", "full_expression", YY_NULL
|
||||
"\"input (input string or data)\"", "\"input\"",
|
||||
"\"request id (-r %d)\"", "$accept", "input", "parameters", "parameter",
|
||||
"req_id", "full_expression", YY_NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -543,24 +552,24 @@ static const yytype_uint16 yytoknum[] =
|
|||
{
|
||||
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
|
||||
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
|
||||
275
|
||||
275, 276
|
||||
};
|
||||
# endif
|
||||
|
||||
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
|
||||
static const yytype_uint8 yyr1[] =
|
||||
{
|
||||
0, 21, 22, 22, 22, 23, 23, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 25, 25, 25, 25
|
||||
0, 22, 23, 23, 23, 24, 24, 24, 25, 25,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
25, 25, 25, 26, 26, 27, 27, 27, 27
|
||||
};
|
||||
|
||||
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
|
||||
static const yytype_uint8 yyr2[] =
|
||||
{
|
||||
0, 2, 1, 1, 0, 1, 2, 3, 4, 4,
|
||||
5, 3, 5, 3, 2, 1, 1, 1, 1, 1,
|
||||
1, 1, 2, 2, 1, 2
|
||||
0, 2, 1, 1, 0, 1, 2, 2, 3, 4,
|
||||
4, 5, 3, 5, 3, 2, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 0, 3, 3, 2, 3
|
||||
};
|
||||
|
||||
/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
|
||||
|
@ -568,33 +577,35 @@ static const yytype_uint8 yyr2[] =
|
|||
means the default is an error. */
|
||||
static const yytype_uint8 yydefact[] =
|
||||
{
|
||||
4, 0, 24, 0, 0, 18, 19, 0, 20, 17,
|
||||
16, 15, 21, 0, 2, 5, 3, 22, 25, 23,
|
||||
14, 0, 0, 0, 0, 1, 6, 0, 0, 7,
|
||||
11, 13, 0, 9, 8, 0, 10, 12
|
||||
4, 24, 24, 24, 0, 19, 20, 0, 21, 18,
|
||||
17, 16, 22, 0, 2, 5, 3, 23, 0, 27,
|
||||
0, 15, 0, 0, 0, 0, 1, 6, 7, 25,
|
||||
28, 26, 0, 0, 8, 12, 14, 0, 10, 9,
|
||||
0, 11, 13
|
||||
};
|
||||
|
||||
/* YYDEFGOTO[NTERM-NUM]. */
|
||||
static const yytype_int8 yydefgoto[] =
|
||||
{
|
||||
-1, 13, 14, 15, 16
|
||||
-1, 13, 14, 15, 18, 16
|
||||
};
|
||||
|
||||
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
|
||||
STATE-NUM. */
|
||||
#define YYPACT_NINF -11
|
||||
#define YYPACT_NINF -16
|
||||
static const yytype_int8 yypact[] =
|
||||
{
|
||||
-3, -10, 11, 12, 13, -11, -11, 15, -11, -11,
|
||||
-11, -11, -4, 29, 10, -11, -11, -11, -11, -11,
|
||||
-11, 24, 7, 17, 22, -11, -11, 8, 23, -11,
|
||||
26, -11, 25, -11, -11, 27, -11, -11
|
||||
-3, -15, -15, -15, -10, -16, -16, 3, -16, -16,
|
||||
-16, -16, 22, 29, 10, -16, -16, -16, 11, 17,
|
||||
19, -16, 30, 8, 21, 27, -16, -16, -16, -16,
|
||||
-16, -16, 23, 28, -16, 31, -16, 32, -16, -16,
|
||||
33, -16, -16
|
||||
};
|
||||
|
||||
/* YYPGOTO[NTERM-NUM]. */
|
||||
static const yytype_int8 yypgoto[] =
|
||||
{
|
||||
-11, -11, -11, 28, -11
|
||||
-16, -16, -16, 34, 5, -16
|
||||
};
|
||||
|
||||
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
|
||||
|
@ -603,26 +614,26 @@ static const yytype_int8 yypgoto[] =
|
|||
#define YYTABLE_NINF -1
|
||||
static const yytype_uint8 yytable[] =
|
||||
{
|
||||
1, 2, 3, 4, 5, 6, 22, 23, 24, 17,
|
||||
1, 2, 3, 4, 5, 6, 17, 19, 20, 21,
|
||||
7, 8, 9, 10, 11, 12, 4, 5, 6, 28,
|
||||
32, 29, 33, 7, 8, 9, 10, 11, 12, 25,
|
||||
18, 19, 20, 21, 27, 30, 31, 34, 35, 36,
|
||||
0, 37, 26
|
||||
33, 22, 34, 7, 8, 9, 10, 11, 12, 26,
|
||||
29, 17, 23, 24, 25, 37, 30, 38, 31, 35,
|
||||
32, 36, 39, 40, 0, 0, 41, 42, 27
|
||||
};
|
||||
|
||||
#define yypact_value_is_default(yystate) \
|
||||
((yystate) == (-11))
|
||||
((yystate) == (-16))
|
||||
|
||||
#define yytable_value_is_error(yytable_value) \
|
||||
YYID (0)
|
||||
|
||||
static const yytype_int8 yycheck[] =
|
||||
{
|
||||
3, 4, 5, 6, 7, 8, 10, 11, 12, 19,
|
||||
13, 14, 15, 16, 17, 18, 6, 7, 8, 12,
|
||||
12, 14, 14, 13, 14, 15, 16, 17, 18, 0,
|
||||
19, 19, 19, 18, 10, 18, 14, 14, 12, 14,
|
||||
-1, 14, 14
|
||||
3, 4, 5, 6, 7, 8, 21, 2, 3, 19,
|
||||
13, 14, 15, 16, 17, 18, 6, 7, 8, 14,
|
||||
12, 18, 14, 13, 14, 15, 16, 17, 18, 0,
|
||||
19, 21, 10, 11, 12, 12, 19, 14, 19, 18,
|
||||
10, 14, 14, 12, -1, -1, 14, 14, 14
|
||||
};
|
||||
|
||||
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
|
||||
|
@ -630,9 +641,10 @@ static const yytype_int8 yycheck[] =
|
|||
static const yytype_uint8 yystos[] =
|
||||
{
|
||||
0, 3, 4, 5, 6, 7, 8, 13, 14, 15,
|
||||
16, 17, 18, 22, 23, 24, 25, 19, 19, 19,
|
||||
19, 18, 10, 11, 12, 0, 24, 10, 12, 14,
|
||||
18, 14, 12, 14, 14, 12, 14, 14
|
||||
16, 17, 18, 23, 24, 25, 27, 21, 26, 26,
|
||||
26, 19, 18, 10, 11, 12, 0, 25, 26, 19,
|
||||
19, 19, 10, 12, 14, 18, 14, 12, 14, 14,
|
||||
12, 14, 14
|
||||
};
|
||||
|
||||
#define yyerrok (yyerrstatus = 0)
|
||||
|
@ -1284,6 +1296,7 @@ YYSTYPE yylval;
|
|||
The wasted elements are never initialized. */
|
||||
yyssp = yyss;
|
||||
yyvsp = yyvs;
|
||||
|
||||
goto yysetstate;
|
||||
|
||||
/*------------------------------------------------------------.
|
||||
|
@ -1461,26 +1474,37 @@ yyreduce:
|
|||
switch (yyn)
|
||||
{
|
||||
case 3:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 67 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 68 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); }
|
||||
break;
|
||||
|
||||
case 5:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 73 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); }
|
||||
break;
|
||||
|
||||
case 6:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 73 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 74 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); }
|
||||
break;
|
||||
|
||||
case 7:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 77 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 75 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (2)]); }
|
||||
break;
|
||||
|
||||
case 8:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 79 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = FILE_PARAM;
|
||||
(yyval).file.name = (yyvsp[(2) - (3)]).str;
|
||||
|
@ -1488,9 +1512,10 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 82 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 9:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 84 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = NUMERIC_FILE_PARAM;
|
||||
(yyval).file.name = (yyvsp[(1) - (4)]).str;
|
||||
|
@ -1498,9 +1523,10 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 10:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 89 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = FILE_PARAM;
|
||||
(yyval).file.name = malloc((yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len + 1);
|
||||
|
@ -1513,9 +1539,10 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 97 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 11:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 99 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = NUMERIC_FILE_PARAM;
|
||||
(yyval).file.name = malloc((yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len + 1);
|
||||
|
@ -1528,9 +1555,10 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 107 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 12:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 109 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = METHOD_PARAM;
|
||||
(yyval).method.class = (yyvsp[(1) - (3)]).str;
|
||||
|
@ -1538,9 +1566,10 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 12:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 13:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 114 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = NUMERIC_METHOD_PARAM;
|
||||
(yyval).method.class = (yyvsp[(1) - (5)]).str;
|
||||
|
@ -1549,9 +1578,10 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 13:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 14:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 120 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = NUMERIC_FUNCTION_PARAM;
|
||||
(yyval).str = (yyvsp[(1) - (3)]).str;
|
||||
|
@ -1560,9 +1590,10 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 14:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 124 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 15:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 126 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = COND_PARAM;
|
||||
(yyval).str = (yyvsp[(2) - (2)]).str;
|
||||
|
@ -1570,90 +1601,109 @@ yyreduce:
|
|||
}
|
||||
break;
|
||||
|
||||
case 15:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 16:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 131 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 17:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 131 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 132 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 18:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 133 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 19:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 133 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 134 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 20:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 135 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 21:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 135 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 136 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 22:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = EVAL_PARAM;
|
||||
(yyval).str = (yyvsp[(2) - (2)]).str;
|
||||
(yyval).len = (yyvsp[(2) - (2)]).len;
|
||||
}
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 137 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ (yyval) = (yyvsp[(1) - (1)]); }
|
||||
break;
|
||||
|
||||
case 23:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 144 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 141 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{ PHPDBG_G(req_id) = (yyvsp[(1) - (1)]).num; }
|
||||
break;
|
||||
|
||||
case 25:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 146 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = SHELL_PARAM;
|
||||
(yyval).str = (yyvsp[(2) - (2)]).str;
|
||||
(yyval).len = (yyvsp[(2) - (2)]).len;
|
||||
(yyval).type = EVAL_PARAM;
|
||||
(yyval).str = (yyvsp[(3) - (3)]).str;
|
||||
(yyval).len = (yyvsp[(3) - (3)]).len;
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 149 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 26:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 151 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = SHELL_PARAM;
|
||||
(yyval).str = (yyvsp[(3) - (3)]).str;
|
||||
(yyval).len = (yyvsp[(3) - (3)]).len;
|
||||
}
|
||||
break;
|
||||
|
||||
case 27:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 156 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = RUN_PARAM;
|
||||
(yyval).len = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 25:
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 153 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
case 28:
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 160 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
{
|
||||
(yyval).type = RUN_PARAM;
|
||||
(yyval).str = (yyvsp[(2) - (2)]).str;
|
||||
(yyval).len = (yyvsp[(2) - (2)]).len;
|
||||
(yyval).str = (yyvsp[(3) - (3)]).str;
|
||||
(yyval).len = (yyvsp[(3) - (3)]).len;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/* Line 1802 of yacc.c */
|
||||
#line 1657 "sapi/phpdbg/phpdbg_parser.c"
|
||||
|
||||
/* Line 1803 of yacc.c */
|
||||
#line 1707 "sapi/phpdbg/phpdbg_parser.c"
|
||||
default: break;
|
||||
}
|
||||
/* User semantic actions sometimes alter yychar, and that requires
|
||||
|
@ -1882,12 +1932,13 @@ yyreturn:
|
|||
}
|
||||
|
||||
|
||||
/* Line 2048 of yacc.c */
|
||||
#line 160 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 2049 of yacc.c */
|
||||
#line 167 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
|
||||
static int yyerror(void ***tsrm_ls, const char *msg) {
|
||||
phpdbg_error("Parse Error: %s", msg);
|
||||
phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg);
|
||||
|
||||
{
|
||||
const phpdbg_param_t *top = PHPDBG_G(parser_stack);
|
||||
|
@ -1909,3 +1960,4 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) {
|
|||
return yyparse(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* A Bison parser, made by GNU Bison 2.6.2. */
|
||||
/* A Bison parser, made by GNU Bison 2.6. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
|
@ -40,8 +40,9 @@
|
|||
extern int phpdbg_debug;
|
||||
#endif
|
||||
/* "%code requires" blocks. */
|
||||
/* Line 2055 of yacc.c */
|
||||
#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
/* Line 2056 of yacc.c */
|
||||
#line 31 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y"
|
||||
|
||||
#include "phpdbg.h"
|
||||
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||
|
@ -50,8 +51,9 @@ typedef void* yyscan_t;
|
|||
#endif
|
||||
|
||||
|
||||
/* Line 2055 of yacc.c */
|
||||
#line 55 "sapi/phpdbg/phpdbg_parser.h"
|
||||
|
||||
/* Line 2056 of yacc.c */
|
||||
#line 57 "sapi/phpdbg/phpdbg_parser.h"
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
|
@ -76,7 +78,8 @@ typedef void* yyscan_t;
|
|||
T_OPCODE = 272,
|
||||
T_ID = 273,
|
||||
T_INPUT = 274,
|
||||
T_UNEXPECTED = 275
|
||||
T_UNEXPECTED = 275,
|
||||
T_REQ_ID = 276
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
|
@ -98,6 +101,7 @@ typedef void* yyscan_t;
|
|||
#define T_ID 273
|
||||
#define T_INPUT 274
|
||||
#define T_UNEXPECTED 275
|
||||
#define T_REQ_ID 276
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ typedef void* yyscan_t;
|
|||
%token T_ID "identifier (command or function name)"
|
||||
%token T_INPUT "input (input string or data)"
|
||||
%token T_UNEXPECTED "input"
|
||||
%token T_REQ_ID "request id (-r %d)"
|
||||
|
||||
%% /* Rules */
|
||||
|
||||
|
@ -71,6 +72,7 @@ input
|
|||
parameters
|
||||
: parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); }
|
||||
| parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); }
|
||||
| parameters req_id { $$ = $1; }
|
||||
;
|
||||
|
||||
parameter
|
||||
|
@ -135,32 +137,37 @@ parameter
|
|||
| T_ID { $$ = $1; }
|
||||
;
|
||||
|
||||
req_id
|
||||
: T_REQ_ID { PHPDBG_G(req_id) = $1.num; }
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
full_expression
|
||||
: T_EVAL T_INPUT {
|
||||
: T_EVAL req_id T_INPUT {
|
||||
$$.type = EVAL_PARAM;
|
||||
$$.str = $2.str;
|
||||
$$.len = $2.len;
|
||||
$$.str = $3.str;
|
||||
$$.len = $3.len;
|
||||
}
|
||||
| T_SHELL T_INPUT {
|
||||
| T_SHELL req_id T_INPUT {
|
||||
$$.type = SHELL_PARAM;
|
||||
$$.str = $2.str;
|
||||
$$.len = $2.len;
|
||||
$$.str = $3.str;
|
||||
$$.len = $3.len;
|
||||
}
|
||||
| T_RUN {
|
||||
| T_RUN req_id {
|
||||
$$.type = RUN_PARAM;
|
||||
$$.len = 0;
|
||||
}
|
||||
| T_RUN T_INPUT {
|
||||
| T_RUN req_id T_INPUT {
|
||||
$$.type = RUN_PARAM;
|
||||
$$.str = $2.str;
|
||||
$$.len = $2.len;
|
||||
$$.str = $3.str;
|
||||
$$.len = $3.len;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
static int yyerror(void ***tsrm_ls, const char *msg) {
|
||||
phpdbg_error("Parse Error: %s", msg);
|
||||
phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg);
|
||||
|
||||
{
|
||||
const phpdbg_param_t *top = PHPDBG_G(parser_stack);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -26,25 +26,25 @@
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9])
|
||||
#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s, flags) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9], flags)
|
||||
|
||||
const phpdbg_command_t phpdbg_print_commands[] = {
|
||||
PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0),
|
||||
PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0),
|
||||
PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s"),
|
||||
PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m"),
|
||||
PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s"),
|
||||
PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0),
|
||||
PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
PHPDBG_PRINT(opline) /* {{{ */
|
||||
{
|
||||
if (EG(in_execution) && EG(current_execute_data)) {
|
||||
if (PHPDBG_G(in_execution) && EG(current_execute_data)) {
|
||||
phpdbg_print_opline(EG(current_execute_data), 1 TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Not Executing!");
|
||||
phpdbg_error("inactive", "type=\"execution\"", "Not Executing!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -63,31 +63,32 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC)
|
|||
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");
|
||||
phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" method=\"%s::%s\" file=\"%s\"", "\tL%d-%d %s::%s() %s",
|
||||
op_array->line_start,
|
||||
op_array->line_end,
|
||||
method->common.scope->name->val,
|
||||
method->common.function_name->val,
|
||||
op_array->filename ? op_array->filename->val : "unknown");
|
||||
} else {
|
||||
phpdbg_writeln("\tL%d-%d %s() %s",
|
||||
phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" function=\"%s\" file=\"%s\"", "\tL%d-%d %s() %s",
|
||||
method->common.function_name ? op_array->line_start : 0,
|
||||
method->common.function_name ? op_array->line_end : 0,
|
||||
method->common.function_name ? method->common.function_name : "{main}",
|
||||
op_array->filename ? op_array->filename : "unknown");
|
||||
method->common.function_name ? method->common.function_name->val : "{main}",
|
||||
op_array->filename ? op_array->filename->val : "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",
|
||||
phpdbg_writeln("print", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\"", "\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);
|
||||
phpdbg_error("print", "type=\"decodefailure\" opline=\"%16p\"", "\tFailed to decode opline %16p", opline);
|
||||
}
|
||||
opline++;
|
||||
} while (opcode++ < end);
|
||||
|
@ -97,9 +98,9 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC)
|
|||
|
||||
default: {
|
||||
if (method->common.scope) {
|
||||
phpdbg_writeln("\tInternal %s::%s()", method->common.scope->name, method->common.function_name);
|
||||
phpdbg_writeln("printoplineinfo", "type=\"Internal\" method=\"%s::%s\"", "\tInternal %s::%s()", method->common.scope->name->val, method->common.function_name->val);
|
||||
} else {
|
||||
phpdbg_writeln("\tInternal %s()", method->common.function_name);
|
||||
phpdbg_writeln("printoplineinfo", "type=\"Internal\" function=\"%s\"", "\tInternal %s()", method->common.function_name->val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,17 +109,17 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC)
|
|||
PHPDBG_PRINT(exec) /* {{{ */
|
||||
{
|
||||
if (PHPDBG_G(exec)) {
|
||||
if (!PHPDBG_G(ops)) {
|
||||
if (!PHPDBG_G(ops) && !(PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER)) {
|
||||
phpdbg_compile(TSRMLS_C);
|
||||
}
|
||||
|
||||
if (PHPDBG_G(ops)) {
|
||||
phpdbg_notice("Context %s", PHPDBG_G(exec));
|
||||
phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Context %s (%d ops)", PHPDBG_G(exec), PHPDBG_G(ops)->last);
|
||||
|
||||
phpdbg_print_function_helper((zend_function*) PHPDBG_G(ops) TSRMLS_CC);
|
||||
}
|
||||
} else {
|
||||
phpdbg_error("No execution context set");
|
||||
phpdbg_error("inactive", "type=\"nocontext\"", "No execution context set");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -126,25 +127,24 @@ return SUCCESS;
|
|||
|
||||
PHPDBG_PRINT(stack) /* {{{ */
|
||||
{
|
||||
zend_op_array *ops = EG(active_op_array);
|
||||
|
||||
if (EG(in_execution) && ops) {
|
||||
if (PHPDBG_G(in_execution) && EG(current_execute_data)) {
|
||||
zend_op_array *ops = &EG(current_execute_data)->func->op_array;
|
||||
if (ops->function_name) {
|
||||
if (ops->scope) {
|
||||
phpdbg_notice("Stack in %s::%s()", ops->scope->name, ops->function_name);
|
||||
phpdbg_notice("printinfo", "method=\"%s::%s\" num=\"%d\"", "Stack in %s::%s() (%d ops)", ops->scope->name->val, ops->function_name->val, ops->last);
|
||||
} else {
|
||||
phpdbg_notice("Stack in %s()", ops->function_name);
|
||||
phpdbg_notice("printinfo", "function=\"%s\" num=\"%d\"", "Stack in %s() (%d ops)", ops->function_name->val, ops->last);
|
||||
}
|
||||
} else {
|
||||
if (ops->filename) {
|
||||
phpdbg_notice("Stack in %s", ops->filename);
|
||||
phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Stack in %s (%d ops)", ops->filename->val, ops->last);
|
||||
} else {
|
||||
phpdbg_notice("Stack @ %p", ops);
|
||||
phpdbg_notice("printinfo", "opline=\"%p\" num=\"%d\"", "Stack @ %p (%d ops)", ops, ops->last);
|
||||
}
|
||||
}
|
||||
phpdbg_print_function_helper((zend_function*) ops TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("Not Executing!");
|
||||
phpdbg_error("inactive", "type=\"execution\"", "Not Executing!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -152,32 +152,33 @@ PHPDBG_PRINT(stack) /* {{{ */
|
|||
|
||||
PHPDBG_PRINT(class) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
zend_class_entry *ce;
|
||||
|
||||
if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
phpdbg_notice("%s %s: %s",
|
||||
((*ce)->type == ZEND_USER_CLASS) ?
|
||||
if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
phpdbg_notice("printinfo", "type=\"%s\" flag=\"%s\" class=\"%s\" num=\"%d\"", "%s %s: %s (%d methods)",
|
||||
(ce->type == ZEND_USER_CLASS) ?
|
||||
"User" : "Internal",
|
||||
((*ce)->ce_flags & ZEND_ACC_INTERFACE) ?
|
||||
(ce->ce_flags & ZEND_ACC_INTERFACE) ?
|
||||
"Interface" :
|
||||
((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ?
|
||||
(ce->ce_flags & ZEND_ACC_ABSTRACT) ?
|
||||
"Abstract Class" :
|
||||
"Class",
|
||||
(*ce)->name);
|
||||
ce->name->val,
|
||||
zend_hash_num_elements(&ce->function_table));
|
||||
|
||||
phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table));
|
||||
if (zend_hash_num_elements(&(*ce)->function_table)) {
|
||||
HashPosition position;
|
||||
phpdbg_xml("<printmethods %r>");
|
||||
|
||||
if (zend_hash_num_elements(&ce->function_table)) {
|
||||
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)) {
|
||||
ZEND_HASH_FOREACH_PTR(&ce->function_table, method) {
|
||||
phpdbg_print_function_helper(method TSRMLS_CC);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_xml("</printmethods>");
|
||||
} else {
|
||||
phpdbg_error("The class %s could not be found", param->str);
|
||||
phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->str);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -185,25 +186,27 @@ PHPDBG_PRINT(class) /* {{{ */
|
|||
|
||||
PHPDBG_PRINT(method) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
zend_class_entry *ce;
|
||||
|
||||
if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
zend_function *fbc;
|
||||
char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
|
||||
zend_string *lcname = zend_string_alloc(strlen(param->method.name), 0);
|
||||
zend_str_tolower_copy(lcname->val, param->method.name, lcname->len);
|
||||
|
||||
if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_notice("%s Method %s",
|
||||
if ((fbc = zend_hash_find_ptr(&ce->function_table, lcname))) {
|
||||
phpdbg_notice("printinfo", "type=\"%s\" flags=\"Method\" symbol=\"%s\" num=\"%d\"", "%s Method %s (%d ops)",
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
|
||||
fbc->common.function_name);
|
||||
fbc->common.function_name->val,
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0);
|
||||
|
||||
phpdbg_print_function_helper(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("The method %s could not be found", param->method.name);
|
||||
phpdbg_error("print", "type=\"nomethod\" method=\"%s::%s\"", "The method %s::%s could not be found", param->method.class, param->method.name);
|
||||
}
|
||||
|
||||
efree(lcname);
|
||||
zend_string_release(lcname);
|
||||
} else {
|
||||
phpdbg_error("The class %s could not be found", param->method.class);
|
||||
phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->method.class);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -215,7 +218,7 @@ PHPDBG_PRINT(func) /* {{{ */
|
|||
zend_function* fbc;
|
||||
const char *func_name = param->str;
|
||||
size_t func_name_len = param->len;
|
||||
char *lcname;
|
||||
zend_string *lcname;
|
||||
/* search active scope if begins with period */
|
||||
if (func_name[0] == '.') {
|
||||
if (EG(scope)) {
|
||||
|
@ -224,28 +227,34 @@ PHPDBG_PRINT(func) /* {{{ */
|
|||
|
||||
func_table = &EG(scope)->function_table;
|
||||
} else {
|
||||
phpdbg_error("No active class");
|
||||
phpdbg_error("inactive", "type=\"noclasses\"", "No active class");
|
||||
return SUCCESS;
|
||||
}
|
||||
} else if (!EG(function_table)) {
|
||||
phpdbg_error("No function table loaded");
|
||||
phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded");
|
||||
return SUCCESS;
|
||||
} else {
|
||||
func_table = EG(function_table);
|
||||
}
|
||||
|
||||
lcname = zend_str_tolower_dup(func_name, func_name_len);
|
||||
lcname = zend_string_alloc(func_name_len, 0);
|
||||
zend_str_tolower_copy(lcname->val, func_name, lcname->len);
|
||||
|
||||
if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_notice("%s %s %s",
|
||||
phpdbg_try_access {
|
||||
if ((fbc = zend_hash_find_ptr(func_table, lcname))) {
|
||||
phpdbg_notice("printinfo", "type=\"%s\" flags=\"%s\" symbol=\"%s\" num=\"%d\"", "%s %s %s (%d ops)",
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
|
||||
(fbc->common.scope) ? "Method" : "Function",
|
||||
fbc->common.function_name);
|
||||
fbc->common.function_name->val,
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0);
|
||||
|
||||
phpdbg_print_function_helper(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("The function %s could not be found", func_name);
|
||||
phpdbg_error("print", "type=\"nofunction\" function=\"%s\"", "The function %s could not be found", func_name);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "function=\"%.*s\"", "Couldn't fetch function %.*s, invalid data source", (int) func_name_len, func_name);
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
efree(lcname);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -24,9 +24,11 @@
|
|||
/* {{{ */
|
||||
void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC);
|
||||
void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC);
|
||||
int phpdbg_interactive(TSRMLS_D);
|
||||
int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC);
|
||||
int phpdbg_compile(TSRMLS_D);
|
||||
void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */
|
||||
void phpdbg_clean(zend_bool full TSRMLS_DC);
|
||||
void phpdbg_force_interruption(TSRMLS_D);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ phpdbg command handlers */
|
||||
PHPDBG_COMMAND(exec);
|
||||
|
@ -47,12 +49,15 @@ PHPDBG_COMMAND(clean);
|
|||
PHPDBG_COMMAND(clear);
|
||||
PHPDBG_COMMAND(help);
|
||||
PHPDBG_COMMAND(sh);
|
||||
PHPDBG_COMMAND(dl);
|
||||
PHPDBG_COMMAND(set);
|
||||
PHPDBG_COMMAND(source);
|
||||
PHPDBG_COMMAND(export);
|
||||
PHPDBG_COMMAND(register);
|
||||
PHPDBG_COMMAND(quit);
|
||||
PHPDBG_COMMAND(watch); /* }}} */
|
||||
PHPDBG_COMMAND(watch);
|
||||
PHPDBG_COMMAND(eol);
|
||||
PHPDBG_COMMAND(wait); /* }}} */
|
||||
|
||||
/* {{{ prompt commands */
|
||||
extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */
|
||||
|
|
101
sapi/phpdbg/phpdbg_rinit_hook.c
Normal file
101
sapi/phpdbg/phpdbg_rinit_hook.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg_rinit_hook.h"
|
||||
#include "php_ini.h"
|
||||
#include <errno.h>
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(phpdbg_webhelper);
|
||||
|
||||
PHP_INI_BEGIN()
|
||||
STD_PHP_INI_ENTRY("phpdbg.auth", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, auth, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals)
|
||||
STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, path, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals)
|
||||
PHP_INI_END()
|
||||
|
||||
static inline void php_phpdbg_webhelper_globals_ctor(zend_phpdbg_webhelper_globals *pg) /* {{{ */
|
||||
{
|
||||
} /* }}} */
|
||||
|
||||
static PHP_MINIT_FUNCTION(phpdbg_webhelper) /* {{{ */
|
||||
{
|
||||
if (!strcmp(sapi_module.name, PHPDBG_NAME)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_INIT_MODULE_GLOBALS(phpdbg_webhelper, php_phpdbg_webhelper_globals_ctor, NULL);
|
||||
REGISTER_INI_ENTRIES();
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
static PHP_RINIT_FUNCTION(phpdbg_webhelper) /* {{{ */
|
||||
{
|
||||
zval cookies = PG(http_globals)[TRACK_VARS_COOKIE];
|
||||
zval *auth;
|
||||
|
||||
if (Z_TYPE(cookies) == IS_ARRAY || (auth = zend_hash_str_find(Z_ARRVAL(cookies), PHPDBG_NAME "_AUTH_COOKIE", sizeof(PHPDBG_NAME "_AUTH_COOKIE"))) || Z_STRLEN_P(auth) != strlen(PHPDBG_WG(auth)) || strcmp(Z_STRVAL_P(auth), PHPDBG_WG(auth))) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
{
|
||||
struct sockaddr_un sock;
|
||||
int s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
int len = strlen(PHPDBG_WG(path)) + sizeof(sock.sun_family);
|
||||
char buf[(1 << 8) + 1];
|
||||
int buflen;
|
||||
sock.sun_family = AF_UNIX;
|
||||
strcpy(sock.sun_path, PHPDBG_WG(path));
|
||||
|
||||
if (connect(s, (struct sockaddr *)&sock, len) == -1) {
|
||||
zend_error(E_ERROR, "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting. Reason: %s", PHPDBG_WG(path), strerror(errno));
|
||||
}
|
||||
|
||||
char *msg = NULL;
|
||||
char msglen[5] = {0};
|
||||
phpdbg_webdata_compress(&msg, (int *)msglen TSRMLS_CC);
|
||||
|
||||
send(s, msglen, 4, 0);
|
||||
send(s, msg, *(int *) msglen, 0);
|
||||
|
||||
while ((buflen = recv(s, buf, sizeof(buf) - 1, 0)) > 0) {
|
||||
php_write(buf, buflen TSRMLS_CC);
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
php_output_flush_all(TSRMLS_C);
|
||||
zend_bailout();
|
||||
}
|
||||
#endif
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
zend_module_entry phpdbg_webhelper_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
"phpdbg_webhelper",
|
||||
NULL,
|
||||
PHP_MINIT(phpdbg_webhelper),
|
||||
NULL,
|
||||
PHP_RINIT(phpdbg_webhelper),
|
||||
NULL,
|
||||
NULL,
|
||||
PHPDBG_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
41
sapi/phpdbg/phpdbg_rinit_hook.h
Normal file
41
sapi/phpdbg/phpdbg_rinit_hook.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Felipe Pena <felipe@php.net> |
|
||||
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_WEBHELPER_H
|
||||
#define PHPDBG_WEBHELPER_H
|
||||
|
||||
#include "phpdbg_webdata_transfer.h"
|
||||
|
||||
extern zend_module_entry phpdbg_webhelper_module_entry;
|
||||
#define phpext_phpdbg_webhelper_ptr &phpdbg_webhelper_module_entry
|
||||
|
||||
#ifdef ZTS
|
||||
# define PHPDBG_WG(v) TSRMG(phpdbg_webhelper_globals_id, zend_phpdbg_webhelper_globals *, v)
|
||||
#else
|
||||
# define PHPDBG_WG(v) (phpdbg_webhelper_globals.v)
|
||||
#endif
|
||||
|
||||
/* {{{ structs */
|
||||
ZEND_BEGIN_MODULE_GLOBALS(phpdbg_webhelper)
|
||||
char *auth;
|
||||
char *path;
|
||||
ZEND_END_MODULE_GLOBALS(phpdbg_webhelper) /* }}} */
|
||||
|
||||
#endif /* PHPDBG_WEBHELPER_H */
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -27,29 +27,31 @@
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[18])
|
||||
#define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s, flags) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[18], flags)
|
||||
|
||||
const phpdbg_command_t phpdbg_set_commands[] = {
|
||||
PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt [<string>]", 'p', set_prompt, NULL, "|s"),
|
||||
PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt [<string>]", 'p', set_prompt, NULL, "|s", 0),
|
||||
#ifndef _WIN32
|
||||
PHPDBG_SET_COMMAND_D(color, "usage: set color <element> <color>", 'c', set_color, NULL, "ss"),
|
||||
PHPDBG_SET_COMMAND_D(colors, "usage: set colors [<on|off>]", 'C', set_colors, NULL, "|b"),
|
||||
PHPDBG_SET_COMMAND_D(color, "usage: set color <element> <color>", 'c', set_color, NULL, "ss", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_SET_COMMAND_D(colors, "usage: set colors [<on|off>]", 'C', set_colors, NULL, "|b", PHPDBG_ASYNC_SAFE),
|
||||
#endif
|
||||
PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog [<output>]", 'O', set_oplog, NULL, "|s"),
|
||||
PHPDBG_SET_COMMAND_D(break, "usage: set break id [<on|off>]", 'b', set_break, NULL, "l|b"),
|
||||
PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks [<on|off>]", 'B', set_breaks, NULL, "|b"),
|
||||
PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet [<on|off>]", 'q', set_quiet, NULL, "|b"),
|
||||
PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping [<line|op>]", 's', set_stepping, NULL, "|s"),
|
||||
PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount [<on|off>]", 'r', set_refcount, NULL, "|b"),
|
||||
PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog [<output>]", 'O', set_oplog, NULL, "|s", 0),
|
||||
PHPDBG_SET_COMMAND_D(break, "usage: set break id [<on|off>]", 'b', set_break, NULL, "l|b", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks [<on|off>]", 'B', set_breaks, NULL, "|b", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet [<on|off>]", 'q', set_quiet, NULL, "|b", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping [<line|op>]", 's', set_stepping, NULL, "|s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount [<on|off>]", 'r', set_refcount, NULL, "|b", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
PHPDBG_SET(prompt) /* {{{ */
|
||||
{
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C));
|
||||
} else phpdbg_set_prompt(param->str TSRMLS_CC);
|
||||
phpdbg_writeln("setprompt", "str=\"%s\"", "Current prompt: %s", phpdbg_get_prompt(TSRMLS_C));
|
||||
} else {
|
||||
phpdbg_set_prompt(param->str TSRMLS_CC);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
@ -61,21 +63,21 @@ PHPDBG_SET(break) /* {{{ */
|
|||
if (param->next) {
|
||||
if (param->next->num) {
|
||||
phpdbg_enable_breakpoint(param->num TSRMLS_CC);
|
||||
} else phpdbg_disable_breakpoint(param->num TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_disable_breakpoint(param->num TSRMLS_CC);
|
||||
}
|
||||
} else {
|
||||
phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC);
|
||||
if (brake) {
|
||||
phpdbg_writeln(
|
||||
"%s", brake->disabled ? "off" : "on");
|
||||
phpdbg_writeln("setbreak", "id=\"%ld\" active=\"%s\"", "Breakpoint #%ld %s", param->num, brake->disabled ? "off" : "on");
|
||||
} else {
|
||||
phpdbg_error("Failed to find breakpoint #%ld", param->num);
|
||||
phpdbg_error("setbreak", "type=\"nobreak\" id=\"%ld\"", "Failed to find breakpoint #%ld", param->num);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
phpdbg_error(
|
||||
"set break used incorrectly: set break [id] <on|off>");
|
||||
phpdbg_error("setbreak", "type=\"wrongargs\"", "set break used incorrectly: set break [id] <on|off>");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -84,18 +86,18 @@ PHPDBG_SET(break) /* {{{ */
|
|||
PHPDBG_SET(breaks) /* {{{ */
|
||||
{
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_writeln("%s",
|
||||
PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off");
|
||||
phpdbg_writeln("setbreaks", "active=\"%s\"", "Breakpoints %s",PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off");
|
||||
} else switch (param->type) {
|
||||
case NUMERIC_PARAM: {
|
||||
if (param->num) {
|
||||
phpdbg_enable_breakpoints(TSRMLS_C);
|
||||
} else phpdbg_disable_breakpoints(TSRMLS_C);
|
||||
} else {
|
||||
phpdbg_disable_breakpoints(TSRMLS_C);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
phpdbg_error(
|
||||
"set break used incorrectly: set break [id] <on|off>");
|
||||
phpdbg_error("setbreaks", "type=\"wrongargs\"", "set breaks used incorrectly: set breaks <on|off>");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -104,19 +106,16 @@ PHPDBG_SET(breaks) /* {{{ */
|
|||
#ifndef _WIN32
|
||||
PHPDBG_SET(color) /* {{{ */
|
||||
{
|
||||
const phpdbg_color_t *color = phpdbg_get_color(
|
||||
param->next->str, param->next->len TSRMLS_CC);
|
||||
const phpdbg_color_t *color = phpdbg_get_color(param->next->str, param->next->len TSRMLS_CC);
|
||||
|
||||
if (!color) {
|
||||
phpdbg_error(
|
||||
"Failed to find the requested color (%s)", param->next->str);
|
||||
phpdbg_error("setcolor", "type=\"nocolor\"", "Failed to find the requested color (%s)", param->next->str);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (phpdbg_get_element(param->str, param->len TSRMLS_CC)) {
|
||||
case PHPDBG_COLOR_PROMPT:
|
||||
phpdbg_notice(
|
||||
"setting prompt color to %s (%s)", color->name, color->code);
|
||||
phpdbg_notice("setcolor", "type=\"prompt\" color=\"%s\" code=\"%s\"", "setting prompt color to %s (%s)", color->name, color->code);
|
||||
if (PHPDBG_G(prompt)[1]) {
|
||||
free(PHPDBG_G(prompt)[1]);
|
||||
PHPDBG_G(prompt)[1]=NULL;
|
||||
|
@ -125,20 +124,17 @@ PHPDBG_SET(color) /* {{{ */
|
|||
break;
|
||||
|
||||
case PHPDBG_COLOR_ERROR:
|
||||
phpdbg_notice(
|
||||
"setting error color to %s (%s)", color->name, color->code);
|
||||
phpdbg_notice("setcolor", "type=\"error\" color=\"%s\" code=\"%s\"", "setting error color to %s (%s)", color->name, color->code);
|
||||
phpdbg_set_color(PHPDBG_COLOR_ERROR, color TSRMLS_CC);
|
||||
break;
|
||||
|
||||
case PHPDBG_COLOR_NOTICE:
|
||||
phpdbg_notice(
|
||||
"setting notice color to %s (%s)", color->name, color->code);
|
||||
phpdbg_notice("setcolor", "type=\"notice\" color=\"%s\" code=\"%s\"", "setting notice color to %s (%s)", color->name, color->code);
|
||||
phpdbg_set_color(PHPDBG_COLOR_NOTICE, color TSRMLS_CC);
|
||||
break;
|
||||
|
||||
default:
|
||||
phpdbg_error(
|
||||
"Failed to find the requested element (%s)", param->str);
|
||||
phpdbg_error("setcolor", "type=\"invalidtype\"", "Failed to find the requested element (%s)", param->str);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -147,7 +143,7 @@ PHPDBG_SET(color) /* {{{ */
|
|||
PHPDBG_SET(colors) /* {{{ */
|
||||
{
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_writeln("%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off");
|
||||
phpdbg_writeln("setcolors", "active=\"%s\"", "Colors %s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off");
|
||||
} else switch (param->type) {
|
||||
case NUMERIC_PARAM: {
|
||||
if (param->num) {
|
||||
|
@ -158,8 +154,7 @@ PHPDBG_SET(colors) /* {{{ */
|
|||
} break;
|
||||
|
||||
default:
|
||||
phpdbg_error(
|
||||
"set colors used incorrectly: set colors <on|off>");
|
||||
phpdbg_error("setcolors", "type=\"wrongargs\"", "set colors used incorrectly: set colors <on|off>");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -169,7 +164,7 @@ PHPDBG_SET(colors) /* {{{ */
|
|||
PHPDBG_SET(oplog) /* {{{ */
|
||||
{
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_notice("Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled");
|
||||
phpdbg_notice("setoplog", "active=\"%s\"", "Oplog %s", PHPDBG_G(oplog) ? "on" : "off");
|
||||
} else switch (param->type) {
|
||||
case STR_PARAM: {
|
||||
/* open oplog */
|
||||
|
@ -177,14 +172,15 @@ PHPDBG_SET(oplog) /* {{{ */
|
|||
|
||||
PHPDBG_G(oplog) = fopen(param->str, "w+");
|
||||
if (!PHPDBG_G(oplog)) {
|
||||
phpdbg_error("Failed to open %s for oplog", param->str);
|
||||
phpdbg_error("setoplog", "type=\"openfailure\" file=\"%s\"", "Failed to open %s for oplog", param->str);
|
||||
PHPDBG_G(oplog) = old;
|
||||
} else {
|
||||
if (old) {
|
||||
phpdbg_notice("Closing previously open oplog");
|
||||
phpdbg_notice("setoplog", "type=\"closingold\"", "Closing previously open oplog");
|
||||
fclose(old);
|
||||
}
|
||||
phpdbg_notice("Successfully opened oplog %s", param->str);
|
||||
|
||||
phpdbg_notice("setoplog", "file=\"%s\"", "Successfully opened oplog %s", param->str);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -197,8 +193,7 @@ PHPDBG_SET(oplog) /* {{{ */
|
|||
PHPDBG_SET(quiet) /* {{{ */
|
||||
{
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_writeln("Quietness %s",
|
||||
PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off");
|
||||
phpdbg_writeln("setquiet", "active=\"%s\"", "Quietness %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off");
|
||||
} else switch (param->type) {
|
||||
case NUMERIC_PARAM: {
|
||||
if (param->num) {
|
||||
|
@ -217,18 +212,15 @@ PHPDBG_SET(quiet) /* {{{ */
|
|||
PHPDBG_SET(stepping) /* {{{ */
|
||||
{
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_writeln("Stepping %s",
|
||||
PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line");
|
||||
phpdbg_writeln("setstepping", "type=\"%s\"", "Stepping %s", PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line");
|
||||
} else switch (param->type) {
|
||||
case STR_PARAM: {
|
||||
if ((param->len == sizeof("opcode")-1) &&
|
||||
(memcmp(param->str, "opcode", sizeof("opcode")) == SUCCESS)) {
|
||||
if (param->len == sizeof("opcode") - 1 && !memcmp(param->str, "opcode", sizeof("opcode"))) {
|
||||
PHPDBG_G(flags) |= PHPDBG_STEP_OPCODE;
|
||||
} else if ((param->len == sizeof("line")-1) &&
|
||||
(memcmp(param->str, "line", sizeof("line")) == SUCCESS)) {
|
||||
} else if (param->len == sizeof("line") - 1 && !memcmp(param->str, "line", sizeof("line"))) {
|
||||
PHPDBG_G(flags) &= ~PHPDBG_STEP_OPCODE;
|
||||
} else {
|
||||
phpdbg_error("usage set stepping [<opcode|line>]");
|
||||
phpdbg_error("setstepping", "type=\"wrongargs\"", "usage set stepping [<opcode|line>]");
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -241,7 +233,7 @@ PHPDBG_SET(stepping) /* {{{ */
|
|||
PHPDBG_SET(refcount) /* {{{ */
|
||||
{
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_writeln("Refcount %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off");
|
||||
phpdbg_writeln("setrefcount", "active=\"%s\"", "Showing refcounts %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off");
|
||||
} else switch (param->type) {
|
||||
case NUMERIC_PARAM: {
|
||||
if (param->num) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
120
sapi/phpdbg/phpdbg_sigio_win32.c
Normal file
120
sapi/phpdbg/phpdbg_sigio_win32.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 7-4 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anatol Belski <ab@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_sigio_win32.h"
|
||||
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
|
||||
VOID
|
||||
SigIoWatcherThread(VOID *p)
|
||||
{
|
||||
zend_uchar sig;
|
||||
struct win32_sigio_watcher_data *swd = (struct win32_sigio_watcher_data *)p;
|
||||
#ifdef ZTS
|
||||
void ***tsrm_ls = swd->tsrm_ls;
|
||||
top:
|
||||
(void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1, tsrm_ls);
|
||||
#else
|
||||
top:
|
||||
(void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1);
|
||||
#endif
|
||||
|
||||
|
||||
if (3 == sig) {
|
||||
printf("signaled, got %d", sig);
|
||||
/* XXX completely not sure it is done right here */
|
||||
if (swd->flags & PHPDBG_IS_INTERACTIVE) {
|
||||
if (raise(sig)) {
|
||||
/* just out*/
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
if (swd->flags & PHPDBG_IS_SIGNALED) {
|
||||
phpdbg_set_sigsafe_mem(&sig TSRMLS_CC);
|
||||
zend_try {
|
||||
phpdbg_force_interruption(TSRMLS_C);
|
||||
} zend_end_try();
|
||||
phpdbg_clear_sigsafe_mem(TSRMLS_C);
|
||||
}
|
||||
/* XXX set signaled flag to the caller thread, question is - whether it's needed */
|
||||
ExitThread(sig);
|
||||
} else {
|
||||
goto top;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Start this only for the time of the run or eval command,
|
||||
for so long that the main thread is busy serving some debug
|
||||
session. */
|
||||
void
|
||||
sigio_watcher_start(void)
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
|
||||
PHPDBG_G(swd).fd = PHPDBG_G(io)[PHPDBG_STDIN].fd;
|
||||
PHPDBG_G(swd).running = 1;
|
||||
PHPDBG_G(swd).flags = PHPDBG_G(flags);
|
||||
#ifdef ZTS
|
||||
PHPDBG_G(swd).tsrm_ls = tsrm_ls;
|
||||
#endif
|
||||
|
||||
PHPDBG_G(sigio_watcher_thread) = CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE)SigIoWatcherThread,
|
||||
&PHPDBG_G(swd),
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sigio_watcher_stop(void)
|
||||
{
|
||||
DWORD waited;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (INVALID_HANDLE_VALUE == PHPDBG_G(sigio_watcher_thread)) {
|
||||
/* it probably did bail out already */
|
||||
return;
|
||||
}
|
||||
|
||||
waited = WaitForSingleObject(PHPDBG_G(sigio_watcher_thread), 300);
|
||||
|
||||
if (WAIT_OBJECT_0 != waited) {
|
||||
if (!CancelSynchronousIo(PHPDBG_G(sigio_watcher_thread))) {
|
||||
/* error out */
|
||||
}
|
||||
|
||||
if (!TerminateThread(PHPDBG_G(sigio_watcher_thread), 0)) {
|
||||
/* error out */
|
||||
}
|
||||
}
|
||||
|
||||
PHPDBG_G(swd).fd = -1;
|
||||
PHPDBG_G(swd).running = 0;
|
||||
PHPDBG_G(swd).flags = 0;
|
||||
PHPDBG_G(sigio_watcher_thread) = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
42
sapi/phpdbg/phpdbg_sigio_win32.h
Normal file
42
sapi/phpdbg/phpdbg_sigio_win32.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 7-4 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anatol Belski <ab@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PHPDBG_SIGIO_WIN32_H
|
||||
#define PHPDBG_SIGIO_WIN32_H
|
||||
|
||||
#include "phpdbg.h"
|
||||
#include "phpdbg_prompt.h"
|
||||
#include "phpdbg_io.h"
|
||||
|
||||
struct win32_sigio_watcher_data {
|
||||
zend_ulong flags;
|
||||
#ifdef ZTS
|
||||
void ***tsrm_ls;
|
||||
#endif
|
||||
int fd;
|
||||
zend_uchar running;
|
||||
};
|
||||
|
||||
void
|
||||
sigio_watcher_start(void);
|
||||
|
||||
void
|
||||
sigio_watcher_stop(void);
|
||||
|
||||
#endif /* PHPDBG_SIGIO_WIN32_H */
|
56
sapi/phpdbg/phpdbg_sigsafe.c
Normal file
56
sapi/phpdbg/phpdbg_sigsafe.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "phpdbg_sigsafe.h"
|
||||
#include "phpdbg.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define STR(x) #x
|
||||
#define EXP_STR(x) STR(x)
|
||||
|
||||
static void* zend_mm_mem_alloc(zend_mm_storage *storage, size_t size, size_t alignment) {
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (EXPECTED(size == PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) {
|
||||
PHPDBG_G(sigsafe_mem).allocated = 1;
|
||||
return PHPDBG_G(sigsafe_mem).mem;
|
||||
}
|
||||
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Tried to allocate more than " EXP_STR(PHPDBG_SIGSAFE_MEM_SIZE) " bytes from stack memory in signal handler ... bailing out of signal handler\n"));
|
||||
|
||||
if (*EG(bailout)) {
|
||||
LONGJMP(*EG(bailout), FAILURE);
|
||||
}
|
||||
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n"));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void zend_mm_mem_free(zend_mm_storage *storage, void *ptr, size_t size) {
|
||||
}
|
||||
|
||||
void phpdbg_set_sigsafe_mem(char *buffer TSRMLS_DC) {
|
||||
phpdbg_signal_safe_mem *mem = &PHPDBG_G(sigsafe_mem);
|
||||
mem->mem = buffer;
|
||||
mem->allocated = 0;
|
||||
|
||||
mem->storage.chunk_alloc = zend_mm_mem_alloc;
|
||||
mem->storage.chunk_free = zend_mm_mem_free;
|
||||
|
||||
mem->heap = zend_mm_startup_ex(&mem->storage);
|
||||
|
||||
mem->old_heap = zend_mm_set_heap(mem->heap TSRMLS_CC);
|
||||
}
|
||||
|
||||
zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D) {
|
||||
return PHPDBG_G(sigsafe_mem).old_heap;
|
||||
}
|
||||
|
||||
void phpdbg_clear_sigsafe_mem(TSRMLS_D) {
|
||||
zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC);
|
||||
PHPDBG_G(sigsafe_mem).mem = NULL;
|
||||
}
|
||||
|
||||
zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D) {
|
||||
return !!PHPDBG_G(sigsafe_mem).mem;
|
||||
}
|
||||
|
28
sapi/phpdbg/phpdbg_sigsafe.h
Normal file
28
sapi/phpdbg/phpdbg_sigsafe.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef PHPDBG_SIGSAFE_H
|
||||
#define PHPDBG_SIGSAFE_H
|
||||
|
||||
//#include "zend_mm_structs.h"
|
||||
|
||||
#define PHPDBG_SIGSAFE_MEM_SIZE ZEND_MM_CHUNK_SIZE
|
||||
//(1 << 20)
|
||||
|
||||
#include "zend.h"
|
||||
|
||||
typedef struct {
|
||||
char *mem;
|
||||
zend_bool allocated;
|
||||
zend_mm_heap *heap;
|
||||
zend_mm_heap *old_heap;
|
||||
zend_mm_storage storage;
|
||||
} phpdbg_signal_safe_mem;
|
||||
|
||||
#include "phpdbg.h"
|
||||
|
||||
zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D);
|
||||
|
||||
void phpdbg_set_sigsafe_mem(char *mem TSRMLS_DC);
|
||||
void phpdbg_clear_sigsafe_mem(TSRMLS_D);
|
||||
|
||||
zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D);
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -18,19 +18,14 @@
|
|||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#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"
|
||||
#elif defined(HAVE_SYS_IOCTL_H)
|
||||
#if defined(HAVE_SYS_IOCTL_H)
|
||||
# include "sys/ioctl.h"
|
||||
# ifndef GWINSZ_IN_SYS_IOCTL
|
||||
# include <termios.h>
|
||||
|
@ -170,27 +165,25 @@ PHPDBG_API const char *phpdbg_current_file(TSRMLS_D) /* {{{ */
|
|||
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);
|
||||
zend_string *lfname = zend_string_alloc(strlen(fname), 0);
|
||||
memcpy(lfname->val, zend_str_tolower_dup(fname, lfname->len), lfname->len + 1);
|
||||
|
||||
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);
|
||||
}
|
||||
zend_class_entry *ce;
|
||||
zend_string *lcname = zend_string_alloc(strlen(cname), 0);
|
||||
memcpy(lcname->val, zend_str_tolower_dup(cname, lcname->len), lcname->len + 1);
|
||||
ce = zend_lookup_class(lcname TSRMLS_CC);
|
||||
|
||||
efree(lcname);
|
||||
|
||||
if (ce) {
|
||||
func = zend_hash_find_ptr(&ce->function_table, lfname);
|
||||
}
|
||||
} else {
|
||||
func = zend_hash_find_ptr(EG(function_table), lfname);
|
||||
}
|
||||
|
||||
efree(lfname);
|
||||
return func;
|
||||
} /* }}} */
|
||||
|
||||
|
@ -224,103 +217,6 @@ PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{
|
|||
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */
|
||||
{
|
||||
int rc = 0;
|
||||
char *buffer = NULL;
|
||||
va_list args;
|
||||
|
||||
if (format != NULL && strlen(format) > 0L) {
|
||||
va_start(args, format);
|
||||
vspprintf(&buffer, 0, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* TODO(anyone) colours */
|
||||
|
||||
switch (type) {
|
||||
case P_ERROR:
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
rc = fprintf(fp,
|
||||
"\033[%sm[%s]\033[0m\n",
|
||||
PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer);
|
||||
} else {
|
||||
rc = fprintf(fp, "[%s]\n", buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case P_NOTICE:
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
rc = fprintf(fp,
|
||||
"\033[%sm[%s]\033[0m\n",
|
||||
PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer);
|
||||
} else {
|
||||
rc = fprintf(fp, "[%s]\n", buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case P_WRITELN: {
|
||||
if (buffer) {
|
||||
rc = fprintf(fp, "%s\n", buffer);
|
||||
} else {
|
||||
rc = fprintf(fp, "\n");
|
||||
}
|
||||
} break;
|
||||
|
||||
case P_WRITE:
|
||||
if (buffer) {
|
||||
rc = fprintf(fp, "%s", buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
/* no formatting on logging output */
|
||||
case P_LOG:
|
||||
if (buffer) {
|
||||
struct timeval tp;
|
||||
if (gettimeofday(&tp, NULL) == SUCCESS) {
|
||||
rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer);
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
efree(buffer);
|
||||
}
|
||||
|
||||
return rc;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
|
||||
int rc = 0;
|
||||
|
||||
va_list args;
|
||||
struct timeval tp;
|
||||
|
||||
va_start(args, fmt);
|
||||
if (gettimeofday(&tp, NULL) == SUCCESS) {
|
||||
char friendly[100];
|
||||
char *format = NULL, *buffer = NULL;
|
||||
const time_t tt = tp.tv_sec;
|
||||
|
||||
strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt));
|
||||
asprintf(
|
||||
&buffer, friendly, tp.tv_usec/1000);
|
||||
asprintf(
|
||||
&format, "[%s]: %s\n", buffer, fmt);
|
||||
rc = vfprintf(
|
||||
fp, format, args);
|
||||
|
||||
free(format);
|
||||
free(buffer);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return rc;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
const phpdbg_color_t *color = colors;
|
||||
|
@ -328,15 +224,13 @@ PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_
|
|||
while (color && color->name) {
|
||||
if (name_length == color->name_length &&
|
||||
memcmp(name, color->name, name_length) == SUCCESS) {
|
||||
phpdbg_debug(
|
||||
"phpdbg_get_color(%s, %lu): %s", name, name_length, color->code);
|
||||
phpdbg_debug("phpdbg_get_color(%s, %lu): %s", name, name_length, color->code);
|
||||
return color;
|
||||
}
|
||||
++color;
|
||||
}
|
||||
|
||||
phpdbg_debug(
|
||||
"phpdbg_get_color(%s, %lu): failed", name, name_length);
|
||||
phpdbg_debug("phpdbg_get_color(%s, %lu): failed", name, name_length);
|
||||
|
||||
return NULL;
|
||||
} /* }}} */
|
||||
|
@ -419,19 +313,15 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */
|
|||
} /* }}} */
|
||||
|
||||
int phpdbg_rebuild_symtable(TSRMLS_D) {
|
||||
if (!EG(active_op_array)) {
|
||||
phpdbg_error("No active op array!");
|
||||
if (!EG(current_execute_data) || !EG(current_execute_data)->func) {
|
||||
phpdbg_error("inactive", "type=\"op_array\"", "No active op array!");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (!EG(active_symbol_table)) {
|
||||
zend_rebuild_symbol_table(TSRMLS_C);
|
||||
|
||||
if (!EG(active_symbol_table)) {
|
||||
phpdbg_error("No active symbol table!");
|
||||
if (!zend_rebuild_symbol_table(TSRMLS_C)) {
|
||||
phpdbg_error("inactive", "type=\"symbol_table\"", "No active symbol table!");
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -453,3 +343,328 @@ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */
|
|||
#endif
|
||||
return columns;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_set_async_io(int fd) {
|
||||
#ifndef _WIN32
|
||||
int flags;
|
||||
fcntl(STDIN_FILENO, F_SETOWN, getpid());
|
||||
flags = fcntl(STDIN_FILENO, F_GETFL);
|
||||
fcntl(STDIN_FILENO, F_SETFL, flags | FASYNC);
|
||||
#endif
|
||||
}
|
||||
|
||||
int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry **ce TSRMLS_DC) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
|
||||
char *lc_name, *lc_free;
|
||||
int lc_length;
|
||||
|
||||
if (name == NULL || !name_length) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
lc_free = lc_name = emalloc(name_length + 1);
|
||||
zend_str_tolower_copy(lc_name, name, name_length);
|
||||
lc_length = name_length + 1;
|
||||
|
||||
if (lc_name[0] == '\\') {
|
||||
lc_name += 1;
|
||||
lc_length -= 1;
|
||||
}
|
||||
|
||||
phpdbg_try_access {
|
||||
*ce = zend_hash_str_find_ptr(EG(class_table), lc_name, lc_length);
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "class=\"%.*s\"", "Could not fetch class %.*s, invalid data source", name_length, name);
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
efree(lc_free);
|
||||
} else {
|
||||
zend_string *str_name = zend_string_init(name, name_length, 0);
|
||||
*ce = zend_lookup_class(str_name TSRMLS_CC);
|
||||
efree(str_name);
|
||||
}
|
||||
|
||||
return ce ? SUCCESS : FAILURE;
|
||||
}
|
||||
|
||||
char *phpdbg_get_property_key(char *key) {
|
||||
if (*key != 0) {
|
||||
return key;
|
||||
}
|
||||
return strchr(key + 1, 0) + 1;
|
||||
}
|
||||
|
||||
static int phpdbg_parse_variable_arg_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv, phpdbg_parse_var_func callback TSRMLS_DC) {
|
||||
return callback(name, len, keyname, keylen, parent, zv TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC) {
|
||||
return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_parse_variable_arg_wrapper, silent, callback TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC) {
|
||||
int ret = FAILURE;
|
||||
zend_bool new_index = 1;
|
||||
char *last_index;
|
||||
size_t index_len = 0;
|
||||
zval *zv;
|
||||
|
||||
if (len < 2 || *input != '$') {
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (i++ < len) {
|
||||
if (i == len) {
|
||||
new_index = 1;
|
||||
} else {
|
||||
switch (input[i]) {
|
||||
case '[':
|
||||
new_index = 1;
|
||||
break;
|
||||
case ']':
|
||||
break;
|
||||
case '>':
|
||||
if (last_index[index_len - 1] == '-') {
|
||||
new_index = 1;
|
||||
index_len--;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (new_index) {
|
||||
last_index = input + i;
|
||||
new_index = 0;
|
||||
}
|
||||
if (input[i - 1] == ']') {
|
||||
goto error;
|
||||
}
|
||||
index_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_index && index_len == 0) {
|
||||
zend_ulong numkey;
|
||||
zend_string *strkey;
|
||||
ZEND_HASH_FOREACH_KEY_PTR(parent, numkey, strkey, zv) {
|
||||
while (Z_TYPE_P(zv) == IS_INDIRECT) {
|
||||
zv = Z_INDIRECT_P(zv);
|
||||
}
|
||||
|
||||
if (i == len || (i == len - 1 && input[len - 1] == ']')) {
|
||||
char *key, *propkey;
|
||||
size_t namelen, keylen;
|
||||
char *name;
|
||||
char *keyname = estrndup(last_index, index_len);
|
||||
if (strkey) {
|
||||
key = strkey->val;
|
||||
keylen = strkey->len;
|
||||
} else {
|
||||
keylen = spprintf(&key, 0, "%llu", numkey);
|
||||
}
|
||||
propkey = phpdbg_get_property_key(key);
|
||||
name = emalloc(i + keylen + 2);
|
||||
namelen = sprintf(name, "%.*s%.*s%s", (int) i, input, keylen - (propkey - key), propkey, input[len - 1] == ']'?"]":"");
|
||||
if (!strkey) {
|
||||
efree(key);
|
||||
}
|
||||
|
||||
ret = callback(name, namelen, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
|
||||
} else if (Z_TYPE_P(zv) == IS_OBJECT) {
|
||||
phpdbg_parse_variable_with_arg(input, len, Z_OBJPROP_P(zv), i, callback, silent, arg TSRMLS_CC);
|
||||
} else if (Z_TYPE_P(zv) == IS_ARRAY) {
|
||||
phpdbg_parse_variable_with_arg(input, len, Z_ARRVAL_P(zv), i, callback, silent, arg TSRMLS_CC);
|
||||
} else {
|
||||
/* Ignore silently */
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
return ret;
|
||||
} else if (new_index) {
|
||||
char last_chr = last_index[index_len];
|
||||
last_index[index_len] = 0;
|
||||
if (!(zv = zend_symtable_str_find(parent, last_index, index_len))) {
|
||||
if (!silent) {
|
||||
phpdbg_error("variable", "type=\"undefined\" variable=\"%.*s\"", "%.*s is undefined", (int) i, input);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
while (Z_TYPE_P(zv) == IS_INDIRECT) {
|
||||
zv = Z_INDIRECT_P(zv);
|
||||
}
|
||||
|
||||
last_index[index_len] = last_chr;
|
||||
if (i == len) {
|
||||
char *name = estrndup(input, len);
|
||||
char *keyname = estrndup(last_index, index_len);
|
||||
|
||||
ret = callback(name, len, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
|
||||
} else if (Z_TYPE_P(zv) == IS_OBJECT) {
|
||||
parent = Z_OBJPROP_P(zv);
|
||||
} else if (Z_TYPE_P(zv) == IS_ARRAY) {
|
||||
parent = Z_ARRVAL_P(zv);
|
||||
} else {
|
||||
phpdbg_error("variable", "type=\"notiterable\" variable=\"%.*s\"", "%.*s is nor an array nor an object", (int) i, input);
|
||||
return FAILURE;
|
||||
}
|
||||
index_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
error:
|
||||
phpdbg_error("variable", "type=\"invalidinput\"", "Malformed input");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int phpdbg_is_auto_global(char *name, int len TSRMLS_DC) {
|
||||
int ret;
|
||||
zend_string *str = zend_string_init(name, len, 0);
|
||||
ret = zend_is_auto_global(str TSRMLS_CC);
|
||||
efree(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int phpdbg_xml_array_element_dump(zval *zv, zend_string *key, zend_ulong num TSRMLS_DC) {
|
||||
phpdbg_xml("<element");
|
||||
|
||||
phpdbg_try_access {
|
||||
if (key) { /* string key */
|
||||
phpdbg_xml(" name=\"%.*s\"", key->len, key->val);
|
||||
} else { /* numeric key */
|
||||
phpdbg_xml(" name=\"%ld\"", num);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_xml(" severity=\"error\" ></element>");
|
||||
return 0;
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
phpdbg_xml(">");
|
||||
|
||||
phpdbg_xml_var_dump(zv TSRMLS_CC);
|
||||
|
||||
phpdbg_xml("</element>");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phpdbg_xml_object_property_dump(zval *zv, zend_string *key, zend_ulong num TSRMLS_DC) {
|
||||
phpdbg_xml("<property");
|
||||
|
||||
phpdbg_try_access {
|
||||
if (key) { /* string key */
|
||||
const char *prop_name, *class_name;
|
||||
int unmangle = zend_unmangle_property_name(key, &class_name, &prop_name);
|
||||
|
||||
if (class_name && unmangle == SUCCESS) {
|
||||
phpdbg_xml(" name=\"%s\"", prop_name);
|
||||
if (class_name[0] == '*') {
|
||||
phpdbg_xml(" protection=\"protected\"");
|
||||
} else {
|
||||
phpdbg_xml(" class=\"%s\" protection=\"private\"", class_name);
|
||||
}
|
||||
} else {
|
||||
phpdbg_xml(" name=\"%.*s\" protection=\"public\"", key->len, key->val);
|
||||
}
|
||||
} else { /* numeric key */
|
||||
phpdbg_xml(" name=\"%ld\" protection=\"public\"", num);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_xml(" severity=\"error\" ></property>");
|
||||
return 0;
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
phpdbg_xml(">");
|
||||
|
||||
phpdbg_xml_var_dump(zv TSRMLS_CC);
|
||||
|
||||
phpdbg_xml("</property>");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define COMMON (is_ref ? "&" : "")
|
||||
|
||||
PHPDBG_API void phpdbg_xml_var_dump(zval *zv TSRMLS_DC) {
|
||||
HashTable *myht;
|
||||
zend_string *class_name, *key;
|
||||
zend_ulong num;
|
||||
zval *val;
|
||||
int (*element_dump_func)(zval *zv, zend_string *key, zend_ulong num TSRMLS_DC);
|
||||
zend_bool is_ref = 0;
|
||||
|
||||
int is_temp;
|
||||
|
||||
phpdbg_try_access {
|
||||
is_ref = Z_ISREF_P(zv) && GC_REFCOUNT(Z_COUNTED_P(zv)) > 1;
|
||||
ZVAL_DEREF(zv);
|
||||
|
||||
switch (Z_TYPE_P(zv)) {
|
||||
case IS_TRUE:
|
||||
phpdbg_xml("<bool refstatus=\"%s\" value=\"true\" />", COMMON);
|
||||
break;
|
||||
case IS_FALSE:
|
||||
phpdbg_xml("<bool refstatus=\"%s\" value=\"false\" />", COMMON);
|
||||
break;
|
||||
case IS_NULL:
|
||||
phpdbg_xml("<null refstatus=\"%s\" />", COMMON);
|
||||
break;
|
||||
case IS_LONG:
|
||||
phpdbg_xml("<int refstatus=\"%s\" value=\"" ZEND_LONG_FMT "\" />", COMMON, Z_LVAL_P(zv));
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
phpdbg_xml("<float refstatus=\"%s\" value=\"%.*G\" />", COMMON, (int) EG(precision), Z_DVAL_P(zv));
|
||||
break;
|
||||
case IS_STRING:
|
||||
phpdbg_xml("<string refstatus=\"%s\" length=\"%d\" value=\"%.*s\" />", COMMON, Z_STRLEN_P(zv), Z_STRLEN_P(zv), Z_STRVAL_P(zv));
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
myht = Z_ARRVAL_P(zv);
|
||||
if (ZEND_HASH_APPLY_PROTECTION(myht) && ++myht->u.v.nApplyCount > 1) {
|
||||
phpdbg_xml("<recursion />");
|
||||
--myht->u.v.nApplyCount;
|
||||
break;
|
||||
}
|
||||
phpdbg_xml("<array refstatus=\"%s\" num=\"%d\">", COMMON, zend_hash_num_elements(myht));
|
||||
element_dump_func = phpdbg_xml_array_element_dump;
|
||||
is_temp = 0;
|
||||
goto head_done;
|
||||
case IS_OBJECT:
|
||||
myht = Z_OBJDEBUG_P(zv, is_temp);
|
||||
if (myht && ++myht->u.v.nApplyCount > 1) {
|
||||
phpdbg_xml("<recursion />");
|
||||
--myht->u.v.nApplyCount;
|
||||
break;
|
||||
}
|
||||
|
||||
class_name = Z_OBJ_HANDLER_P(zv, get_class_name)(Z_OBJ_P(zv) TSRMLS_CC);
|
||||
phpdbg_xml("<object refstatus=\"%s\" class=\"%.*s\" id=\"%d\" num=\"%d\">", COMMON, class_name->len, class_name->val, Z_OBJ_HANDLE_P(zv), myht ? zend_hash_num_elements(myht) : 0);
|
||||
zend_string_release(class_name);
|
||||
|
||||
element_dump_func = phpdbg_xml_object_property_dump;
|
||||
head_done:
|
||||
if (myht) {
|
||||
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
|
||||
element_dump_func(val, key, num TSRMLS_CC);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) element_dump_func, 0);
|
||||
--myht->u.v.nApplyCount;
|
||||
if (is_temp) {
|
||||
zend_hash_destroy(myht);
|
||||
efree(myht);
|
||||
}
|
||||
}
|
||||
if (Z_TYPE_P(zv) == IS_ARRAY) {
|
||||
phpdbg_xml("</array>");
|
||||
} else {
|
||||
phpdbg_xml("</object>");
|
||||
}
|
||||
break;
|
||||
case IS_RESOURCE: {
|
||||
const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(zv) TSRMLS_CC);
|
||||
phpdbg_xml("<resource refstatus=\"%s\" id=\"%pd\" type=\"%ld\" />", COMMON, Z_RES_P(zv)->handle, type_name ? type_name : "unknown");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} phpdbg_end_try_access();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -33,52 +33,6 @@ PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC);
|
|||
PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*);
|
||||
PHPDBG_API const zend_function *phpdbg_get_function(const char*, const char* TSRMLS_DC);
|
||||
|
||||
/**
|
||||
* Error/notice/formatting helpers
|
||||
*/
|
||||
enum {
|
||||
P_ERROR = 1,
|
||||
P_NOTICE,
|
||||
P_WRITELN,
|
||||
P_WRITE,
|
||||
P_LOG
|
||||
};
|
||||
|
||||
#ifdef ZTS
|
||||
PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5);
|
||||
#else
|
||||
PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
|
||||
#endif
|
||||
|
||||
PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...);
|
||||
|
||||
#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||
|
||||
#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_writeln_ex(out, fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_write_ex(out, fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||
|
||||
#if PHPDBG_DEBUG
|
||||
# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define phpdbg_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* {{{ For writing blank lines */
|
||||
#define EMPTY NULL /* }}} */
|
||||
|
||||
/* {{{ For prompt lines */
|
||||
#define PROMPT "phpdbg>" /* }}} */
|
||||
|
||||
/* {{{ For separation */
|
||||
#define SEPARATE "------------------------------------------------" /* }}} */
|
||||
|
||||
/* {{{ Color Management */
|
||||
#define PHPDBG_COLOR_LEN 12
|
||||
#define PHPDBG_COLOR_D(color, code) \
|
||||
|
@ -122,26 +76,22 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */
|
|||
/* {{{ Console Width */
|
||||
PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_set_async_io(int fd);
|
||||
|
||||
int phpdbg_rebuild_symtable(TSRMLS_D);
|
||||
|
||||
#if PHP_VERSION_ID < 50500
|
||||
/* copy from zend_hash.c PHP 5.5 for 5.4 compatibility */
|
||||
static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) {
|
||||
Bucket *p;
|
||||
int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry **ce TSRMLS_DC);
|
||||
|
||||
p = pos ? (*pos) : ht->pInternalPointer;
|
||||
char *phpdbg_get_property_key(char *key);
|
||||
|
||||
if (!p) {
|
||||
Z_TYPE_P(key) = IS_NULL;
|
||||
} else if (p->nKeyLength) {
|
||||
Z_TYPE_P(key) = IS_STRING;
|
||||
Z_STRVAL_P(key) = IS_INTERNED(p->arKey) ? (char*)p->arKey : estrndup(p->arKey, p->nKeyLength - 1);
|
||||
Z_STRLEN_P(key) = p->nKeyLength - 1;
|
||||
} else {
|
||||
Z_TYPE_P(key) = IS_LONG;
|
||||
Z_LVAL_P(key) = p->h;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
typedef int (*phpdbg_parse_var_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv TSRMLS_DC);
|
||||
typedef int (*phpdbg_parse_var_with_arg_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv, void *arg TSRMLS_DC);
|
||||
|
||||
PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC);
|
||||
|
||||
int phpdbg_is_auto_global(char *name, int len TSRMLS_DC);
|
||||
|
||||
PHPDBG_API void phpdbg_xml_var_dump(zval *zv TSRMLS_DC);
|
||||
|
||||
#endif /* PHPDBG_UTILS_H */
|
||||
|
|
400
sapi/phpdbg/phpdbg_wait.c
Normal file
400
sapi/phpdbg/phpdbg_wait.c
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg_wait.h"
|
||||
#include "phpdbg_prompt.h"
|
||||
#include "ext/json/JSON_parser.h"
|
||||
#include "ext/standard/basic_functions.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
ZEND_EXTERN_MODULE_GLOBALS(json);
|
||||
|
||||
static void phpdbg_rebuild_http_globals_array(int type, const char *name TSRMLS_DC) {
|
||||
zval *zvp;
|
||||
if (Z_TYPE(PG(http_globals)[type]) != IS_UNDEF) {
|
||||
zval_dtor(&PG(http_globals)[type]);
|
||||
}
|
||||
if ((zvp = zend_hash_str_find(&EG(symbol_table).ht, name, strlen(name)))) {
|
||||
Z_ADDREF_P(zvp);
|
||||
PG(http_globals)[type] = *zvp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int phpdbg_dearm_autoglobals(zend_auto_global *auto_global TSRMLS_DC) {
|
||||
if (auto_global->name->len != sizeof("GLOBALS") - 1 || memcmp(auto_global->name->val, "GLOBALS", sizeof("GLOBALS") - 1)) {
|
||||
auto_global->armed = 0;
|
||||
}
|
||||
|
||||
return ZEND_HASH_APPLY_KEEP;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
HashTable *ht[2];
|
||||
HashPosition pos[2];
|
||||
} phpdbg_intersect_ptr;
|
||||
|
||||
static int phpdbg_array_data_compare(const void *a, const void *b TSRMLS_DC) {
|
||||
Bucket *f, *s;
|
||||
zval result;
|
||||
zval *first, *second;
|
||||
|
||||
f = *((Bucket **) a);
|
||||
s = *((Bucket **) b);
|
||||
|
||||
first = &f->val;
|
||||
second = &s->val;
|
||||
|
||||
if (string_compare_function(&result, first, second TSRMLS_CC) == FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Z_LVAL(result) < 0) {
|
||||
return -1;
|
||||
} else if (Z_LVAL(result) > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void phpdbg_array_intersect_init(phpdbg_intersect_ptr *info, HashTable *ht1, HashTable *ht2 TSRMLS_DC) {
|
||||
info->ht[0] = ht1;
|
||||
info->ht[1] = ht2;
|
||||
|
||||
zend_hash_sort(info->ht[0], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC);
|
||||
zend_hash_sort(info->ht[1], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC);
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(info->ht[0], &info->pos[0]);
|
||||
zend_hash_internal_pointer_reset_ex(info->ht[1], &info->pos[1]);
|
||||
}
|
||||
|
||||
/* -1 => first array, 0 => both arrays equal, 1 => second array */
|
||||
static int phpdbg_array_intersect(phpdbg_intersect_ptr *info, zval **ptr) {
|
||||
int ret;
|
||||
zval *zvp[2];
|
||||
int invalid = !info->ht[0] + !info->ht[1];
|
||||
|
||||
if (invalid > 0) {
|
||||
invalid = !info->ht[0];
|
||||
|
||||
if (!(*ptr = zend_hash_get_current_data_ex(info->ht[invalid], &info->pos[invalid]))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zend_hash_move_forward_ex(info->ht[invalid], &info->pos[invalid]);
|
||||
|
||||
return invalid ? 1 : -1;
|
||||
}
|
||||
|
||||
if (!(zvp[0] = zend_hash_get_current_data_ex(info->ht[0], &info->pos[0]))) {
|
||||
info->ht[0] = NULL;
|
||||
return phpdbg_array_intersect(info, ptr);
|
||||
}
|
||||
if (!(zvp[1] = zend_hash_get_current_data_ex(info->ht[1], &info->pos[1]))) {
|
||||
info->ht[1] = NULL;
|
||||
return phpdbg_array_intersect(info, ptr);
|
||||
}
|
||||
|
||||
ret = zend_binary_zval_strcmp(zvp[0], zvp[1]);
|
||||
|
||||
if (ret <= 0) {
|
||||
*ptr = zvp[0];
|
||||
zend_hash_move_forward_ex(info->ht[0], &info->pos[0]);
|
||||
}
|
||||
if (ret >= 0) {
|
||||
*ptr = zvp[1];
|
||||
zend_hash_move_forward_ex(info->ht[1], &info->pos[1]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC) {
|
||||
#ifdef HAVE_JSON
|
||||
zval *free_zv = NULL;
|
||||
zval zv, *zvp;
|
||||
HashTable *ht;
|
||||
php_json_decode(&zv, msg, len, 1, 1000 /* enough */ TSRMLS_CC);
|
||||
|
||||
if (JSON_G(error_code) != PHP_JSON_ERROR_NONE) {
|
||||
phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed JSON was sent to this socket, arborting");
|
||||
return;
|
||||
}
|
||||
|
||||
ht = Z_ARRVAL(zv);
|
||||
|
||||
/* Reapply symbol table */
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("GLOBALS"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
|
||||
{
|
||||
zval *srv;
|
||||
if ((srv = zend_hash_str_find(Z_ARRVAL_P(zvp), ZEND_STRL("_SERVER"))) && Z_TYPE_P(srv) == IS_ARRAY) {
|
||||
zval *script;
|
||||
if ((script = zend_hash_str_find(Z_ARRVAL_P(srv), ZEND_STRL("SCRIPT_FILENAME"))) && Z_TYPE_P(script) == IS_STRING) {
|
||||
phpdbg_param_t param;
|
||||
param.str = Z_STRVAL_P(script);
|
||||
PHPDBG_COMMAND_HANDLER(exec)(¶m TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PG(auto_globals_jit) = 0;
|
||||
zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_dearm_autoglobals TSRMLS_CC);
|
||||
|
||||
zend_hash_clean(&EG(symbol_table).ht);
|
||||
EG(symbol_table) = *Z_ARR_P(zvp);
|
||||
|
||||
/* Rebuild cookies, env vars etc. from GLOBALS (PG(http_globals)) */
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_POST, "_POST" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_GET, "_GET" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_COOKIE, "_COOKIE" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_SERVER, "_SERVER" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_ENV, "_ENV" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_FILES, "_FILES" TSRMLS_CC);
|
||||
|
||||
Z_ADDREF_P(zvp);
|
||||
free_zv = zvp;
|
||||
}
|
||||
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("input"))) && Z_TYPE_P(zvp) == IS_STRING) {
|
||||
if (SG(request_info).request_body) {
|
||||
php_stream_close(SG(request_info).request_body);
|
||||
}
|
||||
SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
|
||||
php_stream_truncate_set_size(SG(request_info).request_body, 0);
|
||||
php_stream_write(SG(request_info).request_body, Z_STRVAL_P(zvp), Z_STRLEN_P(zvp));
|
||||
}
|
||||
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("cwd"))) && Z_TYPE_P(zvp) == IS_STRING) {
|
||||
if (VCWD_CHDIR(Z_STRVAL_P(zvp)) == SUCCESS) {
|
||||
if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) {
|
||||
efree(BG(CurrentStatFile));
|
||||
BG(CurrentStatFile) = NULL;
|
||||
}
|
||||
if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) {
|
||||
efree(BG(CurrentLStatFile));
|
||||
BG(CurrentLStatFile) = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("sapi_name"))) && (Z_TYPE_P(zvp) == IS_STRING || Z_TYPE_P(zvp) == IS_NULL)) {
|
||||
if (PHPDBG_G(sapi_name_ptr)) {
|
||||
free(PHPDBG_G(sapi_name_ptr));
|
||||
}
|
||||
if (Z_TYPE_P(zvp) == IS_STRING) {
|
||||
PHPDBG_G(sapi_name_ptr) = sapi_module.name = strdup(Z_STRVAL_P(zvp));
|
||||
} else {
|
||||
PHPDBG_G(sapi_name_ptr) = sapi_module.name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("modules"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
|
||||
phpdbg_intersect_ptr pos;
|
||||
zval *module;
|
||||
zend_module_entry *mod;
|
||||
HashTable zv_registry;
|
||||
|
||||
/* intersect modules, unregister modules loaded "too much", announce not yet registered modules (phpdbg_notice) */
|
||||
|
||||
zend_hash_init(&zv_registry, zend_hash_num_elements(&module_registry), 0, ZVAL_PTR_DTOR, 0);
|
||||
ZEND_HASH_FOREACH_PTR(&module_registry, mod) {
|
||||
if (mod->name) {
|
||||
zval value;
|
||||
ZVAL_NEW_STR(&value, zend_string_init(mod->name, strlen(mod->name), 0));
|
||||
zend_hash_next_index_insert(&zv_registry, &value);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
phpdbg_array_intersect_init(&pos, &zv_registry, Z_ARRVAL_P(zvp) TSRMLS_CC);
|
||||
do {
|
||||
int mode = phpdbg_array_intersect(&pos, &module);
|
||||
if (mode < 0) {
|
||||
// loaded module, but not needed
|
||||
if (strcmp(PHPDBG_NAME, Z_STRVAL_P(module))) {
|
||||
zend_hash_del(&module_registry, Z_STR_P(module));
|
||||
}
|
||||
} else if (mode > 0) {
|
||||
// not loaded module
|
||||
if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_P(module))) {
|
||||
phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", Z_STRLEN_P(module), Z_STRVAL_P(module), Z_STRLEN_P(module), Z_STRVAL_P(module));
|
||||
}
|
||||
}
|
||||
} while (module);
|
||||
|
||||
zend_hash_clean(&zv_registry);
|
||||
}
|
||||
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("extensions"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
|
||||
zend_extension *extension;
|
||||
zend_llist_position pos;
|
||||
zval *name = NULL;
|
||||
zend_string *strkey;
|
||||
|
||||
extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
|
||||
while (extension) {
|
||||
extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
|
||||
|
||||
/* php_serach_array() body should be in some ZEND_API function... */
|
||||
ZEND_HASH_FOREACH_STR_KEY_PTR(Z_ARRVAL_P(zvp), strkey, name) {
|
||||
if (Z_TYPE_P(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_P(name), Z_STRLEN_P(name))) {
|
||||
break;
|
||||
}
|
||||
name = NULL;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
if (name) {
|
||||
/* sigh, breaking the encapsulation, there aren't any functions manipulating the llist at the place of the zend_llist_position */
|
||||
zend_llist_element *elm = pos;
|
||||
if (elm->prev) {
|
||||
elm->prev->next = elm->next;
|
||||
} else {
|
||||
zend_extensions.head = elm->next;
|
||||
}
|
||||
if (elm->next) {
|
||||
elm->next->prev = elm->prev;
|
||||
} else {
|
||||
zend_extensions.tail = elm->prev;
|
||||
}
|
||||
#if ZEND_EXTENSIONS_SUPPORT
|
||||
if (extension->shutdown) {
|
||||
extension->shutdown(extension);
|
||||
}
|
||||
#endif
|
||||
if (zend_extensions.dtor) {
|
||||
zend_extensions.dtor(elm->data);
|
||||
}
|
||||
pefree(elm, zend_extensions.persistent);
|
||||
zend_extensions.count--;
|
||||
} else {
|
||||
/* zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &hpos);
|
||||
if (Z_TYPE(key) == IS_LONG) {
|
||||
zend_hash_index_del(Z_ARRVAL_PP(zvpp), Z_LVAL(key));
|
||||
}
|
||||
*/
|
||||
zend_hash_del(Z_ARRVAL_P(zvp), strkey);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zvp), name) {
|
||||
if (Z_TYPE_P(name) == IS_STRING) {
|
||||
phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", Z_STRLEN_P(name), Z_STRVAL_P(name));
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
zend_ini_deactivate(TSRMLS_C);
|
||||
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("systemini"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
|
||||
zval *ini_entry;
|
||||
zend_ini_entry *original_ini;
|
||||
zend_string *key;
|
||||
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) {
|
||||
if (key && Z_TYPE_P(ini_entry) == IS_STRING) {
|
||||
if ((original_ini = zend_hash_find_ptr(EG(ini_directives), key))) {
|
||||
if (!original_ini->on_modify || original_ini->on_modify(original_ini, Z_STR_P(ini_entry), original_ini->mh_arg1, original_ini->mh_arg2, original_ini->mh_arg3, ZEND_INI_STAGE_ACTIVATE TSRMLS_CC) == SUCCESS) {
|
||||
if (original_ini->modified && original_ini->orig_value != original_ini->value) {
|
||||
efree(original_ini->value);
|
||||
}
|
||||
original_ini->value = Z_STR_P(ini_entry);
|
||||
Z_ADDREF_P(ini_entry); /* don't free the string */
|
||||
}
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
if ((zvp = zend_hash_str_find(ht, ZEND_STRL("userini"))) && Z_TYPE_P(zvp) == IS_ARRAY) {
|
||||
zval *ini_entry;
|
||||
zend_string *key;
|
||||
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) {
|
||||
if (key && Z_TYPE_P(ini_entry) == IS_STRING) {
|
||||
zend_alter_ini_entry_ex(key, Z_STR_P(ini_entry), ZEND_INI_PERDIR, ZEND_INI_STAGE_HTACCESS, 1 TSRMLS_CC);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
zval_dtor(&zv);
|
||||
if (free_zv) {
|
||||
/* separate freeing to not dtor the symtable too, just the container zval... */
|
||||
efree(free_zv);
|
||||
}
|
||||
|
||||
/* Reapply raw input */
|
||||
/* ??? */
|
||||
#endif
|
||||
}
|
||||
|
||||
PHPDBG_COMMAND(wait) /* {{{ */
|
||||
{
|
||||
#ifdef HAVE_JSON
|
||||
struct sockaddr_un local, remote;
|
||||
int rlen, sr, sl;
|
||||
unlink(PHPDBG_G(socket_path));
|
||||
if (PHPDBG_G(socket_server_fd) == -1) {
|
||||
int len;
|
||||
PHPDBG_G(socket_server_fd) = sl = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
local.sun_family = AF_UNIX;
|
||||
strcpy(local.sun_path, PHPDBG_G(socket_path));
|
||||
len = strlen(local.sun_path) + sizeof(local.sun_family);
|
||||
if (bind(sl, (struct sockaddr *)&local, len) == -1) {
|
||||
phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting", PHPDBG_G(socket_path));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
chmod(PHPDBG_G(socket_path), 0666);
|
||||
|
||||
listen(sl, 2);
|
||||
} else {
|
||||
sl = PHPDBG_G(socket_server_fd);
|
||||
}
|
||||
|
||||
rlen = sizeof(remote);
|
||||
sr = accept(sl, (struct sockaddr *) &remote, (socklen_t *) &rlen);
|
||||
|
||||
char msglen[5];
|
||||
int recvd = 4;
|
||||
|
||||
do {
|
||||
recvd -= recv(sr, &(msglen[4 - recvd]), recvd, 0);
|
||||
} while (recvd > 0);
|
||||
|
||||
recvd = *(size_t *) msglen;
|
||||
char *data = emalloc(recvd);
|
||||
|
||||
do {
|
||||
recvd -= recv(sr, &(data[(*(int *) msglen) - recvd]), recvd, 0);
|
||||
} while (recvd > 0);
|
||||
|
||||
phpdbg_webdata_decompress(data, *(int *) msglen TSRMLS_CC);
|
||||
|
||||
if (PHPDBG_G(socket_fd) != -1) {
|
||||
close(PHPDBG_G(socket_fd));
|
||||
}
|
||||
PHPDBG_G(socket_fd) = sr;
|
||||
|
||||
efree(data);
|
||||
|
||||
phpdbg_notice("wait", "import=\"success\"", "Successfully imported request data, stopped before executing");
|
||||
|
||||
return SUCCESS;
|
||||
#endif
|
||||
} /* }}} */
|
29
sapi/phpdbg/phpdbg_wait.h
Normal file
29
sapi/phpdbg/phpdbg_wait.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_WAIT_H
|
||||
#define PHPDBG_WAIT_H
|
||||
|
||||
#include "zend.h"
|
||||
#include "phpdbg.h"
|
||||
|
||||
PHPDBG_COMMAND(wait);
|
||||
|
||||
void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC);
|
||||
|
||||
#endif /* PHPDBG_WAIT_H */
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -30,6 +30,15 @@
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
const phpdbg_command_t phpdbg_watch_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s", 0),
|
||||
PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s", 0),
|
||||
PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s", 0),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
//#define HT_FROM_WATCH(watch) (watch->type == WATCH_ON_OBJECT ? watch->addr.obj->handlers->get_properties(watch->parent_container.zv TSRMLS_CC) : watch->type == WATCH_ON_ARRAY ? &watch->addr.arr->ht : NULL)
|
||||
#define HT_FROM_ZVP(zvp) (Z_TYPE_P(zvp) == IS_OBJECT ? Z_OBJPROP_P(zvp) : Z_TYPE_P(zvp) == IS_ARRAY ? Z_ARRVAL_P(zvp) : NULL)
|
||||
|
||||
typedef struct {
|
||||
void *page;
|
||||
|
@ -62,10 +71,8 @@ static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr TSRMLS_DC) {
|
|||
}
|
||||
|
||||
static void phpdbg_change_watchpoint_access(phpdbg_watchpoint_t *watch, int access TSRMLS_DC) {
|
||||
int m;
|
||||
|
||||
/* pagesize is assumed to be in the range of 2^x */
|
||||
m = mprotect(phpdbg_get_page_boundary(watch->addr.ptr), phpdbg_get_total_page_size(watch->addr.ptr, watch->size), access);
|
||||
mprotect(phpdbg_get_page_boundary(watch->addr.ptr), phpdbg_get_total_page_size(watch->addr.ptr, watch->size), access);
|
||||
}
|
||||
|
||||
static inline void phpdbg_activate_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
|
@ -99,35 +106,110 @@ void phpdbg_create_ht_watchpoint(HashTable *ht, phpdbg_watchpoint_t *watch) {
|
|||
watch->type = WATCH_ON_HASHTABLE;
|
||||
}
|
||||
|
||||
void phpdbg_watch_HashTable_dtor(zval **ptr);
|
||||
void phpdbg_watch_HashTable_dtor(zval *ptr);
|
||||
|
||||
static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC);
|
||||
static void phpdbg_delete_ht_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC);
|
||||
static void phpdbg_delete_zval_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC);
|
||||
static void phpdbg_delete_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC);
|
||||
|
||||
/* TODO: Store all the possible watches the refcounted may refer to (for displaying & deleting by identifier) */
|
||||
|
||||
static phpdbg_watchpoint_t *phpdbg_create_refcounted_watchpoint(phpdbg_watchpoint_t *parent, zend_refcounted *ref) {
|
||||
phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
watch->flags = parent->flags;
|
||||
watch->parent = parent;
|
||||
phpdbg_create_addr_watchpoint(&ref->refcount, sizeof(uint32_t), watch);
|
||||
watch->type = WATCH_ON_REFCOUNTED;
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static void phpdbg_add_watch_collision(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
phpdbg_watch_collision *cur;
|
||||
if ((cur = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->addr.ref))) {
|
||||
cur->num++;
|
||||
if (watch->flags == PHPDBG_WATCH_RECURSIVE) {
|
||||
cur->refs++;
|
||||
}
|
||||
} else {
|
||||
phpdbg_watch_collision coll;
|
||||
coll.num = 1;
|
||||
coll.refs = watch->flags == PHPDBG_WATCH_RECURSIVE;
|
||||
coll.watch = *watch;
|
||||
zend_hash_init(&coll.watches, 8, NULL, NULL, 0);
|
||||
cur = zend_hash_index_add_mem(&PHPDBG_G(watch_collisions), (zend_ulong) watch->addr.ref, &coll, sizeof(phpdbg_watch_collision));
|
||||
phpdbg_store_watchpoint(&cur->watch TSRMLS_CC);
|
||||
phpdbg_activate_watchpoint(&cur->watch TSRMLS_CC);
|
||||
}
|
||||
|
||||
zend_hash_str_add_ptr(&cur->watches, watch->parent->str, watch->parent->str_len, watch->parent);
|
||||
}
|
||||
|
||||
static void phpdbg_remove_watch_collision(zend_refcounted *ref TSRMLS_DC) {
|
||||
phpdbg_watch_collision *cur;
|
||||
if ((cur = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) ref))) {
|
||||
phpdbg_watchpoint_t *watch = cur->watch.parent;
|
||||
|
||||
if (watch->flags == PHPDBG_WATCH_RECURSIVE && !--cur->refs) {
|
||||
phpdbg_delete_watchpoints_recursive(watch TSRMLS_CC);
|
||||
}
|
||||
|
||||
zend_hash_str_del(&cur->watches, watch->str, watch->str_len);
|
||||
|
||||
if (!--cur->num) {
|
||||
phpdbg_deactivate_watchpoint(&cur->watch TSRMLS_CC);
|
||||
phpdbg_remove_watchpoint(&cur->watch TSRMLS_CC);
|
||||
|
||||
phpdbg_delete_watchpoint(watch TSRMLS_CC);
|
||||
|
||||
zend_hash_index_del(&PHPDBG_G(watch_collisions), (zend_ulong) ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int phpdbg_create_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
watch->flags |= PHPDBG_WATCH_SIMPLE;
|
||||
|
||||
phpdbg_store_watchpoint(watch TSRMLS_CC);
|
||||
zend_hash_add(&PHPDBG_G(watchpoints), watch->str, watch->str_len, &watch, sizeof(phpdbg_watchpoint_t *), NULL);
|
||||
zend_hash_str_add_ptr(&PHPDBG_G(watchpoints), watch->str, watch->str_len, watch);
|
||||
|
||||
if (watch->parent && watch->parent->type == WATCH_ON_ZVAL && Z_REFCOUNTED_P(watch->parent->addr.zv)) {
|
||||
phpdbg_add_watch_collision(phpdbg_create_refcounted_watchpoint(watch, Z_COUNTED_P(watch->parent->addr.zv)) TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (watch->type == WATCH_ON_ZVAL) {
|
||||
if (watch->parent_container) {
|
||||
phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong) watch->parent_container, watch->parent_container->pDestructor);
|
||||
watch->parent_container->pDestructor = (dtor_func_t) phpdbg_watch_HashTable_dtor;
|
||||
}
|
||||
|
||||
if (Z_ISREF_P(watch->addr.zv)) {
|
||||
phpdbg_watchpoint_t *ref = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
ref->flags = watch->flags;
|
||||
ref->str = watch->str;
|
||||
ref->str_len = watch->str_len;
|
||||
ref->parent = watch;
|
||||
ref->parent_container = NULL;
|
||||
phpdbg_create_zval_watchpoint(Z_REFVAL_P(watch->addr.zv), ref);
|
||||
|
||||
phpdbg_create_watchpoint(ref TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_activate_watchpoint(watch TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
HashTable *ht;
|
||||
static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *zv_watch TSRMLS_DC) {
|
||||
zval *zv = zv_watch->addr.zv;
|
||||
phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
HashTable *ht = HT_FROM_ZVP(zv);
|
||||
|
||||
switch (Z_TYPE_P(watch->addr.zv)) {
|
||||
case IS_ARRAY:
|
||||
ht = Z_ARRVAL_P(watch->addr.zv);
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
ht = Z_OBJPROP_P(watch->addr.zv);
|
||||
break;
|
||||
default:
|
||||
watch->parent = zv_watch;
|
||||
|
||||
if (!ht) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -135,18 +217,20 @@ static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC)
|
|||
|
||||
phpdbg_create_watchpoint(watch TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
if (Z_TYPE_P(zv) == IS_ARRAY) {
|
||||
watch->flags |= PHPDBG_WATCH_ARRAY;
|
||||
} else {
|
||||
watch->flags |= PHPDBG_WATCH_OBJECT;
|
||||
}
|
||||
|
||||
static char *phpdbg_get_property_key(char *key) {
|
||||
if (*key != 0) {
|
||||
return key;
|
||||
}
|
||||
return strchr(key + 1, 0) + 1;
|
||||
phpdbg_add_watch_collision(phpdbg_create_refcounted_watchpoint(watch, Z_COUNTED_P(zv)) TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
HashTable *ht;
|
||||
zval *zvp = watch->addr.zv;
|
||||
|
||||
if (watch->type != WATCH_ON_ZVAL) {
|
||||
return FAILURE;
|
||||
|
@ -155,25 +239,18 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_
|
|||
watch->flags |= PHPDBG_WATCH_RECURSIVE;
|
||||
phpdbg_create_watchpoint(watch TSRMLS_CC);
|
||||
|
||||
switch (Z_TYPE_P(watch->addr.zv)) {
|
||||
case IS_ARRAY:
|
||||
ht = Z_ARRVAL_P(watch->addr.zv);
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
ht = Z_OBJPROP_P(watch->addr.zv);
|
||||
break;
|
||||
default:
|
||||
ZVAL_DEREF(zvp);
|
||||
|
||||
if (!(ht = HT_FROM_ZVP(zvp))) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
{
|
||||
HashPosition position;
|
||||
zval **zv;
|
||||
zval *zv;
|
||||
zval key;
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(ht, &position);
|
||||
zend_hash_get_current_data_ex(ht, (void **)&zv, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(ht, &position)) {
|
||||
ZEND_HASH_FOREACH_VAL(ht, zv) {
|
||||
phpdbg_watchpoint_t *new_watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
|
||||
new_watch->flags = PHPDBG_WATCH_RECURSIVE;
|
||||
|
@ -182,19 +259,21 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_
|
|||
|
||||
zend_hash_get_current_key_zval_ex(ht, &key, &position);
|
||||
if (Z_TYPE(key) == IS_STRING) {
|
||||
new_watch->name_in_parent = zend_strndup(Z_STRVAL(key), Z_STRLEN(key));
|
||||
new_watch->name_in_parent = estrndup(Z_STRVAL(key), Z_STRLEN(key));
|
||||
new_watch->name_in_parent_len = Z_STRLEN(key);
|
||||
} else {
|
||||
new_watch->name_in_parent = NULL;
|
||||
new_watch->name_in_parent_len = asprintf(&new_watch->name_in_parent, "%ld", Z_LVAL(key));
|
||||
new_watch->name_in_parent_len = spprintf(&new_watch->name_in_parent, 0, "%lld", Z_LVAL(key));
|
||||
}
|
||||
|
||||
new_watch->str = NULL;
|
||||
new_watch->str_len = asprintf(&new_watch->str, "%.*s%s%s%s", (int)watch->str_len, watch->str, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(new_watch->name_in_parent), Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"]":"");
|
||||
new_watch->str_len = spprintf(&new_watch->str, 0, "%.*s%s%s%s", (int) watch->str_len, watch->str, Z_TYPE_P(zvp) == IS_ARRAY ? "[" : "->", phpdbg_get_property_key(new_watch->name_in_parent), Z_TYPE_P(zvp) == IS_ARRAY ? "]" : "");
|
||||
|
||||
phpdbg_create_zval_watchpoint(*zv, new_watch);
|
||||
while (Z_TYPE_P(zv) == IS_INDIRECT) {
|
||||
zv = Z_INDIRECT_P(zv);
|
||||
}
|
||||
|
||||
phpdbg_create_zval_watchpoint(zv, new_watch);
|
||||
phpdbg_create_recursive_watchpoint(new_watch TSRMLS_CC);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -202,12 +281,18 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_
|
|||
|
||||
new_watch->parent = watch;
|
||||
new_watch->parent_container = watch->parent_container;
|
||||
new_watch->name_in_parent = zend_strndup(watch->name_in_parent, watch->name_in_parent_len);
|
||||
new_watch->name_in_parent = estrndup(watch->name_in_parent, watch->name_in_parent_len);
|
||||
new_watch->name_in_parent_len = watch->name_in_parent_len;
|
||||
new_watch->str = NULL;
|
||||
new_watch->str_len = asprintf(&new_watch->str, "%.*s[]", (int)watch->str_len, watch->str);
|
||||
new_watch->str_len = spprintf(&new_watch->str, 0, "%.*s[]", (int) watch->str_len, watch->str);
|
||||
new_watch->flags = PHPDBG_WATCH_RECURSIVE;
|
||||
|
||||
if (Z_TYPE_P(zvp) == IS_ARRAY) {
|
||||
new_watch->flags |= PHPDBG_WATCH_ARRAY;
|
||||
} else {
|
||||
new_watch->flags |= PHPDBG_WATCH_OBJECT;
|
||||
}
|
||||
|
||||
phpdbg_create_ht_watchpoint(ht, new_watch);
|
||||
phpdbg_create_watchpoint(new_watch TSRMLS_CC);
|
||||
}
|
||||
|
@ -216,52 +301,58 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_
|
|||
}
|
||||
|
||||
static int phpdbg_delete_watchpoint_recursive(phpdbg_watchpoint_t *watch, zend_bool user_request TSRMLS_DC) {
|
||||
if (watch->type == WATCH_ON_HASHTABLE || (watch->type == WATCH_ON_ZVAL && (Z_TYPE_P(watch->addr.zv) == IS_ARRAY || Z_TYPE_P(watch->addr.zv) == IS_OBJECT))) {
|
||||
if (watch->type == WATCH_ON_HASHTABLE) {
|
||||
HashTable *ht;
|
||||
phpdbg_btree_result *result;
|
||||
|
||||
if (watch->type == WATCH_ON_HASHTABLE && user_request) {
|
||||
HashPosition position;
|
||||
zval **zv;
|
||||
zval key;
|
||||
char *str;
|
||||
int str_len;
|
||||
phpdbg_watchpoint_t **watchpoint;
|
||||
|
||||
ht = watch->addr.ht;
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(ht, &position);
|
||||
zend_hash_get_current_data_ex(ht, (void **)&zv, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(ht, &position)) {
|
||||
zend_hash_get_current_key_zval_ex(ht, &key, &position);
|
||||
str = NULL;
|
||||
if (Z_TYPE(key) == IS_STRING) {
|
||||
str_len = asprintf(&str, "%.*s%s%s%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(Z_STRVAL(key)), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":"");
|
||||
phpdbg_delete_ht_watchpoints_recursive(watch TSRMLS_CC);
|
||||
} else {
|
||||
str_len = asprintf(&str, "%.*s%s%li%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_LVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":"");
|
||||
}
|
||||
|
||||
if (zend_hash_find(&PHPDBG_G(watchpoints), str, str_len, (void **) &watchpoint) == SUCCESS) {
|
||||
phpdbg_delete_watchpoint_recursive(*watchpoint, 1 TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (Z_TYPE_P(watch->addr.zv)) {
|
||||
case IS_ARRAY:
|
||||
ht = Z_ARRVAL_P(watch->addr.zv);
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
ht = Z_OBJPROP_P(watch->addr.zv);
|
||||
break;
|
||||
}
|
||||
ht = HT_FROM_ZVP(watch->addr.zv);
|
||||
|
||||
if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) ht))) {
|
||||
phpdbg_delete_watchpoint_recursive((phpdbg_watchpoint_t *) result->ptr, user_request TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
} else if (watch->type == WATCH_ON_ZVAL) {
|
||||
phpdbg_delete_zval_watchpoints_recursive(watch TSRMLS_CC);
|
||||
}
|
||||
|
||||
return zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
return zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
}
|
||||
|
||||
static void phpdbg_delete_ht_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
zend_string *strkey;
|
||||
zend_long numkey;
|
||||
char *str;
|
||||
int str_len;
|
||||
phpdbg_watchpoint_t *watchpoint;
|
||||
|
||||
ZEND_HASH_FOREACH_KEY(watch->addr.ht, numkey, strkey) {
|
||||
if (strkey) {
|
||||
str_len = asprintf(&str, "%.*s%s%s%s", (int) watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", phpdbg_get_property_key(strkey->val), (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : "");
|
||||
} else {
|
||||
str_len = asprintf(&str, "%.*s%s%lli%s", (int) watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", numkey, (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : "");
|
||||
}
|
||||
|
||||
if ((watchpoint = zend_hash_str_find_ptr(&PHPDBG_G(watchpoints), str, str_len))) {
|
||||
phpdbg_delete_watchpoint_recursive(watchpoint, 1 TSRMLS_CC);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
static void phpdbg_delete_zval_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
if (Z_REFCOUNTED_P(watch->addr.zv)) {
|
||||
phpdbg_remove_watch_collision(Z_COUNTED_P(watch->addr.zv) TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
static void phpdbg_delete_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
if (watch->type == WATCH_ON_ZVAL) {
|
||||
phpdbg_delete_zval_watchpoints_recursive(watch TSRMLS_CC);
|
||||
} else if (watch->type == WATCH_ON_HASHTABLE) {
|
||||
phpdbg_delete_ht_watchpoints_recursive(watch TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) {
|
||||
|
@ -278,133 +369,52 @@ static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) {
|
|||
if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
|
||||
ret = phpdbg_delete_watchpoint_recursive(watch, 1 TSRMLS_CC);
|
||||
} else {
|
||||
ret = zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
ret = zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
}
|
||||
|
||||
free(tmp_watch->str);
|
||||
efree(tmp_watch->str);
|
||||
efree(tmp_watch->name_in_parent);
|
||||
efree(tmp_watch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) {
|
||||
int ret = FAILURE;
|
||||
zend_bool new_index = 1;
|
||||
char *last_index;
|
||||
int index_len = 0;
|
||||
zval **zv;
|
||||
|
||||
if (len < 2 || *input != '$') {
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (i++ < len) {
|
||||
if (i == len) {
|
||||
new_index = 1;
|
||||
} else {
|
||||
switch (input[i]) {
|
||||
case '[':
|
||||
new_index = 1;
|
||||
break;
|
||||
case ']':
|
||||
break;
|
||||
case '>':
|
||||
if (last_index[index_len - 1] == '-') {
|
||||
new_index = 1;
|
||||
index_len--;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (new_index) {
|
||||
last_index = input + i;
|
||||
new_index = 0;
|
||||
}
|
||||
if (input[i - 1] == ']') {
|
||||
goto error;
|
||||
}
|
||||
index_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_index && index_len == 0) {
|
||||
HashPosition position;
|
||||
for (zend_hash_internal_pointer_reset_ex(parent, &position);
|
||||
zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(parent, &position)) {
|
||||
if (i == len || (i == len - 1 && input[len - 1] == ']')) {
|
||||
zval *key = emalloc(sizeof(zval));
|
||||
static int phpdbg_watchpoint_parse_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) {
|
||||
int ret;
|
||||
phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
watch->flags = 0;
|
||||
zend_hash_get_current_key_zval_ex(parent, key, &position);
|
||||
convert_to_string(key);
|
||||
watch->str = malloc(i + Z_STRLEN_P(key) + 2);
|
||||
watch->str_len = sprintf(watch->str, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":"");
|
||||
efree(key);
|
||||
watch->name_in_parent = zend_strndup(last_index, index_len);
|
||||
watch->name_in_parent_len = index_len;
|
||||
watch->parent_container = parent;
|
||||
phpdbg_create_zval_watchpoint(*zv, watch);
|
||||
|
||||
ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
|
||||
} else if (Z_TYPE_PP(zv) == IS_OBJECT) {
|
||||
phpdbg_watchpoint_parse_input(input, len, Z_OBJPROP_PP(zv), i, callback, silent TSRMLS_CC);
|
||||
} else if (Z_TYPE_PP(zv) == IS_ARRAY) {
|
||||
phpdbg_watchpoint_parse_input(input, len, Z_ARRVAL_PP(zv), i, callback, silent TSRMLS_CC);
|
||||
} else {
|
||||
/* Ignore silently */
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} else if (new_index) {
|
||||
char last_chr = last_index[index_len];
|
||||
last_index[index_len] = 0;
|
||||
if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) {
|
||||
if (!silent) {
|
||||
phpdbg_error("%.*s is undefined", (int)i, input);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
last_index[index_len] = last_chr;
|
||||
if (i == len) {
|
||||
phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
watch->flags = 0;
|
||||
watch->str = zend_strndup(input, len);
|
||||
watch->str = name;
|
||||
watch->str_len = len;
|
||||
watch->name_in_parent = zend_strndup(last_index, index_len);
|
||||
watch->name_in_parent_len = index_len;
|
||||
watch->name_in_parent = keyname;
|
||||
watch->name_in_parent_len = keylen;
|
||||
watch->parent_container = parent;
|
||||
phpdbg_create_zval_watchpoint(*zv, watch);
|
||||
phpdbg_create_zval_watchpoint(zv, watch);
|
||||
|
||||
ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
|
||||
} else if (Z_TYPE_PP(zv) == IS_OBJECT) {
|
||||
parent = Z_OBJPROP_PP(zv);
|
||||
} else if (Z_TYPE_PP(zv) == IS_ARRAY) {
|
||||
parent = Z_ARRVAL_PP(zv);
|
||||
} else {
|
||||
phpdbg_error("%.*s is nor an array nor an object", (int)i, input);
|
||||
return FAILURE;
|
||||
}
|
||||
index_len = 0;
|
||||
}
|
||||
ret = callback(watch TSRMLS_CC);
|
||||
|
||||
if (ret != SUCCESS) {
|
||||
efree(watch);
|
||||
efree(name);
|
||||
efree(keyname);
|
||||
}
|
||||
|
||||
return ret;
|
||||
error:
|
||||
phpdbg_error("Malformed input");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) {
|
||||
return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, 0, callback TSRMLS_CC);
|
||||
}
|
||||
|
||||
static int phpdbg_watchpoint_parse_symtables(char *input, size_t len, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) {
|
||||
if (EG(This) && len >= 5 && !memcmp("$this", input, 5)) {
|
||||
zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), NULL);
|
||||
if (EG(scope) && len >= 5 && !memcmp("$this", input, 5)) {
|
||||
zend_hash_str_add(&EG(current_execute_data)->symbol_table->ht, ZEND_STRL("this"), &EG(current_execute_data)->This);
|
||||
}
|
||||
|
||||
if (zend_is_auto_global(input, len TSRMLS_CC) && phpdbg_watchpoint_parse_input(input, len, &EG(symbol_table), 0, callback, 1 TSRMLS_CC) != FAILURE) {
|
||||
if (phpdbg_is_auto_global(input, len TSRMLS_CC) && phpdbg_watchpoint_parse_input(input, len, &EG(symbol_table).ht, 0, callback, 1 TSRMLS_CC) != FAILURE) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return phpdbg_watchpoint_parse_input(input, len, EG(active_symbol_table), 0, callback, 0 TSRMLS_CC);
|
||||
return phpdbg_watchpoint_parse_input(input, len, &EG(current_execute_data)->symbol_table->ht, 0, callback, 0 TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHPDBG_WATCH(delete) /* {{{ */
|
||||
|
@ -412,9 +422,9 @@ PHPDBG_WATCH(delete) /* {{{ */
|
|||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
if (phpdbg_delete_var_watchpoint(param->str, param->len TSRMLS_CC) == FAILURE) {
|
||||
phpdbg_error("Nothing was deleted, no corresponding watchpoint found");
|
||||
phpdbg_error("watchdelete", "type=\"nowatch\"", "Nothing was deleted, no corresponding watchpoint found");
|
||||
} else {
|
||||
phpdbg_notice("Removed watchpoint %.*s", (int)param->len, param->str);
|
||||
phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Removed watchpoint %.*s", (int) param->len, param->str);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -433,7 +443,7 @@ PHPDBG_WATCH(recursive) /* {{{ */
|
|||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_recursive_watchpoint TSRMLS_CC) != FAILURE) {
|
||||
phpdbg_notice("Set recursive watchpoint on %.*s", (int)param->len, param->str);
|
||||
phpdbg_notice("watchrecursive", "variable=\"%.*s\"", "Set recursive watchpoint on %.*s", (int)param->len, param->str);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -452,7 +462,7 @@ PHPDBG_WATCH(array) /* {{{ */
|
|||
switch (param->type) {
|
||||
case STR_PARAM:
|
||||
if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_array_watchpoint TSRMLS_CC) != FAILURE) {
|
||||
phpdbg_notice("Set array watchpoint on %.*s", (int)param->len, param->str);
|
||||
phpdbg_notice("watcharray", "variable=\"%.*s\"", "Set array watchpoint on %.*s", (int)param->len, param->str);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -462,23 +472,23 @@ PHPDBG_WATCH(array) /* {{{ */
|
|||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_watch_HashTable_dtor(zval **zv) {
|
||||
void phpdbg_watch_HashTable_dtor(zval *zv) {
|
||||
phpdbg_btree_result *result;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
zval_ptr_dtor_wrapper(zv);
|
||||
|
||||
if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)*zv))) {
|
||||
if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) zv))) {
|
||||
phpdbg_watchpoint_t *watch = result->ptr;
|
||||
|
||||
PHPDBG_G(watchpoint_hit) = 1;
|
||||
|
||||
phpdbg_notice("%.*s was removed, removing watchpoint%s", (int)watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_RECURSIVE)?" recursively":"");
|
||||
phpdbg_notice("watchdelete", "variable=\"%.*s\" recursive=\"%s\"", "%.*s was removed, removing watchpoint%s", (int) watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_RECURSIVE) ? " recursively" : "");
|
||||
|
||||
if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
|
||||
phpdbg_delete_watchpoint_recursive(watch, 0 TSRMLS_CC);
|
||||
} else {
|
||||
zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -543,16 +553,15 @@ void phpdbg_watchpoints_clean(TSRMLS_D) {
|
|||
zend_hash_clean(&PHPDBG_G(watchpoints));
|
||||
}
|
||||
|
||||
static void phpdbg_watch_dtor(void *pDest) {
|
||||
phpdbg_watchpoint_t *watch = *(phpdbg_watchpoint_t **)pDest;
|
||||
static void phpdbg_watch_dtor(zval *pDest) {
|
||||
phpdbg_watchpoint_t *watch = (phpdbg_watchpoint_t *) Z_PTR_P(pDest);
|
||||
TSRMLS_FETCH();
|
||||
|
||||
phpdbg_deactivate_watchpoint(watch TSRMLS_CC);
|
||||
phpdbg_remove_watchpoint(watch TSRMLS_CC);
|
||||
|
||||
free(watch->str);
|
||||
free(watch->name_in_parent);
|
||||
efree(watch);
|
||||
efree(watch->str);
|
||||
efree(watch->name_in_parent);
|
||||
}
|
||||
|
||||
static void phpdbg_watch_mem_dtor(void *llist_data) {
|
||||
|
@ -580,40 +589,45 @@ void phpdbg_setup_watchpoints(TSRMLS_D) {
|
|||
zend_llist_init(&PHPDBG_G(watchlist_mem), sizeof(void *), phpdbg_watch_mem_dtor, 1);
|
||||
phpdbg_btree_init(&PHPDBG_G(watchpoint_tree), sizeof(void *) * 8);
|
||||
phpdbg_btree_init(&PHPDBG_G(watch_HashTables), sizeof(void *) * 8);
|
||||
zend_hash_init(&PHPDBG_G(watchpoints), 8, NULL, phpdbg_watch_dtor, 0 ZEND_FILE_LINE_CC);
|
||||
zend_hash_init(&PHPDBG_G(watchpoints), 8, NULL, phpdbg_watch_dtor, 0);
|
||||
zend_hash_init(&PHPDBG_G(watch_collisions), 8, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) {
|
||||
/* fetch all changes between dump->page and dump->page + dump->size */
|
||||
phpdbg_btree_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), (zend_ulong) dump->page, (zend_ulong) dump->page + dump->size);
|
||||
phpdbg_btree_result *result, *htresult;
|
||||
phpdbg_btree_result *result;
|
||||
int elementDiff;
|
||||
void *curTest;
|
||||
|
||||
dump->reenable_writing = 0;
|
||||
|
||||
while ((result = phpdbg_btree_next(&pos))) {
|
||||
phpdbg_watchpoint_t *watch = result->ptr, *htwatch;
|
||||
phpdbg_watchpoint_t *watch = result->ptr;
|
||||
void *oldPtr = (char *) &dump->data + ((size_t) watch->addr.ptr - (size_t) dump->page);
|
||||
char reenable = 1;
|
||||
int removed = 0;
|
||||
|
||||
if ((size_t) watch->addr.ptr < (size_t) dump->page || (size_t) watch->addr.ptr + watch->size > (size_t) dump->page + dump->size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Test if the zval was separated and if necessary move the watchpoint */
|
||||
if (zend_hash_find(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len + 1, &curTest) == SUCCESS) {
|
||||
if ((watch->type == WATCH_ON_HASHTABLE || watch->type == WATCH_ON_ZVAL) && watch->parent_container) {
|
||||
if ((curTest = zend_hash_str_find(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len))) {
|
||||
while (Z_TYPE_P((zval *) curTest) == IS_INDIRECT) {
|
||||
curTest = Z_INDIRECT_P((zval *) curTest);
|
||||
}
|
||||
|
||||
if (watch->type == WATCH_ON_HASHTABLE) {
|
||||
switch (Z_TYPE_PP((zval **)curTest)) {
|
||||
switch (Z_TYPE_P((zval *) curTest)) {
|
||||
case IS_ARRAY:
|
||||
curTest = (void *)Z_ARRVAL_PP((zval **)curTest);
|
||||
curTest = (void *) Z_ARRVAL_P((zval *) curTest);
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
curTest = (void *)Z_OBJPROP_PP((zval **)curTest);
|
||||
curTest = (void *) Z_OBJPROP_P((zval *) curTest);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
curTest = *(void **)curTest;
|
||||
}
|
||||
|
||||
if (curTest != watch->addr.ptr) {
|
||||
|
@ -625,86 +639,95 @@ static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) {
|
|||
|
||||
reenable = 0;
|
||||
}
|
||||
} else {
|
||||
removed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Show to the user what changed and delete watchpoint upon removal */
|
||||
if (memcmp(oldPtr, watch->addr.ptr, watch->size) != SUCCESS) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS || (watch->type == WATCH_ON_ZVAL && memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value))) || (watch->type == WATCH_ON_HASHTABLE
|
||||
#if ZEND_DEBUG
|
||||
&& !watch->addr.ht->inconsistent
|
||||
#endif
|
||||
&& zend_hash_num_elements((HashTable *)oldPtr) != zend_hash_num_elements(watch->addr.ht))) {
|
||||
zend_bool do_break = 0;
|
||||
|
||||
switch (watch->type) {
|
||||
case WATCH_ON_ZVAL:
|
||||
do_break = memcmp(oldPtr, watch->addr.zv, sizeof(zend_value) + sizeof(uint32_t) /* value + typeinfo */);
|
||||
break;
|
||||
case WATCH_ON_HASHTABLE:
|
||||
do_break = zend_hash_num_elements((HashTable *) oldPtr) != zend_hash_num_elements(watch->addr.ht);
|
||||
break;
|
||||
case WATCH_ON_REFCOUNTED:
|
||||
if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS) {
|
||||
do_break = memcmp(oldPtr, watch->addr.ref, sizeof(uint32_t) /* no zend_refcounted metadata info */);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (do_break) {
|
||||
PHPDBG_G(watchpoint_hit) = 1;
|
||||
|
||||
phpdbg_notice("Breaking on watchpoint %s", watch->str);
|
||||
phpdbg_notice("watchhit", "variable=\"%s\"", "Breaking on watchpoint %.*s", (int) watch->str_len, watch->str);
|
||||
phpdbg_xml("<watchdata %r>");
|
||||
}
|
||||
|
||||
switch (watch->type) {
|
||||
case WATCH_ON_ZVAL: {
|
||||
int removed = ((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc && !zend_symtable_exists(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len + 1);
|
||||
int show_value = memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value));
|
||||
int show_ref = ((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc || ((zval *)oldPtr)->is_ref__gc != watch->addr.zv->is_ref__gc;
|
||||
int show_value = memcmp(oldPtr, watch->addr.zv, sizeof(zval) - sizeof(uint32_t) /* no metadata info */);
|
||||
|
||||
if (removed || show_value) {
|
||||
phpdbg_write("Old value: ");
|
||||
if ((Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) && removed) {
|
||||
phpdbg_writeln("Value inaccessible, HashTable already destroyed");
|
||||
if (removed && (Z_TYPE_P((zval *) oldPtr) == IS_ARRAY || Z_TYPE_P((zval *) oldPtr) == IS_OBJECT)) {
|
||||
phpdbg_writeln("watchvalue", "type=\"old\" inaccessible=\"inaccessible\"", "Old value inaccessible, array or object (HashTable) already destroyed");
|
||||
} else {
|
||||
phpdbg_out("Old value: ");
|
||||
phpdbg_xml("<watchvalue %r type=\"old\">");
|
||||
zend_print_flat_zval_r((zval *) oldPtr TSRMLS_CC);
|
||||
phpdbg_writeln("");
|
||||
phpdbg_xml("</watchvalue>");
|
||||
phpdbg_out("\n");
|
||||
}
|
||||
}
|
||||
if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && (removed || show_ref)) {
|
||||
phpdbg_writeln("Old refcount: %d; Old is_ref: %d", ((zval *)oldPtr)->refcount__gc, ((zval *)oldPtr)->is_ref__gc);
|
||||
}
|
||||
|
||||
/* check if zval was removed */
|
||||
if (removed) {
|
||||
phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str);
|
||||
zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Watchpoint %.*s was unset, removing watchpoint", (int) watch->str_len, watch->str);
|
||||
zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
|
||||
reenable = 0;
|
||||
|
||||
if (Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) {
|
||||
goto remove_ht_watch;
|
||||
if (Z_REFCOUNTED_P((zval *) oldPtr)) {
|
||||
phpdbg_remove_watch_collision(Z_COUNTED_P((zval *) oldPtr) TSRMLS_CC);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (show_value) {
|
||||
phpdbg_write("New value: ");
|
||||
phpdbg_out("New value: ");
|
||||
phpdbg_xml("<watchvalue %r type=\"new\">");
|
||||
zend_print_flat_zval_r(watch->addr.zv TSRMLS_CC);
|
||||
phpdbg_writeln("");
|
||||
}
|
||||
if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && show_ref) {
|
||||
phpdbg_writeln("New refcount: %d; New is_ref: %d", watch->addr.zv->refcount__gc, watch->addr.zv->is_ref__gc);
|
||||
phpdbg_xml("</watchvalue>");
|
||||
phpdbg_out("\n");
|
||||
}
|
||||
|
||||
if ((Z_TYPE_P(watch->addr.zv) == IS_ARRAY && Z_ARRVAL_P(watch->addr.zv) != Z_ARRVAL_P((zval *)oldPtr)) || (Z_TYPE_P(watch->addr.zv) != IS_OBJECT && Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) {
|
||||
/* add new watchpoints if necessary */
|
||||
if (Z_PTR_P(watch->addr.zv) != Z_PTR_P((zval *) oldPtr)) {
|
||||
if (Z_REFCOUNTED_P((zval *) oldPtr)) {
|
||||
phpdbg_remove_watch_collision(Z_COUNTED_P((zval *) oldPtr) TSRMLS_CC);
|
||||
}
|
||||
if (Z_REFCOUNTED_P(watch->addr.zv)) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS) {
|
||||
phpdbg_writeln("watchrefcount", "type=\"new\" refcount=\"%d\"", "New refcount: %d", Z_COUNTED_P(watch->addr.zv)->refcount);
|
||||
}
|
||||
if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
|
||||
phpdbg_create_recursive_watchpoint(watch TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
if ((Z_TYPE_P((zval *)oldPtr) != IS_ARRAY || Z_ARRVAL_P(watch->addr.zv) == Z_ARRVAL_P((zval *)oldPtr)) && (Z_TYPE_P((zval *)oldPtr) != IS_OBJECT || Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) {
|
||||
break;
|
||||
}
|
||||
|
||||
remove_ht_watch:
|
||||
if ((htresult = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)Z_ARRVAL_P((zval *)oldPtr)))) {
|
||||
htwatch = htresult->ptr;
|
||||
zend_hash_del(&PHPDBG_G(watchpoints), htwatch->str, htwatch->str_len);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WATCH_ON_HASHTABLE:
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (watch->addr.ht->inconsistent) {
|
||||
phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str);
|
||||
#if 0 && ZEND_DEBUG
|
||||
if (watch->addr.arr->ht->inconsistent) {
|
||||
phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Watchpoint %.*s was unset, removing watchpoint", (int) watch->str_len, watch->str);
|
||||
zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
|
||||
reenable = 0;
|
||||
|
@ -712,13 +735,12 @@ remove_ht_watch:
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
elementDiff = zend_hash_num_elements((HashTable *) oldPtr) - zend_hash_num_elements(watch->addr.ht);
|
||||
if (elementDiff) {
|
||||
if (elementDiff > 0) {
|
||||
phpdbg_writeln("%d elements were removed from the array", elementDiff);
|
||||
phpdbg_writeln("watchsize", "removed=\"%d\"", "%d elements were removed from the array", elementDiff);
|
||||
} else {
|
||||
phpdbg_writeln("%d elements were added to the array", -elementDiff);
|
||||
phpdbg_writeln("watchsize", "added=\"%d\"", "%d elements were added to the array", -elementDiff);
|
||||
|
||||
/* add new watchpoints if necessary */
|
||||
if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
|
||||
|
@ -726,10 +748,25 @@ remove_ht_watch:
|
|||
}
|
||||
}
|
||||
}
|
||||
if (((HashTable *)oldPtr)->pInternalPointer != watch->addr.ht->pInternalPointer) {
|
||||
phpdbg_writeln("Internal pointer of array was changed");
|
||||
if (watch->addr.ht->nInternalPointer != ((HashTable *) oldPtr)->nInternalPointer) {
|
||||
phpdbg_writeln("watcharrayptr", "", "Internal pointer of array was changed");
|
||||
}
|
||||
break;
|
||||
case WATCH_ON_REFCOUNTED: {
|
||||
if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS) {
|
||||
phpdbg_writeln("watchrefcount", "type=\"old\" refcount=\"%d\"", "Old refcount: %d", ((zend_refcounted *) oldPtr)->refcount);
|
||||
|
||||
if (!removed) {
|
||||
phpdbg_writeln("watchrefcount", "type=\"old\" refcount=\"%d\"", "Old refcount: %d", ((zend_refcounted *) oldPtr)->refcount);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_break) {
|
||||
phpdbg_xml("</watchdata>");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,14 +798,15 @@ int phpdbg_print_changed_zvals(TSRMLS_D) {
|
|||
}
|
||||
|
||||
void phpdbg_list_watchpoints(TSRMLS_D) {
|
||||
HashPosition position;
|
||||
phpdbg_watchpoint_t **watch;
|
||||
phpdbg_watchpoint_t *watch;
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(watchpoints), &position);
|
||||
zend_hash_get_current_data_ex(&PHPDBG_G(watchpoints), (void**) &watch, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&PHPDBG_G(watchpoints), &position)) {
|
||||
phpdbg_writeln("%.*s", (int)(*watch)->str_len, (*watch)->str);
|
||||
}
|
||||
phpdbg_xml("<watchlist %r>");
|
||||
|
||||
ZEND_HASH_FOREACH_PTR(&PHPDBG_G(watchpoints), watch) {
|
||||
phpdbg_writeln("watchvariable", "variable=\"%.*s\" on=\"%s\" type=\"%s\"", "%.*s (%s, %s)", (int) watch->str_len, watch->str, watch->type == WATCH_ON_HASHTABLE ? "array" : watch->type == WATCH_ON_REFCOUNTED ? "refcount" : "variable", watch->flags == PHPDBG_WATCH_RECURSIVE ? "recursive" : "simple");
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
phpdbg_xml("</watchlist>");
|
||||
}
|
||||
|
||||
void phpdbg_watch_efree(void *ptr) {
|
||||
|
@ -781,7 +819,10 @@ void phpdbg_watch_efree(void *ptr) {
|
|||
phpdbg_watchpoint_t *watch = result->ptr;
|
||||
|
||||
if ((size_t) watch->addr.ptr + watch->size > (size_t) ptr) {
|
||||
zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
if (watch->type == WATCH_ON_ZVAL) {
|
||||
phpdbg_remove_watch_collision(Z_COUNTED_P(watch->addr.zv) TSRMLS_CC);
|
||||
}
|
||||
zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
@ -37,47 +37,49 @@ PHPDBG_WATCH(array);
|
|||
PHPDBG_WATCH(delete);
|
||||
PHPDBG_WATCH(recursive);
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*/
|
||||
|
||||
static const phpdbg_command_t phpdbg_watch_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s"),
|
||||
PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s"),
|
||||
PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s"),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
extern const phpdbg_command_t phpdbg_watch_commands[];
|
||||
|
||||
/* Watchpoint functions/typedefs */
|
||||
|
||||
typedef enum {
|
||||
WATCH_ON_ZVAL,
|
||||
WATCH_ON_HASHTABLE,
|
||||
WATCH_ON_REFCOUNTED,
|
||||
} phpdbg_watchtype;
|
||||
|
||||
|
||||
#define PHPDBG_WATCH_SIMPLE 0x0
|
||||
#define PHPDBG_WATCH_RECURSIVE 0x1
|
||||
#define PHPDBG_WATCH_ARRAY 0x2
|
||||
#define PHPDBG_WATCH_OBJECT 0x4
|
||||
|
||||
typedef struct _phpdbg_watchpoint_t phpdbg_watchpoint_t;
|
||||
|
||||
struct _phpdbg_watchpoint_t {
|
||||
union {
|
||||
zval *zv;
|
||||
HashTable *ht;
|
||||
zend_refcounted *ref;
|
||||
void *ptr;
|
||||
} addr;
|
||||
size_t size;
|
||||
phpdbg_watchtype type;
|
||||
char flags;
|
||||
phpdbg_watchpoint_t *parent;
|
||||
HashTable *parent_container;
|
||||
char *name_in_parent;
|
||||
size_t name_in_parent_len;
|
||||
char *str;
|
||||
size_t str_len;
|
||||
union {
|
||||
zval *zv;
|
||||
HashTable *ht;
|
||||
void *ptr;
|
||||
} addr;
|
||||
size_t size;
|
||||
phpdbg_watchtype type;
|
||||
char flags;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
phpdbg_watchpoint_t watch;
|
||||
unsigned int num;
|
||||
unsigned int refs;
|
||||
HashTable watches;
|
||||
} phpdbg_watch_collision;
|
||||
|
||||
void phpdbg_setup_watchpoints(TSRMLS_D);
|
||||
|
||||
#ifndef _WIN32
|
||||
|
|
170
sapi/phpdbg/phpdbg_webdata_transfer.c
Normal file
170
sapi/phpdbg/phpdbg_webdata_transfer.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "phpdbg_webdata_transfer.h"
|
||||
#include "ext/json/php_json.h"
|
||||
|
||||
static int phpdbg_is_auto_global(char *name, int len TSRMLS_DC) {
|
||||
int ret;
|
||||
zend_string *str = zend_string_init(name, len, 0);
|
||||
ret = zend_is_auto_global(str TSRMLS_CC);
|
||||
efree(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC) {
|
||||
#ifdef HAVE_JSON
|
||||
smart_str buf = {0};
|
||||
zval array;
|
||||
HashTable *ht;
|
||||
zval zv[9] = {{{0}}};
|
||||
|
||||
array_init(&array);
|
||||
ht = Z_ARRVAL(array);
|
||||
|
||||
/* fetch superglobals */
|
||||
{
|
||||
phpdbg_is_auto_global(ZEND_STRL("GLOBALS") TSRMLS_CC);
|
||||
/* might be JIT */
|
||||
phpdbg_is_auto_global(ZEND_STRL("_ENV") TSRMLS_CC);
|
||||
phpdbg_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC);
|
||||
phpdbg_is_auto_global(ZEND_STRL("_REQUEST") TSRMLS_CC);
|
||||
array_init(&zv[1]);
|
||||
zend_hash_copy(Z_ARRVAL(zv[1]), &EG(symbol_table).ht, NULL);
|
||||
Z_ARRVAL(zv[1])->pDestructor = NULL; /* we're operating on a copy! Don't double free zvals */
|
||||
zend_hash_str_del(Z_ARRVAL(zv[1]), ZEND_STRL("GLOBALS")); /* do not use the reference to itself in json */
|
||||
zend_hash_str_add(ht, ZEND_STRL("GLOBALS"), &zv[1]);
|
||||
}
|
||||
|
||||
/* save php://input */
|
||||
{
|
||||
php_stream *stream;
|
||||
zend_string *str;
|
||||
|
||||
stream = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
|
||||
if ((str = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0))) {
|
||||
ZVAL_STR(&zv[2], str);
|
||||
} else {
|
||||
ZVAL_EMPTY_STRING(&zv[2]);
|
||||
}
|
||||
Z_SET_REFCOUNT(zv[2], 1);
|
||||
zend_hash_str_add(ht, ZEND_STRL("input"), &zv[2]);
|
||||
}
|
||||
|
||||
/* change sapi name */
|
||||
{
|
||||
if (sapi_module.name) {
|
||||
ZVAL_STRING(&zv[6], sapi_module.name);
|
||||
} else {
|
||||
Z_TYPE_INFO(zv[6]) = IS_NULL;
|
||||
}
|
||||
zend_hash_str_add(ht, ZEND_STRL("sapi_name"), &zv[6]);
|
||||
Z_SET_REFCOUNT(zv[6], 1);
|
||||
}
|
||||
|
||||
/* handle modules / extensions */
|
||||
{
|
||||
zend_module_entry *module;
|
||||
zend_extension *extension;
|
||||
zend_llist_position pos;
|
||||
|
||||
array_init(&zv[7]);
|
||||
ZEND_HASH_FOREACH_PTR(&module_registry, module) {
|
||||
zval *value = ecalloc(sizeof(zval), 1);
|
||||
ZVAL_STRING(value, module->name);
|
||||
zend_hash_next_index_insert(Z_ARRVAL(zv[7]), value);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
zend_hash_str_add(ht, ZEND_STRL("modules"), &zv[7]);
|
||||
|
||||
array_init(&zv[8]);
|
||||
extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
|
||||
while (extension) {
|
||||
zval *value = ecalloc(sizeof(zval), 1);
|
||||
ZVAL_STRING(value, extension->name);
|
||||
zend_hash_next_index_insert(Z_ARRVAL(zv[8]), value);
|
||||
extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
|
||||
}
|
||||
zend_hash_str_add(ht, ZEND_STRL("extensions"), &zv[8]);
|
||||
}
|
||||
|
||||
/* switch cwd */
|
||||
if (SG(options) & SAPI_OPTION_NO_CHDIR) {
|
||||
char *ret = NULL;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
#if HAVE_GETCWD
|
||||
ret = VCWD_GETCWD(path, MAXPATHLEN);
|
||||
#elif HAVE_GETWD
|
||||
ret = VCWD_GETWD(path);
|
||||
#endif
|
||||
if (ret) {
|
||||
ZVAL_STRING(&zv[5], path);
|
||||
Z_SET_REFCOUNT(zv[5], 1);
|
||||
zend_hash_str_add(ht, ZEND_STRL("cwd"), &zv[5]);
|
||||
}
|
||||
}
|
||||
|
||||
/* get system ini entries */
|
||||
{
|
||||
zend_ini_entry *ini_entry;
|
||||
|
||||
array_init(&zv[3]);
|
||||
ZEND_HASH_FOREACH_PTR(EG(ini_directives), ini_entry) {
|
||||
zval *value = ecalloc(sizeof(zval), 1);
|
||||
if (ini_entry->modified) {
|
||||
if (!ini_entry->orig_value) {
|
||||
efree(value);
|
||||
continue;
|
||||
}
|
||||
ZVAL_STR(value, ini_entry->orig_value);
|
||||
} else {
|
||||
if (!ini_entry->value) {
|
||||
efree(value);
|
||||
continue;
|
||||
}
|
||||
ZVAL_STR(value, ini_entry->value);
|
||||
}
|
||||
zend_hash_add(Z_ARRVAL(zv[3]), ini_entry->name, value);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
zend_hash_str_add(ht, ZEND_STRL("systemini"), &zv[3]);
|
||||
}
|
||||
|
||||
/* get perdir ini entries */
|
||||
if (EG(modified_ini_directives)) {
|
||||
zend_ini_entry *ini_entry;
|
||||
|
||||
array_init(&zv[4]);
|
||||
ZEND_HASH_FOREACH_PTR(EG(ini_directives), ini_entry) {
|
||||
zval *value = ecalloc(sizeof(zval), 1);
|
||||
if (!ini_entry->value) {
|
||||
efree(value);
|
||||
continue;
|
||||
}
|
||||
ZVAL_STR(value, ini_entry->value);
|
||||
zend_hash_add(Z_ARRVAL(zv[4]), ini_entry->name, value);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
zend_hash_str_add(ht, ZEND_STRL("userini"), &zv[4]);
|
||||
}
|
||||
|
||||
/* encode data */
|
||||
php_json_encode(&buf, &array, 0 TSRMLS_CC);
|
||||
*msg = buf.s->val;
|
||||
*len = buf.s->len;
|
||||
zval_dtor(&array);
|
||||
#endif
|
||||
}
|
27
sapi/phpdbg/phpdbg_webdata_transfer.h
Normal file
27
sapi/phpdbg/phpdbg_webdata_transfer.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Bob Weinand <bwoebi@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHPDBG_WEBDATA_TRANSFER_H
|
||||
#define PHPDBG_WEBDATA_TRANSFER_H
|
||||
|
||||
#include "zend.h"
|
||||
#include "phpdbg.h"
|
||||
|
||||
PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC);
|
||||
|
||||
#endif /* PHPDBG_WEBDATA_TRANSFER_H */
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# setting error color
|
||||
# setting notice color
|
||||
# Failed to find breakpoint #0
|
||||
# oplog disabled
|
||||
# [Oplog off]
|
||||
# opened oplog test.log
|
||||
# nothing
|
||||
#################################################
|
||||
|
|
|
@ -4,15 +4,14 @@
|
|||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[User Class: test]
|
||||
#Methods (3):
|
||||
#[User Class: test (3 methods)]
|
||||
#L%d-%d test::testMethod() %s
|
||||
# L%d %s ZEND_RETURN C%d <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]
|
||||
#[User Method testMethod (1 ops)]
|
||||
# L%d-%d test::testMethod() %s
|
||||
# L%d %s ZEND_RETURN C%d <unused> <unused>
|
||||
#################################################
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[Cleaning Execution Environment]
|
||||
#Cleaning Execution Environment
|
||||
#Classes %d
|
||||
#Functions %d
|
||||
#Constants %d
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[Clearing Breakpoints]
|
||||
#Clearing Breakpoints
|
||||
#File%w%d
|
||||
#Functions%w%d
|
||||
#Methods%w%d
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
# expect: TEST::FORMAT
|
||||
# options: -rr
|
||||
#################################################
|
||||
#[Attempting compilation of %s]
|
||||
#[Success]
|
||||
#[Successful compilation of %s]
|
||||
#Hello World
|
||||
#[Script ended normally]
|
||||
#################################################
|
||||
<:
|
||||
define('OUT',
|
||||
|
|
|
@ -389,7 +389,7 @@ namespace phpdbg\testing {
|
|||
} break;
|
||||
|
||||
default: {
|
||||
$this->$chunks[0] = $chunks[1];
|
||||
$this->{$chunks[0]} = $chunks[1];
|
||||
}
|
||||
}
|
||||
} else switch(substr($trim, 1, 1)) {
|
||||
|
|
651
sapi/phpdbg/xml.md
Normal file
651
sapi/phpdbg/xml.md
Normal file
|
@ -0,0 +1,651 @@
|
|||
phpdbg XML format
|
||||
=================
|
||||
|
||||
Common attributes
|
||||
=================
|
||||
|
||||
severity
|
||||
--------
|
||||
|
||||
- indicates the genre of phpdbg system output
|
||||
- usually one of these values:
|
||||
- normal
|
||||
- notice
|
||||
- error
|
||||
|
||||
msgout
|
||||
------
|
||||
|
||||
- text message output related to the xml data (e.g. <intro severity="normal" help="help" msgout="To get help using phpdbg type &quot;help&quot; and press enter" />)
|
||||
|
||||
req
|
||||
---
|
||||
|
||||
- the request id, if one was passed to the last command (via -r %d, where %d is the id) (and the output is related to that message)
|
||||
|
||||
file
|
||||
----
|
||||
|
||||
- refers to a filename
|
||||
|
||||
method
|
||||
------
|
||||
|
||||
- format classname::methodname
|
||||
- refers to a method
|
||||
|
||||
function
|
||||
--------
|
||||
|
||||
- refers to a function
|
||||
|
||||
symbol
|
||||
------
|
||||
|
||||
- either function or method (is method if "::" are present)
|
||||
|
||||
opline
|
||||
------
|
||||
|
||||
- in hexadecimal format
|
||||
- refers to a specific pointer to a (zend_)op
|
||||
|
||||
opcode
|
||||
------
|
||||
|
||||
- refers to an opcode (ZEND_*)
|
||||
|
||||
type
|
||||
----
|
||||
|
||||
- general attribute for most errors, describes the genre of the error
|
||||
|
||||
General tags
|
||||
============
|
||||
|
||||
intro
|
||||
-----
|
||||
|
||||
- appears on startup if -q flag wasn't provided as command line arg
|
||||
- before any input possibility
|
||||
- attributes may be spread over multiple tags
|
||||
- wrapped in <intros> tag
|
||||
|
||||
### attributes ###
|
||||
|
||||
- version: current phpdbg version (as string)
|
||||
- help: command name for help
|
||||
- report: URL for bug reporting
|
||||
|
||||
|
||||
phpdbg
|
||||
------
|
||||
|
||||
- general text message output from phpdbg system
|
||||
|
||||
stream
|
||||
------
|
||||
|
||||
- any output by PHP itself (e.g. <stream type="stdout">test</stream>)
|
||||
|
||||
### attributes ###
|
||||
|
||||
- type: stderr or stdout
|
||||
|
||||
php
|
||||
---
|
||||
|
||||
- php error output
|
||||
|
||||
### attributes ###
|
||||
|
||||
- msg: the error message
|
||||
|
||||
|
||||
General error tags
|
||||
==================
|
||||
|
||||
command
|
||||
-------
|
||||
|
||||
- general errors about commands
|
||||
|
||||
### possible attributes ###
|
||||
|
||||
- type
|
||||
- toomanyargs: more arguments than allowed
|
||||
- noarg: argument missing
|
||||
- wrongarg: wrong type of argument (e.g. letters instead of integer)
|
||||
- toofewargs: not enough arguments
|
||||
- notfound: command (or subcommand) doesn't exist
|
||||
- ambiguous: command was ambiguous
|
||||
- invalidcommand: command input is totally invalid
|
||||
- (nostack: should not happen: is an internal error)
|
||||
- (emptystack: should not happen: is an internal error)
|
||||
- command: passed command
|
||||
- subcommand: passed subcommand (present if the error is related to the subcommand)
|
||||
- expected: count of expected arguments
|
||||
- got: type of argument for type "wrongarg"
|
||||
- num: if possible, information about which parameter had a wrong argument
|
||||
|
||||
inactive
|
||||
--------
|
||||
|
||||
- by type
|
||||
- op_array: nothing was yet compiled (probably because no execution context set)
|
||||
- symbol_table: no symbol table present (not yet initiailized or already destructed)
|
||||
- noexec: not in execution
|
||||
- memory_manager: using the native memory manager (malloc, free, realloc) instead of e.g. the Zend MM
|
||||
- notfound: file not found
|
||||
- nocontext: execution context was not set (or compilation had failed)
|
||||
- isrunning: command requires no running script
|
||||
|
||||
|
||||
Commands
|
||||
========
|
||||
|
||||
export
|
||||
------
|
||||
|
||||
- tag: <exportbreakpoint />
|
||||
- usually triggered by successful export command
|
||||
- may appear when cleaning to temporary store breakpoints
|
||||
- errors by type
|
||||
- openfailure: could not create file
|
||||
|
||||
### attributes ###
|
||||
|
||||
- count: number of exported breakpoints
|
||||
|
||||
break / info break
|
||||
------------------
|
||||
|
||||
- General tag for breakpoint creation, deletion and hits is "<breakpoint />"
|
||||
|
||||
### possible attributes ###
|
||||
|
||||
- id: the breakpoint id (if the leave command was executed, the id has the value "leave")
|
||||
- num: the nth opline of a function/method/file
|
||||
- add: has value "success"/"fail": a brekpoint was successfully/not added
|
||||
- pending: the breakpoint is waiting for resolving (e.g. a file opline on a not yet loaded file)
|
||||
- deleted: has value "success"/"fail": a breakpoint was successfully/not deleted
|
||||
- eval: the condition on conditional breakpoints
|
||||
- file
|
||||
- opline
|
||||
- opcode
|
||||
- symbol
|
||||
- function
|
||||
- method
|
||||
- line
|
||||
|
||||
|
||||
- listing breakpoints always in a container element "<breakpoints>"
|
||||
- Child nodes:
|
||||
- function
|
||||
- method
|
||||
- file
|
||||
- opline
|
||||
- methodopline
|
||||
- functionopline
|
||||
- fileopline
|
||||
- evalfunction
|
||||
- evalfunctionopline
|
||||
- evalmethod
|
||||
- evalmethodopline
|
||||
- evalfile
|
||||
- evalopline
|
||||
- eval
|
||||
- opcode
|
||||
- attributes:
|
||||
- name: name of the symbol (function/method/file/opcode)
|
||||
- disabled: empty value if enabled, non-empty if enabled
|
||||
|
||||
- errors (by type)
|
||||
- exists: the breakpoint already exists
|
||||
- maxoplines: tries to break at an opline (usedoplinenum) higher than the number of present oplines (in maxoplinenum)
|
||||
- nomethod: method doesn't exist
|
||||
- internalfunction: one cannot break on an opline of an internal function
|
||||
- notregular: tries to set a breakpoint in not a regular file
|
||||
- (invalidparameter: should not happen: is an internal error)
|
||||
|
||||
frame
|
||||
-----
|
||||
|
||||
- General tag for frames is "<frame>"
|
||||
- always has id attribute; if it only has id attribute, it just indicates current frame number, no other elements follow
|
||||
- may contain other elements (of type <arg>) when contained in <backtrace> tag
|
||||
- <arg> always contains a <stream> element, the value of the variable
|
||||
|
||||
### possible attributes ###
|
||||
|
||||
- id: the frame id, current frame has id 0 (frames with internal function calls have the same id than their called frame)
|
||||
- symbol ("{main}" is root frame)
|
||||
- file
|
||||
- line
|
||||
- internal: has value "internal" when being an internal function call (one cannot inspect that frame)
|
||||
|
||||
- being an error: (by type)
|
||||
- maxnum: tried to access a frame with a number heigher than existing (or < 0)
|
||||
|
||||
### attributes on <arg> ###
|
||||
|
||||
- variadic: has a non-empty value if the argument is variadic
|
||||
- name: variable name of parameter
|
||||
|
||||
info (subcommands)
|
||||
------------------
|
||||
|
||||
### break ###
|
||||
|
||||
- See above ("break / info break")
|
||||
|
||||
### files ###
|
||||
|
||||
- lists included files
|
||||
- <includedfileinfo num="" /> with num having an integer value, indicating the number of included files
|
||||
- <includedfile name=""/>: one per file, with name being the file path of the included file
|
||||
|
||||
### error ###
|
||||
|
||||
- gets last error
|
||||
- <lasterror error="" (file="" line="") />
|
||||
- error attribute contains the last error as a string, is empty if there's no last error
|
||||
|
||||
### vars / globals ###
|
||||
|
||||
- <variableinfo num="" /> with num having an integer value, indicating the number of (local or superglobal) variables
|
||||
- if info vars was used it'll have also one of these attributes:
|
||||
- method
|
||||
- function
|
||||
- file
|
||||
- opline
|
||||
- for each variable there is a <variable> followed by a <variabledetails> element
|
||||
- <variable address="" refcount="" type="" name="" />
|
||||
- address: pointer to zval (hexadecimal)
|
||||
- refcount: refcount of zval
|
||||
- type: the variable type (long, string, ...). If the value is "unknown", the other attributes are meaningless
|
||||
- name: the name of the variable
|
||||
- refstatus: empty if the zval is not a reference
|
||||
- class: the class the object in the zval is an instance of
|
||||
- resource: the type of the resource in the zval
|
||||
|
||||
### literal ###
|
||||
|
||||
- <literalinfo num="" /> with num having an integer value, indicating the number of literals, optional arguments are:
|
||||
- method
|
||||
- function
|
||||
- file
|
||||
- opline
|
||||
- for each literal there is a <literal> followed by a <stream type="stdout"> which prints the value of the literal
|
||||
- <literal id="" />: where id is the internal identifier of the literal
|
||||
|
||||
### memory ###
|
||||
|
||||
- Format:
|
||||
|
||||
<meminfo />
|
||||
<current />
|
||||
<used mem="" />
|
||||
<real mem="" />
|
||||
<peak />
|
||||
<used mem="" />
|
||||
<real mem="" />
|
||||
|
||||
- mem is an attribute whose value is a float. The memory is given in kilobytes (1 kB == 1024 bytes)
|
||||
|
||||
### classes ###
|
||||
|
||||
- <classinfo num="" /> with num having an integer value, indicating the number of loaded user-defined classes
|
||||
- Each class is enumerated with first a <class>, then an optional <parents> container and then a <classsource> element
|
||||
- The <parents> container contains the <class> elements of the parent of the last <class> element.
|
||||
- <class type="" flags="" name="" methodcount="" />
|
||||
- type: either "User" or "Internal"
|
||||
- flags: either "Interface", "Class" or "Abstract Class"
|
||||
- <classsource /> where the class was defined, if there are no attributes, location is unknown, usually defined by
|
||||
- file
|
||||
- line
|
||||
|
||||
### funcs ###
|
||||
|
||||
- <functioninfo num="" /> with num having an integer value, indicating the number of loaded user-defined functions
|
||||
- Each class is enumerated with first a <function> and then a <functionsource> element
|
||||
- <function name="" />
|
||||
- <functionsource /> where the function was defined, if there are no attributes, location is unknown, usually defined by
|
||||
- file
|
||||
- line
|
||||
|
||||
list
|
||||
----
|
||||
|
||||
- consists of <line> elements wrapped in a <list> container
|
||||
- <list file=""> is the container element with file being the filename
|
||||
- <line line="" code="" /> with value of code being the whole line of code in the line specified in the line attribute
|
||||
- current: this attribute is set to "current" if that line is the line where the executor currently is
|
||||
|
||||
print
|
||||
-----
|
||||
|
||||
### without a subcommand ###
|
||||
|
||||
- <print> elements are wrapped in a <printinfo> element
|
||||
- there may be a variable number of <print> elements with a variable count of args inside the <printinfo> element
|
||||
- possible args are:
|
||||
- readline: yes/no - readline enabled or disabled
|
||||
- libedit: yes/no - libedit enabled or disabled
|
||||
- context: current executing context
|
||||
- compiled: yes/no - are there actual compiled ops?
|
||||
- stepping: @@ TODO (meaningless for now) @@
|
||||
- quiet: on/off - should it always print the opline being currently executed?
|
||||
- oplog: on/off - are oplines logged in a file?
|
||||
- ops: number of opcodes in current executing context
|
||||
- vars: number of compiled variables (CV)
|
||||
- executing: yes/no - in executor?
|
||||
- vmret: the return value of the last executed opcode
|
||||
- default: continue
|
||||
- 1: return from vm
|
||||
- 2: enter stack frame
|
||||
- 3: leave stack frame
|
||||
- classes: number of classes
|
||||
- functions: number of functions
|
||||
- constants: number of constants
|
||||
- includes: number of included files
|
||||
|
||||
### with a subcommand ###
|
||||
|
||||
- introduced by <printinfo num="" /> (except for print opline) with num being the number of opcodes and one of these args:
|
||||
- file
|
||||
- method
|
||||
- function
|
||||
- class (then also type and flags attributes, see info classes command for their meanings)
|
||||
- symbol (also type and flags attributes; here the value of flags is either "Method" or "Function")
|
||||
- if there is a class method, the methods are all wrapped in a <printmethods> container
|
||||
- then comes a <printoplineinfo type="" /> where type is either "User" or "Internal"
|
||||
- the <printoplineinfo> has either a method or a function attribute
|
||||
- if the type is "Internal"
|
||||
- there are no oplines, it's an internal method or function
|
||||
- if the type is "User"
|
||||
- it has these attributes
|
||||
- startline: the first line of code where the method or function is defined
|
||||
- endline: the lastt line of code where the method or function is defined
|
||||
- file: the file of code where the method or function is defined
|
||||
- is followed by the oplines of that method or function (<print> elements)
|
||||
- <print line="%u" opline="%p" opcode="%s" op="%s" />
|
||||
- in case of print opline it emits a single <opline line="" opline="" opcode="" op="" file="" />
|
||||
|
||||
exec
|
||||
----
|
||||
|
||||
- command executing and compiling a given file
|
||||
- <exec type="unset" context="" />: indicates unsetting of the old context
|
||||
- <exec type="unsetops" />: indicates unsetting of the old compiled opcodes
|
||||
- <exec type="unchanged" />: same execution context choosen again
|
||||
- <exec type="set" context="" />: indicates setting of the new context
|
||||
- errors by tag
|
||||
- <compile>
|
||||
- openfailure: couldn't open file
|
||||
- compilefailure: The file indicated in context couldn't be compiled
|
||||
- <exec>
|
||||
- invalid: given context (attribute) is not matching a valid file or symlink
|
||||
- notfound: given context (attribute) does not exist
|
||||
|
||||
run / <stop> tag
|
||||
-------------------
|
||||
|
||||
- runs the script (set via exec command)
|
||||
- <stop type="end" />: script execution ended normally
|
||||
- (error) <stop type="bailout" /> the VM bailed out (usually because there was some error)
|
||||
- compile failures see under exec, errors, <compile>
|
||||
|
||||
step
|
||||
----
|
||||
|
||||
- steps by one line or opcode (as defined via set stepping) default is one line
|
||||
- returns back to the executor
|
||||
|
||||
continue
|
||||
--------
|
||||
|
||||
- returns back to the executor
|
||||
|
||||
until
|
||||
-----
|
||||
|
||||
- temporarily disables all the breakpoints on that line until that line was left once
|
||||
- returns back to the executor
|
||||
|
||||
finish
|
||||
------
|
||||
|
||||
- temporarily disables all the breakpoints until the end of the current frame
|
||||
- returns back to the executor
|
||||
|
||||
leave
|
||||
------
|
||||
|
||||
- temporarily disables all the breakpoints past the end of the current frame and then stops
|
||||
- returns back to the executor
|
||||
|
||||
back
|
||||
----
|
||||
|
||||
- prints backtrace
|
||||
- see frame command
|
||||
|
||||
ev
|
||||
--
|
||||
|
||||
- eval()uates some code
|
||||
- output wrapped in <eval> tags
|
||||
|
||||
sh
|
||||
--
|
||||
|
||||
- executes shell command
|
||||
- still pipes to stdout ... without wrapping <stream> !!! (@@ TODO @@)
|
||||
|
||||
source
|
||||
------
|
||||
|
||||
- executes a file in .phpdbginit format
|
||||
- errors by type
|
||||
- notfound: file not found
|
||||
|
||||
register
|
||||
--------
|
||||
|
||||
- registers a function to be used like a command
|
||||
- <register function="" />: successfully registered function
|
||||
- errors by type
|
||||
- notfound: no such function
|
||||
- inuse: function already registered
|
||||
|
||||
quit
|
||||
----
|
||||
|
||||
- quits phpdbg
|
||||
- if successful connection will be closed...
|
||||
|
||||
clean
|
||||
-----
|
||||
|
||||
- cleans environment (basically a shutdown + new startup)
|
||||
- <clean> tags wrapped in a <cleaninfo> container
|
||||
- possible attributes of <clean> tag
|
||||
- classes: number of classes
|
||||
- functions: number of functions
|
||||
- constants: number of constants
|
||||
- includes: number of included files
|
||||
|
||||
clear
|
||||
-----
|
||||
|
||||
- removes all breakpoints
|
||||
- <clear> tags wrapped in a <clearinfo> container
|
||||
- possible attributes of <clear> tag (value is always the number of defined breakpoints of that type)
|
||||
- files
|
||||
- functions
|
||||
- methods
|
||||
- oplines
|
||||
- fileoplines
|
||||
- functionoplines
|
||||
- methodoplines
|
||||
- eval
|
||||
|
||||
watch
|
||||
-----
|
||||
|
||||
- watchpoints generally are identified by a variable (one may need to switch frames first...)
|
||||
- <watch variable="" />, <watchrecursive variable="" /> and <watcharray variable="" /> (normal, array, recursive)
|
||||
- <watch> if error, by type:
|
||||
- undefined: tried to set a watchpoint on a not (yet) defined variable
|
||||
- notiterable: element which is tried to be accessed as an object or array is nor array nor object
|
||||
- invalidinput: generally malformed input
|
||||
- <watchdelete variable="" />: when "watch delete" was used on a watchpoint
|
||||
- (error) <watchdelete type="nowatch" />: that watchpoint doesn't exist, so couldn't be deleted
|
||||
- for hit watchpoints etc., see Other tags, <watch*>
|
||||
- when using watch list, <watchvariable> elements are wrapped in a <watchlist> container
|
||||
- <watchvariable variable="" on="" type="" />
|
||||
- variable: watched variable (may be a variable of another scope!)
|
||||
- on: values are array or variable, depending on what is watched
|
||||
- type: values are recursive or simple, depending on whether the watchpoint is checked recursively or not
|
||||
|
||||
set
|
||||
---
|
||||
|
||||
- a general error is type="wrongargs" where a wrong argument was passed to a subcommand; tag is then <set*>
|
||||
|
||||
### prompt ###
|
||||
|
||||
- without other args, a <setpromt str="" /> tag is emitted where the value of the str attribue is the value of the prompt
|
||||
- when there is another arg, the prompt is changed to that arg, no further xml answer
|
||||
|
||||
### break ###
|
||||
|
||||
- enables / disables a given breakpoint silently with no further xml answer
|
||||
- if the boolean switch is omitted, it emits current state in a <setbreak id="" active="" /> where active is on or off
|
||||
- error with type="nobreak", when no breakpoint with the given id exists
|
||||
|
||||
### breaks ###
|
||||
|
||||
- generally enables / disables breakpoint functionality silently with no futher xml answer
|
||||
- if the boolean switch is omitted, it emits current state in a <setbreaks active="" /> where active is on or off
|
||||
|
||||
### color ###
|
||||
|
||||
- sets the color on prompt, error or notices
|
||||
- <setcolor type="" color="" code="" />: code is the color code of color, type is either:
|
||||
- prompt
|
||||
- error
|
||||
- notice
|
||||
- errors by type:
|
||||
- nocolor: color doesn't exist
|
||||
- invalidtype: type wasn't one of the three allowed types
|
||||
|
||||
### colors ###
|
||||
|
||||
- generally enables / disables colors silently with no further xml answer
|
||||
- if the boolean switch is omitted, it emits current state in a <setcolors active="" /> where active is on or off
|
||||
|
||||
### oplog ###
|
||||
|
||||
- sets oplog
|
||||
- (error) <setoplog type="openfailure" file="" /> when it couldn't open the passed file path
|
||||
- <setoplog type="closingold" /> is emitted when there was a previous open oplog (and a file is passed)
|
||||
- if no further argument is passed, it emits current state in a <setoplog active="" /> where active is on or off
|
||||
|
||||
### quiet ###
|
||||
|
||||
- generally enables / disables quietness silently with no further xml answer
|
||||
- if the boolean switch is omitted, it emits current state in a <setquiet active="" /> where active is on or off
|
||||
|
||||
### setpping ###
|
||||
|
||||
- sets stepping to either opcode or line (so a step command will either advance one op or one line)
|
||||
- if no further argument is passed, it emits current state in a <setoplog type="" /> where active is opcode or line
|
||||
|
||||
### refcount ###
|
||||
|
||||
- generally enables / disables showing of refcount in watchpoint breaks silently with no further xml answer
|
||||
- if the boolean switch is omitted, it emits current state in a <setrefcount active="" /> where active is on or off
|
||||
|
||||
wait
|
||||
----
|
||||
|
||||
- internally executes exec, so exec will output first (if binding to socket worked)
|
||||
|
||||
### attributes ###
|
||||
|
||||
- import: has value "success"/"fail"
|
||||
- missingmodule/missingextension: modules/extensions loaded in the target SAPI, but not in phpdbg
|
||||
|
||||
### errors (by type) ###
|
||||
|
||||
- nosocket: couldn't establish socket
|
||||
- invaliddata: invalid JSON passed to socket
|
||||
|
||||
dl
|
||||
--
|
||||
|
||||
- loads a module or Zend extension at a given path
|
||||
- if a relative path is passed, it's relative to the extension_dir ini setting
|
||||
|
||||
### attributes ###
|
||||
|
||||
- extensiontype: "Zend extension" or "module"
|
||||
- name: the extension name
|
||||
- path: the path where it was loaded
|
||||
|
||||
### errors (by type) ###
|
||||
|
||||
- unsupported: dynamic extension loading is unsupported
|
||||
- relpath: relative path given, but no extension_dir defined
|
||||
- unknown: general error with internal DL_LOAD() (for message see msg attribute)
|
||||
- wrongapi: wrong Zend engine version (apineeded / apiinstalled attributes give information about the API versions)
|
||||
- wrongbuild: unmatched build versions (buildneeded / buildinstalled attributes give information about the build versions)
|
||||
- registerfailure: registering module failed
|
||||
- startupfailure: couldn't startup Zend extension / module
|
||||
- initfailure: couldn't initialize module
|
||||
- nophpso: passed shared object is not a valid Zend extension nor module
|
||||
|
||||
- errors may have the module or extension attribute when their name is already known at the point of failure
|
||||
|
||||
Other tags
|
||||
==========
|
||||
|
||||
<signal>
|
||||
-----------
|
||||
|
||||
- received caught signal
|
||||
|
||||
### attributes ###
|
||||
|
||||
- type: type of signal (e.g. SIGINT)
|
||||
|
||||
### by type ###
|
||||
|
||||
- SIGINT: interactive mode is entered...
|
||||
|
||||
<watch*>
|
||||
-----------
|
||||
|
||||
- generally emitted on hit watchpoint
|
||||
- <watchdelete variable="" />: when a variable was unset, the watchpoint is removed too
|
||||
- <watchhit variable="" />: when ever a watched variable is changed, followed by a <watchdata> container
|
||||
- <watchdata> may contain
|
||||
- for watchpoints on variables:
|
||||
- each of these <watch*> tags conatins a type attribute whose value is either "old" or "new")
|
||||
- <watchvalue type="" inaccessible="inaccessible" />: old value is inaccessible
|
||||
- <watchvalue type=""> may contain a <stream> element which indicates the old/new (type attribute) value of the variable
|
||||
- <watchrefcount type="" refcount="" isref="" />: old/new (type attribute) refcount and isref, both numbers
|
||||
- isref: if the value is 0, it's not a reference, else it is one
|
||||
- for watchpoints on arrays:
|
||||
- <watchsize> inspects size variations of an array (the sum):
|
||||
- removed: number of elements removed
|
||||
- added: number of elements added
|
||||
- <watcharrayptr>: if this tag appears, the internal pointer of the array way changed
|
||||
|
||||
<signalsegv>
|
||||
---------------
|
||||
|
||||
- generally emitted when data couldn't be fetched (e.g. by accessing inconsistent data); only used in hard interrupt mode
|
||||
- it might mean that data couldn't be fetched at all, or that only incomplete data was fetched (e.g. when a fixed number of following attributes are fetched, this tag will mark a stop of fetching if none or not all tags were printed)
|
102
sapi/phpdbg/zend_mm_structs.h
Normal file
102
sapi/phpdbg/zend_mm_structs.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
#ifndef ZEND_MM_STRUCTS_H
|
||||
#define ZEND_MM_STRUCTS_H
|
||||
|
||||
/* structs and macros defined in Zend/zend_alloc.c
|
||||
Needed for realizing watchpoints and sigsafe memory */
|
||||
|
||||
#include "zend.h"
|
||||
|
||||
#ifndef ZEND_MM_COOKIES
|
||||
# define ZEND_MM_COOKIES ZEND_DEBUG
|
||||
#endif
|
||||
|
||||
#define ZEND_MM_CACHE 1
|
||||
#ifndef ZEND_MM_CACHE_STAT
|
||||
# define ZEND_MM_CACHE_STAT 0
|
||||
#endif
|
||||
|
||||
typedef struct _zend_mm_block_info {
|
||||
#if ZEND_MM_COOKIES
|
||||
size_t _cookie;
|
||||
#endif
|
||||
size_t _size;
|
||||
size_t _prev;
|
||||
} zend_mm_block_info;
|
||||
|
||||
typedef struct _zend_mm_small_free_block {
|
||||
zend_mm_block_info info;
|
||||
#if ZEND_DEBUG
|
||||
unsigned int magic;
|
||||
#ifdef ZTS
|
||||
THREAD_T thread_id;
|
||||
#endif
|
||||
#endif
|
||||
struct _zend_mm_free_block *prev_free_block;
|
||||
struct _zend_mm_free_block *next_free_block;
|
||||
} zend_mm_small_free_block;
|
||||
|
||||
typedef struct _zend_mm_free_block {
|
||||
zend_mm_block_info info;
|
||||
#if ZEND_DEBUG
|
||||
unsigned int magic;
|
||||
#ifdef ZTS
|
||||
THREAD_T thread_id;
|
||||
#endif
|
||||
#endif
|
||||
struct _zend_mm_free_block *prev_free_block;
|
||||
struct _zend_mm_free_block *next_free_block;
|
||||
|
||||
struct _zend_mm_free_block **parent;
|
||||
struct _zend_mm_free_block *child[2];
|
||||
} zend_mm_free_block;
|
||||
|
||||
#define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
|
||||
(zend_mm_free_block *) ((char *)&heap->free_buckets[index * 2] + \
|
||||
sizeof(zend_mm_free_block *) * 2 - \
|
||||
sizeof(zend_mm_small_free_block))
|
||||
|
||||
#define ZEND_MM_REST_BUCKET(heap) \
|
||||
(zend_mm_free_block *)((char *)&heap->rest_buckets[0] + \
|
||||
sizeof(zend_mm_free_block *) * 2 - \
|
||||
sizeof(zend_mm_small_free_block))
|
||||
|
||||
#define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
|
||||
struct _zend_mm_heap {
|
||||
int use_zend_alloc;
|
||||
void *(*_malloc)(size_t);
|
||||
void (*_free)(void *);
|
||||
void *(*_realloc)(void *, size_t);
|
||||
size_t free_bitmap;
|
||||
size_t large_free_bitmap;
|
||||
size_t block_size;
|
||||
size_t compact_size;
|
||||
zend_mm_segment *segments_list;
|
||||
zend_mm_storage *storage;
|
||||
size_t real_size;
|
||||
size_t real_peak;
|
||||
size_t limit;
|
||||
size_t size;
|
||||
size_t peak;
|
||||
size_t reserve_size;
|
||||
void *reserve;
|
||||
int overflow;
|
||||
int internal;
|
||||
#if ZEND_MM_CACHE
|
||||
unsigned int cached;
|
||||
zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
|
||||
#endif
|
||||
zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
|
||||
zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
|
||||
zend_mm_free_block *rest_buckets[2];
|
||||
int rest_count;
|
||||
#if ZEND_MM_CACHE_STAT
|
||||
struct {
|
||||
int count;
|
||||
int max_count;
|
||||
int hit;
|
||||
int miss;
|
||||
} cache_stat[ZEND_MM_NUM_BUCKETS+1];
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue