dereference: hard code nla_data() as dereferencing the parameter
[smatch.git] / smatch_mtag.c
blob90f261f565a46e112ba8884a3cdef81bd6457244
1 /*
2 * Copyright (C) 2017 Oracle. All rights reserved.
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.
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.
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
19 * One problem that I have is that it's really hard to track how pointers are
20 * passed around. For example, it would be nice to know that the probe() and
21 * remove() functions get the same pci_dev pointer. It would be good to know
22 * what pointers we're passing to the open() and close() functions. But that
23 * information gets lost in a call tree full of function pointer calls.
25 * I think the first step is to start naming specific pointers. So when a
26 * pointer is allocated, then it gets a tag. So calls to kmalloc() generate a
27 * tag. But we might not use that, because there might be a better name like
28 * framebuffer_alloc(). The framebuffer_alloc() is interesting because there is
29 * one per driver and it's passed around to all the file operations.
31 * Perhaps we could make a list of functions like framebuffer_alloc() which take
32 * a size and say that those are the interesting alloc functions.
34 * Another place where we would maybe name the pointer is when they are passed
35 * to the probe(). Because that's an important pointer, since there is one
36 * per driver (sort of).
38 * My vision is that you could take a pointer and trace it back to a global. So
39 * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
40 * tag. You could follow that one back and so on. Also when we pass a pointer
41 * to a function that would be recorded as sort of a link or path or something.
45 #include "smatch.h"
46 #include "smatch_slist.h"
47 #include "smatch_extra.h"
48 #include "cwchash/hashtable.h"
50 static DEFINE_HASHTABLE_INSERT(insert_sym, mtag_t, struct symbol);
51 static DEFINE_HASHTABLE_SEARCH(search_sym, mtag_t, struct symbol);
52 static struct hashtable *tag_sym_map;
54 static int my_id;
56 static inline unsigned int rehash(void *_tag)
58 mtag_t *tag = _tag;
59 return (unsigned int)*tag;
62 static inline int equalkeys(void *_tag1, void *_tag2)
64 mtag_t *tag1 = _tag1;
65 mtag_t *tag2 = _tag2;
67 return *tag1 == *tag2;
70 static void insert_tag_map(mtag_t tag, struct symbol *sym)
72 mtag_t *p;
74 p = malloc(sizeof(tag));
75 *p = tag;
76 insert_sym(tag_sym_map, p, sym);
79 static void store_hash(const char *str, unsigned long long hash)
81 sql_insert_cache_or_ignore(hash_string, "0x%llx, '%s'", hash, str);
84 unsigned long long str_to_llu_hash(const char *str)
86 unsigned long long hash;
88 hash = str_to_llu_hash_helper(str);
89 store_hash(str, hash);
91 return hash;
94 mtag_t str_to_mtag(const char *str)
96 unsigned long long tag;
98 tag = str_to_llu_hash_helper(str);
100 tag &= ~MTAG_OFFSET_MASK;
102 return tag;
105 static int save_allocator(void *_allocator, int argc, char **argv, char **azColName)
107 char **allocator = _allocator;
109 if (*allocator) {
110 if (strcmp(*allocator, argv[0]) == 0)
111 return 0;
112 /* should be impossible */
113 free_string(*allocator);
114 *allocator = alloc_string("unknown");
115 return 0;
117 *allocator = alloc_string(argv[0]);
118 return 0;
121 char *get_allocator_info_from_tag(mtag_t tag)
123 char *allocator = NULL;
125 run_sql(save_allocator, &allocator,
126 "select value from mtag_info where tag = %lld and type = %d;",
127 tag, ALLOCATOR);
129 return allocator;
132 static char *get_allocator_info(struct expression *expr, struct smatch_state *state)
134 sval_t sval;
136 if (expr->type != EXPR_ASSIGNMENT)
137 return NULL;
138 if (estate_get_single_value(state, &sval))
139 return get_allocator_info_from_tag(sval.value);
141 expr = strip_expr(expr->right);
142 if (expr->type != EXPR_CALL ||
143 !expr->fn ||
144 expr->fn->type != EXPR_SYMBOL)
145 return NULL;
146 return expr_to_str(expr->fn);
149 static void update_mtag_info(struct expression *expr, mtag_t tag,
150 const char *left_name, const char *tag_info,
151 struct smatch_state *state)
153 char *allocator;
155 sql_insert_mtag_about(tag, left_name, tag_info);
157 allocator = get_allocator_info(expr, state);
158 if (allocator)
159 sql_insert_mtag_info(tag, ALLOCATOR, allocator);
162 struct smatch_state *get_mtag_return(struct expression *expr, struct smatch_state *state)
164 struct expression *left, *right;
165 char *left_name, *right_name;
166 struct symbol *left_sym;
167 struct range_list *rl;
168 char buf[256];
169 mtag_t tag;
170 sval_t tag_sval;
172 if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
173 return NULL;
174 if (!is_fresh_alloc(expr->right))
175 return NULL;
176 if (!rl_intersection(estate_rl(state), valid_ptr_rl))
177 return NULL;
179 left = strip_expr(expr->left);
180 right = strip_expr(expr->right);
182 left_name = expr_to_str_sym(left, &left_sym);
183 if (!left_name || !left_sym)
184 return NULL;
185 right_name = expr_to_str(right);
187 snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
188 left_name, right_name);
189 tag = str_to_mtag(buf);
190 tag_sval.type = estate_type(state);
191 tag_sval.uvalue = tag;
193 rl = rl_filter(estate_rl(state), valid_ptr_rl);
194 rl = clone_rl(rl);
195 add_range(&rl, tag_sval, tag_sval);
197 update_mtag_info(expr, tag, left_name, buf, state);
199 free_string(left_name);
200 free_string(right_name);
202 return alloc_estate_rl(rl);
205 int get_string_mtag(struct expression *expr, mtag_t *tag)
207 mtag_t xor;
209 if (expr->type != EXPR_STRING || !expr->string)
210 return 0;
212 /* I was worried about collisions so I added a xor */
213 xor = str_to_mtag("__smatch string");
214 *tag = str_to_mtag(expr->string->data);
215 *tag = *tag ^ xor;
217 return 1;
220 struct symbol *get_symbol_from_mtag(mtag_t tag)
222 struct symbol *sym;
224 sym = search_sym(tag_sym_map, &tag);
225 return sym;
228 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
230 char buf[256];
232 if (!sym)
233 return 0;
235 if (!sym->ident ||
236 !(sym->ctype.modifiers & MOD_TOPLEVEL))
237 return 0;
239 snprintf(buf, sizeof(buf), "%s %s",
240 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
241 sym->ident->name);
242 *tag = str_to_mtag(buf);
243 insert_tag_map(*tag, sym);
244 return 1;
247 bool get_symbol_mtag(struct symbol *sym, mtag_t *tag)
249 char buf[256];
251 if (!sym || !sym->ident)
252 return false;
254 if (get_toplevel_mtag(sym, tag))
255 return true;
257 if (get_param_num_from_sym(sym) >= 0)
258 return false;
260 snprintf(buf, sizeof(buf), "%s %s %s",
261 get_filename(), get_function(), sym->ident->name);
262 *tag = str_to_mtag(buf);
263 return true;
266 static void global_variable(struct symbol *sym)
268 mtag_t tag;
270 if (!get_toplevel_mtag(sym, &tag))
271 return;
273 sql_insert_mtag_about(tag,
274 sym->ident->name,
275 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
278 static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
280 struct expression *array, *offset_expr;
281 struct symbol *type;
282 sval_t sval;
283 int start_offset;
285 if (!is_array(expr))
286 return 0;
288 array = get_array_base(expr);
289 if (!array)
290 return 0;
291 type = get_type(array);
292 if (!type || type->type != SYM_ARRAY)
293 return 0;
294 type = get_real_base_type(type);
295 if (!type_bytes(type))
296 return 0;
298 if (!expr_to_mtag_offset(array, tag, &start_offset))
299 return 0;
301 offset_expr = get_array_offset(expr);
302 if (!get_value(offset_expr, &sval))
303 return 0;
304 *offset = start_offset + sval.value * type_bytes(type);
306 return 1;
309 struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl)
311 char buf[256];
312 char *name;
313 sval_t sval;
314 mtag_t tag;
316 if (!rl_to_sval(rl, &sval))
317 return rl;
318 if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED)
319 return rl;
321 name = expr_to_str(expr);
322 snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name);
323 free_string(name);
324 tag = str_to_mtag(buf);
325 sval.value = tag;
326 return alloc_rl(sval, sval);
329 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
331 char buf[256];
332 int lines_from_start;
333 char *str;
336 * We need the alias to be unique. It's not totally required that it
337 * be the same from one DB build to then next, but it makes debugging
338 * a bit simpler.
342 if (!cur_func_sym)
343 return 0;
345 lines_from_start = expr->pos.line - cur_func_sym->pos.line;
346 str = expr_to_str(expr);
347 snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
348 free_string(str);
350 *new = str_to_mtag(buf);
351 sql_insert_mtag_alias(tag, *new);
353 return 1;
356 static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
358 struct smatch_state *state;
359 struct symbol *type;
360 sval_t sval;
362 type = get_type(expr);
363 if (!type_is_ptr(type))
364 return 0;
365 state = get_extra_state(expr);
366 if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
367 return 0;
369 *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
370 *offset = sval.uvalue & MTAG_OFFSET_MASK;
371 return 1;
375 * The point of this function is to give you the mtag and the offset so
376 * you can look up the data in the DB. It takes an expression.
378 * So say you give it "foo->bar". Then it would give you the offset of "bar"
379 * and the implied value of "foo". Or if you lookup "*foo" then the offset is
380 * zero and we look up the implied value of "foo. But if the expression is
381 * foo, then if "foo" is a global variable, then we get the mtag and the offset
382 * is zero. If "foo" is a local variable, then there is nothing to look up in
383 * the mtag_data table because that's handled by smatch_extra.c to this returns
384 * false.
387 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
389 *tag = 0;
390 *offset = 0;
392 if (bits_in_pointer != 64)
393 return 0;
395 expr = strip_expr(expr);
396 if (!expr)
397 return 0;
399 if (is_array(expr))
400 return get_array_mtag_offset(expr, tag, offset);
402 if (expr->type == EXPR_PREOP && expr->op == '*') {
403 expr = strip_expr(expr->unop);
404 return get_implied_mtag_offset(expr, tag, offset);
405 } else if (expr->type == EXPR_DEREF) {
406 int tmp, tmp_offset = 0;
408 while (expr->type == EXPR_DEREF) {
409 tmp = get_member_offset_from_deref(expr);
410 if (tmp < 0)
411 return 0;
412 tmp_offset += tmp;
413 expr = strip_expr(expr->deref);
415 *offset = tmp_offset;
416 if (expr->type == EXPR_PREOP && expr->op == '*') {
417 expr = strip_expr(expr->unop);
419 if (get_implied_mtag_offset(expr, tag, &tmp_offset)) {
420 // FIXME: look it up recursively?
421 if (tmp_offset)
422 return 0;
423 return 1;
425 return 0;
426 } else if (expr->type == EXPR_SYMBOL) {
427 return get_symbol_mtag(expr->symbol, tag);
429 return 0;
430 } else if (expr->type == EXPR_SYMBOL) {
431 return get_symbol_mtag(expr->symbol, tag);
433 return 0;
437 * This function takes an address and returns an sval. Let's take some
438 * example things you might pass to it:
439 * foo->bar:
440 * If we were only called from smatch_math, we wouldn't need to bother with
441 * this because it's already been looked up in smatch_extra.c but this is
442 * also called from other places so we have to check smatch_extra.c.
443 * &foo
444 * If "foo" is global return the mtag for "foo".
445 * &foo.bar
446 * If "foo" is global return the mtag for "foo" + the offset of ".bar".
447 * It also handles string literals.
450 int get_mtag_sval(struct expression *expr, sval_t *sval)
452 struct symbol *type;
453 mtag_t tag;
454 int offset = 0;
456 if (bits_in_pointer != 64)
457 return 0;
459 expr = strip_expr(expr);
461 type = get_type(expr);
462 if (!type_is_ptr(type))
463 return 0;
465 * There are several options:
467 * If the expr is a string literal, that's an address/mtag.
468 * SYM_ARRAY and SYM_FN are mtags. There are "&foo" type addresses.
469 * And there are saved pointers "p = &foo;"
473 if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
474 goto found;
476 if (expr->type == EXPR_SYMBOL &&
477 (type->type == SYM_ARRAY || type->type == SYM_FN) &&
478 get_toplevel_mtag(expr->symbol, &tag))
479 goto found;
481 if (expr->type == EXPR_PREOP && expr->op == '&') {
482 expr = strip_expr(expr->unop);
483 if (expr_to_mtag_offset(expr, &tag, &offset))
484 goto found;
485 return 0;
488 if (get_implied_mtag_offset(expr, &tag, &offset))
489 goto found;
491 return 0;
492 found:
493 if (offset >= MTAG_OFFSET_MASK)
494 return 0;
496 sval->type = type;
497 sval->uvalue = tag | offset;
499 return 1;
502 void register_mtag(int id)
504 my_id = id;
508 * The mtag stuff only works on 64 systems because we store the
509 * information in the pointer itself.
510 * bit 63 : set for alias mtags
511 * bit 62-12: mtag hash
512 * bit 11-0 : offset
516 add_hook(&global_variable, BASE_HOOK);
517 tag_sym_map = create_hashtable(5000, rehash, equalkeys);