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
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 
get_vals(void * _db_vals,int argc,char ** argv,char ** azColName)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 
match_inline_start(struct expression * expr)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 
match_inline_end(struct expression * expr)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 
get_cached(struct expression * expr,struct range_list ** rl,int * ret)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 
get_db_type_rl(struct expression * expr,struct range_list ** rl)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 
add_type_val(char * member,struct range_list * rl)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 
add_fake_type_val(char * member,struct range_list * rl,int ignore)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 
add_global_type_val(char * member,struct range_list * rl)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 
has_link_cb(void * has_link,int argc,char ** argv,char ** azColName)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 
is_ignored_fake_assignment(void)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 
is_container_of(void)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 
is_driver_data(void)230c85f09ccSJohn Levon static bool is_driver_data(void)
2311f5207b7SJohn Levon {
232c85f09ccSJohn Levon 	static struct expression *prev_expr;
2331f5207b7SJohn Levon 	struct expression *expr;
2341f5207b7SJohn Levon 	char *name;
235c85f09ccSJohn Levon 	static bool prev_ret;
236c85f09ccSJohn Levon 	bool ret = false;
2371f5207b7SJohn Levon 
2381f5207b7SJohn Levon 	expr = get_faked_expression();
2391f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT)
240c85f09ccSJohn Levon 		return false;
241c85f09ccSJohn Levon 
242c85f09ccSJohn Levon 	if (expr == prev_expr)
243c85f09ccSJohn Levon 		return prev_ret;
244c85f09ccSJohn Levon 	prev_expr = expr;
245c85f09ccSJohn Levon 
246c85f09ccSJohn Levon 	name = expr_to_str(expr->right);
247c85f09ccSJohn Levon 	if (!name) {
248c85f09ccSJohn Levon 		prev_ret = false;
249c85f09ccSJohn Levon 		return false;
250c85f09ccSJohn Levon 	}
251c85f09ccSJohn Levon 
252c85f09ccSJohn Levon 	if (strstr(name, "get_drvdata(") ||
253c85f09ccSJohn Levon 	    strstr(name, "dev.driver_data") ||
254c85f09ccSJohn Levon 	    strstr(name, "dev->driver_data"))
255c85f09ccSJohn Levon 		ret = true;
256c85f09ccSJohn Levon 
257c85f09ccSJohn Levon 	free_string(name);
258c85f09ccSJohn Levon 
259c85f09ccSJohn Levon 	prev_ret = ret;
260c85f09ccSJohn Levon 	return ret;
261c85f09ccSJohn Levon }
262c85f09ccSJohn Levon 
is_ignored_macro(void)263c85f09ccSJohn Levon static int is_ignored_macro(void)
264c85f09ccSJohn Levon {
265c85f09ccSJohn Levon 	struct expression *expr;
266c85f09ccSJohn Levon 	char *name;
267c85f09ccSJohn Levon 
268c85f09ccSJohn Levon 	expr = get_faked_expression();
269c85f09ccSJohn 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;
284c85f09ccSJohn Levon 	if (strcmp(name, "per_cpu_ptr") == 0)
285c85f09ccSJohn Levon 		return 1;
286c85f09ccSJohn Levon 	if (strcmp(name, "raw_cpu_ptr") == 0)
287c85f09ccSJohn Levon 		return 1;
288c85f09ccSJohn Levon 	if (strcmp(name, "this_cpu_ptr") == 0)
289c85f09ccSJohn Levon 		return 1;
290c85f09ccSJohn Levon 
291c85f09ccSJohn Levon 	if (strcmp(name, "TRACE_EVENT") == 0)
292c85f09ccSJohn Levon 		return 1;
293c85f09ccSJohn Levon 	if (strcmp(name, "DECLARE_EVENT_CLASS") == 0)
294c85f09ccSJohn Levon 		return 1;
295c85f09ccSJohn Levon 	if (strcmp(name, "DEFINE_EVENT") == 0)
296c85f09ccSJohn Levon 		return 1;
297c85f09ccSJohn Levon 
2981f5207b7SJohn Levon 	if (strstr(name, "for_each"))
2991f5207b7SJohn Levon 		return 1;
3001f5207b7SJohn Levon 	return 0;
3011f5207b7SJohn Levon }
3021f5207b7SJohn Levon 
is_ignored_function(void)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;
316c85f09ccSJohn Levon 	if (sym_name_is("vmalloc", expr->fn))
317c85f09ccSJohn Levon 		return 1;
318c85f09ccSJohn Levon 	if (sym_name_is("kvmalloc", expr->fn))
319c85f09ccSJohn Levon 		return 1;
320c85f09ccSJohn Levon 	if (sym_name_is("kmalloc_array", expr->fn))
321c85f09ccSJohn Levon 		return 1;
322c85f09ccSJohn Levon 	if (sym_name_is("vmalloc_array", expr->fn))
323c85f09ccSJohn Levon 		return 1;
324c85f09ccSJohn Levon 	if (sym_name_is("kvmalloc_array", expr->fn))
325c85f09ccSJohn Levon 		return 1;
326c85f09ccSJohn Levon 
327c85f09ccSJohn Levon 	if (sym_name_is("mmu_memory_cache_alloc", expr->fn))
328c85f09ccSJohn Levon 		return 1;
329c85f09ccSJohn Levon 	if (sym_name_is("kmem_alloc", expr->fn))
330c85f09ccSJohn Levon 		return 1;
331c85f09ccSJohn Levon 	if (sym_name_is("alloc_pages", expr->fn))
332c85f09ccSJohn Levon 		return 1;
333c85f09ccSJohn 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;
338c85f09ccSJohn Levon 	if (sym_name_is("i2c_get_clientdata", expr->fn))
339c85f09ccSJohn Levon 		return 1;
340*6523a3aaSJohn Levon 	if (sym_name_is("idr_find", expr->fn))
341*6523a3aaSJohn Levon 		return 1;
3421f5207b7SJohn Levon 
3431f5207b7SJohn Levon 	return 0;
3441f5207b7SJohn Levon }
3451f5207b7SJohn Levon 
is_uncasted_pointer_assign(void)3461f5207b7SJohn Levon static int is_uncasted_pointer_assign(void)
3471f5207b7SJohn Levon {
3481f5207b7SJohn Levon 	struct expression *expr;
3491f5207b7SJohn Levon 	struct symbol *left_type, *right_type;
3501f5207b7SJohn Levon 
3511f5207b7SJohn Levon 	expr = get_faked_expression();
3521f5207b7SJohn Levon 	if (!expr)
3531f5207b7SJohn Levon 		return 0;
3541f5207b7SJohn Levon 	if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) {
3551f5207b7SJohn Levon 		if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
3561f5207b7SJohn Levon 			return 1;
3571f5207b7SJohn Levon 	}
3581f5207b7SJohn Levon 	if (expr->type != EXPR_ASSIGNMENT)
3591f5207b7SJohn Levon 		return 0;
3601f5207b7SJohn Levon 	left_type = get_type(expr->left);
3611f5207b7SJohn Levon 	right_type = get_type(expr->right);
3621f5207b7SJohn Levon 
3631f5207b7SJohn Levon 	if (!left_type || !right_type)
3641f5207b7SJohn Levon 		return 0;
3651f5207b7SJohn Levon 
366c85f09ccSJohn Levon 	if (left_type->type == SYM_STRUCT && left_type == right_type)
367c85f09ccSJohn Levon 		return 1;
368c85f09ccSJohn Levon 
3691f5207b7SJohn Levon 	if (left_type->type != SYM_PTR &&
3701f5207b7SJohn Levon 	    left_type->type != SYM_ARRAY)
3711f5207b7SJohn Levon 		return 0;
3721f5207b7SJohn Levon 	if (right_type->type != SYM_PTR &&
3731f5207b7SJohn Levon 	    right_type->type != SYM_ARRAY)
3741f5207b7SJohn Levon 		return 0;
3751f5207b7SJohn Levon 	left_type = get_real_base_type(left_type);
3761f5207b7SJohn Levon 	right_type = get_real_base_type(right_type);
3771f5207b7SJohn Levon 
3781f5207b7SJohn Levon 	if (left_type == right_type)
3791f5207b7SJohn Levon 		return 1;
3801f5207b7SJohn Levon 	return 0;
3811f5207b7SJohn Levon }
3821f5207b7SJohn Levon 
set_param_type(void * _type_str,int argc,char ** argv,char ** azColName)3831f5207b7SJohn Levon static int set_param_type(void *_type_str, int argc, char **argv, char **azColName)
3841f5207b7SJohn Levon {
3851f5207b7SJohn Levon 	char **type_str = _type_str;
3861f5207b7SJohn Levon 	static char type_buf[128];
3871f5207b7SJohn Levon 
3881f5207b7SJohn Levon 	if (*type_str) {
3891f5207b7SJohn Levon 		if (strcmp(*type_str, argv[0]) == 0)
3901f5207b7SJohn Levon 			return 0;
3911f5207b7SJohn Levon 		strncpy(type_buf, "unknown", sizeof(type_buf));
3921f5207b7SJohn Levon 		return 0;
3931f5207b7SJohn Levon 	}
3941f5207b7SJohn Levon 	strncpy(type_buf, argv[0], sizeof(type_buf));
3951f5207b7SJohn Levon 	*type_str = type_buf;
3961f5207b7SJohn Levon 
3971f5207b7SJohn Levon 	return 0;
3981f5207b7SJohn Levon }
3991f5207b7SJohn Levon 
db_get_parameter_type(int param)4001f5207b7SJohn Levon static char *db_get_parameter_type(int param)
4011f5207b7SJohn Levon {
4021f5207b7SJohn Levon 	char *ret = NULL;
4031f5207b7SJohn Levon 
4041f5207b7SJohn Levon 	if (!cur_func_sym)
4051f5207b7SJohn Levon 		return NULL;
4061f5207b7SJohn Levon 
4071f5207b7SJohn Levon 	run_sql(set_param_type, &ret,
4081f5207b7SJohn Levon 		"select value from fn_data_link where "
4091f5207b7SJohn Levon 		"file = '%s' and function = '%s' and static = %d and type = %d and parameter = %d and key = '$';",
4101f5207b7SJohn Levon 		(cur_func_sym->ctype.modifiers & MOD_STATIC) ? get_base_file() : "extern",
4111f5207b7SJohn Levon 		cur_func_sym->ident->name,
4121f5207b7SJohn Levon 		!!(cur_func_sym->ctype.modifiers & MOD_STATIC),
4131f5207b7SJohn Levon 		PASSES_TYPE, param);
4141f5207b7SJohn Levon 
4151f5207b7SJohn Levon 	return ret;
4161f5207b7SJohn Levon }
4171f5207b7SJohn Levon 
is_uncasted_fn_param_from_db(void)4181f5207b7SJohn Levon static int is_uncasted_fn_param_from_db(void)
4191f5207b7SJohn Levon {
4201f5207b7SJohn Levon 	struct expression *expr, *right;
4211f5207b7SJohn Levon 	struct symbol *left_type;
4221f5207b7SJohn Levon 	char left_type_name[128];
4231f5207b7SJohn Levon 	int param;
4241f5207b7SJohn Levon 	char *right_type_name;
4251f5207b7SJohn Levon 	static struct expression *prev_expr;
4261f5207b7SJohn Levon 	static int prev_ans;
4271f5207b7SJohn Levon 
4281f5207b7SJohn Levon 	expr = get_faked_expression();
4291f5207b7SJohn Levon 
4301f5207b7SJohn Levon 	if (expr == prev_expr)
4311f5207b7SJohn Levon 		return prev_ans;
4321f5207b7SJohn Levon 	prev_expr = expr;
4331f5207b7SJohn Levon 	prev_ans = 0;
4341f5207b7SJohn Levon 
4351f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_ASSIGNMENT)
4361f5207b7SJohn Levon 		return 0;
4371f5207b7SJohn Levon 	left_type = get_type(expr->left);
4381f5207b7SJohn Levon 	if (!left_type || left_type->type != SYM_PTR)
4391f5207b7SJohn Levon 		return 0;
4401f5207b7SJohn Levon 	left_type = get_real_base_type(left_type);
4411f5207b7SJohn Levon 	if (!left_type || left_type->type != SYM_STRUCT)
4421f5207b7SJohn Levon 		return 0;
4431f5207b7SJohn Levon 	snprintf(left_type_name, sizeof(left_type_name), "%s", type_to_str(left_type));
4441f5207b7SJohn Levon 
4451f5207b7SJohn Levon 	right = strip_expr(expr->right);
4461f5207b7SJohn Levon 	param = get_param_num(right);
4471f5207b7SJohn Levon 	if (param < 0)
4481f5207b7SJohn Levon 		return 0;
4491f5207b7SJohn Levon 	right_type_name = db_get_parameter_type(param);
4501f5207b7SJohn Levon 	if (!right_type_name)
4511f5207b7SJohn Levon 		return 0;
4521f5207b7SJohn Levon 
4531f5207b7SJohn Levon 	if (strcmp(right_type_name, left_type_name) == 0) {
4541f5207b7SJohn Levon 		prev_ans = 1;
4551f5207b7SJohn Levon 		return 1;
4561f5207b7SJohn Levon 	}
4571f5207b7SJohn Levon 
4581f5207b7SJohn Levon 	return 0;
4591f5207b7SJohn Levon }
4601f5207b7SJohn Levon 
match_assign_value(struct expression * expr)4611f5207b7SJohn Levon static void match_assign_value(struct expression *expr)
4621f5207b7SJohn Levon {
4631f5207b7SJohn Levon 	char *member, *right_member;
4641f5207b7SJohn Levon 	struct range_list *rl;
4651f5207b7SJohn Levon 	struct symbol *type;
4661f5207b7SJohn Levon 
4671f5207b7SJohn Levon 	if (!cur_func_sym)
4681f5207b7SJohn Levon 		return;
4691f5207b7SJohn Levon 
4701f5207b7SJohn Levon 	type = get_type(expr->left);
471c85f09ccSJohn Levon 	if (type && type->type == SYM_STRUCT)
472c85f09ccSJohn Levon 		return;
4731f5207b7SJohn Levon 	member = get_member_name(expr->left);
4741f5207b7SJohn Levon 	if (!member)
4751f5207b7SJohn Levon 		return;
4761f5207b7SJohn Levon 
4771f5207b7SJohn Levon 	/* if we're saying foo->mtu = bar->mtu then that doesn't add information */
4781f5207b7SJohn Levon 	right_member = get_member_name(expr->right);
4791f5207b7SJohn Levon 	if (right_member && strcmp(right_member, member) == 0)
4801f5207b7SJohn Levon 		goto free;
4811f5207b7SJohn Levon 
4821f5207b7SJohn Levon 	if (is_fake_call(expr->right)) {
4831f5207b7SJohn Levon 		if (is_ignored_macro())
4841f5207b7SJohn Levon 			goto free;
4851f5207b7SJohn Levon 		if (is_ignored_function())
4861f5207b7SJohn Levon 			goto free;
4871f5207b7SJohn Levon 		if (is_uncasted_pointer_assign())
4881f5207b7SJohn Levon 			goto free;
4891f5207b7SJohn Levon 		if (is_uncasted_fn_param_from_db())
4901f5207b7SJohn Levon 			goto free;
4911f5207b7SJohn Levon 		if (is_container_of())
4921f5207b7SJohn Levon 			goto free;
493c85f09ccSJohn Levon 		if (is_driver_data())
494c85f09ccSJohn Levon 			goto free;
4951f5207b7SJohn Levon 		add_fake_type_val(member, alloc_whole_rl(get_type(expr->left)), is_ignored_fake_assignment());
4961f5207b7SJohn Levon 		goto free;
4971f5207b7SJohn Levon 	}
4981f5207b7SJohn Levon 
4991f5207b7SJohn Levon 	if (expr->op == '=') {
5001f5207b7SJohn Levon 		get_absolute_rl(expr->right, &rl);
5011f5207b7SJohn Levon 		rl = cast_rl(type, rl);
5021f5207b7SJohn Levon 	} else {
5031f5207b7SJohn Levon 		/*
5041f5207b7SJohn Levon 		 * This is a bit cheating.  We order it so this will already be set
5051f5207b7SJohn Levon 		 * by smatch_extra.c and we just look up the value.
5061f5207b7SJohn Levon 		 */
5071f5207b7SJohn Levon 		get_absolute_rl(expr->left, &rl);
5081f5207b7SJohn Levon 	}
5091f5207b7SJohn Levon 	add_type_val(member, rl);
5101f5207b7SJohn Levon free:
5111f5207b7SJohn Levon 	free_string(right_member);
5121f5207b7SJohn Levon 	free_string(member);
5131f5207b7SJohn Levon }
5141f5207b7SJohn Levon 
5151f5207b7SJohn Levon /*
5161f5207b7SJohn Levon  * If we too:  int *p = &my_struct->member then abandon all hope of tracking
5171f5207b7SJohn Levon  * my_struct->member.
5181f5207b7SJohn Levon  */
match_assign_pointer(struct expression * expr)5191f5207b7SJohn Levon static void match_assign_pointer(struct expression *expr)
5201f5207b7SJohn Levon {
5211f5207b7SJohn Levon 	struct expression *right;
5221f5207b7SJohn Levon 	char *member;
5231f5207b7SJohn Levon 	struct range_list *rl;
5241f5207b7SJohn Levon 	struct symbol *type;
5251f5207b7SJohn Levon 
5261f5207b7SJohn Levon 	right = strip_expr(expr->right);
5271f5207b7SJohn Levon 	if (right->type != EXPR_PREOP || right->op != '&')
5281f5207b7SJohn Levon 		return;
5291f5207b7SJohn Levon 	right = strip_expr(right->unop);
5301f5207b7SJohn Levon 
5311f5207b7SJohn Levon 	member = get_member_name(right);
5321f5207b7SJohn Levon 	if (!member)
5331f5207b7SJohn Levon 		return;
5341f5207b7SJohn Levon 	type = get_type(right);
5351f5207b7SJohn Levon 	rl = alloc_whole_rl(type);
5361f5207b7SJohn Levon 	add_type_val(member, rl);
5371f5207b7SJohn Levon 	free_string(member);
5381f5207b7SJohn Levon }
5391f5207b7SJohn Levon 
match_global_assign(struct expression * expr)5401f5207b7SJohn Levon static void match_global_assign(struct expression *expr)
5411f5207b7SJohn Levon {
5421f5207b7SJohn Levon 	char *member;
5431f5207b7SJohn Levon 	struct range_list *rl;
5441f5207b7SJohn Levon 	struct symbol *type;
5451f5207b7SJohn Levon 
5461f5207b7SJohn Levon 	type = get_type(expr->left);
5471f5207b7SJohn Levon 	if (type && (type->type == SYM_ARRAY || type->type == SYM_STRUCT))
5481f5207b7SJohn Levon 		return;
5491f5207b7SJohn Levon 	member = get_member_name(expr->left);
5501f5207b7SJohn Levon 	if (!member)
5511f5207b7SJohn Levon 		return;
5521f5207b7SJohn Levon 	get_absolute_rl(expr->right, &rl);
5531f5207b7SJohn Levon 	rl = cast_rl(type, rl);
5541f5207b7SJohn Levon 	add_global_type_val(member, rl);
5551f5207b7SJohn Levon 	free_string(member);
5561f5207b7SJohn Levon }
5571f5207b7SJohn Levon 
unop_expr(struct expression * expr)5581f5207b7SJohn Levon static void unop_expr(struct expression *expr)
5591f5207b7SJohn Levon {
5601f5207b7SJohn Levon 	struct range_list *rl;
5611f5207b7SJohn Levon 	char *member;
5621f5207b7SJohn Levon 
5631f5207b7SJohn Levon 	if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
5641f5207b7SJohn Levon 		return;
5651f5207b7SJohn Levon 
5661f5207b7SJohn Levon 	expr = strip_expr(expr->unop);
5671f5207b7SJohn Levon 	member = get_member_name(expr);
5681f5207b7SJohn Levon 	if (!member)
5691f5207b7SJohn Levon 		return;
5701f5207b7SJohn Levon 	rl = alloc_whole_rl(get_type(expr));
5711f5207b7SJohn Levon 	add_type_val(member, rl);
5721f5207b7SJohn Levon 	free_string(member);
5731f5207b7SJohn Levon }
5741f5207b7SJohn Levon 
asm_expr(struct statement * stmt)5751f5207b7SJohn Levon static void asm_expr(struct statement *stmt)
5761f5207b7SJohn Levon {
5771f5207b7SJohn Levon 	struct expression *expr;
5781f5207b7SJohn Levon 	struct range_list *rl;
5791f5207b7SJohn Levon 	char *member;
5801f5207b7SJohn Levon 
5811f5207b7SJohn Levon 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
582c85f09ccSJohn Levon 		member = get_member_name(expr->expr);
583c85f09ccSJohn Levon 		if (!member)
5841f5207b7SJohn Levon 			continue;
585c85f09ccSJohn Levon 		rl = alloc_whole_rl(get_type(expr->expr));
586c85f09ccSJohn Levon 		add_type_val(member, rl);
587c85f09ccSJohn Levon 		free_string(member);
5881f5207b7SJohn Levon 	} END_FOR_EACH_PTR(expr);
5891f5207b7SJohn Levon }
5901f5207b7SJohn Levon 
db_param_add(struct expression * expr,int param,char * key,char * value)5911f5207b7SJohn Levon static void db_param_add(struct expression *expr, int param, char *key, char *value)
5921f5207b7SJohn Levon {
5931f5207b7SJohn Levon 	struct expression *arg;
5941f5207b7SJohn Levon 	struct symbol *type;
5951f5207b7SJohn Levon 	struct range_list *rl;
5961f5207b7SJohn Levon 	char *member;
5971f5207b7SJohn Levon 
5981f5207b7SJohn Levon 	if (strcmp(key, "*$") != 0)
5991f5207b7SJohn Levon 		return;
6001f5207b7SJohn Levon 
6011f5207b7SJohn Levon 	while (expr->type == EXPR_ASSIGNMENT)
6021f5207b7SJohn Levon 		expr = strip_expr(expr->right);
6031f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
6041f5207b7SJohn Levon 		return;
6051f5207b7SJohn Levon 
6061f5207b7SJohn Levon 	arg = get_argument_from_call_expr(expr->args, param);
6071f5207b7SJohn Levon 	arg = strip_expr(arg);
6081f5207b7SJohn Levon 	if (!arg)
6091f5207b7SJohn Levon 		return;
6101f5207b7SJohn Levon 	type = get_member_type_from_key(arg, key);
611c85f09ccSJohn Levon 	/*
612c85f09ccSJohn Levon 	 * The situation here is that say we memset() a void pointer to zero
613c85f09ccSJohn Levon 	 * then that's returned to the called as "*$ = 0;" but on the caller's
614c85f09ccSJohn Levon 	 * side it's not void, it's a struct.
615c85f09ccSJohn Levon 	 *
616c85f09ccSJohn Levon 	 * So the question is should we be passing that slightly bogus
617c85f09ccSJohn Levon 	 * information back to the caller?  Maybe, maybe not, but either way we
618c85f09ccSJohn Levon 	 * are not going to record it here because a struct can't be zero.
619c85f09ccSJohn Levon 	 *
620c85f09ccSJohn Levon 	 */
621c85f09ccSJohn Levon 	if (type && type->type == SYM_STRUCT)
622c85f09ccSJohn Levon 		return;
623c85f09ccSJohn Levon 
6241f5207b7SJohn Levon 	if (arg->type != EXPR_PREOP || arg->op != '&')
6251f5207b7SJohn Levon 		return;
6261f5207b7SJohn Levon 	arg = strip_expr(arg->unop);
6271f5207b7SJohn Levon 
6281f5207b7SJohn Levon 	member = get_member_name(arg);
6291f5207b7SJohn Levon 	if (!member)
6301f5207b7SJohn Levon 		return;
6311f5207b7SJohn Levon 	call_results_to_rl(expr, type, value, &rl);
6321f5207b7SJohn Levon 	add_type_val(member, rl);
6331f5207b7SJohn Levon 	free_string(member);
6341f5207b7SJohn Levon }
6351f5207b7SJohn Levon 
match_end_func_info(struct symbol * sym)6361f5207b7SJohn Levon static void match_end_func_info(struct symbol *sym)
6371f5207b7SJohn Levon {
6381f5207b7SJohn Levon 	struct sm_state *sm;
6391f5207b7SJohn Levon 
6401f5207b7SJohn Levon 	FOR_EACH_SM(fn_type_val, sm) {
6411f5207b7SJohn Levon 		sql_insert_function_type_value(sm->name, sm->state->name);
6421f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
6431f5207b7SJohn Levon }
6441f5207b7SJohn Levon 
clear_cache(struct symbol * sym)6451f5207b7SJohn Levon static void clear_cache(struct symbol *sym)
6461f5207b7SJohn Levon {
6471f5207b7SJohn Levon 	memset(cached_results, 0, sizeof(cached_results));
6481f5207b7SJohn Levon }
6491f5207b7SJohn Levon 
match_after_func(struct symbol * sym)6501f5207b7SJohn Levon static void match_after_func(struct symbol *sym)
6511f5207b7SJohn Levon {
6521f5207b7SJohn Levon 	free_stree(&fn_type_val);
6531f5207b7SJohn Levon }
6541f5207b7SJohn Levon 
match_end_file(struct symbol_list * sym_list)6551f5207b7SJohn Levon static void match_end_file(struct symbol_list *sym_list)
6561f5207b7SJohn Levon {
6571f5207b7SJohn Levon 	struct sm_state *sm;
6581f5207b7SJohn Levon 
6591f5207b7SJohn Levon 	FOR_EACH_SM(global_type_val, sm) {
6601f5207b7SJohn Levon 		sql_insert_function_type_value(sm->name, sm->state->name);
6611f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
6621f5207b7SJohn Levon }
6631f5207b7SJohn Levon 
register_type_val(int id)6641f5207b7SJohn Levon void register_type_val(int id)
6651f5207b7SJohn Levon {
6661f5207b7SJohn Levon 	my_id = id;
6671f5207b7SJohn Levon 	add_hook(&clear_cache, AFTER_FUNC_HOOK);
6681f5207b7SJohn Levon 
6691f5207b7SJohn Levon 	if (!option_info)
6701f5207b7SJohn Levon 		return;
6711f5207b7SJohn Levon 
6721f5207b7SJohn Levon 	add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER);
6731f5207b7SJohn Levon 	add_hook(&match_assign_pointer, ASSIGNMENT_HOOK);
6741f5207b7SJohn Levon 	add_hook(&unop_expr, OP_HOOK);
6751f5207b7SJohn Levon 	add_hook(&asm_expr, ASM_HOOK);
6761f5207b7SJohn Levon 	select_return_states_hook(PARAM_ADD, &db_param_add);
6771f5207b7SJohn Levon 	select_return_states_hook(PARAM_SET, &db_param_add);
6781f5207b7SJohn Levon 
6791f5207b7SJohn Levon 
6801f5207b7SJohn Levon 	add_hook(&match_inline_start, INLINE_FN_START);
6811f5207b7SJohn Levon 	add_hook(&match_inline_end, INLINE_FN_END);
6821f5207b7SJohn Levon 
6831f5207b7SJohn Levon 	add_hook(&match_end_func_info, END_FUNC_HOOK);
6841f5207b7SJohn Levon 	add_hook(&match_after_func, AFTER_FUNC_HOOK);
6851f5207b7SJohn Levon 
6861f5207b7SJohn Levon 	add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK);
6871f5207b7SJohn Levon 	add_hook(&match_end_file, END_FILE_HOOK);
6881f5207b7SJohn Levon }