/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://www.php.net/license/2_02.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: Derick Rethans <derick@derickrethans.nl> |
| Andrei Zmievski <andrei@gravitonic.com> |
| Marcus Börger <marcus.boerger@t-online.de> |
+----------------------------------------------------------------------+
*/
/* $Id: srm_oparray.c,v 1.53 2007-11-29 13:12:32 derick Exp $ */
#include "php.h"
#include "zend_alloc.h"
#include "srm_oparray.h"
#include "ext/standard/url.h"
#include "set.h"
#include "php_vld.h"
ZEND_EXTERN_MODULE_GLOBALS(vld)
/* Input zend_compile.h
* And replace [^(...)(#define )([^ \t]+).*$]
* BY [/=* \1 *=/ { "\3", ALL_USED },] REMEMBER to remove the two '=' signs
*/
static const op_usage opcodes[] = {
/* 0 */ { "NOP", NONE_USED },
/* 1 */ { "ADD", ALL_USED },
/* 2 */ { "SUB", ALL_USED },
/* 3 */ { "MUL", ALL_USED },
/* 4 */ { "DIV", ALL_USED },
/* 5 */ { "MOD", ALL_USED },
/* 6 */ { "SL", ALL_USED },
/* 7 */ { "SR", ALL_USED },
/* 8 */ { "CONCAT", ALL_USED },
/* 9 */ { "BW_OR", ALL_USED },
/* 10 */ { "BW_AND", ALL_USED },
/* 11 */ { "BW_XOR", ALL_USED },
/* 12 */ { "BW_NOT", RES_USED | OP1_USED },
/* 13 */ { "BOOL_NOT", RES_USED | OP1_USED },
/* 14 */ { "BOOL_XOR", ALL_USED },
/* 15 */ { "IS_IDENTICAL", ALL_USED },
/* 16 */ { "IS_NOT_IDENTICAL", ALL_USED },
/* 17 */ { "IS_EQUAL", ALL_USED },
/* 18 */ { "IS_NOT_EQUAL", ALL_USED },
/* 19 */ { "IS_SMALLER", ALL_USED },
/* 20 */ { "IS_SMALLER_OR_EQUAL", ALL_USED },
/* 21 */ { "CAST", ALL_USED },
/* 22 */ { "QM_ASSIGN", RES_USED | OP1_USED },
/* 23 */ { "ASSIGN_ADD", ALL_USED },
/* 24 */ { "ASSIGN_SUB", ALL_USED },
/* 25 */ { "ASSIGN_MUL", ALL_USED },
/* 26 */ { "ASSIGN_DIV", ALL_USED },
/* 27 */ { "ASSIGN_MOD", ALL_USED },
/* 28 */ { "ASSIGN_SL", ALL_USED },
/* 29 */ { "ASSIGN_SR", ALL_USED },
/* 30 */ { "ASSIGN_CONCAT", ALL_USED },
/* 31 */ { "ASSIGN_BW_OR", ALL_USED },
/* 32 */ { "ASSIGN_BW_AND", ALL_USED },
/* 33 */ { "ASSIGN_BW_XOR", ALL_USED },
/* 34 */ { "PRE_INC", OP1_USED | RES_USED },
/* 35 */ { "PRE_DEC", OP1_USED | RES_USED },
/* 36 */ { "POST_INC", OP1_USED | RES_USED },
/* 37 */ { "POST_DEC", OP1_USED | RES_USED },
/* 38 */ { "ASSIGN", ALL_USED },
/* 39 */ { "ASSIGN_REF", SPECIAL },
/* 40 */ { "ECHO", OP1_USED },
/* 41 */ { "PRINT", RES_USED | OP1_USED },
/* 42 */ { "JMP", OP1_USED | OP1_OPLINE },
/* 43 */ { "JMPZ", OP1_USED | OP2_USED | OP2_OPLINE },
/* 44 */ { "JMPNZ", OP1_USED | OP2_USED | OP2_OPLINE },
/* 45 */ { "JMPZNZ", SPECIAL },
/* 46 */ { "JMPZ_EX", ALL_USED | OP2_OPLINE },
/* 47 */ { "JMPNZ_EX", ALL_USED | OP2_OPLINE },
/* 48 */ { "CASE", ALL_USED },
/* 49 */ { "SWITCH_FREE", RES_USED | OP1_USED },
/* 50 */ { "BRK", ALL_USED },
/* 51 */ { "CONT", ALL_USED },
/* 52 */ { "BOOL", RES_USED | OP1_USED },
/* 53 */ { "INIT_STRING", RES_USED },
/* 54 */ { "ADD_CHAR", ALL_USED },
/* 55 */ { "ADD_STRING", ALL_USED },
/* 56 */ { "ADD_VAR", ALL_USED },
/* 57 */ { "BEGIN_SILENCE", ALL_USED },
/* 58 */ { "END_SILENCE", ALL_USED },
/* 59 */ { "INIT_FCALL_BY_NAME", SPECIAL },
/* 60 */ { "DO_FCALL", SPECIAL },
/* 61 */ { "DO_FCALL_BY_NAME", SPECIAL },
/* 62 */ { "RETURN", OP1_USED },
/* 63 */ { "RECV", RES_USED | OP1_USED },
/* 64 */ { "RECV_INIT", ALL_USED },
/* 65 */ { "SEND_VAL", OP1_USED },
/* 66 */ { "SEND_VAR", OP1_USED },
/* 67 */ { "SEND_REF", ALL_USED },
/* 68 */ { "NEW", SPECIAL },
#if (PHP_MAJOR_VERSION < 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1)
/* 69 */ { "JMP_NO_CTOR", SPECIAL },
#else
/* 69 */ { "UNKNOWN", ALL_USED },
#endif
/* 70 */ { "FREE", OP1_USED },
/* 71 */ { "INIT_ARRAY", ALL_USED },
/* 72 */ { "ADD_ARRAY_ELEMENT", ALL_USED },
/* 73 */ { "INCLUDE_OR_EVAL", ALL_USED | OP2_INCLUDE },
/* 74 */ { "UNSET_VAR", ALL_USED },
#ifdef ZEND_ENGINE_2
/* 75 */ { "UNSET_DIM", ALL_USED },
/* 76 */ { "UNSET_OBJ", ALL_USED },
#else
/* 75 */ { "UNSET_DIM_OBJ", ALL_USED },
/* 76 */ { "ISSET_ISEMPTY", ALL_USED },
#endif
/* 77 */ { "FE_RESET", SPECIAL },
/* 78 */ { "FE_FETCH", ALL_USED | OP2_OPNUM },
/* 79 */ { "EXIT", ALL_USED },
/* 80 */ { "FETCH_R", RES_USED | OP1_USED | OP_FETCH },
/* 81 */ { "FETCH_DIM_R", ALL_USED },
/* 82 */ { "FETCH_OBJ_R", ALL_USED },
/* 83 */ { "FETCH_W", RES_USED | OP1_USED | OP_FETCH },
/* 84 */ { "FETCH_DIM_W", ALL_USED },
/* 85 */ { "FETCH_OBJ_W", ALL_USED },
/* 86 */ { "FETCH_RW", RES_USED | OP1_USED | OP_FETCH },
/* 87 */ { "FETCH_DIM_RW", ALL_USED },
/* 88 */ { "FETCH_OBJ_RW", ALL_USED },
/* 89 */ { "FETCH_IS", ALL_USED },
/* 90 */ { "FETCH_DIM_IS", ALL_USED },
/* 91 */ { "FETCH_OBJ_IS", ALL_USED },
/* 92 */ { "FETCH_FUNC_ARG", RES_USED | OP1_USED | OP_FETCH },
/* 93 */ { "FETCH_DIM_FUNC_ARG", ALL_USED },
/* 94 */ { "FETCH_OBJ_FUNC_ARG", ALL_USED },
/* 95 */ { "FETCH_UNSET", ALL_USED },
/* 96 */ { "FETCH_DIM_UNSET", ALL_USED },
/* 97 */ { "FETCH_OBJ_UNSET", ALL_USED },
/* 98 */ { "FETCH_DIM_TMP_VAR", ALL_USED },
/* 99 */ { "FETCH_CONSTANT", ALL_USED },
/* 100 */ { "DECLARE_FUNCTION_OR_CLASS", ALL_USED },
/* 101 */ { "EXT_STMT", ALL_USED },
/* 102 */ { "EXT_FCALL_BEGIN", ALL_USED },
/* 103 */ { "EXT_FCALL_END", ALL_USED },
/* 104 */ { "EXT_NOP", ALL_USED },
/* 105 */ { "TICKS", ALL_USED },
/* 106 */ { "SEND_VAR_NO_REF", ALL_USED },
#ifdef ZEND_ENGINE_2
/* 107 */ { "ZEND_CATCH", ALL_USED | EXT_VAL },
/* 108 */ { "ZEND_THROW", ALL_USED | EXT_VAL },
/* 109 */ { "ZEND_FETCH_CLASS", SPECIAL },
/* 110 */ { "ZEND_CLONE", ALL_USED },
/* 111 */ { "ZEND_INIT_CTOR_CALL", ALL_USED },
/* 112 */ { "ZEND_INIT_METHOD_CALL", ALL_USED },
/* 113 */ { "ZEND_INIT_STATIC_METHOD_CALL", ALL_USED },
/* 114 */ { "ZEND_ISSET_ISEMPTY_VAR", ALL_USED | EXT_VAL },
/* 115 */ { "ZEND_ISSET_ISEMPTY_DIM_OBJ", ALL_USED | EXT_VAL },
/* 116 */ { "ZEND_IMPORT_FUNCTION", ALL_USED },
/* 117 */ { "ZEND_IMPORT_CLASS", ALL_USED },
/* 118 */ { "ZEND_IMPORT_CONST", ALL_USED },
/* 119 */ { "119", ALL_USED },
/* 120 */ { "120", ALL_USED },
/* 121 */ { "ZEND_ASSIGN_ADD_OBJ", ALL_USED },
/* 122 */ { "ZEND_ASSIGN_SUB_OBJ", ALL_USED },
/* 123 */ { "ZEND_ASSIGN_MUL_OBJ", ALL_USED },
/* 124 */ { "ZEND_ASSIGN_DIV_OBJ", ALL_USED },
/* 125 */ { "ZEND_ASSIGN_MOD_OBJ", ALL_USED },
/* 126 */ { "ZEND_ASSIGN_SL_OBJ", ALL_USED },
/* 127 */ { "ZEND_ASSIGN_SR_OBJ", ALL_USED },
/* 128 */ { "ZEND_ASSIGN_CONCAT_OBJ", ALL_USED },
/* 129 */ { "ZEND_ASSIGN_BW_OR_OBJ", ALL_USED },
/* 130 */ { "ZEND_ASSIGN_BW_AND_OBJ", ALL_USED },
/* 131 */ { "ZEND_ASSIGN_BW_XOR_OBJ", ALL_USED },
/* 132 */ { "ZEND_PRE_INC_OBJ", ALL_USED },
/* 133 */ { "ZEND_PRE_DEC_OBJ", ALL_USED },
/* 134 */ { "ZEND_POST_INC_OBJ", ALL_USED },
/* 135 */ { "ZEND_POST_DEC_OBJ", ALL_USED },
/* 136 */ { "ZEND_ASSIGN_OBJ", ALL_USED },
/* 137 */ { "ZEND_OP_DATA", ALL_USED },
/* 138 */ { "ZEND_INSTANCEOF", ALL_USED },
/* 139 */ { "ZEND_DECLARE_CLASS", ALL_USED },
/* 140 */ { "ZEND_DECLARE_INHERITED_CLASS", ALL_USED },
/* 141 */ { "ZEND_DECLARE_FUNCTION", ALL_USED },
/* 142 */ { "ZEND_RAISE_ABSTRACT_ERROR", ALL_USED },
/* 143 */ { "ZEND_START_NAMESPACE", ALL_USED },
/* 144 */ { "ZEND_ADD_INTERFACE", ALL_USED },
/* 145 */ { "ZEND_VERIFY_INSTANCEOF", ALL_USED },
/* 146 */ { "ZEND_VERIFY_ABSTRACT_CLASS", ALL_USED },
/* 147 */ { "ZEND_ASSIGN_DIM", ALL_USED },
/* 148 */ { "ZEND_ISSET_ISEMPTY_PROP_OBJ", ALL_USED },
/* 149 */ { "ZEND_HANDLE_EXCEPTION", NONE_USED },
#ifdef ZEND_USER_OPCODE
/* 150 */ { "ZEND_USER_OPCODE", ALL_USED },
#ifdef ZEND_U_NORMALIZE
/* 151 */ { "ZEND_U_NORMALIZE", RES_USED | OP1_USED },
#ifdef ZEND_JMP_SET
/* 152 */ { "ZEND_JMP_SET", ALL_USED | OP2_OPLINE },
#endif
#endif
#endif
#endif
};
inline int vld_dump_zval_null(zvalue_value value)
{
return vld_printf (stderr, "null");
}
inline int vld_dump_zval_long(zvalue_value value)
{
return vld_printf (stderr, "%ld", value.lval);
}
inline int vld_dump_zval_double(zvalue_value value)
{
return vld_printf (stderr, "%g", value.dval);
}
inline int vld_dump_zval_string(zvalue_value value)
{
char *new_str;
int new_len, len;
new_str = php_url_encode(value.str.val, value.str.len, &new_len);
len = vld_printf (stderr, "'%s'", new_str);
efree(new_str);
return len;
}
#if PHP_VERSION_ID >= 60000
inline int vld_dump_zval_unicode(zvalue_value value)
{
int len;
len = vld_printf(stderr, "%R", IS_UNICODE, value.ustr.val);
return len;
}
#endif
inline int vld_dump_zval_array(zvalue_value value)
{
return vld_printf (stderr, "<array>");
}
inline int vld_dump_zval_object(zvalue_value value)
{
return vld_printf (stderr, "<object>");
}
inline int vld_dump_zval_bool(zvalue_value value)
{
return vld_printf (stderr, value.lval ? "true" : "false");
}
inline int vld_dump_zval_resource(zvalue_value value)
{
return vld_printf (stderr, "<resource>");
}
inline int vld_dump_zval_constant(zvalue_value value)
{
return vld_printf (stderr, "<const>");
}
inline int vld_dump_zval_constant_array(zvalue_value value)
{
return vld_printf (stderr, "<const array>");
}
int vld_dump_zval (zval val)
{
switch (val.type) {
case IS_NULL: return vld_dump_zval_null (val.value);
case IS_LONG: return vld_dump_zval_long (val.value);
case IS_DOUBLE: return vld_dump_zval_double (val.value);
case IS_STRING: return vld_dump_zval_string (val.value);
case IS_ARRAY: return vld_dump_zval_array (val.value);
case IS_OBJECT: return vld_dump_zval_object (val.value);
case IS_BOOL: return vld_dump_zval_bool (val.value);
case IS_RESOURCE: return vld_dump_zval_resource (val.value);
case IS_CONSTANT: return vld_dump_zval_constant (val.value);
case IS_CONSTANT_ARRAY: return vld_dump_zval_constant_array (val.value);
#if PHP_VERSION_ID >= 60000
case IS_UNICODE: return vld_dump_zval_unicode (val.value);
#endif
}
return vld_printf(stderr, "<unknown>");
}
int vld_dump_znode (int *print_sep, znode node, zend_uint base_address TSRMLS_DC)
{
int len = 0;
if (node.op_type != IS_UNUSED && print_sep) {
if (*print_sep) {
len += vld_printf (stderr, ", ");
}
*print_sep = 1;
}
switch (node.op_type) {
case IS_UNUSED:
VLD_PRINT(3, " IS_UNUSED ");
break;
case IS_CONST: /* 1 */
VLD_PRINT(3, " IS_CONST (%d) ", node.u.var / sizeof(temp_variable));
vld_dump_zval (node.u.constant);
break;
#ifdef ZEND_ENGINE_2
case IS_TMP_VAR: /* 2 */
VLD_PRINT(3, " IS_TMP_VAR ");
len += vld_printf (stderr, "~%d", node.u.var / sizeof(temp_variable));
break;
case IS_VAR: /* 4 */
VLD_PRINT(3, " IS_VAR ");
len += vld_printf (stderr, "$%d", node.u.var / sizeof(temp_variable));
break;
#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)
case IS_CV: /* 16 */
VLD_PRINT(3, " IS_CV ");
len += vld_printf (stderr, "!%d", node.u.var);
break;
#endif
case VLD_IS_OPNUM:
len += vld_printf (stderr, "->%d", node.u.opline_num);
break;
case VLD_IS_OPLINE:
len += vld_printf (stderr, "->%d", (node.u.opline_num - base_address) / sizeof(zend_op));
break;
case VLD_IS_CLASS:
len += vld_printf (stderr, ":%d", node.u.var / sizeof(temp_variable));
break;
#else
case IS_TMP_VAR: /* 2 */
len += vld_printf (stderr, "~%d", node.u.var);
break;
case IS_VAR: /* 4 */
len += vld_printf (stderr, "$%d", node.u.var);
break;
case VLD_IS_OPNUM:
case VLD_IS_OPLINE:
len += vld_printf (stderr, "->%d", node.u.opline_num);
break;
case VLD_IS_CLASS:
len += vld_printf (stderr, ":%d", node.u.var);
break;
#endif
default:
return 0;
}
return len;
}
static zend_uint vld_get_special_flags(zend_op *op, zend_uint base_address)
{
zend_uint flags = 0;
switch (op->opcode) {
case ZEND_FE_RESET:
flags = ALL_USED;
#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)
flags |= OP2_OPNUM;
#elif (PHP_MAJOR_VERSION > 4) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION == 3 && PHP_RELEASE_VERSION >= 11)
flags |= NOP2_OPNUM;
#endif
break;
case ZEND_ASSIGN_REF:
flags = OP1_USED | OP2_USED;
if (op->result.op_type != IS_UNUSED) {
flags |= RES_USED;
}
break;
case ZEND_DO_FCALL_BY_NAME:
case ZEND_DO_FCALL:
flags = OP1_USED | EXT_VAL;
/*flags = ALL_USED | EXT_VAL;
op->op2.op_type = IS_CONST;
op->op2.u.constant.type = IS_LONG;*/
break;
case ZEND_INIT_FCALL_BY_NAME:
flags = OP2_USED;
if (op->op1.op_type != IS_UNUSED) {
flags |= OP1_USED;
}
break;
case ZEND_JMPZNZ:
flags = OP1_USED | OP2_USED | EXT_VAL;
op->result = op->op1;
op->op2.op_type = VLD_IS_OPNUM;
break;
#if (PHP_MAJOR_VERSION < 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1)
case ZEND_JMP_NO_CTOR:
flags = OP2_USED;
if (op->op1.op_type != IS_UNUSED) {
flags |= OP1_USED;
}
op->op2.op_type = VLD_IS_OPNUM;
break;
#endif
#ifdef ZEND_ENGINE_2
case ZEND_FETCH_CLASS:
flags = RES_USED|OP2_USED;
op->result.op_type = VLD_IS_CLASS;
break;
#endif
case ZEND_NEW:
flags = RES_USED|OP1_USED;
#ifdef ZEND_ENGINE_2
op->op1.op_type = VLD_IS_CLASS;
#endif
break;
}
return flags;
}
#define NUM_KNOWN_OPCODES (sizeof(opcodes)/sizeof(opcodes[0]))
void vld_dump_op(int nr, zend_op * op_ptr, zend_uint base_address, int notdead TSRMLS_DC)
{
static uint last_lineno = -1;
int print_sep = 0, len;
char *fetch_type = "";
zend_uint flags;
zend_op op = op_ptr[nr];
if (op.opcode >= NUM_KNOWN_OPCODES) {
flags = ALL_USED;
} else {
flags = opcodes[op.opcode].flags;
}
if (op.lineno == 0)
return;
if (flags == SPECIAL) {
flags = vld_get_special_flags(&op, base_address);
} else {
if (flags & OP1_OPLINE) {
op.op1.op_type = VLD_IS_OPLINE;
}
if (flags & OP2_OPLINE) {
op.op2.op_type = VLD_IS_OPLINE;
}
}
if (flags & OP1_OPNUM) {
op.op1.op_type = VLD_IS_OPNUM;
}
if (flags & OP2_OPNUM) {
op.op2.op_type = VLD_IS_OPNUM;
}
if (flags & OP_FETCH) {
#ifdef ZEND_ENGINE_2
switch (op.op2.u.EA.type) {
case ZEND_FETCH_GLOBAL:
fetch_type = "global";
break;
case ZEND_FETCH_LOCAL:
fetch_type = "local";
break;
case ZEND_FETCH_STATIC:
fetch_type = "static";
break;
case ZEND_FETCH_STATIC_MEMBER:
fetch_type = "static member";
break;
#ifdef ZEND_FETCH_GLOBAL_LOCK
case ZEND_FETCH_GLOBAL_LOCK:
fetch_type = "global lock";
break;
#endif
#ifdef ZEND_FETCH_AUTO_GLOBAL
case ZEND_FETCH_AUTO_GLOBAL:
fetch_type = "auto global";
break;
#endif
default:
fetch_type = "unknown";
break;
}
#else
if (op.op2.u.fetch_type == ZEND_FETCH_GLOBAL) {
fetch_type = "global";
} else if (op.op2.u.fetch_type == ZEND_FETCH_STATIC) {
fetch_type = "static";
}
#endif
}
if (op.lineno == last_lineno) {
vld_printf(stderr, " ");
} else {
vld_printf(stderr, "%4d ", op.lineno);
last_lineno = op.lineno;
}
if (op.opcode >= NUM_KNOWN_OPCODES) {
vld_printf(stderr, "%5d%c <%03d>%-23s %-14s ", nr, notdead ? ' ' : '*', op.opcode, "", fetch_type);
} else {
vld_printf(stderr, "%5d%c %-28s %-14s ", nr, notdead ? ' ' : '*', opcodes[op.opcode].name, fetch_type);
}
if (flags & EXT_VAL) {
vld_printf(stderr, "%3ld ", op.extended_value);
} else {
vld_printf(stderr, " ");
}
if ((flags & RES_USED) && !(op.result.u.EA.type & EXT_TYPE_UNUSED)) {
VLD_PRINT(3, " RES[ ");
len = vld_dump_znode (NULL, op.result, base_address TSRMLS_CC);
VLD_PRINT(3, " ]");
vld_printf(stderr, "%*s", 8-len, " ");
} else {
vld_printf(stderr, " ");
}
if (flags & OP1_USED) {
VLD_PRINT(3, " OP1[ ");
vld_dump_znode (&print_sep, op.op1, base_address TSRMLS_CC);
VLD_PRINT(3, " ]");
}
if (flags & OP2_USED) {
VLD_PRINT(3, " OP2[ ");
if (flags & OP2_INCLUDE) {
if (VLD_G(verbosity) < 3 && print_sep) {
vld_printf(stderr, ", ");
}
switch (Z_LVAL(op.op2.u.constant)) {
case ZEND_INCLUDE_ONCE:
vld_printf(stderr, "INCLUDE_ONCE");
break;
case ZEND_REQUIRE_ONCE:
vld_printf(stderr, "REQUIRE_ONCE");
break;
case ZEND_INCLUDE:
vld_printf(stderr, "INCLUDE");
break;
case ZEND_REQUIRE:
vld_printf(stderr, "REQUIRE");
break;
case ZEND_EVAL:
vld_printf(stderr, "EVAL");
break;
default:
vld_printf(stderr, "!!ERROR!!");
break;
}
} else {
vld_dump_znode (&print_sep, op.op2, base_address TSRMLS_CC);
}
VLD_PRINT(3, " ]");
}
if (flags & NOP2_OPNUM) {
zend_op next_op = op_ptr[nr+1];
next_op.op2.op_type = VLD_IS_OPNUM;
vld_dump_znode (&print_sep, next_op.op2, base_address TSRMLS_CC);
}
vld_printf (stderr, "\n");
}
void vld_analyse_branch(zend_op_array *opa, unsigned int position, vld_set *set TSRMLS_DC);
void vld_dump_oparray(zend_op_array *opa TSRMLS_DC)
{
unsigned int i;
vld_set *set;
zend_uint base_address = (zend_uint) &(opa->opcodes[0]);
set = vld_set_create(opa->size);
vld_analyse_branch(opa, 0, set TSRMLS_CC);
vld_printf (stderr, "filename: %s\n", opa->filename);
vld_printf (stderr, "function name: " ZSTRFMT "\n", ZSTRCP(opa->function_name));
vld_printf (stderr, "number of ops: %d\n", opa->last);
#ifdef IS_CV /* PHP >= 5.1 */
vld_printf (stderr, "compiled vars: ");
for (i = 0; i < opa->last_var; i++) {
vld_printf (stderr, "!%d = $" ZSTRFMT "%s", i, ZSTRCP(opa->vars[i].name), ((i + 1) == opa->last_var) ? "\n" : ", ");
}
if (!opa->last_var) {
vld_printf(stderr, "none\n");
}
#endif
vld_printf(stderr, "line # op fetch ext return operands\n");
vld_printf(stderr, "-------------------------------------------------------------------------------\n");
for (i = 0; i < opa->last; i++) {
vld_dump_op(i, opa->opcodes, base_address, vld_set_in(set, i) TSRMLS_CC);
}
vld_printf(stderr, "\n");
vld_set_free(set);
}
void opt_set_nop (zend_op_array *opa, int nr)
{
opa->opcodes[nr].opcode = ZEND_NOP;
}
zend_brk_cont_element* vld_find_brk_cont(zval *nest_levels_zval, int array_offset, zend_op_array *op_array)
{
int nest_levels;
zend_brk_cont_element *jmp_to;
nest_levels = nest_levels_zval->value.lval;
do {
jmp_to = &op_array->brk_cont_array[array_offset];
array_offset = jmp_to->parent;
} while (--nest_levels > 0);
return jmp_to;
}
int vld_find_jump(zend_op_array *opa, unsigned int position, int *jmp1, int *jmp2)
{
zend_op *base_address = &(opa->opcodes[0]);
zend_op opcode = opa->opcodes[position];
if (opcode.opcode == ZEND_JMP) {
#ifdef ZEND_ENGINE_2
*jmp1 = (opcode.op1.u.jmp_addr - base_address) / sizeof(zend_op);
#else
*jmp1 = opcode.op1.u.opline_num;
#endif
return 1;
} else if (
opcode.opcode == ZEND_JMPZ ||
opcode.opcode == ZEND_JMPNZ ||
opcode.opcode == ZEND_JMPZ_EX ||
opcode.opcode == ZEND_JMPNZ_EX
) {
*jmp1 = position + 1;
#ifdef ZEND_ENGINE_2
*jmp2 = (opcode.op2.u.jmp_addr - base_address) / sizeof(zend_op);
#else
*jmp2 = opcode.op1.u.opline_num;
#endif
return 1;
} else if (opcode.opcode == ZEND_JMPZNZ) {
*jmp1 = opcode.op2.u.opline_num;
*jmp2 = opcode.extended_value;
return 1;
} else if (opcode.opcode == ZEND_BRK || opcode.opcode == ZEND_CONT) {
zend_brk_cont_element *el;
if (opcode.op2.op_type == IS_CONST && opcode.op1.u.jmp_addr != (zend_op*) 0xFFFFFFFF) {
el = vld_find_brk_cont(&opcode.op2.u.constant, opcode.op1.u.opline_num, opa);
*jmp1 = opcode.opcode == ZEND_BRK ? el->brk : el->cont;
return 1;
}
} else if (opcode.opcode == ZEND_FE_RESET || opcode.opcode == ZEND_FE_FETCH) {
*jmp1 = position + 1;
*jmp2 = opcode.op2.u.opline_num;
return 1;
}
return 0;
}
void vld_analyse_branch(zend_op_array *opa, unsigned int position, vld_set *set TSRMLS_DC)
{
int jump_pos1 = -1;
int jump_pos2 = -1;
VLD_PRINT(1, "Branch analysis from position: %d\n", position);
/* First we see if the branch has been visited, if so we bail out. */
if (vld_set_in(set, position)) {
return;
}
/* Loop over the opcodes until the end of the array, or until a jump point has been found */
VLD_PRINT(2, "Add %d\n", position);
vld_set_add(set, position);
while (position < opa->size - 1) {
/* See if we have a jump instruction */
if (vld_find_jump(opa, position, &jump_pos1, &jump_pos2)) {
VLD_PRINT(1, "Jump found. Position 1 = %d", jump_pos1);
if (jump_pos2 != -1) {
VLD_PRINT(1, ", Position 2 = %d\n", jump_pos2);
} else {
VLD_PRINT(1, "\n");
}
vld_analyse_branch(opa, jump_pos1, set TSRMLS_CC);
if (jump_pos2 != -1) {
vld_analyse_branch(opa, jump_pos2, set TSRMLS_CC);
}
break;
}
#ifdef ZEND_ENGINE_2
/* See if we have a throw instruction */
if (opa->opcodes[position].opcode == ZEND_THROW) {
VLD_PRINT(1, "Throw found at %d\n", position);
/* Now we need to go forward to the first
* zend_fetch_class/zend_catch combo */
while (position < opa->size - 1) {
if (opa->opcodes[position].opcode == ZEND_CATCH) {
VLD_PRINT(1, "Found catch at %d\n", position);
position--;
break;
}
position++;
VLD_PRINT(2, "Skipping %d\n", position);
}
position--;
}
#endif
/* See if we have an exit instruction */
if (opa->opcodes[position].opcode == ZEND_EXIT) {
VLD_PRINT(1, "Exit found\n");
break;
}
/* See if we have a return instruction */
if (opa->opcodes[position].opcode == ZEND_RETURN) {
VLD_PRINT(1, "Return found\n");
break;
}
position++;
VLD_PRINT(2, "Add %d\n", position);
vld_set_add(set, position);
}
}
syntax highlighted by Code2HTML, v. 0.9.1