Adapted opline_num breakpoints to master branch

This commit is contained in:
Bob Weinand 2013-12-07 15:35:35 +01:00
commit 50db4919ce
47 changed files with 4454 additions and 642 deletions

4
.gitignore vendored
View file

@ -1,5 +1,5 @@
.libs/
phpdbg
./phpdbg
*.lo
*.o
build

View file

@ -1,15 +1,24 @@
ChangeLog for phpdbg
====================
Version 0.2.0 2013-00-00
Version 0.3.0 2013-00-00
------------------------
1. Added ability to disable an enable a single breakpoint
2. Added ability to override SAPI name
3. Added extended conditional breakpoint support "break at"
4. Fix loading of zend extnsions with -z
Version 0.2.0 2013-11-31
------------------------
(this needs tidying before release)
1. Added "break delete <id>" command
2. Added "break opcode <opcode>" command
3. Added "set" command - control prompt and console colors
4. .phpdbginit now searched in (additional) ini dirs
5. Added source command - load additional .phpdbginit script during session
6. Added remote console mode
7. Added info memory command
Version 0.1.0 2013-11-23
------------------------

View file

@ -17,6 +17,7 @@ Features
- PHP Configuration File Support
- JIT Super Globals - Set Your Own !!
- Optional readline Support - Comfortable Terminal Operation
- Remote Debugging Support - Bundled Java GUI
- Easy Operation - See Help :)
Planned
@ -63,6 +64,9 @@ The following switches change the default behaviour of phpdbg:
- -q do not print banner on startup
- -r jump straight to run
- -E enable step through eval()
- -l listen ports for remote mode
- -a listen address for remote mode
- -S override SAPI name
*Note: passing -rr will cause phpdbg to quit after execution, rather than returning to the console*

View file

@ -17,7 +17,7 @@ if test "$PHP_PHPDBG" != "no"; then
AC_DEFINE(PHPDBG_DEBUG, 0, [ ])
fi
PHP_PHPDBG_CFLAGS="-I$abc_srcdir"
PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE"
PHP_PHPDBG_FILES="phpdbg.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c"
PHP_SUBST(PHP_PHPDBG_CFLAGS)

368
phpdbg.c
View file

