33 *
34 * Another place where we would maybe name the pointer is when they are passed
35 * to the probe(). Because that's an important pointer, since there is one
36 * per driver (sort of).
37 *
38 * My vision is that you could take a pointer and trace it back to a global. So
39 * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
40 * tag. You could follow that one back and so on. Also when we pass a pointer
41 * to a function that would be recorded as sort of a link or path or something.
42 *
43 */
44
45 #include "smatch.h"
46 #include "smatch_slist.h"
47 #include "smatch_extra.h"
48
49 #include <openssl/md5.h>
50
51 static int my_id;
52
53 static struct smatch_state *alloc_tag_state(mtag_t tag)
54 {
55 struct smatch_state *state;
56 char buf[64];
57
58 state = __alloc_smatch_state(0);
59 snprintf(buf, sizeof(buf), "%lld", tag);
60 state->name = alloc_sname(buf);
61 state->data = malloc(sizeof(mtag_t));
62 *(mtag_t *)state->data = tag;
63
64 return state;
65 }
66
67 static mtag_t str_to_tag(const char *str)
68 {
69 unsigned char c[MD5_DIGEST_LENGTH];
70 unsigned long long *tag = (unsigned long long *)&c;
71 MD5_CTX mdContext;
72 int len;
73
74 len = strlen(str);
75 MD5_Init(&mdContext);
76 MD5_Update(&mdContext, str, len);
77 MD5_Final(c, &mdContext);
78
79 *tag &= ~MTAG_ALIAS_BIT;
80 *tag &= ~MTAG_OFFSET_MASK;
81
82 return *tag;
83 }
84
85 static void alloc_assign(const char *fn, struct expression *expr, void *unused)
86 {
87 struct expression *left, *right;
88 char *left_name, *right_name;
89 struct symbol *left_sym;
90 char buf[256];
91 mtag_t tag;
92
93
94 // FIXME: This should only happen when the size is not a paramter of
95 // the caller
96 return;
97
98 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
99 return;
100 left = strip_expr(expr->left);
101 right = strip_expr(expr->right);
102 if (right->type != EXPR_CALL || right->fn->type != EXPR_SYMBOL)
103 return;
104
105 left_name = expr_to_str_sym(left, &left_sym);
106 right_name = expr_to_str(right);
107
108 snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
109 left_name, right_name);
110 tag = str_to_tag(buf);
111
112 sql_insert_mtag_about(tag, left_name, right_name);
113
114 if (left_name && left_sym)
115 set_state(my_id, left_name, left_sym, alloc_tag_state(tag));
116
117 free_string(left_name);
118 free_string(right_name);
119 }
120
121 int get_string_mtag(struct expression *expr, mtag_t *tag)
122 {
123 mtag_t xor;
124
125 if (expr->type != EXPR_STRING || !expr->string)
126 return 0;
127
128 /* I was worried about collisions so I added a xor */
129 xor = str_to_tag("__smatch string");
130 *tag = str_to_tag(expr->string->data);
131 *tag = *tag ^ xor;
132
133 return 1;
134 }
135
136 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
137 {
138 char buf[256];
139
140 if (!sym)
141 return 0;
142
143 if (!sym->ident ||
144 !(sym->ctype.modifiers & MOD_TOPLEVEL))
145 return 0;
146
147 snprintf(buf, sizeof(buf), "%s %s",
148 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
149 sym->ident->name);
150 *tag = str_to_tag(buf);
151 return 1;
152 }
153
154 int get_deref_mtag(struct expression *expr, mtag_t *tag)
155 {
156 mtag_t container_tag, member_tag;
157 int offset;
158
159 /*
160 * I'm not totally sure what I'm doing...
161 *
162 * This is supposed to get something like "global_var->ptr", but I don't
163 * feel like it's complete at all.
164 *
165 */
166
167 if (!get_mtag(expr->unop, &container_tag))
168 return 0;
169
170 offset = get_member_offset_from_deref(expr);
171 if (offset < 0)
172 return 0;
173
174 if (!mtag_map_select_tag(container_tag, -offset, &member_tag))
175 return 0;
176
177 *tag = member_tag;
178 return 1;
179 }
180
181 static void global_variable(struct symbol *sym)
182 {
183 mtag_t tag;
184
185 if (!get_toplevel_mtag(sym, &tag))
186 return;
187
188 sql_insert_mtag_about(tag,
189 sym->ident->name,
190 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
191 }
192
193 static void db_returns_buf_size(struct expression *expr, int param, char *unused, char *math)
194 {
195 struct expression *call;
196 struct range_list *rl;
197
198 if (expr->type != EXPR_ASSIGNMENT)
199 return;
200 call = strip_expr(expr->right);
201
202 if (!parse_call_math_rl(call, math, &rl))
203 return;
204 // rl = cast_rl(&int_ctype, rl);
205 // set_state_expr(my_size_id, expr->left, alloc_estate_rl(rl));
206 }
207
208 static void db_returns_memory_tag(struct expression *expr, int param, char *key, char *value)
209 {
210 struct expression *call, *arg;
211 mtag_t tag, alias;
212 char *name;
213 struct symbol *sym;
214
215 call = strip_expr(expr);
216 while (call->type == EXPR_ASSIGNMENT)
217 call = strip_expr(call->right);
218 if (call->type != EXPR_CALL)
219 return;
220
221 tag = strtoul(value, NULL, 10);
222
223 if (!create_mtag_alias(tag, call, &alias))
224 return;
225
226 arg = get_argument_from_call_expr(call->args, param);
227 if (!arg)
228 return;
229
230 name = get_variable_from_key(arg, key, &sym);
231 if (!name || !sym)
232 goto free;
233
234 set_state(my_id, name, sym, alloc_tag_state(alias));
235 free:
236 free_string(name);
237 }
238
239 static void match_call_info(struct expression *expr)
240 {
241 struct smatch_state *state;
242 struct expression *arg;
243 int i = -1;
244
245 FOR_EACH_PTR(expr->args, arg) {
246 i++;
247 state = get_state_expr(my_id, arg);
248 if (!state || !state->data)
249 continue;
250 sql_insert_caller_info(expr, MEMORY_TAG, i, "$", state->name);
251 } END_FOR_EACH_PTR(arg);
252 }
253
254 static void save_caller_info(const char *name, struct symbol *sym, char *key, char *value)
255 {
256 struct smatch_state *state;
257 char fullname[256];
258 mtag_t tag;
259
260 if (strncmp(key, "$", 1) != 0)
261 return;
262
263 tag = atoll(value);
264 snprintf(fullname, 256, "%s%s", name, key + 1);
265 state = alloc_tag_state(tag);
266 set_state(my_id, fullname, sym, state);
267 }
268
269 static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
270 {
271 struct expression *array, *offset_expr;
272 struct symbol *type;
273 sval_t sval;
274
275 if (!is_array(expr))
276 return 0;
277
278 array = get_array_base(expr);
279 if (!array)
280 return 0;
281 type = get_type(array);
282 if (!type || type->type != SYM_ARRAY)
283 return 0;
284 type = get_real_base_type(type);
285 if (!type_bytes(type))
286 return 0;
287
288 if (!get_mtag(array, tag))
289 return 0;
290
291 offset_expr = get_array_offset(expr);
292 if (!get_value(offset_expr, &sval))
293 return 0;
294 *offset = sval.value * type_bytes(type);
295
296 return 1;
297 }
298
299 static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
300 {
301 struct smatch_state *state;
302 struct symbol *type;
303 sval_t sval;
304
305 type = get_type(expr);
306 if (!type_is_ptr(type))
307 return 0;
308 state = get_extra_state(expr);
309 if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
310 return 0;
311
312 *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
313 *offset = sval.uvalue & MTAG_OFFSET_MASK;
314 return 1;
315 }
316
317 static int get_mtag_cnt;
318 int get_mtag(struct expression *expr, mtag_t *tag)
319 {
320 struct smatch_state *state;
321 int ret = 0;
322
323 expr = strip_expr(expr);
324 if (!expr)
325 return 0;
326
327 if (get_mtag_cnt > 0)
328 return 0;
329
330 get_mtag_cnt++;
331
332 switch (expr->type) {
333 case EXPR_STRING:
334 if (get_string_mtag(expr, tag)) {
335 ret = 1;
336 goto dec_cnt;
337 }
338 break;
339 case EXPR_SYMBOL:
340 if (get_toplevel_mtag(expr->symbol, tag)) {
341 ret = 1;
342 goto dec_cnt;
343 }
344 break;
345 case EXPR_DEREF:
346 if (get_deref_mtag(expr, tag)) {
347 ret = 1;
348 goto dec_cnt;
349 }
350 break;
351 }
352
353 state = get_state_expr(my_id, expr);
354 if (!state)
355 goto dec_cnt;
356 if (state->data) {
357 *tag = *(mtag_t *)state->data;
358 ret = 1;
359 goto dec_cnt;
360 }
361
362 dec_cnt:
363 get_mtag_cnt--;
364 return ret;
365 }
366
367 int get_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
368 {
369 int val;
370
371 if (!expr)
372 return 0;
373 if (expr->type == EXPR_PREOP && expr->op == '*')
374 return get_mtag_offset(expr->unop, tag, offset);
375 if (get_implied_mtag_offset(expr, tag, offset))
376 return 1;
377 if (!get_mtag(expr, tag))
378 return 0;
379 expr = strip_expr(expr);
380 if (expr->type == EXPR_SYMBOL) {
381 *offset = 0;
382 return 1;
383 }
384 val = get_member_offset_from_deref(expr);
385 if (val < 0)
386 return 0;
387 *offset = val;
388 return 1;
389 }
390
391 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
392 {
393 char buf[256];
394 int lines_from_start;
395 char *str;
396
397 /*
398 * We need the alias to be unique. It's not totally required that it
399 * be the same from one DB build to then next, but it makes debugging
400 * a bit simpler.
401 *
402 */
403
404 if (!cur_func_sym)
405 return 0;
406
407 lines_from_start = expr->pos.line - cur_func_sym->pos.line;
408 str = expr_to_str(expr);
409 snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
410 free_string(str);
411
412 *new = str_to_tag(buf);
413 sql_insert_mtag_alias(tag, *new);
414
415 return 1;
416 }
417
418 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
419 {
420 *offset = 0;
421
422 expr = strip_expr(expr);
423 if (!expr)
424 return 0;
425
426 if (is_array(expr))
427 return get_array_mtag_offset(expr, tag, offset);
428
429 if (expr->type == EXPR_DEREF) {
430 *offset = get_member_offset_from_deref(expr);
431 if (*offset < 0)
432 return 0;
433 return get_mtag(expr->deref, tag);
434 }
435
436 if (get_implied_mtag_offset(expr, tag, offset))
437 return 1;
438
439 return get_mtag(expr, tag);
440 }
441
442 int get_mtag_sval(struct expression *expr, sval_t *sval)
443 {
444 struct symbol *type;
445 mtag_t tag;
446 int offset = 0;
447
448 if (bits_in_pointer != 64)
449 return 0;
450
451 expr = strip_expr(expr);
452
453 type = get_type(expr);
454 if (!type_is_ptr(type))
455 return 0;
456 /*
457 * There are only three options:
458 *
459 * 1) An array address:
460 * p = array;
461 * 2) An address like so:
462 * p = &my_struct->member;
463 * 3) A pointer:
464 * p = pointer;
465 *
466 */
467
468 if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
469 goto found;
470
471 if (type->type == SYM_ARRAY && get_toplevel_mtag(expr->symbol, &tag))
472 goto found;
473
474 if (get_implied_mtag_offset(expr, &tag, &offset))
475 goto found;
476
477 if (expr->type != EXPR_PREOP || expr->op != '&')
478 return 0;
479 expr = strip_expr(expr->unop);
480
481 if (!expr_to_mtag_offset(expr, &tag, &offset))
482 return 0;
483 if (offset > MTAG_OFFSET_MASK)
484 offset = MTAG_OFFSET_MASK;
485
486 found:
487 sval->type = type;
488 sval->uvalue = tag | offset;
489
490 return 1;
491 }
492
493 static struct expression *remove_dereference(struct expression *expr)
494 {
495 expr = strip_expr(expr);
496
497 if (expr->type == EXPR_PREOP && expr->op == '*')
498 return strip_expr(expr->unop);
499 return preop_expression(expr, '&');
500 }
501
502 int get_mtag_addr_sval(struct expression *expr, sval_t *sval)
503 {
504 return get_mtag_sval(remove_dereference(expr), sval);
505 }
506
507 static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr)
508 {
509 struct sm_state *sm;
510 char buf[256];
511 const char *param_name;
512 int param;
513
514 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
515 if (!sm->state->data)
516 continue;
517
518 param = get_param_num_from_sym(sm->sym);
519 if (param < 0)
520 continue;
521 param_name = get_param_name(sm);
522 if (!param_name)
523 continue;
524 if (strcmp(param_name, "$") == 0)
525 continue;
526
527 snprintf(buf, sizeof(buf), "%lld", *(mtag_t *)sm->state->data);
528 sql_insert_return_states(return_id, return_ranges, MEMORY_TAG, param, param_name, buf);
529 } END_FOR_EACH_SM(sm);
530 }
531
532 void register_mtag(int id)
533 {
534 my_id = id;
535
536
537 /*
538 * The mtag stuff only works on 64 systems because we store the
539 * information in the pointer itself.
540 * bit 63 : set for alias mtags
541 * bit 62-12: mtag hash
542 * bit 11-0 : offset
543 *
544 */
545 if (bits_in_pointer != 64)
546 return;
547
548 add_hook(&global_variable, BASE_HOOK);
549
550 add_function_assign_hook("kmalloc", &alloc_assign, NULL);
551 add_function_assign_hook("kzalloc", &alloc_assign, NULL);
552
553 select_return_states_hook(BUF_SIZE, &db_returns_buf_size);
554
555 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
556 select_caller_info_hook(save_caller_info, MEMORY_TAG);
557 add_split_return_callback(&print_stored_to_mtag);
558 select_return_states_hook(MEMORY_TAG, db_returns_memory_tag);
559 }
|
33 *
34 * Another place where we would maybe name the pointer is when they are passed
35 * to the probe(). Because that's an important pointer, since there is one
36 * per driver (sort of).
37 *
38 * My vision is that you could take a pointer and trace it back to a global. So
39 * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
40 * tag. You could follow that one back and so on. Also when we pass a pointer
41 * to a function that would be recorded as sort of a link or path or something.
42 *
43 */
44
45 #include "smatch.h"
46 #include "smatch_slist.h"
47 #include "smatch_extra.h"
48
49 #include <openssl/md5.h>
50
51 static int my_id;
52
53 static mtag_t str_to_tag(const char *str)
54 {
55 unsigned char c[MD5_DIGEST_LENGTH];
56 unsigned long long *tag = (unsigned long long *)&c;
57 MD5_CTX mdContext;
58 int len;
59
60 len = strlen(str);
61 MD5_Init(&mdContext);
62 MD5_Update(&mdContext, str, len);
63 MD5_Final(c, &mdContext);
64
65 *tag &= ~MTAG_ALIAS_BIT;
66 *tag &= ~MTAG_OFFSET_MASK;
67
68 return *tag;
69 }
70
71 const struct {
72 const char *name;
73 int size_arg;
74 } allocator_info[] = {
75 { "kmalloc", 0 },
76 { "kzalloc", 0 },
77 { "devm_kmalloc", 1},
78 { "devm_kzalloc", 1},
79 };
80
81 static bool is_mtag_call(struct expression *expr)
82 {
83 struct expression *arg;
84 int i;
85 sval_t sval;
86
87 if (expr->type != EXPR_CALL ||
88 expr->fn->type != EXPR_SYMBOL ||
89 !expr->fn->symbol)
90 return false;
91
92 for (i = 0; i < ARRAY_SIZE(allocator_info); i++) {
93 if (strcmp(expr->fn->symbol->ident->name, allocator_info[i].name) == 0)
94 break;
95 }
96 if (i == ARRAY_SIZE(allocator_info))
97 return false;
98
99 arg = get_argument_from_call_expr(expr->args, allocator_info[i].size_arg);
100 if (!get_implied_value(arg, &sval))
101 return false;
102
103 return true;
104 }
105
106 struct smatch_state *swap_mtag_return(struct expression *expr, struct smatch_state *state)
107 {
108 struct expression *left, *right;
109 char *left_name, *right_name;
110 struct symbol *left_sym;
111 struct range_list *rl;
112 char buf[256];
113 mtag_t tag;
114 sval_t tag_sval;
115
116 if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
117 return state;
118
119 if (!estate_rl(state) || strcmp(state->name, "0,4096-ptr_max") != 0)
120 return state;
121
122 left = strip_expr(expr->left);
123 right = strip_expr(expr->right);
124
125 if (!is_mtag_call(right))
126 return state;
127
128 left_name = expr_to_str_sym(left, &left_sym);
129 if (!left_name || !left_sym)
130 return state;
131 right_name = expr_to_str(right);
132
133 snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
134 left_name, right_name);
135 tag = str_to_tag(buf);
136 tag_sval.type = estate_type(state);
137 tag_sval.uvalue = tag;
138
139 rl = rl_filter(estate_rl(state), valid_ptr_rl);
140 rl = clone_rl(rl);
141 add_range(&rl, tag_sval, tag_sval);
142
143 sql_insert_mtag_about(tag, left_name, buf);
144
145 free_string(left_name);
146 free_string(right_name);
147
148 return alloc_estate_rl(rl);
149 }
150
151 int get_string_mtag(struct expression *expr, mtag_t *tag)
152 {
153 mtag_t xor;
154
155 if (expr->type != EXPR_STRING || !expr->string)
156 return 0;
157
158 /* I was worried about collisions so I added a xor */
159 xor = str_to_tag("__smatch string");
160 *tag = str_to_tag(expr->string->data);
161 *tag = *tag ^ xor;
162
163 return 1;
164 }
165
166 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
167 {
168 char buf[256];
169
170 if (!sym)
171 return 0;
172
173 if (!sym->ident ||
174 !(sym->ctype.modifiers & MOD_TOPLEVEL))
175 return 0;
176
177 snprintf(buf, sizeof(buf), "%s %s",
178 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
179 sym->ident->name);
180 *tag = str_to_tag(buf);
181 return 1;
182 }
183
184 bool get_symbol_mtag(struct symbol *sym, mtag_t *tag)
185 {
186 char buf[256];
187
188 if (!sym || !sym->ident)
189 return false;
190
191 if (get_toplevel_mtag(sym, tag))
192 return true;
193
194 if (get_param_num_from_sym(sym) >= 0)
195 return false;
196
197 snprintf(buf, sizeof(buf), "%s %s %s",
198 get_filename(), get_function(), sym->ident->name);
199 *tag = str_to_tag(buf);
200 return true;
201 }
202
203 static void global_variable(struct symbol *sym)
204 {
205 mtag_t tag;
206
207 if (!get_toplevel_mtag(sym, &tag))
208 return;
209
210 sql_insert_mtag_about(tag,
211 sym->ident->name,
212 (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
213 }
214
215 static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
216 {
217 struct expression *array, *offset_expr;
218 struct symbol *type;
219 sval_t sval;
220 int start_offset;
221
222 if (!is_array(expr))
223 return 0;
224
225 array = get_array_base(expr);
226 if (!array)
227 return 0;
228 type = get_type(array);
229 if (!type || type->type != SYM_ARRAY)
230 return 0;
231 type = get_real_base_type(type);
232 if (!type_bytes(type))
233 return 0;
234
235 if (!expr_to_mtag_offset(array, tag, &start_offset))
236 return 0;
237
238 offset_expr = get_array_offset(expr);
239 if (!get_value(offset_expr, &sval))
240 return 0;
241 *offset = start_offset + sval.value * type_bytes(type);
242
243 return 1;
244 }
245
246 struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl)
247 {
248 char buf[256];
249 char *name;
250 sval_t sval;
251 mtag_t tag;
252
253 if (!rl_to_sval(rl, &sval))
254 return rl;
255 if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED)
256 return rl;
257
258 name = expr_to_str(expr);
259 snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name);
260 free_string(name);
261 tag = str_to_tag(buf);
262 sval.value = tag;
263 return alloc_rl(sval, sval);
264 }
265
266 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
267 {
268 char buf[256];
269 int lines_from_start;
270 char *str;
271
272 /*
273 * We need the alias to be unique. It's not totally required that it
274 * be the same from one DB build to then next, but it makes debugging
275 * a bit simpler.
276 *
277 */
278
279 if (!cur_func_sym)
280 return 0;
281
282 lines_from_start = expr->pos.line - cur_func_sym->pos.line;
283 str = expr_to_str(expr);
284 snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
285 free_string(str);
286
287 *new = str_to_tag(buf);
288 sql_insert_mtag_alias(tag, *new);
289
290 return 1;
291 }
292
293 static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
294 {
295 struct smatch_state *state;
296 struct symbol *type;
297 sval_t sval;
298
299 type = get_type(expr);
300 if (!type_is_ptr(type))
301 return 0;
302 state = get_extra_state(expr);
303 if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
304 return 0;
305
306 *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
307 *offset = sval.uvalue & MTAG_OFFSET_MASK;
308 return 1;
309 }
310
311 /*
312 * The point of this function is to give you the mtag and the offset so
313 * you can look up the data in the DB. It takes an expression.
314 *
315 * So say you give it "foo->bar". Then it would give you the offset of "bar"
316 * and the implied value of "foo". Or if you lookup "*foo" then the offset is
317 * zero and we look up the implied value of "foo. But if the expression is
318 * foo, then if "foo" is a global variable, then we get the mtag and the offset
319 * is zero. If "foo" is a local variable, then there is nothing to look up in
320 * the mtag_data table because that's handled by smatch_extra.c to this returns
321 * false.
322 *
323 */
324 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
325 {
326 *tag = 0;
327 *offset = 0;
328
329 if (bits_in_pointer != 64)
330 return 0;
331
332 expr = strip_expr(expr);
333 if (!expr)
334 return 0;
335
336 if (is_array(expr))
337 return get_array_mtag_offset(expr, tag, offset);
338
339 if (expr->type == EXPR_PREOP && expr->op == '*') {
340 expr = strip_expr(expr->unop);
341 return get_implied_mtag_offset(expr, tag, offset);
342 } else if (expr->type == EXPR_DEREF) {
343 int tmp, tmp_offset = 0;
344
345 while (expr->type == EXPR_DEREF) {
346 tmp = get_member_offset_from_deref(expr);
347 if (tmp < 0)
348 return 0;
349 tmp_offset += tmp;
350 expr = expr->deref;
351 }
352 *offset = tmp_offset;
353 if (expr->type == EXPR_PREOP && expr->op == '*') {
354 expr = strip_expr(expr->unop);
355
356 if (get_implied_mtag_offset(expr, tag, &tmp_offset)) {
357 // FIXME: look it up recursively?
358 if (tmp_offset)
359 return 0;
360 return 1;
361 }
362 return 0;
363 } else if (expr->type == EXPR_SYMBOL) {
364 return get_symbol_mtag(expr->symbol, tag);
365 }
366 return 0;
367 } else if (expr->type == EXPR_SYMBOL) {
368 return get_symbol_mtag(expr->symbol, tag);
369 }
370 return 0;
371 }
372
373 /*
374 * This function takes an address and returns an sval. Let's take some
375 * example things you might pass to it:
376 * foo->bar:
377 * If we were only called from smatch_math, we wouldn't need to bother with
378 * this because it's already been looked up in smatch_extra.c but this is
379 * also called from other places so we have to check smatch_extra.c.
380 * &foo
381 * If "foo" is global return the mtag for "foo".
382 * &foo.bar
383 * If "foo" is global return the mtag for "foo" + the offset of ".bar".
384 * It also handles string literals.
385 *
386 */
387 int get_mtag_sval(struct expression *expr, sval_t *sval)
388 {
389 struct symbol *type;
390 mtag_t tag;
391 int offset = 0;
392
393 if (bits_in_pointer != 64)
394 return 0;
395
396 expr = strip_expr(expr);
397
398 type = get_type(expr);
399 if (!type_is_ptr(type))
400 return 0;
401 /*
402 * There are several options:
403 *
404 * If the expr is a string literal, that's an address/mtag.
405 * SYM_ARRAY and SYM_FN are mtags. There are "&foo" type addresses.
406 * And there are saved pointers "p = &foo;"
407 *
408 */
409
410 if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
411 goto found;
412
413 if (expr->type == EXPR_SYMBOL &&
414 (type->type == SYM_ARRAY || type->type == SYM_FN) &&
415 get_toplevel_mtag(expr->symbol, &tag))
416 goto found;
417
418 if (expr->type == EXPR_PREOP && expr->op == '&') {
419 expr = strip_expr(expr->unop);
420 if (expr_to_mtag_offset(expr, &tag, &offset))
421 goto found;
422 return 0;
423 }
424
425 if (get_implied_mtag_offset(expr, &tag, &offset))
426 goto found;
427
428 return 0;
429 found:
430 if (offset >= MTAG_OFFSET_MASK)
431 return 0;
432
433 sval->type = type;
434 sval->uvalue = tag | offset;
435
436 return 1;
437 }
438
439 void register_mtag(int id)
440 {
441 my_id = id;
442
443
444 /*
445 * The mtag stuff only works on 64 systems because we store the
446 * information in the pointer itself.
447 * bit 63 : set for alias mtags
448 * bit 62-12: mtag hash
449 * bit 11-0 : offset
450 *
451 */
452
453 add_hook(&global_variable, BASE_HOOK);
454 }
|