mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Merge branch 'master' into xml-protocol
Conflicts: phpdbg.c phpdbg.h phpdbg_cmd.c phpdbg_cmd.h phpdbg_frame.c phpdbg_info.c phpdbg_list.c phpdbg_print.c phpdbg_prompt.c phpdbg_utils.c phpdbg_utils.h phpdbg_watch.c
This commit is contained in:
commit
8bc2881260
22
config.m4
22
config.m4
@ -3,12 +3,15 @@ dnl $Id$
|
||||
dnl
|
||||
|
||||
PHP_ARG_ENABLE(phpdbg, for phpdbg support,
|
||||
[ --enable-phpdbg Build phpdbg], no, no)
|
||||
[ --enable-phpdbg Build phpdbg], no, no)
|
||||
|
||||
PHP_ARG_ENABLE(phpdbg-webhelper, for phpdbg web SAPI support,
|
||||
[ --enable-phpdbg-webhelper Build phpdbg web SAPI support], yes, yes)
|
||||
|
||||
PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build,
|
||||
[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no)
|
||||
[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no)
|
||||
|
||||
if test "$PHP_PHPDBG" != "no"; then
|
||||
if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then
|
||||
AC_HEADER_TIOCGWINSZ
|
||||
AC_DEFINE(HAVE_PHPDBG, 1, [ ])
|
||||
|
||||
@ -18,8 +21,19 @@ if test "$PHP_PHPDBG" != "no"; then
|
||||
AC_DEFINE(PHPDBG_DEBUG, 0, [ ])
|
||||
fi
|
||||
|
||||
if test "$PHP_PHPDBG_WEBHELPER" != "no"; then
|
||||
if ! test -d ext/phpdbg_webhelper; then
|
||||
ln -s ../sapi/phpdbg ext/phpdbg_webhelper
|
||||
fi
|
||||
if test "$PHP_JSON" != "no"; then
|
||||
PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared)
|
||||
else
|
||||
AC_MSG_ERROR(Webhelper extension of phpdbg needs json enabled)
|
||||
fi
|
||||
fi
|
||||
|
||||
PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
|
||||
PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c"
|
||||
PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_wait.c"
|
||||
|
||||
if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then
|
||||
PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS"
|
||||
|
168
phpdbg.c
168
phpdbg.c
@ -36,6 +36,7 @@
|
||||
# include <sys/select.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/poll.h>
|
||||
# include <netinet/in.h>
|
||||
# include <unistd.h>
|
||||
# include <arpa/inet.h>
|
||||
@ -43,6 +44,10 @@
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
PHP_INI_BEGIN()
|
||||
STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, socket_path, zend_phpdbg_globals, phpdbg_globals)
|
||||
PHP_INI_END()
|
||||
|
||||
static zend_bool phpdbg_booted = 0;
|
||||
|
||||
#if PHP_VERSION_ID >= 50500
|
||||
@ -69,19 +74,26 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
|
||||
pg->bp_count = 0;
|
||||
pg->flags = PHPDBG_DEFAULT_FLAGS;
|
||||
pg->oplog = NULL;
|
||||
pg->io[PHPDBG_STDIN] = NULL;
|
||||
pg->io[PHPDBG_STDOUT] = NULL;
|
||||
pg->io[PHPDBG_STDERR] = NULL;
|
||||
memset(pg->io, 0, sizeof(pg->io));
|
||||
pg->frame.num = 0;
|
||||
pg->sapi_name_ptr = NULL;
|
||||
pg->socket_fd = -1;
|
||||
pg->socket_server_fd = -1;
|
||||
|
||||
pg->req_id = 0;
|
||||
pg->err_buf.active = 0;
|
||||
pg->err_buf.type = 0;
|
||||
|
||||
pg->input_buflen = 0;
|
||||
pg->sigsafe_mem.mem = NULL;
|
||||
pg->sigsegv_bailout = NULL;
|
||||
} /* }}} */
|
||||
|
||||
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
|
||||
{
|
||||
ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
|
||||
REGISTER_INI_ENTRIES();
|
||||
|
||||
#if PHP_VERSION_ID >= 50500
|
||||
zend_execute_old = zend_execute_ex;
|
||||
zend_execute_ex = phpdbg_execute_ex;
|
||||
@ -184,6 +196,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
|
||||
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
|
||||
zend_hash_destroy(&PHPDBG_G(seek));
|
||||
zend_hash_destroy(&PHPDBG_G(registered));
|
||||
zend_hash_destroy(&PHPDBG_G(file_sources));
|
||||
zend_hash_destroy(&PHPDBG_G(watchpoints));
|
||||
zend_llist_destroy(&PHPDBG_G(watchlist_mem));
|
||||
|
||||
@ -451,7 +464,7 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
|
||||
}
|
||||
|
||||
do {
|
||||
switch (phpdbg_interactive(TSRMLS_C)) {
|
||||
switch (phpdbg_interactive(1 TSRMLS_CC)) {
|
||||
case PHPDBG_LEAVE:
|
||||
case PHPDBG_FINISH:
|
||||
case PHPDBG_UNTIL:
|
||||
@ -521,6 +534,9 @@ static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {
|
||||
|
||||
static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
|
||||
send(PHPDBG_G(socket_fd), message, length, 0);
|
||||
}
|
||||
return phpdbg_script(P_STDOUT, "%.*s", length, message);
|
||||
} /* }}} */
|
||||
|
||||
@ -563,7 +579,9 @@ static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
|
||||
TSRMLS_FETCH();
|
||||
#endif
|
||||
|
||||
fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
|
||||
if (!phpdbg_active_sigsafe_mem(TSRMLS_C)) {
|
||||
fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
/* copied from sapi/cli/php_cli.c cli_register_file_handles */
|
||||
@ -739,17 +757,27 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */
|
||||
{
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (EG(in_execution)) {
|
||||
/* set signalled only when not interactive */
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
|
||||
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
|
||||
}
|
||||
} else {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
|
||||
/* we quit remote consoles on recv SIGINT */
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
|
||||
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
|
||||
zend_bailout();
|
||||
}
|
||||
} else {
|
||||
/* set signalled only when not interactive */
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
|
||||
char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
|
||||
|
||||
phpdbg_set_sigsafe_mem(mem TSRMLS_CC);
|
||||
zend_try {
|
||||
phpdbg_force_interruption(TSRMLS_C);
|
||||
} zend_end_try()
|
||||
phpdbg_clear_sigsafe_mem(TSRMLS_C);
|
||||
return;
|
||||
}
|
||||
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
|
||||
}
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
@ -810,12 +838,12 @@ static int phpdbg_remote_init(const char* address, short port, int *server, int
|
||||
*server = phpdbg_open_socket(address, port);
|
||||
|
||||
if (*server < 0) {
|
||||
phpdbg_rlog(stderr, "Initializing connection on %s:%d failed", address, port);
|
||||
phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%d failed", address, port);
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
phpdbg_rlog(stderr, "accepting connections on %s:%d", address, port);
|
||||
phpdbg_rlog(fileno(stderr), "accepting connections on %s:%d", address, port);
|
||||
{
|
||||
struct sockaddr_in address;
|
||||
socklen_t size = sizeof(address);
|
||||
@ -825,7 +853,7 @@ static int phpdbg_remote_init(const char* address, short port, int *server, int
|
||||
*socket = accept(*server, (struct sockaddr *) &address, &size);
|
||||
inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
|
||||
|
||||
phpdbg_rlog(stderr, "connection established from %s", buffer);
|
||||
phpdbg_rlog(fileno(stderr), "connection established from %s", buffer);
|
||||
}
|
||||
|
||||
dup2(*socket, fileno(stdout));
|
||||
@ -835,9 +863,65 @@ static int phpdbg_remote_init(const char* address, short port, int *server, int
|
||||
|
||||
*stream = fdopen(*socket, "r+");
|
||||
|
||||
phpdbg_set_async_io(*socket);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* This function *strictly* assumes that SIGIO is *only* used on the remote connection stream */
|
||||
void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */
|
||||
{
|
||||
int flags;
|
||||
size_t newlen;
|
||||
size_t i/*, last_nl*/;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
// if (!(info->si_band & POLLIN)) {
|
||||
// return; /* Not interested in writeablility etc., just interested in incoming data */
|
||||
// }
|
||||
|
||||
/* only non-blocking reading, avoid non-blocking writing */
|
||||
flags = fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_GETFL, 0);
|
||||
fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
do {
|
||||
char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
|
||||
size_t off = 0;
|
||||
|
||||
if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) {
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < newlen; i++) {
|
||||
switch (mem[off + i]) {
|
||||
case '\x03': /* ^C char */
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
|
||||
break; /* or quit ??? */
|
||||
}
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
|
||||
phpdbg_set_sigsafe_mem(mem TSRMLS_CC);
|
||||
zend_try {
|
||||
phpdbg_force_interruption(TSRMLS_C);
|
||||
} zend_end_try();
|
||||
phpdbg_clear_sigsafe_mem(TSRMLS_C);
|
||||
break;
|
||||
}
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
|
||||
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
|
||||
}
|
||||
break;
|
||||
/* case '\n':
|
||||
zend_llist_add_element(PHPDBG_G(stdin), strndup()
|
||||
last_nl = PHPDBG_G(stdin_buf).len + i;
|
||||
break;
|
||||
*/ }
|
||||
}
|
||||
off += i;
|
||||
} while (0);
|
||||
|
||||
|
||||
fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags);
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
|
||||
{
|
||||
int is_handled = FAILURE;
|
||||
@ -846,6 +930,9 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
|
||||
switch (sig) {
|
||||
case SIGBUS:
|
||||
case SIGSEGV:
|
||||
if (PHPDBG_G(sigsegv_bailout)) {
|
||||
LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE);
|
||||
}
|
||||
is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC);
|
||||
if (is_handled == FAILURE) {
|
||||
#ifdef ZEND_SIGNALS
|
||||
@ -931,9 +1018,13 @@ int main(int argc, char **argv) /* {{{ */
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigio_struct;
|
||||
struct sigaction signal_struct;
|
||||
signal_struct.sa_sigaction = phpdbg_signal_handler;
|
||||
signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
|
||||
sigio_struct.sa_sigaction = phpdbg_sigio_handler;
|
||||
sigio_struct.sa_flags = SA_SIGINFO;
|
||||
|
||||
|
||||
address = strdup("127.0.0.1");
|
||||
#endif
|
||||
@ -1150,18 +1241,6 @@ phpdbg_main:
|
||||
php_optind++;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* setup remote server if necessary */
|
||||
if (!cleaning && listen > 0) {
|
||||
if (phpdbg_remote_init(address, listen, &server, &socket, &stream) == FAILURE) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* set remote flag to stop service shutting down upon quit */
|
||||
remote = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sapi_name) {
|
||||
phpdbg->name = sapi_name;
|
||||
}
|
||||
@ -1216,7 +1295,23 @@ phpdbg_main:
|
||||
EXCEPTION_POINTERS *xp;
|
||||
__try {
|
||||
#endif
|
||||
zend_mm_heap *mm_heap = phpdbg_mm_get_heap();
|
||||
zend_mm_heap *mm_heap;
|
||||
|
||||
#ifndef _WIN32
|
||||
/* setup remote server if necessary */
|
||||
if (!cleaning && listen > 0) {
|
||||
if (phpdbg_remote_init(address, listen, &server, &socket, &stream) == FAILURE) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sigaction(SIGIO, &sigio_struct, NULL);
|
||||
|
||||
/* set remote flag to stop service shutting down upon quit */
|
||||
remote = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
mm_heap = phpdbg_mm_get_heap();
|
||||
|
||||
if (mm_heap->use_zend_alloc) {
|
||||
mm_heap->_malloc = phpdbg_malloc_wrapper;
|
||||
@ -1227,6 +1322,8 @@ phpdbg_main:
|
||||
|
||||
zend_activate(TSRMLS_C);
|
||||
|
||||
phpdbg_init_list(TSRMLS_C);
|
||||
|
||||
PHPDBG_G(original_free_function) = mm_heap->_free;
|
||||
mm_heap->_free = phpdbg_watch_efree;
|
||||
|
||||
@ -1246,6 +1343,8 @@ phpdbg_main:
|
||||
sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
|
||||
#endif
|
||||
|
||||
PHPDBG_G(sapi_name_ptr) = sapi_name;
|
||||
|
||||
php_output_activate(TSRMLS_C);
|
||||
php_output_deactivate(TSRMLS_C);
|
||||
|
||||
@ -1292,9 +1391,12 @@ phpdbg_main:
|
||||
}
|
||||
#endif
|
||||
|
||||
PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
|
||||
PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
|
||||
PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
|
||||
PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
|
||||
PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin);
|
||||
PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
|
||||
PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
|
||||
PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr;
|
||||
PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr);
|
||||
|
||||
#ifndef _WIN32
|
||||
PHPDBG_G(php_stdiop_write) = php_stream_stdio_ops.write;
|
||||
@ -1371,7 +1473,7 @@ phpdbg_interact:
|
||||
/* phpdbg main() */
|
||||
do {
|
||||
zend_try {
|
||||
phpdbg_interactive(TSRMLS_C);
|
||||
phpdbg_interactive(1 TSRMLS_CC);
|
||||
} zend_catch {
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
|
||||
FILE *bp_tmp_fp = fopen(bp_tmp_file, "w");
|
||||
@ -1484,8 +1586,8 @@ phpdbg_out:
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sapi_name) {
|
||||
free(sapi_name);
|
||||
if (PHPDBG_G(sapi_name_ptr)) {
|
||||
free(PHPDBG_G(sapi_name_ptr));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
116
phpdbg.h
116
phpdbg.h
@ -2,7 +2,7 @@
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2014 The PHP Group |
|
||||
| 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 |
|
||||
@ -64,7 +64,7 @@
|
||||
# include "TSRM.h"
|
||||
#endif
|
||||
|
||||
#ifdef LIBREADLINE
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
@ -72,14 +72,25 @@
|
||||
# include <editline/readline.h>
|
||||
#endif
|
||||
|
||||
#include "phpdbg_lexer.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_bp.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>
|
||||
#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>"
|
||||
/* }}} */
|
||||
|
||||
#if !defined(PHPDBG_WEBDATA_TRANSFER_H) && !defined(PHPDBG_WEBHELPER_H)
|
||||
|
||||
#ifdef ZTS
|
||||
# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
|
||||
@ -87,6 +98,15 @@ 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_lexer.h"
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_utils.h"
|
||||
#include "phpdbg_btree.h"
|
||||
#include "phpdbg_watch.h"
|
||||
|
||||
int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
||||
|
||||
#define PHPDBG_NEXT 2
|
||||
#define PHPDBG_UNTIL 3
|
||||
#define PHPDBG_FINISH 4
|
||||
@ -96,6 +116,19 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
||||
BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
|
||||
*/
|
||||
|
||||
/* {{{ tables */
|
||||
#define PHPDBG_BREAK_FILE 0
|
||||
#define PHPDBG_BREAK_SYM 1
|
||||
#define PHPDBG_BREAK_OPLINE 2
|
||||
#define PHPDBG_BREAK_METHOD 3
|
||||
#define PHPDBG_BREAK_COND 4
|
||||
#define PHPDBG_BREAK_OPCODE 5
|
||||
#define PHPDBG_BREAK_FUNCTION_OPLINE 6
|
||||
#define PHPDBG_BREAK_METHOD_OPLINE 7
|
||||
#define PHPDBG_BREAK_FILE_OPLINE 8
|
||||
#define PHPDBG_BREAK_MAP 9
|
||||
#define PHPDBG_BREAK_TABLES 10 /* }}} */
|
||||
|
||||
/* {{{ flags */
|
||||
#define PHPDBG_HAS_FILE_BP (1<<1)
|
||||
#define PHPDBG_HAS_SYM_BP (1<<2)
|
||||
@ -137,8 +170,10 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC);
|
||||
|
||||
#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)
|
||||
#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
|
||||
#define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP|PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP)
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -147,22 +182,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"
|
||||
#define PHPDBG_DEFAULT_PROMPT "prompt>"
|
||||
/* }}} */
|
||||
|
||||
/* {{{ 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)
|
||||
@ -192,8 +232,14 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
||||
int bp_count; /* breakpoint count */
|
||||
int vmret; /* return from last opcode handler execution */
|
||||
|
||||
zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
|
||||
HashTable file_sources;
|
||||
|
||||
FILE *oplog; /* opline log */
|
||||
FILE *io[PHPDBG_IO_FDS]; /* io */
|
||||
struct {
|
||||
FILE *ptr;
|
||||
int fd;
|
||||
} io[PHPDBG_IO_FDS]; /* io */
|
||||
#ifndef _WIN32
|
||||
size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC);
|
||||
#endif
|
||||
@ -201,7 +247,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
||||
struct {
|
||||
zend_bool active;
|
||||
int type;
|
||||
FILE *fp;
|
||||
int fd;
|
||||
char *tag;
|
||||
char *msg;
|
||||
int msglen;
|
||||
@ -215,22 +261,20 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
||||
char *buffer; /* buffer */
|
||||
zend_bool last_was_newline; /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */
|
||||
|
||||
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) */
|
||||
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 */
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
123
phpdbg_cmd.c
123
phpdbg_cmd.c
@ -636,14 +636,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 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) {
|
||||
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)) {
|
||||
@ -655,15 +655,15 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
||||
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;
|
||||
}
|
||||
@ -677,11 +677,9 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
||||
switch (matches) {
|
||||
case 0:
|
||||
if (parent) {
|
||||
phpdbg_error("command", "type=\"notfound\" command=\"%s\" subcommand=\"%s\"", "The command \"%s %s\" could not be found",
|
||||
parent->name, name->str);
|
||||
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);
|
||||
phpdbg_error("command", "type=\"notfound\" command=\"%s\"", "The command \"%s\" could not be found", name->str);
|
||||
}
|
||||
return parent;
|
||||
|
||||
@ -698,9 +696,9 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
||||
|
||||
while (it < matches) {
|
||||
if (!list) {
|
||||
list = emalloc(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 = erealloc(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;
|
||||
@ -714,8 +712,7 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
||||
}
|
||||
|
||||
/* ", " 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);
|
||||
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;
|
||||
@ -732,7 +729,7 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ */
|
||||
PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack 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;
|
||||
|
||||
@ -746,7 +743,7 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack TSRMLS_DC) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
top = (phpdbg_param_t*) stack->next;
|
||||
top = (phpdbg_param_t *) stack->next;
|
||||
|
||||
switch (top->type) {
|
||||
case EVAL_PARAM:
|
||||
@ -755,11 +752,18 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack TSRMLS_DC) {
|
||||
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);
|
||||
@ -768,9 +772,14 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack TSRMLS_DC) {
|
||||
handler = phpdbg_stack_resolve(phpdbg_prompt_commands, NULL, &top TSRMLS_CC);
|
||||
|
||||
if (handler) {
|
||||
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;
|
||||
}
|
||||
|
||||
phpdbg_activate_err_buf(0 TSRMLS_CC);
|
||||
phpdbg_free_err_buf(TSRMLS_C);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -787,15 +796,11 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack 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) {
|
||||
@ -806,35 +811,56 @@ disconnect:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT)
|
||||
#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT))
|
||||
#if !USE_LIB_STAR
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
|
||||
if (!phpdbg_out("%s", phpdbg_get_prompt(TSRMLS_C))) {
|
||||
goto disconnect;
|
||||
}
|
||||
PHPDBG_G(last_was_newline) = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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])) {
|
||||
cmd = buf;
|
||||
} else goto disconnect;
|
||||
} else {
|
||||
int bytes = 0, len = PHPDBG_G(input_buflen);
|
||||
if (PHPDBG_G(input_buflen)) {
|
||||
memcpy(buf, PHPDBG_G(input_buffer), len);
|
||||
}
|
||||
|
||||
while ((bytes = read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len)) > 0) {
|
||||
int i;
|
||||
for (i = len; i < len + bytes; i++) {
|
||||
if (buf[i] == '\n') {
|
||||
PHPDBG_G(input_buflen) = len + bytes - 1 - i;
|
||||
if (PHPDBG_G(input_buflen)) {
|
||||
memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen));
|
||||
}
|
||||
if (i != PHPDBG_MAX_CMD - 1) {
|
||||
buf[i + 1] = 0;
|
||||
}
|
||||
cmd = buf;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
len += bytes;
|
||||
}
|
||||
|
||||
if (bytes <= 0) {
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
cmd = buf;
|
||||
}
|
||||
#if USE_LIB_STAR
|
||||
else {
|
||||
cmd = readline(phpdbg_get_prompt(TSRMLS_C));
|
||||
PHPDBG_G(last_was_newline) = 1;
|
||||
}
|
||||
|
||||
if (!cmd) {
|
||||
@ -845,13 +871,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
|
||||
@ -885,4 +913,3 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */
|
||||
{
|
||||
efree(*input);
|
||||
} /* }}} */
|
||||
|
||||
|
25
phpdbg_cmd.h
25
phpdbg_cmd.h
@ -86,6 +86,8 @@ struct _phpdbg_param {
|
||||
#define YYSTYPE phpdbg_param_t
|
||||
#endif
|
||||
|
||||
#define PHPDBG_ASYNC_SAFE 1
|
||||
|
||||
typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t* TSRMLS_DC);
|
||||
|
||||
typedef struct _phpdbg_command_t phpdbg_command_t;
|
||||
@ -97,8 +99,9 @@ struct _phpdbg_command_t {
|
||||
char alias; /* Alias */
|
||||
phpdbg_command_handler_t handler; /* Command handler */
|
||||
const phpdbg_command_t *subs; /* Sub Commands */
|
||||
char *args; /* Argument Spec */
|
||||
const phpdbg_command_t *parent; /* Parent Command */
|
||||
char *args; /* Argument Spec */
|
||||
const phpdbg_command_t *parent; /* Parent Command */
|
||||
zend_bool flags; /* General flags */
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
@ -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 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 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,20 +158,20 @@ 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, '\0', NULL, 0}
|
||||
|
||||
/*
|
||||
* Default Switch Case
|
||||
|
@ -56,15 +56,20 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */
|
||||
return;
|
||||
}
|
||||
|
||||
while (execute_data) {
|
||||
if (i++ == frame) {
|
||||
break;
|
||||
}
|
||||
phpdbg_try_access {
|
||||
while (execute_data) {
|
||||
if (i++ == frame) {
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
execute_data = execute_data->prev_execute_data;
|
||||
} while (execute_data && execute_data->opline == NULL);
|
||||
}
|
||||
do {
|
||||
execute_data = execute_data->prev_execute_data;
|
||||
} while (execute_data && execute_data->opline == NULL);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Couldn't switch frames, invalid data source");
|
||||
return;
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
if (execute_data == NULL) {
|
||||
phpdbg_error("frame", "type=\"maxnum\" id=\"%d\"", "No frame #%d", frame);
|
||||
@ -106,16 +111,12 @@ static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */
|
||||
char is_class;
|
||||
int has_args = FAILURE;
|
||||
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"),
|
||||
(void **)&funcname);
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"), (void **) &funcname);
|
||||
|
||||
if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp),
|
||||
"object", sizeof("object"), (void **)&class)) == FAILURE) {
|
||||
is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"),
|
||||
(void **)&class);
|
||||
if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "object", sizeof("object"), (void **) &class)) == FAILURE) {
|
||||
is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"), (void **)&class);
|
||||
} else {
|
||||
zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class),
|
||||
(uint32_t *)&Z_STRLEN_PP(class) TSRMLS_CC);
|
||||
zend_get_object_classname(*class, (const char **) &Z_STRVAL_PP(class), (zend_uint *) &Z_STRLEN_PP(class) TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (is_class == SUCCESS) {
|
||||
@ -143,25 +144,32 @@ static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */
|
||||
|
||||
if (has_args) {
|
||||
HashPosition iterator;
|
||||
const zend_function *func = phpdbg_get_function(
|
||||
Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC);
|
||||
const zend_arg_info *arginfo = func ? func->common.arg_info : NULL;
|
||||
int j = 0, m = func ? func->common.num_args : 0;
|
||||
const zend_function *func = NULL;
|
||||
const zend_arg_info *arginfo = NULL;
|
||||
int j = 0, m;
|
||||
zend_bool is_variadic = 0;
|
||||
|
||||
phpdbg_try_access {
|
||||
/* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */
|
||||
if ((func = phpdbg_get_function(Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC))) {
|
||||
arginfo = func->common.arg_info;
|
||||
}
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
m = func ? func->common.num_args : 0;
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator);
|
||||
while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args),
|
||||
(void **) &argstmp, &iterator) == SUCCESS) {
|
||||
while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args), (void **) &argstmp, &iterator) == SUCCESS) {
|
||||
if (j) {
|
||||
phpdbg_out(", ");
|
||||
}
|
||||
phpdbg_xml("<arg %r");
|
||||
if (m && j < m) {
|
||||
#if PHP_VERSION_ID >= 50600
|
||||
is_variadic = arginfo[j].is_variadic;
|
||||
is_variadic = arginfo ? arginfo[j].is_variadic : 0;
|
||||
#endif
|
||||
phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arginfo[j].name);
|
||||
phpdbg_out("%s=%s", arginfo[j].name, is_variadic ? "[": "");
|
||||
phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arginfo ? arginfo[j].name : "");
|
||||
phpdbg_out("%s=%s", arginfo ? arginfo[j].name : "?", is_variadic ? "[": "");
|
||||
|
||||
} else {
|
||||
phpdbg_xml(">");
|
||||
@ -192,22 +200,26 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
|
||||
|
||||
if (limit < 0) {
|
||||
phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit);
|
||||
return;
|
||||
}
|
||||
|
||||
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_fetch_debug_backtrace(
|
||||
&zbacktrace, 0, 0, limit TSRMLS_CC);
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void **) &tmp, &position);
|
||||
while (1) {
|
||||
user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file);
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line);
|
||||
user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **) &file);
|
||||
zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **) &line);
|
||||
zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
|
||||
|
||||
if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace),
|
||||
(void**)&tmp, &position) == FAILURE) {
|
||||
if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void **) &tmp, &position) == FAILURE) {
|
||||
phpdbg_write("frame", "id=\"%d\" symbol=\"{main}\" file=\"%s\" line=\"%d\"", "frame #%d: {main} at %s:%ld", i, Z_STRVAL_PP(file), Z_LVAL_PP(line));
|
||||
break;
|
||||
}
|
||||
@ -226,7 +238,7 @@ void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */
|
||||
}
|
||||
|
||||
phpdbg_out("\n");
|
||||
zval_dtor(&zbacktrace);
|
||||
|
||||
phpdbg_xml("</backtrace>");
|
||||
|
||||
zval_dtor(&zbacktrace);
|
||||
} /* }}} */
|
||||
|
184
phpdbg_info.c
184
phpdbg_info.c
@ -27,19 +27,19 @@
|
||||
|
||||
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(globals, "show superglobals", 'g', info_globals, 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(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
|
||||
};
|
||||
|
||||
@ -63,15 +63,21 @@ PHPDBG_INFO(files) /* {{{ */
|
||||
HashPosition pos;
|
||||
char *fname;
|
||||
|
||||
phpdbg_notice("includedfilecount", "num=\"%d\"", "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");
|
||||
} 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("includedfile", "name=\"%s\"", "File: %s", fname);
|
||||
zend_hash_move_forward_ex(&EG(included_files), &pos);
|
||||
}
|
||||
phpdbg_try_access {
|
||||
zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos);
|
||||
while (zend_hash_get_current_key_ex(&EG(included_files), &fname, NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
|
||||
phpdbg_writeln("includedfile", "name=\"%s\"", "File: %s", fname);
|
||||
zend_hash_move_forward_ex(&EG(included_files), &pos);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Could not fetch file name, invalid data source, aborting included file listing");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
@ -79,8 +85,11 @@ PHPDBG_INFO(files) /* {{{ */
|
||||
PHPDBG_INFO(error) /* {{{ */
|
||||
{
|
||||
if (PG(last_error_message)) {
|
||||
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_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("lasterror", "error=\"\"", "No error found!");
|
||||
}
|
||||
@ -89,7 +98,11 @@ PHPDBG_INFO(error) /* {{{ */
|
||||
|
||||
static int phpdbg_arm_auto_global(zend_auto_global *auto_global TSRMLS_DC) {
|
||||
if (auto_global->armed) {
|
||||
auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC);
|
||||
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
|
||||
phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", auto_global->name_len, auto_global->name);
|
||||
} else {
|
||||
auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -117,6 +130,7 @@ static int phpdbg_print_symbols(zend_bool show_globals TSRMLS_DC) {
|
||||
|
||||
|
||||
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 {
|
||||
@ -125,15 +139,18 @@ static int phpdbg_print_symbols(zend_bool show_globals TSRMLS_DC) {
|
||||
|
||||
zend_hash_init(&vars, 8, NULL, NULL, 0);
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(symtable, &pos);
|
||||
while (zend_hash_get_current_key_ex(symtable, &var,
|
||||
NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
|
||||
zend_hash_get_current_data_ex(symtable, (void **)&data, &pos);
|
||||
if (zend_is_auto_global(var, strlen(var) TSRMLS_CC) ^ !show_globals) {
|
||||
zend_hash_update(&vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL);
|
||||
phpdbg_try_access {
|
||||
zend_hash_internal_pointer_reset_ex(symtable, &pos);
|
||||
while (zend_hash_get_current_key_ex(symtable, &var, NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) {
|
||||
zend_hash_get_current_data_ex(symtable, (void **)&data, &pos);
|
||||
if (zend_is_auto_global(var, strlen(var) TSRMLS_CC) ^ !show_globals) {
|
||||
zend_hash_update(&vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL);
|
||||
}
|
||||
zend_hash_move_forward_ex(symtable, &pos);
|
||||
}
|
||||
zend_hash_move_forward_ex(symtable, &pos);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Cannot fetch all data from the symbol table, invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
if (show_globals) {
|
||||
phpdbg_notice("variableinfo", "num=\"%d\"", "Superglobal variables (%d)", zend_hash_num_elements(&vars));
|
||||
@ -161,23 +178,35 @@ static int phpdbg_print_symbols(zend_bool show_globals TSRMLS_DC) {
|
||||
zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&vars, &pos)) {
|
||||
char *var;
|
||||
zend_bool invalid_data = 1;
|
||||
|
||||
zend_hash_get_current_key_ex(&vars, &var, NULL, NULL, 0, &pos);
|
||||
|
||||
if (*data) {
|
||||
phpdbg_writeln("variable", "address=\"%p\" refcount=\"%d\" type=\"%s\"", "%p\t%d\t(%s)", *data, Z_REFCOUNT_PP(data), zend_zval_type_name(*data));
|
||||
phpdbg_try_access {
|
||||
if (!(invalid_data = !*data)) {
|
||||
phpdbg_writeln("variable", "address=\"%p\" refcount=\"%d\" type=\"%s\"", "%p\t%d\t(%s)", *data, Z_REFCOUNT_PP(data), zend_zval_type_name(*data));
|
||||
|
||||
if (Z_TYPE_PP(data) == IS_RESOURCE) {
|
||||
int type;
|
||||
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\" type=\"%s\"", "%s$%s\n|-------(typeof)------> (%s)\n", Z_ISREF_PP(data) ? "&": "", var, zend_list_find(Z_RESVAL_PP(data), &type) ? zend_rsrc_list_get_rsrc_type(type TSRMLS_CC) : "unknown");
|
||||
} else if (Z_TYPE_PP(data) == IS_OBJECT) {
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\" instanceof=\"%s\"", "%s$%s\n|-----(instanceof)----> (%s)\n", Z_ISREF_PP(data) ? "&": "", var, Z_OBJCE_PP(data)->name);
|
||||
} else {
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\"", "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
|
||||
if (Z_TYPE_PP(data) == IS_RESOURCE) {
|
||||
phpdbg_try_access {
|
||||
int type;
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\" type=\"%s\"", "%s$%s\n|-------(typeof)------> (%s)\n", Z_ISREF_PP(data) ? "&": "", var, zend_list_find(Z_RESVAL_PP(data), &type) ? zend_rsrc_list_get_rsrc_type(type TSRMLS_CC) : "unknown");
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\" type=\"unknown\"", "%s$%s\n|-------(typeof)------> (unknown)\n", Z_ISREF_PP(data) ? "&": "", var);
|
||||
} phpdbg_end_try_access();
|
||||
} else if (Z_TYPE_PP(data) == IS_OBJECT) {
|
||||
phpdbg_try_access {
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\" instanceof=\"%s\"", "%s$%s\n|-----(instanceof)----> (%s)\n", Z_ISREF_PP(data) ? "&": "", var, Z_OBJCE_PP(data)->name);
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\" instanceof=\"unknown\"", "%s$%s\n|-----(instanceof)----> (unknown)\n", Z_ISREF_PP(data) ? "&": "", var);
|
||||
} phpdbg_end_try_access();
|
||||
} else {
|
||||
phpdbg_writeln("variabledetails", "refstatus=\"%s\" name=\"%s\"", "%s$%s", Z_ISREF_PP(data) ? "&": "", var);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
phpdbg_writeln("variable", "address=\"\" type=\"unknown\" name=\"%s\"", "n/a\tn/a\tn/a\t$%s", var);
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
if (invalid_data) {
|
||||
phpdbg_writeln("variabledetails", "name=\"%s\"", "n/a\tn/a\tn/a\t$%s", var);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,6 +228,7 @@ PHPDBG_INFO(globals) /* {{{ */
|
||||
|
||||
PHPDBG_INFO(literal) /* {{{ */
|
||||
{
|
||||
/* literals are assumed to not be manipulated during executing of their op_array and as such async safe */
|
||||
if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) {
|
||||
zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops);
|
||||
int literal = 0, count = ops->last_literal-1;
|
||||
@ -220,8 +250,7 @@ PHPDBG_INFO(literal) /* {{{ */
|
||||
while (literal < ops->last_literal) {
|
||||
if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) {
|
||||
phpdbg_write("literal", "id=\"%u\"", "|-------- C%u -------> [", literal);
|
||||
zend_print_zval(
|
||||
&ops->literals[literal].constant, 0);
|
||||
zend_print_zval(&ops->literals[literal].constant, 0);
|
||||
phpdbg_out("]\n");
|
||||
}
|
||||
literal++;
|
||||
@ -235,14 +264,31 @@ PHPDBG_INFO(literal) /* {{{ */
|
||||
|
||||
PHPDBG_INFO(memory) /* {{{ */
|
||||
{
|
||||
if (is_zend_mm(TSRMLS_C)) {
|
||||
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) (zend_memory_usage(0 TSRMLS_CC)/1024));
|
||||
phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (zend_memory_usage(1 TSRMLS_CC)/1024));
|
||||
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) (zend_memory_peak_usage(0 TSRMLS_CC)/1024));
|
||||
phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024));
|
||||
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("inactive", "type=\"memory_manager\"", "Memory Manager Disabled!");
|
||||
}
|
||||
@ -270,20 +316,24 @@ PHPDBG_INFO(classes) /* {{{ */
|
||||
|
||||
zend_hash_init(&classes, 8, NULL, NULL, 0);
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position);
|
||||
zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(class_table), &position)) {
|
||||
|
||||
if ((*ce)->type == ZEND_USER_CLASS) {
|
||||
zend_hash_next_index_insert(&classes, ce, sizeof(ce), NULL);
|
||||
phpdbg_try_access {
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position);
|
||||
zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(class_table), &position)) {
|
||||
if ((*ce)->type == ZEND_USER_CLASS) {
|
||||
zend_hash_next_index_insert(&classes, ce, sizeof(ce), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_notice("signalsegv", "", "Not all classes could be fetched, possibly invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
phpdbg_notice("classinfo", "num=\"%d\"", "User Classes (%d)", zend_hash_num_elements(&classes));
|
||||
|
||||
/* once added, assume that classes are stable... until shutdown. */
|
||||
for (zend_hash_internal_pointer_reset_ex(&classes, &position);
|
||||
zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&classes, &position)) {
|
||||
zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&classes, &position)) {
|
||||
|
||||
phpdbg_print_class_name(ce TSRMLS_CC);
|
||||
|
||||
@ -319,15 +369,17 @@ PHPDBG_INFO(funcs) /* {{{ */
|
||||
|
||||
zend_hash_init(&functions, 8, NULL, NULL, 0);
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position);
|
||||
zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(function_table), &position)) {
|
||||
|
||||
if (zf->type == ZEND_USER_FUNCTION) {
|
||||
zend_hash_next_index_insert(
|
||||
&functions, (void**) &zf, sizeof(zend_function), NULL);
|
||||
phpdbg_try_access {
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position);
|
||||
zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(function_table), &position)) {
|
||||
if (zf->type == ZEND_USER_FUNCTION) {
|
||||
zend_hash_next_index_insert(&functions, (void**) &zf, sizeof(zend_function), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_notice("signalsegv", "", "Not all functions could be fetched, possibly invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
phpdbg_notice("functioninfo", "num=\"%d\"", "User Functions (%d)", zend_hash_num_elements(&functions));
|
||||
|
||||
|
163
phpdbg_list.c
163
phpdbg_list.c
@ -34,14 +34,14 @@
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
@ -81,7 +81,7 @@ PHPDBG_LIST(method) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
|
||||
if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
zend_function *function;
|
||||
char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
|
||||
|
||||
@ -103,7 +103,7 @@ PHPDBG_LIST(class) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
|
||||
if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
if ((*ce)->type == ZEND_USER_CLASS) {
|
||||
if ((*ce)->info.user.filename) {
|
||||
phpdbg_list_file(
|
||||
@ -124,24 +124,13 @@ PHPDBG_LIST(class) /* {{{ */
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */
|
||||
void phpdbg_list_file(const char *filename, uint count, uint 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("list", "type=\"statfailure\"", "Failed to stat file %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = php_stream_open_wrapper(filename, "rb", USE_PATH, &opened);
|
||||
|
||||
if (!stream) {
|
||||
phpdbg_error("list", "type=\"openfailure\"", "Failed to open file %s to list", filename);
|
||||
if (zend_hash_find(&PHPDBG_G(file_sources), filename, strlen(filename), (void **) &data) == FAILURE) {
|
||||
phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file...");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -150,37 +139,35 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
phpdbg_xml("<list file=\"%s\">", filename);
|
||||
lastline = offset + count;
|
||||
|
||||
while (php_stream_gets(stream, buffer, sizeof(buffer)) != NULL) {
|
||||
long linelen = strlen(buffer);
|
||||
if (lastline > (*data)->lines) {
|
||||
lastline = (*data)->lines;
|
||||
}
|
||||
|
||||
++line;
|
||||
phpdbg_xml("<list %r file=\"%s\">", filename);
|
||||
|
||||
if (offset <= line) {
|
||||
if (!highlight) {
|
||||
phpdbg_write("line", "line=\"%d\" code=\"%s\"", " %05ld: %s", line, buffer);
|
||||
for (line = offset; line < lastline;) {
|
||||
uint linestart = (*data)->line[line++];
|
||||
uint linelen = (*data)->line[line] - linestart;
|
||||
char *buffer = (*data)->buf + linestart;
|
||||
|
||||
if (!highlight) {
|
||||
phpdbg_write("line", "line=\"%u\" code=\"%s\"", " %05u: %s", line, buffer);
|
||||
} else {
|
||||
if (highlight != line) {
|
||||
phpdbg_write("line", "line=\"%u\" code=\"%s\"", " %05u: %s", line, buffer);
|
||||
} else {
|
||||
if (highlight != line) {
|
||||
phpdbg_write("line", "line=\"%ld\" code=\"%s\"", " %05ld: %s", line, buffer);
|
||||
} else {
|
||||
phpdbg_write("line", "line=\"%ld\" code=\"%s\" current=\"current\"", ">%05ld: %s", line, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer[linelen - 1] != '\n') {
|
||||
phpdbg_out("\n");
|
||||
phpdbg_write("line", "line=\"%u\" code=\"%s\" current=\"current\"", ">%05u: %s", line, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0 && count + offset - 1 < line) {
|
||||
break;
|
||||
if (*(buffer + linelen - 1) != '\n') {
|
||||
phpdbg_out("\n");
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_xml("</list>");
|
||||
|
||||
php_stream_close(stream);
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */
|
||||
@ -192,10 +179,9 @@ void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */
|
||||
return;
|
||||
}
|
||||
|
||||
ops = (zend_op_array*)fbc;
|
||||
ops = (zend_op_array *)fbc;
|
||||
|
||||
phpdbg_list_file(ops->filename,
|
||||
ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC);
|
||||
phpdbg_list_file(ops->filename, ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC);
|
||||
} /* }}} */
|
||||
|
||||
void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */
|
||||
@ -226,12 +212,85 @@ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ *
|
||||
/* use lowercase names, case insensitive */
|
||||
func_name = zend_str_tolower_dup(func_name, func_name_len);
|
||||
|
||||
if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_list_function(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("list", "type=\"nofunction\" function=\"%s\"", "Function %s not found", func_name);
|
||||
}
|
||||
phpdbg_try_access {
|
||||
if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_list_function(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("list", "type=\"nofunction\" function=\"%s\"", "Function %s not found", func_name);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "function=\"%s\"", "Could not list function %s, invalid data source", func_name);
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
efree(func_name);
|
||||
} /* }}} */
|
||||
|
||||
zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) {
|
||||
phpdbg_file_source data, *dataptr;
|
||||
zend_file_handle fake = {0};
|
||||
zend_op_array *ret;
|
||||
char *filename = (char *)(file->opened_path ? file->opened_path : file->filename);
|
||||
uint line;
|
||||
char *bufptr, *endptr;
|
||||
|
||||
zend_stream_fixup(file, &data.buf, &data.len TSRMLS_CC);
|
||||
|
||||
data.filename = filename;
|
||||
data.line[0] = 0;
|
||||
|
||||
if (file->handle.stream.mmap.old_closer) {
|
||||
/* do not unmap */
|
||||
file->handle.stream.closer = file->handle.stream.mmap.old_closer;
|
||||
}
|
||||
|
||||
#if HAVE_MMAP
|
||||
if (file->handle.stream.mmap.map) {
|
||||
data.map = file->handle.stream.mmap.map;
|
||||
}
|
||||
#endif
|
||||
|
||||
fake.type = ZEND_HANDLE_MAPPED;
|
||||
fake.handle.stream.mmap.buf = data.buf;
|
||||
fake.handle.stream.mmap.len = data.len;
|
||||
fake.free_filename = 0;
|
||||
fake.opened_path = file->opened_path;
|
||||
fake.filename = filename;
|
||||
fake.opened_path = file->opened_path;
|
||||
|
||||
*(dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * data.len)) = data;
|
||||
zend_hash_add(&PHPDBG_G(file_sources), filename, strlen(filename), &dataptr, sizeof(phpdbg_file_source *), NULL);
|
||||
|
||||
for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) {
|
||||
if (*bufptr == '\n') {
|
||||
dataptr->line[++line] = (uint)(bufptr - data.buf) + 1;
|
||||
}
|
||||
}
|
||||
dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line);
|
||||
dataptr->lines = ++line;
|
||||
|
||||
ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC);
|
||||
|
||||
fake.opened_path = NULL;
|
||||
zend_file_handle_dtor(&fake TSRMLS_CC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void phpdbg_free_file_source(phpdbg_file_source *data) {
|
||||
#if HAVE_MMAP
|
||||
if (data->map) {
|
||||
munmap(data->map, data->len + ZEND_MMAP_AHEAD);
|
||||
} else
|
||||
#endif
|
||||
if (data->buf) {
|
||||
efree(data->buf);
|
||||
}
|
||||
|
||||
efree(data);
|
||||
}
|
||||
|
||||
void phpdbg_init_list(TSRMLS_D) {
|
||||
PHPDBG_G(compile_file) = zend_compile_file;
|
||||
zend_hash_init(&PHPDBG_G(file_sources), 1, NULL, (dtor_func_t) phpdbg_free_file_source, 0);
|
||||
zend_compile_file = phpdbg_compile_file;
|
||||
}
|
||||
|
@ -34,8 +34,21 @@ PHPDBG_LIST(func);
|
||||
|
||||
void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC);
|
||||
void phpdbg_list_function(const zend_function* TSRMLS_DC);
|
||||
void phpdbg_list_file(const char*, long, long, int TSRMLS_DC);
|
||||
void phpdbg_list_file(const char*, uint, uint, 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 */
|
||||
|
@ -156,7 +156,7 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, ze
|
||||
}
|
||||
|
||||
if (!ignore_flags && PHPDBG_G(oplog)) {
|
||||
phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s",
|
||||
phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %-30s %s %s",
|
||||
opline->lineno,
|
||||
opline,
|
||||
phpdbg_decode_opcode(opline->opcode),
|
||||
|
@ -26,16 +26,16 @@
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9])
|
||||
#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s, flags) \
|
||||
PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9], flags)
|
||||
|
||||
const phpdbg_command_t phpdbg_print_commands[] = {
|
||||
PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0),
|
||||
PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0),
|
||||
PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s"),
|
||||
PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m"),
|
||||
PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s"),
|
||||
PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0),
|
||||
PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
@ -109,7 +109,7 @@ 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);
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ PHPDBG_PRINT(class) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
|
||||
if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) {
|
||||
phpdbg_notice("printinfo", "type=\"%s\" flag=\"%s\" class=\"%s\" num=\"%d\"", "%s %s: %s (%d methods)",
|
||||
((*ce)->type == ZEND_USER_CLASS) ?
|
||||
"User" : "Internal",
|
||||
@ -192,7 +192,7 @@ PHPDBG_PRINT(method) /* {{{ */
|
||||
{
|
||||
zend_class_entry **ce;
|
||||
|
||||
if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) {
|
||||
zend_function *fbc;
|
||||
char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name));
|
||||
|
||||
@ -240,19 +240,23 @@ PHPDBG_PRINT(func) /* {{{ */
|
||||
func_table = EG(function_table);
|
||||
}
|
||||
|
||||
lcname = zend_str_tolower_dup(func_name, func_name_len);
|
||||
lcname = zend_str_tolower_dup(func_name, func_name_len);
|
||||
|
||||
if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) {
|
||||
phpdbg_notice("printinfo", "type=\"%s\" flags=\"%s\" symbol=\"%s\" num=\"%d\"", "%s %s %s (%d ops)",
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
|
||||
(fbc->common.scope) ? "Method" : "Function",
|
||||
fbc->common.function_name,
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0 );
|
||||
phpdbg_try_access {
|
||||
if (zend_hash_find(func_table, lcname, func_name_len + 1, (void **) &fbc) == SUCCESS) {
|
||||
phpdbg_notice("printinfo", "type=\"%s\" flags=\"%s\" symbol=\"%s\" num=\"%d\"", "%s %s %s (%d ops)",
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal",
|
||||
(fbc->common.scope) ? "Method" : "Function",
|
||||
fbc->common.function_name,
|
||||
(fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0);
|
||||
|
||||
phpdbg_print_function_helper(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("print", "type=\"nofunction\" function=\"%s\"", "The function %s could not be found", func_name);
|
||||
}
|
||||
phpdbg_print_function_helper(fbc TSRMLS_CC);
|
||||
} else {
|
||||
phpdbg_error("print", "type=\"nofunction\" function=\"%s\"", "The function %s could not be found", func_name);
|
||||
}
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "function=\"%.*s\"", "Couldn't fetch function %.*s, invalid data source", (int) func_name_len, func_name);
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
efree(lcname);
|
||||
|
||||
|
390
phpdbg_prompt.c
390
phpdbg_prompt.c
@ -23,6 +23,7 @@
|
||||
#include "zend.h"
|
||||
#include "zend_compile.h"
|
||||
#include "phpdbg.h"
|
||||
|
||||
#include "phpdbg_help.h"
|
||||
#include "phpdbg_print.h"
|
||||
#include "phpdbg_info.h"
|
||||
@ -37,38 +38,54 @@
|
||||
#include "phpdbg_frame.h"
|
||||
#include "phpdbg_lexer.h"
|
||||
#include "phpdbg_parser.h"
|
||||
#include "phpdbg_wait.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
#ifdef PHP_WIN32
|
||||
#include "win32/param.h"
|
||||
#include "win32/winutil.h"
|
||||
#define GET_DL_ERROR() php_win_err()
|
||||
#elif defined(NETWARE)
|
||||
#include <sys/param.h>
|
||||
#define GET_DL_ERROR() dlerror()
|
||||
#else
|
||||
#include <sys/param.h>
|
||||
#define GET_DL_ERROR() DL_ERROR()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* {{{ command declarations */
|
||||
const phpdbg_command_t phpdbg_prompt_commands[] = {
|
||||
PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s"),
|
||||
PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0),
|
||||
PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0),
|
||||
PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s"),
|
||||
PHPDBG_COMMAND_D(ev, "evaluate some code", 0, NULL, "i"),
|
||||
PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0),
|
||||
PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0),
|
||||
PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0),
|
||||
PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 0),
|
||||
PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c"),
|
||||
PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n"),
|
||||
PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n"),
|
||||
PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*"),
|
||||
PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s"),
|
||||
PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0),
|
||||
PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0),
|
||||
PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s"),
|
||||
PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s"),
|
||||
PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s"),
|
||||
PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s"),
|
||||
PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s"),
|
||||
PHPDBG_COMMAND_D(sh, "shell a command", 0, NULL, "i"),
|
||||
PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0),
|
||||
PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss"),
|
||||
PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s", 0),
|
||||
PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s", 0),
|
||||
PHPDBG_COMMAND_D(ev, "evaluate some code", 0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */
|
||||
PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0, 0),
|
||||
PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0, 0),
|
||||
PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0, 0),
|
||||
PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 0, 0),
|
||||
PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c", 0),
|
||||
PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0, 0),
|
||||
PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0, 0),
|
||||
PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s", 0),
|
||||
PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s", 0),
|
||||
PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s", PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(sh, "shell a command", 0 , NULL, "i", 0),
|
||||
PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0, PHPDBG_ASYNC_SAFE),
|
||||
PHPDBG_COMMAND_D(wait, "wait for other process", 'W', NULL, 0, 0),
|
||||
PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss", 0),
|
||||
PHPDBG_END_COMMAND
|
||||
}; /* }}} */
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
phpdbg_param_t *name = NULL;
|
||||
@ -246,7 +263,7 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_
|
||||
phpdbg_activate_err_buf(1 TSRMLS_CC);
|
||||
|
||||
if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) {
|
||||
switch (phpdbg_stack_execute(&stack TSRMLS_CC)) {
|
||||
switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */ TSRMLS_CC)) {
|
||||
case FAILURE:
|
||||
phpdbg_activate_err_buf(0 TSRMLS_CC);
|
||||
if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) {
|
||||
@ -345,6 +362,8 @@ PHPDBG_COMMAND(exec) /* {{{ */
|
||||
PHPDBG_G(exec) = res;
|
||||
PHPDBG_G(exec_len) = res_len;
|
||||
|
||||
VCWD_CHDIR_FILE(res);
|
||||
|
||||
*SG(request_info).argv = PHPDBG_G(exec);
|
||||
php_hash_environment(TSRMLS_C);
|
||||
|
||||
@ -621,6 +640,11 @@ PHPDBG_COMMAND(run) /* {{{ */
|
||||
}
|
||||
} zend_end_try();
|
||||
|
||||
if (PHPDBG_G(socket_fd) != -1) {
|
||||
close(PHPDBG_G(socket_fd));
|
||||
PHPDBG_G(socket_fd) = -1;
|
||||
}
|
||||
|
||||
if (restore) {
|
||||
if (EG(exception)) {
|
||||
phpdbg_handle_exception(TSRMLS_C);
|
||||
@ -639,11 +663,33 @@ out:
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
int phpdbg_output_ev_variable(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv TSRMLS_DC) {
|
||||
phpdbg_notice("eval", "variable=\"%.*s\"", "Printing variable %.*s", (int) len, name);
|
||||
phpdbg_xml("<eval>");
|
||||
zend_print_zval_r(*zv, 0 TSRMLS_CC);
|
||||
phpdbg_xml("</eval>");
|
||||
phpdbg_out("\n");
|
||||
|
||||
efree(name);
|
||||
efree(keyname);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PHPDBG_COMMAND(ev) /* {{{ */
|
||||
{
|
||||
zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING) == PHPDBG_IS_STEPPING);
|
||||
zval retval;
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
|
||||
phpdbg_try_access {
|
||||
phpdbg_parse_variable(param->str, param->len, &EG(symbol_table), 0, phpdbg_output_ev_variable, 0 TSRMLS_CC);
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "", "Could not fetch data, invalid data source");
|
||||
} phpdbg_end_try_access();
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) {
|
||||
PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING;
|
||||
}
|
||||
@ -802,6 +848,193 @@ PHPDBG_COMMAND(sh) /* {{{ */
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
static int add_module_info(zend_module_entry *module TSRMLS_DC) {
|
||||
phpdbg_write("module", "name=\"%s\"", "%s\n", module->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_zendext_info(zend_extension *ext TSRMLS_DC) {
|
||||
phpdbg_write("extension", "name=\"%s\"", "%s\n", ext->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, char **name TSRMLS_DC) {
|
||||
DL_HANDLE handle;
|
||||
char *extension_dir;
|
||||
|
||||
extension_dir = INI_STR("extension_dir");
|
||||
|
||||
if (strchr(*path, '/') != NULL || strchr(*path, DEFAULT_SLASH) != NULL) {
|
||||
/* path is fine */
|
||||
} else if (extension_dir && extension_dir[0]) {
|
||||
char *libpath;
|
||||
int extension_dir_len = strlen(extension_dir);
|
||||
if (IS_SLASH(extension_dir[extension_dir_len-1])) {
|
||||
spprintf(&libpath, 0, "%s%s", extension_dir, *path); /* SAFE */
|
||||
} else {
|
||||
spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, *path); /* SAFE */
|
||||
}
|
||||
efree(*path);
|
||||
*path = libpath;
|
||||
} else {
|
||||
phpdbg_error("dl", "type=\"relpath\"", "Not a full path given or extension_dir ini setting is not set");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handle = DL_LOAD(*path);
|
||||
|
||||
if (!handle) {
|
||||
#if PHP_WIN32
|
||||
char *err = GET_DL_ERROR();
|
||||
if (err && *err != "") {
|
||||
phpdbg_error("dl", "type=\"unknown\"", "%s", err);
|
||||
LocalFree(err);
|
||||
} else {
|
||||
phpdbg_error("dl", "type=\"unknown\"", "Unknown reason");
|
||||
}
|
||||
#else
|
||||
phpdbg_error("dl", "type=\"unknown\"", "%s", GET_DL_ERROR());
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if ZEND_EXTENSIONS_SUPPORT
|
||||
do {
|
||||
zend_extension *new_extension;
|
||||
zend_extension_version_info *extension_version_info;
|
||||
|
||||
extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info");
|
||||
if (!extension_version_info) {
|
||||
extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info");
|
||||
}
|
||||
new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry");
|
||||
if (!new_extension) {
|
||||
new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "_zend_extension_entry");
|
||||
}
|
||||
if (!extension_version_info || !new_extension) {
|
||||
break;
|
||||
}
|
||||
if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) {
|
||||
phpdbg_error("dl", "type=\"wrongapi\" extension=\"%s\" apineeded=\"%d\" apiinstalled=\"%d\"", "%s requires Zend Engine API version %d, which does not match the installed Zend Engine API version %d", new_extension->name, extension_version_info->zend_extension_api_no, ZEND_EXTENSION_API_NO);
|
||||
|
||||
goto quit;
|
||||
} else if (strcmp(ZEND_EXTENSION_BUILD_ID, extension_version_info->build_id) && (!new_extension->build_id_check || new_extension->build_id_check(ZEND_EXTENSION_BUILD_ID) != SUCCESS)) {
|
||||
phpdbg_error("dl", "type=\"wrongbuild\" extension=\"%s\" buildneeded=\"%s\" buildinstalled=\"%s\"", "%s was built with configuration %s, whereas running engine is %s", new_extension->name, extension_version_info->build_id, ZEND_EXTENSION_BUILD_ID);
|
||||
|
||||
goto quit;
|
||||
}
|
||||
|
||||
*name = new_extension->name;
|
||||
|
||||
zend_register_extension(new_extension, handle);
|
||||
|
||||
if (new_extension->startup) {
|
||||
if (new_extension->startup(new_extension) != SUCCESS) {
|
||||
phpdbg_error("dl", "type=\"startupfailure\" extension=\"%s\"", "Unable to startup Zend extension %s", new_extension->name);
|
||||
|
||||
goto quit;
|
||||
}
|
||||
zend_append_version_info(new_extension);
|
||||
}
|
||||
|
||||
return "Zend extension";
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
do {
|
||||
zend_module_entry *module_entry;
|
||||
zend_module_entry *(*get_module)(void);
|
||||
|
||||
get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module");
|
||||
if (!get_module) {
|
||||
get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module");
|
||||
}
|
||||
|
||||
if (!get_module) {
|
||||
break;
|
||||
}
|
||||
|
||||
module_entry = get_module();
|
||||
*name = (char *) module_entry->name;
|
||||
|
||||
if (strcmp(ZEND_EXTENSION_BUILD_ID, module_entry->build_id)) {
|
||||
phpdbg_error("dl", "type=\"wrongbuild\" module=\"%s\" buildneeded=\"%s\" buildinstalled=\"%s\"", "%s was built with configuration %s, whereas running engine is %s", module_entry->name, module_entry->build_id, ZEND_EXTENSION_BUILD_ID);
|
||||
|
||||
goto quit;
|
||||
}
|
||||
|
||||
module_entry->type = MODULE_PERSISTENT;
|
||||
module_entry->module_number = zend_next_free_module();
|
||||
module_entry->handle = handle;
|
||||
|
||||
if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) {
|
||||
phpdbg_error("dl", "type=\"registerfailure\" module=\"%s\"", "Unable to register module %s", module_entry->name);
|
||||
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) {
|
||||
phpdbg_error("dl", "type=\"startupfailure\" module=\"%s\"", "Unable to startup module %s", module_entry->name);
|
||||
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (module_entry->request_startup_func) {
|
||||
if (module_entry->request_startup_func(MODULE_PERSISTENT, module_entry->module_number TSRMLS_CC) == FAILURE) {
|
||||
phpdbg_error("dl", "type=\"initfailure\" module=\"%s\"", "Unable to initialize module %s", module_entry->name);
|
||||
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
return "module";
|
||||
} while (0);
|
||||
|
||||
phpdbg_error("dl", "type=\"nophpso\"", "This shared object is nor a Zend extension nor a module");
|
||||
|
||||
quit:
|
||||
DL_UNLOAD(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PHPDBG_COMMAND(dl) /* {{{ */
|
||||
{
|
||||
const char *type;
|
||||
char *name, *path;
|
||||
|
||||
if (!param || param->type == EMPTY_PARAM) {
|
||||
phpdbg_notice("dl", "extensiontype=\"Zend extension\"", "Zend extensions");
|
||||
zend_llist_apply(&zend_extensions, (llist_apply_func_t) add_zendext_info TSRMLS_CC);
|
||||
phpdbg_out("\n");
|
||||
phpdbg_notice("dl", "extensiontype=\"module\"", "Modules");
|
||||
zend_hash_apply(&module_registry, (apply_func_t) add_module_info TSRMLS_CC);
|
||||
} else switch (param->type) {
|
||||
case STR_PARAM:
|
||||
#ifdef HAVE_LIBDL
|
||||
path = estrndup(param->str, param->len);
|
||||
|
||||
phpdbg_activate_err_buf(1 TSRMLS_CC);
|
||||
if ((type = phpdbg_load_module_or_extension(&path, &name TSRMLS_CC)) == NULL) {
|
||||
phpdbg_error("dl", "path=\"%s\" %b", "Could not load %s, not found or invalid zend extension / module: %b", path);
|
||||
efree(name);
|
||||
} else {
|
||||
phpdbg_notice("dl", "extensiontype=\"%s\" name=\"%s\" path=\"%s\"", "Successfully loaded the %s %s at path %s", type, name, path);
|
||||
}
|
||||
phpdbg_activate_err_buf(0 TSRMLS_CC);
|
||||
phpdbg_free_err_buf(TSRMLS_C);
|
||||
efree(path);
|
||||
#else
|
||||
phpdbg_error("dl", "type=\"unsupported\" path=\"%.*s\"", "Cannot dynamically load %.*s - dynamic modules are not supported", (int) param->len, param->str);
|
||||
#endif
|
||||
break;
|
||||
|
||||
phpdbg_default_switch_case();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_COMMAND(source) /* {{{ */
|
||||
{
|
||||
struct stat sb;
|
||||
@ -947,7 +1180,7 @@ PHPDBG_COMMAND(watch) /* {{{ */
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
int phpdbg_interactive(TSRMLS_D) /* {{{ */
|
||||
int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
int ret = SUCCESS;
|
||||
char *input = NULL;
|
||||
@ -964,10 +1197,10 @@ int phpdbg_interactive(TSRMLS_D) /* {{{ */
|
||||
if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) {
|
||||
phpdbg_activate_err_buf(1 TSRMLS_CC);
|
||||
|
||||
switch (ret = phpdbg_stack_execute(&stack TSRMLS_CC)) {
|
||||
switch (ret = phpdbg_stack_execute(&stack, allow_async_unsafe TSRMLS_CC)) {
|
||||
case FAILURE:
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
|
||||
if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) {
|
||||
if (!allow_async_unsafe || phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) {
|
||||
phpdbg_output_err_buf(NULL, "%b", "%b" TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
@ -1091,6 +1324,27 @@ static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_ar
|
||||
#endif
|
||||
} /* }}} */
|
||||
|
||||
#define DO_INTERACTIVE(allow_async_unsafe) do { \
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \
|
||||
phpdbg_list_file( \
|
||||
zend_get_executed_filename(TSRMLS_C), \
|
||||
3, \
|
||||
zend_get_executed_lineno(TSRMLS_C)-1, \
|
||||
zend_get_executed_lineno(TSRMLS_C) \
|
||||
TSRMLS_CC \
|
||||
); \
|
||||
} \
|
||||
\
|
||||
switch (phpdbg_interactive(allow_async_unsafe TSRMLS_CC)) { \
|
||||
case PHPDBG_LEAVE: \
|
||||
case PHPDBG_FINISH: \
|
||||
case PHPDBG_UNTIL: \
|
||||
case PHPDBG_NEXT:{ \
|
||||
goto next; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if PHP_VERSION_ID >= 50500
|
||||
void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
@ -1127,41 +1381,17 @@ zend_vm_enter:
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
|
||||
if ((PHPDBG_G(flags) & PHPDBG_BP_RESOLVE_MASK)) {
|
||||
/* resolve nth opline breakpoints */
|
||||
phpdbg_resolve_op_array_breaks(EG(active_op_array) TSRMLS_CC);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ZEND_WIN32
|
||||
if (EG(timed_out)) {
|
||||
zend_timeout(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DO_INTERACTIVE() do { \
|
||||
if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \
|
||||
phpdbg_list_file( \
|
||||
zend_get_executed_filename(TSRMLS_C), \
|
||||
3, \
|
||||
zend_get_executed_lineno(TSRMLS_C)-1, \
|
||||
zend_get_executed_lineno(TSRMLS_C) \
|
||||
TSRMLS_CC \
|
||||
); \
|
||||
} \
|
||||
\
|
||||
/* do { */\
|
||||
switch (phpdbg_interactive(TSRMLS_C)) { \
|
||||
case PHPDBG_LEAVE: \
|
||||
case PHPDBG_FINISH: \
|
||||
case PHPDBG_UNTIL: \
|
||||
case PHPDBG_NEXT:{ \
|
||||
goto next; \
|
||||
} \
|
||||
} \
|
||||
/* } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); */\
|
||||
} while (0)
|
||||
|
||||
/* allow conditional breakpoints and
|
||||
initialization to access the vm uninterrupted */
|
||||
if ((PHPDBG_G(flags) & PHPDBG_IN_COND_BP) ||
|
||||
@ -1205,7 +1435,7 @@ zend_vm_enter:
|
||||
zend_get_executed_filename(TSRMLS_C),
|
||||
zend_get_executed_lineno(TSRMLS_C)
|
||||
);
|
||||
DO_INTERACTIVE();
|
||||
DO_INTERACTIVE(1);
|
||||
} else {
|
||||
/* skip possible breakpoints */
|
||||
goto next;
|
||||
@ -1218,13 +1448,13 @@ zend_vm_enter:
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING && (PHPDBG_G(flags) & PHPDBG_STEP_OPCODE || execute_data->opline->lineno != PHPDBG_G(last_line))) {
|
||||
PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING;
|
||||
DO_INTERACTIVE();
|
||||
DO_INTERACTIVE(1);
|
||||
}
|
||||
|
||||
/* check if some watchpoint was hit */
|
||||
{
|
||||
if (phpdbg_print_changed_zvals(TSRMLS_C) == SUCCESS) {
|
||||
DO_INTERACTIVE();
|
||||
DO_INTERACTIVE(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1236,26 +1466,36 @@ zend_vm_enter:
|
||||
&& (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC))
|
||||
&& (brake->type != PHPDBG_BREAK_FILE || execute_data->opline->lineno != PHPDBG_G(last_line))) {
|
||||
phpdbg_hit_breakpoint(brake, 1 TSRMLS_CC);
|
||||
DO_INTERACTIVE();
|
||||
DO_INTERACTIVE(1);
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
|
||||
PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
|
||||
|
||||
phpdbg_out("\n");
|
||||
phpdbg_notice("signal", "type=\"SIGINT\"", "Program received signal SIGINT");
|
||||
PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
|
||||
DO_INTERACTIVE();
|
||||
DO_INTERACTIVE(1);
|
||||
}
|
||||
|
||||
next:
|
||||
|
||||
PHPDBG_G(last_line) = execute_data->opline->lineno;
|
||||
|
||||
/* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */
|
||||
if ((execute_data->opline->opcode == ZEND_DO_FCALL_BY_NAME || execute_data->opline->opcode == ZEND_DO_FCALL) && execute_data->function_state.function->type == ZEND_USER_FUNCTION) {
|
||||
#if PHP_VERSION_ID < 50500
|
||||
zend_execute = execute;
|
||||
#else
|
||||
zend_execute_ex = execute_ex;
|
||||
#endif
|
||||
}
|
||||
PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC);
|
||||
#if PHP_VERSION_ID < 50500
|
||||
zend_execute = phpdbg_execute_ex;
|
||||
#else
|
||||
zend_execute_ex = phpdbg_execute_ex;
|
||||
#endif
|
||||
|
||||
if (PHPDBG_G(vmret) > 0) {
|
||||
switch (PHPDBG_G(vmret)) {
|
||||
@ -1280,3 +1520,29 @@ next:
|
||||
}
|
||||
zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
|
||||
} /* }}} */
|
||||
|
||||
/* only if *not* interactive and while executing */
|
||||
void phpdbg_force_interruption(TSRMLS_D) {
|
||||
zend_execute_data *data = EG(current_execute_data); /* should be always readable if not NULL */
|
||||
|
||||
PHPDBG_G(flags) |= PHPDBG_IN_SIGNAL_HANDLER;
|
||||
|
||||
if (data) {
|
||||
if (data->op_array) {
|
||||
phpdbg_notice("hardinterrupt", "opline=\"%p\" num=\"%lu\" file=\"%s\" line=\"%u\"", "Current opline: %p (op #%lu) in %s:%u", data->opline, (data->opline - data->op_array->opcodes) / sizeof(data->opline), data->op_array->filename, data->opline->lineno);
|
||||
} else {
|
||||
phpdbg_notice("hardinterrupt", "opline=\"%p\"", "Current opline: %p (op_array information unavailable)", data->opline);
|
||||
}
|
||||
} else {
|
||||
phpdbg_notice("hardinterrupt", "", "No information available about executing context");
|
||||
}
|
||||
|
||||
DO_INTERACTIVE(0);
|
||||
|
||||
next:
|
||||
PHPDBG_G(flags) &= ~PHPDBG_IN_SIGNAL_HANDLER;
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
|
||||
zend_bailout();
|
||||
}
|
||||
}
|
||||
|
@ -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,14 @@ 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(wait); /* }}} */
|
||||
|
||||
/* {{{ prompt commands */
|
||||
extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */
|
||||
|
101
phpdbg_rinit_hook.c
Normal file
101
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 (!cookies || zend_hash_find(Z_ARRVAL_P(cookies), PHPDBG_NAME "_AUTH_COOKIE", sizeof(PHPDBG_NAME "_AUTH_COOKIE"), (void **) &auth) == FAILURE || Z_STRLEN_PP(auth) != strlen(PHPDBG_WG(auth)) || strcmp(Z_STRVAL_PP(auth), PHPDBG_WG(auth))) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
{
|
||||
struct sockaddr_un sock;
|
||||
int s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
int len = strlen(PHPDBG_WG(path)) + sizeof(sock.sun_family);
|
||||
char buf[(1 << 8) + 1];
|
||||
int buflen;
|
||||
sock.sun_family = AF_UNIX;
|
||||
strcpy(sock.sun_path, PHPDBG_WG(path));
|
||||
|
||||
if (connect(s, (struct sockaddr *)&sock, len) == -1) {
|
||||
zend_error(E_ERROR, "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting. Reason: %s", PHPDBG_WG(path), strerror(errno));
|
||||
}
|
||||
|
||||
char *msg = NULL;
|
||||
char msglen[5] = {0};
|
||||
phpdbg_webdata_compress(&msg, (int *)msglen TSRMLS_CC);
|
||||
|
||||
send(s, msglen, 4, 0);
|
||||
send(s, msg, *(int *) msglen, 0);
|
||||
|
||||
while ((buflen = recv(s, buf, sizeof(buf) - 1, 0)) > 0) {
|
||||
php_write(buf, buflen TSRMLS_CC);
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
php_output_flush_all(TSRMLS_C);
|
||||
zend_bailout();
|
||||
}
|
||||
#endif
|
||||
|
||||
return SUCCESS;
|
||||
} /* }}} */
|
||||
|
||||
zend_module_entry phpdbg_webhelper_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
"phpdbg_webhelper",
|
||||
NULL,
|
||||
PHP_MINIT(phpdbg_webhelper),
|
||||
NULL,
|
||||
PHP_RINIT(phpdbg_webhelper),
|
||||
NULL,
|
||||
NULL,
|
||||
PHPDBG_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
41
phpdbg_rinit_hook.h
Normal file
41
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 */
|
22
phpdbg_set.c
22
phpdbg_set.c
@ -27,21 +27,21 @@
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
111
phpdbg_sigsafe.c
Normal file
111
phpdbg_sigsafe.c
Normal file
@ -0,0 +1,111 @@
|
||||
#include "phpdbg_sigsafe.h"
|
||||
#include "phpdbg.h"
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
static inline void zend_mm_init(zend_mm_heap *heap) {
|
||||
zend_mm_free_block *p;
|
||||
int i;
|
||||
|
||||
heap->free_bitmap = 0;
|
||||
heap->large_free_bitmap = 0;
|
||||
#if ZEND_MM_CACHE
|
||||
heap->cached = 0;
|
||||
memset(heap->cache, 0, sizeof(heap->cache));
|
||||
#endif
|
||||
#if ZEND_MM_CACHE_STAT
|
||||
for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
|
||||
heap->cache_stat[i].count = 0;
|
||||
}
|
||||
#endif
|
||||
p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
|
||||
for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
|
||||
p->next_free_block = p;
|
||||
p->prev_free_block = p;
|
||||
p = (zend_mm_free_block *)((char *)p + sizeof(zend_mm_free_block *) * 2);
|
||||
heap->large_free_buckets[i] = NULL;
|
||||
}
|
||||
heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap);
|
||||
heap->rest_count = 0;
|
||||
}
|
||||
|
||||
static zend_mm_storage* zend_mm_mem_init(void *params) {
|
||||
TSRMLS_FETCH();
|
||||
|
||||
return &PHPDBG_G(sigsafe_mem).storage;
|
||||
}
|
||||
|
||||
static void zend_mm_mem_dummy(zend_mm_storage *storage) {
|
||||
}
|
||||
|
||||
#define STR(x) #x
|
||||
#define EXP_STR(x) STR(x)
|
||||
|
||||
static zend_mm_segment* zend_mm_mem_alloc(zend_mm_storage *storage, size_t size) {
|
||||
TSRMLS_FETCH();
|
||||
|
||||
if (EXPECTED(size == PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) {
|
||||
PHPDBG_G(sigsafe_mem).allocated = 1;
|
||||
return (zend_mm_segment *) PHPDBG_G(sigsafe_mem).mem;
|
||||
}
|
||||
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Tried to allocate more than " EXP_STR(PHPDBG_SIGSAFE_MEM_SIZE) " bytes from stack memory in signal handler ... bailing out of signal handler\n"));
|
||||
|
||||
if (*EG(bailout)) {
|
||||
LONGJMP(*EG(bailout), FAILURE);
|
||||
}
|
||||
|
||||
write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n"));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static zend_mm_segment* zend_mm_mem_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size) {
|
||||
return zend_mm_mem_alloc(storage, size);
|
||||
}
|
||||
|
||||
static void zend_mm_mem_free(zend_mm_storage *storage, zend_mm_segment *ptr) {
|
||||
}
|
||||
|
||||
static const zend_mm_mem_handlers phpdbg_handlers_sigsafe_mem = { "stack", zend_mm_mem_init, zend_mm_mem_dummy, zend_mm_mem_dummy, zend_mm_mem_alloc, zend_mm_mem_realloc, zend_mm_mem_free };
|
||||
|
||||
void phpdbg_set_sigsafe_mem(char *buffer TSRMLS_DC) {
|
||||
phpdbg_signal_safe_mem *mem = &PHPDBG_G(sigsafe_mem);
|
||||
mem->old_heap = zend_mm_set_heap(&mem->heap TSRMLS_CC);
|
||||
mem->mem = buffer;
|
||||
mem->allocated = 0;
|
||||
|
||||
mem->storage.handlers = &phpdbg_handlers_sigsafe_mem;
|
||||
mem->heap.storage = &mem->storage;
|
||||
mem->heap.block_size = PHPDBG_SIGSAFE_MEM_SIZE;
|
||||
mem->heap.compact_size = 0;
|
||||
mem->heap.segments_list = NULL;
|
||||
zend_mm_init(&mem->heap);
|
||||
#if ZEND_MM_CACHE_STAT
|
||||
memset(mem->heap.cache_stat, 0, sizeof(mem->heap.cache_stat));
|
||||
#endif
|
||||
mem->heap.use_zend_alloc = 1;
|
||||
mem->heap.real_size = 0;
|
||||
mem->heap.overflow = 0;
|
||||
mem->heap.real_peak = 0;
|
||||
mem->heap.limit = PHPDBG_SIGSAFE_MEM_SIZE;
|
||||
mem->heap.size = 0;
|
||||
mem->heap.peak = 0;
|
||||
mem->heap.internal = 0;
|
||||
mem->heap.reserve = NULL;
|
||||
mem->heap.reserve_size = 0;
|
||||
}
|
||||
|
||||
zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D) {
|
||||
return PHPDBG_G(sigsafe_mem).old_heap;
|
||||
}
|
||||
|
||||
void phpdbg_clear_sigsafe_mem(TSRMLS_D) {
|
||||
zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC);
|
||||
PHPDBG_G(sigsafe_mem).mem = NULL;
|
||||
}
|
||||
|
||||
zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D) {
|
||||
return !!PHPDBG_G(sigsafe_mem).mem;
|
||||
}
|
||||
|
25
phpdbg_sigsafe.h
Normal file
25
phpdbg_sigsafe.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef PHPDBG_SIGSAFE_H
|
||||
#define PHPDBG_SIGSAFE_H
|
||||
|
||||
#include "zend_mm_structs.h"
|
||||
|
||||
#define PHPDBG_SIGSAFE_MEM_SIZE (1 << 20)
|
||||
|
||||
typedef struct {
|
||||
char *mem;
|
||||
zend_bool allocated;
|
||||
zend_mm_heap heap;
|
||||
zend_mm_heap *old_heap;
|
||||
zend_mm_storage storage;
|
||||
} phpdbg_signal_safe_mem;
|
||||
|
||||
#include "phpdbg.h"
|
||||
|
||||
zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D);
|
||||
|
||||
void phpdbg_set_sigsafe_mem(char *mem TSRMLS_DC);
|
||||
void phpdbg_clear_sigsafe_mem(TSRMLS_D);
|
||||
|
||||
zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D);
|
||||
|
||||
#endif
|
326
phpdbg_utils.c
326
phpdbg_utils.c
@ -716,7 +716,7 @@ static int format_converter(register buffy *odp, const char *fmt, zend_bool esca
|
||||
|
||||
int old_slen = s_len, i = 0;
|
||||
char *old_s = s, *s_ptr;
|
||||
free_s = s_ptr = s = malloc(old_slen * 6 + 1);
|
||||
free_s = s_ptr = s = emalloc(old_slen * 6 + 1);
|
||||
do {
|
||||
if (old_s[i] == '&' || old_s[i] == '"') {
|
||||
*s_ptr++ = '&';
|
||||
@ -772,7 +772,7 @@ static int format_converter(register buffy *odp, const char *fmt, zend_bool esca
|
||||
|
||||
|
||||
case 'r':
|
||||
s_len = asprintf(&s, "req=\"%lu\"", PHPDBG_G(req_id));
|
||||
s_len = spprintf(&s, 0, "req=\"%lu\"", PHPDBG_G(req_id));
|
||||
free_s = s;
|
||||
break;
|
||||
|
||||
@ -983,7 +983,7 @@ fmt_error:
|
||||
}
|
||||
skip_output:
|
||||
if (free_s) {
|
||||
free(free_s);
|
||||
efree(free_s);
|
||||
free_s = NULL;
|
||||
}
|
||||
|
||||
@ -1040,9 +1040,9 @@ PHPAPI int phpdbg_xml_vasprintf(char **buf, const char *format, zend_bool escape
|
||||
*buf = NULL;
|
||||
|
||||
if (cc >= 0) {
|
||||
if ((*buf = malloc(++cc)) != NULL) {
|
||||
if ((*buf = emalloc(++cc)) != NULL) {
|
||||
if ((cc = phpdbg_xml_vsnprintf(*buf, cc, format, escape_xml, ap TSRMLS_CC)) < 0) {
|
||||
free(*buf);
|
||||
efree(*buf);
|
||||
*buf = NULL;
|
||||
}
|
||||
}
|
||||
@ -1052,13 +1052,36 @@ PHPAPI int phpdbg_xml_vasprintf(char **buf, const char *format, zend_bool escape
|
||||
}
|
||||
/* copy end */
|
||||
|
||||
static int phpdbg_process_print(FILE *fp, int type, const char *tag, const char *msg, int msglen, const char *xml, int xmllen TSRMLS_DC) {
|
||||
char *msgout, *buf;
|
||||
static int phpdbg_encode_xml(char **buf, char *msg, int msglen, char from, char *to) {
|
||||
int i;
|
||||
char *tmp = *buf = emalloc(msglen * strlen(to));
|
||||
int tolen = strlen(to);
|
||||
for (i = 0; i++ < msglen; msg++) {
|
||||
if (*msg == '&') {
|
||||
memcpy(tmp, ZEND_STRL("&"));
|
||||
tmp += sizeof("&") - 1;
|
||||
} else if (*msg == from) {
|
||||
memcpy(tmp, to, tolen);
|
||||
tmp += tolen;
|
||||
} else {
|
||||
*tmp++ = *msg;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int len = tmp - *buf;
|
||||
*buf = erealloc(*buf, len);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
static int phpdbg_process_print(int fd, int type, const char *tag, const char *msg, int msglen, const char *xml, int xmllen TSRMLS_DC) {
|
||||
char *msgout = NULL, *buf;
|
||||
int msgoutlen, xmloutlen, buflen;
|
||||
const char *severity;
|
||||
|
||||
if ((PHPDBG_G(flags) & PHPDBG_WRITE_XML) && PHPDBG_G(in_script_xml) && PHPDBG_G(in_script_xml) != type) {
|
||||
fprintf(fp, "</stream>");
|
||||
write(fd, ZEND_STRL("</stream>"));
|
||||
PHPDBG_G(in_script_xml) = 0;
|
||||
}
|
||||
|
||||
@ -1069,16 +1092,16 @@ static int phpdbg_process_print(FILE *fp, int type, const char *tag, const char
|
||||
severity = "error";
|
||||
if (!PHPDBG_G(last_was_newline)) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
|
||||
fprintf(fp, "<phpdbg>\n</phpdbg>");
|
||||
write(fd, ZEND_STRL("<phpdbg>\n</phpdbg>"));
|
||||
} else {
|
||||
fprintf(fp, "\n");
|
||||
write(fd, ZEND_STRL("\n"));
|
||||
}
|
||||
PHPDBG_G(last_was_newline) = 1;
|
||||
}
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
msgoutlen = asprintf(&msgout, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, msglen, msg);
|
||||
msgoutlen = spprintf(&msgout, 0, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, msglen, msg);
|
||||
} else {
|
||||
msgoutlen = asprintf(&msgout, "[%.*s]\n", msglen, msg);
|
||||
msgoutlen = spprintf(&msgout, 0, "[%.*s]\n", msglen, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1086,26 +1109,26 @@ static int phpdbg_process_print(FILE *fp, int type, const char *tag, const char
|
||||
severity = "notice";
|
||||
if (!PHPDBG_G(last_was_newline)) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
|
||||
fprintf(fp, "<phpdbg>\n</phpdbg>");
|
||||
write(fd, ZEND_STRL("<phpdbg>\n</phpdbg>"));
|
||||
} else {
|
||||
fprintf(fp, "\n");
|
||||
write(fd, ZEND_STRL("\n"));
|
||||
}
|
||||
PHPDBG_G(last_was_newline) = 1;
|
||||
}
|
||||
if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) {
|
||||
msgoutlen = asprintf(&msgout, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, msglen, msg);
|
||||
msgoutlen = spprintf(&msgout, 0, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, msglen, msg);
|
||||
} else {
|
||||
msgoutlen = asprintf(&msgout, "[%.*s]\n", msglen, msg);
|
||||
msgoutlen = spprintf(&msgout, 0, "[%.*s]\n", msglen, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case P_WRITELN:
|
||||
severity = "normal";
|
||||
if (msg) {
|
||||
msgoutlen = asprintf(&msgout, "%.*s\n", msglen, msg);
|
||||
msgoutlen = spprintf(&msgout, 0, "%.*s\n", msglen, msg);
|
||||
} else {
|
||||
msgoutlen = 1;
|
||||
msgout = strdup("\n");
|
||||
msgout = estrdup("\n");
|
||||
}
|
||||
PHPDBG_G(last_was_newline) = 1;
|
||||
break;
|
||||
@ -1113,12 +1136,12 @@ static int phpdbg_process_print(FILE *fp, int type, const char *tag, const char
|
||||
case P_WRITE:
|
||||
severity = "normal";
|
||||
if (msg) {
|
||||
msgout = strndup(msg, msglen);
|
||||
msgout = estrndup(msg, msglen);
|
||||
msgoutlen = msglen;
|
||||
PHPDBG_G(last_was_newline) = msg[msglen - 1] == '\n';
|
||||
} else {
|
||||
msgoutlen = 0;
|
||||
msgout = strdup("");
|
||||
msgout = estrdup("");
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1128,14 +1151,17 @@ static int phpdbg_process_print(FILE *fp, int type, const char *tag, const char
|
||||
PHPDBG_G(last_was_newline) = msg[msglen - 1] == '\n';
|
||||
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
|
||||
if (PHPDBG_G(in_script_xml) != type) {
|
||||
fprintf(fp, "<stream type=\"%s\">", type == P_STDERR ? "stderr" : "stdout");
|
||||
char *stream_buf;
|
||||
int stream_buflen = spprintf(&stream_buf, 0, "<stream type=\"%s\">", type == P_STDERR ? "stderr" : "stdout");
|
||||
write(fd, stream_buf, stream_buflen);
|
||||
efree(stream_buf);
|
||||
PHPDBG_G(in_script_xml) = type;
|
||||
}
|
||||
buf = php_escape_html_entities((unsigned char *) msg, msglen, (size_t *) &buflen, 0, ENT_NOQUOTES, PG(internal_encoding) && PG(internal_encoding)[0] ? PG(internal_encoding) : (SG(default_charset) ? SG(default_charset) : "UTF-8") TSRMLS_CC);
|
||||
fprintf(fp, "%.*s", buflen, buf);
|
||||
write(fd, buf, buflen);
|
||||
efree(buf);
|
||||
} else {
|
||||
fprintf(fp, "%.*s", msglen, msg);
|
||||
write(fd, msg, msglen);
|
||||
}
|
||||
return msglen;
|
||||
}
|
||||
@ -1147,7 +1173,7 @@ static int phpdbg_process_print(FILE *fp, int type, const char *tag, const char
|
||||
if (msg) {
|
||||
struct timeval tp;
|
||||
if (gettimeofday(&tp, NULL) == SUCCESS) {
|
||||
msgoutlen = asprintf(&msgout, "[%ld %.8F]: %.*s\n", tp.tv_sec, tp.tv_usec / 1000000., msglen, msg);
|
||||
msgoutlen = spprintf(&msgout, 0, "[%ld %.8F]: %.*s\n", tp.tv_sec, tp.tv_usec / 1000000., msglen, msg);
|
||||
} else {
|
||||
msgoutlen = FAILURE;
|
||||
}
|
||||
@ -1155,37 +1181,43 @@ static int phpdbg_process_print(FILE *fp, int type, const char *tag, const char
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
|
||||
char *xmlout;
|
||||
|
||||
if (PHPDBG_G(req_id)) {
|
||||
char *xmlbuf = NULL;
|
||||
xmllen = asprintf(&xmlbuf, "req=\"%lu\" %.*s", PHPDBG_G(req_id), xmllen, xml);
|
||||
xmllen = spprintf(&xmlbuf, 0, "req=\"%lu\" %.*s", PHPDBG_G(req_id), xmllen, xml);
|
||||
xml = xmlbuf;
|
||||
}
|
||||
if (msgout) {
|
||||
buf = php_escape_html_entities((unsigned char *) msgout, msgoutlen, (size_t *) &buflen, 0, ENT_COMPAT, PG(internal_encoding) && PG(internal_encoding)[0] ? PG(internal_encoding) : (SG(default_charset) ? SG(default_charset) : "UTF-8") TSRMLS_CC);
|
||||
xmloutlen = fprintf(fp, "<%s severity=\"%s\" %.*s msgout=\"%.*s\" />", tag, severity, xmllen, xml, buflen, buf);
|
||||
// unsigned char *tmp = msgout;
|
||||
// buf = php_escape_html_entities(tmp, msgoutlen, (size_t *) &buflen, 0, ENT_COMPAT, PG(internal_encoding) && PG(internal_encoding)[0] ? PG(internal_encoding) : (SG(default_charset) ? SG(default_charset) : "UTF-8") TSRMLS_CC);
|
||||
buflen = phpdbg_encode_xml(&buf, msgout, msgoutlen, '"', """);
|
||||
xmloutlen = spprintf(&xmlout, 0, "<%s severity=\"%s\" %.*s msgout=\"%.*s\" />", tag, severity, xmllen, xml, buflen, buf);
|
||||
|
||||
efree(buf);
|
||||
} else {
|
||||
xmloutlen = fprintf(fp, "<%s severity=\"%s\" %.*s msgout=\"\" />", tag, severity, xmllen, xml);
|
||||
xmloutlen = spprintf(&xmlout, 0, "<%s severity=\"%s\" %.*s msgout=\"\" />", tag, severity, xmllen, xml);
|
||||
}
|
||||
|
||||
write(fd, xmlout, xmloutlen);
|
||||
efree(xmlout);
|
||||
} else if (msgout) {
|
||||
fprintf(fp, "%.*s", msgoutlen, msgout);
|
||||
write(fd, msgout, msgoutlen);
|
||||
}
|
||||
|
||||
if (PHPDBG_G(req_id) && (PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
|
||||
free((char *) xml);
|
||||
efree((char *) xml);
|
||||
}
|
||||
|
||||
if (msgout) {
|
||||
free(msgout);
|
||||
efree(msgout);
|
||||
}
|
||||
|
||||
return msgout ? msgoutlen : xmloutlen;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, FILE *fp, const char *tag, const char *xmlfmt, const char *strfmt, va_list args) {
|
||||
PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, va_list args) {
|
||||
char *msg = NULL, *xml = NULL;
|
||||
int msglen = 0, xmllen = 0;
|
||||
int len;
|
||||
@ -1207,8 +1239,8 @@ PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, FILE *fp, const char *tag, cons
|
||||
|
||||
if (PHPDBG_G(err_buf).active && type != P_STDOUT && type != P_STDERR) {
|
||||
PHPDBG_G(err_buf).type = type;
|
||||
PHPDBG_G(err_buf).fp = fp;
|
||||
PHPDBG_G(err_buf).tag = strdup(tag);
|
||||
PHPDBG_G(err_buf).fd = fd;
|
||||
PHPDBG_G(err_buf).tag = estrdup(tag);
|
||||
PHPDBG_G(err_buf).msg = msg;
|
||||
PHPDBG_G(err_buf).msglen = msglen;
|
||||
PHPDBG_G(err_buf).xml = xml;
|
||||
@ -1217,14 +1249,14 @@ PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, FILE *fp, const char *tag, cons
|
||||
return msglen;
|
||||
}
|
||||
|
||||
len = phpdbg_process_print(fp, type, tag, msg, msglen, xml, xmllen TSRMLS_CC);
|
||||
len = phpdbg_process_print(fd, type, tag, msg, msglen, xml, xmllen TSRMLS_CC);
|
||||
|
||||
if (msg) {
|
||||
free(msg);
|
||||
efree(msg);
|
||||
}
|
||||
|
||||
if (xml) {
|
||||
free(xml);
|
||||
efree(xml);
|
||||
}
|
||||
|
||||
return len;
|
||||
@ -1237,9 +1269,9 @@ PHPDBG_API void phpdbg_free_err_buf(TSRMLS_D) {
|
||||
|
||||
PHPDBG_G(err_buf).type = 0;
|
||||
|
||||
free(PHPDBG_G(err_buf).tag);
|
||||
free(PHPDBG_G(err_buf).msg);
|
||||
free(PHPDBG_G(err_buf).xml);
|
||||
efree(PHPDBG_G(err_buf).tag);
|
||||
efree(PHPDBG_G(err_buf).msg);
|
||||
efree(PHPDBG_G(err_buf).xml);
|
||||
}
|
||||
|
||||
PHPDBG_API void phpdbg_activate_err_buf(zend_bool active TSRMLS_DC) {
|
||||
@ -1258,7 +1290,7 @@ PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const
|
||||
#else
|
||||
va_start(args, strfmt);
|
||||
#endif
|
||||
len = phpdbg_vprint(PHPDBG_G(err_buf).type TSRMLS_CC, PHPDBG_G(err_buf).fp, tag ? tag : PHPDBG_G(err_buf).tag, xmlfmt, strfmt, args);
|
||||
len = phpdbg_vprint(PHPDBG_G(err_buf).type TSRMLS_CC, PHPDBG_G(err_buf).fd, tag ? tag : PHPDBG_G(err_buf).tag, xmlfmt, strfmt, args);
|
||||
va_end(args);
|
||||
|
||||
PHPDBG_G(err_buf).active = errbuf_active;
|
||||
@ -1267,18 +1299,20 @@ PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const
|
||||
return len;
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *tag, const char *xmlfmt, const char *strfmt, ...) {
|
||||
PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) {
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
va_start(args, strfmt);
|
||||
len = phpdbg_vprint(type TSRMLS_CC, fp, tag, xmlfmt, strfmt, args);
|
||||
len = phpdbg_vprint(type TSRMLS_CC, fd, tag, xmlfmt, strfmt, args);
|
||||
va_end(args);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_xml_internal(FILE *fp TSRMLS_DC, const char *fmt, ...) {
|
||||
PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) {
|
||||
int len = 0;
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
|
||||
va_list args;
|
||||
char *buffer;
|
||||
@ -1289,32 +1323,38 @@ PHPDBG_API int phpdbg_xml_internal(FILE *fp TSRMLS_DC, const char *fmt, ...) {
|
||||
va_end(args);
|
||||
|
||||
if (PHPDBG_G(in_script_xml)) {
|
||||
fprintf(fp, "</stream>");
|
||||
write(fd, ZEND_STRL("</stream>"));
|
||||
PHPDBG_G(in_script_xml) = 0;
|
||||
}
|
||||
|
||||
return fprintf(fp, "%.*s", buflen, buffer);
|
||||
len = write(fd, buffer, buflen);
|
||||
efree(buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_log_internal(FILE *fp TSRMLS_DC, const char *fmt, ...) {
|
||||
PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...) {
|
||||
va_list args;
|
||||
char *buffer;
|
||||
int buflen;
|
||||
int len = 0;
|
||||
|
||||
va_start(args, fmt);
|
||||
buflen = vspprintf(&buffer, 0, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return fprintf(fp, "%.*s", buflen, buffer);
|
||||
len = write(fd, buffer, buflen);
|
||||
efree(buffer);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_out_internal(FILE *fp TSRMLS_DC, const char *fmt, ...) {
|
||||
PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) {
|
||||
va_list args;
|
||||
char *buffer;
|
||||
int buflen;
|
||||
int len = 0;
|
||||
|
||||
va_start(args, fmt);
|
||||
buflen = vspprintf(&buffer, 0, fmt, args);
|
||||
@ -1322,19 +1362,22 @@ PHPDBG_API int phpdbg_out_internal(FILE *fp TSRMLS_DC, const char *fmt, ...) {
|
||||
|
||||
if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) {
|
||||
if (PHPDBG_G(in_script_xml)) {
|
||||
fprintf(fp, "</stream>");
|
||||
write(fd, ZEND_STRL("</stream>"));
|
||||
PHPDBG_G(in_script_xml) = 0;
|
||||
}
|
||||
|
||||
fprintf(fp, "<phpdbg>%.*s</phpdbg>", buflen, buffer);
|
||||
return buflen;
|
||||
write(fd, ZEND_STRL("<phpdbg>"));
|
||||
len = write(fd, buffer, buflen);
|
||||
write(fd, ZEND_STRL("</phpdbg>"));
|
||||
} else {
|
||||
return fprintf(fp, "%.*s", buflen, buffer);
|
||||
len = write(fd, buffer, buflen);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
|
||||
PHPDBG_API int phpdbg_rlog(int fd, const char *fmt, ...) { /* {{{ */
|
||||
int rc = 0;
|
||||
|
||||
va_list args;
|
||||
@ -1343,16 +1386,21 @@ PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
|
||||
va_start(args, fmt);
|
||||
if (gettimeofday(&tp, NULL) == SUCCESS) {
|
||||
char friendly[100];
|
||||
char *format = NULL, *buffer = NULL;
|
||||
char *format = NULL, *buffer = NULL, *outbuf = 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);
|
||||
spprintf(&buffer, 0, friendly, tp.tv_usec/1000);
|
||||
spprintf(&format, 0, "[%s]: %s\n", buffer, fmt);
|
||||
rc = vspprintf(&outbuf, 0, format, args);
|
||||
|
||||
free(format);
|
||||
free(buffer);
|
||||
if (outbuf) {
|
||||
rc = write(fd, outbuf, rc);
|
||||
efree(outbuf);
|
||||
}
|
||||
|
||||
efree(format);
|
||||
efree(buffer);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
@ -1489,3 +1537,157 @@ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */
|
||||
#endif
|
||||
return columns;
|
||||
} /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_set_async_io(int fd) {
|
||||
#ifndef _WIN32
|
||||
int flags;
|
||||
fcntl(STDIN_FILENO, F_SETOWN, getpid());
|
||||
flags = fcntl(STDIN_FILENO, F_GETFL);
|
||||
fcntl(STDIN_FILENO, F_SETFL, flags | FASYNC);
|
||||
#endif
|
||||
}
|
||||
|
||||
int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) {
|
||||
if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
|
||||
char *lc_name, *lc_free;
|
||||
int lc_length, ret = FAILURE;
|
||||
|
||||
if (name == NULL || !name_length) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
lc_free = lc_name = emalloc(name_length + 1);
|
||||
zend_str_tolower_copy(lc_name, name, name_length);
|
||||
lc_length = name_length + 1;
|
||||
|
||||
if (lc_name[0] == '\\') {
|
||||
lc_name += 1;
|
||||
lc_length -= 1;
|
||||
}
|
||||
|
||||
phpdbg_try_access {
|
||||
ret = zend_hash_find(EG(class_table), lc_name, lc_length, (void **) &ce);
|
||||
} phpdbg_catch_access {
|
||||
phpdbg_error("signalsegv", "class=\"%.*s\"", "Could not fetch class %.*s, invalid data source", name_length, name);
|
||||
} phpdbg_end_try_access();
|
||||
|
||||
efree(lc_free);
|
||||
return ret;
|
||||
} else {
|
||||
return zend_lookup_class(name, name_length, ce TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
char *phpdbg_get_property_key(char *key) {
|
||||
if (*key != 0) {
|
||||
return key;
|
||||
}
|
||||
return strchr(key + 1, 0) + 1;
|
||||
}
|
||||
|
||||
static int phpdbg_parse_variable_arg_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, phpdbg_parse_var_func callback TSRMLS_DC) {
|
||||
return callback(name, len, keyname, keylen, parent, zv TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC) {
|
||||
return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_parse_variable_arg_wrapper, silent, callback TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC) {
|
||||
int ret = FAILURE;
|
||||
zend_bool new_index = 1;
|
||||
char *last_index;
|
||||
size_t index_len = 0;
|
||||
zval **zv;
|
||||
|
||||
if (len < 2 || *input != '$') {
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (i++ < len) {
|
||||
if (i == len) {
|
||||
new_index = 1;
|
||||
} else {
|
||||
switch (input[i]) {
|
||||
case '[':
|
||||
new_index = 1;
|
||||
break;
|
||||
case ']':
|
||||
break;
|
||||
case '>':
|
||||
if (last_index[index_len - 1] == '-') {
|
||||
new_index = 1;
|
||||
index_len--;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (new_index) {
|
||||
last_index = input + i;
|
||||
new_index = 0;
|
||||
}
|
||||
if (input[i - 1] == ']') {
|
||||
goto error;
|
||||
}
|
||||
index_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_index && index_len == 0) {
|
||||
HashPosition position;
|
||||
for (zend_hash_internal_pointer_reset_ex(parent, &position);
|
||||
zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(parent, &position)) {
|
||||
if (i == len || (i == len - 1 && input[len - 1] == ']')) {
|
||||
zval *key = emalloc(sizeof(zval));
|
||||
size_t namelen;
|
||||
char *name;
|
||||
char *keyname = estrndup(last_index, index_len);
|
||||
zend_hash_get_current_key_zval_ex(parent, key, &position);
|
||||
convert_to_string(key);
|
||||
name = emalloc(i + Z_STRLEN_P(key) + 2);
|
||||
namelen = sprintf(name, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":"");
|
||||
efree(key);
|
||||
|
||||
ret = callback(name, namelen, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
|
||||
} else if (Z_TYPE_PP(zv) == IS_OBJECT) {
|
||||
phpdbg_parse_variable_with_arg(input, len, Z_OBJPROP_PP(zv), i, callback, silent, arg TSRMLS_CC);
|
||||
} else if (Z_TYPE_PP(zv) == IS_ARRAY) {
|
||||
phpdbg_parse_variable_with_arg(input, len, Z_ARRVAL_PP(zv), i, callback, silent, arg TSRMLS_CC);
|
||||
} else {
|
||||
/* Ignore silently */
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} else if (new_index) {
|
||||
char last_chr = last_index[index_len];
|
||||
last_index[index_len] = 0;
|
||||
if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) {
|
||||
if (!silent) {
|
||||
phpdbg_error("variable", "type=\"undefined\" variable=\"%.*s\"", "%.*s is undefined", (int) i, input);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
last_index[index_len] = last_chr;
|
||||
if (i == len) {
|
||||
char *name = estrndup(input, len);
|
||||
char *keyname = estrndup(last_index, index_len);
|
||||
|
||||
ret = callback(name, len, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
|
||||
} else if (Z_TYPE_PP(zv) == IS_OBJECT) {
|
||||
parent = Z_OBJPROP_PP(zv);
|
||||
} else if (Z_TYPE_PP(zv) == IS_ARRAY) {
|
||||
parent = Z_ARRVAL_PP(zv);
|
||||
} else {
|
||||
phpdbg_error("variable", "type=\"notiterable\" variable=\"%.*s\"", "%.*s is nor an array nor an object", (int) i, input);
|
||||
return FAILURE;
|
||||
}
|
||||
index_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
error:
|
||||
phpdbg_error("variable", "type=\"invalidinput\"", "Malformed input");
|
||||
return FAILURE;
|
||||
}
|
||||
|
@ -47,37 +47,37 @@ enum {
|
||||
};
|
||||
|
||||
#ifdef ZTS
|
||||
PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE *, const char *, const char *, const char *, ...) PHP_ATTRIBUTE_FORMAT(printf, 6, 7);
|
||||
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);
|
||||
#else
|
||||
PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE *, const char *, const char *, const char *, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6);
|
||||
PHPDBG_API int phpdbg_print(int severity TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6);
|
||||
#endif
|
||||
|
||||
PHPDBG_API int phpdbg_xml_internal(FILE *fp TSRMLS_DC, const char *fmt, ...);
|
||||
PHPDBG_API int phpdbg_log_internal(FILE *fp TSRMLS_DC, const char *fmt, ...);
|
||||
PHPDBG_API int phpdbg_out_internal(FILE *fp TSRMLS_DC, const char *fmt, ...);
|
||||
PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...);
|
||||
PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...);
|
||||
PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...);
|
||||
|
||||
PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...);
|
||||
PHPDBG_API int phpdbg_rlog(int fd, const char *fmt, ...);
|
||||
|
||||
#define phpdbg_error(tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_notice(tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_writeln(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_write(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], tag, xmlfmt, strfmt, ##__VA_ARGS__)
|
||||
#define phpdbg_script(type, fmt, ...) phpdbg_print(type TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], NULL, NULL, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_log(fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT] TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_xml(fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT] TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_out(fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT] TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#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] TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_xml_ex(out, fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT] TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#define phpdbg_out_ex(out, fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT] TSRMLS_CC, 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__)
|
||||
|
||||
#if PHPDBG_DEBUG
|
||||
# define phpdbg_debug(fmt, ...) phpdbg_log_ex(PHPDBG_G(io)[PHPDBG_STDERR] TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
# define phpdbg_debug(fmt, ...) phpdbg_log_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd TSRMLS_CC, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define phpdbg_debug(fmt, ...)
|
||||
#endif
|
||||
@ -133,6 +133,8 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */
|
||||
/* {{{ Console Width */
|
||||
PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */
|
||||
|
||||
PHPDBG_API void phpdbg_set_async_io(int fd);
|
||||
|
||||
int phpdbg_rebuild_symtable(TSRMLS_D);
|
||||
|
||||
#if PHP_VERSION_ID < 50500
|
||||
@ -155,4 +157,14 @@ static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, Ha
|
||||
}
|
||||
#endif
|
||||
|
||||
int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC);
|
||||
|
||||
char *phpdbg_get_property_key(char *key);
|
||||
|
||||
typedef int (*phpdbg_parse_var_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv TSRMLS_DC);
|
||||
typedef int (*phpdbg_parse_var_with_arg_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, void *arg TSRMLS_DC);
|
||||
|
||||
PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC);
|
||||
PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC);
|
||||
|
||||
#endif /* PHPDBG_UTILS_H */
|
||||
|
416
phpdbg_wait.c
Normal file
416
phpdbg_wait.c
Normal file
@ -0,0 +1,416 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 **zvpp;
|
||||
if (PG(http_globals)[type]) {
|
||||
zval_dtor(PG(http_globals)[type]);
|
||||
}
|
||||
if (zend_hash_find(&EG(symbol_table), name, strlen(name) + 1, (void **) &zvpp) == SUCCESS) {
|
||||
Z_SET_REFCOUNT_PP(zvpp, 2);
|
||||
PG(http_globals)[type] = *zvpp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int phpdbg_dearm_autoglobals(zend_auto_global *auto_global TSRMLS_DC) {
|
||||
if (auto_global->name_len != sizeof("GLOBALS") - 1 || memcmp(auto_global->name, "GLOBALS", sizeof("GLOBALS") - 1)) {
|
||||
auto_global->armed = 0;
|
||||
}
|
||||
|
||||
return ZEND_HASH_APPLY_KEEP;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
HashTable *ht[2];
|
||||
HashPosition pos[2];
|
||||
} phpdbg_intersect_ptr;
|
||||
|
||||
static int phpdbg_array_data_compare(const void *a, const void *b TSRMLS_DC) {
|
||||
Bucket *f, *s;
|
||||
zval result;
|
||||
zval *first, *second;
|
||||
|
||||
f = *((Bucket **) a);
|
||||
s = *((Bucket **) b);
|
||||
|
||||
first = *((zval **) f->pData);
|
||||
second = *((zval **) s->pData);
|
||||
|
||||
if (string_compare_function(&result, first, second TSRMLS_CC) == FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Z_LVAL(result) < 0) {
|
||||
return -1;
|
||||
} else if (Z_LVAL(result) > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void phpdbg_array_intersect_init(phpdbg_intersect_ptr *info, HashTable *ht1, HashTable *ht2 TSRMLS_DC) {
|
||||
info->ht[0] = ht1;
|
||||
info->ht[1] = ht2;
|
||||
|
||||
zend_hash_sort(info->ht[0], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC);
|
||||
zend_hash_sort(info->ht[1], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC);
|
||||
|
||||
zend_hash_internal_pointer_reset_ex(info->ht[0], &info->pos[0]);
|
||||
zend_hash_internal_pointer_reset_ex(info->ht[1], &info->pos[1]);
|
||||
}
|
||||
|
||||
/* -1 => first array, 0 => both arrays equal, 1 => second array */
|
||||
static int phpdbg_array_intersect(phpdbg_intersect_ptr *info, zval ***ptr) {
|
||||
int ret;
|
||||
zval **zvpp[2];
|
||||
int invalid = !info->ht[0] + !info->ht[1];
|
||||
|
||||
if (invalid > 0) {
|
||||
invalid = !info->ht[0];
|
||||
|
||||
if (zend_hash_get_current_data_ex(info->ht[invalid], (void **) ptr, &info->pos[invalid]) == FAILURE) {
|
||||
*ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
zend_hash_move_forward_ex(info->ht[invalid], &info->pos[invalid]);
|
||||
|
||||
return invalid ? 1 : -1;
|
||||
}
|
||||
|
||||
if (zend_hash_get_current_data_ex(info->ht[0], (void **) &zvpp[0], &info->pos[0]) == FAILURE) {
|
||||
info->ht[0] = NULL;
|
||||
return phpdbg_array_intersect(info, ptr);
|
||||
}
|
||||
if (zend_hash_get_current_data_ex(info->ht[1], (void **) &zvpp[1], &info->pos[1]) == FAILURE) {
|
||||
info->ht[1] = NULL;
|
||||
return phpdbg_array_intersect(info, ptr);
|
||||
}
|
||||
|
||||
ret = zend_binary_zval_strcmp(*zvpp[0], *zvpp[1]);
|
||||
|
||||
if (ret <= 0) {
|
||||
*ptr = zvpp[0];
|
||||
zend_hash_move_forward_ex(info->ht[0], &info->pos[0]);
|
||||
}
|
||||
if (ret >= 0) {
|
||||
*ptr = zvpp[1];
|
||||
zend_hash_move_forward_ex(info->ht[1], &info->pos[1]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC) {
|
||||
zval *free_zv = NULL;
|
||||
zval zv, **zvpp;
|
||||
HashTable *ht;
|
||||
php_json_decode(&zv, msg, len, 1, 1000 /* enough */ TSRMLS_CC);
|
||||
|
||||
if (JSON_G(error_code) != PHP_JSON_ERROR_NONE) {
|
||||
phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed JSON was sent to this socket, arborting");
|
||||
return;
|
||||
}
|
||||
|
||||
ht = Z_ARRVAL(zv);
|
||||
|
||||
/* Reapply symbol table */
|
||||
if (zend_hash_find(ht, "GLOBALS", sizeof("GLOBALS"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) {
|
||||
{
|
||||
zval **srv;
|
||||
if (zend_hash_find(Z_ARRVAL_PP(zvpp), "_SERVER", sizeof("_SERVER"), (void **) &srv) == SUCCESS && Z_TYPE_PP(srv) == IS_ARRAY) {
|
||||
zval **script;
|
||||
if (zend_hash_find(Z_ARRVAL_PP(srv), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &script) == SUCCESS && Z_TYPE_PP(script) == IS_STRING) {
|
||||
phpdbg_param_t param;
|
||||
param.str = Z_STRVAL_PP(script);
|
||||
PHPDBG_COMMAND_HANDLER(exec)(¶m TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PG(auto_globals_jit) = 0;
|
||||
zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_dearm_autoglobals TSRMLS_CC);
|
||||
|
||||
zend_hash_clean(&EG(symbol_table));
|
||||
EG(symbol_table) = *Z_ARRVAL_PP(zvpp);
|
||||
|
||||
/* Rebuild cookies, env vars etc. from GLOBALS (PG(http_globals)) */
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_POST, "_POST" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_GET, "_GET" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_COOKIE, "_COOKIE" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_SERVER, "_SERVER" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_ENV, "_ENV" TSRMLS_CC);
|
||||
phpdbg_rebuild_http_globals_array(TRACK_VARS_FILES, "_FILES" TSRMLS_CC);
|
||||
|
||||
Z_ADDREF_PP(zvpp);
|
||||
free_zv = *zvpp;
|
||||
}
|
||||
|
||||
if (zend_hash_find(ht, "input", sizeof("input"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_STRING) {
|
||||
if (SG(request_info).request_body) {
|
||||
php_stream_close(SG(request_info).request_body);
|
||||
}
|
||||
SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
|
||||
php_stream_truncate_set_size(SG(request_info).request_body, 0);
|
||||
php_stream_write(SG(request_info).request_body, Z_STRVAL_PP(zvpp), Z_STRLEN_PP(zvpp));
|
||||
}
|
||||
|
||||
if (zend_hash_find(ht, "cwd", sizeof("cwd"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_STRING) {
|
||||
if (VCWD_CHDIR(Z_STRVAL_PP(zvpp)) == SUCCESS) {
|
||||
if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) {
|
||||
efree(BG(CurrentStatFile));
|
||||
BG(CurrentStatFile) = NULL;
|
||||
}
|
||||
if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) {
|
||||
efree(BG(CurrentLStatFile));
|
||||
BG(CurrentLStatFile) = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zend_hash_find(ht, "sapi_name", sizeof("sapi_name"), (void **) &zvpp) == SUCCESS && (Z_TYPE_PP(zvpp) == IS_STRING || Z_TYPE_PP(zvpp) == IS_NULL)) {
|
||||
if (PHPDBG_G(sapi_name_ptr)) {
|
||||
free(PHPDBG_G(sapi_name_ptr));
|
||||
}
|
||||
if (Z_TYPE_PP(zvpp) == IS_STRING) {
|
||||
PHPDBG_G(sapi_name_ptr) = sapi_module.name = strdup(Z_STRVAL_PP(zvpp));
|
||||
} else {
|
||||
PHPDBG_G(sapi_name_ptr) = sapi_module.name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (zend_hash_find(ht, "modules", sizeof("modules"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) {
|
||||
HashPosition position;
|
||||
phpdbg_intersect_ptr pos;
|
||||
zval **module;
|
||||
zend_module_entry *mod;
|
||||
HashTable zv_registry;
|
||||
|
||||
/* intersect modules, unregister modules loaded "too much", announce not yet registered modules (phpdbg_notice) */
|
||||
|
||||
zend_hash_init(&zv_registry, zend_hash_num_elements(&module_registry), 0, ZVAL_PTR_DTOR, 0);
|
||||
for (zend_hash_internal_pointer_reset_ex(&module_registry, &position);
|
||||
zend_hash_get_current_data_ex(&module_registry, (void **) &mod, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&module_registry, &position)) {
|
||||
if (mod->name) {
|
||||
zval **value = emalloc(sizeof(zval *));
|
||||
MAKE_STD_ZVAL(*value);
|
||||
ZVAL_STRING(*value, mod->name, 1);
|
||||
zend_hash_next_index_insert(&zv_registry, value, sizeof(zval *), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
phpdbg_array_intersect_init(&pos, &zv_registry, Z_ARRVAL_PP(zvpp) TSRMLS_CC);
|
||||
do {
|
||||
int mode = phpdbg_array_intersect(&pos, &module);
|
||||
if (mode < 0) {
|
||||
// loaded module, but not needed
|
||||
if (strcmp(PHPDBG_NAME, Z_STRVAL_PP(module))) {
|
||||
zend_hash_del(&module_registry, Z_STRVAL_PP(module), Z_STRLEN_PP(module) + 1);
|
||||
}
|
||||
} else if (mode > 0) {
|
||||
// not loaded module
|
||||
if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_PP(module))) {
|
||||
phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", Z_STRLEN_PP(module), Z_STRVAL_PP(module), Z_STRLEN_PP(module), Z_STRVAL_PP(module));
|
||||
}
|
||||
}
|
||||
} while (module);
|
||||
|
||||
zend_hash_clean(&zv_registry);
|
||||
}
|
||||
|
||||
if (zend_hash_find(ht, "extensions", sizeof("extensions"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) {
|
||||
zend_extension *extension;
|
||||
zend_llist_position pos;
|
||||
HashPosition hpos;
|
||||
zval **name, key;
|
||||
|
||||
extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
|
||||
while (extension) {
|
||||
extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
|
||||
|
||||
/* php_serach_array() body should be in some ZEND_API function */
|
||||
for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &hpos);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void **) &name, &hpos) == SUCCESS;
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &hpos)) {
|
||||
if (Z_TYPE_PP(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_PP(name), Z_STRLEN_PP(name))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void **) &zvpp, &hpos) == FAILURE) {
|
||||
/* sigh, breaking the encapsulation, there aren't any functions manipulating the llist at the place of the zend_llist_position */
|
||||
zend_llist_element *elm = pos;
|
||||
if (elm->prev) {
|
||||
elm->prev->next = elm->next;
|
||||
} else {
|
||||
zend_extensions.head = elm->next;
|
||||
}
|
||||
if (elm->next) {
|
||||
elm->next->prev = elm->prev;
|
||||
} else {
|
||||
zend_extensions.tail = elm->prev;
|
||||
}
|
||||
#if ZEND_EXTENSIONS_SUPPORT
|
||||
if (extension->shutdown) {
|
||||
extension->shutdown(extension);
|
||||
}
|
||||
#endif
|
||||
if (zend_extensions.dtor) {
|
||||
zend_extensions.dtor(elm->data);
|
||||
}
|
||||
pefree(elm, zend_extensions.persistent);
|
||||
zend_extensions.count--;
|
||||
} else {
|
||||
zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &hpos);
|
||||
if (Z_TYPE(key) == IS_LONG) {
|
||||
zend_hash_index_del(Z_ARRVAL_PP(zvpp), Z_LVAL(key));
|
||||
}
|
||||
}
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &hpos);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void **) &name, &hpos) == SUCCESS;
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &hpos)) {
|
||||
phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", Z_STRLEN_PP(name), Z_STRVAL_PP(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zend_ini_deactivate(TSRMLS_C);
|
||||
|
||||
if (zend_hash_find(ht, "systemini", sizeof("systemini"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) {
|
||||
HashPosition position;
|
||||
zval **ini_entry;
|
||||
zend_ini_entry *original_ini;
|
||||
zval key;
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &position);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void**) &ini_entry, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &position)) {
|
||||
zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &position);
|
||||
if (Z_TYPE(key) == IS_STRING) {
|
||||
if (Z_TYPE_PP(ini_entry) == IS_STRING) {
|
||||
if (zend_hash_find(EG(ini_directives), Z_STRVAL(key), Z_STRLEN(key) + 1, (void **) &original_ini) == SUCCESS) {
|
||||
if (!original_ini->on_modify || original_ini->on_modify(original_ini, Z_STRVAL_PP(ini_entry), Z_STRLEN_PP(ini_entry), original_ini->mh_arg1, original_ini->mh_arg2, original_ini->mh_arg3, ZEND_INI_STAGE_ACTIVATE TSRMLS_CC) == SUCCESS) {
|
||||
if (original_ini->modified && original_ini->orig_value != original_ini->value) {
|
||||
efree(original_ini->value);
|
||||
}
|
||||
original_ini->value = Z_STRVAL_PP(ini_entry);
|
||||
original_ini->value_length = Z_STRLEN_PP(ini_entry);
|
||||
Z_TYPE_PP(ini_entry) = IS_NULL; /* don't free the value */
|
||||
}
|
||||
}
|
||||
}
|
||||
efree(Z_STRVAL(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zend_hash_find(ht, "userini", sizeof("userini"), (void **) &zvpp) == SUCCESS && Z_TYPE_PP(zvpp) == IS_ARRAY) {
|
||||
HashPosition position;
|
||||
zval **ini_entry;
|
||||
zval key;
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(zvpp), &position);
|
||||
zend_hash_get_current_data_ex(Z_ARRVAL_PP(zvpp), (void**) &ini_entry, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(Z_ARRVAL_PP(zvpp), &position)) {
|
||||
zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &position);
|
||||
if (Z_TYPE(key) == IS_STRING) {
|
||||
if (Z_TYPE_PP(ini_entry) == IS_STRING) {
|
||||
zend_alter_ini_entry_ex(Z_STRVAL(key), Z_STRLEN(key) + 1, Z_STRVAL_PP(ini_entry), Z_STRLEN_PP(ini_entry), ZEND_INI_PERDIR, ZEND_INI_STAGE_HTACCESS, 1 TSRMLS_CC);
|
||||
}
|
||||
efree(Z_STRVAL(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zval_dtor(&zv);
|
||||
if (free_zv) {
|
||||
/* separate freeing to not dtor the symtable too, just the container zval... */
|
||||
efree(free_zv);
|
||||
}
|
||||
|
||||
/* Reapply raw input */
|
||||
/* ??? */
|
||||
}
|
||||
|
||||
PHPDBG_COMMAND(wait) /* {{{ */
|
||||
{
|
||||
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;
|
||||
} /* }}} */
|
||||
|
29
phpdbg_wait.h
Normal file
29
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 */
|
135
phpdbg_watch.c
135
phpdbg_watch.c
@ -30,7 +30,6 @@
|
||||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *page;
|
||||
size_t size;
|
||||
@ -138,13 +137,6 @@ static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC)
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static char *phpdbg_get_property_key(char *key) {
|
||||
if (*key != 0) {
|
||||
return key;
|
||||
}
|
||||
return strchr(key + 1, 0) + 1;
|
||||
}
|
||||
|
||||
static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
|
||||
HashTable *ht;
|
||||
|
||||
@ -281,118 +273,37 @@ static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) {
|
||||
ret = zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
|
||||
}
|
||||
|
||||
free(tmp_watch->str);
|
||||
efree(tmp_watch->str);
|
||||
efree(tmp_watch->name_in_parent);
|
||||
efree(tmp_watch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) {
|
||||
int ret = FAILURE;
|
||||
zend_bool new_index = 1;
|
||||
char *last_index;
|
||||
int index_len = 0;
|
||||
zval **zv;
|
||||
static int phpdbg_watchpoint_parse_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) {
|
||||
int ret;
|
||||
phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
watch->flags = 0;
|
||||
watch->str = name;
|
||||
watch->str_len = len;
|
||||
watch->name_in_parent = keyname;
|
||||
watch->name_in_parent_len = keylen;
|
||||
watch->parent_container = parent;
|
||||
phpdbg_create_zval_watchpoint(*zv, watch);
|
||||
|
||||
if (len < 2 || *input != '$') {
|
||||
goto error;
|
||||
}
|
||||
ret = callback(watch TSRMLS_CC);
|
||||
|
||||
while (i++ < len) {
|
||||
if (i == len) {
|
||||
new_index = 1;
|
||||
} else {
|
||||
switch (input[i]) {
|
||||
case '[':
|
||||
new_index = 1;
|
||||
break;
|
||||
case ']':
|
||||
break;
|
||||
case '>':
|
||||
if (last_index[index_len - 1] == '-') {
|
||||
new_index = 1;
|
||||
index_len--;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (new_index) {
|
||||
last_index = input + i;
|
||||
new_index = 0;
|
||||
}
|
||||
if (input[i - 1] == ']') {
|
||||
goto error;
|
||||
}
|
||||
index_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_index && index_len == 0) {
|
||||
HashPosition position;
|
||||
for (zend_hash_internal_pointer_reset_ex(parent, &position);
|
||||
zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(parent, &position)) {
|
||||
if (i == len || (i == len - 1 && input[len - 1] == ']')) {
|
||||
zval *key = emalloc(sizeof(zval));
|
||||
phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
watch->flags = 0;
|
||||
zend_hash_get_current_key_zval_ex(parent, key, &position);
|
||||
convert_to_string(key);
|
||||
watch->str = malloc(i + Z_STRLEN_P(key) + 2);
|
||||
watch->str_len = sprintf(watch->str, "%.*s%s%s", (int) i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']' ? "]" : "");
|
||||
efree(key);
|
||||
watch->name_in_parent = zend_strndup(last_index, index_len);
|
||||
watch->name_in_parent_len = index_len;
|
||||
watch->parent_container = parent;
|
||||
phpdbg_create_zval_watchpoint(*zv, watch);
|
||||
|
||||
ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS ? SUCCESS : FAILURE;
|
||||
} else if (Z_TYPE_PP(zv) == IS_OBJECT) {
|
||||
phpdbg_watchpoint_parse_input(input, len, Z_OBJPROP_PP(zv), i, callback, silent TSRMLS_CC);
|
||||
} else if (Z_TYPE_PP(zv) == IS_ARRAY) {
|
||||
phpdbg_watchpoint_parse_input(input, len, Z_ARRVAL_PP(zv), i, callback, silent TSRMLS_CC);
|
||||
} else {
|
||||
/* Ignore silently */
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} else if (new_index) {
|
||||
char last_chr = last_index[index_len];
|
||||
last_index[index_len] = 0;
|
||||
if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) {
|
||||
if (!silent) {
|
||||
phpdbg_error("watch", "type=\"undefined\" variable=\"%.*s\"", "%.*s is undefined", (int) i, input);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
last_index[index_len] = last_chr;
|
||||
if (i == len) {
|
||||
phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
|
||||
watch->flags = 0;
|
||||
watch->str = zend_strndup(input, len);
|
||||
watch->str_len = len;
|
||||
watch->name_in_parent = zend_strndup(last_index, index_len);
|
||||
watch->name_in_parent_len = index_len;
|
||||
watch->parent_container = parent;
|
||||
phpdbg_create_zval_watchpoint(*zv, watch);
|
||||
|
||||
ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
|
||||
} else if (Z_TYPE_PP(zv) == IS_OBJECT) {
|
||||
parent = Z_OBJPROP_PP(zv);
|
||||
} else if (Z_TYPE_PP(zv) == IS_ARRAY) {
|
||||
parent = Z_ARRVAL_PP(zv);
|
||||
} else {
|
||||
phpdbg_error("watch", "type=\"notiterable\" variable=\"%.*s\"", "%.*s is nor an array nor an object", (int) i, input);
|
||||
return FAILURE;
|
||||
}
|
||||
index_len = 0;
|
||||
}
|
||||
if (ret != SUCCESS) {
|
||||
efree(watch);
|
||||
efree(name);
|
||||
efree(keyname);
|
||||
}
|
||||
|
||||
return ret;
|
||||
error:
|
||||
phpdbg_error("watch", "type=\"invalidinput\"", "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) {
|
||||
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) {
|
||||
@ -550,8 +461,8 @@ static void phpdbg_watch_dtor(void *pDest) {
|
||||
phpdbg_deactivate_watchpoint(watch TSRMLS_CC);
|
||||
phpdbg_remove_watchpoint(watch TSRMLS_CC);
|
||||
|
||||
free(watch->str);
|
||||
free(watch->name_in_parent);
|
||||
efree(watch->str);
|
||||
efree(watch->name_in_parent);
|
||||
efree(watch);
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,9 @@ PHPDBG_WATCH(recursive);
|
||||
*/
|
||||
|
||||
static const phpdbg_command_t phpdbg_watch_commands[] = {
|
||||
PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s"),
|
||||
PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s"),
|
||||
PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s"),
|
||||
PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s", 0),
|
||||
PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s", 0),
|
||||
PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s", 0),
|
||||
PHPDBG_END_COMMAND
|
||||
};
|
||||
|
||||
|
183
phpdbg_webdata_transfer.c
Normal file
183
phpdbg_webdata_transfer.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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_webdata_transfer.h"
|
||||
#include "ext/json/php_json.h"
|
||||
|
||||
PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC) {
|
||||
smart_str buf = {0};
|
||||
zval array;
|
||||
HashTable *ht;
|
||||
/* I really need to change that to an array of zvals... */
|
||||
zval zv1 = {{0}}, *zvp1 = &zv1;
|
||||
zval zv2 = {{0}}, *zvp2 = &zv2;
|
||||
zval zv3 = {{0}}, *zvp3 = &zv3;
|
||||
zval zv4 = {{0}}, *zvp4 = &zv4;
|
||||
zval zv5 = {{0}}, *zvp5 = &zv5;
|
||||
zval zv6 = {{0}}, *zvp6 = &zv6;
|
||||
zval zv7 = {{0}}, *zvp7 = &zv7;
|
||||
zval zv8 = {{0}}, *zvp8 = &zv8;
|
||||
|
||||
array_init(&array);
|
||||
ht = Z_ARRVAL(array);
|
||||
|
||||
/* fetch superglobals */
|
||||
{
|
||||
zend_is_auto_global(ZEND_STRL("GLOBALS") TSRMLS_CC);
|
||||
/* might be JIT */
|
||||
zend_is_auto_global(ZEND_STRL("_ENV") TSRMLS_CC);
|
||||
zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC);
|
||||
zend_is_auto_global(ZEND_STRL("_REQUEST") TSRMLS_CC);
|
||||
array_init(&zv1);
|
||||
zend_hash_copy(Z_ARRVAL(zv1), &EG(symbol_table), NULL, (void *) NULL, sizeof(zval *));
|
||||
Z_ARRVAL(zv1)->pDestructor = NULL; /* we're operating on a copy! Don't double free zvals */
|
||||
zend_hash_del(Z_ARRVAL(zv1), "GLOBALS", sizeof("GLOBALS")); /* do not use the reference to itself in json */
|
||||
zend_hash_add(ht, "GLOBALS", sizeof("GLOBALS"), &zvp1, sizeof(zval *), NULL);
|
||||
}
|
||||
|
||||
/* save php://input */
|
||||
{
|
||||
php_stream *stream;
|
||||
int len;
|
||||
char *contents;
|
||||
|
||||
stream = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
|
||||
if ((len = php_stream_copy_to_mem(stream, &contents, PHP_STREAM_COPY_ALL, 0)) > 0) {
|
||||
ZVAL_STRINGL(&zv2, contents, len, 0);
|
||||
} else {
|
||||
ZVAL_EMPTY_STRING(&zv2);
|
||||
}
|
||||
Z_SET_REFCOUNT(zv2, 2);
|
||||
zend_hash_add(ht, "input", sizeof("input"), &zvp2, sizeof(zval *), NULL);
|
||||
}
|
||||
|
||||
/* change sapi name */
|
||||
{
|
||||
if (sapi_module.name) {
|
||||
ZVAL_STRING(&zv6, sapi_module.name, 0);
|
||||
} else {
|
||||
Z_TYPE(zv6) = IS_NULL;
|
||||
}
|
||||
Z_SET_REFCOUNT(zv6, 2);
|
||||
zend_hash_add(ht, "sapi_name", sizeof("sapi_name"), &zvp6, sizeof(zval *), NULL);
|
||||
}
|
||||
|
||||
/* handle modules / extensions */
|
||||
{
|
||||
HashPosition position;
|
||||
zend_module_entry *module;
|
||||
zend_extension *extension;
|
||||
zend_llist_position pos;
|
||||
|
||||
array_init(&zv7);
|
||||
for (zend_hash_internal_pointer_reset_ex(&module_registry, &position);
|
||||
zend_hash_get_current_data_ex(&module_registry, (void**) &module, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(&module_registry, &position)) {
|
||||
zval **value = emalloc(sizeof(zval *));
|
||||
ALLOC_ZVAL(*value);
|
||||
ZVAL_STRING(*value, module->name, 1);
|
||||
zend_hash_next_index_insert(Z_ARRVAL(zv7), value, sizeof(zval *), NULL);
|
||||
}
|
||||
zend_hash_add(ht, "modules", sizeof("modules"), &zvp7, sizeof(zval *), NULL);
|
||||
|
||||
array_init(&zv8);
|
||||
extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
|
||||
while (extension) {
|
||||
zval **value = emalloc(sizeof(zval *));
|
||||
ALLOC_ZVAL(*value);
|
||||
ZVAL_STRING(*value, extension->name, 1);
|
||||
zend_hash_next_index_insert(Z_ARRVAL(zv8), value, sizeof(zval *), NULL);
|
||||
extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
|
||||
}
|
||||
zend_hash_add(ht, "extensions", sizeof("extensions"), &zvp8, sizeof(zval *), NULL);
|
||||
}
|
||||
|
||||
/* switch cwd */
|
||||
if (SG(options) & SAPI_OPTION_NO_CHDIR) {
|
||||
char *ret = NULL;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
#if HAVE_GETCWD
|
||||
ret = VCWD_GETCWD(path, MAXPATHLEN);
|
||||
#elif HAVE_GETWD
|
||||
ret = VCWD_GETWD(path);
|
||||
#endif
|
||||
if (ret) {
|
||||
ZVAL_STRING(&zv5, path, 1);
|
||||
Z_SET_REFCOUNT(zv5, 1);
|
||||
zend_hash_add(ht, "cwd", sizeof("cwd"), &zvp5, sizeof(zval *), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* get system ini entries */
|
||||
{
|
||||
HashPosition position;
|
||||
zend_ini_entry *ini_entry;
|
||||
|
||||
array_init(&zv3);
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(ini_directives), &position);
|
||||
zend_hash_get_current_data_ex(EG(ini_directives), (void**) &ini_entry, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(ini_directives), &position)) {
|
||||
zval **value = emalloc(sizeof(zval *));
|
||||
if (ini_entry->modified) {
|
||||
if (!ini_entry->orig_value) {
|
||||
efree(value);
|
||||
continue;
|
||||
}
|
||||
ALLOC_ZVAL(*value);
|
||||
ZVAL_STRINGL(*value, ini_entry->orig_value, ini_entry->orig_value_length, 1);
|
||||
} else {
|
||||
if (!ini_entry->value) {
|
||||
efree(value);
|
||||
continue;
|
||||
}
|
||||
ALLOC_ZVAL(*value);
|
||||
ZVAL_STRINGL(*value, ini_entry->value, ini_entry->value_length, 1);
|
||||
}
|
||||
zend_hash_add(Z_ARRVAL(zv3), ini_entry->name, ini_entry->name_length, value, sizeof(zval *), NULL);
|
||||
}
|
||||
zend_hash_add(ht, "systemini", sizeof("systemini"), &zvp3, sizeof(zval *), NULL);
|
||||
}
|
||||
|
||||
/* get perdir ini entries */
|
||||
if (EG(modified_ini_directives)) {
|
||||
HashPosition position;
|
||||
zend_ini_entry *ini_entry;
|
||||
|
||||
array_init(&zv4);
|
||||
for (zend_hash_internal_pointer_reset_ex(EG(modified_ini_directives), &position);
|
||||
zend_hash_get_current_data_ex(EG(modified_ini_directives), (void**) &ini_entry, &position) == SUCCESS;
|
||||
zend_hash_move_forward_ex(EG(modified_ini_directives), &position)) {
|
||||
zval **value = emalloc(sizeof(zval *));
|
||||
if (!ini_entry->value) {
|
||||
efree(value);
|
||||
continue;
|
||||
}
|
||||
ALLOC_ZVAL(*value);
|
||||
ZVAL_STRINGL(*value, ini_entry->value, ini_entry->value_length, 1);
|
||||
zend_hash_add(Z_ARRVAL(zv4), ini_entry->name, ini_entry->name_length, value, sizeof(zval *), NULL);
|
||||
}
|
||||
zend_hash_add(ht, "userini", sizeof("userini"), &zvp4, sizeof(zval *), NULL);
|
||||
}
|
||||
|
||||
/* encode data */
|
||||
php_json_encode(&buf, &array, 0 TSRMLS_CC);
|
||||
*msg = buf.c;
|
||||
*len = buf.len;
|
||||
zval_dtor(&array);
|
||||
}
|
27
phpdbg_webdata_transfer.h
Normal file
27
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 */
|
66
xml.md
66
xml.md
@ -18,6 +18,11 @@ 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
|
||||
----
|
||||
|
||||
@ -222,7 +227,7 @@ frame
|
||||
- maxnum: tried to access a frame with a number heigher than existing (or < 0)
|
||||
|
||||
### attributes on <arg> ###
|
||||
|
||||
v
|
||||
- variadic: has a non-empty value if the argument is variadic
|
||||
- name: variable name of parameter
|
||||
|
||||
@ -382,8 +387,8 @@ exec
|
||||
- invalid: given context (attribute) is not matching a valid file or symlink
|
||||
- notfound: given context (attribute) does not exist
|
||||
|
||||
run / <stop> tag
|
||||
----------------
|
||||
run / <stop> tag
|
||||
-------------------
|
||||
|
||||
- runs the script (set via exec command)
|
||||
- <stop type="end" />: script execution ended normally
|
||||
@ -562,21 +567,65 @@ set
|
||||
- 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
|
||||
- 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
|
||||
@ -593,3 +642,8 @@ Other tags
|
||||
- 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
|
||||
|
102
zend_mm_structs.h
Normal file
102
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…
Reference in New Issue
Block a user