// Start stmt duplication on marked function parameters
static struct interesting_stmts *search_interesting_calls(struct interesting_stmts *head, gcall *call_stmt)
{
	tree decl;
	unsigned int i, len;

	len = gimple_call_num_args(call_stmt);
	if (len == 0)
		return head;

	decl = get_fn_or_fnptr_decl(call_stmt);
	if (decl == NULL_TREE)
		return head;

	for (i = 0; i < len; i++) {
		tree arg;

		arg = gimple_call_arg(call_stmt, i);
		if (is_gimple_constant(arg))
			continue;
		if (skip_types(arg))
			continue;
		if (is_interesting_function(decl, i + 1))
			head = search_interesting_stmt(head, call_stmt, arg, i + 1);
	}

	return head;
}
Beispiel #2
0
bool
is_gimple_ip_invariant (const_tree t)
{
  if (TREE_CODE (t) == ADDR_EXPR)
    return is_gimple_ip_invariant_address (t);

  return is_gimple_constant (t);
}
static tree get_fn_or_fnptr_decl(const gcall *call_stmt)
{
	const_tree fnptr;
	const_gimple def_stmt;
	tree decl = gimple_call_fndecl(call_stmt);

	if (decl != NULL_TREE)
		return decl;

	fnptr = gimple_call_fn(call_stmt);
	// !!! assertot kell irni 0-ra, mert csak az lehet ott
	if (is_gimple_constant(fnptr))
		return NULL_TREE;
	def_stmt = get_fnptr_def_stmt(fnptr);
	return handle_fnptr_assign(def_stmt);
}
/* This function calls the main recursion function (expand) that duplicates the stmts. Before that it checks the intentional_overflow attribute,
 * it decides whether the duplication is necessary or not. After expand() it changes the orig node to the duplicated node
 * in the original stmt (first stmt) and it inserts the overflow check for the arg of the callee or for the return value.
 */
static struct interesting_stmts *search_interesting_stmt(struct interesting_stmts *head, gimple first_stmt, tree orig_node, unsigned int num)
{
	enum tree_code orig_code;

	gcc_assert(orig_node != NULL_TREE);

	if (is_gimple_constant(orig_node))
		return head;

	orig_code = TREE_CODE(orig_node);
	gcc_assert(orig_code != FIELD_DECL && orig_code != FUNCTION_DECL);
	gcc_assert(!skip_types(orig_node));

	if (check_intentional_asm(first_stmt, num) != MARK_NO)
		return head;

	if (SSA_NAME_IS_DEFAULT_DEF(orig_node))
		return head;

	if (skip_asm_cast(orig_node))
		return head;

	return create_interesting_stmts(head, orig_node, first_stmt, num);
}
tree handle_fnptr_assign(const_gimple stmt)
{
	tree field, rhs, op0;
	const_tree op0_type;
	enum tree_code rhs_code;

	// TODO skip binary assignments for now (fs/sync.c _591 = __bpf_call_base + _590;)
	if (gimple_num_ops(stmt) != 2)
		return NULL_TREE;

	gcc_assert(gimple_num_ops(stmt) == 2);
	// TODO skip asm_stmt for now
	if (gimple_code(stmt) == GIMPLE_ASM)
		return NULL_TREE;
	rhs = gimple_assign_rhs1(stmt);
	if (is_gimple_constant(rhs))
		return NULL_TREE;

	rhs_code = TREE_CODE(rhs);
	if (rhs_code == VAR_DECL)
		return rhs;

	switch (rhs_code) {
	case ADDR_EXPR:
		op0 = TREE_OPERAND(rhs, 0);
		gcc_assert(TREE_CODE(op0) == FUNCTION_DECL);
		return op0;
	case COMPONENT_REF:
		break;
	// TODO skip array_ref for now
	case ARRAY_REF:
		return NULL_TREE;
	// TODO skip ssa_name because it can lead to parm_decl
	case SSA_NAME:
		return NULL_TREE;
	// TODO skip mem_ref and indirect_ref for now
#if BUILDING_GCC_VERSION >= 4006
	case MEM_REF:
#endif
	case INDIRECT_REF:
		return NULL_TREE;
	default:
		debug_tree(rhs);
		debug_gimple_stmt((gimple)stmt);
		gcc_unreachable();
	}

	op0 = TREE_OPERAND(rhs, 0);
	switch (TREE_CODE(op0)) {
	// TODO skip array_ref and parm_decl for now
	case ARRAY_REF:
	case PARM_DECL:
		return NULL_TREE;
	case COMPONENT_REF:
#if BUILDING_GCC_VERSION >= 4006
	case MEM_REF:
#endif
	case INDIRECT_REF:
	case VAR_DECL:
		break;
	default:
		debug_tree(op0);
		gcc_unreachable();
	}

	op0_type = TREE_TYPE(op0);
	// TODO skip unions for now
	if (TREE_CODE(op0_type) == UNION_TYPE)
		return NULL_TREE;
	gcc_assert(TREE_CODE(op0_type) == RECORD_TYPE);

	field = TREE_OPERAND(rhs, 1);
	gcc_assert(TREE_CODE(field) == FIELD_DECL);
	return field;
}