1 /*
2  * Copyright (C) 2016 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 /*
19  * What we're doing here is saving all the possible values for static variables.
20  * Later on we might do globals as well.
21  *
22  */
23 
24 #include "smatch.h"
25 #include "smatch_slist.h"
26 #include "smatch_extra.h"
27 
28 static int my_id;
29 static struct stree *vals;
30 
save_rl(void * _rl,int argc,char ** argv,char ** azColName)31 static int save_rl(void *_rl, int argc, char **argv, char **azColName)
32 {
33 	unsigned long *rl = _rl;
34 
35 	*rl = strtoul(argv[0], NULL, 10);
36 	return 0;
37 }
38 
select_orig(mtag_t tag,int offset)39 static struct range_list *select_orig(mtag_t tag, int offset)
40 {
41 	struct range_list *rl = NULL;
42 
43 	mem_sql(&save_rl, &rl, "select value from mtag_data where tag = %lld and offset = %d;",
44 		tag, offset);
45 	return rl;
46 }
47 
is_kernel_param(const char * name)48 static int is_kernel_param(const char *name)
49 {
50 	struct sm_state *tmp;
51 	char buf[256];
52 
53 	/*
54 	 * I'm ignoring these because otherwise Smatch thinks that kernel
55 	 * parameters are always set to the default.
56 	 *
57 	 */
58 
59 	if (option_project != PROJ_KERNEL)
60 		return 0;
61 
62 	snprintf(buf, sizeof(buf), "__param_%s.arg", name);
63 
64 	FOR_EACH_SM(vals, tmp) {
65 		if (strcmp(tmp->name, buf) == 0)
66 			return 1;
67 	} END_FOR_EACH_SM(tmp);
68 
69 	return 0;
70 }
71 
is_ignored_macro(struct expression * expr)72 static bool is_ignored_macro(struct expression *expr)
73 {
74 	char *macro;
75 
76 	macro = get_macro_name(expr->pos);
77 	if (!macro)
78 		return false;
79 	if (strcmp(macro, "EXPORT_SYMBOL") == 0)
80 		return true;
81 	return false;
82 }
83 
is_head_next(struct expression * expr)84 static bool is_head_next(struct expression *expr)
85 {
86 	struct symbol *type;
87 
88 	/* Smatch thinks head->next == head is always true.  *sad face* */
89 
90 	if (option_project != PROJ_KERNEL)
91 		return false;
92 
93 	if (expr->type != EXPR_DEREF)
94 		return false;
95 	if (!expr->member || !expr->member->name ||
96 	    strcmp(expr->member->name, "next") != 0)
97 		return false;
98 
99 	type = get_type(expr->deref);
100 	if (!type)
101 		return false;
102 	if (type->type == SYM_PTR)
103 		type = get_real_base_type(type);
104 	if (type->type != SYM_STRUCT)
105 		return false;
106 	if (!type->ident || !type->ident->name ||
107 	    strcmp(type->ident->name, "list_head") != 0)
108 		return false;
109 	return true;
110 }
111 
112 mtag_t ignored_mtag;
is_ignored_tag(mtag_t tag)113 static bool is_ignored_tag(mtag_t tag)
114 {
115 	if (tag == ignored_mtag)
116 		return true;
117 	return false;
118 }
119 
insert_mtag_data(mtag_t tag,int offset,struct range_list * rl)120 static void insert_mtag_data(mtag_t tag, int offset, struct range_list *rl)
121 {
122 	if (is_ignored_tag(tag))
123 		return;
124 
125 	rl = clone_rl_permanent(rl);
126 
127 	mem_sql(NULL, NULL, "delete from mtag_data where tag = %lld and offset = %d and type = %d",
128 		tag, offset, DATA_VALUE);
129 	mem_sql(NULL, NULL, "insert into mtag_data values (%lld, %d, %d, '%lu');",
130 		tag, offset, DATA_VALUE, (unsigned long)rl);
131 }
132 
invalid_type(struct symbol * type)133 static bool invalid_type(struct symbol *type)
134 {
135 	if (!type)
136 		return true;
137 	if (type == &void_ctype)
138 		return true;
139 	if (type->type == SYM_STRUCT ||
140 	    type->type == SYM_ARRAY ||
141 	    type->type == SYM_UNION)
142 		return true;
143 	return false;
144 }
145 
parent_is_fresh_alloc(struct expression * expr)146 static bool parent_is_fresh_alloc(struct expression *expr)
147 {
148 	struct symbol *sym;
149 
150 	sym = expr_to_sym(expr);
151 	if (!sym || !sym->ident)
152 		return false;
153 	return is_fresh_alloc_var_sym(sym->ident->name, sym);
154 }
155 
update_mtag_data(struct expression * expr,struct smatch_state * state)156 void update_mtag_data(struct expression *expr, struct smatch_state *state)
157 {
158 	struct range_list *orig, *new;
159 	struct symbol *type;
160 	char *name;
161 	mtag_t tag;
162 	int offset;
163 
164 	if (!expr)
165 		return;
166 	if (is_local_variable(expr))
167 		return;
168 	if (is_ignored_macro(expr))
169 		return;
170 	if (is_head_next(expr))
171 		return;
172 	name = expr_to_var(expr);
173 	if (is_kernel_param(name)) {
174 		free_string(name);
175 		return;
176 	}
177 	free_string(name);
178 
179 	if (!expr_to_mtag_offset(expr, &tag, &offset))
180 		return;
181 
182 	type = get_type(expr);
183 	if (offset == 0 && invalid_type(type))
184 		return;
185 
186 	if (parent_is_fresh_alloc(expr))
187 		orig = NULL;
188 	else
189 		orig = select_orig(tag, offset);
190 	new = rl_union(orig, estate_rl(state));
191 	insert_mtag_data(tag, offset, new);
192 }
193 
match_global_assign(struct expression * expr)194 static void match_global_assign(struct expression *expr)
195 {
196 	struct range_list *rl;
197 	mtag_t tag;
198 	int offset;
199 	char *name;
200 
201 	if (is_ignored_macro(expr))
202 		return;
203 	if (is_head_next(expr->left))
204 		return;
205 	name = expr_to_var(expr->left);
206 	if (is_kernel_param(name)) {
207 		free_string(name);
208 		return;
209 	}
210 	free_string(name);
211 
212 	if (!expr_to_mtag_offset(expr->left, &tag, &offset))
213 		return;
214 
215 	get_absolute_rl(expr->right, &rl);
216 	insert_mtag_data(tag, offset, rl);
217 }
218 
save_mtag_data(void * _unused,int argc,char ** argv,char ** azColName)219 static int save_mtag_data(void *_unused, int argc, char **argv, char **azColName)
220 {
221 	struct range_list *rl;
222 
223 	if (argc != 4) {
224 		sm_msg("Error saving mtag data");
225 		return 0;
226 	}
227 	if (!option_info)
228 		return 0;
229 
230 	rl = (struct range_list *)strtoul(argv[3], NULL, 10);
231 	sm_msg("SQL: insert into mtag_data values ('%s', '%s', '%s', '%s');",
232 	       argv[0], argv[1], argv[2], show_rl(rl));
233 
234 	return 0;
235 }
236 
match_end_file(struct symbol_list * sym_list)237 static void match_end_file(struct symbol_list *sym_list)
238 {
239 	mem_sql(&save_mtag_data, NULL, "select * from mtag_data where type = %d;",
240 		DATA_VALUE);
241 }
242 
243 struct db_info {
244 	struct symbol *type;
245 	struct range_list *rl;
246 };
247 
get_vals(void * _db_info,int argc,char ** argv,char ** azColName)248 static int get_vals(void *_db_info, int argc, char **argv, char **azColName)
249 {
250 	struct db_info *db_info = _db_info;
251 	struct range_list *tmp;
252 
253 	str_to_rl(db_info->type, argv[0], &tmp);
254 	if (db_info->rl)
255 		db_info->rl = rl_union(db_info->rl, tmp);
256 	else
257 		db_info->rl = tmp;
258 
259 	return 0;
260 }
261 
262 struct db_cache_results {
263 	mtag_t tag;
264 	struct range_list *rl;
265 };
266 static struct db_cache_results cached_results[8];
267 
get_rl_from_mtag_offset(mtag_t tag,int offset,struct symbol * type,struct range_list ** rl)268 static int get_rl_from_mtag_offset(mtag_t tag, int offset, struct symbol *type, struct range_list **rl)
269 {
270 	struct db_info db_info = {};
271 	mtag_t merged = tag | offset;
272 	static int idx;
273 	int ret;
274 	int i;
275 
276 	for (i = 0; i < ARRAY_SIZE(cached_results); i++) {
277 		if (merged == cached_results[i].tag) {
278 			if (cached_results[i].rl) {
279 				*rl = cached_results[i].rl;
280 				return 1;
281 			}
282 			return 0;
283 		}
284 	}
285 
286 	db_info.type = type;
287 
288 	run_sql(get_vals, &db_info,
289 		"select value from mtag_data where tag = %lld and offset = %d and type = %d;",
290 		tag, offset, DATA_VALUE);
291 	if (!db_info.rl || is_whole_rl(db_info.rl)) {
292 		db_info.rl = NULL;
293 		ret = 0;
294 		goto update_cache;
295 	}
296 
297 	*rl = db_info.rl;
298 	ret = 1;
299 
300 update_cache:
301 	cached_results[idx].tag = merged;
302 	cached_results[idx].rl = db_info.rl;
303 	idx = (idx + 1) % ARRAY_SIZE(cached_results);
304 
305 	return ret;
306 }
307 
clear_cache(struct symbol * sym)308 static void clear_cache(struct symbol *sym)
309 {
310 	memset(cached_results, 0, sizeof(cached_results));
311 }
312 
get_mtag_rl(struct expression * expr,struct range_list ** rl)313 int get_mtag_rl(struct expression *expr, struct range_list **rl)
314 {
315 	struct symbol *type;
316 	mtag_t tag;
317 	int offset;
318 
319 	if (is_local_variable(expr))
320 		return 0;
321 	if (!expr_to_mtag_offset(expr, &tag, &offset))
322 		return 0;
323 	if (offset >= MTAG_OFFSET_MASK)
324 		return 0;
325 
326 	type = get_type(expr);
327 	if (invalid_type(type))
328 		return 0;
329 
330 	return get_rl_from_mtag_offset(tag, offset, type, rl);
331 }
332 
register_mtag_data(int id)333 void register_mtag_data(int id)
334 {
335 	my_id = id;
336 
337 	ignored_mtag = str_to_mtag("extern boot_params");
338 	add_hook(&clear_cache, FUNC_DEF_HOOK);
339 
340 //	if (!option_info)
341 //		return;
342 	add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK);
343 	add_hook(&match_end_file, END_FILE_HOOK);
344 }
345 
346