Ejemplo n.º 1
0
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars) /*{{{ */
{
	char *decode[4] = {NULL, NULL, NULL, NULL};

	switch (op->opcode) {
	case ZEND_JMP:
	case ZEND_GOTO:
	case ZEND_FAST_CALL:
		asprintf(&decode[1], "J%ld", OP_JMP_ADDR(op, op->op1) - ops->opcodes);
		goto format;

	case ZEND_JMPZNZ:
		decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars);
		asprintf(&decode[2], "J%u or J%" PRIu32, op->op2.opline_num, op->extended_value);
		goto result;

	case ZEND_JMPZ:
	case ZEND_JMPNZ:
	case ZEND_JMPZ_EX:
	case ZEND_JMPNZ_EX:
	case ZEND_JMP_SET:
		decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars);
		asprintf(&decode[2], "J%ld", OP_JMP_ADDR(op, op->op2) - ops->opcodes);
		goto result;

	case ZEND_RECV_INIT:
		goto result;

	default:
		decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars);
		decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars);
result:
		decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars);
format:
		asprintf(&decode[0],
			"%-20s %-20s %-20s",
			decode[1] ? decode[1] : "",
			decode[2] ? decode[2] : "",
			decode[3] ? decode[3] : "");
	}

	if (decode[1])
		free(decode[1]);
	if (decode[2])
		free(decode[2]);
	if (decode[3])
		free(decode[3]);

	return decode[0];
} /* }}} */
Ejemplo n.º 2
0
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, &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_LIVE_RANGE == (flags & ZEND_VM_OP_MASK)) {
		if (opline->extended_value & ZEND_FREE_ON_RETURN) {
			spprintf(&result, 0, "live-range(%" 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;
}
Ejemplo n.º 3
0
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */
{
	const char *opcode_name = phpdbg_decode_opcode(op->opcode);
	char *result, *decode[4] = {NULL, NULL, NULL, NULL};

	/* EX */
	switch (op->opcode) {
	case ZEND_FAST_CALL:
		if (op->extended_value == ZEND_FAST_CALL_FROM_FINALLY) {
			decode[0] = estrdup("FAST_CALL<FROM_FINALLY>");
		}
		break;
	case ZEND_FAST_RET:
		if (op->extended_value != 0) {
			spprintf(&decode[0], 0, "FAST_RET<%s>",
				op->extended_value == ZEND_FAST_RET_TO_CATCH ? "TO_CATCH" : "TO_FINALLY");
		}
		break;
	}

	/* OP1 */
	switch (op->opcode) {
	case ZEND_JMP:
	case ZEND_FAST_CALL:
		spprintf(&decode[1], 0, "J%td", OP_JMP_ADDR(op, op->op1) - ops->opcodes);
		break;

	case ZEND_INIT_FCALL:
	case ZEND_RECV:
	case ZEND_RECV_INIT:
	case ZEND_RECV_VARIADIC:
		spprintf(&decode[1], 0, "%" PRIu32, op->op1.num);
		break;

	default:
		decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type);
		break;
	}

	/* OP2 */
	switch (op->opcode) {
	case ZEND_JMPZNZ:
		spprintf(&decode[2], 0, "J%td or J%td",
			OP_JMP_ADDR(op, op->op2) - ops->opcodes,
			ZEND_OFFSET_TO_OPLINE(op, op->extended_value) - ops->opcodes);
		break;

	case ZEND_JMPZ:
	case ZEND_JMPNZ:
	case ZEND_JMPZ_EX:
	case ZEND_JMPNZ_EX:
	case ZEND_JMP_SET:
	case ZEND_ASSERT_CHECK:
		spprintf(&decode[2], 0, "J%td", OP_JMP_ADDR(op, op->op2) - ops->opcodes);
		break;

	case ZEND_FAST_CALL:
	case ZEND_FAST_RET:
		if (op->extended_value != 0) {
			spprintf(&decode[2], 0, "J%" PRIu32, op->op2.opline_num);
		}
		break;

	case ZEND_SEND_VAL:
	case ZEND_SEND_VAL_EX:
	case ZEND_SEND_VAR:
	case ZEND_SEND_VAR_NO_REF:
	case ZEND_SEND_REF:
	case ZEND_SEND_VAR_EX:
	case ZEND_SEND_USER:
		spprintf(&decode[2], 0, "%" PRIu32, op->op2.num);
		break;

	default:
		decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type);
		break;
	}

	/* RESULT */
	switch (op->opcode) {
	case ZEND_CATCH:
		spprintf(&decode[3], 0, "%" PRIu32, op->result.num);
		break;
	default:
		decode[3] = phpdbg_decode_op(ops, &op->result, op->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;
} /* }}} */
Ejemplo n.º 4
0
int uopz_mock_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
	int UOPZ_VM_ACTION = ZEND_USER_OPCODE_DISPATCH;
	zend_string *key;
	zval *mock = NULL;
	zend_class_entry *ce;

	if (EX(opline)->op1_type == IS_CONST) {
		ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)));

		if (UNEXPECTED(ce == NULL)) {
			key = Z_STR_P(EX_CONSTANT(EX(opline)->op1));
		} else {
			key = ce->name;
		}

		key = zend_string_tolower(key);
	} else if(EX(opline)->op1_type == IS_UNUSED) {
		ce = zend_fetch_class(NULL, EX(opline)->op1.num);
		if (UNEXPECTED(ce == NULL)) {
			return UOPZ_VM_ACTION;
		}
		key = 
			zend_string_tolower(ce->name);
	} else {
		key = zend_string_tolower(
			Z_CE_P(EX_VAR(EX(opline)->op1.var))->name);
	}

	if (UNEXPECTED((mock = zend_hash_find(&UOPZ(mocks), key)))) {
		switch (Z_TYPE_P(mock)) {
			case IS_OBJECT:
				ZVAL_COPY(
					EX_VAR(EX(opline)->result.var), mock);
#if PHP_VERSION_ID < 70100
				EX(opline) = 
					OP_JMP_ADDR(EX(opline), EX(opline)->op2);
#else
				if (EX(opline)->extended_value == 0 && 
					(EX(opline)+1)->opcode == ZEND_DO_FCALL) {
					EX(opline) += 2;
				}
#endif
				UOPZ_VM_ACTION = ZEND_USER_OPCODE_CONTINUE;
			break;

			case IS_STRING:
				ce = zend_lookup_class(Z_STR_P(mock));
				if (EXPECTED(ce)) {
					if (EX(opline)->op1_type == IS_CONST) {
						CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), ce);
					} else if (EX(opline)->op1_type != IS_UNUSED) {
						Z_CE_P(EX_VAR(EX(opline)->op1.var)) = ce;
					} else {
						/* oh dear, can't do what is requested */			
					}
					
				}
			break;
		}
	}

	zend_string_release(key);

	if (UOPZ_VM_ACTION == ZEND_USER_OPCODE_DISPATCH) {
		if (uopz_new_handler) {
			return uopz_new_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		}
	}

	return UOPZ_VM_ACTION;
} /* }}} */
Ejemplo n.º 5
0
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg, uint32_t *func_flags) /* {{{ */
{
	uint32_t flags = 0;
	uint32_t i;
	int j;
	uint32_t *block_map;
	zend_function *fn;
	int blocks_count = 0;
	zend_basic_block *blocks;
	zval *zv;

	cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
	if (!block_map) {
		return FAILURE;
	}

	/* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */
	BB_START(0);
	for (i = 0; i < op_array->last; i++) {
		zend_op *opline = op_array->opcodes + i;
		switch(opline->opcode) {
			case ZEND_RETURN:
			case ZEND_RETURN_BY_REF:
			case ZEND_GENERATOR_RETURN:
			case ZEND_EXIT:
			case ZEND_THROW:
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_INCLUDE_OR_EVAL:
				flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
			case ZEND_YIELD:
			case ZEND_YIELD_FROM:
				if (build_flags & ZEND_CFG_STACKLESS) {
					BB_START(i + 1);
				}
				break;
			case ZEND_DO_FCALL:
			case ZEND_DO_UCALL:
			case ZEND_DO_FCALL_BY_NAME:
				flags |= ZEND_FUNC_HAS_CALLS;
				if (build_flags & ZEND_CFG_STACKLESS) {
					BB_START(i + 1);
				}
				break;
			case ZEND_DO_ICALL:
				flags |= ZEND_FUNC_HAS_CALLS;
				break;
			case ZEND_INIT_FCALL:
			case ZEND_INIT_NS_FCALL_BY_NAME:
				zv = CRT_CONSTANT(opline->op2);
				if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
					/* The third literal is the lowercased unqualified name */
					zv += 2;
				}
				if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
					if (fn->type == ZEND_INTERNAL_FUNCTION) {
						if (zend_string_equals_literal(Z_STR_P(zv), "extract")) {
							flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
						} else if (zend_string_equals_literal(Z_STR_P(zv), "compact")) {
							flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
						} else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str") &&
						           opline->extended_value == 1) {
							flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
						} else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str") &&
						           opline->extended_value == 1) {
							flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
						} else if (zend_string_equals_literal(Z_STR_P(zv), "get_defined_vars")) {
							flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
						} else if (zend_string_equals_literal(Z_STR_P(zv), "func_num_args")) {
							flags |= ZEND_FUNC_VARARG;
						} else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_arg")) {
							flags |= ZEND_FUNC_VARARG;
						} else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_args")) {
							flags |= ZEND_FUNC_VARARG;
						}
					}
				}
				break;
			case ZEND_FAST_CALL:
				BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
				BB_START(i + 1);
				break;
			case ZEND_FAST_RET:
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_JMP:
				BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_JMPZNZ:
				BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
				BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_JMPZ:
			case ZEND_JMPNZ:
			case ZEND_JMPZ_EX:
			case ZEND_JMPNZ_EX:
			case ZEND_JMP_SET:
			case ZEND_COALESCE:
			case ZEND_ASSERT_CHECK:
				BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
				BB_START(i + 1);
				break;
			case ZEND_CATCH:
				if (!opline->result.num) {
					BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
				}
				BB_START(i + 1);
				break;
			case ZEND_DECLARE_ANON_CLASS:
			case ZEND_DECLARE_ANON_INHERITED_CLASS:
			case ZEND_FE_FETCH_R:
			case ZEND_FE_FETCH_RW:
				BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
				BB_START(i + 1);
				break;
			case ZEND_FE_RESET_R:
			case ZEND_FE_RESET_RW:
			case ZEND_NEW:
				BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
				BB_START(i + 1);
				break;
			case ZEND_UNSET_VAR:
			case ZEND_ISSET_ISEMPTY_VAR:
				if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) &&
				    !(opline->extended_value & ZEND_QUICK_SET)) {
					flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
				} else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL ||
				            (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) &&
				           !op_array->function_name) {
					flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
				}
				break;
			case ZEND_FETCH_R:
			case ZEND_FETCH_W:
			case ZEND_FETCH_RW:
			case ZEND_FETCH_FUNC_ARG:
			case ZEND_FETCH_IS:
			case ZEND_FETCH_UNSET:
				if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) {
					flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
				} else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL ||
				            (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) &&
				           !op_array->function_name) {
					flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
				}
				break;
		}
	}
	for (j = 0; j < op_array->last_live_range; j++) {
		BB_START(op_array->live_range[j].start);
		BB_START(op_array->live_range[j].end);
	}
	if (op_array->last_try_catch) {
		for (j = 0; j < op_array->last_try_catch; j++) {
			BB_START(op_array->try_catch_array[j].try_op);
			if (op_array->try_catch_array[j].catch_op) {
				BB_START(op_array->try_catch_array[j].catch_op);
			}
			if (op_array->try_catch_array[j].finally_op) {
				BB_START(op_array->try_catch_array[j].finally_op);
			}
			if (op_array->try_catch_array[j].finally_end) {
				BB_START(op_array->try_catch_array[j].finally_end);
			}
		}
	}

	cfg->blocks_count = blocks_count;

	/* Build CFG, Step 2: Build Array of Basic Blocks */
	cfg->blocks = blocks = zend_arena_calloc(arena, sizeof(zend_basic_block), blocks_count);
	if (!blocks) {
		return FAILURE;
	}

	for (i = 0, blocks_count = -1; i < op_array->last; i++) {
		if (block_map[i]) {
			if (blocks_count >= 0) {
				blocks[blocks_count].end = i - 1;
			}
			blocks_count++;
			blocks[blocks_count].flags = 0;
			blocks[blocks_count].start = i;
			blocks[blocks_count].successors[0] = -1;
			blocks[blocks_count].successors[1] = -1;
			blocks[blocks_count].predecessors_count = 0;
			blocks[blocks_count].predecessor_offset = -1;
			blocks[blocks_count].idom = -1;
			blocks[blocks_count].loop_header = -1;
			blocks[blocks_count].level = -1;
			blocks[blocks_count].children = -1;
			blocks[blocks_count].next_child = -1;
			block_map[i] = blocks_count;
		} else {
			block_map[i] = (uint32_t)-1;
		}
	}

	blocks[blocks_count].end = i - 1;
	blocks_count++;

	/* Build CFG, Step 3: Calculate successors */
	for (j = 0; j < blocks_count; j++) {
		zend_op *opline = op_array->opcodes + blocks[j].end;
		switch(opline->opcode) {
			case ZEND_FAST_RET:
			case ZEND_RETURN:
			case ZEND_RETURN_BY_REF:
			case ZEND_GENERATOR_RETURN:
			case ZEND_EXIT:
			case ZEND_THROW:
				break;
			case ZEND_JMP:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
				break;
			case ZEND_JMPZNZ:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
				record_successor(blocks, j, 1, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
				break;
			case ZEND_JMPZ:
			case ZEND_JMPNZ:
			case ZEND_JMPZ_EX:
			case ZEND_JMPNZ_EX:
			case ZEND_JMP_SET:
			case ZEND_COALESCE:
			case ZEND_ASSERT_CHECK:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
				record_successor(blocks, j, 1, j + 1);
				break;
			case ZEND_CATCH:
				if (!opline->result.num) {
					record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
					record_successor(blocks, j, 1, j + 1);
				} else {
					record_successor(blocks, j, 0, j + 1);
				}
				break;
			case ZEND_DECLARE_ANON_CLASS:
			case ZEND_DECLARE_ANON_INHERITED_CLASS:
			case ZEND_FE_FETCH_R:
			case ZEND_FE_FETCH_RW:
				record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
				record_successor(blocks, j, 1, j + 1);
				break;
			case ZEND_FE_RESET_R:
			case ZEND_FE_RESET_RW:
			case ZEND_NEW:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
				record_successor(blocks, j, 1, j + 1);
				break;
			case ZEND_FAST_CALL:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
				record_successor(blocks, j, 1, j + 1);
				break;
			default:
				record_successor(blocks, j, 0, j + 1);
				break;
		}
	}

	/* Build CFG, Step 4, Mark Reachable Basic Blocks */
	zend_mark_reachable_blocks(op_array, cfg, 0);

	if (func_flags) {
		*func_flags |= flags;
	}

	return SUCCESS;
}
Ejemplo n.º 6
0
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */
{
	char *decode[4] = {NULL, NULL, NULL, NULL};

	/* OP1 */
	switch (op->opcode) {
	case ZEND_JMP:
	case ZEND_FAST_CALL:
		asprintf(&decode[1], "J%ld", OP_JMP_ADDR(op, op->op1) - ops->opcodes);
		break;

	case ZEND_INIT_FCALL:
	case ZEND_RECV:
	case ZEND_RECV_INIT:
	case ZEND_RECV_VARIADIC:
		asprintf(&decode[1], "%" PRIu32, op->op1.num);
		break;

	default:
		decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type);
		break;
	}

	/* OP2 */
	switch (op->opcode) {
	/* TODO: ZEND_FAST_CALL, ZEND_FAST_RET op2 */
	case ZEND_JMPZNZ:
		asprintf(&decode[2], "J%u or J%" PRIu32, OP_JMP_ADDR(op, op->op2) - ops->opcodes, ZEND_OFFSET_TO_OPLINE(op, op->extended_value) - ops->opcodes);
		break;

	case ZEND_JMPZ:
	case ZEND_JMPNZ:
	case ZEND_JMPZ_EX:
	case ZEND_JMPNZ_EX:
	case ZEND_JMP_SET:
	case ZEND_ASSERT_CHECK:
		asprintf(&decode[2], "J%ld", OP_JMP_ADDR(op, op->op2) - ops->opcodes);
		break;

	case ZEND_SEND_VAL:
	case ZEND_SEND_VAL_EX:
	case ZEND_SEND_VAR:
	case ZEND_SEND_VAR_NO_REF:
	case ZEND_SEND_REF:
	case ZEND_SEND_VAR_EX:
	case ZEND_SEND_USER:
		asprintf(&decode[2], "%" PRIu32, op->op2.num);
		break;

	default:
		decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type);
		break;
	}

	/* RESULT */
	switch (op->opcode) {
	case ZEND_CATCH:
		asprintf(&decode[2], "%" PRIu32, op->result.num);
		break;
	default:
		decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type);
		break;
	}

