replace phpdbg custom opcode dumper with O+ dump (#7227)

This commit is contained in:
Joe Watkins 2021-07-13 15:32:14 +02:00 committed by GitHub
parent 52d3d0d8d7
commit 60fbd6df95
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 137 additions and 475 deletions

View file

@ -716,11 +716,15 @@ ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block
}
}
static void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data)
ZEND_API void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data)
{
int len = 0;
const zend_ssa *ssa = NULL;
zend_ssa_op *ssa_op = NULL;
if (dump_flags & ZEND_DUMP_LINE_NUMBERS) {
fprintf(stderr, "L%04u ", opline->lineno);
}
len = fprintf(stderr, "%04u", (uint32_t)(opline - op_array->opcodes));
fprintf(stderr, "%*c", 5-len, ' ');

View file

@ -27,11 +27,13 @@
#define ZEND_DUMP_CFG (1<<2)
#define ZEND_DUMP_SSA (1<<3)
#define ZEND_DUMP_LIVE_RANGES (1<<4)
#define ZEND_DUMP_LINE_NUMBERS (1<<5)
BEGIN_EXTERN_C()
ZEND_API void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data);
ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const zend_ssa *ssa, const zend_ssa_op *ssa_op);
ZEND_API void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data);
void zend_dump_dominators(const zend_op_array *op_array, const zend_cfg *cfg);
void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg);
void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa);

View file

@ -30,7 +30,7 @@ if test "$BUILD_PHPDBG" = "" && test "$PHP_PHPDBG" != "no"; then
fi
PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"
PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.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_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_io.c phpdbg_out.c"
PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_io.c phpdbg_out.c"
AC_MSG_CHECKING([for phpdbg and readline integration])
if test "$PHP_PHPDBG_READLINE" = "yes"; then

View file

@ -2,7 +2,7 @@ ARG_ENABLE('phpdbg', 'Build phpdbg', 'no');
ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no');
PHPDBG_SOURCES='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_print.c phpdbg_bp.c phpdbg_list.c phpdbg_utils.c ' +
'phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c '+
'phpdbg_parser.c phpdbg_lexer.c phpdbg_sigsafe.c phpdbg_io.c phpdbg_out.c';
PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll';

View file

@ -49,10 +49,6 @@ Override .phpgdbinit location (implies -I)
.B \-I
Ignore .phpdbginit (default init file)
.TP
.B \-O \fIfile\fR
Set oplog output to
.IR file
.TP
.B \-r
Jump straight to run
.TP

View file

@ -122,7 +122,6 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
pg->in_execution = 0;
pg->bp_count = 0;
pg->flags = PHPDBG_DEFAULT_FLAGS;
pg->oplog = NULL;
memset(pg->io, 0, sizeof(pg->io));
pg->frame.num = 0;
pg->sapi_name_ptr = NULL;
@ -199,11 +198,6 @@ static PHP_MSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
PHPDBG_G(exec) = NULL;
}
if (PHPDBG_G(oplog)) {
fclose(PHPDBG_G(oplog));
PHPDBG_G(oplog) = NULL;
}
if (PHPDBG_G(oplog_list)) {
phpdbg_oplog_list *cur = PHPDBG_G(oplog_list);
do {
@ -1134,8 +1128,6 @@ int main(int argc, char **argv) /* {{{ */
char *init_file;
size_t init_file_len;
bool init_file_default;
char *oplog_file;
size_t oplog_file_len;
uint64_t flags;
char *php_optarg;
int php_optind, opt, show_banner = 1;
@ -1186,8 +1178,6 @@ phpdbg_main:
init_file = NULL;
init_file_len = 0;
init_file_default = 1;
oplog_file = NULL;
oplog_file_len = 0;
flags = PHPDBG_DEFAULT_FLAGS;
is_exit = 0;
php_optarg = NULL;
@ -1281,13 +1271,6 @@ phpdbg_main:
}
} break;
case 'O': { /* set oplog output */
oplog_file_len = strlen(php_optarg);
if (oplog_file_len) {
oplog_file = strdup(php_optarg);
}
} break;
case 'v': /* set quietness off */
flags &= ~PHPDBG_IS_QUIET;
break;
@ -1442,9 +1425,6 @@ phpdbg_main:
if (exec) {
free(exec);
}
if (oplog_file) {
free(oplog_file);
}
if (init_file) {
free(init_file);
}
@ -1534,15 +1514,6 @@ phpdbg_main:
php_stream_stdio_ops.write = phpdbg_stdiop_write;
#endif
if (oplog_file) { /* open oplog */
PHPDBG_G(oplog) = fopen(oplog_file, "w+");
if (!PHPDBG_G(oplog)) {
phpdbg_error("Failed to open oplog %s", oplog_file);
}
free(oplog_file);
oplog_file = NULL;
}
{
zval *zv = zend_hash_str_find(php_stream_get_url_stream_wrappers_hash(), ZEND_STRL("php"));
php_stream_wrapper *tmp_wrapper = Z_PTR_P(zv);
@ -1757,7 +1728,6 @@ phpdbg_out:
settings->exec = zend_strndup(PHPDBG_G(exec), PHPDBG_G(exec_len));
settings->exec_len = PHPDBG_G(exec_len);
}
settings->oplog = PHPDBG_G(oplog);
settings->prompt[0] = PHPDBG_G(prompt)[0];
settings->prompt[1] = PHPDBG_G(prompt)[1];
memcpy(ZEND_VOIDP(settings->colors), PHPDBG_G(colors), sizeof(settings->colors));