@ -27,6 +27,16 @@
#include "phpdbg_utils.h"
#include "phpdbg_set.h"
/* {{{ remote console headers */
#ifndef _WIN32
# include <sys/socket.h>
# include <sys/select.h>
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# include <arpa/inet.h>
#endif /* }}} */
ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
#if PHP_VERSION_ID >= 50500
@ -84,7 +94,7 @@ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */
{
zend_llist_destroy((zend_llist*)brake);
zend_hash_destroy((HashTable*)brake);
} /* }}} */
static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */
@ -115,11 +125,11 @@ static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */
brake->ops TSRMLS_CC);
efree(brake->ops);
}
zval_dtor(&brake->code);
efree((char*)brake->code);
}
} /* }}} */
static void php_phpdbg_destroy_registered(void *data)
static void php_phpdbg_destroy_registered(void *data) /* {{{ */
{
TSRMLS_FETCH();
@ -127,7 +137,7 @@ static void php_phpdbg_destroy_registered(void *data)
destroy_zend_function(
function TSRMLS_CC);
}
} /* }}} */
static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
{
@ -140,6 +150,8 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
@ -157,6 +169,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
zend_hash_destroy(&PHPDBG_G(seek));
zend_hash_destroy(&PHPDBG_G(registered));
@ -514,6 +527,11 @@ const opt_struct OPTIONS[] = { /* {{{ */
{'O', 1, "opline log"},
{'r', 0, "run"},
{'E', 0, "step-through-eval"},
{'S', 1, "sapi-name"},
#ifndef _WIN32
{'l', 1, "listen"},
{'a', 1, "address-or-any"},
#endif
{'-', 0, NULL}
}; /* }}} */
@ -572,11 +590,160 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */
}
} /* }}} */
#ifndef _WIN32
int phpdbg_open_socket(const char *interface, short port) /* {{{ */
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
switch (fd) {
case -1:
return -1;
default: {
int reuse = 1;
switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) {
case -1:
close(fd);
return -2;
default: {
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_port = htons(port);
address.sin_family = AF_INET;
if ((*interface == '*')) {
address.sin_addr.s_addr = htonl(INADDR_ANY);
} else if (!inet_pton(AF_INET, interface, &address.sin_addr)) {
close(fd);
return -3;
}
switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) {
case -1:
close(fd);
return -4;
default: {
listen(fd, 5);
}
}
}
}
}
}
return fd;
} /* }}} */
static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */
{
if ((*socket)[0] >= 0) {
shutdown(
(*socket)[0], SHUT_RDWR);
close((*socket)[0]);
}
if (streams[0]) {
fclose(streams[0]);
}
if ((*socket)[1] >= 0) {
shutdown(
(*socket)[1], SHUT_RDWR);
close((*socket)[1]);
}
if (streams[1]) {
fclose(streams[1]);
}
} /* }}} */
/* don't inline this, want to debug it easily, will inline when done */
int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */
{
if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) {
((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]);
((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]);
}
streams[0] = NULL;
streams[1] = NULL;
if ((*listen)[0] < 0 || (*listen)[1] < 0) {
if ((*listen)[0] < 0) {
phpdbg_rlog(stderr,
"console failed to initialize (stdin) on %s:%d", address, port[0]);
}
if ((*listen)[1] < 0) {
phpdbg_rlog(stderr,
"console failed to initialize (stdout) on %s:%d", address, port[1]);
}
if ((*listen)[0] >= 0) {
close((*listen)[0]);
}
if ((*listen)[1] >= 0) {
close((*listen)[1]);
}
return FAILURE;
}
phpdbg_close_sockets(socket, streams);
phpdbg_rlog(stderr,
"accepting connections on %s:%d/%d", address, port[0], port[1]);
{
struct sockaddr_in address;
socklen_t size = sizeof(address);
char buffer[20] = {0};
{
memset(&address, 0, size);
(*socket)[0] = accept(
(*listen)[0], (struct sockaddr *) &address, &size);
inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
phpdbg_rlog(stderr, "connection (stdin) from %s", buffer);
}
{
memset(&address, 0, size);
(*socket)[1] = accept(
(*listen)[1], (struct sockaddr *) &address, &size);
inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
phpdbg_rlog(stderr, "connection (stdout) from %s", buffer);
}
}
dup2((*socket)[0], fileno(stdin));
dup2((*socket)[1], fileno(stdout));
setbuf(stdout, NULL);
streams[0] = fdopen((*socket)[0], "r");
streams[1] = fdopen((*socket)[1], "w");
return SUCCESS;
} /* }}} */
#endif
int main(int argc, char **argv) /* {{{ */
{
sapi_module_struct *phpdbg = &phpdbg_sapi_module;
char *sapi_name;
char *ini_entries;
int ini_entries_len;
char **zend_extensions = NULL;
zend_ulong zend_extensions_len = 0L;
zend_bool ini_ignore;
char *ini_override;
char *exec;
@ -590,14 +757,34 @@ int main(int argc, char **argv) /* {{{ */
char *php_optarg;
int php_optind, opt, show_banner = 1;
long cleaning = 0;
zend_bool remote = 0;
int run = 0;
int step = 0;
char *bp_tmp_file;
#ifndef _WIN32
char *address;
int listen[2];
int server[2];
int socket[2];
FILE* streams[2] = {NULL, NULL};
#endif
#ifdef ZTS
void ***tsrm_ls;
#endif
#ifndef _WIN32
address = strdup("127.0.0.1");
socket[0] = -1;
socket[1] = -1;
listen[0] = -1;
listen[1] = -1;
server[0] = -1;
server[1] = -1;
streams[0] = NULL;
streams[1] = NULL;
#endif
#ifdef PHP_WIN32
_fmode = _O_BINARY; /* sets default for file streams to binary */
setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
@ -623,6 +810,8 @@ phpdbg_main:
ini_entries_len = 0;
ini_ignore = 0;
ini_override = NULL;
zend_extensions = NULL;
zend_extensions_len = 0L;
exec = NULL;
exec_len = 0;
init_file = NULL;
@ -636,7 +825,9 @@ phpdbg_main:
opt = 0;
run = 0;
step = 0;
sapi_name = NULL;
while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
switch (opt) {
case 'r':
@ -680,8 +871,13 @@ phpdbg_main:
ini_entries_len += len + sizeof("=1\n\0") - 2;
}
} break;
case 'z':
zend_load_extension(php_optarg);
zend_extensions_len++;
if (zend_extensions) {
zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
} else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
break;
/* begin phpdbg options */
@ -689,9 +885,19 @@ phpdbg_main:
case 'e': { /* set execution context */
exec_len = strlen(php_optarg);
if (exec_len) {
if (exec) {
free(exec);
}
exec = strdup(php_optarg);
}
} break;
case 'S': { /* set SAPI name */
if (sapi_name) {
free(sapi_name);
}
sapi_name = strdup(php_optarg);
} break;
case 'I': { /* ignore .phpdbginit */
init_file_default = 0;
@ -730,9 +936,50 @@ phpdbg_main:
case 'q': /* hide banner */
show_banner = 0;
break;
#ifndef _WIN32
/* if you pass a listen port, we will accept input on listen port */
/* and write output to listen port * 2 */
case 'l': { /* set listen ports */
if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) {
if (sscanf(php_optarg, "%d", &listen[0]) != 1) {
/* default to hardcoded ports */
listen[0] = 4000;
listen[1] = 8000;
} else {
listen[1] = (listen[0] * 2);
}
}
} break;
case 'a': { /* set bind address */
free(address);
if (!php_optarg) {
address = strdup("*");
} else address = strdup(php_optarg);
} break;
#endif
}
}
#ifndef _WIN32
/* setup remote server if necessary */
if (!cleaning &&
(listen[0] > 0 && listen[1] > 0)) {
if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) {
remote = 0;
exit(0);
}
/* set remote flag to stop service shutting down upon quit */
remote = 1;
}
#endif
if (sapi_name) {
phpdbg->name = sapi_name;
}
phpdbg->ini_defaults = phpdbg_ini_defaults;
phpdbg->phpinfo_as_text = 1;
phpdbg->php_ini_ignore_cwd = 1;
@ -753,30 +1000,77 @@ phpdbg_main:
memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
}
ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
if (zend_extensions_len) {
zend_ulong zend_extension = 0L;
while (zend_extension < zend_extensions_len) {
const char *ze = zend_extensions[zend_extension];
size_t ze_len = strlen(ze);
ini_entries = realloc(
ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
ini_entries_len += (sizeof("zend_extension=")-1);
memcpy(&ini_entries[ini_entries_len], ze, ze_len);
ini_entries_len += ze_len;
memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
free(zend_extensions[zend_extension]);
zend_extension++;
}
free(zend_extensions);
}
phpdbg->ini_entries = ini_entries;
if (phpdbg->startup(phpdbg) == SUCCESS) {
zend_register_extension(&zend_extension_entry, NULL);
zend_activate(TSRMLS_C);
/* do not install sigint handlers for remote consoles */
/* sending SIGINT then provides a decent way of shutting down the server */
#ifdef ZEND_SIGNALS
zend_try {
zend_signal_activate(TSRMLS_C);
zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC);
} zend_end_try();
# ifndef _WIN32
if (listen[0] < 0) {
# endif
zend_try {
zend_signal_activate(TSRMLS_C);
zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC);
} zend_end_try();
# ifndef _WIN32
}
# endif
#else
signal(SIGINT, phpdbg_sigint_handler);
# ifndef _WIN32
if (listen[0] < 0) {
# endif
signal(SIGINT, phpdbg_sigint_handler);
#ifndef _WIN32
}
#endif
#endif
PG(modules_activated) = 0;
/* set flags from command line */
PHPDBG_G(flags) = flags;
#ifndef _WIN32
/* setup io here */
if (streams[0] && streams[1]) {
PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
signal(SIGPIPE, SIG_IGN);
}
#endif
/* set up basic io here */
PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
if (exec) { /* set execution context */
PHPDBG_G(exec) = phpdbg_resolve_path(
exec TSRMLS_CC);
@ -794,9 +1088,6 @@ phpdbg_main:
free(oplog_file);
}
/* set flags from command line */
PHPDBG_G(flags) = flags;
/* set default colors */
phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold") TSRMLS_CC);
phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold") TSRMLS_CC);
@ -846,6 +1137,7 @@ phpdbg_main:
}
}
phpdbg_interact:
/* phpdbg main() */
do {
zend_try {
@ -860,14 +1152,40 @@ phpdbg_main:
} else {
cleaning = 0;
}
#ifndef _WIN32
/* remote client disconnected */
if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
/* renegociate connections */
phpdbg_open_sockets(
address, listen, &server, &socket, streams);
/* set streams */
if (streams[0] && streams[1]) {
PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
}
/* this must be forced */
CG(unclean_shutdown) = 0;
}
#endif
if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
goto phpdbg_out;
}
} zend_end_try();
} while(!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
/* this must be forced */
CG(unclean_shutdown) = 0;
phpdbg_out:
#ifndef _WIN32
if (PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED) {
PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
goto phpdbg_interact;
}
#endif
if (ini_entries) {
free(ini_entries);
}
@ -901,7 +1219,7 @@ phpdbg_out:
sapi_shutdown();
}
if (cleaning) {
if (cleaning || remote) {
goto phpdbg_main;
}
@ -909,6 +1227,16 @@ phpdbg_out:
/* bugggy */
/* tsrm_shutdown(); */
#endif
#ifndef _WIN32
if (address) {
free(address);
}
#endif
if (sapi_name) {
free(sapi_name);
}
free(bp_tmp_file);

View file

@ -79,6 +79,10 @@
#define PHPDBG_FINISH 4
#define PHPDBG_LEAVE 5
/*
BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
*/
/* {{{ tables */
#define PHPDBG_BREAK_FILE 0
#define PHPDBG_BREAK_SYM 1
@ -89,7 +93,8 @@
#define PHPDBG_BREAK_FUNCTION_OPLINE 6
#define PHPDBG_BREAK_METHOD_OPLINE 7
#define PHPDBG_BREAK_FILE_OPLINE 8
#define PHPDBG_BREAK_TABLES 9 /* }}} */
#define PHPDBG_BREAK_MAP 9
#define PHPDBG_BREAK_TABLES 10 /* }}} */
/* {{{ flags */
#define PHPDBG_HAS_FILE_BP (1<<1)
@ -103,6 +108,10 @@
#define PHPDBG_HAS_FILE_OPLINE_BP (1<<9)
#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)
/*
END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
*/
#define PHPDBG_IN_COND_BP (1<<8)
#define PHPDBG_IN_EVAL (1<<9)
@ -123,6 +132,8 @@
#define PHPDBG_IS_SIGNALED (1<<21)
#define PHPDBG_IS_INTERACTIVE (1<<22)
#define PHPDBG_IS_BP_ENABLED (1<<23)
#define PHPDBG_IS_REMOTE (1<<24)
#define PHPDBG_IS_DISCONNECTED (1<<25)
#ifndef _WIN32
# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED|PHPDBG_IS_BP_ENABLED)
@ -135,7 +146,7 @@
#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
#define PHPDBG_URL "http://phpdbg.com"
#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
#define PHPDBG_VERSION "0.2.0-dev"
#define PHPDBG_VERSION "0.3.0-dev"
#define PHPDBG_INIT_FILENAME ".phpdbginit"
/* }}} */
@ -157,7 +168,6 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
zend_op_array *ops; /* op_array */
zval *retval; /* return value */
int bp_count; /* breakpoint count */
int del_bp_num; /* breakpoint to delete */
int vmret; /* return from last opcode handler execution */
FILE *oplog; /* opline log */

122
phpdbg.init.d Executable file
View file

@ -0,0 +1,122 @@
################################################################
# File: /etc/init.d/phpdbg #
# Author: krakjoe #
# Purpose: Daemonize phpdbg automatically on boot #
# chkconfig: 2345 07 09 #
# description:Starts, stops and restarts phpdbg daemon #
################################################################
LOCKFILE=/var/lock/subsys/phpdbg
PIDFILE=/var/run/phpdbg.pid
STDIN=4000
STDOUT=8000
################################################################
# Either set path to phpdbg here or rely on phpdbg in ENV/PATH #
################################################################
if [ "x${PHPDBG}" == "x" ]; then
PHPDBG=$(which phpdbg 2>/dev/null)
fi
################################################################
# Options to pass to phpdbg upon boot #
################################################################
OPTIONS=
LOGFILE=/var/log/phpdbg.log
################################################################
# STOP EDITING STOP EDITING STOP EDITING STOP EDITING #
################################################################
. /etc/rc.d/init.d/functions
RETVAL=1
################################################################
insanity()
{
if [ "x${PHPDBG}" == "x" ]; then
PHPDBG=$(which phpdbg 2>>/dev/null)
if [ $? != 0 ]; then
echo -n $"Fatal: cannot find phpdbg ${PHPDBG}"
echo_failure
echo
return 1
fi
else
if [ ! -x ${PHPDBG} ]; then
echo -n $"Fatal: cannot execute phpdbg ${PHPDBG}"
echo_failure
echo
return 1
fi
fi
return 0
}
start()
{
insanity
if [ $? -eq 1 ]; then
return $RETVAL
fi
echo -n $"Starting: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} "
nohup ${PHPDBG} -l${STDIN}/${STDOUT} ${OPTIONS} 2>>${LOGFILE} 1>/dev/null </dev/null &
PID=$!
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo $PID > $PIDFILE
echo_success
else
echo_failure
fi
echo
[ $RETVAL = 0 ] && touch ${LOCKFILE}
return $RETVAL
}
stop()
{
insanity
if [ $? -eq 1 ]; then
return $RETVAL
fi
if [ -f ${LOCKFILE} ] && [ -f ${PIDFILE} ]
then
echo -n $"Stopping: phpdbg ${OPTIONS} on ${STDIN}/${STDOUT} "
kill -s TERM $(cat $PIDFILE)
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo_success
else
echo_failure
fi
echo
[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
else
echo -n $"Error: phpdbg not running"
echo_failure
echo
[ $RETVAL = 1 ]
fi
return $RETVAL
}
##################################################################
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $PHPDBG
;;
restart)
$0 stop
$0 start
;;
*)
echo "usage: $0 start|stop|restart|status"
;;
esac
###################################################################
exit $RETVAL