#if 0
	if (ops->T_liveliness) {
		uint32_t *var = ops->T_liveliness + (op - ops->opcodes);

		if (*var != (uint32_t)-1) {
			smart_str str = {0};

			var = ops->T_liveliness + (*var);
			smart_str_appends(&str, "; [@");
			smart_str_append_long(&str, EX_VAR_TO_NUM(((*var) & ~0x3)) - ops->last_var);
			while (*(++var) != (uint32_t)-1) {
				smart_str_appends(&str, ", @");
				smart_str_append_long(&str, EX_VAR_TO_NUM(((*var) & ~0x3)) - ops->last_var);
			}
			smart_str_appendc(&str, ']');
			smart_str_0(&str);

			asprintf(&decode[0],
				"%-20s %-20s %-20s%-20s",
				decode[1] ? decode[1] : "",
				decode[2] ? decode[2] : "",
				decode[3] ? decode[3] : "",
				ZSTR_VAL(str.s));

			smart_str_free(&str);

			if (decode[1])
				free(decode[1]);
			if (decode[2])
				free(decode[2]);
			if (decode[3])
				free(decode[3]);

			return decode[0];
		}
	}
#endif

	asprintf(&decode[0],
		"%-20s %-20s %-20s",
		decode[1] ? decode[1] : "",
		decode[2] ? decode[2] : "",
		decode[3] ? decode[3] : "");

	if (decode[1])
		free(decode[1]);
	if (decode[2])
		free(decode[2]);
	if (decode[3])
		free(decode[3]);

	return decode[0];
} /* }}} */
Ejemplo n.º 7
0
char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars) /*{{{ */
{
	char *decode[4] = {NULL, NULL, NULL, NULL};

	/* OP1 */
	switch (op->opcode) {
	case ZEND_JMP:
	case ZEND_GOTO:
	case ZEND_FAST_CALL:
		asprintf(&decode[1], "J%ld", OP_JMP_ADDR(op, op->op1) - ops->opcodes);
		break;

	case ZEND_INIT_FCALL:
	case ZEND_RECV:
	case ZEND_RECV_INIT:
	case ZEND_RECV_VARIADIC:
		asprintf(&decode[1], "%" PRIu32, op->op1.num);
		break;

	default:
		decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars);
		break;
	}

	/* OP2 */
	switch (op->opcode) {
	/* TODO: ZEND_FAST_CALL, ZEND_FAST_RET op2 */
	case ZEND_JMPZNZ:
		asprintf(&decode[2], "J%u or J%" PRIu32, op->op2.opline_num, op->extended_value);
		break;

	case ZEND_JMPZ:
	case ZEND_JMPNZ:
	case ZEND_JMPZ_EX:
	case ZEND_JMPNZ_EX:
	case ZEND_JMP_SET:
	case ZEND_ASSERT_CHECK:
		asprintf(&decode[2], "J%ld", OP_JMP_ADDR(op, op->op2) - ops->opcodes);
		break;

	case ZEND_SEND_VAL:
	case ZEND_SEND_VAL_EX:
	case ZEND_SEND_VAR:
	case ZEND_SEND_VAR_NO_REF:
	case ZEND_SEND_REF:
	case ZEND_SEND_VAR_EX:
	case ZEND_SEND_USER:
		asprintf(&decode[2], "%" PRIu32, op->op2.num);
		break;

	default:
		decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type, vars);
		break;
	}

	/* RESULT */
	switch (op->opcode) {
	case ZEND_CATCH:
		asprintf(&decode[2], "%" PRIu32, op->result.num);
		break;
	default:
		decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars);
		break;
	}

	asprintf(&decode[0],
		"%-20s %-20s %-20s",
		decode[1] ? decode[1] : "",
		decode[2] ? decode[2] : "",
		decode[3] ? decode[3] : "");

	if (decode[1])
		free(decode[1]);
	if (decode[2])
		free(decode[2]);
	if (decode[3])
		free(decode[3]);

	return decode[0];
} /* }}} */
Ejemplo n.º 8
0
int zend_build_cfg(zend_arena **arena, zend_op_array *op_array, int rt_constants, int stackless, zend_cfg *cfg, uint32_t *func_flags) /* {{{ */
{
	uint32_t flags = 0;
	uint32_t i;
	int j;
	uint32_t *block_map;
	zend_function *fn;
	int blocks_count = 0;
	zend_basic_block *blocks;
	zval *zv;

	cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
	if (!block_map) {
		return FAILURE;
	}

	/* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */
	BB_START(0);
	if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->static_variables) {
		// FIXME: Really we should try to perform variable initialization
		flags |= ZEND_FUNC_TOO_DYNAMIC;
	}
	for (i = 0; i < op_array->last; i++) {
		zend_op *opline = op_array->opcodes + i;
		switch(opline->opcode) {
			case ZEND_RETURN:
			case ZEND_RETURN_BY_REF:
			case ZEND_GENERATOR_RETURN:
			case ZEND_EXIT:
			case ZEND_THROW:
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_INCLUDE_OR_EVAL:
			case ZEND_YIELD:
			case ZEND_YIELD_FROM:
				flags |= ZEND_FUNC_TOO_DYNAMIC;
				if (stackless) {
					BB_START(i + 1);
				}
				break;
			case ZEND_DO_FCALL:
			case ZEND_DO_UCALL:
			case ZEND_DO_FCALL_BY_NAME:
				flags |= ZEND_FUNC_HAS_CALLS;
				if (stackless) {
					BB_START(i + 1);
				}
				break;
			case ZEND_DO_ICALL:
				flags |= ZEND_FUNC_HAS_CALLS;
				break;
			case ZEND_INIT_FCALL:
				if (rt_constants) {
					zv = RT_CONSTANT(op_array, opline->op2);
				} else {
					zv = CT_CONSTANT_EX(op_array, opline->op2.constant);
				}
				if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
					if (fn->type == ZEND_INTERNAL_FUNCTION) {
						if (Z_STRLEN_P(zv) == sizeof("extract")-1 &&
						    memcmp(Z_STRVAL_P(zv), "extract", sizeof("extract")-1) == 0) {
							flags |= ZEND_FUNC_TOO_DYNAMIC;
						} else if (Z_STRLEN_P(zv) == sizeof("compact")-1 &&
						    memcmp(Z_STRVAL_P(zv), "compact", sizeof("compact")-1) == 0) {
							flags |= ZEND_FUNC_TOO_DYNAMIC;
						} else if (Z_STRLEN_P(zv) == sizeof("parse_str")-1 &&
						    memcmp(Z_STRVAL_P(zv), "parse_str", sizeof("parse_str")-1) == 0) {
							flags |= ZEND_FUNC_TOO_DYNAMIC;
						} else if (Z_STRLEN_P(zv) == sizeof("mb_parse_str")-1 &&
						    memcmp(Z_STRVAL_P(zv), "mb_parse_str", sizeof("mb_parse_str")-1) == 0) {
							flags |= ZEND_FUNC_TOO_DYNAMIC;
						} else if (Z_STRLEN_P(zv) == sizeof("get_defined_vars")-1 &&
						    memcmp(Z_STRVAL_P(zv), "get_defined_vars", sizeof("get_defined_vars")-1) == 0) {
							flags |= ZEND_FUNC_TOO_DYNAMIC;
						} else if (Z_STRLEN_P(zv) == sizeof("func_num_args")-1 &&
						    memcmp(Z_STRVAL_P(zv), "func_num_args", sizeof("func_num_args")-1) == 0) {
							flags |= ZEND_FUNC_VARARG;
						} else if (Z_STRLEN_P(zv) == sizeof("func_get_arg")-1 &&
						    memcmp(Z_STRVAL_P(zv), "func_get_arg", sizeof("func_get_arg")-1) == 0) {
							flags |= ZEND_FUNC_VARARG;
						} else if (Z_STRLEN_P(zv) == sizeof("func_get_args")-1 &&
						    memcmp(Z_STRVAL_P(zv), "func_get_args", sizeof("func_get_args")-1) == 0) {
							flags |= ZEND_FUNC_VARARG;
						}
					}
				}
				break;
			case ZEND_FAST_CALL:
				flags |= ZEND_FUNC_TOO_DYNAMIC;
				BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
				BB_START(i + 1);
				break;
			case ZEND_FAST_RET:
				flags |= ZEND_FUNC_TOO_DYNAMIC;
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_DECLARE_ANON_CLASS:
			case ZEND_DECLARE_ANON_INHERITED_CLASS:
				BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
				BB_START(i + 1);
				break;
			case ZEND_JMP:
				BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_JMPZNZ:
				BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
				BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
				if (i + 1 < op_array->last) {
					BB_START(i + 1);
				}
				break;
			case ZEND_JMPZ:
			case ZEND_JMPNZ:
			case ZEND_JMPZ_EX:
			case ZEND_JMPNZ_EX:
			case ZEND_JMP_SET:
			case ZEND_COALESCE:
			case ZEND_ASSERT_CHECK:
				BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
				BB_START(i + 1);
				break;
			case ZEND_CATCH:
				flags |= ZEND_FUNC_TOO_DYNAMIC;
				if (!opline->result.num) {
					BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
				}
				BB_START(i + 1);
				break;
			case ZEND_FE_FETCH_R:
			case ZEND_FE_FETCH_RW:
				BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
				BB_START(i + 1);
				break;
			case ZEND_FE_RESET_R:
			case ZEND_FE_RESET_RW:
			case ZEND_NEW:
				BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
				BB_START(i + 1);
				break;
			case ZEND_DECLARE_LAMBDA_FUNCTION: {
//???					zend_op_array *lambda_op_array;
//???
//???					if (rt_constants) {
//???						zv = RT_CONSTANT(op_array, opline->op1);
//???					} else {
//???						zv = CT_CONSTANT_EX(op_array, opline->op1.constant);
//???					}
//???					if (ctx->main_script &&
//???					    (lambda_op_array = zend_hash_find_ptr(&ctx->main_script->function_table, Z_STR_P(zv))) != NULL) {
//???						if (lambda_op_array->type == ZEND_USER_FUNCTION &&
//???						    lambda_op_array->static_variables) {
//???							// FIXME: Really we should try to perform alias
//???							// analysis on variables used by the closure
//???							info->flags |= ZEND_FUNC_TOO_DYNAMIC;
//???						}
//???					} else {
//???						// FIXME: how to find the lambda function?
						flags |= ZEND_FUNC_TOO_DYNAMIC;
//???					}
				}
				break;
			case ZEND_UNSET_VAR:
				if (!(opline->extended_value & ZEND_QUICK_SET)) {
					flags |= ZEND_FUNC_TOO_DYNAMIC;
				}
				break;
			case ZEND_FETCH_R:
			case ZEND_FETCH_W:
			case ZEND_FETCH_RW:
			case ZEND_FETCH_FUNC_ARG:
			case ZEND_FETCH_IS:
			case ZEND_FETCH_UNSET:
				if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) {
					flags |= ZEND_FUNC_TOO_DYNAMIC;
				} else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL ||
				            (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) &&
				           !op_array->function_name) {
					flags |= ZEND_FUNC_TOO_DYNAMIC;
				}
				break;
		}
	}
	for (j = 0; j < op_array->last_live_range; j++) {
		BB_START(op_array->live_range[j].start);
		BB_START(op_array->live_range[j].end);
	}
	if (op_array->last_try_catch) {
		for (j = 0; j < op_array->last_try_catch; j++) {
			BB_START(op_array->try_catch_array[j].try_op);
			if (op_array->try_catch_array[j].catch_op) {
				BB_START(op_array->try_catch_array[j].catch_op);
			}
			if (op_array->try_catch_array[j].finally_op) {
				BB_START(op_array->try_catch_array[j].finally_op);
			}
			if (op_array->try_catch_array[j].finally_end) {
				BB_START(op_array->try_catch_array[j].finally_end);
			}
		}
	}

	cfg->blocks_count = blocks_count;

	/* Build CFG, Step 2: Build Array of Basic Blocks */
	cfg->blocks = blocks = zend_arena_calloc(arena, sizeof(zend_basic_block), blocks_count);
	if (!blocks) {
		return FAILURE;
	}

	for (i = 0, blocks_count = -1; i < op_array->last; i++) {
		if (block_map[i]) {
			if (blocks_count >= 0) {
				blocks[blocks_count].end = i - 1;
			}
			blocks_count++;
			blocks[blocks_count].flags = 0;
			blocks[blocks_count].start = i;
			blocks[blocks_count].successors[0] = -1;
			blocks[blocks_count].successors[1] = -1;
			blocks[blocks_count].predecessors_count = 0;
			blocks[blocks_count].predecessor_offset = -1;
			blocks[blocks_count].idom = -1;
			blocks[blocks_count].loop_header = -1;
			blocks[blocks_count].level = -1;
			blocks[blocks_count].children = -1;
			blocks[blocks_count].next_child = -1;
			block_map[i] = blocks_count;
		} else {
			block_map[i] = (uint32_t)-1;
		}
	}

	blocks[blocks_count].end = i - 1;
	blocks_count++;

	/* Build CFG, Step 3: Calculate successors */
	for (j = 0; j < blocks_count; j++) {
		zend_op *opline = op_array->opcodes + blocks[j].end;
		switch(opline->opcode) {
			case ZEND_FAST_RET:
			case ZEND_RETURN:
			case ZEND_RETURN_BY_REF:
			case ZEND_GENERATOR_RETURN:
			case ZEND_EXIT:
			case ZEND_THROW:
				break;
			case ZEND_DECLARE_ANON_CLASS:
			case ZEND_DECLARE_ANON_INHERITED_CLASS:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
				record_successor(blocks, j, 1, j + 1);
				break;
			case ZEND_JMP:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
				break;
			case ZEND_JMPZNZ:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
				record_successor(blocks, j, 1, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
				break;
			case ZEND_JMPZ:
			case ZEND_JMPNZ:
			case ZEND_JMPZ_EX:
			case ZEND_JMPNZ_EX:
			case ZEND_JMP_SET:
			case ZEND_COALESCE:
			case ZEND_ASSERT_CHECK:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
				record_successor(blocks, j, 1, j + 1);
				break;
			case ZEND_CATCH:
				if (!opline->result.num) {
					record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
					record_successor(blocks, j, 1, j + 1);
				} else {
					record_successor(blocks, j, 0, j + 1);
				}
				break;
			case ZEND_FE_FETCH_R:
			case ZEND_FE_FETCH_RW:
				record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
				record_successor(blocks, j, 1, j + 1);
				break;
			case ZEND_FE_RESET_R:
			case ZEND_FE_RESET_RW:
			case ZEND_NEW:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
				record_successor(blocks, j, 1, j + 1);
				break;
			case ZEND_FAST_CALL:
				record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
				record_successor(blocks, j, 1, j + 1);
				break;
			default:
				record_successor(blocks, j, 0, j + 1);
				break;
		}
	}

	/* Build CFG, Step 4, Mark Reachable Basic Blocks */
	zend_mark_reachable_blocks(op_array, cfg, 0);

	if (func_flags) {
		*func_flags = flags;
	}

	return SUCCESS;
}