View file

@ -100,15 +100,6 @@
#define PHPDBG_DEFAULT_PROMPT "prompt>"
/* }}} */
/* Hey, apple. One shouldn't define *functions* from the standard C library as macros. */
#ifdef memcpy
#define memcpy_tmp(...) memcpy(__VA_ARGS__)
#undef memcpy
#define memcpy(...) memcpy_tmp(__VA_ARGS__)
#endif
#if !defined(PHPDBG_WEBDATA_TRANSFER_H) && !defined(PHPDBG_WEBHELPER_H)
#ifdef ZTS
# define PHPDBG_G(v) ZEND_TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
#else
@ -123,7 +114,6 @@
#include "phpdbg_btree.h"
#include "phpdbg_watch.h"
#include "phpdbg_bp.h"
#include "phpdbg_opcode.h"
int phpdbg_do_parse(phpdbg_param_t *stack, char *input);
@ -223,6 +213,23 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input);
void phpdbg_register_file_handles(void);
typedef struct _phpdbg_oplog_entry phpdbg_oplog_entry;
struct _phpdbg_oplog_entry {
phpdbg_oplog_entry *next;
zend_string *function_name;
zend_class_entry *scope;
zend_string *filename;
zend_op *opcodes;
zend_op *op;
};
typedef struct _phpdbg_oplog_list phpdbg_oplog_list;
struct _phpdbg_oplog_list {
phpdbg_oplog_list *prev;
phpdbg_oplog_entry start; /* Only "next" member used. */
};
/* {{{ structs */
ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
HashTable bp[PHPDBG_BREAK_TABLES]; /* break points */
@ -266,7 +273,6 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
zend_op_array *(*compile_string)(zend_string *source_string, const char *filename);
HashTable file_sources;
FILE *oplog; /* opline log */
zend_arena *oplog_arena; /* arena for storing oplog */
phpdbg_oplog_list *oplog_list; /* list of oplog starts */
phpdbg_oplog_entry *oplog_cur; /* current oplog entry */
@ -304,6 +310,4 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
zend_ulong lines; /* max number of lines to display */
ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
#endif
#endif /* PHPDBG_H */

View file

@ -21,7 +21,6 @@
#include "phpdbg.h"
#include "phpdbg_bp.h"
#include "phpdbg_utils.h"
#include "phpdbg_opcode.h"
#include "zend_globals.h"
#include "ext/standard/php_string.h"

View file

@ -19,7 +19,6 @@
#include "phpdbg.h"
#include "phpdbg_print.h"
#include "phpdbg_utils.h"
#include "phpdbg_opcode.h"
#include "phpdbg_break.h"
#include "phpdbg_bp.h"
#include "phpdbg_prompt.h"

View file

