slist: allow show_sm() to accept NULL pointers
[smatch.git] / smatch_param_to_mtag_data.c
blob2597456944416e1774c878417b5250eeee76cbe5
1 /*
2 * Copyright (C) 2017 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
19 * Take a look at request_threaded_irq(). It takes thread_fn and dev_id. Then
20 * it does:
22 * action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
23 * action->thread_fn = thread_fn;
24 * action->dev_id = dev_id;
26 * It doesn't ever pass action back to the higher levels, but instead registers
27 * it with the lower levels.
29 * The kzalloc() allocation creates a new mtag. We don't know at this point
30 * what "thread_fn" and "dev_id" are because they come from many different
31 * sources.
33 * So what we do is we pass the information back to the callers that thread_fn
34 * and dev_id are stored as a specific mtag data. Then when the callers *do*
35 * know what values are passed they create an mtag_alias. An mtag_alias is a
36 * many to one relationship. Then they store that in mtag_data using the
37 * mtag_alias.
41 #include "smatch.h"
42 #include "smatch_extra.h"
43 #include "smatch_slist.h"
45 static int my_id;
47 struct tag_assign_info {
48 mtag_t tag;
49 int offset;
50 int param;
52 ALLOCATOR(tag_assign_info, "tag name offset");
54 static struct smatch_state *alloc_tag_data_state(mtag_t tag, char *data_name, int offset, int param)
56 struct smatch_state *state;
57 struct tag_assign_info *data;
59 data = __alloc_tag_assign_info(0);
60 data->tag = tag;
61 data->offset = offset;
62 data->param = param;
64 state = __alloc_smatch_state(0);
65 state->name = alloc_sname(data_name);
66 state->data = data;
67 return state;
70 struct smatch_state *merge_tag_info(struct smatch_state *s1, struct smatch_state *s2)
72 /* Basically ignore undefined states */
73 if (s1 == &undefined)
74 return s2;
75 if (s2 == &undefined)
76 return s1;
78 return &merged;
81 static void match_assign(struct expression *expr)
83 struct expression *left, *right;
84 char *data_name;
85 mtag_t tag;
86 int offset;
87 int param;
89 if (expr->op != '=')
90 return;
91 left = strip_expr(expr->left);
92 right = strip_expr(expr->right);
94 if (right->type != EXPR_SYMBOL)
95 return;
96 param = get_param_num_from_sym(right->symbol);
97 if (param < 0)
98 return;
99 // FIXME: modify param_has_filter_data() to take a name/sym
100 if (!expr_to_mtag_name_offset(left, &tag, &data_name, &offset))
101 return;
102 set_state_expr(my_id, left, alloc_tag_data_state(tag, data_name, offset, param));
105 static int propogate_assignment(struct expression *expr, int param, mtag_t tag, int offset)
107 struct expression *arg;
108 int orig_param;
109 char buf[32];
111 arg = get_argument_from_call_expr(expr->args, param);
112 if (!arg)
113 return 0;
114 if (arg->type != EXPR_SYMBOL)
115 return 0;
116 orig_param = get_param_num_from_sym(arg->symbol);
117 if (orig_param < 0)
118 return 0;
119 snprintf(buf, sizeof(buf), "$->[%d]", offset);
120 set_state_expr(my_id, arg, alloc_tag_data_state(tag, buf, offset, orig_param));
121 return 1;
124 static void assign_to_alias(struct expression *expr, int param, mtag_t tag, int offset)
126 struct expression *arg;
127 struct range_list *rl;
128 mtag_t arg_tag;
129 mtag_t alias;
131 arg = get_argument_from_call_expr(expr->args, param);
132 if (!arg)
133 return;
134 get_absolute_rl(arg, &rl);
136 if (!create_mtag_alias(tag, expr, &alias))
137 return;
139 insert_mtag_data(alias, "", offset, rl);
141 if (get_mtag(arg, &arg_tag))
142 sql_insert_mtag_map(arg_tag, -offset, alias);
145 static void call_does_mtag_assign(struct expression *expr, int param, char *key, char *value)
147 char *p;
148 mtag_t tag;
149 int offset;
151 while (expr->type == EXPR_ASSIGNMENT)
152 expr = strip_expr(expr->right);
153 if (expr->type != EXPR_CALL)
154 return;
156 tag = strtoul(value, NULL, 10);
157 p = strchr(value, '+');
158 if (!p)
159 return;
160 offset = atoi(p + 1);
162 if (propogate_assignment(expr, param, tag, offset))
163 return;
165 assign_to_alias(expr, param, tag, offset);
168 static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr)
170 struct sm_state *tmp;
171 struct tag_assign_info *data;
172 char buf[256];
174 FOR_EACH_MY_SM(my_id, __get_cur_stree(), tmp) {
175 if (!tmp->state->data)
176 continue;
177 data = tmp->state->data;
178 snprintf(buf, sizeof(buf), "%lld+%d", data->tag, data->offset);
179 sql_insert_return_states(return_id, return_ranges, MTAG_ASSIGN, data->param, "$", buf);
180 } END_FOR_EACH_SM(tmp);
183 void register_param_to_mtag_data(int id)
185 my_id = id;
187 add_hook(&match_assign, ASSIGNMENT_HOOK);
188 select_return_states_hook(MTAG_ASSIGN, &call_does_mtag_assign);
189 add_merge_hook(my_id, &merge_tag_info);
190 add_split_return_callback(&print_stored_to_mtag);