File diff suppressed because it is too large Load diff

View file

@ -23,102 +23,123 @@
/* {{{ */
typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */
/* {{{ breakpoint base structure */
#define phpdbg_breakbase(name) \
int id; \
zend_uchar type; \
zend_ulong hits; \
zend_bool disabled; \
const char *name /* }}} */
/* {{{ breakpoint base */
typedef struct _phpdbg_breakbase_t {
phpdbg_breakbase(name);
} phpdbg_breakbase_t; /* }}} */
/**
* Breakpoint file-based representation
*/
typedef struct _phpdbg_breakfile_t {
const char *filename;
phpdbg_breakbase(filename);
long line;
int id;
} phpdbg_breakfile_t;
/**
* Breakpoint symbol-based representation
*/
typedef struct _phpdbg_breaksymbol_t {
const char *symbol;
int id;
phpdbg_breakbase(symbol);
} phpdbg_breaksymbol_t;
/**
* Breakpoint method based representation
*/
typedef struct _phpdbg_breakmethod_t {
const char *class_name;
phpdbg_breakbase(class_name);
size_t class_len;
const char *func_name;
size_t func_len;
int id;
} phpdbg_breakmethod_t;
/**
* Breakpoint opline num based representation
*/
typedef struct _phpdbg_breakopline_t {
phpdbg_breakbase(func_name);
size_t func_len;
const char *class_name;
size_t class_len;
const char *func_name;
size_t func_len;
int opline;
int id;
zend_ulong opline_num;
zend_ulong opline;
} phpdbg_breakopline_t;
/**
* Breakpoint opline based representation
*/
typedef struct _phpdbg_breakline_t {
const char *name;
zend_ulong opline;
zend_uchar type;
int id;
phpdbg_breakbase(name);
zend_ulong opline;
phpdbg_breakopline_t *base;
} phpdbg_breakline_t;
/**
* Breakpoint opcode based representation
*/
typedef struct _phpdbg_breakop_t {
zend_ulong hash;
const char *name;
int id;
phpdbg_breakbase(name);
zend_ulong hash;
} phpdbg_breakop_t;
/**
* Breakpoint condition based representation
*/
typedef struct _phpdbg_breakcond_t {
phpdbg_breakbase(code);
size_t code_len;
zend_bool paramed;
phpdbg_param_t param;
zend_ulong hash;
zval code;
zend_op_array *ops;
int id;
} phpdbg_breakcond_t;
/* {{{ Opline breaks API */
PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC);
PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC);
PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC);
PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC); /* }}} */
PHPDBG_API void phpdbg_set_breakpoint_file(const char*, long TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_symbol(const char*, size_t TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_method(const char*, const char* TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_opcode(const char*, size_t TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, int opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, int opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, int opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_expression(const char*, size_t TSRMLS_DC);
/* {{{ Breakpoint Creation API */
PHPDBG_API void phpdbg_set_breakpoint_file(const char* filename, long lineno TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_symbol(const char* func_name, size_t func_name_len TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char* func_name TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_opcode(const char* opname, size_t opname_len TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_expression(const char* expression, size_t expression_len TSRMLS_DC);
PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC); /* }}} */
int phpdbg_find_breakpoint_file(zend_op_array* TSRMLS_DC);
int phpdbg_find_breakpoint_symbol(zend_function* TSRMLS_DC);
int phpdbg_find_breakpoint_method(zend_op_array* TSRMLS_DC);
int phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t TSRMLS_DC);
int phpdbg_find_breakpoint_opcode(zend_uchar TSRMLS_DC);
int phpdbg_find_conditional_breakpoint(TSRMLS_D);
int phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC);
/* {{{ Breakpoint Detection API */
PHPDBG_API phpdbg_breakbase_t* phpdbg_find_breakpoint(zend_execute_data* TSRMLS_DC); /* }}} */
PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC);
PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D);
/* {{{ Misc Breakpoint API */
PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t* brake, zend_bool output TSRMLS_DC);
PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC);
PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t* brake TSRMLS_DC);
PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D);
PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D);
PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC);
PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D);
PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC);
PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC);
PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D); /* }}} */
PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC);
/* {{{ Breakbase API */
PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC);
PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC); /* }}} */
/* {{{ Breakpoint Exportation API */
PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */
#endif /* PHPDBG_BP_H */

View file

@ -48,7 +48,7 @@ PHPDBG_BREAK(method) /* {{{ */
phpdbg_default_switch_case();
}
return SUCCESS;
} /* }}} */
@ -90,6 +90,13 @@ PHPDBG_BREAK(on) /* {{{ */
return SUCCESS;
} /* }}} */
PHPDBG_BREAK(at) /* {{{ */
{
phpdbg_set_breakpoint_at(param, input TSRMLS_CC);
return SUCCESS;
} /* }}} */
PHPDBG_BREAK(lineno) /* {{{ */
{
switch (param->type) {

View file

@ -29,12 +29,13 @@
* Printer Forward Declarations
*/
PHPDBG_BREAK(file);
PHPDBG_BREAK(func);
PHPDBG_BREAK(method);
PHPDBG_BREAK(address);
PHPDBG_BREAK(at);
PHPDBG_BREAK(op);
PHPDBG_BREAK(on);
PHPDBG_BREAK(lineno);
PHPDBG_BREAK(func);
PHPDBG_BREAK(del);
/**
@ -42,12 +43,13 @@ PHPDBG_BREAK(del);
*/
static const phpdbg_command_t phpdbg_break_commands[] = {
PHPDBG_COMMAND_D_EX(file, "specify breakpoint by file:line", 'F', break_file, NULL, 1),
PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, 1),
PHPDBG_COMMAND_D_EX(method, "specify breakpoint by class::method", 'm', break_method, NULL, 1),
PHPDBG_COMMAND_D_EX(address, "specify breakpoint by address", 'a', break_address, NULL, 1),
PHPDBG_COMMAND_D_EX(op, "specify breakpoint by opcode", 'O', break_op, NULL, 1),
PHPDBG_COMMAND_D_EX(on, "specify breakpoint by expression", 'o', break_on, NULL, 1),
PHPDBG_COMMAND_D_EX(on, "specify breakpoint by condition", 'o', break_on, NULL, 1),
PHPDBG_COMMAND_D_EX(at, "specify breakpoint by location and condition", 'A', break_at, NULL, 1),
PHPDBG_COMMAND_D_EX(lineno, "specify breakpoint by line of currently executing file", 'l', break_lineno, NULL, 1),
PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, 1),
PHPDBG_COMMAND_D_EX(del, "delete breakpoint by identifier number", 'd', break_del, NULL, 1),
PHPDBG_END_COMMAND
};

View file

