mirror of
https://github.com/php/php-src.git
synced 2025-08-19 08:49:28 +02:00
Added frames and beautified backtrace
This commit is contained in:
parent
0488640f4c
commit
5b51fb40e9
9 changed files with 213 additions and 14 deletions
|
@ -18,7 +18,7 @@ if test "$PHP_PHPDBG" != "no"; then
|
|||
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)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
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");
|
||||
}
|
||||
|
||||
|
|
1
phpdbg.c
1
phpdbg.c
|
@ -45,6 +45,7 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
|
|||
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) /* {{{ */
|
||||
|
|
2
phpdbg.h
2
phpdbg.h
|
@ -54,6 +54,7 @@
|
|||
#endif
|
||||
|
||||
#include "phpdbg_cmd.h"
|
||||
#include "phpdbg_frame.h"
|
||||
|
||||
#ifdef ZTS
|
||||
# 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 */
|
||||
zend_ulong flags; /* phpdbg flags */
|
||||
HashTable registered; /* registered */
|
||||
phpdbg_frame frame; /* frame */
|
||||
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
|
||||
|
||||
#endif /* PHPDBG_H */
|
||||
|
|
100
phpdbg_frame.c
Normal file
100
phpdbg_frame.c
Normal 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
36
phpdbg_frame.h
Normal 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 */
|
|
@ -32,6 +32,7 @@
|
|||
#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[] = {
|
||||
|
@ -42,8 +43,9 @@ 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),
|
||||
|
@ -370,6 +372,21 @@ PHPDBG_COMMAND(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) /* }}} */
|
||||
{
|
||||
zend_fcall_info fci;
|
||||
|
@ -529,21 +546,58 @@ PHPDBG_COMMAND(back) /* {{{ */
|
|||
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);
|
||||
|
@ -1021,6 +1075,9 @@ last:
|
|||
|
||||
out:
|
||||
phpdbg_destroy_input(&input TSRMLS_CC);
|
||||
if (EG(in_execution)) {
|
||||
restore_frame();
|
||||
}
|
||||
|
||||
return ret;
|
||||
} /* }}} */
|
||||
|
|
|
@ -44,6 +44,7 @@ PHPDBG_COMMAND(eval);
|
|||
PHPDBG_COMMAND(until);
|
||||
PHPDBG_COMMAND(finish);
|
||||
PHPDBG_COMMAND(leave);
|
||||
PHPDBG_COMMAND(frame);
|
||||
PHPDBG_COMMAND(print);
|
||||
PHPDBG_COMMAND(break);
|
||||
PHPDBG_COMMAND(back);
|
||||
|
|
10
test.php
10
test.php
|
@ -12,12 +12,14 @@ class phpdbg {
|
|||
}
|
||||
}
|
||||
|
||||
function test() {
|
||||
$var = 1 + 1;
|
||||
function test($x) {
|
||||
$var = $x + 1;
|
||||
$var += 2;
|
||||
$var <<= 3;
|
||||
|
||||
$foo = function () {};
|
||||
$foo = function () {
|
||||
echo "bar!\n";
|
||||
};
|
||||
|
||||
$foo();
|
||||
|
||||
|
@ -29,7 +31,7 @@ $dbg = new phpdbg();
|
|||
var_dump(
|
||||
$dbg->isGreat("PHP Rocks !!"));
|
||||
|
||||
foreach (test() as $gen)
|
||||
foreach (test(1) as $gen)
|
||||
continue;
|
||||
|
||||
echo "it works!\n";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue