1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2016 Oracle.
3*1f5207b7SJohn Levon  *
4*1f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
5*1f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
6*1f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
7*1f5207b7SJohn Levon  * of the License, or (at your option) any later version.
8*1f5207b7SJohn Levon  *
9*1f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
10*1f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*1f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*1f5207b7SJohn Levon  * GNU General Public License for more details.
13*1f5207b7SJohn Levon  *
14*1f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
15*1f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16*1f5207b7SJohn Levon  */
17*1f5207b7SJohn Levon 
18*1f5207b7SJohn Levon /*
19*1f5207b7SJohn Levon  * What we're trying to do here is record links between function pointers and
20*1f5207b7SJohn Levon  * function data.  If you have foo->function(foo->data); that's very easy.  But
21*1f5207b7SJohn Levon  * the problem is maybe when you pass the function and the data as parameters.
22*1f5207b7SJohn Levon  *
23*1f5207b7SJohn Levon  */
24*1f5207b7SJohn Levon 
25*1f5207b7SJohn Levon #include "smatch.h"
26*1f5207b7SJohn Levon #include <ctype.h>
27*1f5207b7SJohn Levon 
28*1f5207b7SJohn Levon static int my_id;
29*1f5207b7SJohn Levon 
save_in_fn_ptr_data_link_table(struct expression * fn,struct expression * arg)30*1f5207b7SJohn Levon static void save_in_fn_ptr_data_link_table(struct expression *fn, struct expression *arg)
31*1f5207b7SJohn Levon {
32*1f5207b7SJohn Levon 	struct symbol *fn_sym, *arg_sym;
33*1f5207b7SJohn Levon 	struct symbol *type;
34*1f5207b7SJohn Levon 	char *fn_name, *arg_name;
35*1f5207b7SJohn Levon 	int sym_len;
36*1f5207b7SJohn Levon 	char fn_buf[128];
37*1f5207b7SJohn Levon 	char arg_buf[128];
38*1f5207b7SJohn Levon 
39*1f5207b7SJohn Levon 	fn_name = expr_to_var_sym(fn, &fn_sym);
40*1f5207b7SJohn Levon 	arg_name = expr_to_var_sym(arg, &arg_sym);
41*1f5207b7SJohn Levon 	if (!fn_sym || !fn_sym->ident || !arg_sym || !fn_name || !arg_name)
42*1f5207b7SJohn Levon 		goto free;
43*1f5207b7SJohn Levon 	if (fn_sym != arg_sym)
44*1f5207b7SJohn Levon 		goto free;
45*1f5207b7SJohn Levon 
46*1f5207b7SJohn Levon 	sym_len = fn_sym->ident->len;
47*1f5207b7SJohn Levon 
48*1f5207b7SJohn Levon 	/* This is ignoring
49*1f5207b7SJohn Levon 	 * net/mac80211/driver-ops.h:482 drv_sta_remove() FN: local->ops->sta_remove ARG: &local->hw
50*1f5207b7SJohn Levon 	 * but ideally the restriction can be removed later.
51*1f5207b7SJohn Levon 	 */
52*1f5207b7SJohn Levon 	if (strncmp(fn_name, arg_name, sym_len) != 0)
53*1f5207b7SJohn Levon 		goto free;
54*1f5207b7SJohn Levon 
55*1f5207b7SJohn Levon 	type = get_real_base_type(fn_sym);
56*1f5207b7SJohn Levon 	if (!type)
57*1f5207b7SJohn Levon 		goto free;
58*1f5207b7SJohn Levon 	if (type->type != SYM_PTR)
59*1f5207b7SJohn Levon 		goto free;
60*1f5207b7SJohn Levon 	type = get_real_base_type(type);
61*1f5207b7SJohn Levon 	if (!type || type->type != SYM_STRUCT || !type->ident)
62*1f5207b7SJohn Levon 		goto free;
63*1f5207b7SJohn Levon 
64*1f5207b7SJohn Levon 	snprintf(fn_buf, sizeof(fn_buf), "(struct %s)%s", type->ident->name,
65*1f5207b7SJohn Levon 		 fn_name + sym_len);
66*1f5207b7SJohn Levon 
67*1f5207b7SJohn Levon 	snprintf(arg_buf, sizeof(arg_buf), "(struct %s)%s", type->ident->name,
68*1f5207b7SJohn Levon 		 arg_name + sym_len);
69*1f5207b7SJohn Levon 
70*1f5207b7SJohn Levon 	sql_insert_fn_ptr_data_link(fn_buf, arg_buf);
71*1f5207b7SJohn Levon free:
72*1f5207b7SJohn Levon 	free_string(arg_name);
73*1f5207b7SJohn Levon 	free_string(fn_name);
74*1f5207b7SJohn Levon }
75*1f5207b7SJohn Levon 
print_calls_parameter(struct expression * call)76*1f5207b7SJohn Levon static int print_calls_parameter(struct expression *call)
77*1f5207b7SJohn Levon {
78*1f5207b7SJohn Levon 	struct expression *arg;
79*1f5207b7SJohn Levon 	int fn_param, arg_param;
80*1f5207b7SJohn Levon 	char buf[32];
81*1f5207b7SJohn Levon 
82*1f5207b7SJohn Levon 	fn_param = get_param_num(call->fn);
83*1f5207b7SJohn Levon 	if (fn_param < 0)
84*1f5207b7SJohn Levon 		return 0;
85*1f5207b7SJohn Levon 
86*1f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, 0);
87*1f5207b7SJohn Levon 	if (!arg)
88*1f5207b7SJohn Levon 		return 0;
89*1f5207b7SJohn Levon 
90*1f5207b7SJohn Levon 	arg_param = get_param_num(arg);
91*1f5207b7SJohn Levon 	if (arg_param < 0)
92*1f5207b7SJohn Levon 		return 0;
93*1f5207b7SJohn Levon 
94*1f5207b7SJohn Levon 	snprintf(buf, sizeof(buf), "%d", arg_param);
95*1f5207b7SJohn Levon 	sql_insert_return_implies(FN_ARG_LINK, fn_param, "$", buf);
96*1f5207b7SJohn Levon 	return 0;
97*1f5207b7SJohn Levon }
98*1f5207b7SJohn Levon 
print_call_is_linked(struct expression * call)99*1f5207b7SJohn Levon static int print_call_is_linked(struct expression *call)
100*1f5207b7SJohn Levon {
101*1f5207b7SJohn Levon 	struct expression *fn, *tmp;
102*1f5207b7SJohn Levon 	struct expression *arg;
103*1f5207b7SJohn Levon 	struct symbol *fn_sym;
104*1f5207b7SJohn Levon 	struct symbol *arg_sym = NULL;
105*1f5207b7SJohn Levon 	int i;
106*1f5207b7SJohn Levon 
107*1f5207b7SJohn Levon 	fn = strip_expr(call->fn);
108*1f5207b7SJohn Levon 	tmp = get_assigned_expr(fn);
109*1f5207b7SJohn Levon 	if (tmp)
110*1f5207b7SJohn Levon 		fn = tmp;
111*1f5207b7SJohn Levon 	if (fn->type != EXPR_DEREF || !fn->member)
112*1f5207b7SJohn Levon 		return 0;
113*1f5207b7SJohn Levon 
114*1f5207b7SJohn Levon 	fn_sym = expr_to_sym(fn);
115*1f5207b7SJohn Levon 	if (!fn_sym)
116*1f5207b7SJohn Levon 		return 0;
117*1f5207b7SJohn Levon 
118*1f5207b7SJohn Levon 	i = -1;
119*1f5207b7SJohn Levon 	FOR_EACH_PTR(call->args, arg) {
120*1f5207b7SJohn Levon 		i++;
121*1f5207b7SJohn Levon 		tmp = get_assigned_expr(arg);
122*1f5207b7SJohn Levon 		if (tmp)
123*1f5207b7SJohn Levon 			arg = tmp;
124*1f5207b7SJohn Levon 		arg_sym = expr_to_sym(arg);
125*1f5207b7SJohn Levon 		if (arg_sym == fn_sym) {
126*1f5207b7SJohn Levon 			save_in_fn_ptr_data_link_table(fn, arg);
127*1f5207b7SJohn Levon 			return 1;
128*1f5207b7SJohn Levon 		}
129*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
130*1f5207b7SJohn Levon 
131*1f5207b7SJohn Levon 	return 0;
132*1f5207b7SJohn Levon }
133*1f5207b7SJohn Levon 
is_recursive_call(struct expression * call)134*1f5207b7SJohn Levon static int is_recursive_call(struct expression *call)
135*1f5207b7SJohn Levon {
136*1f5207b7SJohn Levon 	if (call->fn->type != EXPR_SYMBOL)
137*1f5207b7SJohn Levon 		return 0;
138*1f5207b7SJohn Levon 	if (call->fn->symbol == cur_func_sym)
139*1f5207b7SJohn Levon 		return 1;
140*1f5207b7SJohn Levon 	return 0;
141*1f5207b7SJohn Levon }
142*1f5207b7SJohn Levon 
check_passes_fn_and_data(struct expression * call,struct expression * fn,char * key,char * value)143*1f5207b7SJohn Levon static void check_passes_fn_and_data(struct expression *call, struct expression *fn, char *key, char *value)
144*1f5207b7SJohn Levon {
145*1f5207b7SJohn Levon 	struct expression *arg;
146*1f5207b7SJohn Levon 	struct expression *tmp;
147*1f5207b7SJohn Levon 	struct symbol *fn_sym, *arg_sym;
148*1f5207b7SJohn Levon 	struct symbol *type;
149*1f5207b7SJohn Levon 	int data_nr;
150*1f5207b7SJohn Levon 	int fn_param, arg_param;
151*1f5207b7SJohn Levon 
152*1f5207b7SJohn Levon 	if (is_recursive_call(call))
153*1f5207b7SJohn Levon 		return;
154*1f5207b7SJohn Levon 
155*1f5207b7SJohn Levon 	type = get_type(fn);
156*1f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
157*1f5207b7SJohn Levon 		return;
158*1f5207b7SJohn Levon 	type = get_real_base_type(type);
159*1f5207b7SJohn Levon 	if (!type || type->type != SYM_FN)
160*1f5207b7SJohn Levon 		return;
161*1f5207b7SJohn Levon 	tmp = get_assigned_expr(fn);
162*1f5207b7SJohn Levon 	if (tmp)
163*1f5207b7SJohn Levon 		fn = tmp;
164*1f5207b7SJohn Levon 
165*1f5207b7SJohn Levon 	if (!isdigit(value[0]))
166*1f5207b7SJohn Levon 		return;
167*1f5207b7SJohn Levon 	data_nr = atoi(value);
168*1f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, data_nr);
169*1f5207b7SJohn Levon 	if (!arg)
170*1f5207b7SJohn Levon 		return;
171*1f5207b7SJohn Levon 	tmp = get_assigned_expr(arg);
172*1f5207b7SJohn Levon 	if (tmp)
173*1f5207b7SJohn Levon 		arg = tmp;
174*1f5207b7SJohn Levon 
175*1f5207b7SJohn Levon 	fn_param = get_param_num(fn);
176*1f5207b7SJohn Levon 	arg_param = get_param_num(arg);
177*1f5207b7SJohn Levon 	if (fn_param >= 0 && arg_param >= 0) {
178*1f5207b7SJohn Levon 		char buf[32];
179*1f5207b7SJohn Levon 
180*1f5207b7SJohn Levon 		snprintf(buf, sizeof(buf), "%d", arg_param);
181*1f5207b7SJohn Levon 		sql_insert_return_implies(FN_ARG_LINK, fn_param, "$", buf);
182*1f5207b7SJohn Levon 		return;
183*1f5207b7SJohn Levon 	}
184*1f5207b7SJohn Levon 
185*1f5207b7SJohn Levon 	fn_sym = expr_to_sym(fn);
186*1f5207b7SJohn Levon 	if (!fn_sym)
187*1f5207b7SJohn Levon 		return;
188*1f5207b7SJohn Levon 	arg_sym = expr_to_sym(arg);
189*1f5207b7SJohn Levon 	if (arg_sym != fn_sym)
190*1f5207b7SJohn Levon 		return;
191*1f5207b7SJohn Levon 	save_in_fn_ptr_data_link_table(fn, tmp);
192*1f5207b7SJohn Levon }
193*1f5207b7SJohn Levon 
match_call_info(struct expression * call)194*1f5207b7SJohn Levon static void match_call_info(struct expression *call)
195*1f5207b7SJohn Levon {
196*1f5207b7SJohn Levon 	if (print_calls_parameter(call))
197*1f5207b7SJohn Levon 		return;
198*1f5207b7SJohn Levon 	if (print_call_is_linked(call))
199*1f5207b7SJohn Levon 		return;
200*1f5207b7SJohn Levon }
201*1f5207b7SJohn Levon 
register_fn_arg_link(int id)202*1f5207b7SJohn Levon void register_fn_arg_link(int id)
203*1f5207b7SJohn Levon {
204*1f5207b7SJohn Levon 	my_id = id;
205*1f5207b7SJohn Levon 
206*1f5207b7SJohn Levon 	if (!option_info)
207*1f5207b7SJohn Levon 		return;
208*1f5207b7SJohn Levon 
209*1f5207b7SJohn Levon 	add_hook(&match_call_info, FUNCTION_CALL_HOOK);
210*1f5207b7SJohn Levon 	select_return_implies_hook(FN_ARG_LINK, &check_passes_fn_and_data);
211*1f5207b7SJohn Levon }
212*1f5207b7SJohn Levon 
213