xref: /illumos-gate/usr/src/tools/smatch/src/smatch_expressions.c (revision 6523a3aa7f325d64841382707603be7a86e68147)
1 #include "smatch.h"
2 #include "smatch_extra.h"
3 
4 DECLARE_ALLOCATOR(sname);
5 __ALLOCATOR(struct expression, "temporary expr", tmp_expression);
6 
get_cur_pos(void)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 
alloc_tmp_expression(struct position pos,int type)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 |= Tmp;
31 	expr->type = type;
32 	expr->pos = pos;
33 	return expr;
34 }
35 
free_tmp_expressions(void)36 void free_tmp_expressions(void)
37 {
38 	clear_tmp_expression_alloc();
39 }
40 
zero_expr(void)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 
value_expr(long long val)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 
member_expression(struct expression * deref,int op,struct ident * member)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 
preop_expression(struct expression * expr,int op)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 
deref_expression(struct expression * expr)86 struct expression *deref_expression(struct expression *expr)
87 {
88 	if (expr->type == EXPR_BINOP)
89 		expr = preop_expression(expr, '(');
90 	return preop_expression(expr, '*');
91 }
92 
assign_expression(struct expression * left,int op,struct expression * right)93 struct expression *assign_expression(struct expression *left, int op, struct expression *right)
94 {
95 	struct expression *expr;
96 
97 	if (!right)
98 		return NULL;
99 
100 	/* FIXME: make this a tmp expression. */
101 	expr = alloc_expression(right->pos, EXPR_ASSIGNMENT);
102 	expr->op = op;
103 	expr->left = left;
104 	expr->right = right;
105 	return expr;
106 }
107 
binop_expression(struct expression * left,int op,struct expression * right)108 struct expression *binop_expression(struct expression *left, int op, struct expression *right)
109 {
110 	struct expression *expr;
111 
112 	expr = alloc_tmp_expression(right->pos, EXPR_BINOP);
113 	expr->op = op;
114 	expr->left = left;
115 	expr->right = right;
116 	return expr;
117 }
118 
array_element_expression(struct expression * array,struct expression * offset)119 struct expression *array_element_expression(struct expression *array, struct expression *offset)
120 {
121 	struct expression *expr;
122 
123 	expr = binop_expression(array, '+', offset);
124 	return deref_expression(expr);
125 }
126 
symbol_expression(struct symbol * sym)127 struct expression *symbol_expression(struct symbol *sym)
128 {
129 	struct expression *expr;
130 
131 	expr = alloc_tmp_expression(sym->pos, EXPR_SYMBOL);
132 	expr->symbol = sym;
133 	expr->symbol_name = sym->ident;
134 	return expr;
135 }
136 
compare_expression(struct expression * left,int op,struct expression * right)137 struct expression *compare_expression(struct expression *left, int op, struct expression *right)
138 {
139 	struct expression *expr;
140 
141 	expr = alloc_tmp_expression(get_cur_pos(), EXPR_COMPARE);
142 	expr->op = op;
143 	expr->left = left;
144 	expr->right = right;
145 	return expr;
146 }
147 
string_expression(char * str)148 struct expression *string_expression(char *str)
149 {
150 	struct expression *ret;
151 	struct string *string;
152 	int len;
153 
154 	len = strlen(str) + 1;
155 	string = (void *)__alloc_sname(4 + len);
156 	string->length = len;
157 	string->immutable = 0;
158 	memcpy(string->data, str, len);
159 
160 	ret = alloc_tmp_expression(get_cur_pos(), EXPR_STRING);
161 	ret->wide = 0;
162 	ret->string = string;
163 
164 	return ret;
165 }
166 
call_expression(struct expression * fn,struct expression_list * args)167 struct expression *call_expression(struct expression *fn, struct expression_list *args)
168 {
169 	struct expression *expr;
170 
171 	expr = alloc_tmp_expression(fn->pos, EXPR_CALL);
172 	expr->fn = fn;
173 	expr->args = args;
174 
175 	return expr;
176 }
177 
get_expression_from_base_and_str(struct expression * base,const char * addition)178 static struct expression *get_expression_from_base_and_str(struct expression *base, const char *addition)
179 {
180 	struct expression *ret = NULL;
181 	struct token *token, *prev, *end;
182 	char *alloc;
183 
184 	if (addition[0] == '\0')
185 		return base;
186 
187 	alloc = alloc_string_newline(addition);
188 
189 	token = tokenize_buffer(alloc, strlen(alloc), &end);
190 	if (!token)
191 		goto free;
192 	if (token_type(token) != TOKEN_STREAMBEGIN)
193 		goto free;
194 	token = token->next;
195 
196 	ret = base;
197 	while (token_type(token) == TOKEN_SPECIAL &&
198 	       (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
199 		prev = token;
200 		token = token->next;
201 		if (token_type(token) != TOKEN_IDENT)
202 			goto free;
203 		switch (prev->special) {
204 		case SPECIAL_DEREFERENCE:
205 			ret = deref_expression(ret);
206 			ret = member_expression(ret, '*', token->ident);
207 			break;
208 		case '.':
209 			ret = member_expression(ret, '.', token->ident);
210 			break;
211 		default:
212 			goto free;
213 		}
214 		token = token->next;
215 	}
216 
217 	if (token_type(token) != TOKEN_STREAMEND)
218 		goto free;
219 
220 free:
221 	free_string(alloc);
222 
223 	return ret;
224 }
225 
gen_expression_from_name_sym(const char * name,struct symbol * sym)226 struct expression *gen_expression_from_name_sym(const char *name, struct symbol *sym)
227 {
228 	struct expression *base;
229 	int skip = 0;
230 	struct expression *ret;
231 
232 	if (!name || !sym)
233 		return NULL;
234 
235 	base = symbol_expression(sym);
236 	while (name[skip] != '\0' && name[skip] != '.' && name[skip] != '-')
237 		skip++;
238 
239 	ret = get_expression_from_base_and_str(base, name + skip);
240 	if (ret) {
241 		char *new = expr_to_str(ret);
242 
243 		/*
244 		 * FIXME: this sometimes changes "foo->bar.a.b->c" into
245 		 * "foo->bar.a.b.c".  I don't know why...  :(
246 		 *
247 		 */
248 		if (!new || strcmp(name, new) != 0)
249 			return NULL;
250 	}
251 	return ret;
252 }
253 
gen_expression_from_key(struct expression * arg,const char * key)254 struct expression *gen_expression_from_key(struct expression *arg, const char *key)
255 {
256 	struct expression *ret;
257 	struct token *token, *prev, *end;
258 	const char *p = key;
259 	char buf[4095];
260 	char *alloc;
261 	size_t len;
262 
263 	/* The idea is that we can parse either $0->foo or $->foo */
264 	if (key[0] != '$')
265 		return NULL;
266 	p++;
267 	while (*p >= '0' && *p <= '9')
268 		p++;
269 	len = snprintf(buf, sizeof(buf), "%s\n", p);
270 	alloc = alloc_string(buf);
271 
272 	token = tokenize_buffer(alloc, len, &end);
273 	if (!token)
274 		return NULL;
275 	if (token_type(token) != TOKEN_STREAMBEGIN)
276 		return NULL;
277 	token = token->next;
278 
279 	ret = arg;
280 	while (token_type(token) == TOKEN_SPECIAL &&
281 	       (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
282 		prev = token;
283 		token = token->next;
284 		if (token_type(token) != TOKEN_IDENT)
285 			return NULL;
286 		ret = deref_expression(ret);
287 		ret = member_expression(ret,
288 				        (prev->special == SPECIAL_DEREFERENCE) ? '*' : '.',
289 					token->ident);
290 		token = token->next;
291 	}
292 
293 	if (token_type(token) != TOKEN_STREAMEND)
294 		return NULL;
295 
296 	return ret;
297 }
298 
expr_set_parent_expr(struct expression * expr,struct expression * parent)299 void expr_set_parent_expr(struct expression *expr, struct expression *parent)
300 {
301 	if (!expr)
302 		return;
303 	if (parent && parent->smatch_flags & Tmp)
304 		return;
305 
306 	expr->parent = (unsigned long)parent | 0x1UL;
307 }
308 
expr_set_parent_stmt(struct expression * expr,struct statement * parent)309 void expr_set_parent_stmt(struct expression *expr, struct statement *parent)
310 {
311 	if (!expr)
312 		return;
313 	expr->parent = (unsigned long)parent;
314 }
315 
expr_get_parent_expr(struct expression * expr)316 struct expression *expr_get_parent_expr(struct expression *expr)
317 {
318 	if (!expr)
319 		return NULL;
320 	if (!(expr->parent & 0x1UL))
321 		return NULL;
322 	return (struct expression *)(expr->parent & ~0x1UL);
323 }
324 
expr_get_parent_stmt(struct expression * expr)325 struct statement *expr_get_parent_stmt(struct expression *expr)
326 {
327 	if (!expr)
328 		return NULL;
329 	if (expr->parent & 0x1UL)
330 		return NULL;
331 	return (struct statement *)expr->parent;
332 }
333 
334