mirror of
https://github.com/php/php-src.git
synced 2025-08-19 17:04:47 +02:00
Merge branch 'master' of https://github.com/krakjoe/phpdbg into frames
Conflicts: phpdbg.h phpdbg_prompt.c
This commit is contained in:
commit
c46a413697
15 changed files with 511 additions and 145 deletions
12
.phpdbginit
12
.phpdbginit
|
@ -31,6 +31,18 @@ function my_debugging_function()
|
||||||
/* phpdbg_break(PHPDBG_METHOD, "phpdbg::method"); */
|
/* phpdbg_break(PHPDBG_METHOD, "phpdbg::method"); */
|
||||||
/* phpdbg_break(PHPDBG_FUNC, "my_global_function"); */
|
/* phpdbg_break(PHPDBG_FUNC, "my_global_function"); */
|
||||||
/* phpdbg_break(PHPDBG_FILE, "/path/to/file.php:10"); */
|
/* phpdbg_break(PHPDBG_FILE, "/path/to/file.php:10"); */
|
||||||
|
|
||||||
|
/*
|
||||||
|
If readline is loaded, you might want to setup completion:
|
||||||
|
*/
|
||||||
|
if (function_exists('readline_completion_function')) {
|
||||||
|
readline_completion_function(function(){
|
||||||
|
return array_merge(
|
||||||
|
get_defined_functions()['user'],
|
||||||
|
array_keys(get_defined_constants())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
:>
|
:>
|
||||||
##########################################################
|
##########################################################
|
||||||
# Now carry on initializing phpdbg ...
|
# Now carry on initializing phpdbg ...
|
||||||
|
|
|
@ -8,7 +8,7 @@ install-phpdbg: $(BUILD_BINARY)
|
||||||
@$(mkinstalldirs) $(INSTALL_ROOT)$(bindir)
|
@$(mkinstalldirs) $(INSTALL_ROOT)$(bindir)
|
||||||
@$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log
|
@$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log
|
||||||
@$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run
|
@$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run
|
||||||
@$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(sbindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT)
|
@$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT)
|
||||||
|
|
||||||
clean-phpdbg:
|
clean-phpdbg:
|
||||||
@echo "Cleaning phpdbg object files ..."
|
@echo "Cleaning phpdbg object files ..."
|
||||||
|
|
29
phpdbg.c
29
phpdbg.c
|
@ -44,6 +44,9 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
|
||||||
pg->lcmd = NULL;
|
pg->lcmd = NULL;
|
||||||
pg->flags = PHPDBG_DEFAULT_FLAGS;
|
pg->flags = PHPDBG_DEFAULT_FLAGS;
|
||||||
pg->oplog = NULL;
|
pg->oplog = NULL;
|
||||||
|
pg->io[PHPDBG_STDIN] = NULL;
|
||||||
|
pg->io[PHPDBG_STDOUT] = NULL;
|
||||||
|
pg->io[PHPDBG_STDERR] = NULL;
|
||||||
memset(&pg->lparam, 0, sizeof(phpdbg_param_t));
|
memset(&pg->lparam, 0, sizeof(phpdbg_param_t));
|
||||||
pg->frame.num = 0;
|
pg->frame.num = 0;
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
@ -340,7 +343,9 @@ static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int len
|
||||||
|
|
||||||
static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
|
static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
|
||||||
{
|
{
|
||||||
fflush(stdout);
|
TSRMLS_FETCH();
|
||||||
|
|
||||||
|
fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
|
||||||
/* {{{ sapi_module_struct phpdbg_sapi_module
|
/* {{{ sapi_module_struct phpdbg_sapi_module
|
||||||
|
@ -435,6 +440,23 @@ static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */
|
||||||
}
|
}
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
|
||||||
|
static inline void phpdbg_sigint_handler(int signo) /* {{{ */
|
||||||
|
{
|
||||||
|
TSRMLS_FETCH();
|
||||||
|
|
||||||
|
if (EG(in_execution)) {
|
||||||
|
/* we don't want to set signalled while phpdbg is interactive */
|
||||||
|
if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
|
||||||
|
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* if we are not executing then just provide advice */
|
||||||
|
phpdbg_writeln(EMPTY);
|
||||||
|
phpdbg_error(
|
||||||
|
"Please leave phpdbg gracefully !");
|
||||||
|
}
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
int main(int argc, char **argv) /* {{{ */
|
int main(int argc, char **argv) /* {{{ */
|
||||||
{
|
{
|
||||||
sapi_module_struct *phpdbg = &phpdbg_sapi_module;
|
sapi_module_struct *phpdbg = &phpdbg_sapi_module;
|
||||||
|
@ -620,6 +642,11 @@ phpdbg_main:
|
||||||
|
|
||||||
PG(modules_activated) = 0;
|
PG(modules_activated) = 0;
|
||||||
|
|
||||||
|
/* 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 */
|
if (exec) { /* set execution context */
|
||||||
PHPDBG_G(exec) = phpdbg_resolve_path(
|
PHPDBG_G(exec) = phpdbg_resolve_path(
|
||||||
exec TSRMLS_CC);
|
exec TSRMLS_CC);
|
||||||
|
|
7
phpdbg.h
7
phpdbg.h
|
@ -101,6 +101,7 @@
|
||||||
#define PHPDBG_IS_STEPONEVAL (1<<17)
|
#define PHPDBG_IS_STEPONEVAL (1<<17)
|
||||||
#define PHPDBG_IS_INITIALIZING (1<<18)
|
#define PHPDBG_IS_INITIALIZING (1<<18)
|
||||||
#define PHPDBG_IS_SIGNALED (1<<19)
|
#define PHPDBG_IS_SIGNALED (1<<19)
|
||||||
|
#define PHPDBG_IS_INTERACTIVE (1<<20)
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED)
|
# define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_COLOURED)
|
||||||
|
@ -112,6 +113,11 @@
|
||||||
#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
|
#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
|
||||||
#define PHPDBG_VERSION "0.0.2-dev" /* }}} */
|
#define PHPDBG_VERSION "0.0.2-dev" /* }}} */
|
||||||
|
|
||||||
|
/* {{{ output descriptors */
|
||||||
|
#define PHPDBG_STDIN 0
|
||||||
|
#define PHPDBG_STDOUT 1
|
||||||
|
#define PHPDBG_STDERR 2 /* }}} */
|
||||||
|
|
||||||
/* {{{ structs */
|
/* {{{ structs */
|
||||||
ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
||||||
HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */
|
HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */
|
||||||
|
@ -128,6 +134,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
|
||||||
zend_ulong flags; /* phpdbg flags */
|
zend_ulong flags; /* phpdbg flags */
|
||||||
HashTable registered; /* registered */
|
HashTable registered; /* registered */
|
||||||
phpdbg_frame frame; /* frame */
|
phpdbg_frame frame; /* frame */
|
||||||
|
FILE *io[3]; /* stdin/stdout/stderr */
|
||||||
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
|
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
|
||||||
|
|
||||||
#endif /* PHPDBG_H */
|
#endif /* PHPDBG_H */
|
||||||
|
|
|
@ -218,7 +218,7 @@ phpdbg_input_t *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */
|
||||||
#ifndef HAVE_LIBREADLINE
|
#ifndef HAVE_LIBREADLINE
|
||||||
char buf[PHPDBG_MAX_CMD];
|
char buf[PHPDBG_MAX_CMD];
|
||||||
if (!phpdbg_write(PROMPT) ||
|
if (!phpdbg_write(PROMPT) ||
|
||||||
!fgets(buf, PHPDBG_MAX_CMD, stdin)) {
|
!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) {
|
||||||
/* the user has gone away */
|
/* the user has gone away */
|
||||||
phpdbg_error("Failed to read console !");
|
phpdbg_error("Failed to read console !");
|
||||||
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
|
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
|
||||||
|
@ -377,10 +377,12 @@ int phpdbg_do_cmd(const phpdbg_command_t *command, phpdbg_input_t *input TSRMLS_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(PHPDBG_G(flags) & PHPDBG_IS_INITIALIZING)) {
|
||||||
PHPDBG_G(lcmd) = (phpdbg_command_t*) command;
|
PHPDBG_G(lcmd) = (phpdbg_command_t*) command;
|
||||||
phpdbg_clear_param(
|
phpdbg_clear_param(
|
||||||
&PHPDBG_G(lparam) TSRMLS_CC);
|
&PHPDBG_G(lparam) TSRMLS_CC);
|
||||||
PHPDBG_G(lparam) = param;
|
PHPDBG_G(lparam) = param;
|
||||||
|
}
|
||||||
|
|
||||||
rc = command->handler(¶m, input TSRMLS_CC);
|
rc = command->handler(¶m, input TSRMLS_CC);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -18,9 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "php.h"
|
#include "php.h"
|
||||||
|
#include "phpdbg.h"
|
||||||
#include "phpdbg_utils.h"
|
#include "phpdbg_utils.h"
|
||||||
#include "phpdbg_info.h"
|
#include "phpdbg_info.h"
|
||||||
|
|
||||||
|
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||||
|
|
||||||
PHPDBG_INFO(files) /* {{{ */
|
PHPDBG_INFO(files) /* {{{ */
|
||||||
{
|
{
|
||||||
HashPosition pos;
|
HashPosition pos;
|
||||||
|
@ -144,6 +147,45 @@ PHPDBG_INFO(vars) /* {{{ */
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
|
||||||
|
PHPDBG_INFO(literal) /* {{{ */
|
||||||
|
{
|
||||||
|
if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) {
|
||||||
|
zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops);
|
||||||
|
zend_uint literal =0, count = ops->last_literal-1;
|
||||||
|
|
||||||
|
if (ops->function_name) {
|
||||||
|
if (ops->scope) {
|
||||||
|
phpdbg_notice(
|
||||||
|
"Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count);
|
||||||
|
} else {
|
||||||
|
phpdbg_notice(
|
||||||
|
"Literal Constants in %s() (%d)", ops->function_name, count);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ops->filename) {
|
||||||
|
phpdbg_notice(
|
||||||
|
"Literal Constants in %s (%d)", ops->filename, count);
|
||||||
|
} else {
|
||||||
|
phpdbg_notice(
|
||||||
|
"Literal Constants @ %p (%d)", ops, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (literal < ops->last_literal) {
|
||||||
|
phpdbg_write("|-------- C%lu -------> [", literal);
|
||||||
|
zend_print_zval(
|
||||||
|
&ops->literals[literal].constant, 0);
|
||||||
|
phpdbg_write("]");
|
||||||
|
phpdbg_writeln(EMPTY);
|
||||||
|
literal++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
phpdbg_error("Not executing !");
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */
|
static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
phpdbg_write(
|
phpdbg_write(
|
||||||
|
|
|
@ -29,6 +29,7 @@ PHPDBG_INFO(classes);
|
||||||
PHPDBG_INFO(funcs);
|
PHPDBG_INFO(funcs);
|
||||||
PHPDBG_INFO(error);
|
PHPDBG_INFO(error);
|
||||||
PHPDBG_INFO(vars);
|
PHPDBG_INFO(vars);
|
||||||
|
PHPDBG_INFO(literal);
|
||||||
|
|
||||||
static const phpdbg_command_t phpdbg_info_commands[] = {
|
static const phpdbg_command_t phpdbg_info_commands[] = {
|
||||||
PHPDBG_COMMAND_D_EX(files, "lists included files", 'F', info_files, NULL, 0),
|
PHPDBG_COMMAND_D_EX(files, "lists included files", 'F', info_files, NULL, 0),
|
||||||
|
@ -36,6 +37,7 @@ static const phpdbg_command_t phpdbg_info_commands[] = {
|
||||||
PHPDBG_COMMAND_D_EX(funcs, "lists loaded classes", 'f', info_funcs, 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(error, "show the last error", 'e', info_error, NULL, 0),
|
||||||
PHPDBG_COMMAND_D_EX(vars, "show active variables", 'v', info_vars, 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_END_COMMAND
|
PHPDBG_END_COMMAND
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
159
phpdbg_opcode.c
159
phpdbg_opcode.c
|
@ -17,9 +17,168 @@
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "phpdbg.h"
|
||||||
#include "zend_vm_opcodes.h"
|
#include "zend_vm_opcodes.h"
|
||||||
#include "zend_compile.h"
|
#include "zend_compile.h"
|
||||||
#include "phpdbg_opcode.h"
|
#include "phpdbg_opcode.h"
|
||||||
|
#include "phpdbg_utils.h"
|
||||||
|
|
||||||
|
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
|
||||||
|
|
||||||
|
static inline zend_uint phpdbg_decode_literal(zend_op_array *ops, zend_literal *literal TSRMLS_DC) /* {{{ */
|
||||||
|
{
|
||||||
|
zend_uint iter = 0;
|
||||||
|
|
||||||
|
while (iter < ops->last_literal) {
|
||||||
|
if (literal == &ops->literals[iter]) {
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
|
static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint type, HashTable *vars TSRMLS_DC) /* {{{ */
|
||||||
|
{
|
||||||
|
char *decode = NULL;
|
||||||
|
|
||||||
|
switch (type &~ EXT_TYPE_UNUSED) {
|
||||||
|
case IS_CV:
|
||||||
|
asprintf(&decode, "$%s", ops->vars[op->var].name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IS_VAR:
|
||||||
|
case IS_TMP_VAR: {
|
||||||
|
zend_ulong id = 0, *pid = NULL;
|
||||||
|
if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) {
|
||||||
|
id = zend_hash_num_elements(vars);
|
||||||
|
zend_hash_index_update(
|
||||||
|
vars, (zend_ulong) ops->vars - op->var,
|
||||||
|
(void**) &id,
|
||||||
|
sizeof(zend_ulong), NULL);
|
||||||
|
} else id = *pid;
|
||||||
|
asprintf(&decode, "@%lu", id);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case IS_CONST:
|
||||||
|
asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->literal TSRMLS_CC));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IS_UNUSED:
|
||||||
|
asprintf(&decode, "<unused>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return decode;
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
|
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC) /*{{{ */
|
||||||
|
{
|
||||||
|
char *decode[4] = {NULL, NULL, NULL, NULL};
|
||||||
|
|
||||||
|
switch (op->opcode) {
|
||||||
|
case ZEND_JMP:
|
||||||
|
#ifdef ZEND_GOTO
|
||||||
|
case ZEND_GOTO:
|
||||||
|
#endif
|
||||||
|
#ifdef ZEND_FAST_CALL
|
||||||
|
case ZEND_FAST_CALL:
|
||||||
|
#endif
|
||||||
|
asprintf(&decode[1], "#%lu", op->op1.jmp_addr - ops->opcodes);
|
||||||
|
goto format;
|
||||||
|
|
||||||
|
case ZEND_JMPZNZ:
|
||||||
|
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||||
|
asprintf(
|
||||||
|
&decode[2], "#%u or #%lu", op->op2.opline_num, op->extended_value);
|
||||||
|
goto result;
|
||||||
|
|
||||||
|
case ZEND_JMPZ:
|
||||||
|
case ZEND_JMPNZ:
|
||||||
|
case ZEND_JMPZ_EX:
|
||||||
|
case ZEND_JMPNZ_EX:
|
||||||
|
|
||||||
|
#ifdef ZEND_JMP_SET
|
||||||
|
case ZEND_JMP_SET:
|
||||||
|
#endif
|
||||||
|
#ifdef ZEND_JMP_SET_VAR
|
||||||
|
case ZEND_JMP_SET_VAR:
|
||||||
|
#endif
|
||||||
|
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||||
|
asprintf(
|
||||||
|
&decode[2], "#%lu", op->op2.jmp_addr - ops->opcodes);
|
||||||
|
goto result;
|
||||||
|
|
||||||
|
case ZEND_RECV_INIT:
|
||||||
|
goto result;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
||||||
|
decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars TSRMLS_CC);
|
||||||
|
result:
|
||||||
|
decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC);
|
||||||
|
format:
|
||||||
|
asprintf(
|
||||||
|
&decode[0],
|
||||||
|
"%-20s %-20s %-20s",
|
||||||
|
decode[1] ? decode[1] : "",
|
||||||
|
decode[2] ? decode[2] : "",
|
||||||
|
decode[3] ? decode[3] : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decode[1])
|
||||||
|
free(decode[1]);
|
||||||
|
if (decode[2])
|
||||||
|
free(decode[2]);
|
||||||
|
if (decode[3])
|
||||||
|
free(decode[3]);
|
||||||
|
|
||||||
|
return decode[0];
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
|
void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
|
||||||
|
{
|
||||||
|
/* force out a line while stepping so the user knows what is happening */
|
||||||
|
if (ignore_flags ||
|
||||||
|
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
|
||||||
|
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ||
|
||||||
|
(PHPDBG_G(oplog)))) {
|
||||||
|
|
||||||
|
zend_op *opline = execute_data->opline;
|
||||||
|
char *decode = phpdbg_decode_opline(execute_data->op_array, opline, vars TSRMLS_CC);
|
||||||
|
|
||||||
|
if (ignore_flags ||
|
||||||
|
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
|
||||||
|
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
|
||||||
|
/* output line info */
|
||||||
|
phpdbg_notice("#%- 5lu %16p %-30s %s %s",
|
||||||
|
opline->lineno,
|
||||||
|
opline,
|
||||||
|
phpdbg_decode_opcode(opline->opcode),
|
||||||
|
decode,
|
||||||
|
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignore_flags && PHPDBG_G(oplog)) {
|
||||||
|
phpdbg_log_ex(PHPDBG_G(oplog), "#%- 5lu %16p %-30s %s %s",
|
||||||
|
opline->lineno,
|
||||||
|
opline,
|
||||||
|
phpdbg_decode_opcode(opline->opcode),
|
||||||
|
decode,
|
||||||
|
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decode) {
|
||||||
|
free(decode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
|
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
|
||||||
|
{
|
||||||
|
phpdbg_print_opline_ex(execute_data, NULL, ignore_flags TSRMLS_CC);
|
||||||
|
} /* }}} */
|
||||||
|
|
||||||
const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
|
const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,5 +23,8 @@
|
||||||
#include "zend_types.h"
|
#include "zend_types.h"
|
||||||
|
|
||||||
const char *phpdbg_decode_opcode(zend_uchar);
|
const char *phpdbg_decode_opcode(zend_uchar);
|
||||||
|
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC);
|
||||||
|
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC);
|
||||||
|
void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC);
|
||||||
|
|
||||||
#endif /* PHPDBG_OPCODE_H */
|
#endif /* PHPDBG_OPCODE_H */
|
||||||
|
|
114
phpdbg_prompt.c
114
phpdbg_prompt.c
|
@ -35,7 +35,7 @@
|
||||||
#include "phpdbg_frame.h"
|
#include "phpdbg_frame.h"
|
||||||
|
|
||||||
/* {{{ command declarations */
|
/* {{{ command declarations */
|
||||||
static const phpdbg_command_t phpdbg_prompt_commands[] = {
|
const phpdbg_command_t phpdbg_prompt_commands[] = {
|
||||||
PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, 1),
|
PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, 1),
|
||||||
PHPDBG_COMMAND_D(compile, "attempt compilation", 'c', NULL, 0),
|
PHPDBG_COMMAND_D(compile, "attempt compilation", 'c', NULL, 0),
|
||||||
PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 1),
|
PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 1),
|
||||||
|
@ -1034,6 +1034,8 @@ int phpdbg_interactive(TSRMLS_D) /* {{{ */
|
||||||
{
|
{
|
||||||
int ret = SUCCESS;
|
int ret = SUCCESS;
|
||||||
|
|
||||||
|
PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
|
||||||
|
|
||||||
phpdbg_input_t *input = phpdbg_read_input(NULL TSRMLS_CC);
|
phpdbg_input_t *input = phpdbg_read_input(NULL TSRMLS_CC);
|
||||||
|
|
||||||
if (input && input->length > 0L) {
|
if (input && input->length > 0L) {
|
||||||
|
@ -1075,112 +1077,12 @@ last:
|
||||||
|
|
||||||
out:
|
out:
|
||||||
phpdbg_destroy_input(&input TSRMLS_CC);
|
phpdbg_destroy_input(&input TSRMLS_CC);
|
||||||
if (EG(in_execution)) {
|
|
||||||
restore_frame();
|
PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE;
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
|
||||||
static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, zend_uint type, HashTable *vars TSRMLS_DC) /* {{{ */
|
|
||||||
{
|
|
||||||
char *decode = NULL;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case IS_CV:
|
|
||||||
asprintf(&decode, "$%s", ops->vars[op->var].name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IS_VAR:
|
|
||||||
case IS_TMP_VAR: {
|
|
||||||
zend_ulong id = 0;
|
|
||||||
if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &id) != SUCCESS) {
|
|
||||||
id = zend_hash_num_elements(vars);
|
|
||||||
zend_hash_index_update(
|
|
||||||
vars, (zend_ulong) ops->vars - op->var,
|
|
||||||
(void**) &id,
|
|
||||||
sizeof(zend_ulong), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
asprintf(&decode, "@%lu", id);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case IS_CONST:
|
|
||||||
asprintf(&decode, "<constant>");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IS_UNUSED:
|
|
||||||
asprintf(&decode, "<unused>");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return decode;
|
|
||||||
} /* }}} */
|
|
||||||
|
|
||||||
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC) /*{{{ */
|
|
||||||
{
|
|
||||||
char *decode[3];
|
|
||||||
|
|
||||||
decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC);
|
|
||||||
decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars TSRMLS_CC);
|
|
||||||
|
|
||||||
switch (op->opcode) {
|
|
||||||
default: asprintf(
|
|
||||||
&decode[0], "%-20s %-20s",
|
|
||||||
decode[1], decode[2]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decode[1])
|
|
||||||
free(decode[1]);
|
|
||||||
if (decode[2])
|
|
||||||
free(decode[2]);
|
|
||||||
|
|
||||||
return decode[0];
|
|
||||||
} /* }}} */
|
|
||||||
|
|
||||||
void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
|
|
||||||
{
|
|
||||||
/* force out a line while stepping so the user knows what is happening */
|
|
||||||
if (ignore_flags ||
|
|
||||||
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
|
|
||||||
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ||
|
|
||||||
(PHPDBG_G(oplog)))) {
|
|
||||||
|
|
||||||
zend_op *opline = execute_data->opline;
|
|
||||||
char *decode = phpdbg_decode_opline(execute_data->op_array, opline, vars TSRMLS_CC);
|
|
||||||
|
|
||||||
if (ignore_flags ||
|
|
||||||
(!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) ||
|
|
||||||
(PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
|
|
||||||
/* output line info */
|
|
||||||
phpdbg_notice("#%- 5lu %16p %-30s %s %s",
|
|
||||||
opline->lineno,
|
|
||||||
opline,
|
|
||||||
phpdbg_decode_opcode(opline->opcode),
|
|
||||||
decode,
|
|
||||||
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ignore_flags && PHPDBG_G(oplog)) {
|
|
||||||
phpdbg_log_ex(PHPDBG_G(oplog), "#%- 5lu %16p %-30s %s %s",
|
|
||||||
opline->lineno,
|
|
||||||
opline,
|
|
||||||
phpdbg_decode_opcode(opline->opcode),
|
|
||||||
decode,
|
|
||||||
execute_data->op_array->filename ? execute_data->op_array->filename : "unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decode) {
|
|
||||||
free(decode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} /* }}} */
|
|
||||||
|
|
||||||
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC) /* {{{ */
|
|
||||||
{
|
|
||||||
phpdbg_print_opline_ex(execute_data, NULL, ignore_flags TSRMLS_CC);
|
|
||||||
} /* }}} */
|
|
||||||
|
|
||||||
void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */
|
void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
/* this is implicitly required */
|
/* this is implicitly required */
|
||||||
|
@ -1197,12 +1099,6 @@ void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */
|
||||||
}
|
}
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
|
||||||
void phpdbg_sigint_handler(int signo)
|
|
||||||
{
|
|
||||||
TSRMLS_FETCH();
|
|
||||||
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_array, zend_bool nested TSRMLS_DC) /* {{{ */
|
static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_array, zend_bool nested TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
#if PHP_VERSION_ID >= 50500
|
#if PHP_VERSION_ID >= 50500
|
||||||
|
|
|
@ -20,21 +20,13 @@
|
||||||
#ifndef PHPDBG_PROMPT_H
|
#ifndef PHPDBG_PROMPT_H
|
||||||
#define PHPDBG_PROMPT_H
|
#define PHPDBG_PROMPT_H
|
||||||
|
|
||||||
|
/* {{{ */
|
||||||
void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC);
|
void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC);
|
||||||
int phpdbg_interactive(TSRMLS_D);
|
int phpdbg_interactive(TSRMLS_D);
|
||||||
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags TSRMLS_DC);
|
|
||||||
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRMLS_DC);
|
|
||||||
int phpdbg_compile(TSRMLS_D);
|
int phpdbg_compile(TSRMLS_D);
|
||||||
void phpdbg_clean(zend_bool full TSRMLS_DC);
|
void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */
|
||||||
void phpdbg_sigint_handler(int signo);
|
|
||||||
|
|
||||||
#if PHP_VERSION_ID >= 50500
|
/* {{{ phpdbg command handlers */
|
||||||
void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC);
|
|
||||||
#else
|
|
||||||
void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* {{{ */
|
|
||||||
PHPDBG_COMMAND(exec);
|
PHPDBG_COMMAND(exec);
|
||||||
PHPDBG_COMMAND(compile);
|
PHPDBG_COMMAND(compile);
|
||||||
PHPDBG_COMMAND(step);
|
PHPDBG_COMMAND(step);
|
||||||
|
@ -60,4 +52,14 @@ PHPDBG_COMMAND(oplog);
|
||||||
PHPDBG_COMMAND(register);
|
PHPDBG_COMMAND(register);
|
||||||
PHPDBG_COMMAND(quit); /* }}} */
|
PHPDBG_COMMAND(quit); /* }}} */
|
||||||
|
|
||||||
|
/* {{{ prompt commands */
|
||||||
|
extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */
|
||||||
|
|
||||||
|
/* {{{ */
|
||||||
|
#if PHP_VERSION_ID >= 50500
|
||||||
|
void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC);
|
||||||
|
#else
|
||||||
|
void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC);
|
||||||
|
#endif /* }}} */
|
||||||
|
|
||||||
#endif /* PHPDBG_PROMPT_H */
|
#endif /* PHPDBG_PROMPT_H */
|
||||||
|
|
|
@ -44,11 +44,11 @@ enum {
|
||||||
|
|
||||||
int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...);
|
int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...);
|
||||||
|
|
||||||
#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, stdout, fmt, ##__VA_ARGS__)
|
#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, 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, stdout, fmt, ##__VA_ARGS__)
|
#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||||
#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, stdout, fmt, ##__VA_ARGS__)
|
#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||||
#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, stdout, fmt, ##__VA_ARGS__)
|
#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||||
#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||||
|
@ -57,7 +57,7 @@ int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...);
|
||||||
#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
#if PHPDBG_DEBUG
|
#if PHPDBG_DEBUG
|
||||||
# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, stderr, fmt, ##__VA_ARGS__)
|
# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define phpdbg_debug(fmt, ...)
|
# define phpdbg_debug(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
Binary file not shown.
82
tutorials/initializing.md
Normal file
82
tutorials/initializing.md
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
phpdbginit
|
||||||
|
==========
|
||||||
|
*Setting up your debugging session automatically*
|
||||||
|
|
||||||
|
By default, phpdbg looks for *.phpdbginit* in the current working directory, this location can be overrideen on the command line:
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg -imy.phpdbginit
|
||||||
|
```
|
||||||
|
|
||||||
|
An init file should contain one command per line, any phpdbg command is supported during init.
|
||||||
|
|
||||||
|
In addition, *.phpdbginit* can contain embedded code, allowing, for example
|
||||||
|
|
||||||
|
- the setup of auto completion
|
||||||
|
- the registration of functions
|
||||||
|
- the acquisition and pre-compilation of code
|
||||||
|
- bootstrapping a web application
|
||||||
|
|
||||||
|
It is common for C projects (PHP included) to include an init file for the GDB debugger; this would be a clever practice to adopt
|
||||||
|
for those distributing PHP library code.
|
||||||
|
|
||||||
|
The default .phpdbginit
|
||||||
|
=======================
|
||||||
|
|
||||||
|
We distribute the following init file by default, it should be copied to any directory you commonly execute in:
|
||||||
|
|
||||||
|
```
|
||||||
|
##########################################################
|
||||||
|
# .phpdbginit
|
||||||
|
#
|
||||||
|
# Lines starting with # are ignored
|
||||||
|
# Code must start and end with <: and :> respectively
|
||||||
|
##########################################################
|
||||||
|
# Place initialization commands one per line
|
||||||
|
##########################################################
|
||||||
|
# exec sapi/phpdbg/test.php
|
||||||
|
|
||||||
|
##########################################################
|
||||||
|
# Embedding code in .phpdbginit
|
||||||
|
##########################################################
|
||||||
|
<:
|
||||||
|
/*
|
||||||
|
If readline is loaded, you might want to setup completion:
|
||||||
|
*/
|
||||||
|
if (function_exists('readline_completion_function')) {
|
||||||
|
readline_completion_function(function(){
|
||||||
|
return array_merge(
|
||||||
|
get_defined_functions()['user'],
|
||||||
|
array_keys(get_defined_constants())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
:>
|
||||||
|
##########################################################
|
||||||
|
# Now carry on initializing phpdbg ...
|
||||||
|
##########################################################
|
||||||
|
# R my_debugging_function
|
||||||
|
|
||||||
|
##########################################################
|
||||||
|
# PHP has many functions that might be useful
|
||||||
|
# ... you choose ...
|
||||||
|
##########################################################
|
||||||
|
# R touch
|
||||||
|
# R unlink
|
||||||
|
# R scandir
|
||||||
|
# R glob
|
||||||
|
|
||||||
|
##########################################################
|
||||||
|
# Remember: *you have access to the shell*
|
||||||
|
##########################################################
|
||||||
|
# The output of registered function calls is not,
|
||||||
|
# by default, very pretty (unless you implement
|
||||||
|
# and register a new implementation for phpdbg)
|
||||||
|
# The output of shell commands will usually be more
|
||||||
|
# readable on the console
|
||||||
|
##########################################################
|
||||||
|
# TLDR; if you have a good shell, use it ...
|
||||||
|
##########################################################
|
||||||
|
```
|
||||||
|
|
||||||
|
|
132
tutorials/simples.md
Normal file
132
tutorials/simples.md
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
Simples
|
||||||
|
=======
|
||||||
|
*Everything is simple ...*
|
||||||
|
|
||||||
|
It is easy to imagine that debugging a whole web application might be difficult, in a console program, in fact this is not the case:
|
||||||
|
|
||||||
|
A web application is just an instance of the PHP interpreter with some very specific super globals set.
|
||||||
|
|
||||||
|
With everything in the correct place, your web application has no clue that it being served not to a client, but to you, probably in your underwear.
|
||||||
|
|
||||||
|
With the facts established, you can use phpdbg to debug anything that is PHP, with a bit of cleverness in the right places.
|
||||||
|
|
||||||
|
Very Simple
|
||||||
|
===========
|
||||||
|
*A good starting place ...*
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg -e/path/to/my/script.php
|
||||||
|
```
|
||||||
|
|
||||||
|
The command above will result in a phpdbg console that has executed *.phpdbginit* (if it exists) and is ready to compile, inspect, step through
|
||||||
|
and execute the code contained in */path/to/my/script.php*
|
||||||
|
|
||||||
|
The first thing to do upon being presented with the console, is decide what to break for ...
|
||||||
|
|
||||||
|
Many options exist for choosing (and setting) breakpoints:
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg> b phpdbg::isGreat
|
||||||
|
phpdbg> b phpdbg_is_great
|
||||||
|
```
|
||||||
|
|
||||||
|
The commands above will be the most common for most developers; that is, specifying the entry point of a function or method on which to break execution.
|
||||||
|
|
||||||
|
Introspection of code is supported on the console, for anything that is compiled, if help is required remembering the name of a particular method then issue:
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg> compile
|
||||||
|
phpdbg> print class myClassName
|
||||||
|
```
|
||||||
|
|
||||||
|
Introspection doesn't only provide you with names, but the addresses of every opcode in every statement, which you may use to specify with as much precision as
|
||||||
|
is possible where to break execution.
|
||||||
|
|
||||||
|
**There is a print command for particular methods, useful if a class is very large and your screen is not !**
|
||||||
|
|
||||||
|
At this point, break points are set; the next thing to do is issue the run command:
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg> run
|
||||||
|
```
|
||||||
|
|
||||||
|
This will cause execution of the context, if a breakpoint is reached, the interactive console returns such that more commands can be issued.
|
||||||
|
|
||||||
|
When a breakpoint is reached, several options for continuation exist:
|
||||||
|
|
||||||
|
- step through every instruction
|
||||||
|
- run past the end of the stack
|
||||||
|
- run to the end of the stack
|
||||||
|
|
||||||
|
*Q: WTF is a stack?*
|
||||||
|
|
||||||
|
*A: Generally the current codepath, more precisely: current function, method or file*
|
||||||
|
|
||||||
|
Just quickly; an explanation of what "to" and "past" the end of a "stack" means:
|
||||||
|
|
||||||
|
Assuming there is a break set for *my_function_somewhere* in the following code:
|
||||||
|
|
||||||
|
```
|
||||||
|
function my_function_somewhere($input = array()) /* break here on entry to the function */
|
||||||
|
{
|
||||||
|
/* ... the stack ... */
|
||||||
|
|
||||||
|
if (count($input))
|
||||||
|
{
|
||||||
|
/* to -> */ return $input[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* to -> */ return rand(1, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* past -> */ $result = my_function_somewhere();
|
||||||
|
if ($result)
|
||||||
|
{
|
||||||
|
/* and so on */
|
||||||
|
var_dump($result);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The commands *finish* and *leave*, run *past* and *to* the end of the stack respecitively.
|
||||||
|
|
||||||
|
**Note: the finish command does not automatically break; to break past the end of the stack enable stepping before issuing finish, the leave command breaks implicitly**
|
||||||
|
|
||||||
|
On with execution ...
|
||||||
|
=====================
|
||||||
|
*Stepping, slowly, is sometimes the way forward ...*
|
||||||
|
|
||||||
|
Should you want to inspect what happens during the execution of the stack, enable stepping:
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg> step 1
|
||||||
|
```
|
||||||
|
|
||||||
|
In case it wasn't obvious, the next thing to do is nearly always *next*:
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg> next
|
||||||
|
```
|
||||||
|
|
||||||
|
Which will cause the vm to assume control and continue execution until the next break point, or completion.
|
||||||
|
|
||||||
|
Stepping through every single instruction is not usually beneficial, issue:
|
||||||
|
|
||||||
|
```
|
||||||
|
phpdbg> step 0
|
||||||
|
```
|
||||||
|
|
||||||
|
To disable stepping again, and only interrupt execution for breakpoints.
|
||||||
|
|
||||||
|
As hard as it gets ...
|
||||||
|
======================
|
||||||
|
*Web Applications*
|
||||||
|
|
||||||
|
As mentioned, a web application is only a script executing with some specific super globals set;
|
||||||
|
|
||||||
|
**The mocking of any web request just requires that you set the super globals of the script accordingly**
|
||||||
|
|
||||||
|
We refer to this as "bootstrapping", mostly because I have always wanted a genuine reason to use that word.
|
||||||
|
|
||||||
|
See the example, for help with bootstrapping ...
|
Loading…
Add table
Add a link
Reference in a new issue