@ -143,6 +143,120 @@ PHPDBG_API void phpdbg_clear_param(phpdbg_param_t *param TSRMLS_DC) /* {{{ */
} /* }}} */
PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* dest TSRMLS_DC) /* {{{ */
{
switch ((dest->type = src->type)) {
case STR_PARAM:
dest->str = estrndup(src->str, src->len);
dest->len = src->len;
break;
case ADDR_PARAM:
dest->addr = src->addr;
break;
case NUMERIC_PARAM:
dest->num = src->num;
break;
case METHOD_PARAM:
dest->method.class = estrdup(src->method.class);
dest->method.name = estrdup(src->method.name);
break;
case FILE_PARAM:
dest->file.name = estrdup(src->file.name);
dest->file.line = src->file.line;
break;
case EMPTY_PARAM: { /* do nothing */ } break;
}
} /* }}} */
PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
{
zend_ulong hash = param->type;
switch (param->type) {
case STR_PARAM:
hash += zend_inline_hash_func(param->str, param->len);
break;
case METHOD_PARAM:
hash += zend_inline_hash_func(param->method.class, strlen(param->method.class));
hash += zend_inline_hash_func(param->method.name, strlen(param->method.name));
break;
case FILE_PARAM:
hash += zend_inline_hash_func(param->file.name, strlen(param->file.name));
hash += param->file.line;
break;
case ADDR_PARAM:
hash += param->addr;
break;
case NUMERIC_PARAM:
hash += param->num;
break;
case EMPTY_PARAM: { /* do nothing */ } break;
}
return hash;
} /* }}} */
PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_param_t *r TSRMLS_DC) /* {{{ */
{
if (l && r) {
if (l->type == r->type) {
switch (l->type) {
case STR_PARAM:
return (l->len == r->len) &&
(memcmp(l->str, r->str, l->len) == SUCCESS);
case NUMERIC_PARAM:
return (l->num == r->num);
case ADDR_PARAM:
return (l->addr == r->addr);
case FILE_PARAM: {
if (l->file.line == r->file.line) {
size_t lengths[2] = {
strlen(l->file.name), strlen(r->file.name)};
if (lengths[0] == lengths[1]) {
return (memcmp(
l->file.name, r->file.name, lengths[0]) == SUCCESS);
}
}
} break;
case METHOD_PARAM: {
size_t lengths[2] = {
strlen(l->method.class), strlen(r->method.class)};
if (lengths[0] == lengths[1]) {
if (memcmp(l->method.class, r->method.class, lengths[0]) == SUCCESS) {
lengths[0] = strlen(l->method.name);
lengths[1] = strlen(r->method.name);
if (lengths[0] == lengths[1]) {
return (memcmp(
l->method.name, r->method.name, lengths[0]) == SUCCESS);
}
}
}
} break;
case EMPTY_PARAM:
return 1;
}
}
}
return 0;
} /* }}} */
PHPDBG_API phpdbg_input_t **phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC) /* {{{ */
{
char *p;
@ -242,35 +356,48 @@ PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
char *cmd = NULL;
if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
if (buffered == NULL) {
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) &&
(buffered == NULL)) {
fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
}
if (buffered == NULL) {
#ifndef HAVE_LIBREADLINE
char buf[PHPDBG_MAX_CMD];
if (!phpdbg_write(phpdbg_get_prompt(TSRMLS_C)) ||
if ((!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && !phpdbg_write(phpdbg_get_prompt(TSRMLS_C))) ||
!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
/* the user has gone away */
phpdbg_error("Failed to read console !");
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
zend_bailout();
return NULL;
}
cmd = buf;
#else
cmd = readline(phpdbg_get_prompt(TSRMLS_C));
if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
char buf[PHPDBG_MAX_CMD];
if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
cmd = buf;
} else cmd = NULL;
} else cmd = readline(phpdbg_get_prompt(TSRMLS_C));
if (!cmd) {
/* the user has gone away */
phpdbg_error("Failed to read console !");
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED);
zend_bailout();
return NULL;
}
add_history(cmd);
if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
add_history(cmd);
}
#endif
} else cmd = buffered;
/* allocate and sanitize buffer */
buffer = (phpdbg_input_t*) emalloc(sizeof(phpdbg_input_t));
buffer = (phpdbg_input_t*) ecalloc(1, sizeof(phpdbg_input_t));
if (!buffer) {
return NULL;
}
@ -296,7 +423,8 @@ PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
#endif
#ifdef HAVE_LIBREADLINE
if (!buffered && cmd) {
if (!buffered && cmd &&
!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) {
free(cmd);
}
#endif
@ -307,6 +435,21 @@ PHPDBG_API phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
return NULL;
} /* }}} */
PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC) /* {{{ */
{
if (argv) {
if (argc) {
int arg;
for (arg=0; arg<argc; arg++) {
phpdbg_destroy_input(
&argv[arg] TSRMLS_CC);
}
}
efree(argv);
}
} /* }}} */
PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t **input TSRMLS_DC) /*{{{ */
{
if (*input) {
@ -314,17 +457,8 @@ PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t **input TSRMLS_DC) /*{{{ */
efree((*input)->string);
}
if ((*input)->argc > 0) {
int arg;
for (arg=0; arg<(*input)->argc; arg++) {
phpdbg_destroy_input(
&(*input)->argv[arg] TSRMLS_CC);
}
}
if ((*input)->argv) {
efree((*input)->argv);
}
phpdbg_destroy_argv(
(*input)->argv, (*input)->argc TSRMLS_CC);
efree(*input);
}
@ -398,7 +532,7 @@ PHPDBG_API int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *in
int arg;
for (arg=1; arg<input->argc; arg++) {
phpdbg_debug(
"\t#%d: [%s=%d]",
"\t#%d: [%s=%zu]",
arg,
input->argv[arg]->string,
input->argv[arg]->length);

View file

@ -114,16 +114,24 @@ typedef struct {
* Input Management
*/
PHPDBG_API phpdbg_input_t* phpdbg_read_input(char *buffered TSRMLS_DC);
PHPDBG_API phpdbg_input_t** phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC);
PHPDBG_API void phpdbg_destroy_input(phpdbg_input_t** TSRMLS_DC);
/*
* Argument Management
*/
PHPDBG_API phpdbg_input_t** phpdbg_read_argv(char *buffer, int *argc TSRMLS_DC);
PHPDBG_API void phpdbg_destroy_argv(phpdbg_input_t **argv, int argc TSRMLS_DC);
#define phpdbg_argv_is(n, s) \
(memcmp(input->argv[n]->string, s, input->argv[n]->length-1) == SUCCESS)
(memcmp(input->argv[n]->string, s, input->argv[n]->length) == SUCCESS)
/*
* Parameter Management
*/
PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char*, size_t, phpdbg_param_t* TSRMLS_DC);
PHPDBG_API void phpdbg_clear_param(phpdbg_param_t* TSRMLS_DC);
PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t*, phpdbg_param_t* TSRMLS_DC);
PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *, const phpdbg_param_t * TSRMLS_DC);
PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t * TSRMLS_DC);
PHPDBG_API const char* phpdbg_get_param_type(const phpdbg_param_t* TSRMLS_DC);
/*

View file

@ -258,6 +258,13 @@ PHPDBG_HELP(break) /* {{{ */
phpdbg_writeln("\t%sb on ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
phpdbg_writeln("\tWill break when the condition evaluates to true");
phpdbg_writeln(EMPTY);
phpdbg_writeln("\t%sbreak at phpdbg::isGreat if ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
phpdbg_writeln("\tWill break at every opcode in phpdbg::isGreat when the condition evaluates to true");
phpdbg_writeln("\t%sbreak at test.php:20 if ($expression == true)", phpdbg_get_prompt(TSRMLS_C));
phpdbg_writeln("\tWill break at every opcode on line 20 of test.php when the condition evaluates to true");
phpdbg_write("\t");
phpdbg_notice("The location can be anything accepted by file, func, method, or address break commands");
phpdbg_writeln(EMPTY);
phpdbg_writeln("\t%sbreak op ZEND_ADD", phpdbg_get_prompt(TSRMLS_C));
phpdbg_writeln("\t%sb O ZEND_ADD", phpdbg_get_prompt(TSRMLS_C));
phpdbg_writeln("\tWill break on every occurence of the opcode provided");
@ -576,7 +583,19 @@ PHPDBG_HELP(options) /* {{{ */
phpdbg_writeln(" -O\t-Omy.oplog\t\tSets oplog output file");
phpdbg_writeln(" -r\tN/A\t\t\tRun execution context");
phpdbg_writeln(" -E\tN/A\t\t\tEnable step through eval, careful !");
phpdbg_writeln(" -S\t-Scli\t\t\tOverride SAPI name, careful !");
#ifndef _WIN32
phpdbg_writeln(" -l\t-l4000\t\t\tSetup remote console ports");
phpdbg_writeln(" -a\t-a192.168.0.3\t\tSetup remote console bind address");
#endif
phpdbg_notice("Passing -rr will quit automatically after execution");
#ifndef _WIN32
phpdbg_writeln("Remote Console Mode");
phpdbg_notice("For security, phpdbg will bind only to the loopback interface by default");
phpdbg_writeln("-a without an argument implies all; phpdbg will bind to all available interfaces.");
phpdbg_writeln("specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2.");
phpdbg_notice("Steps should be taken to secure this service if bound to a public interface/port");
#endif
phpdbg_help_footer();
return SUCCESS;
} /* }}} */

View file

@ -76,6 +76,11 @@ PHPDBG_INFO(vars) /* {{{ */
char *var;
zval **data;
if (!EG(active_op_array)) {
phpdbg_error("No active op array!");
return SUCCESS;
}
if (!EG(active_symbol_table)) {
zend_rebuild_symbol_table(TSRMLS_C);
@ -223,6 +228,26 @@ PHPDBG_INFO(literal) /* {{{ */
return SUCCESS;
} /* }}} */
PHPDBG_INFO(memory) /* {{{ */
{
if (is_zend_mm(TSRMLS_C)) {
phpdbg_notice("Memory Manager Information");
phpdbg_notice("Current");
phpdbg_writeln("|-------> Used:\t%.3f kB",
(float) (zend_memory_usage(0 TSRMLS_CC)/1024));
phpdbg_writeln("|-------> Real:\t%.3f kB",
(float) (zend_memory_usage(1 TSRMLS_CC)/1024));
phpdbg_notice("Peak");
phpdbg_writeln("|-------> Used:\t%.3f kB",
(float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024));
phpdbg_writeln("|-------> Real:\t%.3f kB",
(float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024));
} else {
phpdbg_error("Memory Manager Disabled !");
}
return SUCCESS;
} /* }}} */
static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */
{
phpdbg_write(

View file

@ -31,15 +31,17 @@ PHPDBG_INFO(funcs);
PHPDBG_INFO(error);
PHPDBG_INFO(vars);
PHPDBG_INFO(literal);
PHPDBG_INFO(memory);
static const phpdbg_command_t phpdbg_info_commands[] = {
PHPDBG_COMMAND_D_EX(break, "show breakpoints", 'b', info_break, NULL, 0),
PHPDBG_COMMAND_D_EX(files, "lists included files", 'F', info_files, NULL, 0),
PHPDBG_COMMAND_D_EX(classes, "lists loaded classes", 'c', info_classes, NULL, 0),
PHPDBG_COMMAND_D_EX(funcs, "lists loaded classes", 'f', info_funcs, NULL, 0),
PHPDBG_COMMAND_D_EX(error, "show the last error", 'e', info_error, NULL, 0),
PHPDBG_COMMAND_D_EX(break, "show breakpoints", 'b', info_break, NULL, 0),
PHPDBG_COMMAND_D_EX(files, "show included files", 'F', info_files, NULL, 0),
PHPDBG_COMMAND_D_EX(classes, "show loaded classes", 'c', info_classes, NULL, 0),
PHPDBG_COMMAND_D_EX(funcs, "show loaded classes", 'f', info_funcs, NULL, 0),
PHPDBG_COMMAND_D_EX(error, "show last error", 'e', info_error, NULL, 0),
PHPDBG_COMMAND_D_EX(vars, "show active variables", 'v', info_vars, NULL, 0),
PHPDBG_COMMAND_D_EX(literal, "show active literal constants", 'l', info_literal, NULL, 0),
PHPDBG_COMMAND_D_EX(memory, "show memory manager stats", 'm', info_memory, NULL, 0),
PHPDBG_END_COMMAND
};

View file

@ -573,6 +573,9 @@ PHPDBG_COMMAND(run) /* {{{ */
zend_hash_clean(
&PHPDBG_G(seek));
/* reset hit counters */
phpdbg_reset_breakpoints(TSRMLS_C);
zend_try {
php_output_activate(TSRMLS_C);
PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
@ -766,11 +769,7 @@ PHPDBG_COMMAND(print) /* {{{ */
phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table)));
phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants)));
phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files)));
phpdbg_writeln(
"Memory\t\t%.3f/%.3f (kB)",
(float) (zend_memory_usage(1 TSRMLS_CC)/1024),
(float) (zend_memory_usage(0 TSRMLS_CC)/1024));
phpdbg_writeln(SEPARATE);
} break;
@ -957,6 +956,9 @@ PHPDBG_COMMAND(clear) /* {{{ */
phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]));
phpdbg_writeln("Methods\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]));
phpdbg_writeln("Oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]));
phpdbg_writeln("File oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]));
phpdbg_writeln("Function oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]));
phpdbg_writeln("Method oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]));
phpdbg_writeln("Conditionals\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]));
phpdbg_clear_breakpoints(TSRMLS_C);
@ -1400,9 +1402,16 @@ zend_vm_enter:
phpdbg_print_opline_ex(
execute_data, &vars, 0 TSRMLS_CC);
if (PHPDBG_G(flags) & PHPDBG_BP_MASK
&& phpdbg_find_breakpoint(execute_data TSRMLS_CC) == SUCCESS) {
DO_INTERACTIVE();
/* search for breakpoints */
{
phpdbg_breakbase_t *brake;
if ((PHPDBG_G(flags) & PHPDBG_BP_MASK) &&
(brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC))) {
phpdbg_hit_breakpoint(
brake, 1 TSRMLS_CC);
DO_INTERACTIVE();
}
}
if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) {

View file

@ -21,6 +21,7 @@
#include "phpdbg_cmd.h"
#include "phpdbg_set.h"
#include "phpdbg_utils.h"
#include "phpdbg_bp.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
@ -51,13 +52,33 @@ PHPDBG_SET(break) /* {{{ */
case STR_PARAM:
if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) {
PHPDBG_G(flags) |= PHPDBG_IS_BP_ENABLED;
phpdbg_enable_breakpoints(TSRMLS_C);
} else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) {
PHPDBG_G(flags) &= ~PHPDBG_IS_BP_ENABLED;
phpdbg_disable_breakpoints(TSRMLS_C);
}
break;
case NUMERIC_PARAM: {
if (input->argc > 2) {
if (phpdbg_argv_is(2, "on")) {
phpdbg_enable_breakpoint(param->num TSRMLS_CC);
} else if (phpdbg_argv_is(2, "off")) {
phpdbg_disable_breakpoint(param->num TSRMLS_CC);
}
} else {
phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC);
if (brake) {
phpdbg_writeln(
"%s", brake->disabled ? "off" : "on");
} else {
phpdbg_error("Failed to find breakpoint #%lx", param->num);
}
}
} break;
phpdbg_default_switch_case();
default:
phpdbg_error(
"set break used incorrectly: set break [id] <on|off>");
}
return SUCCESS;
@ -71,6 +92,7 @@ PHPDBG_SET(color) /* {{{ */
input->argv[2]->string, input->argv[2]->length TSRMLS_CC);
int element = PHPDBG_COLOR_INVALID;
/* @TODO(anyone) make this consistent with other set commands */
if (color) {
if (phpdbg_argv_is(1, "prompt")) {
phpdbg_notice(
@ -105,6 +127,34 @@ usage:
}
return SUCCESS;
} /* }}} */
PHPDBG_SET(colors) /* {{{ */
{
switch (param->type) {
case EMPTY_PARAM: {
phpdbg_writeln(
"%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off");
goto done;
}
case STR_PARAM: {
if (strncasecmp(param->str, PHPDBG_STRL("on")) == 0) {
PHPDBG_G(flags) |= PHPDBG_IS_COLOURED;
goto done;
} else if (strncasecmp(param->str, PHPDBG_STRL("off")) == 0) {
PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED;
goto done;
}
}
default:
phpdbg_error(
"set colors used incorrectly: set colors <on|off>");
}
done:
return SUCCESS;
} /* }}} */
#endif
PHPDBG_SET(oplog) /* {{{ */

View file

@ -27,6 +27,7 @@
PHPDBG_SET(prompt);
#ifndef _WIN32
PHPDBG_SET(color);
PHPDBG_SET(colors);
#endif
PHPDBG_SET(oplog);
PHPDBG_SET(break);
@ -35,9 +36,10 @@ static const phpdbg_command_t phpdbg_set_commands[] = {
PHPDBG_COMMAND_D_EX(prompt, "usage: set prompt <string>", 'p', set_prompt, NULL, 0),
#ifndef _WIN32
PHPDBG_COMMAND_D_EX(color, "usage: set color <element> <color>", 'c', set_color, NULL, 1),
PHPDBG_COMMAND_D_EX(colors, "usage: set colors <on|off>", 'C', set_colors, NULL, 1),
#endif
PHPDBG_COMMAND_D_EX(oplog, "usage: set oplog <output>", 'O', set_oplog, NULL, 0),
PHPDBG_COMMAND_D_EX(break, "usage: set break <on|off>", 'b', set_break, NULL, 0),
PHPDBG_COMMAND_D_EX(break, "usage: set break [id] <on|off>", 'b', set_break, NULL, 0),
PHPDBG_END_COMMAND
};

View file

@ -19,6 +19,7 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "zend.h"
#include "php.h"
#include "spprintf.h"
@ -100,6 +101,9 @@ PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class,
{
char *sep = NULL;
if (strstr(str, "#") != NULL)
return 0;
if (strstr(str, " ") != NULL)
return 0;
@ -242,6 +246,33 @@ PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ..
return rc;
} /* }}} */
PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */
int rc = 0;
va_list args;
struct timeval tp;
va_start(args, fmt);
if (gettimeofday(&tp, NULL) == SUCCESS) {
char friendly[100];
char *format = NULL, *buffer = NULL;
strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tp.tv_sec));
asprintf(
&buffer, friendly, tp.tv_usec/1000);
asprintf(
&format, "[%s]: %s\n", buffer, fmt);
rc = vfprintf(
fp, format, args);
free(format);
free(buffer);
}
va_end(args);
return rc;
} /* }}} */
PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */
{
const phpdbg_color_t *color = colors;
@ -299,7 +330,7 @@ PHPDBG_API void phpdbg_set_prompt(const char *prompt TSRMLS_DC) /* {{{ */
} /* }}} */
PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */
{
{
/* find cached prompt */
if (PHPDBG_G(prompt)[1]) {
return PHPDBG_G(prompt)[1];

View file

@ -32,7 +32,7 @@ PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC);
PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*);
/**
* Error/notice/formatting helper
* Error/notice/formatting helpers
*/
enum {
P_ERROR = 1,
@ -48,6 +48,8 @@ PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUT
PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
#endif
PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...);
#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)

BIN
tutorials/break-at.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Before After
Before After

BIN
tutorials/java-example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

73
tutorials/java/build.xml Normal file
View file

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="phpdbg-ui" default="default" basedir=".">
<description>Builds, tests, and runs the project phpdbg-ui.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar: JAR building
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="phpdbg-ui-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

32
tutorials/java/dist/README.TXT vendored Normal file
View file

@ -0,0 +1,32 @@
========================
BUILD OUTPUT DESCRIPTION
========================
When you build an Java application project that has a main class, the IDE
automatically copies all of the JAR
files on the projects classpath to your projects dist/lib folder. The IDE
also adds each of the JAR files to the Class-Path element in the application
JAR files manifest file (MANIFEST.MF).
To run the project from the command line, go to the dist folder and
type the following:
java -jar "phpdbg-ui.jar"
To distribute this project, zip up the dist folder (including the lib folder)
and distribute the ZIP file.
Notes:
* If two JAR files on the project classpath have the same name, only the first
JAR file is copied to the lib folder.
* Only JAR files are copied to the lib folder.
If the classpath contains other types of files or folders, these files (folders)
are not copied.
* If a library on the projects classpath also has a Class-Path element
specified in the manifest,the content of the Class-Path element has to be on
the projects runtime path.
* To set a main class in a standard Java project, right-click the project node
in the Projects window and choose Properties. Then click Run and enter the
class name in the Main Class field. Alternatively, you can manually type the
class name in the manifest Main-Class element.

BIN
tutorials/java/dist/phpdbg-ui.jar vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
build.xml.data.CRC32=ed67686a
build.xml.script.CRC32=8c03bdb5
build.xml.stylesheet.CRC32=8064a381@1.68.1.46
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=ed67686a
nbproject/build-impl.xml.script.CRC32=ea01fe36
nbproject/build-impl.xml.stylesheet.CRC32=5a01deb7@1.68.1.46

View file

@ -0,0 +1,6 @@
compile.on.save=true
do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
user.properties.file=/home/joe/.netbeans/7.4/build.properties

View file

@ -0,0 +1,76 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.title=phpdbg-ui
application.vendor=joe
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# Files in build.classes.dir which should be excluded from distribution jar
dist.archive.excludes=
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/phpdbg-ui.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
includes=**
jar.compress=false
javac.classpath=\
${libs.eclipselink.classpath}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.processorpath=\
${javac.classpath}
javac.source=1.7
javac.target=1.7
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
javac.test.processorpath=\
${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=phpdbg.ui.JConsole
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project.
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
# To set system properties for unit tests define test-sys-prop.name=value:
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>phpdbg-ui</name>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>

View file

@ -0,0 +1,49 @@
package phpdbg.ui;
import java.util.ArrayList;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Implement a simple history list for command input
* @author krakjoe
*/
public class CommandHistory extends ArrayList<String> {
private Integer position = new Integer(0);
public CommandHistory() {
super();
}
@Override public boolean add(String text) {
String last = last();
if (text != null) {
if (last == null || !last.equals(text)) {
if (super.add(text)) {
position = size();
return true;
}
}
}
return false;
}
public String last() {
if (position >= 1) {
position--;
return get(position);
} else return new String();
}
public String next() {
if (position+1 < size()) {
position++;
return get(position);
} else return new String();
}
}

View file

@ -0,0 +1,157 @@
package phpdbg.ui;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import static java.nio.channels.SelectionKey.OP_READ;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.Set;
import phpdbg.ui.JConsole.MessageType;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Manage input and output data
* @author krakjoe
*/
public class DebugSocket implements Runnable {
private final String host;
private final Integer port;
private final Boolean reader;
private final JConsole main;
private final Thread thread;
private volatile Boolean quit;
private volatile Boolean started;
public DebugSocket(final String host, final Integer port, final JConsole main, Boolean reader) throws IOException {
this.host = host;
this.port = port;
this.main = main;
this.reader = reader;
this.quit = false;
this.started = false;
this.thread = new Thread(this);
}
public void start() {
synchronized(this) {
if (!started) {
quit = false;
started = true;
thread.start();
}
}
}
public void quit() {
synchronized(this) {
quit = true;
started = false;
notifyAll();
}
}
@Override public void run() {
try {
synchronized(main) {
if (!main.isConnected()) {
main.setConnected(true);
}
}
if (reader) {
/* The reader thread will wait() until there is input */
Socket socket = new Socket(this.host, this.port);
String command;
OutputStream output = socket.getOutputStream();
do {
synchronized(this) {
wait();
if (!quit) {
command = main.getInputField().getText();
/* send command to stdin socket */
if (command != null) {
if (main.isEchoing()) {
main.getOutputField()
.appendANSI(
String.format("remote> %s\n", command));
}
output.write(
command.getBytes());
output.write("\n".getBytes());
output.flush();
}
main.getInputField().setText(null);
}
}
} while (!quit);
socket.close();
} else {
/*
* The writer thread will use non-blocking i/o consuming
* resources only when there is data to read
*/
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.connect(
new InetSocketAddress(this.host, this.port));
channel.configureBlocking(false);
channel.register(selector, OP_READ);
while (!quit) {
selector.select();
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
if (!quit) {
SocketChannel ready = (SocketChannel) (iter.next().channel());
ByteBuffer bytes = ByteBuffer.allocate(128);
if (ready != null) {
if (ready.read(bytes) != -1) {
bytes.flip();
main.getOutputField()
.appendANSI(new String(bytes.array()));
}
}
iter.remove();
}
}
}
channel.close();
}
} catch (IOException | InterruptedException ex) {
if (!quit) {
main.messageBox(ex.getMessage(), MessageType.ERROR);
}
} finally {
synchronized(main) {
if (main.isConnected()) {
main.setConnected(false);
}
}
}
}
}

View file

@ -0,0 +1,225 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<NonVisualComponents>
<Container class="javax.swing.JPopupMenu" name="stdoutPopupMenu">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
<Property name="useNullLayout" type="boolean" value="true"/>
</Layout>
<SubComponents>
<MenuItem class="javax.swing.JMenuItem" name="resetStdout">
<Properties>
<Property name="text" type="java.lang.String" value="Clear"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="resetStdoutActionPerformed"/>
</Events>
</MenuItem>
</SubComponents>
</Container>
<Menu class="java.awt.PopupMenu" name="systrayMenu">
<Properties>
<Property name="label" type="java.lang.String" value="phpdbg"/>
<Property name="name" type="java.lang.String" value=""/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="systrayMenuActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="10"/>
</AuxValues>
<SubComponents>
<MenuItem class="java.awt.MenuItem" name="systrayExitMenuItem">
<Properties>
<Property name="label" type="java.lang.String" value="Exit"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="systrayExitMenuItemActionPerformed"/>
</Events>
</MenuItem>
</SubComponents>
</Menu>
</NonVisualComponents>
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" value="phpdbg jui"/>
<Property name="iconImage" type="java.awt.Image" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="default"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="outputScrollPane" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hostnameLabel" min="-2" max="-2" attributes="0"/>
<Component id="commandLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="input" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="echoCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="host" pref="345" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="stdinCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="stdinPort" min="-2" pref="60" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="stdoutCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="stdoutPort" min="-2" pref="60" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="openButton" min="-2" pref="100" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="outputScrollPane" pref="403" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="input" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="echoCheckBox" alignment="3" max="-2" attributes="0"/>
<Component id="commandLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="stdoutPort" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="stdinCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="stdoutCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="stdinPort" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="hostnameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="host" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="openButton" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="host">
<Properties>
<Property name="text" type="java.lang.String" value="127.0.0.1"/>
<Property name="toolTipText" type="java.lang.String" value="Set the hostname, or IPv4 address of the machine running the phpdbg remote console server"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="stdoutPort">
<Properties>
<Property name="text" type="java.lang.String" value="8000"/>
<Property name="toolTipText" type="java.lang.String" value="By default, stdin * 2"/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="stdinCheckBox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="stdin:"/>
<Property name="toolTipText" type="java.lang.String" value="Set the port for stdin, or uncheck to disable stdin"/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="stdoutCheckBox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="stdout:"/>
<Property name="toolTipText" type="java.lang.String" value="Set the port for stdout, or unset to disable stdout"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="openButton">
<Properties>
<Property name="text" type="java.lang.String" value="Connect"/>
<Property name="actionCommand" type="java.lang.String" value="open"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="stdinPort">
<Properties>
<Property name="text" type="java.lang.String" value="4000"/>
<Property name="toolTipText" type="java.lang.String" value="The listen port passed to phpdbg (-l option)"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="hostnameLabel">
<Properties>
<Property name="text" type="java.lang.String" value="Hostname:"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="input">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="Enter phpdbg commands here !"/>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="inputKeyReleased"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="outputScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="phpdbg.ui.JTerminalPane" name="output">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="DialogInput" size="12" style="0"/>
</Property>
<Property name="componentPopupMenu" type="javax.swing.JPopupMenu" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="stdoutPopupMenu"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="echoCheckBox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" value="Check to echo sent commands in output"/>
<Property name="enabled" type="boolean" value="false"/>
<Property name="horizontalAlignment" type="int" value="2"/>
<Property name="label" type="java.lang.String" value="echo"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="commandLabel">
<Properties>
<Property name="text" type="java.lang.String" value="Command:"/>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Form>

View file

@ -0,0 +1,471 @@
package phpdbg.ui;
import java.awt.AWTException;
import java.awt.Frame;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import static java.awt.event.KeyEvent.VK_DOWN;
import static java.awt.event.KeyEvent.VK_ENTER;
import static java.awt.event.KeyEvent.VK_UP;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author krakjoe
*/
public class JConsole extends javax.swing.JDialog {
/**
* Creates user interface
* @param parent
* @param modal
*/
public JConsole(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
stdoutPopupMenu = new javax.swing.JPopupMenu();
resetStdout = new javax.swing.JMenuItem();
systrayMenu = new java.awt.PopupMenu();
systrayExitMenuItem = new java.awt.MenuItem();
host = new javax.swing.JTextField();
stdoutPort = new javax.swing.JTextField();
stdinCheckBox = new javax.swing.JCheckBox();
stdoutCheckBox = new javax.swing.JCheckBox();
openButton = new javax.swing.JButton();
stdinPort = new javax.swing.JTextField();
hostnameLabel = new javax.swing.JLabel();
input = new javax.swing.JTextField();
outputScrollPane = new javax.swing.JScrollPane();
output = new phpdbg.ui.JTerminalPane();
echoCheckBox = new javax.swing.JCheckBox();
commandLabel = new javax.swing.JLabel();
resetStdout.setText("Clear");
resetStdout.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
resetStdoutActionPerformed(evt);
}
});
stdoutPopupMenu.add(resetStdout);
systrayMenu.setLabel("phpdbg");
systrayMenu.setName("");
systrayMenu.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
systrayMenuActionPerformed(evt);
}
});
systrayExitMenuItem.setLabel("Exit");
systrayExitMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
systrayExitMenuItemActionPerformed(evt);
}
});
systrayMenu.add(systrayExitMenuItem);
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("phpdbg jui");
host.setText("127.0.0.1");
host.setToolTipText("Set the hostname, or IPv4 address of the machine running the phpdbg remote console server");
stdoutPort.setText("8000");
stdoutPort.setToolTipText("By default, stdin * 2");
stdinCheckBox.setSelected(true);
stdinCheckBox.setText("stdin:");
stdinCheckBox.setToolTipText("Set the port for stdin, or uncheck to disable stdin");
stdoutCheckBox.setSelected(true);
stdoutCheckBox.setText("stdout:");
stdoutCheckBox.setToolTipText("Set the port for stdout, or unset to disable stdout");
openButton.setText("Connect");
openButton.setActionCommand("open");
openButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
openButtonActionPerformed(evt);
}
});
stdinPort.setText("4000");
stdinPort.setToolTipText("The listen port passed to phpdbg (-l option)");
hostnameLabel.setText("Hostname:");
input.setToolTipText("Enter phpdbg commands here !");
input.setEnabled(false);
input.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
inputKeyReleased(evt);
}
});
output.setFont(new java.awt.Font("DialogInput", 0, 12)); // NOI18N
output.setComponentPopupMenu(stdoutPopupMenu);
outputScrollPane.setViewportView(output);
echoCheckBox.setSelected(true);
echoCheckBox.setToolTipText("Check to echo sent commands in output");
echoCheckBox.setEnabled(false);
echoCheckBox.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
echoCheckBox.setLabel("echo");
commandLabel.setText("Command:");
commandLabel.setEnabled(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(outputScrollPane)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hostnameLabel)
.addComponent(commandLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(input)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(echoCheckBox))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(host, javax.swing.GroupLayout.DEFAULT_SIZE, 345, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(stdinCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(stdinPort, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(stdoutCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(stdoutPort, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(openButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(outputScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 403, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(input, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(echoCheckBox)
.addComponent(commandLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(stdoutPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(stdinCheckBox)
.addComponent(stdoutCheckBox)
.addComponent(stdinPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(hostnameLabel)
.addComponent(host, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(openButton))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void inputKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_inputKeyReleased
switch (evt.getKeyCode()) {
case VK_ENTER: {
if (in != null) {
history.add(input.getText());
synchronized(in) {
in.notifyAll();
}
}
} break;
case VK_UP: {
String last = history.last();
if (last.length() > 0) {
input.setText(last);
}
} break;
case VK_DOWN: {
String next = history.next();
if (next.length() > 0) {
input.setText(next);
}
} break;
}
}//GEN-LAST:event_inputKeyReleased
private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed
try {
if (!connected) {
connect();
} else {
disconnect();
}
} catch (IOException ex) {
messageBox(ex.getMessage(), MessageType.ERROR);
}
}//GEN-LAST:event_openButtonActionPerformed
private void resetStdoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetStdoutActionPerformed
// TODO add your handling code here:
output.setText(null);
}//GEN-LAST:event_resetStdoutActionPerformed
private void systrayExitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_systrayExitMenuItemActionPerformed
// TODO add your handling code here:
dialog.disconnect();
System.exit(0);
}//GEN-LAST:event_systrayExitMenuItemActionPerformed
private void systrayMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_systrayMenuActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_systrayMenuActionPerformed
private void disconnect() {
if (in != null) {
in.quit();
}
if (out != null) {
out.quit();
}
}
private void connect() throws IOException {
Integer ports[] = new Integer[2];
String address = getHost();
if (address != null) {
ports[0] = stdinCheckBox.isSelected() ? getStdinPort() : -1;
ports[1] = stdoutCheckBox.isSelected() ? getStdoutPort() : -1;
if (ports[0] != 0 && ports[1] != 0) {
if (stdinCheckBox.isSelected()) {
if (ports[0] > 0) {
in = new DebugSocket(
address, ports[0], this, true);
in.start();
}
}
if (stdoutCheckBox.isSelected()) {
if (ports[1] > 0) {
out = new DebugSocket(
address, ports[1], this, false);
out.start();
}
}
}
}
}
public Boolean isConnected() {
return connected;
}
public Boolean isEchoing() {
return echoCheckBox.isSelected();
}
public void setConnected(Boolean isConnected) {
synchronized(this) {
if (isConnected) {
connected = true;
openButton.setText("Disconnect");
host.setEnabled(false);
stdinPort.setEnabled(false);
stdinCheckBox.setEnabled(false);
if (stdinCheckBox.isSelected()) {
input.setEnabled(true);
commandLabel.setEnabled(true);
echoCheckBox.setEnabled(true);
} else {
input.setEnabled(false);
commandLabel.setEnabled(false);
echoCheckBox.setEnabled(false);
}
stdoutPort.setEnabled(false);
stdoutCheckBox.setEnabled(false);
hostnameLabel.setEnabled(false);
commandLabel.setEnabled(true);
} else {
connected = false;
openButton.setText("Connect");
host.setEnabled(true);
stdinPort.setEnabled(true);
input.setEnabled(false);
commandLabel.setEnabled(false);
echoCheckBox.setEnabled(false);
stdinCheckBox.setEnabled(true);
stdoutPort.setEnabled(true);
stdoutCheckBox.setEnabled(true);
hostnameLabel.setEnabled(true);
}
}
}
public JTextField getInputField() { return input; }
public JTerminalPane getOutputField() { return output; }
public String getHost() {
String address = host.getText();
if (address != null && address.length() > 0) {
return address;
} else {
messageBox("Invalid hostname provided !", MessageType.WARN);
}
return null;
}
public Integer getStdinPort() {
try {
return Integer.parseInt(stdinPort.getText());
} catch (NumberFormatException ex) {
messageBox("Invalid stdin port provided !", MessageType.WARN);
}
return 0;
}
public Integer getStdoutPort() {
try {
return Integer.parseInt(stdoutPort.getText());
} catch (NumberFormatException ex) {
messageBox("Invalid stdout port provided !", MessageType.WARN);
}
return 0;
}
public JScrollPane getOutputScrollPane() {
return outputScrollPane;
}
public synchronized void messageBox(String message) {
messageBox(message, MessageType.INFO);
}
public synchronized void messageBox(String message, MessageType type) {
JOptionPane.showMessageDialog(this, message, "phpdbg jui", type.getType());
}
/**
* @param args the command line arguments
*/
public static void main(final String args[]) {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if (info.getName().equals("Nimbus")) {
try {
UIManager.setLookAndFeel(
info.getClassName());
break;
} catch (ClassNotFoundException |
InstantiationException |
IllegalAccessException |
UnsupportedLookAndFeelException ex) {
Logger.getLogger(JConsole.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/* Create and display the dialog */
java.awt.EventQueue.invokeLater(new Runnable() {
@Override public void run() {
dialog = new JConsole(new javax.swing.JFrame(), true);
dialog.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
dialog.disconnect();
System.exit(0);
}
});
try {
if (tray == null) {
Image trayIconImage = ImageIO.read(
JConsole.class.getResource("logo-dbg.png"));
dialog.setIconImage(trayIconImage);
tray = new TrayIcon(trayIconImage);
tray.setPopupMenu(systrayMenu);
tray.setToolTip("phpdbg - The Interactive PHP Debugger");
SystemTray.getSystemTray().add(tray);
}
} catch ( AWTException | IOException ex) {
dialog.messageBox(ex.getMessage(), MessageType.ERROR);
}
dialog.setVisible(true);
}
});
}
private static DebugSocket in;
private static DebugSocket out;
private static JConsole dialog;
private static Boolean connected = false;
private static CommandHistory history = new CommandHistory();
private static TrayIcon tray;
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel commandLabel;
private javax.swing.JCheckBox echoCheckBox;
private javax.swing.JTextField host;
private javax.swing.JLabel hostnameLabel;
private javax.swing.JTextField input;
private javax.swing.JButton openButton;
private phpdbg.ui.JTerminalPane output;
private javax.swing.JScrollPane outputScrollPane;
private javax.swing.JMenuItem resetStdout;
private javax.swing.JCheckBox stdinCheckBox;
private javax.swing.JTextField stdinPort;
private javax.swing.JCheckBox stdoutCheckBox;
private javax.swing.JPopupMenu stdoutPopupMenu;
private javax.swing.JTextField stdoutPort;
private java.awt.MenuItem systrayExitMenuItem;
private static java.awt.PopupMenu systrayMenu;
// End of variables declaration//GEN-END:variables
public enum MessageType {
INFO (JOptionPane.INFORMATION_MESSAGE),
WARN (JOptionPane.WARNING_MESSAGE),
ERROR (JOptionPane.ERROR_MESSAGE);
private final Integer type;
private MessageType(Integer type) {
this.type = type;
}
public Integer getType() { return this.type; }
public Boolean equals(Integer other) { return this.type.equals(other); }
public Boolean equals(MessageType other) { return this.type.equals(other.getType()); }
}
}

View file

@ -0,0 +1,182 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package phpdbg.ui;
/**
*
* @author krakjoe
*/
import javax.swing.*;
import javax.swing.text.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
public class JTerminalPane extends JTextPane {
private static class JTerminalColor {
private final Color color;
private final Boolean bold;
private final Boolean underline;
public JTerminalColor(Float h, Float s, Float b, Boolean bold, Boolean underline) {
this.color = Color.getHSBColor(h, s, b);
this.bold = bold;
this.underline = underline;
}
public JTerminalColor(Float h, Float s, Float b, Boolean bold) {
this(h, s, b, bold, false);
}
public JTerminalColor(Float h, Float s, Float b) {
this(h, s, b, false, false);
}
public Boolean isUnderlined() { return this.underline; }
public Boolean isBold() { return this.bold; }
public Color getColor() { return this.color; }
}
private static class JTerminalColors extends HashMap<String, JTerminalColor> {
public JTerminalColors() {
put("\u001B[0;30m", new JTerminalColor(0.000f, 0.000f, 0.502f));
put("\u001B[0;31m", new JTerminalColor(0.000f, 1.000f, 1.000f));
put("\u001B[0;32m", new JTerminalColor(0.333f, 1.000f, 1.000f));
put("\u001B[0;33m", new JTerminalColor(0.167f, 1.000f, 1.000f));
put("\u001B[0;34m", new JTerminalColor(0.667f, 1.000f, 1.000f));
put("\u001B[0;35m", new JTerminalColor(0.833f, 1.000f, 1.000f));
put("\u001B[0;36m", new JTerminalColor(0.500f, 1.000f, 1.000f));
put("\u001B[0;37m", new JTerminalColor(0.000f, 0.000f, 1.000f));
put("\u001B[0;64m", new JTerminalColor(0.000f, 0.000f, 1.000f));
put("\u001B[1;30m", new JTerminalColor(0.000f, 0.000f, 0.502f, true));
put("\u001B[1;31m", new JTerminalColor(0.000f, 1.000f, 1.000f, true));
put("\u001B[1;32m", new JTerminalColor(0.333f, 1.000f, 1.000f, true));
put("\u001B[1;33m", new JTerminalColor(0.167f, 1.000f, 1.000f, true));
put("\u001B[1;34m", new JTerminalColor(0.667f, 1.000f, 1.000f, true));
put("\u001B[1;35m", new JTerminalColor(0.833f, 1.000f, 1.000f, true));
put("\u001B[1;36m", new JTerminalColor(0.500f, 1.000f, 1.000f, true));
put("\u001B[1;37m", new JTerminalColor(0.000f, 0.000f, 1.000f, true));
put("\u001B[1;64m", new JTerminalColor(0.000f, 0.000f, 1.000f, true));
put("\u001B[4;30m", new JTerminalColor(0.000f, 0.000f, 0.502f, false, true));
put("\u001B[4;31m", new JTerminalColor(0.000f, 1.000f, 1.000f, false, true));
put("\u001B[4;32m", new JTerminalColor(0.333f, 1.000f, 1.000f, false, true));
put("\u001B[4;33m", new JTerminalColor(0.167f, 1.000f, 1.000f, false, true));
put("\u001B[4;34m", new JTerminalColor(0.667f, 1.000f, 1.000f, false, true));
put("\u001B[4;35m", new JTerminalColor(0.833f, 1.000f, 1.000f, false, true));
put("\u001B[4;36m", new JTerminalColor(0.500f, 1.000f, 1.000f, false, true));
put("\u001B[4;37m", new JTerminalColor(0.000f, 0.000f, 1.000f, false, true));
put("\u001B[4;64m", new JTerminalColor(0.000f, 0.000f, 1.000f, false, true));
put("reset", new JTerminalColor(0.000f, 0.000f, 1.000f));
}
public JTerminalColor find(String ANSIColor) {
if (containsKey(ANSIColor)) {
return get(ANSIColor);
} else return get("reset");
}
}
public JTerminalPane() {
super();
setOpaque(false);
setBackground(new Color(0, 0, 0, 0));
colorCurrent = colors.find("reset");
}
@Override public void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
try {
Image image = ImageIO.read(
JTerminalPane.class.getResource("logo-small.png"));
g.drawImage(
image,
getWidth() - image.getWidth(this) - 10,
getHeight() - image.getHeight(this) - 10,
image.getWidth(this), image.getHeight(this), this);
} catch (IOException | NullPointerException | IllegalArgumentException ex) {}
super.paintComponent(g);
}
private void append(JTerminalColor c, String s) {
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(
SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c.getColor());
aset = sc.addAttribute(aset, StyleConstants.Underline, c.isUnderlined());
aset = sc.addAttribute(aset, StyleConstants.Bold, c.isBold());
setCharacterAttributes(aset, false);
replaceSelection(s);
setCaretPosition(getDocument().getLength());
}
public synchronized void appendANSI(String s) {
int aPos = 0;
int aIndex;
int mIndex;
String tmpString;
boolean stillSearching;
String addString = remaining + s;
remaining = "";
if (addString.length() > 0) {
aIndex = addString.indexOf("\u001B");
if (aIndex == -1) {
append(colorCurrent,addString);
return;
}
if (aIndex > 0) {
tmpString = addString.substring(0,aIndex);
append(colorCurrent, tmpString);
aPos = aIndex;
}
stillSearching = true;
while (stillSearching) {
mIndex = addString.indexOf("m",aPos);
if (mIndex < 0) {
remaining = addString.substring(aPos,addString.length());
stillSearching = false;
continue;
}
else {
tmpString = addString.substring(aPos,mIndex+1);
colorCurrent = colors.find(tmpString);
}
aPos = mIndex + 1;
aIndex = addString.indexOf("\u001B", aPos);
if (aIndex == -1) {
tmpString = addString.substring(aPos,addString.length());
append(colorCurrent, tmpString);
stillSearching = false;
continue;
}
tmpString = addString.substring(aPos,aIndex);
aPos = aIndex;
append(colorCurrent, tmpString);
}
}
}
private static JTerminalColors colors = new JTerminalColors();
private JTerminalColor colorCurrent;
private String remaining = "";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Before After
Before After

66
tutorials/remote.md Normal file
View file

@ -0,0 +1,66 @@
Remote Debugging
================
*Using phpdbg across the network*
It is sometimes useful to execute some code in the environment that exhibits some bugs; while there is a pretty good chance of being able to mock the environment that exhibited the bug on another machine, it is sometimes impossible or impractical.
Remote debugging allows you to start an instance of phpdbg on any machine, and connect to it from any machine, bundled is a remote client implemented in Java:
![phpdbg jui](https://raw.github.com/krakjoe/phpdbg/master/tutorials/java-example.png)
Starting phpdbg in Remote Console Mode
======================================
*Starting the server ...*
Simply open a terminal on the target machine and issue the command
```
./phpdbg -l4000
```
This will initialize phpdbg in Remote Console Mode, using port 4000 for stdin and port 8000 for stdout.
To stop the service, send *SIGINT* to the phpdbg process, this will force it to bailout, as gracefully as it ever does.
Specific Ports
--------------
To listen on specific ports, the -l flag will accept a pair of ports in the following way:
```
./phpdbg -l4000/8000
```
Specific Interfaces
-------------------
To bind to a specific interface, or all interfaces use the -a flag:
```
./phpdbg -l4000 -a192.168.0.3
```
Will bind the Remote Console to the interface with the specified address, while:
```
./phpdbg -l4000 -a
```
Will bind the Remote Console to all available addresses.
Starting phpdbg-jui Anywhere
============================
*Java is everywhere, so is phpdbg ...*
A JRE is needed for the bundled remote client, given any operating system with a working installation of Java:
```
java -jar /path/to/phpdbg-ui.jar
```
Will initialize the bundled client, simply configure the settings accordingly and press *Connect*
If disconnection is normal, the environment persists - another team member can pick up the session where it is left off.
Debugging remotely is no different to debugging locally, all of the same functionality is provided remotely.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 338 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Before After
Before After