@ -391,7 +391,6 @@ phpdbg_help_text_t phpdbg_help_text[] = {
" **-b** Disable colour" CR
" **-i** **-i**my.init Set .phpdbginit file" CR
" **-I** Ignore default .phpdbginit" CR
" **-O** **-O**my.oplog Sets oplog output file" CR
" **-r** Run execution context" CR
" **-rr** Run execution context and quit after execution (not respecting breakpoints)" CR
" **-e** Generate extended information for debugger/profiler" CR
@ -872,7 +871,6 @@ phpdbg_help_text_t phpdbg_help_text[] = {
" **prompt** **p** set the prompt" CR
" **color** **c** set color <element> <color>" CR
" **colors** **C** set colors [<on|off>]" CR
" **oplog** **O** set oplog [output]" CR
" **break** **b** set break **id** <on|off>" CR
" **breaks** **B** set breaks [<on|off>]" CR
" **quiet** **q** set quiet [<on|off>]" CR

View file

@ -1,192 +0,0 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 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: |
| https://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 "zend_vm_opcodes.h"
#include "zend_compile.h"
#include "phpdbg_opcode.h"
#include "phpdbg_utils.h"
#include "ext/standard/php_string.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
static inline const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */
{
const char *ret = zend_get_opcode_name(opcode);
if (ret) {
return ret + 5; /* Skip ZEND_ prefix */
}
return "UNKNOWN";
} /* }}} */
static inline char *phpdbg_decode_op(
zend_op_array *ops, const zend_op *opline, const znode_op *op, uint32_t type) /* {{{ */
{
char *decode = NULL;
switch (type) {
case IS_CV: {
zend_string *var = ops->vars[EX_VAR_TO_NUM(op->var)];
spprintf(&decode, 0, "$%.*s%c",
ZSTR_LEN(var) <= 19 ? (int) ZSTR_LEN(var) : 18,
ZSTR_VAL(var), ZSTR_LEN(var) <= 19 ? 0 : '+');
} break;
case IS_VAR:
spprintf(&decode, 0, "@%u", EX_VAR_TO_NUM(op->var) - ops->last_var);
break;
case IS_TMP_VAR:
spprintf(&decode, 0, "~%u", EX_VAR_TO_NUM(op->var) - ops->last_var);
break;
case IS_CONST: {
zval *literal = RT_CONSTANT(opline, *op);
decode = phpdbg_short_zval_print(literal, 20);
} break;
}
return decode;
} /* }}} */
char *phpdbg_decode_input_op(
zend_op_array *ops, const zend_op *opline, znode_op op, zend_uchar op_type,
uint32_t flags) {
char *result = NULL;
if (op_type != IS_UNUSED) {
result = phpdbg_decode_op(ops, opline, &op, op_type);
} else if (ZEND_VM_OP_JMP_ADDR == (flags & ZEND_VM_OP_MASK)) {
spprintf(&result, 0, "J%td", OP_JMP_ADDR(opline, op) - ops->opcodes);
} else if (ZEND_VM_OP_NUM == (flags & ZEND_VM_OP_MASK)) {
spprintf(&result, 0, "%" PRIu32, op.num);
} else if (ZEND_VM_OP_TRY_CATCH == (flags & ZEND_VM_OP_MASK)) {
if (op.num != (uint32_t)-1) {
spprintf(&result, 0, "try-catch(%" PRIu32 ")", op.num);
}
} else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) {
result = estrdup("THIS");
} else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) {
result = estrdup("NEXT");
} else if (ZEND_VM_OP_CLASS_FETCH == (flags & ZEND_VM_OP_MASK)) {
//zend_dump_class_fetch_type(op.num);
} else if (ZEND_VM_OP_CONSTRUCTOR == (flags & ZEND_VM_OP_MASK)) {
result = estrdup("CONSTRUCTOR");
}
return result;
}
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *opline) /*{{{ */
{
const char *opcode_name = phpdbg_decode_opcode(opline->opcode);
uint32_t flags = zend_get_opcode_flags(opline->opcode);
char *result, *decode[4] = {NULL, NULL, NULL, NULL};
/* OpcodeName */
if (opline->extended_value) {
spprintf(&decode[0], 0, "%s<%" PRIi32 ">", opcode_name, opline->extended_value);
}
/* OP1 */
decode[1] = phpdbg_decode_input_op(
ops, opline, opline->op1, opline->op1_type, ZEND_VM_OP1_FLAGS(flags));
/* OP2 */
decode[2] = phpdbg_decode_input_op(
ops, opline, opline->op2, opline->op2_type, ZEND_VM_OP2_FLAGS(flags));
/* RESULT */
switch (opline->opcode) {
case ZEND_CATCH:
if (opline->extended_value & ZEND_LAST_CATCH) {
if (decode[2]) {
efree(decode[2]);
decode[2] = NULL;
}
}
decode[3] = phpdbg_decode_op(ops, opline, &opline->result, opline->result_type);
break;
default:
decode[3] = phpdbg_decode_op(ops, opline, &opline->result, opline->result_type);
break;
}
spprintf(&result, 0,
"%-23s %-20s %-20s %-20s",
decode[0] ? decode[0] : opcode_name,
decode[1] ? decode[1] : "",
decode[2] ? decode[2] : "",
decode[3] ? decode[3] : "");
if (decode[0])
efree(decode[0]);
if (decode[1])
efree(decode[1]);
if (decode[2])
efree(decode[2]);
if (decode[3])
efree(decode[3]);
return result;
} /* }}} */
void phpdbg_print_opline_ex(zend_execute_data *execute_data, bool ignore_flags) /* {{{ */
{
/* 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 = (zend_op *) execute_data->opline;
char *decode = phpdbg_decode_opline(&execute_data->func->op_array, opline);
if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
/* output line info */
phpdbg_notice("L%-5u %16p %s %s",
opline->lineno,
opline,
decode,
execute_data->func->op_array.filename ? ZSTR_VAL(execute_data->func->op_array.filename) : "unknown");
}
if (!ignore_flags && PHPDBG_G(oplog)) {
phpdbg_log_internal(fileno(PHPDBG_G(oplog)), "L%-5u %16p %s %s\n",
opline->lineno,
opline,
decode,
execute_data->func->op_array.filename ? ZSTR_VAL(execute_data->func->op_array.filename) : "unknown");
}
efree(decode);
}
if (PHPDBG_G(oplog_list)) {
phpdbg_oplog_entry *cur = zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry));
zend_op_array *op_array = &execute_data->func->op_array;
cur->op = (zend_op *) execute_data->opline;
cur->opcodes = op_array->opcodes;
cur->filename = op_array->filename;
cur->scope = op_array->scope;
cur->function_name = op_array->function_name;
cur->next = NULL;
PHPDBG_G(oplog_cur)->next = cur;
PHPDBG_G(oplog_cur) = cur;
}
} /* }}} */
void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags) /* {{{ */
{
phpdbg_print_opline_ex(execute_data, ignore_flags);
} /* }}} */

