11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2013 Oracle.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon /*
191f5207b7SJohn Levon  * The plan here is to save all the possible values store to a given struct
201f5207b7SJohn Levon  * member.
211f5207b7SJohn Levon  *
221f5207b7SJohn Levon  * We will load all the values in to the function_type_val table first then
231f5207b7SJohn Levon  * run a script on that and load all the resulting values into the type_val
241f5207b7SJohn Levon  * table.
251f5207b7SJohn Levon  *
261f5207b7SJohn Levon  * So in this file we want to take the union of everything assigned to the
271f5207b7SJohn Levon  * struct member and insert it into the function_type_val at the end.
281f5207b7SJohn Levon  *
291f5207b7SJohn Levon  * You would think that we could use smatch_modification_hooks.c or
301f5207b7SJohn Levon  * extra_modification_hook() here to get the information here but in the end we
311f5207b7SJohn Levon  * need to code everything again a third time.
321f5207b7SJohn Levon  *
331f5207b7SJohn Levon  */
341f5207b7SJohn Levon 
351f5207b7SJohn Levon #include "smatch.h"
361f5207b7SJohn Levon #include "smatch_slist.h"
371f5207b7SJohn Levon #include "smatch_extra.h"
381f5207b7SJohn Levon 
391f5207b7SJohn Levon static int my_id;
401f5207b7SJohn Levon 
411f5207b7SJohn Levon struct stree_stack *fn_type_val_stack;
421f5207b7SJohn Levon struct stree *fn_type_val;
431f5207b7SJohn Levon struct stree *global_type_val;
441f5207b7SJohn Levon 
451f5207b7SJohn Levon static int get_vals(void *_db_vals, int argc, char **argv, char **azColName)
461f5207b7SJohn Levon {
471f5207b7SJohn Levon 	char **db_vals = _db_vals;
481f5207b7SJohn Levon 
491f5207b7SJohn Levon 	*db_vals = alloc_string(argv[0]);
501f5207b7SJohn Levon 	return 0;
511f5207b7SJohn Levon }
521f5207b7SJohn Levon 
531f5207b7SJohn Levon static void match_inline_start(struct expression *expr)
541f5207b7SJohn Levon {
551f5207b7SJohn Levon 	push_stree(&fn_type_val_stack, fn_type_val);
561f5207b7SJohn Levon 	fn_type_val = NULL;
571f5207b7SJohn Levon }
581f5207b7SJohn Levon 
591f5207b7SJohn Levon static void match_inline_end(struct expression *expr)
601f5207b7SJohn Levon {
611f5207b7SJohn Levon 	free_stree(&fn_type_val);
621f5207b7SJohn Levon 	fn_type_val = pop_stree(&fn_type_val_stack);
631f5207b7SJohn Levon }
641f5207b7SJohn Levon 
651f5207b7SJohn Levon struct expr_rl {
661f5207b7SJohn Levon 	struct expression *expr;
671f5207b7SJohn Levon 	struct range_list *rl;
681f5207b7SJohn Levon };
691f5207b7SJohn Levon static struct expr_rl cached_results[10];
701f5207b7SJohn Levon static int res_idx;
711f5207b7SJohn Levon 
721f5207b7SJohn Levon static int get_cached(struct expression *expr, struct range_list **rl, int *ret)
731f5207b7SJohn Levon {
741f5207b7SJohn Levon 	int i;
751f5207b7SJohn Levon 
761f5207b7SJohn Levon 	*ret = 0;
771f5207b7SJohn Levon 
781f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(cached_results); i++) {
791f5207b7SJohn Levon 		if (expr == cached_results[i].expr) {
801f5207b7SJohn Levon 			if (cached_results[i].rl) {
811f5207b7SJohn Levon 				*rl = clone_rl(cached_results[i].rl);
821f5207b7SJohn Levon 				*ret = 1;
831f5207b7SJohn Levon 			}
841f5207b7SJohn Levon 			return 1;
851f5207b7SJohn Levon 		}
861f5207b7SJohn Levon 	}
871f5207b7SJohn Levon 
881f5207b7SJohn Levon 	return 0;
891f5207b7SJohn Levon }
901f5207b7SJohn Levon 
911f5207b7SJohn Levon int get_db_type_rl(struct expression *expr, struct range_list **rl)
921f5207b7SJohn Levon {
931f5207b7SJohn Levon 	char *db_vals = NULL;
941f5207b7SJohn Levon 	char *member;
951f5207b7SJohn Levon 	struct range_list *tmp;
961f5207b7SJohn Levon 	struct symbol *type;
971f5207b7SJohn Levon 	int ret;
981f5207b7SJohn Levon 
991f5207b7SJohn Levon 	if (get_cached(expr, rl, &ret))
1001f5207b7SJohn Levon 		return ret;
1011f5207b7SJohn Levon 
1021f5207b7SJohn Levon 	member = get_member_name(expr);
1031f5207b7SJohn Levon 	if (!member)
1041f5207b7SJohn Levon 		return 0;
1051f5207b7SJohn Levon 
1061f5207b7SJohn Levon 	res_idx = (res_idx + 1) % ARRAY_SIZE(cached_results);
1071f5207b7SJohn Levon 	cached_results[res_idx].expr = expr;
1081f5207b7SJohn Levon 	cached_results[res_idx].rl = NULL;
1091f5207b7SJohn Levon 
1101f5207b7SJohn Levon 	run_sql(get_vals, &db_vals,
1111f5207b7SJohn Levon 		"select value from type_value where type = '%s';", member);
1121f5207b7SJohn Levon 	free_string(member);
1131f5207b7SJohn Levon 	if (!db_vals)
1141f5207b7SJohn Levon 		return 0;
1151f5207b7SJohn Levon 	type = get_type(expr);
1161f5207b7SJohn Levon 	str_to_rl(type, db_vals, &tmp);
1171f5207b7SJohn Levon 	free_string(db_vals);
1181f5207b7SJohn Levon 	if (is_whole_rl(tmp))
1191f5207b7SJohn Levon 		return 0;
1201f5207b7SJohn Levon 
1211f5207b7SJohn Levon 	*rl = tmp;
1221f5207b7SJohn Levon 	cached_results[res_idx].rl = clone_rl(tmp);
1231f5207b7SJohn Levon 
1241f5207b7SJohn Levon 	return 1;
1251f5207b7SJohn Levon }
1261f5207b7SJohn Levon 
1271f5207b7SJohn Levon static void add_type_val(char *member, struct range_list *rl)
1281f5207b7SJohn Levon {
1291f5207b7SJohn Levon 	struct smatch_state *old, *add, *new;
1301f5207b7SJohn Levon 
1311f5207b7SJohn Levon 	member = alloc_string(member);
1321f5207b7SJohn Levon 	old = get_state_stree(fn_type_val, my_id, member, NULL);
1331f5207b7SJohn Levon 	add = alloc_estate_rl(rl);
1341f5207b7SJohn Levon 	if (old)
1351f5207b7SJohn Levon 		new = merge_estates(old, add);
1361f5207b7SJohn Levon 	else
1371f5207b7SJohn Levon 		new = add;
1381f5207b7SJohn Levon 	set_state_stree(&fn_type_val, my_id, member, NULL, new);
1391f5207b7SJohn Levon }
1401f5207b7SJohn Levon 
1411f5207b7SJohn Levon static void add_fake_type_val(char *member, struct range_list *rl, int ignore)
1421f5207b7SJohn Levon {
1431f5207b7SJohn Levon 	struct smatch_state *old, *add, *new;
1441f5207b7SJohn Levon 
1451f5207b7SJohn Levon 	member = alloc_string(member);
1461f5207b7SJohn Levon 	old = get_state_stree(fn_type_val, my_id, member, NULL);
1471f5207b7SJohn Levon 	if (old && strcmp(old->name, "min-max") == 0)
1481f5207b7SJohn Levon 		return;
1491f5207b7SJohn Levon 	if (ignore && old && strcmp(old->name, "ignore") == 0)
1501f5207b7SJohn Levon 		return;
1511f5207b7SJohn Levon 	add = alloc_estate_rl(rl);
1521f5207b7SJohn Levon 	if (old) {
1531f5207b7SJohn Levon 		new = merge_estates(old, add);
1541f5207b7SJohn Levon 	} else {
1551f5207b7SJohn Levon 		new = add;
1561f5207b7SJohn Levon 		if (ignore)
1571f5207b7SJohn Levon 			new->name = alloc_string("ignore");
1581f5207b7SJohn Levon 		else
1591f5207b7SJohn Levon 			new->name = alloc_string("min-max");
1601f5207b7SJohn Levon 	}
1611f5207b7SJohn Levon 	set_state_stree(&fn_type_val, my_id, member, NULL, new);
1621f5207b7SJohn Levon }
1631f5207b7SJohn Levon 
1641f5207b7SJohn Levon static void add_global_type_val(char *member, struct range_list *rl)
1651f5207b7SJohn Levon {
1661f5207b7SJohn Levon 	struct smatch_state *old, *add, *new;
1671f5207b7SJohn Levon 
1681f5207b7SJohn Levon 	member = alloc_string(member);
1691f5207b7SJohn Levon 	old = get_state_stree(global_type_val, my_id, member, NULL);
1701f5207b7SJohn Levon 	add = alloc_estate_rl(rl);
1711f5207b7SJohn Levon 	if (old)
1721f5207b7SJohn Levon 		new = merge_estates(old, add);
1731f5207b7SJohn Levon 	else
1741f5207b7SJohn Levon 		new = add;
1751f5207b7SJohn Levon 	new = clone_estate_perm(new);
1761f5207b7SJohn Levon 	set_state_stree_perm(&global_type_val, my_id, member, NULL, new);
1771f5207b7SJohn Levon }
1781f5207b7SJohn Levon 
1791f5207b7SJohn Levon static int has_link_cb(void *has_link, int argc, char **argv, char **azColName)
1801f5207b7SJohn Levon {
1811f5207b7SJohn Levon 	*(int *)has_link = 1;
1821f5207b7SJohn Levon 	return 0;
1831f5207b7SJohn Levon }
1841f5207b7SJohn Levon 
1851f5207b7SJohn Levon static int is_ignored_fake_assignment(void)
1861f5207b7SJohn Levon {
1871f5207b7SJohn Levon 	struct expression *expr;
1881f5207b7SJohn Levon 	struct symbol *type;
1891f5207b7SJohn Levon 	char *member_name;
1901f5207b7SJohn Levon 	int has_link = 0;
1911f5207b7SJohn Levon 
1921f5207b7SJohn Levon 	expr = get_faked_expression();
1931f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT)
1941f5207b7SJohn Levon 		return 0;
1951f5207b7SJohn Levon 	if (!is_void_pointer(expr->right))
1961f5207b7SJohn Levon 		return 0;
1971f5207b7SJohn Levon 	member_name = get_member_name(expr->right);
1981f5207b7SJohn Levon 	if (!member_name)
1991f5207b7SJohn Levon 		return 0;
2001f5207b7SJohn Levon 
2011f5207b7SJohn Levon 	type = get_type(expr->left);
2021f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
2031f5207b7SJohn Levon 		return 0;
2041f5207b7SJohn Levon 	type = get_real_base_type(type);
2051f5207b7SJohn Levon 	if (!type || type->type != SYM_STRUCT)
2061f5207b7SJohn Levon 		return 0;
2071f5207b7SJohn Levon 
2081f5207b7SJohn Levon 	run_sql(has_link_cb, &has_link,
2091f5207b7SJohn Levon 		"select * from data_info where type = %d and data = '%s' and value = '%s';",
2101f5207b7SJohn Levon 		TYPE_LINK, member_name, type_to_str(type));
2111f5207b7SJohn Levon 	return has_link;
2121f5207b7SJohn Levon }
2131f5207b7SJohn Levon 
2141f5207b7SJohn Levon static int is_container_of(void)
2151f5207b7SJohn Levon {
2161f5207b7SJohn Levon 	/* We already check the macro name in is_ignored_macro() */
2171f5207b7SJohn Levon 	struct expression *expr;
2181f5207b7SJohn Levon 	int offset;
2191f5207b7SJohn Levon 
2201f5207b7SJohn Levon 	expr = get_faked_expression();
2211f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT)
2221f5207b7SJohn Levon 		return 0;
2231f5207b7SJohn Levon 
2241f5207b7SJohn Levon 	offset = get_offset_from_container_of(expr->right);
2251f5207b7SJohn Levon 	if (offset < 0)
2261f5207b7SJohn Levon 		return 0;
2271f5207b7SJohn Levon 	return 1;
2281f5207b7SJohn Levon }
2291f5207b7SJohn Levon 
230*c85f09ccSJohn Levon static bool is_driver_data(void)
2311f5207b7SJohn Levon {
232*c85f09ccSJohn Levon 	static struct expression *prev_expr;
2331f5207b7SJohn Levon 	struct expression *expr;
2341f5207b7SJohn Levon 	char *name;
235*c85f09ccSJohn Levon 	static bool prev_ret;
236*c85f09ccSJohn Levon 	bool ret = false;
2371f5207b7SJohn Levon 
2381f5207b7SJohn Levon 	expr = get_faked_expression();
2391f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT)
240*c85f09ccSJohn Levon 		return false;
241*c85f09ccSJohn Levon 
242*c85f09ccSJohn Levon 	if (expr == prev_expr)
243*c85f09ccSJohn Levon 		return prev_ret;
244*c85f09ccSJohn Levon 	prev_expr = expr;
245*c85f09ccSJohn Levon 
246*c85f09ccSJohn Levon 	name = expr_to_str(expr->right);
247*c85f09ccSJohn Levon 	if (!name) {
248*c85f09ccSJohn Levon 		prev_ret = false;
249*c85f09ccSJohn Levon 		return false;
250*c85f09ccSJohn Levon 	}
251*c85f09ccSJohn Levon 
252*c85f09ccSJohn Levon 	if (strstr(name, "get_drvdata(") ||
253*c85f09ccSJohn Levon 	    strstr(name, "dev.driver_data") ||
254*c85f09ccSJohn Levon 	    strstr(name, "dev->driver_data"))
255*c85f09ccSJohn Levon 		ret = true;
256*c85f09ccSJohn Levon 
257*c85f09ccSJohn Levon 	free_string(name);
258*c85f09ccSJohn Levon 
259*c85f09ccSJohn Levon 	prev_ret = ret;
260*c85f09ccSJohn Levon 	return ret;
261*c85f09ccSJohn Levon }
262*c85f09ccSJohn Levon 
263*c85f09ccSJohn Levon static int is_ignored_macro(void)
264*c85f09ccSJohn Levon {
265*c85f09ccSJohn Levon 	struct expression *expr;
266*c85f09ccSJohn Levon 	char *name;
267*c85f09ccSJohn Levon 
268*c85f09ccSJohn Levon 	expr = get_faked_expression();
269*c85f09ccSJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
2701f5207b7SJohn Levon 		return 0;
2711f5207b7SJohn Levon 	name = get_macro_name(expr->right->pos);
2721f5207b7SJohn Levon 	if (!name)
2731f5207b7SJohn Levon 		return 0;
2741f5207b7SJohn Levon 	if (strcmp(name, "container_of") == 0)
2751f5207b7SJohn Levon 		return 1;
2761f5207b7SJohn Levon 	if (strcmp(name, "rb_entry") == 0)
2771f5207b7SJohn Levon 		return 1;
2781f5207b7SJohn Levon 	if (strcmp(name, "list_entry") == 0)
2791f5207b7SJohn Levon 		return 1;
2801f5207b7SJohn Levon 	if (strcmp(name, "list_first_entry") == 0)
2811f5207b7SJohn Levon 		return 1;
2821f5207b7SJohn Levon 	if (strcmp(name, "hlist_entry") == 0)
2831f5207b7SJohn Levon 		return 1;
284*c85f09ccSJohn Levon 	if (strcmp(name, "per_cpu_ptr") == 0)
285*c85f09ccSJohn Levon 		return 1;
286*c85f09ccSJohn Levon 	if (strcmp(name, "raw_cpu_ptr") == 0)
287*c85f09ccSJohn Levon 		return 1;
288*c85f09ccSJohn Levon 	if (strcmp(name, "this_cpu_ptr") == 0)
289*c85f09ccSJohn Levon 		return 1;
290*c85f09ccSJohn Levon 
291*c85f09ccSJohn Levon 	if (strcmp(name, "TRACE_EVENT") == 0)
292*c85f09ccSJohn Levon 		return 1;
293*c85f09ccSJohn Levon 	if (strcmp(name, "DECLARE_EVENT_CLASS") == 0)
294*c85f09ccSJohn Levon 		return 1;
295*c85f09ccSJohn Levon 	if (strcmp(name, "DEFINE_EVENT") == 0)
296*c85f09ccSJohn Levon 		return 1;
297*c85f09ccSJohn Levon 
2981f5207b7SJohn Levon 	if (strstr(name, "for_each"))
2991f5207b7SJohn Levon 		return 1;
3001f5207b7SJohn Levon 	return 0;
3011f5207b7SJohn Levon }
3021f5207b7SJohn Levon 
3031f5207b7SJohn Levon static int is_ignored_function(void)
3041f5207b7SJohn Levon {
3051f5207b7SJohn Levon 	struct expression *expr;
3061f5207b7SJohn Levon 
3071f5207b7SJohn Levon 	expr = get_faked_expression();
3081f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT)
3091f5207b7SJohn Levon 		return 0;
3101f5207b7SJohn Levon 	expr = strip_expr(expr->right);
3111f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
3121f5207b7SJohn Levon 		return 0;
3131f5207b7SJohn Levon 
3141f5207b7SJohn Levon 	if (sym_name_is("kmalloc", expr->fn))
3151f5207b7SJohn Levon 		return 1;
316*c85f09ccSJohn Levon 	if (sym_name_is("vmalloc", expr->fn))
317*c85f09ccSJohn Levon 		return 1;
318*c85f09ccSJohn Levon 	if (sym_name_is("kvmalloc", expr->fn))
319*c85f09ccSJohn Levon 		return 1;
320*c85f09ccSJohn Levon 	if (sym_name_is("kmalloc_array", expr->fn))
321*c85f09ccSJohn Levon 		return 1;
322*c85f09ccSJohn Levon 	if (sym_name_is("vmalloc_array", expr->fn))
323*c85f09ccSJohn Levon 		return 1;
324*c85f09ccSJohn Levon 	if (sym_name_is("kvmalloc_array", expr->fn))
325*c85f09ccSJohn Levon 		return 1;
326*c85f09ccSJohn Levon 
327*c85f09ccSJohn Levon 	if (sym_name_is("mmu_memory_cache_alloc", expr->fn))
328*c85f09ccSJohn Levon 		return 1;
329*c85f09ccSJohn Levon 	if (sym_name_is("kmem_alloc", expr->fn))
330*c85f09ccSJohn Levon 		return 1;
331*c85f09ccSJohn Levon 	if (sym_name_is("alloc_pages", expr->fn))
332*c85f09ccSJohn Levon 		return 1;
333*c85f09ccSJohn Levon 
3341f5207b7SJohn Levon 	if (sym_name_is("netdev_priv", expr->fn))
3351f5207b7SJohn Levon 		return 1;
3361f5207b7SJohn Levon 	if (sym_name_is("dev_get_drvdata", expr->fn))
3371f5207b7SJohn Levon 		return 1;
338*c85f09ccSJohn Levon 	if (sym_name_is("i2c_get_clientdata", expr->fn))
339*c85f09ccSJohn Levon 		return 1;
3401f5207b7SJohn Levon 
3411f5207b7SJohn Levon 	return 0;
3421f5207b7SJohn Levon }
3431f5207b7SJohn Levon 
3441f5207b7SJohn Levon static int is_uncasted_pointer_assign(void)
3451f5207b7SJohn Levon {
3461f5207b7SJohn Levon 	struct expression *expr;
3471f5207b7SJohn Levon 	struct symbol *left_type, *right_type;
3481f5207b7SJohn Levon 
3491f5207b7SJohn Levon 	expr = get_faked_expression();
3501f5207b7SJohn Levon 	if (!expr)
3511f5207b7SJohn Levon 		return 0;
3521f5207b7SJohn Levon 	if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) {
3531f5207b7SJohn Levon 		if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
3541f5207b7SJohn Levon 			return 1;
3551f5207b7SJohn Levon 	}
3561f5207b7SJohn Levon 	if (expr->type != EXPR_ASSIGNMENT)
3571f5207b7SJohn Levon 		return 0;
3581f5207b7SJohn Levon 	left_type = get_type(expr->left);
3591f5207b7SJohn Levon 	right_type = get_type(expr->right);
3601f5207b7SJohn Levon 
3611f5207b7SJohn Levon 	if (!left_type || !right_type)
3621f5207b7SJohn Levon 		return 0;
3631f5207b7SJohn Levon 
364*c85f09ccSJohn Levon 	if (left_type->type == SYM_STRUCT && left_type == right_type)
365*c85f09ccSJohn Levon 		return 1;
366*c85f09ccSJohn Levon 
3671f5207b7SJohn Levon 	if (left_type->type != SYM_PTR &&
3681f5207b7SJohn Levon 	    left_type->type != SYM_ARRAY)
3691f5207b7SJohn Levon 		return 0;
3701f5207b7SJohn Levon 	if (right_type->type != SYM_PTR &&
3711f5207b7SJohn Levon 	    right_type->type != SYM_ARRAY)
3721f5207b7SJohn Levon 		return 0;
3731f5207b7SJohn Levon 	left_type = get_real_base_type(left_type);
3741f5207b7SJohn Levon 	right_type = get_real_base_type(right_type);
3751f5207b7SJohn Levon 
3761f5207b7SJohn Levon 	if (left_type == right_type)
3771f5207b7SJohn Levon 		return 1;
3781f5207b7SJohn Levon 	return 0;
3791f5207b7SJohn Levon }
3801f5207b7SJohn Levon 
3811f5207b7SJohn Levon static int set_param_type(void *_type_str, int argc, char **argv, char **azColName)
3821f5207b7SJohn Levon {
3831f5207b7SJohn Levon 	char **type_str = _type_str;
3841f5207b7SJohn Levon 	static char type_buf[128];
3851f5207b7SJohn Levon 
3861f5207b7SJohn Levon 	if (*type_str) {
3871f5207b7SJohn Levon 		if (strcmp(*type_str, argv[0]) == 0)
3881f5207b7SJohn Levon 			return 0;
3891f5207b7SJohn Levon 		strncpy(type_buf, "unknown", sizeof(type_buf));
3901f5207b7SJohn Levon 		return 0;
3911f5207b7SJohn Levon 	}
3921f5207b7SJohn Levon 	strncpy(type_buf, argv[0], sizeof(type_buf));
3931f5207b7SJohn Levon 	*type_str = type_buf;
3941f5207b7SJohn Levon 
3951f5207b7SJohn Levon 	return 0;
3961f5207b7SJohn Levon }
3971f5207b7SJohn Levon 
3981f5207b7SJohn Levon static char *db_get_parameter_type(int param)
3991f5207b7SJohn Levon {
4001f5207b7SJohn Levon 	char *ret = NULL;
4011f5207b7SJohn Levon 
4021f5207b7SJohn Levon 	if (!cur_func_sym)
4031f5207b7SJohn Levon 		return NULL;
4041f5207b7SJohn Levon 
4051f5207b7SJohn Levon 	run_sql(set_param_type, &ret,
4061f5207b7SJohn Levon 		"select value from fn_data_link where "
4071f5207b7SJohn Levon 		"file = '%s' and function = '%s' and static = %d and type = %d and parameter = %d and key = '$';",
4081f5207b7SJohn Levon 		(cur_func_sym->ctype.modifiers & MOD_STATIC) ? get_base_file() : "extern",
4091f5207b7SJohn Levon 		cur_func_sym->ident->name,
4101f5207b7SJohn Levon 		!!(cur_func_sym->ctype.modifiers & MOD_STATIC),
4111f5207b7SJohn Levon 		PASSES_TYPE, param);
4121f5207b7SJohn Levon 
4131f5207b7SJohn Levon 	return ret;
4141f5207b7SJohn Levon }
4151f5207b7SJohn Levon 
4161f5207b7SJohn Levon static int is_uncasted_fn_param_from_db(void)
4171f5207b7SJohn Levon {
4181f5207b7SJohn Levon 	struct expression *expr, *right;
4191f5207b7SJohn Levon 	struct symbol *left_type;
4201f5207b7SJohn Levon 	char left_type_name[128];
4211f5207b7SJohn Levon 	int param;
4221f5207b7SJohn Levon 	char *right_type_name;
4231f5207b7SJohn Levon 	static struct expression *prev_expr;
4241f5207b7SJohn Levon 	static int prev_ans;
4251f5207b7SJohn Levon 
4261f5207b7SJohn Levon 	expr = get_faked_expression();
4271f5207b7SJohn Levon 
4281f5207b7SJohn Levon 	if (expr == prev_expr)
4291f5207b7SJohn Levon 		return prev_ans;
4301f5207b7SJohn Levon 	prev_expr = expr;
4311f5207b7SJohn Levon 	prev_ans = 0;
4321f5207b7SJohn Levon 
4331f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT)
4341f5207b7SJohn Levon 		return 0;
4351f5207b7SJohn Levon 	left_type = get_type(expr->left);
4361f5207b7SJohn Levon 	if (!left_type || left_type->type != SYM_PTR)
4371f5207b7SJohn Levon 		return 0;
4381f5207b7SJohn Levon 	left_type = get_real_base_type(left_type);
4391f5207b7SJohn Levon 	if (!left_type || left_type->type != SYM_STRUCT)
4401f5207b7SJohn Levon 		return 0;
4411f5207b7SJohn Levon 	snprintf(left_type_name, sizeof(left_type_name), "%s", type_to_str(left_type));
4421f5207b7SJohn Levon 
4431f5207b7SJohn Levon 	right = strip_expr(expr->right);
4441f5207b7SJohn Levon 	param = get_param_num(right);
4451f5207b7SJohn Levon 	if (param < 0)
4461f5207b7SJohn Levon 		return 0;
4471f5207b7SJohn Levon 	right_type_name = db_get_parameter_type(param);
4481f5207b7SJohn Levon 	if (!right_type_name)
4491f5207b7SJohn Levon 		return 0;
4501f5207b7SJohn Levon 
4511f5207b7SJohn Levon 	if (strcmp(right_type_name, left_type_name) == 0) {
4521f5207b7SJohn Levon 		prev_ans = 1;
4531f5207b7SJohn Levon 		return 1;
4541f5207b7SJohn Levon 	}
4551f5207b7SJohn Levon 
4561f5207b7SJohn Levon 	return 0;
4571f5207b7SJohn Levon }
4581f5207b7SJohn Levon 
4591f5207b7SJohn Levon static void match_assign_value(struct expression *expr)
4601f5207b7SJohn Levon {
4611f5207b7SJohn Levon 	char *member, *right_member;
4621f5207b7SJohn Levon 	struct range_list *rl;
4631f5207b7SJohn Levon 	struct symbol *type;
4641f5207b7SJohn Levon 
4651f5207b7SJohn Levon 	if (!cur_func_sym)
4661f5207b7SJohn Levon 		return;
4671f5207b7SJohn Levon 
4681f5207b7SJohn Levon 	type = get_type(expr->left);
469*c85f09ccSJohn Levon 	if (type && type->type == SYM_STRUCT)
470*c85f09ccSJohn Levon 		return;
4711f5207b7SJohn Levon 	member = get_member_name(expr->left);
4721f5207b7SJohn Levon 	if (!member)
4731f5207b7SJohn Levon 		return;
4741f5207b7SJohn Levon 
4751f5207b7SJohn Levon 	/* if we're saying foo->mtu = bar->mtu then that doesn't add information */
4761f5207b7SJohn Levon 	right_member = get_member_name(expr->right);
4771f5207b7SJohn Levon 	if (right_member && strcmp(right_member, member) == 0)
4781f5207b7SJohn Levon 		goto free;
4791f5207b7SJohn Levon 
4801f5207b7SJohn Levon 	if (is_fake_call(expr->right)) {
4811f5207b7SJohn Levon 		if (is_ignored_macro())
4821f5207b7SJohn Levon 			goto free;
4831f5207b7SJohn Levon 		if (is_ignored_function())
4841f5207b7SJohn Levon 			goto free;
4851f5207b7SJohn Levon 		if (is_uncasted_pointer_assign())
4861f5207b7SJohn Levon 			goto free;
4871f5207b7SJohn Levon 		if (is_uncasted_fn_param_from_db())
4881f5207b7SJohn Levon 			goto free;
4891f5207b7SJohn Levon 		if (is_container_of())
4901f5207b7SJohn Levon 			goto free;
491*c85f09ccSJohn Levon 		if (is_driver_data())
492*c85f09ccSJohn Levon 			goto free;
4931f5207b7SJohn Levon 		add_fake_type_val(member, alloc_whole_rl(get_type(expr->left)), is_ignored_fake_assignment());
4941f5207b7SJohn Levon 		goto free;
4951f5207b7SJohn Levon 	}
4961f5207b7SJohn Levon 
4971f5207b7SJohn Levon 	if (expr->op == '=') {
4981f5207b7SJohn Levon 		get_absolute_rl(expr->right, &rl);
4991f5207b7SJohn Levon 		rl = cast_rl(type, rl);
5001f5207b7SJohn Levon 	} else {
5011f5207b7SJohn Levon 		/*
5021f5207b7SJohn Levon 		 * This is a bit cheating.  We order it so this will already be set
5031f5207b7SJohn Levon 		 * by smatch_extra.c and we just look up the value.
5041f5207b7SJohn Levon 		 */
5051f5207b7SJohn Levon 		get_absolute_rl(expr->left, &rl);
5061f5207b7SJohn Levon 	}
5071f5207b7SJohn Levon 	add_type_val(member, rl);
5081f5207b7SJohn Levon free:
5091f5207b7SJohn Levon 	free_string(right_member);
5101f5207b7SJohn Levon 	free_string(member);
5111f5207b7SJohn Levon }
5121f5207b7SJohn Levon 
5131f5207b7SJohn Levon /*
5141f5207b7SJohn Levon  * If we too:  int *p = &my_struct->member then abandon all hope of tracking
5151f5207b7SJohn Levon  * my_struct->member.
5161f5207b7SJohn Levon  */
5171f5207b7SJohn Levon static void match_assign_pointer(struct expression *expr)
5181f5207b7SJohn Levon {
5191f5207b7SJohn Levon 	struct expression *right;
5201f5207b7SJohn Levon 	char *member;
5211f5207b7SJohn Levon 	struct range_list *rl;
5221f5207b7SJohn Levon 	struct symbol *type;
5231f5207b7SJohn Levon 
5241f5207b7SJohn Levon 	right = strip_expr(expr->right);
5251f5207b7SJohn Levon 	if (right->type != EXPR_PREOP || right->op != '&')
5261f5207b7SJohn Levon 		return;
5271f5207b7SJohn Levon 	right = strip_expr(right->unop);
5281f5207b7SJohn Levon 
5291f5207b7SJohn Levon 	member = get_member_name(right);
5301f5207b7SJohn Levon 	if (!member)
5311f5207b7SJohn Levon 		return;
5321f5207b7SJohn Levon 	type = get_type(right);
5331f5207b7SJohn Levon 	rl = alloc_whole_rl(type);
5341f5207b7SJohn Levon 	add_type_val(member, rl);
5351f5207b7SJohn Levon 	free_string(member);
5361f5207b7SJohn Levon }
5371f5207b7SJohn Levon 
5381f5207b7SJohn Levon static void match_global_assign(struct expression *expr)
5391f5207b7SJohn Levon {
5401f5207b7SJohn Levon 	char *member;
5411f5207b7SJohn Levon 	struct range_list *rl;
5421f5207b7SJohn Levon 	struct symbol *type;
5431f5207b7SJohn Levon 
5441f5207b7SJohn Levon 	type = get_type(expr->left);
5451f5207b7SJohn Levon 	if (type && (type->type == SYM_ARRAY || type->type == SYM_STRUCT))
5461f5207b7SJohn Levon 		return;
5471f5207b7SJohn Levon 	member = get_member_name(expr->left);
5481f5207b7SJohn Levon 	if (!member)
5491f5207b7SJohn Levon 		return;
5501f5207b7SJohn Levon 	get_absolute_rl(expr->right, &rl);
5511f5207b7SJohn Levon 	rl = cast_rl(type, rl);
5521f5207b7SJohn Levon 	add_global_type_val(member, rl);
5531f5207b7SJohn Levon 	free_string(member);
5541f5207b7SJohn Levon }
5551f5207b7SJohn Levon 
5561f5207b7SJohn Levon static void unop_expr(struct expression *expr)
5571f5207b7SJohn Levon {
5581f5207b7SJohn Levon 	struct range_list *rl;
5591f5207b7SJohn Levon 	char *member;
5601f5207b7SJohn Levon 
5611f5207b7SJohn Levon 	if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
5621f5207b7SJohn Levon 		return;
5631f5207b7SJohn Levon 
5641f5207b7SJohn Levon 	expr = strip_expr(expr->unop);
5651f5207b7SJohn Levon 	member = get_member_name(expr);
5661f5207b7SJohn Levon 	if (!member)
5671f5207b7SJohn Levon 		return;
5681f5207b7SJohn Levon 	rl = alloc_whole_rl(get_type(expr));
5691f5207b7SJohn Levon 	add_type_val(member, rl);
5701f5207b7SJohn Levon 	free_string(member);
5711f5207b7SJohn Levon }
5721f5207b7SJohn Levon 
5731f5207b7SJohn Levon static void asm_expr(struct statement *stmt)
5741f5207b7SJohn Levon {
5751f5207b7SJohn Levon 	struct expression *expr;
5761f5207b7SJohn Levon 	struct range_list *rl;
5771f5207b7SJohn Levon 	char *member;
5781f5207b7SJohn Levon 
5791f5207b7SJohn Levon 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
580*c85f09ccSJohn Levon 		member = get_member_name(expr->expr);
581*c85f09ccSJohn Levon 		if (!member)
5821f5207b7SJohn Levon 			continue;
583*c85f09ccSJohn Levon 		rl = alloc_whole_rl(get_type(expr->expr));
584*c85f09ccSJohn Levon 		add_type_val(member, rl);
585*c85f09ccSJohn Levon 		free_string(member);
5861f5207b7SJohn Levon 	} END_FOR_EACH_PTR(expr);
5871f5207b7SJohn Levon }
5881f5207b7SJohn Levon 
5891f5207b7SJohn Levon static void db_param_add(struct expression *expr, int param, char *key, char *value)
5901f5207b7SJohn Levon {
5911f5207b7SJohn Levon 	struct expression *arg;
5921f5207b7SJohn Levon 	struct symbol *type;
5931f5207b7SJohn Levon 	struct range_list *rl;
5941f5207b7SJohn Levon 	char *member;
5951f5207b7SJohn Levon 
5961f5207b7SJohn Levon 	if (strcmp(key, "*$") != 0)
5971f5207b7SJohn Levon 		return;
5981f5207b7SJohn Levon 
5991f5207b7SJohn Levon 	while (expr->type == EXPR_ASSIGNMENT)
6001f5207b7SJohn Levon 		expr = strip_expr(expr->right);
6011f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
6021f5207b7SJohn Levon 		return;
6031f5207b7SJohn Levon 
6041f5207b7SJohn Levon 	arg = get_argument_from_call_expr(expr->args, param);
6051f5207b7SJohn Levon 	arg = strip_expr(arg);
6061f5207b7SJohn Levon 	if (!arg)
6071f5207b7SJohn Levon 		return;
6081f5207b7SJohn Levon 	type = get_member_type_from_key(arg, key);
609*c85f09ccSJohn Levon 	/*
610*c85f09ccSJohn Levon 	 * The situation here is that say we memset() a void pointer to zero
611*c85f09ccSJohn Levon 	 * then that's returned to the called as "*$ = 0;" but on the caller's
612*c85f09ccSJohn Levon 	 * side it's not void, it's a struct.
613*c85f09ccSJohn Levon 	 *
614*c85f09ccSJohn Levon 	 * So the question is should we be passing that slightly bogus
615*c85f09ccSJohn Levon 	 * information back to the caller?  Maybe, maybe not, but either way we
616*c85f09ccSJohn Levon 	 * are not going to record it here because a struct can't be zero.
617*c85f09ccSJohn Levon 	 *
618*c85f09ccSJohn Levon 	 */
619*c85f09ccSJohn Levon 	if (type && type->type == SYM_STRUCT)
620*c85f09ccSJohn Levon 		return;
621*c85f09ccSJohn Levon 
6221f5207b7SJohn Levon 	if (arg->type != EXPR_PREOP || arg->op != '&')
6231f5207b7SJohn Levon 		return;
6241f5207b7SJohn Levon 	arg = strip_expr(arg->unop);
6251f5207b7SJohn Levon 
6261f5207b7SJohn Levon 	member = get_member_name(arg);
6271f5207b7SJohn Levon 	if (!member)
6281f5207b7SJohn Levon 		return;
6291f5207b7SJohn Levon 	call_results_to_rl(expr, type, value, &rl);
6301f5207b7SJohn Levon 	add_type_val(member, rl);
6311f5207b7SJohn Levon 	free_string(member);
6321f5207b7SJohn Levon }
6331f5207b7SJohn Levon 
6341f5207b7SJohn Levon static void match_end_func_info(struct symbol *sym)
6351f5207b7SJohn Levon {
6361f5207b7SJohn Levon 	struct sm_state *sm;
6371f5207b7SJohn Levon 
6381f5207b7SJohn Levon 	FOR_EACH_SM(fn_type_val, sm) {
6391f5207b7SJohn Levon 		sql_insert_function_type_value(sm->name, sm->state->name);
6401f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
6411f5207b7SJohn Levon }
6421f5207b7SJohn Levon 
6431f5207b7SJohn Levon static void clear_cache(struct symbol *sym)
6441f5207b7SJohn Levon {
6451f5207b7SJohn Levon 	memset(cached_results, 0, sizeof(cached_results));
6461f5207b7SJohn Levon }
6471f5207b7SJohn Levon 
6481f5207b7SJohn Levon static void match_after_func(struct symbol *sym)
6491f5207b7SJohn Levon {
6501f5207b7SJohn Levon 	free_stree(&fn_type_val);
6511f5207b7SJohn Levon }
6521f5207b7SJohn Levon 
6531f5207b7SJohn Levon static void match_end_file(struct symbol_list *sym_list)
6541f5207b7SJohn Levon {
6551f5207b7SJohn Levon 	struct sm_state *sm;
6561f5207b7SJohn Levon 
6571f5207b7SJohn Levon 	FOR_EACH_SM(global_type_val, sm) {
6581f5207b7SJohn Levon 		sql_insert_function_type_value(sm->name, sm->state->name);
6591f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
6601f5207b7SJohn Levon }
6611f5207b7SJohn Levon 
6621f5207b7SJohn Levon void register_type_val(int id)
6631f5207b7SJohn Levon {
6641f5207b7SJohn Levon 	my_id = id;
6651f5207b7SJohn Levon 	add_hook(&clear_cache, AFTER_FUNC_HOOK);
6661f5207b7SJohn Levon 
6671f5207b7SJohn Levon 	if (!option_info)
6681f5207b7SJohn Levon 		return;
6691f5207b7SJohn Levon 
6701f5207b7SJohn Levon 	add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER);
6711f5207b7SJohn Levon 	add_hook(&match_assign_pointer, ASSIGNMENT_HOOK);
6721f5207b7SJohn Levon 	add_hook(&unop_expr, OP_HOOK);
6731f5207b7SJohn Levon 	add_hook(&asm_expr, ASM_HOOK);
6741f5207b7SJohn Levon 	select_return_states_hook(PARAM_ADD, &db_param_add);
6751f5207b7SJohn Levon 	select_return_states_hook(PARAM_SET, &db_param_add);
6761f5207b7SJohn Levon 
6771f5207b7SJohn Levon 
6781f5207b7SJohn Levon 	add_hook(&match_inline_start, INLINE_FN_START);
6791f5207b7SJohn Levon 	add_hook(&match_inline_end, INLINE_FN_END);
6801f5207b7SJohn Levon 
6811f5207b7SJohn Levon 	add_hook(&match_end_func_info, END_FUNC_HOOK);
6821f5207b7SJohn Levon 	add_hook(&match_after_func, AFTER_FUNC_HOOK);
6831f5207b7SJohn Levon 
6841f5207b7SJohn Levon 	add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK);
6851f5207b7SJohn Levon 	add_hook(&match_end_file, END_FILE_HOOK);
6861f5207b7SJohn Levon }
687