1/*
2 * Copyright (C) 2015 Oracle.
3 *
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.
8 *
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.
13 *
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
16 */
17
18#include "smatch.h"
19#include "smatch_slist.h"
20
21static int my_id;
22
23static struct stree *used_stree;
24static struct stree_stack *saved_stack;
25
26STATE(used);
27
28static void get_state_hook(int owner, const char *name, struct symbol *sym)
29{
30	int arg;
31
32	if (!option_info)
33		return;
34
35	if (__in_fake_assign || __in_fake_parameter_assign || __in_function_def || __in_unmatched_hook)
36		return;
37
38	arg = get_param_num_from_sym(sym);
39	if (arg < 0)
40		return;
41	if (param_was_set_var_sym(name, sym))
42		return;
43	set_state_stree(&used_stree, my_id, name, sym, &used);
44}
45
46static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused)
47{
48	struct symbol *sym;
49	char *name;
50	int arg_nr;
51
52	if (!option_info)
53		return;
54
55	name = get_variable_from_key(arg, key, &sym);
56	if (!name || !sym)
57		goto free;
58
59	arg_nr = get_param_num_from_sym(sym);
60	if (arg_nr < 0)
61		goto free;
62	if (param_was_set_var_sym(name, sym))
63		goto free;
64	set_state_stree(&used_stree, my_id, name, sym, &used);
65free:
66	free_string(name);
67}
68
69static void process_states(void)
70{
71	struct sm_state *tmp;
72	int arg;
73	const char *name;
74
75	FOR_EACH_SM(used_stree, tmp) {
76		arg = get_param_num_from_sym(tmp->sym);
77		if (arg < 0)
78			continue;
79		name = get_param_name(tmp);
80		if (!name)
81			continue;
82		if (is_recursive_member(name))
83			continue;
84
85		if (is_ignored_kernel_data(name))
86			continue;
87
88		sql_insert_return_implies(PARAM_USED, arg, name, "");
89	} END_FOR_EACH_SM(tmp);
90
91	free_stree(&used_stree);
92}
93
94static void match_function_def(struct symbol *sym)
95{
96	free_stree(&used_stree);
97}
98
99static void match_save_states(struct expression *expr)
100{
101	push_stree(&saved_stack, used_stree);
102	used_stree = NULL;
103}
104
105static void match_restore_states(struct expression *expr)
106{
107	free_stree(&used_stree);
108	used_stree = pop_stree(&saved_stack);
109}
110
111void register_param_used(int id)
112{
113	my_id = id;
114
115	add_hook(&match_function_def, FUNC_DEF_HOOK);
116
117	add_get_state_hook(&get_state_hook);
118
119	add_hook(&match_save_states, INLINE_FN_START);
120	add_hook(&match_restore_states, INLINE_FN_END);
121
122	select_return_implies_hook(PARAM_USED, &set_param_used);
123	all_return_states_hook(&process_states);
124}
125