View file

@ -1,44 +0,0 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 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: |
| https://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_OPCODE_H
#define PHPDBG_OPCODE_H
#include "zend_types.h"
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op);
void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags);
void phpdbg_print_opline_ex(zend_execute_data *execute_data, bool ignore_flags);
typedef struct _phpdbg_oplog_entry phpdbg_oplog_entry;
struct _phpdbg_oplog_entry {
phpdbg_oplog_entry *next;
zend_string *function_name;
zend_class_entry *scope;
zend_string *filename;
zend_op *opcodes;
zend_op *op;
};
typedef struct _phpdbg_oplog_list phpdbg_oplog_list;
struct _phpdbg_oplog_list {
phpdbg_oplog_list *prev;
phpdbg_oplog_entry start; /* Only "next" member used. */
};
#endif /* PHPDBG_OPCODE_H */

View file

@ -19,9 +19,10 @@
#include "phpdbg.h"
#include "phpdbg_print.h"
#include "phpdbg_utils.h"
#include "phpdbg_opcode.h"
#include "phpdbg_prompt.h"
#include "Optimizer/zend_dump.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s, flags) \
@ -55,44 +56,13 @@ static inline void phpdbg_print_function_helper(zend_function *method) /* {{{ */
zend_op_array* op_array = &(method->op_array);
if (op_array) {
zend_op *opline = &(op_array->opcodes[0]);
uint32_t opcode = 0,
end = op_array->last-1;
if (method->common.scope) {
phpdbg_writeln("L%d-%d %s::%s() %s - %p + %d ops",
op_array->line_start,
op_array->line_end,
ZSTR_VAL(method->common.scope->name),
ZSTR_VAL(method->common.function_name),
op_array->filename ? ZSTR_VAL(op_array->filename) : "unknown",
opline,
op_array->last);
} else {
phpdbg_writeln("L%d-%d %s() %s - %p + %d ops",
op_array->line_start,
op_array->line_end,
method->common.function_name ? ZSTR_VAL(method->common.function_name) : "{main}",
op_array->filename ? ZSTR_VAL(op_array->filename) : "unknown",
opline,
op_array->last);
}
do {
char *decode = phpdbg_decode_opline(op_array, opline);
phpdbg_writeln(" L%-4u #%-5u %s",
opline->lineno,
opcode,
decode);
efree(decode);
opline++;
} while (opcode++ < end);
zend_dump_op_array(op_array, ZEND_DUMP_LINE_NUMBERS, NULL, NULL);
for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
zend_op_array *def = op_array->dynamic_func_defs[i];
phpdbg_out("\ndynamic def: %i, function name: %.*s\n",
i, (int) ZSTR_LEN(def->function_name), ZSTR_VAL(def->function_name));
phpdbg_print_function_helper((zend_function *) def);
zend_dump_op_array(def, ZEND_DUMP_LINE_NUMBERS, NULL, NULL);
}
}
} break;
@ -123,7 +93,7 @@ PHPDBG_PRINT(exec) /* {{{ */
phpdbg_error("No execution context set");
}
return SUCCESS;
return SUCCESS;
} /* }}} */
PHPDBG_PRINT(stack) /* {{{ */
@ -261,7 +231,6 @@ PHPDBG_PRINT(func) /* {{{ */
} /* }}} */
void phpdbg_print_opcodes_main(void) {
phpdbg_out("function name: (null)\n");
phpdbg_print_function_helper((zend_function *) PHPDBG_G(ops));
}
@ -269,19 +238,10 @@ void phpdbg_print_opcodes_function(const char *function, size_t len) {
zend_function *func = zend_hash_str_find_ptr(EG(function_table), function, len);
if (!func) {
zend_string *rt_name;
ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), rt_name, func) {
if (func->type == ZEND_USER_FUNCTION && *rt_name->val == '\0') {
if (func->op_array.function_name->len == len && !zend_binary_strcasecmp(function, len, func->op_array.function_name->val, func->op_array.function_name->len)) {
phpdbg_print_opcodes_function(rt_name->val, rt_name->len);
}
}
} ZEND_HASH_FOREACH_END();
phpdbg_error("The function %s could not be found", function);
return;
}
phpdbg_out("function name: %.*s\n", (int) ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name));
phpdbg_print_function_helper(func);
}
@ -294,10 +254,10 @@ static void phpdbg_print_opcodes_method_ce(zend_class_entry *ce, const char *fun
}
if (!(func = zend_hash_str_find_ptr(&ce->function_table, function, strlen(function)))) {
phpdbg_error("The method %s::%s could not be found", ZSTR_VAL(ce->name), function);
return;
}
phpdbg_out("function name: %s::%s\n", ce->name->val, function);
phpdbg_print_function_helper(func);
}
@ -305,15 +265,7 @@ void phpdbg_print_opcodes_method(const char *class, const char *function) {
zend_class_entry *ce;
if (phpdbg_safe_class_lookup(class, strlen(class), &ce) != SUCCESS) {
zend_string *rt_name;
ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), rt_name, ce) {
if (ce->type == ZEND_USER_CLASS && *rt_name->val == '\0') {
if (ce->name->len == strlen(class) && !zend_binary_strcasecmp(class, strlen(class), ce->name->val, ce->name->len)) {
phpdbg_print_opcodes_method_ce(ce, function);
}
}
} ZEND_HASH_FOREACH_END();
phpdbg_error("The class %s could not be found", class);
return;
}
@ -322,7 +274,6 @@ void phpdbg_print_opcodes_method(const char *class, const char *function) {
static void phpdbg_print_opcodes_ce(zend_class_entry *ce) {
zend_function *method;
zend_string *method_name;
bool first = 1;
phpdbg_out("%s %s: %s\n",
@ -353,8 +304,7 @@ static void phpdbg_print_opcodes_ce(zend_class_entry *ce) {
}
phpdbg_out("\n");
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, method_name, method) {
phpdbg_out("\nfunction name: %s\n", ZSTR_VAL(method_name));
ZEND_HASH_FOREACH_PTR(&ce->function_table, method) {
phpdbg_print_function_helper(method);
} ZEND_HASH_FOREACH_END();
}
@ -363,22 +313,14 @@ void phpdbg_print_opcodes_class(const char *class) {
zend_class_entry *ce;
if (phpdbg_safe_class_lookup(class, strlen(class), &ce) != SUCCESS) {
zend_string *rt_name;
ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), rt_name, ce) {
if (ce->type == ZEND_USER_CLASS && *rt_name->val == '\0') {
if (ce->name->len == strlen(class) && !zend_binary_strcasecmp(class, strlen(class), ce->name->val, ce->name->len)) {
phpdbg_print_opcodes_ce(ce);
}
}
} ZEND_HASH_FOREACH_END();
phpdbg_error("The class %s could not be found", class);
return;
}
phpdbg_print_opcodes_ce(ce);
}
PHPDBG_API void phpdbg_print_opcodes(const char *function)
void phpdbg_print_opcodes(const char *function)
{
if (function == NULL) {
phpdbg_print_opcodes_main();
@ -392,14 +334,13 @@ PHPDBG_API void phpdbg_print_opcodes(const char *function)
ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), name, func) {
if (func->type == ZEND_USER_FUNCTION) {
phpdbg_out("\n");
phpdbg_print_opcodes_function(ZSTR_VAL(name), ZSTR_LEN(name));
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(EG(class_table), ce) {
if (ce->type == ZEND_USER_CLASS) {
phpdbg_out("\n\n");
phpdbg_out("\n");
phpdbg_print_opcodes_ce(ce);
}
} ZEND_HASH_FOREACH_END();
@ -420,3 +361,23 @@ PHPDBG_API void phpdbg_print_opcodes(const char *function)
efree(function_lowercase);
}
}
void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags) /* {{{ */
{
if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) && (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) {
zend_dump_op_line(&EX(func)->op_array, NULL, EX(opline), ZEND_DUMP_LINE_NUMBERS, NULL);
}
if (PHPDBG_G(oplog_list)) {
phpdbg_oplog_entry *cur = zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry));
zend_op_array *op_array = &EX(func)->op_array;
cur->op = (zend_op *) EX(opline);
cur->opcodes = op_array->opcodes;
cur->filename = op_array->filename;
cur->scope = op_array->scope;
cur->function_name = op_array->function_name;
cur->next = NULL;
PHPDBG_G(oplog_cur)->next = cur;
PHPDBG_G(oplog_cur) = cur;
}
} /* }}} */

