Added frames and beautified backtrace

This commit is contained in:
Bob Weinand 2013-11-22 18:27:55 +01:00
parent 0488640f4c
commit 5b51fb40e9
9 changed files with 213 additions and 14 deletions

View file

@ -18,7 +18,7 @@ if test "$PHP_PHPDBG" != "no"; then
fi fi
PHP_PHPDBG_CFLAGS="-I$abc_srcdir" 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_CFLAGS)
PHP_SUBST(PHP_PHPDBG_FILES) PHP_SUBST(PHP_PHPDBG_FILES)

View file

@ -1,7 +1,7 @@
ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes'); ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes');
if (PHP_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"); ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib");
} }

View file

@ -45,6 +45,7 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
pg->flags = PHPDBG_DEFAULT_FLAGS; pg->flags = PHPDBG_DEFAULT_FLAGS;
pg->oplog = NULL; pg->oplog = NULL;
memset(&pg->lparam, 0, sizeof(phpdbg_param_t)); memset(&pg->lparam, 0, sizeof(phpdbg_param_t));
pg->frame.num = 0;
} /* }}} */ } /* }}} */
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */

View file

@ -54,6 +54,7 @@
#endif #endif
#include "phpdbg_cmd.h" #include "phpdbg_cmd.h"
#include "phpdbg_frame.h"
#ifdef ZTS #ifdef ZTS
# define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) # define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
@ -126,6 +127,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
HashTable seek; /* seek oplines */ HashTable seek; /* seek oplines */
zend_ulong flags; /* phpdbg flags */ zend_ulong flags; /* phpdbg flags */
HashTable registered; /* registered */ HashTable registered; /* registered */
phpdbg_frame frame; /* frame */
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
#endif /* PHPDBG_H */ #endif /* PHPDBG_H */

100
phpdbg_frame.c Normal file
View file

@ -0,0 +1,100 @@
/*
+----------------------------------------------------------------------+
| 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);
}

36
phpdbg_frame.h Normal file
View file

@ -0,0 +1,36 @@
/*
+----------------------------------------------------------------------+
| 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 */

View file

@ -32,6 +32,7 @@
#include "phpdbg_utils.h" #include "phpdbg_utils.h"
#include "phpdbg_prompt.h" #include "phpdbg_prompt.h"
#include "phpdbg_cmd.h" #include "phpdbg_cmd.h"
#include "phpdbg_frame.h"
/* {{{ command declarations */ /* {{{ command declarations */
static const phpdbg_command_t phpdbg_prompt_commands[] = { static const phpdbg_command_t phpdbg_prompt_commands[] = {
@ -42,8 +43,9 @@ static const phpdbg_command_t phpdbg_prompt_commands[] = {
PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0), PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0),
PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, 1), 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(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(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(print, "print something", 'p', phpdbg_print_commands, 2),
PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1), PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1),
PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0), PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0),
@ -370,6 +372,21 @@ PHPDBG_COMMAND(leave) /* {{{ */
return PHPDBG_LEAVE; 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) /* }}} */ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */
{ {
zend_fcall_info fci; zend_fcall_info fci;
@ -529,21 +546,58 @@ PHPDBG_COMMAND(back) /* {{{ */
case EMPTY_PARAM: case EMPTY_PARAM:
case NUMERIC_PARAM: { case NUMERIC_PARAM: {
zval zbacktrace; zval zbacktrace;
zval **tmp; zval **tmp, **argstmp;
HashPosition position; HashPosition position;
int i = 0, int i = 0,
limit = (param->type == NUMERIC_PARAM) ? param->num : 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( zend_fetch_debug_backtrace(
&zbacktrace, 0, 0, limit TSRMLS_CC); &zbacktrace, 0, 0, limit TSRMLS_CC);
for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position); 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_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position);
zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position)) { while (1) {
if (i++) { zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file);
phpdbg_writeln(","); 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); phpdbg_writeln(EMPTY);
@ -1021,6 +1075,9 @@ last:
out: out:
phpdbg_destroy_input(&input TSRMLS_CC); phpdbg_destroy_input(&input TSRMLS_CC);
if (EG(in_execution)) {
restore_frame();
}
return ret; return ret;
} /* }}} */ } /* }}} */

View file

@ -44,6 +44,7 @@ PHPDBG_COMMAND(eval);
PHPDBG_COMMAND(until); PHPDBG_COMMAND(until);
PHPDBG_COMMAND(finish); PHPDBG_COMMAND(finish);
PHPDBG_COMMAND(leave); PHPDBG_COMMAND(leave);
PHPDBG_COMMAND(frame);
PHPDBG_COMMAND(print); PHPDBG_COMMAND(print);
PHPDBG_COMMAND(break); PHPDBG_COMMAND(break);
PHPDBG_COMMAND(back); PHPDBG_COMMAND(back);

View file

@ -12,12 +12,14 @@ class phpdbg {
} }
} }
function test() { function test($x) {
$var = 1 + 1; $var = $x + 1;
$var += 2; $var += 2;
$var <<= 3; $var <<= 3;
$foo = function () {}; $foo = function () {
echo "bar!\n";
};
$foo(); $foo();
@ -29,7 +31,7 @@ $dbg = new phpdbg();
var_dump( var_dump(
$dbg->isGreat("PHP Rocks !!")); $dbg->isGreat("PHP Rocks !!"));
foreach (test() as $gen) foreach (test(1) as $gen)
continue; continue;
echo "it works!\n"; echo "it works!\n";