xref: /illumos-gate/usr/src/tools/smatch/src/smatch_expressions.c (revision c4ccc1f9004b70b07e4cdb57641c38ab607306c9)
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 struct expression *gen_expression_from_key(struct expression *arg, const char *key)
166 {
167 	struct expression *ret;
168 	struct token *token, *prev, *end;
169 	const char *p = key;
170 	char buf[4095];
171 	char *alloc;
172 	size_t len;
173 
174 	/* The idea is that we can parse either $0->foo or $->foo */
175 	if (key[0] != '$')
176 		return NULL;
177 	p++;
178 	while (*p >= '0' && *p <= '9')
179 		p++;
180 	len = snprintf(buf, sizeof(buf), "%s\n", p);
181 	alloc = alloc_string(buf);
182 
183 	token = tokenize_buffer(alloc, len, &end);
184 	if (!token)
185 		return NULL;
186 	if (token_type(token) != TOKEN_STREAMBEGIN)
187 		return NULL;
188 	token = token->next;
189 
190 	ret = arg;
191 	while (token_type(token) == TOKEN_SPECIAL &&
192 	       (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
193 		prev = token;
194 		token = token->next;
195 		if (token_type(token) != TOKEN_IDENT)
196 			return NULL;
197 		ret = deref_expression(ret);
198 		ret = member_expression(ret,
199 				        (prev->special == SPECIAL_DEREFERENCE) ? '*' : '.',
200 					token->ident);
201 		token = token->next;
202 	}
203 
204 	if (token_type(token) != TOKEN_STREAMEND)
205 		return NULL;
206 
207 	return ret;
208 }
209 
210 void expr_set_parent_expr(struct expression *expr, struct expression *parent)
211 {
212 	if (!expr)
213 		return;
214 	if (parent->smatch_flags & Fake)
215 		return;
216 
217 	expr->parent = (unsigned long)parent | 0x1UL;
218 }
219 
220 void expr_set_parent_stmt(struct expression *expr, struct statement *parent)
221 {
222 	if (!expr)
223 		return;
224 	expr->parent = (unsigned long)parent;
225 }
226 
227 struct expression *expr_get_parent_expr(struct expression *expr)
228 {
229 	if (!expr)
230 		return NULL;
231 	if (!(expr->parent & 0x1UL))
232 		return NULL;
233 	return (struct expression *)(expr->parent & ~0x1UL);
234 }
235 
236 struct statement *expr_get_parent_stmt(struct expression *expr)
237 {
238 	if (!expr)
239 		return NULL;
240 	if (expr->parent & 0x1UL)
241 		return NULL;
242 	return (struct statement *)expr->parent;
243 }
244 
245