View file

@ -33,8 +33,9 @@ PHPDBG_PRINT(method);
PHPDBG_PRINT(func);
PHPDBG_PRINT(stack);
PHPDBG_API void phpdbg_print_opcodes(const char *function);
extern const phpdbg_command_t phpdbg_print_commands[];
void phpdbg_print_opcodes(const char *function);
void phpdbg_print_opline(zend_execute_data *execute_data, bool ignore_flags);
#endif /* PHPDBG_PRINT_H */

View file

@ -32,7 +32,6 @@
#include "phpdbg_print.h"
#include "phpdbg_info.h"
#include "phpdbg_break.h"
#include "phpdbg_opcode.h"
#include "phpdbg_list.h"
#include "phpdbg_utils.h"
#include "phpdbg_prompt.h"
@ -1107,7 +1106,6 @@ PHPDBG_COMMAND(info) /* {{{ */
phpdbg_writeln("Compiled %s", PHPDBG_G(ops) ? "yes" : "no");
phpdbg_writeln("Stepping %s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off");
phpdbg_writeln("Quietness %s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off");
phpdbg_writeln("Oplog %s", PHPDBG_G(oplog) ? "on" : "off");
if (PHPDBG_G(ops)) {
phpdbg_writeln("Opcodes %d", PHPDBG_G(ops)->last);
@ -1676,7 +1674,7 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */
}
if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
phpdbg_print_opline_ex(execute_data, 0);
phpdbg_print_opline(execute_data, 0);
goto next;
}
@ -1720,7 +1718,7 @@ ex_is_caught:
}
/* not while in conditionals */
phpdbg_print_opline_ex(execute_data, 0);
phpdbg_print_opline(execute_data, 0);
/* perform seek operation */
if ((PHPDBG_G(flags) & PHPDBG_SEEK_MASK) && !(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {

View file

@ -35,7 +35,6 @@ const phpdbg_command_t phpdbg_set_commands[] = {
PHPDBG_SET_COMMAND_D(color, "usage: set color <element> <color>", 'c', set_color, NULL, "ss", PHPDBG_ASYNC_SAFE),
PHPDBG_SET_COMMAND_D(colors, "usage: set colors [<on|off>]", 'C', set_colors, NULL, "|b", PHPDBG_ASYNC_SAFE),
#endif
PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog [<output>]", 'O', set_oplog, NULL, "|s", 0),
PHPDBG_SET_COMMAND_D(break, "usage: set break id [<on|off>]", 'b', set_break, NULL, "l|b", PHPDBG_ASYNC_SAFE),
PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks [<on|off>]", 'B', set_breaks, NULL, "|b", PHPDBG_ASYNC_SAFE),
PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet [<on|off>]", 'q', set_quiet, NULL, "|b", PHPDBG_ASYNC_SAFE),
@ -197,35 +196,6 @@ PHPDBG_SET(colors) /* {{{ */
} /* }}} */
#endif
PHPDBG_SET(oplog) /* {{{ */
{
if (!param || param->type == EMPTY_PARAM) {
phpdbg_notice("Oplog %s", PHPDBG_G(oplog) ? "on" : "off");
} else switch (param->type) {
case STR_PARAM: {
/* open oplog */
FILE *old = PHPDBG_G(oplog);
PHPDBG_G(oplog) = fopen(param->str, "w+");
if (!PHPDBG_G(oplog)) {
phpdbg_error("Failed to open %s for oplog", param->str);
PHPDBG_G(oplog) = old;
} else {
if (old) {
phpdbg_notice("Closing previously open oplog");
fclose(old);
}
phpdbg_notice("Successfully opened oplog %s", param->str);
}
} break;
phpdbg_default_switch_case();
}
return SUCCESS;
} /* }}} */
PHPDBG_SET(quiet) /* {{{ */
{
if (!param || param->type == EMPTY_PARAM) {

View file

@ -28,7 +28,6 @@ PHPDBG_SET(prompt);
PHPDBG_SET(color);
PHPDBG_SET(colors);
#endif
PHPDBG_SET(oplog);
PHPDBG_SET(break);
PHPDBG_SET(breaks);
PHPDBG_SET(quiet);

View file

@ -20,7 +20,6 @@
#include "php.h"
#include "phpdbg.h"
#include "phpdbg_opcode.h"
#include "phpdbg_utils.h"
#include "ext/standard/php_string.h"

View file

@ -16,28 +16,22 @@ prompt> [Breakpoint #0 at %s:5, hits: 1]
>00005: x();
00006: } finally {
00007: print "ok\n";
prompt> [L0 %s HANDLE_EXCEPTION %s]
>00005: x();
prompt> >00005: x();
00006: } finally {
00007: print "ok\n";
prompt> [L7 %s ECHO<1> "ok\n" %s]
>00007: print "ok\n";
prompt> >00007: print "ok\n";
00008: }
00009: } catch (Error $e) {
prompt> ok
[L7 %s FAST_RET ~%d try-catch(0) %s]
[L9 %s CATCH<%d> %s "Error" $e %s]
>00005: x();
00006: } finally {
00007: print "ok\n";
prompt> [L10 %s ECHO<1> "caught\n" %s]
>00010: print "caught\n";
prompt> >00010: print "caught\n";
00011: }
00012:
prompt> caught
[L14 %s RETURN<-1> 1 %s]
>00014:
prompt>
prompt>
--FILE--
<?php

View file

@ -11,27 +11,25 @@ q
[Successful compilation of %s]
prompt> [Breakpoint #0 added at %s:4]
prompt> [Breakpoint #0 at %s:4, hits: 1]
>00004: echo 0;
>00004: echo 0 . PHP_EOL;
00005: }
00006:
prompt> 0
[L5 %s RETURN<-1> null %s]
>00005: }
00006:
00007: foo();
prompt> [L8 %s ECHO 1 %s]
>00008: echo 1;
prompt> >00008: echo 1 . PHP_EOL;
00009:
prompt> 1
[L9 %s RETURN<-1> 1 %s]
>00009:
prompt>
prompt>
--FILE--
<?php
function foo() {
echo 0;
echo 0 . PHP_EOL;
}
foo();
echo 1;
echo 1 . PHP_EOL;

View file

@ -11,36 +11,48 @@ q
--EXPECTF--
[Successful compilation of %s]
prompt> [User Function foo (8 ops)]
L14-16 foo() %s - %s + 8 ops
L14 #0 RECV 1 $baz
L15 #1 INIT_FCALL%s %d %s "var_dump"
L15 #2 INIT_FCALL%s %d %s "strrev"
L15 #3 SEND_VAR $baz 1
L15 #4 DO_%cCALL @0
L15 #5 SEND_VAR @0 1
L15 #6 DO_%cCALL
L16 #7 RETURN<-1> null
foo:
; (lines=8, args=1, vars=1, tmps=2)
; %s:14-16
L0014 0000 CV0($baz) = RECV 1
L0015 0001 INIT_FCALL %d %d string("var_dump")
L0015 0002 INIT_FCALL %d %d string("strrev")
L0015 0003 SEND_VAR CV0($baz) 1
L0015 0004 V1 = DO_ICALL
L0015 0005 SEND_VAR V1 1
L0015 0006 DO_ICALL
L0016 0007 RETURN null
prompt> [User Class: Foo\Bar (2 methods)]
L5-7 Foo\Bar::Foo() %s - %s + 5 ops
L5 #0 RECV 1 $bar
L6 #1 INIT_NS_FCALL_BY_NAME<1> "Foo\\var_dump"
L6 #2 SEND_VAR_EX $bar 1
L6 #3 DO_FCALL
L7 #4 RETURN<-1> null
L9-9 Foo\Bar::baz() %s - %s + 1 ops
L9 #0 RETURN<-1> null
Foo\Bar::Foo:
; (lines=5, args=1, vars=1, tmps=1)
; %s:5-7
L0005 0000 CV0($bar) = RECV 1
L0006 0001 INIT_NS_FCALL_BY_NAME 1 string("Foo\var_dump")
L0006 0002 SEND_VAR_EX CV0($bar) 1
L0006 0003 DO_FCALL
L0007 0004 RETURN null
Foo\Bar::baz:
; (lines=1, args=0, vars=0, tmps=0)
; %s:9-9
L0009 0000 RETURN null
prompt> [Not Executing!]
prompt> [Context %s (9 ops)]
L1-21 {main}() %s - %s + 9 ops
L18 #0 NEW "Foo\\Bar" @0
L18 #1 DO_FCALL
L18 #2 INIT_METHOD_CALL<1> @0 "Foo"
L18 #3 SEND_VAL_EX "test" 1
L18 #4 DO_FCALL
L19 #5 INIT_FCALL%s %d %s "foo"
L19 #6 SEND_VAL "test" 1
L19 #7 DO_FCALL
L21 #8 RETURN<-1> 1
$_main:
; (lines=9, args=0, vars=0, tmps=4)
; %s:1-21
L0018 0000 V0 = NEW 0 string("Foo\Bar")
L0018 0001 DO_FCALL
L0018 0002 INIT_METHOD_CALL 1 V0 string("Foo")
L0018 0003 SEND_VAL_EX string("test") 1
L0018 0004 DO_FCALL
L0019 0005 INIT_FCALL %d %d string("foo")
L0019 0006 SEND_VAL string("test") 1
L0019 0007 DO_FCALL
L0021 0008 RETURN int(1)
prompt>
--FILE--
<?php

View file

@ -17,16 +17,19 @@ prompt> string(4) "test"
00016: }
00017:
prompt> [Stack in foo() (8 ops)]
L14-16 foo() %s - %s + 8 ops
L14 #0 RECV 1 $baz
L15 #1 INIT_FCALL%s %d %s "var_dump"
L15 #2 INIT_FCALL%s %d %s "strrev"
L15 #3 SEND_VAR $baz 1
L15 #4 DO_%cCALL @0
L15 #5 SEND_VAR @0 1
L15 #6 DO_%cCALL
L16 #7 RETURN<-1> null
prompt> [L15 %s INIT_FCALL%s %d %s "var_dump" %s]
foo:
; (lines=8, args=1, vars=1, tmps=2)
; %s:14-16
L0014 0000 CV0($baz) = RECV 1
L0015 0001 INIT_FCALL %d %d string("var_dump")
L0015 0002 INIT_FCALL %d %d string("strrev")
L0015 0003 SEND_VAR CV0($baz) 1
L0015 0004 V1 = DO_ICALL
L0015 0005 SEND_VAR V1 1
L0015 0006 DO_ICALL
L0016 0007 RETURN null
prompt> L0015 0001 INIT_FCALL %d %d string("var_dump")
prompt>
--FILE--
<?php

View file

@ -20,37 +20,28 @@ prompt> [Breakpoint #0 in ZEND_THROW at %s:4, hits: 1]
>00004: throw new Exception;
00005: }
00006:
prompt> [L0 %s HANDLE_EXCEPTION %s]
>00004: throw new Exception;
prompt> >00004: throw new Exception;
00005: }
00006:
prompt> [L0 %s HANDLE_EXCEPTION %s]
[L9 %s CATCH<%d> "Exception" $e %s]
>00008: foo();
prompt> >00008: foo();
00009: } catch (Exception $e) {
00010: echo "ok";
prompt> [L10 %s ECHO "ok" %s]
>00010: echo "ok";
00010: echo "ok\n";
prompt> >00010: echo "ok\n";
00011: } finally {
00012: echo " ... ok";
00012: echo " ... ok\n";
prompt> ok
[L11 %s FAST_CALL J7 ~%d %s]
>00011: } finally {
00012: echo " ... ok";
00012: echo " ... ok\n";
00013: }
prompt> [L12 %s ECHO " ... ok" %s]
>00012: echo " ... ok";
prompt> >00012: echo " ... ok\n";
00013: }
00014:
prompt> ... ok
[L12 %s FAST_RET ~%d %s]
[L11 %s JMP J9 %s]
>00011: } finally {
00012: echo " ... ok";
00012: echo " ... ok\n";
00013: }
prompt> [L14 %s RETURN<-1> 1 %s]
>00014:
prompt>
prompt> >00014:
prompt>
--FILE--
<?php
@ -61,7 +52,7 @@ function foo() {
try {
foo();
} catch (Exception $e) {
echo "ok";
echo "ok\n";
} finally {
echo " ... ok";
echo " ... ok\n";
}