1 #include "smatch.h"
2 #include "smatch_extra.h"
3
4 DECLARE_ALLOCATOR(sname);
5 __ALLOCATOR(struct expression, "temporary expr", tmp_expression);
6
7 static struct position get_cur_pos(void)
8 {
9 static struct position pos;
10 static struct position none;
11 struct expression *expr;
12 struct statement *stmt;
13
14 expr = last_ptr_list((struct ptr_list *)big_expression_stack);
15 stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
16 if (expr)
17 pos = expr->pos;
18 else if (stmt)
19 pos = stmt->pos;
20 else
21 pos = none;
22 return pos;
23 }
24
25 struct expression *alloc_tmp_expression(struct position pos, int type)
26 {
27 struct expression *expr;
28
29 expr = __alloc_tmp_expression(0);
30 expr->smatch_flags |= Fake;
31 expr->type = type;
32 expr->pos = pos;
33 return expr;
34 }
35
36 void free_tmp_expressions(void)
37 {
38 clear_tmp_expression_alloc();
39 }
40
41 struct expression *zero_expr(void)
42 {
43 struct expression *zero;
44
45 zero = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
46 zero->value = 0;
47 zero->ctype = &int_ctype;
48 return zero;
49 }
50
51 struct expression *value_expr(long long val)
52 {
53 struct expression *expr;
54
55 if (!val)
56 return zero_expr();
57
58 expr = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
59 expr->value = val;
60 expr->ctype = &llong_ctype;
61 return expr;
62 }
63
64 struct expression *member_expression(struct expression *deref, int op, struct ident *member)
65 {
66 struct expression *expr;
67
68 expr = alloc_tmp_expression(deref->pos, EXPR_DEREF);
69 expr->op = op;
70 expr->deref = deref;
71 expr->member = member;
72 expr->member_offset = -1;
73 return expr;
74 }
75
76 struct expression *preop_expression(struct expression *expr, int op)
77 {
78 struct expression *preop;
79
80 preop = alloc_tmp_expression(expr->pos, EXPR_PREOP);
81 preop->unop = expr;
82 preop->op = op;
83 return preop;
84 }
85
86 struct expression *deref_expression(struct expression *expr)
87 {
88 return preop_expression(expr, '*');
89 }
90
91 struct expression *assign_expression(struct expression *left, int op, struct expression *right)
92 {
93 struct expression *expr;
94
95 if (!right)
96 return NULL;
97
98 /* FIXME: make this a tmp expression. */
99 expr = alloc_expression(right->pos, EXPR_ASSIGNMENT);
100 expr->op = op;
101 expr->left = left;
102 expr->right = right;
103 return expr;
104 }
105
106 struct expression *binop_expression(struct expression *left, int op, struct expression *right)
107 {
108 struct expression *expr;
109
110 expr = alloc_tmp_expression(right->pos, EXPR_BINOP);
111 expr->op = op;
112 expr->left = left;
113 expr->right = right;
114 return expr;
115 }
116
117 struct expression *array_element_expression(struct expression *array, struct expression *offset)
118 {
119 struct expression *expr;
120
121 expr = binop_expression(array, '+', offset);
122 return deref_expression(expr);
123 }
124
125 struct expression *symbol_expression(struct symbol *sym)
126 {
127 struct expression *expr;
128
129 expr = alloc_tmp_expression(sym->pos, EXPR_SYMBOL);
130 expr->symbol = sym;
131 expr->symbol_name = sym->ident;
132 return expr;
133 }
134
135 struct expression *compare_expression(struct expression *left, int op, struct expression *right)
136 {
137 struct expression *expr;
138
139 expr = alloc_tmp_expression(get_cur_pos(), EXPR_COMPARE);
140 expr->op = op;
141 expr->left = left;
142 expr->right = right;
143 return expr;
144 }
145
146 struct expression *string_expression(char *str)
147 {
148 struct expression *ret;
149 struct string *string;
150 int len;
151
152 len = strlen(str) + 1;
153 string = (void *)__alloc_sname(4 + len);
154 string->length = len;
155 string->immutable = 0;
156 memcpy(string->data, str, len);
157
158 ret = alloc_tmp_expression(get_cur_pos(), EXPR_STRING);
159 ret->wide = 0;
160 ret->string = string;
161
162 return ret;
163 }
164
165 static struct expression *get_expression_from_base_and_str(struct expression *base, const char *addition)
166 {
167 struct expression *ret = NULL;
168 struct token *token, *prev, *end;
169 char *alloc;
170
171 if (addition[0] == '\0')
172 return base;
173
174 alloc = alloc_string_newline(addition);
175
176 token = tokenize_buffer(alloc, strlen(alloc), &end);
177 if (!token)
178 goto free;
179 if (token_type(token) != TOKEN_STREAMBEGIN)
180 goto free;
181 token = token->next;
182
183 ret = base;
184 while (token_type(token) == TOKEN_SPECIAL &&
185 (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
186 prev = token;
187 token = token->next;
188 if (token_type(token) != TOKEN_IDENT)
189 goto free;
190 switch (prev->special) {
191 case SPECIAL_DEREFERENCE:
192 ret = deref_expression(ret);
193 ret = member_expression(ret, '*', token->ident);
194 break;
195 case '.':
196 ret = member_expression(ret, '.', token->ident);
197 break;
198 default:
199 goto free;
200 }
201 token = token->next;
202 }
203
204 if (token_type(token) != TOKEN_STREAMEND)
205 goto free;
206
207 free:
208 free_string(alloc);
209
210 return ret;
211 }
212
213 struct expression *gen_expression_from_name_sym(const char *name, struct symbol *sym)
214 {
215 struct expression *base;
216 int skip = 0;
217 struct expression *ret;
218
219 if (!name || !sym)
220 return NULL;
221
222 base = symbol_expression(sym);
223 while (name[skip] != '\0' && name[skip] != '.' && name[skip] != '-')
224 skip++;
225
226 ret = get_expression_from_base_and_str(base, name + skip);
227 if (ret) {
228 char *new = expr_to_str(ret);
229
230 /*
231 * FIXME: this sometimes changes "foo->bar.a.b->c" into
232 * "foo->bar.a.b.c". I don't know why... :(
233 *
234 */
235 if (!new || strcmp(name, new) != 0)
236 return NULL;
237 }
238 return ret;
239 }
240
241 struct expression *gen_expression_from_key(struct expression *arg, const char *key)
242 {
243 struct expression *ret;
244 struct token *token, *prev, *end;
245 const char *p = key;
246 char buf[4095];
247 char *alloc;
248 size_t len;
249
250 /* The idea is that we can parse either $0->foo or $->foo */
251 if (key[0] != '$')
252 return NULL;
253 p++;
254 while (*p >= '0' && *p <= '9')
255 p++;
256 len = snprintf(buf, sizeof(buf), "%s\n", p);
257 alloc = alloc_string(buf);
258
259 token = tokenize_buffer(alloc, len, &end);
260 if (!token)
261 return NULL;
262 if (token_type(token) != TOKEN_STREAMBEGIN)
263 return NULL;
264 token = token->next;
265
266 ret = arg;
267 while (token_type(token) == TOKEN_SPECIAL &&
268 (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
269 prev = token;
270 token = token->next;
271 if (token_type(token) != TOKEN_IDENT)
272 return NULL;
273 ret = deref_expression(ret);
274 ret = member_expression(ret,
275 (prev->special == SPECIAL_DEREFERENCE) ? '*' : '.',
276 token->ident);
277 token = token->next;
278 }
279
280 if (token_type(token) != TOKEN_STREAMEND)
281 return NULL;
282
283 return ret;
284 }
285
286 void expr_set_parent_expr(struct expression *expr, struct expression *parent)
287 {
288 if (!expr)
289 return;
290 if (parent->smatch_flags & Fake)
291 return;
292
293 expr->parent = (unsigned long)parent | 0x1UL;
294 }
295
296 void expr_set_parent_stmt(struct expression *expr, struct statement *parent)
297 {
298 if (!expr)
299 return;
300 expr->parent = (unsigned long)parent;
301 }
302
303 struct expression *expr_get_parent_expr(struct expression *expr)
304 {
305 if (!expr)
306 return NULL;
307 if (!(expr->parent & 0x1UL))
308 return NULL;
309 return (struct expression *)(expr->parent & ~0x1UL);
310 }
311
312 struct statement *expr_get_parent_stmt(struct expression *expr)
313 {
314 if (!expr)
315 return NULL;
316 if (expr->parent & 0x1UL)
317 return NULL;
318 return (struct statement *)expr->parent;
319 }
320