mirror of
https://github.com/php/php-src.git
synced 2025-08-19 17:04:47 +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
|
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)
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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->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) /* {{{ */
|
||||||
|
|
2
phpdbg.h
2
phpdbg.h
|
@ -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
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_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;
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
10
test.php
10
test.php
|
@ -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";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue