comparison: select the caller_info
[smatch.git] / smatch_param_key.c
blobcf24f54e90568b21bb91b58e0e5d456ed9aea128
1 /*
2 * Copyright (C) 2020 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
18 #include "ctype.h"
19 #include "smatch.h"
20 #include "smatch_extra.h"
21 #include "smatch_slist.h"
23 static int my_id;
25 static void undef(struct sm_state *sm, struct expression *mod_expr)
27 set_state(my_id, sm->name, sm->sym, &undefined);
30 char *swap_names(const char *orig, const char *remove, const char *add)
32 char buf[64];
33 int offset, len, ret;
34 bool is_addr = false;
36 if (add[0] == '&') {
37 is_addr = true;
38 add++;
41 offset = 0;
42 while(orig[offset] == '*' || orig[offset] == '&' || orig[offset] == '(')
43 offset++;
45 len = strlen(remove);
46 if (len + offset > strlen(orig))
47 return NULL;
48 if (orig[offset + len] != '-')
49 return NULL;
50 if (strncmp(orig + offset, remove, len) != 0)
51 return NULL;
53 ret = snprintf(buf, sizeof(buf), "%.*s%s%s%s", offset, orig,
54 add, is_addr ? "." : "->", orig + offset + 2 + len);
55 if (ret >= sizeof(buf))
56 return NULL;
57 return alloc_string(buf);
60 static char *swap_with_param(const char *name, struct symbol *sym, struct symbol **sym_p)
62 struct smatch_state *state;
63 struct var_sym *var_sym;
64 char *ret;
67 * Say you know that "foo = bar;" and you have a state "foo->baz" then
68 * we can just substitute "bar" for "foo" giving "bar->baz".
71 if (!sym || !sym->ident)
72 return NULL;
74 state = get_state(my_id, sym->ident->name, sym);
75 if (!state || !state->data)
76 return NULL;
77 var_sym = state->data;
79 ret = swap_names(name, sym->ident->name, var_sym->var);
80 if (!ret)
81 return NULL;
83 *sym_p = var_sym->sym;
84 return ret;
87 struct expression *map_container_of_to_simpler_expr_key(struct expression *expr, const char *orig_key, char **new_key)
89 int offset;
90 char *p = (char *)orig_key;
91 char *start, *end;
92 char buf[64];
93 int ret;
95 expr = strip_expr(expr);
96 if (expr->type != EXPR_DEREF)
97 return NULL;
99 while (*p != '\0') {
100 if (*p == '(' && isdigit(*(p + 1))) {
101 start = p;
102 offset = strtoul(p + 1, &p, 10);
103 if (!p || p[0] != '<' || p[1] != '~' || p[2] != '$' ||
104 p[3] != ')' || p[4] != '-' || p[5] != '>')
105 return NULL;
106 end = p + 6;
107 break;
109 p++;
111 if (*p == '\0')
112 return NULL;
114 if (offset != get_member_offset_from_deref(expr))
115 return NULL;
117 ret = snprintf(buf, sizeof(buf), "%.*s$.%s", (int)(start - orig_key), orig_key, end);
118 if (ret >= sizeof(buf))
119 return NULL;
120 *new_key = alloc_sname(buf);
121 return expr->deref;
124 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
126 struct symbol *type;
127 char buf[256];
128 char *tmp;
129 bool address = false;
130 int star_cnt = 0;
131 bool add_dot = false;
132 int ret;
134 // FIXME: this function has been marked for being made static
135 // Use get_name_sym_from_param_key().
137 if (!arg)
138 return NULL;
140 arg = strip_expr(arg);
142 if (strcmp(key, "$") == 0)
143 return expr_to_var_sym(arg, sym);
145 if (strcmp(key, "*$") == 0) {
146 if (arg->type == EXPR_PREOP && arg->op == '&') {
147 arg = strip_expr(arg->unop);
148 return expr_to_var_sym(arg, sym);
149 } else {
150 tmp = expr_to_var_sym(arg, sym);
151 if (!tmp)
152 return NULL;
153 ret = snprintf(buf, sizeof(buf), "*%s", tmp);
154 free_string(tmp);
155 if (ret >= sizeof(buf))
156 return NULL;
157 return alloc_string(buf);
161 if (strncmp(key, "(*$)", 4) == 0) {
162 if (arg->type == EXPR_PREOP && arg->op == '&') {
163 arg = strip_expr(arg->unop);
164 snprintf(buf, sizeof(buf), "$%s", key + 4);
165 return get_variable_from_key(arg, buf, sym);
166 } else {
167 tmp = expr_to_var_sym(arg, sym);
168 if (!tmp)
169 return NULL;
170 ret = snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
171 free_string(tmp);
172 if (ret >= sizeof(buf))
173 return NULL;
174 return alloc_string(buf);
178 if (strstr(key, "<~$")) {
179 struct expression *expr;
180 char *new_key;
182 expr = map_container_of_to_simpler_expr_key(arg, key, &new_key);
183 if (!expr)
184 return NULL;
185 arg = expr;
186 key = new_key;
189 while (key[0] == '*') {
190 star_cnt++;
191 key++;
194 if (key[0] == '&') {
195 address = true;
196 key++;
200 * FIXME: This is a hack.
201 * We should be able to parse expressions like (*$)->foo and *$->foo.
203 type = get_type(arg);
204 if (is_struct_ptr(type))
205 add_dot = true;
207 if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
208 arg = strip_expr(arg->unop);
209 star_cnt--;
212 if (arg->type == EXPR_PREOP && arg->op == '&') {
213 arg = strip_expr(arg->unop);
214 tmp = expr_to_var_sym(arg, sym);
215 if (!tmp)
216 return NULL;
217 ret = snprintf(buf, sizeof(buf), "%s%.*s%s.%s",
218 address ? "&" : "", star_cnt, "**********",
219 tmp, key + 3);
220 if (ret >= sizeof(buf))
221 return NULL;
222 return alloc_string(buf);
225 tmp = expr_to_var_sym(arg, sym);
226 if (!tmp)
227 return NULL;
228 ret = snprintf(buf, sizeof(buf), "%s%.*s%s%s",
229 address ? "&" : "", star_cnt, "**********", tmp, key + 1);
230 free_string(tmp);
231 if (ret >= sizeof(buf))
232 return NULL;
233 return alloc_string(buf);
236 static bool split_param_key(char *value, int *param, char *key, int len)
238 char *p;
239 int l, skip = 1;
241 l = snprintf(key, len, "%s", value);
242 if (l >= len)
243 return false;
245 p = key;
246 while (*p && *p != '$')
247 p++;
248 if (*p != '$')
249 return false;
250 p++;
252 *param = atoi(p);
253 if (*param < 0 || *param > 99)
254 return false;
256 p++;
257 if (*param > 9) {
258 skip = 2;
259 p++;
262 memmove(p - skip, p, l - (p - key) + 1);
264 return true;
267 bool get_implied_rl_from_call_str(struct expression *expr, const char *data, struct range_list **rl)
269 struct smatch_state *state;
270 struct expression *arg;
271 struct symbol *sym;
272 char buf[256];
273 char *name;
274 int param;
276 while (expr->type == EXPR_ASSIGNMENT)
277 expr = expr->right;
278 if (expr->type != EXPR_CALL)
279 return false;
281 if (!split_param_key(data, &param, buf, sizeof(buf)))
282 return false;
284 if (strcmp(buf, "$") == 0) {
285 arg = get_argument_from_call_expr(expr->args, param);
286 if (!arg)
287 return false;
288 return get_implied_rl(arg, rl);
291 name = get_name_sym_from_param_key(expr, param, buf, &sym);
292 if (!name)
293 return false;
295 state = get_state(SMATCH_EXTRA, name, sym);
296 if (!estate_rl(state))
297 return false;
298 *rl = estate_rl(state);
299 return true;
302 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl)
304 *vsl = NULL;
306 if (strcmp("$", key) == 0)
307 return expr_to_chunk_sym_vsl(arg, sym, vsl);
308 return get_variable_from_key(arg, key, sym);
311 static char *state_name_to_param_name(const char *state_name, const char *param_name)
313 bool address = false;
314 int star_cnt = 0;
315 int name_len;
316 char buf[256];
317 int ret;
320 * Normally what happens is that we map "*foo->bar" to "*param->bar"
321 * but with container_of() there is no notation for that in C and it's
322 * just a Smatch invention. So in that case, the state name is the
323 * param name.
325 if (strstr(state_name, "<~$"))
326 return (char *)state_name;
328 name_len = strlen(param_name);
330 while (state_name[0] == '*') {
331 star_cnt++;
332 state_name++;
335 if (state_name[0] == '&') {
336 address = true;
337 state_name++;
340 /* ten out of ten stars! */
341 if (star_cnt > 10)
342 return NULL;
344 if (strncmp(state_name, "(*", 2) == 0 &&
345 strncmp(state_name + 2, param_name, name_len) == 0 &&
346 state_name[name_len + 2] == ')') {
347 ret = snprintf(buf, sizeof(buf), "%s%.*s(*$)%s",
348 address ? "&" : "",
349 star_cnt, "**********",
350 state_name + name_len + 3);
351 if (ret >= sizeof(buf))
352 return NULL;
353 return alloc_sname(buf);
356 if (strcmp(state_name, param_name) == 0) {
357 snprintf(buf, sizeof(buf), "%s%.*s$",
358 address ? "&" : "",
359 star_cnt, "**********");
360 return alloc_sname(buf);
363 /* check for '-' from "->" */
364 if (strncmp(state_name, param_name, name_len) == 0 &&
365 state_name[name_len] == '-') {
366 ret = snprintf(buf, sizeof(buf), "%s%.*s$%s",
367 address ? "&" : "",
368 star_cnt, "**********",
369 state_name + name_len);
370 if (ret >= sizeof(buf))
371 return NULL;
372 return alloc_sname(buf);
374 return NULL;
377 char *get_param_name_var_sym(const char *name, struct symbol *sym)
379 if (!sym || !sym->ident)
380 return NULL;
382 return state_name_to_param_name(name, sym->ident->name);
385 const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym)
387 struct symbol *type;
388 const char *sym_name;
389 int name_len;
390 static char buf[256];
393 * mtag_name is different from param_name because mtags can be a struct
394 * instead of a struct pointer. But we want to treat it like a pointer
395 * because really an mtag is a pointer. Or in other words, if you pass
396 * a struct foo then you want to talk about foo.bar but with an mtag
397 * you want to refer to it as foo->bar.
401 if (!sym || !sym->ident)
402 return NULL;
404 type = get_real_base_type(sym);
405 if (type && type->type == SYM_BASETYPE)
406 return "*$";
408 sym_name = sym->ident->name;
409 name_len = strlen(sym_name);
411 if (state_name[name_len] == '.' && /* check for '-' from "->" */
412 strncmp(state_name, sym_name, name_len) == 0) {
413 snprintf(buf, sizeof(buf), "$->%s", state_name + name_len + 1);
414 return buf;
417 return state_name_to_param_name(state_name, sym_name);
420 const char *get_mtag_name_expr(struct expression *expr)
422 char *name;
423 struct symbol *sym;
424 const char *ret = NULL;
426 name = expr_to_var_sym(expr, &sym);
427 if (!name || !sym)
428 goto free;
430 ret = get_mtag_name_var_sym(name, sym);
431 free:
432 free_string(name);
433 return ret;
436 char *get_param_name(struct sm_state *sm)
438 return get_param_name_var_sym(sm->name, sm->sym);
441 char *get_param_var_sym_var_sym(const char *name, struct symbol *sym, struct expression *ret_expr, struct symbol **sym_p)
443 struct smatch_state *state;
444 struct var_sym *var_sym;
445 int param;
447 *sym_p = NULL;
449 // FIXME was modified...
451 param = get_param_num_from_sym(sym);
452 if (param >= 0) {
453 *sym_p = sym;
454 return alloc_string(name);
457 state = get_state(my_id, name, sym);
458 if (state && state->data) {
459 var_sym = state->data;
460 if (!var_sym)
461 return NULL;
463 *sym_p = var_sym->sym;
464 return alloc_string(var_sym->var);
467 /* One would think that handling container_of() should be done here
468 * but it it's quite tricky because we only have a name and a sym
469 * and none of the assignments have been handled yet, either here or
470 * in smatch_assignments.c. On the other hand handling container_of()
471 * in the assignment hook has the advantage that it saves resources and
472 * it should work fine because of the fake assignments which we do.
475 return swap_with_param(name, sym, sym_p);
478 char *get_param_name_sym(struct expression *expr, struct symbol **sym_p)
480 struct symbol *sym;
481 const char *ret = NULL;
482 char *name;
484 name = expr_to_var_sym(expr, &sym);
485 if (!name || !sym)
486 goto free;
488 ret = get_param_var_sym_var_sym(name, sym, NULL, sym_p);
489 free:
490 free_string(name);
491 return alloc_string(ret);
494 int get_param_key_from_var_sym(const char *name, struct symbol *sym,
495 struct expression *ret_expr,
496 const char **key)
498 const char *param_name;
499 char *other_name;
500 struct symbol *other_sym;
501 int param;
503 if (key)
504 *key = name;
506 /* straight forward param match */
507 param = get_param_num_from_sym(sym);
508 if (param >= 0) {
509 param_name = get_param_name_var_sym(name, sym);
510 if (param_name) {
511 if (key)
512 *key = param_name;
513 return param;
517 /* it's the return value */
518 if (ret_expr) {
519 struct symbol *ret_sym;
520 char *ret_str;
522 ret_str = expr_to_str_sym(ret_expr, &ret_sym);
523 if (ret_str && ret_sym == sym) {
524 param_name = state_name_to_param_name(name, ret_str);
525 if (param_name) {
526 free_string(ret_str);
527 if (key)
528 *key = param_name;
529 return -1;
532 free_string(ret_str);
535 other_name = get_param_var_sym_var_sym(name, sym, ret_expr, &other_sym);
536 if (!other_name || !other_sym)
537 return -2;
538 param = get_param_num_from_sym(other_sym);
539 if (param < 0) {
540 sm_msg("internal: '%s' parameter not found", other_name);
541 return -2;
544 param_name = get_param_name_var_sym(other_name, other_sym);
545 if (param_name) {
546 if (key)
547 *key = param_name;
548 return param;
550 return -2;
553 int get_param_key_from_sm(struct sm_state *sm, struct expression *ret_expr,
554 const char **key)
556 return get_param_key_from_var_sym(sm->name, sm->sym, ret_expr, key);
559 int map_to_param(const char *name, struct symbol *sym)
561 return get_param_key_from_var_sym(name, sym, NULL, NULL);
564 int get_param_num_from_sym(struct symbol *sym)
566 struct symbol *tmp;
567 int i;
569 if (!sym)
570 return UNKNOWN_SCOPE;
572 if (sym->ctype.modifiers & MOD_TOPLEVEL) {
573 if (sym->ctype.modifiers & MOD_STATIC)
574 return FILE_SCOPE;
575 return GLOBAL_SCOPE;
578 if (!cur_func_sym) {
579 if (!parse_error) {
580 sm_msg("warn: internal. problem with scope: %s",
581 sym->ident ? sym->ident->name : "<anon var>");
583 return GLOBAL_SCOPE;
587 i = 0;
588 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
589 if (tmp == sym)
590 return i;
591 i++;
592 } END_FOR_EACH_PTR(tmp);
593 return LOCAL_SCOPE;
596 int get_param_num(struct expression *expr)
598 struct symbol *sym;
599 char *name;
601 if (!cur_func_sym)
602 return UNKNOWN_SCOPE;
603 name = expr_to_var_sym(expr, &sym);
604 free_string(name);
605 if (!sym)
606 return UNKNOWN_SCOPE;
607 return get_param_num_from_sym(sym);
610 struct symbol *get_param_sym_from_num(int num)
612 struct symbol *sym;
613 int i;
615 if (!cur_func_sym)
616 return NULL;
618 i = 0;
619 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) {
620 if (i++ == num)
621 return sym;
622 } END_FOR_EACH_PTR(sym);
623 return NULL;
626 char *get_name_sym_from_param_key(struct expression *expr, int param, const char *key, struct symbol **sym)
628 struct expression *call, *arg;
629 char *name;
631 if (sym)
632 *sym = NULL;
634 if (!expr) {
635 sm_msg("internal: null call_expr. param=%d key='%s'", param, key);
636 return NULL;
639 call = expr;
640 while (call->type == EXPR_ASSIGNMENT)
641 call = strip_expr(call->right);
643 if (call->type != EXPR_CALL)
644 return NULL;
646 if (param == -1 &&
647 expr->type == EXPR_ASSIGNMENT &&
648 expr->op == '=') {
649 name = get_variable_from_key(expr->left, key, sym);
650 if (!name || (sym && !*sym))
651 goto free;
652 } else if (param >= 0) {
653 arg = get_argument_from_call_expr(call->args, param);
654 if (!arg)
655 return NULL;
657 name = get_variable_from_key(arg, key, sym);
658 if (!name || (sym && !*sym))
659 goto free;
660 } else {
661 name = alloc_string(key);
664 return name;
665 free:
666 free_string(name);
667 return NULL;
670 char *handle_container_of_assign(struct expression *expr, struct symbol **sym)
672 struct expression *right, *orig;
673 struct symbol *type;
674 sval_t sval;
675 int param;
676 char buf[64];
678 type = get_type(expr->left);
679 if (!type || type->type != SYM_PTR)
680 return NULL;
682 right = strip_expr(expr->right);
683 if (right->type != EXPR_BINOP || right->op != '-')
684 return NULL;
686 if (!get_value(right->right, &sval) ||
687 sval.value < 0 || sval.value > MTAG_OFFSET_MASK)
688 return NULL;
690 orig = get_assigned_expr(right->left);
691 if (!orig)
692 return NULL;
693 if (orig->type != EXPR_SYMBOL)
694 return NULL;
695 param = get_param_num_from_sym(orig->symbol);
696 if (param < 0)
697 return NULL;
699 snprintf(buf, sizeof(buf), "(%lld<~$)", sval.value);
700 *sym = orig->symbol;
701 return alloc_string(buf);
704 const char *get_container_of_str(struct expression *expr)
706 struct smatch_state *state;
708 state = get_state_expr(my_id, expr);
709 if (!state)
710 return NULL;
711 return state->name;
714 static void match_assign(struct expression *expr)
716 struct symbol *param_sym;
717 char *param_name;
719 if (expr->op != '=')
720 return;
722 /* __in_fake_parameter_assign is included deliberately */
723 if (is_fake_call(expr->right) ||
724 __in_fake_struct_assign)
725 return;
727 param_name = get_param_name_sym(expr->right, &param_sym);
728 if (param_name && param_sym)
729 goto set_state;
731 param_name = handle_container_of_assign(expr, &param_sym);
732 if (param_name && param_sym)
733 goto set_state;
735 goto free;
737 set_state:
738 set_state_expr(my_id, expr->left, alloc_var_sym_state(param_name, param_sym));
739 free:
740 free_string(param_name);
743 void register_param_key(int id)
745 my_id = id;
747 set_dynamic_states(my_id);
748 add_hook(&match_assign, ASSIGNMENT_HOOK_AFTER);
749 add_modification_hook(my_id, &undef);