fi
PHP_PHPDBG_CFLAGS="-I$abc_srcdir"
- 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"
+ 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_frame.c"
PHP_SUBST(PHP_PHPDBG_CFLAGS)
PHP_SUBST(PHP_PHPDBG_FILES)
ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes');
if (PHP_PHPDBG == "yes") {
- SAPI('phpdbg', 'phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c', 'phpdbg.exe');
+ SAPI('phpdbg', 'phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_frame.c', 'phpdbg.exe');
ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib");
}
pg->flags = PHPDBG_DEFAULT_FLAGS;
pg->oplog = NULL;
memset(&pg->lparam, 0, sizeof(phpdbg_param_t));
+ pg->frame.num = 0;
} /* }}} */
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
#endif
#include "phpdbg_cmd.h"
+#include "phpdbg_frame.h"
#ifdef ZTS
# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
HashTable seek; /* seek oplines */
zend_ulong flags; /* phpdbg flags */
HashTable registered; /* registered */
+ phpdbg_frame frame; /* frame */
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
#endif /* PHPDBG_H */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phpdbg.h"
+#include "phpdbg_frame.h"
+#include "phpdbg_list.h"
+#include "phpdbg_utils.h"
+
+ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
+
+#define PHPDBG_FRAME(v) (PHPDBG_G(frame).v)
+#define PHPDBG_EX(v) (EG(current_execute_data)->v)
+
+void switch_to_frame(int frame) {
+ zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data);
+ int i = 0;
+
+ if (PHPDBG_FRAME(num) == frame) {
+ phpdbg_notice("Already in frame #%d", frame);
+ return;
+ }
+
+ while (execute_data) {
+ if (i++ == frame) {
+ break;
+ }
+
+ do {
+ execute_data = execute_data->prev_execute_data;
+ } while (execute_data && execute_data->opline == NULL);
+ }
+
+ if (execute_data == NULL) {
+ phpdbg_error("No frame #%d", frame);
+ return;
+ }
+
+ restore_frame();
+
+ if (frame > 0) {
+ PHPDBG_FRAME(num) = frame;
+
+ /* backup things and jump back */
+ PHPDBG_FRAME(execute_data) = EG(current_execute_data);
+ EG(current_execute_data) = execute_data;
+
+ EG(opline_ptr) = &PHPDBG_EX(opline);
+ EG(active_op_array) = PHPDBG_EX(op_array);
+ EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
+ EG(active_symbol_table) = PHPDBG_EX(symbol_table);
+ EG(This) = PHPDBG_EX(current_this);
+ EG(scope) = PHPDBG_EX(current_scope);
+ EG(called_scope) = PHPDBG_EX(current_called_scope);
+ }
+
+ phpdbg_notice("Switched to frame #%d", frame);
+ phpdbg_list_file(
+ zend_get_executed_filename(TSRMLS_C),
+ 3,
+ zend_get_executed_lineno(TSRMLS_C)-1,
+ zend_get_executed_lineno(TSRMLS_C)
+ TSRMLS_CC
+ );
+}
+
+void restore_frame() {
+ if (PHPDBG_FRAME(num) == 0) {
+ return;
+ }
+
+ PHPDBG_FRAME(num) = 0;
+
+ /* move things back */
+ EG(current_execute_data) = PHPDBG_FRAME(execute_data);
+
+ EG(opline_ptr) = &PHPDBG_EX(opline);
+ EG(active_op_array) = PHPDBG_EX(op_array);
+ EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value);
+ EG(active_symbol_table) = PHPDBG_EX(symbol_table);
+ EG(This) = PHPDBG_EX(current_this);
+ EG(scope) = PHPDBG_EX(current_scope);
+ EG(called_scope) = PHPDBG_EX(current_called_scope);
+}
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Felipe Pena <felipe@php.net> |
+ | Authors: Joe Watkins <joe.watkins@live.co.uk> |
+ | Authors: Bob Weinand <bwoebi@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHPDBG_FRAME_H
+#define PHPDBG_FRAME_H
+
+#include "php.h"
+
+typedef struct {
+ long num;
+
+ zend_execute_data *execute_data;
+} phpdbg_frame;
+
+void switch_to_frame(int frame);
+
+void restore_frame();
+
+#endif /* PHPDBG_FRAME_H */
#include "phpdbg_utils.h"
#include "phpdbg_prompt.h"
#include "phpdbg_cmd.h"
+#include "phpdbg_frame.h"
/* {{{ command declarations */
static const phpdbg_command_t phpdbg_prompt_commands[] = {
PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0),
PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, 1),
PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0),
- PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'f', NULL, 0),
+ PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0),
PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0),
+ PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, 1),
PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 2),
PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1),
PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0),
return PHPDBG_LEAVE;
} /* }}} */
+PHPDBG_COMMAND(frame) /* {{{ */
+{
+ switch (param->type) {
+ case NUMERIC_PARAM:
+ switch_to_frame(param->num);
+ break;
+
+ case EMPTY_PARAM:
+ phpdbg_writeln("Currently at frame %d:", PHPDBG_G(frame).num);
+ break;
+
+ phpdbg_default_switch_case();
+ }
+} /* }}} */
+
static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */
{
zend_fcall_info fci;
case EMPTY_PARAM:
case NUMERIC_PARAM: {
zval zbacktrace;
- zval **tmp;
+ zval **tmp, **argstmp;
HashPosition position;
int i = 0,
limit = (param->type == NUMERIC_PARAM) ? param->num : 0;
+ zval **file, **line, **funcname, **class, **type, **args;
+ char *func, is_class;
+ long funcsize;
+
zend_fetch_debug_backtrace(
&zbacktrace, 0, 0, limit TSRMLS_CC);
- for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
- zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position) == SUCCESS;
- zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position)) {
- if (i++) {
- phpdbg_writeln(",");
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position);
+ zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position);
+ while (1) {
+ zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file);
+ zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line);
+ zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position);
+ if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position) == FAILURE) {
+ phpdbg_write("frame #%d {main} at %s:%d", i, Z_STRVAL_PP(file), Z_LVAL_PP(line));
+ break;
}
- zend_print_flat_zval_r(*tmp TSRMLS_CC);
+ zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"), (void **)&funcname);
+ if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "object", sizeof("object"), (void **)&class)) == FAILURE) {
+ is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"), (void **)&class);
+ } else {
+ zend_get_object_classname(class, &Z_STRVAL_PP(class), &Z_STRLEN_PP(class) TSRMLS_CC);
+ }
+ if (is_class) {
+ zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type);
+ }
+
+ funcsize = Z_STRLEN_PP(funcname) + (is_class == FAILURE?0:Z_STRLEN_PP(type) + Z_STRLEN_PP(class)) + 1;
+
+ func = emalloc(funcsize + 2);
+ phpdbg_write("frame #%d: %s%s%s(", i++, Z_STRVAL_PP(funcname), is_class == FAILURE?"":Z_STRVAL_PP(type), is_class == FAILURE?"":Z_STRVAL_PP(class));
+
+ if (zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"), (void **)&args) == SUCCESS) {
+ HashPosition iterator;
+ int j = 0;
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator);
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args), (void **) &argstmp, &iterator) == SUCCESS) {
+ if (j++) {
+ phpdbg_write(", ");
+ }
+ zend_print_flat_zval_r(*argstmp TSRMLS_CC);
+ zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator);
+ }
+ }
+
+ phpdbg_writeln(") at %s:%d", Z_STRVAL_PP(file), Z_LVAL_PP(line));
}
phpdbg_writeln(EMPTY);
out:
phpdbg_destroy_input(&input TSRMLS_CC);
+ if (EG(in_execution)) {
+ restore_frame();
+ }
return ret;
} /* }}} */
PHPDBG_COMMAND(until);
PHPDBG_COMMAND(finish);
PHPDBG_COMMAND(leave);
+PHPDBG_COMMAND(frame);
PHPDBG_COMMAND(print);
PHPDBG_COMMAND(break);
PHPDBG_COMMAND(back);
}
}
-function test() {
- $var = 1 + 1;
+function test($x) {
+ $var = $x + 1;
$var += 2;
$var <<= 3;
- $foo = function () {};
+ $foo = function () {
+ echo "bar!\n";
+ };
$foo();
var_dump(
$dbg->isGreat("PHP Rocks !!"));
-foreach (test() as $gen)
+foreach (test(1) as $gen)
continue;
echo "it works!\n";