struct_assignment: add memcpy_fromio()
[smatch.git] / smatch_dereference.c
bloba14c3b9bdfad3235cb4ae2eedb46f9ead74a3e41
1 /*
2 * Copyright (C) 2021 Oracle.
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
18 #include "smatch.h"
19 #include "smatch_extra.h"
21 static int my_id;
22 static struct expr_fn_list *deref_hooks;
24 struct deref_info {
25 const char *name;
26 int param;
27 const char *key;
28 const sval_t *implies_start, *implies_end;
30 static struct deref_info fn_deref_table[] = {
31 { "nla_data", 0, "$" },
34 void add_dereference_hook(expr_func *fn)
36 add_ptr_list(&deref_hooks, fn);
39 static void call_deref_hooks(struct expression *expr)
41 if (__in_fake_assign || __in_fake_parameter_assign)
42 return;
43 if (!expr)
44 return;
46 call_expr_fns(deref_hooks, expr);
49 static void match_dereference(struct expression *expr)
51 struct expression *p, *tmp;
53 if (expr->type != EXPR_PREOP ||
54 expr->op != '*')
55 return;
56 p = strip_expr(expr->unop);
57 if (!is_pointer(p))
58 return;
59 call_deref_hooks(p);
61 tmp = get_assigned_expr(p);
62 if (!tmp)
63 return;
65 * Imagine we have:
66 * p = &foo->bar;
67 * x = p->whatever;
69 * Note that we only care about address assignments because other
70 * dereferences would have been handled already.
72 if (tmp->type != EXPR_PREOP || tmp->op != '&')
73 return;
74 p = strip_expr(tmp->unop);
75 if (p->type != EXPR_DEREF)
76 return;
77 p = strip_expr(p->deref);
78 if (p->type != EXPR_PREOP || p->op != '*')
79 return;
80 p = strip_expr(p->unop);
81 if (!is_pointer(p))
82 return;
83 call_deref_hooks(p);
86 static void match_pointer_as_array(struct expression *expr)
88 if (!is_array(expr))
89 return;
90 if (getting_address(expr))
91 return;
92 call_deref_hooks(get_array_base(expr));
95 static void set_param_dereferenced(struct expression *call, struct expression *arg, char *key, char *unused)
97 struct expression *deref;
99 deref = gen_expression_from_key(arg, key);
100 if (!deref)
101 return;
103 call_deref_hooks(deref);
106 static void param_deref(struct expression *expr, const char *name, struct symbol *sym, void *data)
108 struct expression *deref;
110 deref = gen_expression_from_name_sym(name, sym);
111 if (!deref)
112 return;
114 call_deref_hooks(deref);
117 void register_dereferences(int id)
119 struct deref_info *info;
120 int i;
122 my_id = id;
124 add_hook(&match_dereference, DEREF_HOOK);
125 add_hook(&match_pointer_as_array, OP_HOOK);
126 select_return_implies_hook_early(DEREFERENCE, &set_param_dereferenced);
128 for (i = 0; i < ARRAY_SIZE(fn_deref_table); i++) {
129 info = &fn_deref_table[i];
130 add_function_param_key_hook(info->name, &param_deref, info->param, info->key, info);