#include "smatch.h"
#include <ctype.h>
static int my_id;
static void save_in_fn_ptr_data_link_table(struct expression *fn, struct expression *arg)
{
struct symbol *fn_sym, *arg_sym;
struct symbol *type;
char *fn_name, *arg_name;
int sym_len;
char fn_buf[128];
char arg_buf[128];
fn_name = expr_to_var_sym(fn, &fn_sym);
arg_name = expr_to_var_sym(arg, &arg_sym);
if (!fn_sym || !fn_sym->ident || !arg_sym || !fn_name || !arg_name)
goto free;
if (fn_sym != arg_sym)
goto free;
sym_len = fn_sym->ident->len;
if (strncmp(fn_name, arg_name, sym_len) != 0)
goto free;
type = get_real_base_type(fn_sym);
if (!type)
goto free;
if (type->type != SYM_PTR)
goto free;
type = get_real_base_type(type);
if (!type || type->type != SYM_STRUCT || !type->ident)
goto free;
snprintf(fn_buf, sizeof(fn_buf), "(struct %s)%s", type->ident->name,
fn_name + sym_len);
snprintf(arg_buf, sizeof(arg_buf), "(struct %s)%s", type->ident->name,
arg_name + sym_len);
sql_insert_fn_ptr_data_link(fn_buf, arg_buf);
free:
free_string(arg_name);
free_string(fn_name);
}
static int print_calls_parameter(struct expression *call)
{
struct expression *arg;
int fn_param, arg_param;
char buf[32];
fn_param = get_param_num(call->fn);
if (fn_param < 0)
return 0;
arg = get_argument_from_call_expr(call->args, 0);
if (!arg)
return 0;
arg_param = get_param_num(arg);
if (arg_param < 0)
return 0;
snprintf(buf, sizeof(buf), "%d", arg_param);
sql_insert_return_implies(FN_ARG_LINK, fn_param, "$", buf);
return 0;
}
static int print_call_is_linked(struct expression *call)
{
struct expression *fn, *tmp;
struct expression *arg;
struct symbol *fn_sym;
struct symbol *arg_sym = NULL;
int i;
fn = strip_expr(call->fn);
tmp = get_assigned_expr(fn);
if (tmp)
fn = tmp;
if (fn->type != EXPR_DEREF || !fn->member)
return 0;
fn_sym = expr_to_sym(fn);
if (!fn_sym)
return 0;
i = -1;
FOR_EACH_PTR(call->args, arg) {
i++;
tmp = get_assigned_expr(arg);
if (tmp)
arg = tmp;
arg_sym = expr_to_sym(arg);
if (arg_sym == fn_sym) {
save_in_fn_ptr_data_link_table(fn, arg);
return 1;
}
} END_FOR_EACH_PTR(arg);
return 0;
}
static int is_recursive_call(struct expression *call)
{
if (call->fn->type != EXPR_SYMBOL)
return 0;
if (call->fn->symbol == cur_func_sym)
return 1;
return 0;
}
static void check_passes_fn_and_data(struct expression *call, struct expression *fn, char *key, char *value)
{
struct expression *arg;
struct expression *tmp;
struct symbol *fn_sym, *arg_sym;
struct symbol *type;
int data_nr;
int fn_param, arg_param;
if (is_recursive_call(call))
return;
type = get_type(fn);
if (!type || type->type != SYM_PTR)
return;
type = get_real_base_type(type);
if (!type || type->type != SYM_FN)
return;
tmp = get_assigned_expr(fn);
if (tmp)
fn = tmp;
if (!isdigit(value[0]))
return;
data_nr = atoi(value);
arg = get_argument_from_call_expr(call->args, data_nr);
if (!arg)
return;
tmp = get_assigned_expr(arg);
if (tmp)
arg = tmp;
fn_param = get_param_num(fn);
arg_param = get_param_num(arg);
if (fn_param >= 0 && arg_param >= 0) {
char buf[32];
snprintf(buf, sizeof(buf), "%d", arg_param);
sql_insert_return_implies(FN_ARG_LINK, fn_param, "$", buf);
return;
}
fn_sym = expr_to_sym(fn);
if (!fn_sym)
return;
arg_sym = expr_to_sym(arg);
if (arg_sym != fn_sym)
return;
save_in_fn_ptr_data_link_table(fn, tmp);
}
static void match_call_info(struct expression *call)
{
if (print_calls_parameter(call))
return;
if (print_call_is_linked(call))
return;
}
void register_fn_arg_link(int id)
{
my_id = id;
if (!option_info)
return;
add_hook(&match_call_info, FUNCTION_CALL_HOOK);
select_return_implies_hook(FN_ARG_LINK, &check_passes_fn_and_data);
}