Ejemplo n.º 1
0
static void
bb_formation_eh_pass (MonoMethodHeader *header, MonoSimpleBasicBlock *bb, MonoSimpleBasicBlock **root, MonoMethod *method, MonoError *error)
{
	int i;
	int end = header->code_size;
	/*We must split at all points to verify for targets in the middle of an instruction*/
	for (i = 0; i < header->num_clauses; ++i) {
		MonoExceptionClause *clause = header->clauses + i;
		MonoSimpleBasicBlock *try_block, *handler;

		if (!(try_block = bb_split (bb, bb, root, clause->try_offset, TRUE, method, error)))
			return;

		handler = bb_split (bb, try_block, root, clause->handler_offset, FALSE, method, error);
		if (!handler)
			return;
		handler->dead = FALSE;

		if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
			MonoSimpleBasicBlock *filter = bb_split (bb, try_block, root, clause->data.filter_offset, FALSE, method, error);
			if (!filter)
				return;
			filter->dead = FALSE;
		}

		if (clause->try_offset + clause->try_len < end && !bb_split (bb, try_block, root, clause->try_offset + clause->try_len, FALSE, method, error))
			return;

		if (clause->handler_offset + clause->handler_len < end && !bb_split (bb, handler, root, clause->handler_offset + clause->handler_len, FALSE, method, error))
			return;
	}
}
Ejemplo n.º 2
0
int convert_tableswitch(struct parse_context *ctx)
{
	struct tableswitch_info info;
	struct tableswitch *table;
	struct basic_block *master_bb;
	struct basic_block *default_bb;
	struct basic_block *b1;
	struct basic_block *b2;

	get_tableswitch_info(ctx->code, ctx->offset, &info);
	ctx->buffer->pos += info.insn_size;

	default_bb = find_bb(ctx->cu, ctx->offset + info.default_target);
	if (!default_bb)
		goto fail_default_bb;

	master_bb = ctx->bb;

	b1 = bb_split(master_bb, master_bb->end);
	b2 = bb_split(b1, master_bb->end);

	assert(b1 && b2);

	master_bb->has_branch = true;
	b1->has_branch = true;
	b2->has_branch = true;

	bb_add_successor(master_bb, default_bb );
	bb_add_successor(master_bb, b1);

	bb_add_successor(b1, default_bb );
	bb_add_successor(b1, b2);

	for (unsigned int i = 0; i < info.count; i++) {
		struct basic_block *target_bb;
		int32_t target;

		target = read_s32(info.targets + i * 4);
		target_bb = find_bb(ctx->cu, ctx->offset + target);

		if (!bb_successors_contains(b2, target_bb))
			bb_add_successor(b2, target_bb);
	}

	table = alloc_tableswitch(&info, ctx->cu, b2, ctx->offset);
	if (!table)
		return -ENOMEM;

	struct statement *if_lesser_stmt;
	struct statement *if_greater_stmt;
	struct statement *stmt;
	struct expression *pure_index;

	pure_index = get_pure_expr(ctx, stack_pop(ctx->bb->mimic_stack));

	if_lesser_stmt =
		branch_if_lesser_stmt(default_bb, pure_index, info.low);
	if (!if_lesser_stmt)
		goto fail_lesser_stmt;

	expr_get(pure_index);
	if_greater_stmt =
		branch_if_greater_stmt(default_bb, pure_index, info.high);
	if (!if_greater_stmt)
		goto fail_greater_stmt;

	stmt = alloc_statement(STMT_TABLESWITCH);
	if (!stmt)
		goto fail_stmt;

	expr_get(pure_index);
	stmt->index = &pure_index->node;
	stmt->table = table;

	do_convert_statement(master_bb, if_lesser_stmt, ctx->offset);
	do_convert_statement(b1, if_greater_stmt, ctx->offset);
	do_convert_statement(b2, stmt, ctx->offset);
	return 0;

 fail_stmt:
	free_statement(if_greater_stmt);
 fail_greater_stmt:
	free_statement(if_lesser_stmt);
 fail_lesser_stmt:
	free_tableswitch(table);
 fail_default_bb:
	return -1;
}
Ejemplo n.º 3
0
static void
bb_formation_il_pass (const unsigned char *start, const unsigned char *end, MonoSimpleBasicBlock *bb, MonoSimpleBasicBlock **root, MonoMethod *method, MonoError *error)
{
	unsigned const char *ip = start;
	int value, size;
	guint cli_addr, offset;
	MonoSimpleBasicBlock *branch, *next, *current;
	const MonoOpcode *opcode;

	current = bb;

	while (ip < end) {
		cli_addr = ip - start;
		size = mono_opcode_value_and_size (&ip, end, &value);
		if (size < 0) {
			mono_error_set_not_verifiable (error, method, "Invalid instruction %x", *ip);
			return;
		}

		while (current && cli_addr >= current->end)
			current = current->next;
		g_assert (current);

		opcode = &mono_opcodes [value];
		switch (opcode->argument) {
		case MonoInlineNone:
			ip++;
			if (!mono_opcode_has_static_branch (value) || ip >= end)
				break;
			if (!(next = bb_split (bb, current, root, ip - start, FALSE, method, error)))
				return;

			bb_unlink (current, next);
			current = next;
			break;
		case MonoInlineString:
		case MonoInlineType:
		case MonoInlineField:
		case MonoInlineTok:
		case MonoInlineSig:
		case MonoShortInlineR:
		case MonoInlineI:
			ip += 5;
			break;

		case MonoInlineMethod:
			ip += 5;
			if (value != MONO_CEE_JMP || ip >= end)
				break;
			if (!(next = bb_split (bb, current, root, ip - start, FALSE, method, error)))
				return;

			bb_unlink (current, next);
			current = next;

			break;
		case MonoInlineVar:
			ip += 3;
			break;
		case MonoShortInlineVar:
		case MonoShortInlineI:
			ip += 2;
			break;
		case MonoInlineR:
		case MonoInlineI8:
			ip += 9;
			break;
		case MonoShortInlineBrTarget:
		case MonoInlineBrTarget:
			if (opcode->argument == MonoShortInlineBrTarget) {
				offset = cli_addr + 2 + (signed char)ip [1];
				ip += 2;
			} else {
				offset = cli_addr + 5 + (gint32)read32 (ip + 1);
				ip += 5;
			}
			
			branch = bb_split (bb, current, root, offset, TRUE, method, error);
			if (!branch)
				return;

			/*If we splitted the current BB*/
			if (offset < cli_addr && branch->start > current->start)
				current = branch;
			if (ip < end) {
				next = bb_split (bb, current, root, ip - start, opcode->flow_type != MONO_FLOW_BRANCH, method, error);
				if (!next)
					return;
			} else {
				next = NULL;
			}

			bb_link (current, branch);
			if (next && opcode->flow_type == MONO_FLOW_BRANCH && next != branch) {
				bb_unlink (current, next);
				current = next;
			}
			break;
		case MonoInlineSwitch: {
			MonoSimpleBasicBlock *tmp;
			guint32 j, n = read32 (ip + 1);

			ip += 5;
			offset = cli_addr + 5 + 4 * n;
			if (!(next = bb_split (bb, current, root, offset, TRUE, method, error)))
				return;

			bb_link (current, next);
			tmp = next;			

			for (j = 0; j < n; ++j) {
				if (ip >= end) {
					mono_error_set_not_verifiable (error, method, "Invalid switch instruction %x", cli_addr);
					return;
				}
				if (!(next = bb_split (bb, next, root, offset + (gint32)read32 (ip), TRUE, method, error)))
					return;
				bb_link (current, next);
				ip += 4;
			}
			current = tmp;
			break;
		}
		default:
			mono_error_set_not_verifiable (error, method, "Invalid instruction %x", *ip);
			return;
		}
	}
	if (ip != end)
		mono_error_set_not_verifiable (error, method, "Invalid last instruction");
}
Ejemplo n.º 4
0
int convert_lookupswitch(struct parse_context *ctx)
{
	struct lookupswitch_info info;
	struct lookupswitch *table;
	struct basic_block *master_bb;
	struct basic_block *default_bb;
	struct basic_block *b1;

	get_lookupswitch_info(ctx->code, ctx->offset, &info);
	ctx->buffer->pos += info.insn_size;

	default_bb = find_bb(ctx->cu, ctx->offset + info.default_target);
	if (!default_bb)
		goto fail_default_bb;

	master_bb = ctx->bb;

	b1 = bb_split(master_bb, master_bb->end);

	assert(b1);

	b1->has_branch = true;

	bb_add_successor(master_bb, default_bb );
	bb_add_successor(master_bb, b1);

	for (unsigned int i = 0; i < info.count; i++) {
		struct basic_block *target_bb;
		int32_t target;

		target = read_lookupswitch_target(&info, i);
		target_bb = find_bb(ctx->cu, ctx->offset + target);

		if (!bb_successors_contains(b1, target_bb))
			bb_add_successor(b1, target_bb);
	}

	table = alloc_lookupswitch(&info, ctx->cu, b1, ctx->offset);
	if (!table)
		return -ENOMEM;

	struct statement *if_null_stmt;
	struct statement *stmt;
	struct expression *key;
	struct expression *bsearch;
	struct expression *pure_bsearch;

	key = stack_pop(ctx->bb->mimic_stack);

	bsearch = lookupswitch_bsearch_expr(key, table);
	if (!bsearch)
		return -1;

	pure_bsearch = get_pure_expr(ctx, bsearch);

	if_null_stmt =
		branch_if_null_stmt(default_bb, pure_bsearch);
	if (!if_null_stmt)
		goto fail_null_stmt;

	stmt = alloc_statement(STMT_LOOKUPSWITCH_JUMP);
	if (!stmt)
		goto fail_stmt;

	expr_get(pure_bsearch);
	stmt->lookupswitch_target = &pure_bsearch->node;

	convert_statement(ctx, if_null_stmt);
	do_convert_statement(b1, stmt, ctx->offset);
	return 0;

 fail_stmt:
	free_statement(if_null_stmt);
 fail_null_stmt:
	free_lookupswitch(table);
 fail_default_bb:
	return -1;
}