2 * Copyright (C) 2016 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * What we're trying to do here is record links between function pointers and
20 * function data. If you have foo->function(foo->data); that's very easy. But
21 * the problem is maybe when you pass the function and the data as parameters.
30 static void save_in_fn_ptr_data_link_table(struct expression
*fn
, struct expression
*arg
)
32 struct symbol
*fn_sym
, *arg_sym
;
34 char *fn_name
, *arg_name
;
39 fn_name
= expr_to_var_sym(fn
, &fn_sym
);
40 arg_name
= expr_to_var_sym(arg
, &arg_sym
);
41 if (!fn_sym
|| !fn_sym
->ident
|| !arg_sym
|| !fn_name
|| !arg_name
)
43 if (fn_sym
!= arg_sym
)
46 sym_len
= fn_sym
->ident
->len
;
49 * net/mac80211/driver-ops.h:482 drv_sta_remove() FN: local->ops->sta_remove ARG: &local->hw
50 * but ideally the restriction can be removed later.
52 if (strncmp(fn_name
, arg_name
, sym_len
) != 0)
55 type
= get_real_base_type(fn_sym
);
58 if (type
->type
!= SYM_PTR
)
60 type
= get_real_base_type(type
);
61 if (!type
|| type
->type
!= SYM_STRUCT
|| !type
->ident
)
64 snprintf(fn_buf
, sizeof(fn_buf
), "(struct %s)%s", type
->ident
->name
,
67 snprintf(arg_buf
, sizeof(arg_buf
), "(struct %s)%s", type
->ident
->name
,
70 sql_insert_fn_ptr_data_link(fn_buf
, arg_buf
);
72 free_string(arg_name
);
76 static int print_calls_parameter(struct expression
*call
)
78 struct expression
*arg
;
79 int fn_param
, arg_param
;
82 fn_param
= get_param_num(call
->fn
);
86 arg
= get_argument_from_call_expr(call
->args
, 0);
90 arg_param
= get_param_num(arg
);
94 snprintf(buf
, sizeof(buf
), "%d", arg_param
);
95 sql_insert_return_implies(FN_ARG_LINK
, fn_param
, "$", buf
);
99 static int print_call_is_linked(struct expression
*call
)
101 struct expression
*fn
, *tmp
;
102 struct expression
*arg
;
103 struct symbol
*fn_sym
;
104 struct symbol
*arg_sym
= NULL
;
107 fn
= strip_expr(call
->fn
);
108 tmp
= get_assigned_expr(fn
);
111 if (fn
->type
!= EXPR_DEREF
|| !fn
->member
)
114 fn_sym
= expr_to_sym(fn
);
119 FOR_EACH_PTR(call
->args
, arg
) {
121 tmp
= get_assigned_expr(arg
);
124 arg_sym
= expr_to_sym(arg
);
125 if (arg_sym
== fn_sym
) {
126 save_in_fn_ptr_data_link_table(fn
, arg
);
129 } END_FOR_EACH_PTR(arg
);
134 static int is_recursive_call(struct expression
*call
)
136 if (call
->fn
->type
!= EXPR_SYMBOL
)
138 if (call
->fn
->symbol
== cur_func_sym
)
143 static void check_passes_fn_and_data(struct expression
*call
, struct expression
*fn
, char *key
, char *value
)
145 struct expression
*arg
;
146 struct expression
*tmp
;
147 struct symbol
*fn_sym
, *arg_sym
;
150 int fn_param
, arg_param
;
152 if (is_recursive_call(call
))
156 if (!type
|| type
->type
!= SYM_PTR
)
158 type
= get_real_base_type(type
);
159 if (!type
|| type
->type
!= SYM_FN
)
161 tmp
= get_assigned_expr(fn
);
165 if (!isdigit(value
[0]))
167 data_nr
= atoi(value
);
168 arg
= get_argument_from_call_expr(call
->args
, data_nr
);
171 tmp
= get_assigned_expr(arg
);
175 fn_param
= get_param_num(fn
);
176 arg_param
= get_param_num(arg
);
177 if (fn_param
>= 0 && arg_param
>= 0) {
180 snprintf(buf
, sizeof(buf
), "%d", arg_param
);
181 sql_insert_return_implies(FN_ARG_LINK
, fn_param
, "$", buf
);
185 fn_sym
= expr_to_sym(fn
);
188 arg_sym
= expr_to_sym(arg
);
189 if (arg_sym
!= fn_sym
)
191 save_in_fn_ptr_data_link_table(fn
, tmp
);
194 static void match_call_info(struct expression
*call
)
196 if (print_calls_parameter(call
))
198 if (print_call_is_linked(call
))
202 void register_fn_arg_link(int id
)
209 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
210 select_return_implies_hook(FN_ARG_LINK
, &check_passes_fn_and_data
);