1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2017 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  * Say you have assign a function to a function pointer and you assign a
20*1f5207b7SJohn Levon  * pointer to the data argument then we want to record some information about
21*1f5207b7SJohn Levon  * the argument.  Right now what I mainly want to record is the type of it, I
22*1f5207b7SJohn Levon  * guess.
23*1f5207b7SJohn Levon  *
24*1f5207b7SJohn Levon  */
25*1f5207b7SJohn Levon 
26*1f5207b7SJohn Levon #include "smatch.h"
27*1f5207b7SJohn Levon #include "smatch_extra.h"
28*1f5207b7SJohn Levon #include "smatch_slist.h"
29*1f5207b7SJohn Levon #include <ctype.h>
30*1f5207b7SJohn Levon 
31*1f5207b7SJohn Levon static int my_id;
32*1f5207b7SJohn Levon 
33*1f5207b7SJohn Levon static int assigns_parameters(struct expression *fn, struct expression *arg)
34*1f5207b7SJohn Levon {
35*1f5207b7SJohn Levon 	int fn_param, arg_param;
36*1f5207b7SJohn Levon 	char buf[32];
37*1f5207b7SJohn Levon 
38*1f5207b7SJohn Levon 	fn_param = get_param_num(fn);
39*1f5207b7SJohn Levon 	if (fn_param < 0)
40*1f5207b7SJohn Levon 		return 0;
41*1f5207b7SJohn Levon 
42*1f5207b7SJohn Levon 	arg_param = get_param_num(arg);
43*1f5207b7SJohn Levon 	if (arg_param < 0)
44*1f5207b7SJohn Levon 		return 0;
45*1f5207b7SJohn Levon 
46*1f5207b7SJohn Levon 	snprintf(buf, sizeof(buf), "%d", arg_param);
47*1f5207b7SJohn Levon 	sql_insert_return_implies(FN_ARG_LINK, fn_param, "$", buf);
48*1f5207b7SJohn Levon 	return 1;
49*1f5207b7SJohn Levon }
50*1f5207b7SJohn Levon 
51*1f5207b7SJohn Levon static void link_function_arg(struct expression *fn, int param, struct expression *arg)
52*1f5207b7SJohn Levon {
53*1f5207b7SJohn Levon 	struct symbol *type;
54*1f5207b7SJohn Levon 
55*1f5207b7SJohn Levon 	if (!fn || !arg)
56*1f5207b7SJohn Levon 		return;
57*1f5207b7SJohn Levon 	if (assigns_parameters(fn, arg))
58*1f5207b7SJohn Levon 		return;
59*1f5207b7SJohn Levon 
60*1f5207b7SJohn Levon 	type = get_type(arg);
61*1f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
62*1f5207b7SJohn Levon 		return;
63*1f5207b7SJohn Levon 	type = get_real_base_type(type);
64*1f5207b7SJohn Levon 	if (!type)
65*1f5207b7SJohn Levon 		return;
66*1f5207b7SJohn Levon 	// FIXME: param shouldn't always be 0?
67*1f5207b7SJohn Levon 	sql_insert_fn_data_link(fn, PASSES_TYPE, param, "$", type_to_str(type));
68*1f5207b7SJohn Levon }
69*1f5207b7SJohn Levon 
70*1f5207b7SJohn Levon char *next_param_name;
71*1f5207b7SJohn Levon struct symbol *next_param_sym;
72*1f5207b7SJohn Levon struct expression *next_fn;
73*1f5207b7SJohn Levon static void match_assign_param(struct expression *expr)
74*1f5207b7SJohn Levon {
75*1f5207b7SJohn Levon 	struct symbol *sym;
76*1f5207b7SJohn Levon 	char *name;
77*1f5207b7SJohn Levon 
78*1f5207b7SJohn Levon 	if (!next_param_name)
79*1f5207b7SJohn Levon 		return;
80*1f5207b7SJohn Levon 
81*1f5207b7SJohn Levon 	name = expr_to_var_sym(expr->left, &sym);
82*1f5207b7SJohn Levon 	if (!name || !sym) {
83*1f5207b7SJohn Levon 		free_string(name);
84*1f5207b7SJohn Levon 		return;
85*1f5207b7SJohn Levon 	}
86*1f5207b7SJohn Levon 
87*1f5207b7SJohn Levon 	if (sym != next_param_sym ||
88*1f5207b7SJohn Levon 	    strcmp(name, next_param_name) != 0)
89*1f5207b7SJohn Levon 		return;
90*1f5207b7SJohn Levon 
91*1f5207b7SJohn Levon 	link_function_arg(next_fn, 0, strip_expr(expr->right));
92*1f5207b7SJohn Levon 
93*1f5207b7SJohn Levon 	next_param_name = 0;
94*1f5207b7SJohn Levon 	next_param_sym = NULL;
95*1f5207b7SJohn Levon 	next_fn = NULL;
96*1f5207b7SJohn Levon }
97*1f5207b7SJohn Levon 
98*1f5207b7SJohn Levon static int get_arg_ptr(void *_arg_ptr, int argc, char **argv, char **azColName)
99*1f5207b7SJohn Levon {
100*1f5207b7SJohn Levon 	char **arg_ptr = _arg_ptr;
101*1f5207b7SJohn Levon 
102*1f5207b7SJohn Levon 	*arg_ptr = NULL;
103*1f5207b7SJohn Levon 	if (argc != 1)
104*1f5207b7SJohn Levon 		return 0;
105*1f5207b7SJohn Levon 	*arg_ptr = alloc_string(argv[0]);
106*1f5207b7SJohn Levon 	return 0;
107*1f5207b7SJohn Levon }
108*1f5207b7SJohn Levon 
109*1f5207b7SJohn Levon static char *get_data_member(char *fn_member, struct expression *expr, struct symbol **sym)
110*1f5207b7SJohn Levon {
111*1f5207b7SJohn Levon 	struct symbol *tmp_sym;
112*1f5207b7SJohn Levon 	char *fn_str;
113*1f5207b7SJohn Levon 	char *arg_ptr = NULL;
114*1f5207b7SJohn Levon 	char *end_type;
115*1f5207b7SJohn Levon 	int len_ptr, len_str;
116*1f5207b7SJohn Levon 	char buf[128];
117*1f5207b7SJohn Levon 
118*1f5207b7SJohn Levon 	*sym = NULL;
119*1f5207b7SJohn Levon 	run_sql(get_arg_ptr, &arg_ptr,
120*1f5207b7SJohn Levon 		"select data from fn_ptr_data_link where fn_ptr = '%s';", fn_member);
121*1f5207b7SJohn Levon 	if (!arg_ptr)
122*1f5207b7SJohn Levon 		return NULL;
123*1f5207b7SJohn Levon 	end_type = strchr(arg_ptr, '>');
124*1f5207b7SJohn Levon 	if (!end_type)
125*1f5207b7SJohn Levon 		return NULL;
126*1f5207b7SJohn Levon 	end_type++;
127*1f5207b7SJohn Levon 	fn_str = expr_to_var_sym(expr, &tmp_sym);
128*1f5207b7SJohn Levon 	if (!fn_str || !tmp_sym)
129*1f5207b7SJohn Levon 		return NULL;
130*1f5207b7SJohn Levon 	len_ptr = strlen(fn_member);
131*1f5207b7SJohn Levon 	len_str = strlen(fn_str);
132*1f5207b7SJohn Levon 	while (len_str > 0 && len_ptr > 0) {
133*1f5207b7SJohn Levon 		if (fn_str[len_str - 1] != fn_member[len_ptr - 1])
134*1f5207b7SJohn Levon 			break;
135*1f5207b7SJohn Levon 		if (fn_str[len_str - 1] == '>')
136*1f5207b7SJohn Levon 			break;
137*1f5207b7SJohn Levon 		len_str--;
138*1f5207b7SJohn Levon 		len_ptr--;
139*1f5207b7SJohn Levon 	}
140*1f5207b7SJohn Levon 
141*1f5207b7SJohn Levon 	strncpy(buf, fn_str, sizeof(buf));
142*1f5207b7SJohn Levon 	snprintf(buf + len_str, sizeof(buf) - len_str, end_type);
143*1f5207b7SJohn Levon 	*sym = tmp_sym;
144*1f5207b7SJohn Levon 	return alloc_string(buf);
145*1f5207b7SJohn Levon }
146*1f5207b7SJohn Levon 
147*1f5207b7SJohn Levon static void match_assign_function(struct expression *expr)
148*1f5207b7SJohn Levon {
149*1f5207b7SJohn Levon 	struct expression *right, *arg;
150*1f5207b7SJohn Levon 	struct symbol *sym;
151*1f5207b7SJohn Levon 	char *data_member;
152*1f5207b7SJohn Levon 	struct symbol *type;
153*1f5207b7SJohn Levon 	char *member_name;
154*1f5207b7SJohn Levon 
155*1f5207b7SJohn Levon 	right = strip_expr(expr->right);
156*1f5207b7SJohn Levon 	if (right->type == EXPR_PREOP && right->op == '&')
157*1f5207b7SJohn Levon 		right = strip_expr(right->unop);
158*1f5207b7SJohn Levon 
159*1f5207b7SJohn Levon 	type = get_type(right);
160*1f5207b7SJohn Levon 	if (type && type->type == SYM_PTR)
161*1f5207b7SJohn Levon 		type = get_real_base_type(type);
162*1f5207b7SJohn Levon 	if (!type || type->type != SYM_FN)
163*1f5207b7SJohn Levon 		return;
164*1f5207b7SJohn Levon 
165*1f5207b7SJohn Levon 	member_name = get_member_name(expr->left);
166*1f5207b7SJohn Levon 	if (!member_name)
167*1f5207b7SJohn Levon 		return;
168*1f5207b7SJohn Levon 
169*1f5207b7SJohn Levon 	data_member = get_data_member(member_name, expr->left, &sym);
170*1f5207b7SJohn Levon 	if (!data_member || !sym) {
171*1f5207b7SJohn Levon 		free_string(data_member);
172*1f5207b7SJohn Levon 		data_member = NULL;
173*1f5207b7SJohn Levon 	}
174*1f5207b7SJohn Levon 
175*1f5207b7SJohn Levon 	arg = get_assigned_expr_name_sym(data_member, sym);
176*1f5207b7SJohn Levon 	if (arg) {
177*1f5207b7SJohn Levon 		link_function_arg(right, 0, arg);
178*1f5207b7SJohn Levon 	} else {
179*1f5207b7SJohn Levon 		next_param_name = data_member;
180*1f5207b7SJohn Levon 		next_param_sym = sym;
181*1f5207b7SJohn Levon 		next_fn = right;
182*1f5207b7SJohn Levon 	}
183*1f5207b7SJohn Levon }
184*1f5207b7SJohn Levon 
185*1f5207b7SJohn Levon static int is_recursive_call(struct expression *call)
186*1f5207b7SJohn Levon {
187*1f5207b7SJohn Levon 	if (call->fn->type != EXPR_SYMBOL)
188*1f5207b7SJohn Levon 		return 0;
189*1f5207b7SJohn Levon 	if (call->fn->symbol == cur_func_sym)
190*1f5207b7SJohn Levon 		return 1;
191*1f5207b7SJohn Levon 	return 0;
192*1f5207b7SJohn Levon }
193*1f5207b7SJohn Levon 
194*1f5207b7SJohn Levon static void check_passes_fn_and_data(struct expression *call, struct expression *fn, char *key, char *value)
195*1f5207b7SJohn Levon {
196*1f5207b7SJohn Levon 	struct expression *arg;
197*1f5207b7SJohn Levon 	struct symbol *type;
198*1f5207b7SJohn Levon 	int data_nr;
199*1f5207b7SJohn Levon 
200*1f5207b7SJohn Levon 	if (is_recursive_call(call))
201*1f5207b7SJohn Levon 		return;
202*1f5207b7SJohn Levon 
203*1f5207b7SJohn Levon 	type = get_type(fn);
204*1f5207b7SJohn Levon 	if (!type || type->type != SYM_FN)
205*1f5207b7SJohn Levon 		return;
206*1f5207b7SJohn Levon 
207*1f5207b7SJohn Levon 	if (!isdigit(value[0]))
208*1f5207b7SJohn Levon 		return;
209*1f5207b7SJohn Levon 	data_nr = atoi(value);
210*1f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, data_nr);
211*1f5207b7SJohn Levon 	if (!arg)
212*1f5207b7SJohn Levon 		return;
213*1f5207b7SJohn Levon 	link_function_arg(fn, 0, arg);
214*1f5207b7SJohn Levon }
215*1f5207b7SJohn Levon 
216*1f5207b7SJohn Levon static void match_end_func(struct symbol *sym)
217*1f5207b7SJohn Levon {
218*1f5207b7SJohn Levon 	next_param_sym = NULL;
219*1f5207b7SJohn Levon 	next_fn = NULL;
220*1f5207b7SJohn Levon }
221*1f5207b7SJohn Levon 
222*1f5207b7SJohn Levon void register_about_fn_ptr_arg(int id)
223*1f5207b7SJohn Levon {
224*1f5207b7SJohn Levon 	my_id = id;
225*1f5207b7SJohn Levon 
226*1f5207b7SJohn Levon 	if (0 && !option_info)
227*1f5207b7SJohn Levon 		return;
228*1f5207b7SJohn Levon 	add_hook(match_assign_param, ASSIGNMENT_HOOK);
229*1f5207b7SJohn Levon 	add_hook(match_assign_function, ASSIGNMENT_HOOK);
230*1f5207b7SJohn Levon 	select_return_implies_hook(FN_ARG_LINK, &check_passes_fn_and_data);
231*1f5207b7SJohn Levon 	add_hook(&match_end_func, END_FUNC_HOOK);
232*1f5207b7SJohn Levon }
233