// 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; }
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; }