db/insert_manual_states.pl: remove debug output
[smatch.git] / smatch_param_key.c
blob4f59f9ff90548f035cba52de67c091be1356c3ad
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;
35 bool is_star = false; /* fixme: this should be star_cnt */
36 bool is_end = false;
38 if (orig[0] == '*')
39 is_star = true;
41 if (add[0] == '&') {
42 if (is_star)
43 is_star = false;
44 else
45 is_addr = true;
46 add++;
49 offset = 0;
50 while(orig[offset] == '*' || orig[offset] == '&' || orig[offset] == '(')
51 offset++;
53 len = strlen(remove);
54 if (len + offset > strlen(orig))
55 return NULL;
56 if (orig[offset + len] == '\0')
57 is_end = true;
58 else if (orig[offset + len] != '-')
59 return NULL;
60 if (strncmp(orig + offset, remove, len) != 0)
61 return NULL;
63 if (!is_star && is_end)
64 return NULL;
66 ret = snprintf(buf, sizeof(buf), "%.*s%s%s%s", offset, orig,
67 add,
68 is_end ? "" : (is_addr ? "." : "->"),
69 is_end ? "" : orig + offset + 2 + len);
70 if (ret >= sizeof(buf))
71 return NULL;
72 return alloc_string(buf);
75 static char *swap_with_param(const char *name, struct symbol *sym, struct symbol **sym_p)
77 struct smatch_state *state;
78 struct var_sym *var_sym;
79 char *ret;
82 * Say you know that "foo = bar;" and you have a state "foo->baz" then
83 * we can just substitute "bar" for "foo" giving "bar->baz".
86 if (!sym || !sym->ident)
87 return NULL;
89 state = get_state(my_id, sym->ident->name, sym);
90 if (!state || !state->data)
91 return NULL;
92 var_sym = state->data;
94 ret = swap_names(name, sym->ident->name, var_sym->var);
95 if (!ret)
96 return NULL;
98 *sym_p = var_sym->sym;
99 return ret;
102 struct expression *map_container_of_to_simpler_expr_key(struct expression *expr, const char *orig_key, char **new_key)
104 struct expression *container;
105 int offset = -1;
106 char *p = (char *)orig_key;
107 char buf[64];
108 char *start;
109 int param;
110 int ret;
111 bool arrow = false;
113 expr = strip_expr(expr);
114 if (expr->type != EXPR_DEREF &&
115 (expr->type != EXPR_PREOP && expr->op == '&'))
116 return NULL;
118 while (*p != '\0') {
119 if (*p == '(' && isdigit(*(p + 1))) {
120 start = p;
121 offset = strtoul(p + 1, &p, 10);
122 if (!p || strncmp(p, "<~$", 3) != 0)
123 return NULL;
124 p += 3;
125 if (!isdigit(p[0]))
126 return NULL;
127 param = strtoul(p + 1, &p, 10);
128 /* fixme */
129 if (param != 0)
130 return NULL;
131 if (!p || strncmp(p, ")->", 3) != 0)
132 return NULL;
133 p += 3;
134 break;
136 p++;
138 if (*p == '\0')
139 return NULL;
141 if (offset == get_member_offset_from_deref(expr)) {
142 if (expr->type == EXPR_PREOP && expr->op == '&') {
143 expr = strip_expr(expr->unop);
144 if (expr->type != EXPR_DEREF)
145 return NULL;
146 expr = strip_expr(expr->deref);
147 if (expr->type != EXPR_PREOP || expr->op != '*')
148 return NULL;
149 container = expr->unop;
150 arrow = true;
152 container = expr->deref;
153 } else {
154 container = get_stored_container(expr, offset);
155 if (!container)
156 return NULL;
157 arrow = true;
160 ret = snprintf(buf, sizeof(buf), "%.*s$%s%s", (int)(start - orig_key), orig_key, arrow ? "->" : ".", p);
161 if (ret >= sizeof(buf))
162 return NULL;
163 *new_key = alloc_sname(buf);
165 return container;
168 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
170 struct symbol *type;
171 char buf[256];
172 char *tmp;
173 bool address = false;
174 int star_cnt = 0;
175 bool add_dot = false;
176 int ret;
178 // FIXME: this function has been marked for being made static
179 // Use get_name_sym_from_param_key().
181 if (sym)
182 *sym = NULL;
184 if (!arg)
185 return NULL;
187 arg = strip_expr(arg);
189 if (strcmp(key, "$") == 0)
190 return expr_to_var_sym(arg, sym);
192 if (strcmp(key, "*$") == 0) {
193 if (arg->type == EXPR_PREOP && arg->op == '&') {
194 arg = strip_expr(arg->unop);
195 return expr_to_var_sym(arg, sym);
196 } else {
197 tmp = expr_to_var_sym(arg, sym);
198 if (!tmp)
199 return NULL;
200 ret = snprintf(buf, sizeof(buf), "*%s", tmp);
201 free_string(tmp);
202 if (ret >= sizeof(buf))
203 return NULL;
204 return alloc_string(buf);
208 if (strncmp(key, "(*$)", 4) == 0) {
209 if (arg->type == EXPR_PREOP && arg->op == '&') {
210 arg = strip_expr(arg->unop);
211 snprintf(buf, sizeof(buf), "$%s", key + 4);
212 return get_variable_from_key(arg, buf, sym);
213 } else {
214 tmp = expr_to_var_sym(arg, sym);
215 if (!tmp)
216 return NULL;
217 ret = snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
218 free_string(tmp);
219 if (ret >= sizeof(buf))
220 return NULL;
221 return alloc_string(buf);
225 if (strstr(key, "<~$")) {
226 struct expression *expr;
227 char *new_key = NULL;
229 expr = map_container_of_to_simpler_expr_key(arg, key, &new_key);
230 if (!expr)
231 return NULL;
232 if (arg != expr) {
233 arg = expr;
234 *sym = expr_to_sym(expr);
236 key = new_key;
239 while (key[0] == '*') {
240 star_cnt++;
241 key++;
244 if (key[0] == '&') {
245 address = true;
246 key++;
250 * FIXME: This is a hack.
251 * We should be able to parse expressions like (*$)->foo and *$->foo.
253 type = get_type(arg);
254 if (is_struct_ptr(type))
255 add_dot = true;
257 if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
258 arg = strip_expr(arg->unop);
259 star_cnt--;
262 if (arg->type == EXPR_PREOP && arg->op == '&') {
263 arg = strip_expr(arg->unop);
264 tmp = expr_to_var_sym(arg, sym);
265 if (!tmp)
266 return NULL;
267 ret = snprintf(buf, sizeof(buf), "%s%.*s%s.%s",
268 address ? "&" : "", star_cnt, "**********",
269 tmp, key + 3);
270 if (ret >= sizeof(buf))
271 return NULL;
272 return alloc_string(buf);
275 tmp = expr_to_var_sym(arg, sym);
276 if (!tmp)
277 return NULL;
278 ret = snprintf(buf, sizeof(buf), "%s%.*s%s%s",
279 address ? "&" : "", star_cnt, "**********", tmp, key + 1);
280 free_string(tmp);
281 if (ret >= sizeof(buf))
282 return NULL;
283 return alloc_string(buf);
286 static bool split_param_key(const char *value, int *param, char *key, int len)
288 char *p;
289 int l, skip = 1;
291 l = snprintf(key, len, "%s", value);
292 if (l >= len)
293 return false;
295 p = key;
296 while (*p && *p != '$')
297 p++;
298 if (*p != '$')
299 return false;
300 p++;
302 *param = atoi(p);
303 if (*param < 0 || *param > 99)
304 return false;
306 p++;
307 if (*param > 9) {
308 skip = 2;
309 p++;
312 memmove(p - skip, p, l - (p - key) + 1);
314 return true;
317 bool get_implied_rl_from_call_str(struct expression *expr, const char *data, struct range_list **rl)
319 struct smatch_state *state;
320 struct expression *arg;
321 struct symbol *sym;
322 char buf[256];
323 char *name;
324 int param;
326 while (expr->type == EXPR_ASSIGNMENT)
327 expr = expr->right;
328 if (expr->type != EXPR_CALL)
329 return false;
331 if (!split_param_key(data, &param, buf, sizeof(buf)))
332 return false;
334 if (strcmp(buf, "$") == 0) {
335 arg = get_argument_from_call_expr(expr->args, param);
336 if (!arg)
337 return false;
338 return get_implied_rl(arg, rl);
341 name = get_name_sym_from_param_key(expr, param, buf, &sym);
342 if (!name)
343 return false;
345 state = get_state(SMATCH_EXTRA, name, sym);
346 if (!estate_rl(state))
347 return false;
348 *rl = estate_rl(state);
349 return true;
352 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl)
354 *vsl = NULL;
356 if (strcmp("$", key) == 0)
357 return expr_to_chunk_sym_vsl(arg, sym, vsl);
358 return get_variable_from_key(arg, key, sym);
361 static char *state_name_to_param_name(const char *state_name, const char *param_name)
363 bool address = false;
364 int star_cnt = 0;
365 int name_len;
366 char buf[256];
367 int ret;
370 * Normally what happens is that we map "*foo->bar" to "*param->bar"
371 * but with container_of() there is no notation for that in C and it's
372 * just a Smatch invention. So in that case, the state name is the
373 * param name.
375 if (strstr(state_name, "<~$"))
376 return (char *)state_name;
378 name_len = strlen(param_name);
380 while (state_name[0] == '*') {
381 star_cnt++;
382 state_name++;
385 if (state_name[0] == '&') {
386 address = true;
387 state_name++;
390 /* ten out of ten stars! */
391 if (star_cnt > 10)
392 return NULL;
394 if (strncmp(state_name, "(*", 2) == 0 &&
395 strncmp(state_name + 2, param_name, name_len) == 0 &&
396 state_name[name_len + 2] == ')') {
397 ret = snprintf(buf, sizeof(buf), "%s%.*s(*$)%s",
398 address ? "&" : "",
399 star_cnt, "**********",
400 state_name + name_len + 3);
401 if (ret >= sizeof(buf))
402 return NULL;
403 return alloc_sname(buf);
406 if (strcmp(state_name, param_name) == 0) {
407 snprintf(buf, sizeof(buf), "%s%.*s$",
408 address ? "&" : "",
409 star_cnt, "**********");
410 return alloc_sname(buf);
413 /* check for '-' from "->" */
414 if (strncmp(state_name, param_name, name_len) == 0 &&
415 state_name[name_len] == '-') {
416 ret = snprintf(buf, sizeof(buf), "%s%.*s$%s",
417 address ? "&" : "",
418 star_cnt, "**********",
419 state_name + name_len);
420 if (ret >= sizeof(buf))
421 return NULL;
422 return alloc_sname(buf);
424 return NULL;
427 char *get_param_name_var_sym(const char *name, struct symbol *sym)
429 if (!sym || !sym->ident)
430 return NULL;
432 return state_name_to_param_name(name, sym->ident->name);
435 const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym)
437 struct symbol *type;
438 const char *sym_name;
439 int name_len;
440 static char buf[256];
443 * mtag_name is different from param_name because mtags can be a struct
444 * instead of a struct pointer. But we want to treat it like a pointer
445 * because really an mtag is a pointer. Or in other words, if you pass
446 * a struct foo then you want to talk about foo.bar but with an mtag
447 * you want to refer to it as foo->bar.
451 if (!sym || !sym->ident)
452 return NULL;
454 type = get_real_base_type(sym);
455 if (type && type->type == SYM_BASETYPE)
456 return "*$";
458 sym_name = sym->ident->name;
459 name_len = strlen(sym_name);
461 if (state_name[name_len] == '.' && /* check for '-' from "->" */
462 strncmp(state_name, sym_name, name_len) == 0) {
463 snprintf(buf, sizeof(buf), "$->%s", state_name + name_len + 1);
464 return buf;
467 return state_name_to_param_name(state_name, sym_name);
470 const char *get_mtag_name_expr(struct expression *expr)
472 char *name;
473 struct symbol *sym;
474 const char *ret = NULL;
476 name = expr_to_var_sym(expr, &sym);
477 if (!name || !sym)
478 goto free;
480 ret = get_mtag_name_var_sym(name, sym);
481 free:
482 free_string(name);
483 return ret;
486 char *get_param_name(struct sm_state *sm)
488 return get_param_name_var_sym(sm->name, sm->sym);
491 char *get_param_var_sym_var_sym(const char *name, struct symbol *sym, struct expression *ret_expr, struct symbol **sym_p)
493 struct smatch_state *state;
494 struct var_sym *var_sym;
495 int param;
497 *sym_p = NULL;
499 // FIXME was modified...
501 param = get_param_num_from_sym(sym);
502 if (param >= 0) {
503 *sym_p = sym;
504 return alloc_string(name);
507 state = get_state(my_id, name, sym);
508 if (state && state->data) {
509 var_sym = state->data;
510 if (!var_sym)
511 return NULL;
513 *sym_p = var_sym->sym;
514 return alloc_string(var_sym->var);
517 /* One would think that handling container_of() should be done here
518 * but it it's quite tricky because we only have a name and a sym
519 * and none of the assignments have been handled yet, either here or
520 * in smatch_assignments.c. On the other hand handling container_of()
521 * in the assignment hook has the advantage that it saves resources and
522 * it should work fine because of the fake assignments which we do.
525 return swap_with_param(name, sym, sym_p);
528 char *get_param_name_sym(struct expression *expr, struct symbol **sym_p)
530 struct symbol *sym;
531 const char *ret = NULL;
532 char *name;
534 name = expr_to_var_sym(expr, &sym);
535 if (!name || !sym)
536 goto free;
538 ret = get_param_var_sym_var_sym(name, sym, NULL, sym_p);
539 free:
540 free_string(name);
541 return alloc_string(ret);
544 int get_param_key_from_var_sym(const char *name, struct symbol *sym,
545 struct expression *ret_expr,
546 const char **key)
548 const char *param_name;
549 char *other_name;
550 struct symbol *other_sym;
551 int param;
553 if (key)
554 *key = name;
556 /* straight forward param match */
557 param = get_param_num_from_sym(sym);
558 if (param >= 0) {
559 param_name = get_param_name_var_sym(name, sym);
560 if (param_name) {
561 if (key)
562 *key = param_name;
563 return param;
567 /* it's the return value */
568 if (ret_expr) {
569 struct symbol *ret_sym;
570 char *ret_str;
572 ret_str = expr_to_str_sym(ret_expr, &ret_sym);
573 if (ret_str && ret_sym == sym) {
574 param_name = state_name_to_param_name(name, ret_str);
575 if (param_name) {
576 free_string(ret_str);
577 if (key)
578 *key = param_name;
579 return -1;
582 free_string(ret_str);
585 other_name = get_param_var_sym_var_sym(name, sym, ret_expr, &other_sym);
586 if (!other_name || !other_sym)
587 return -2;
588 param = get_param_num_from_sym(other_sym);
589 if (param < 0) {
590 sm_msg("internal: '%s' parameter not found", other_name);
591 return -2;
594 param_name = get_param_name_var_sym(other_name, other_sym);
595 if (param_name) {
596 if (key)
597 *key = param_name;
598 return param;
600 return -2;
603 int get_param_key_from_sm(struct sm_state *sm, struct expression *ret_expr,
604 const char **key)
606 return get_param_key_from_var_sym(sm->name, sm->sym, ret_expr, key);
609 int get_param_key_from_expr(struct expression *expr, struct expression *ret_expr,
610 const char **key)
612 char *name;
613 struct symbol *sym;
614 int ret = -2;
616 *key = NULL;
617 name = expr_to_var_sym(expr, &sym);
618 if (!name || !sym)
619 goto free;
621 ret = get_param_key_from_var_sym(name, sym, ret_expr, key);
622 free:
623 free_string(name);
624 return ret;
627 int map_to_param(const char *name, struct symbol *sym)
629 return get_param_key_from_var_sym(name, sym, NULL, NULL);
632 int get_param_num_from_sym(struct symbol *sym)
634 struct symbol *tmp;
635 int i;
637 if (!sym)
638 return UNKNOWN_SCOPE;
640 if (sym->ctype.modifiers & MOD_TOPLEVEL) {
641 if (sym->ctype.modifiers & MOD_STATIC)
642 return FILE_SCOPE;
643 return GLOBAL_SCOPE;
646 if (!cur_func_sym) {
647 if (!parse_error) {
648 sm_msg("warn: internal. problem with scope: %s",
649 sym->ident ? sym->ident->name : "<anon var>");
651 return GLOBAL_SCOPE;
655 i = 0;
656 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
657 if (tmp == sym)
658 return i;
659 i++;
660 } END_FOR_EACH_PTR(tmp);
661 return LOCAL_SCOPE;
664 int get_param_num(struct expression *expr)
666 struct symbol *sym;
667 char *name;
669 if (!cur_func_sym)
670 return UNKNOWN_SCOPE;
671 name = expr_to_var_sym(expr, &sym);
672 free_string(name);
673 if (!sym)
674 return UNKNOWN_SCOPE;
675 return get_param_num_from_sym(sym);
678 struct symbol *get_param_sym_from_num(int num)
680 struct symbol *sym;
681 int i;
683 if (!cur_func_sym)
684 return NULL;
686 i = 0;
687 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) {
688 if (i++ == num)
689 return sym;
690 } END_FOR_EACH_PTR(sym);
691 return NULL;
694 char *get_name_sym_from_param_key(struct expression *expr, int param, const char *key, struct symbol **sym)
696 struct expression *call, *arg;
697 char *name;
699 if (sym)
700 *sym = NULL;
702 if (!expr) {
703 sm_msg("internal: null call_expr. param=%d key='%s'", param, key);
704 return NULL;
707 call = expr;
708 while (call->type == EXPR_ASSIGNMENT)
709 call = strip_expr(call->right);
711 if (call->type != EXPR_CALL)
712 return NULL;
714 if (param == -1 &&
715 expr->type == EXPR_ASSIGNMENT &&
716 expr->op == '=') {
717 name = get_variable_from_key(expr->left, key, sym);
718 if (!name || (sym && !*sym))
719 goto free;
720 } else if (param >= 0) {
721 arg = get_argument_from_call_expr(call->args, param);
722 if (!arg)
723 return NULL;
725 name = get_variable_from_key(arg, key, sym);
726 if (!name || (sym && !*sym))
727 goto free;
728 } else {
729 name = alloc_string(key);
732 return name;
733 free:
734 free_string(name);
735 return NULL;
738 static char *handle_container_of_assign(struct expression *expr, struct symbol **sym)
740 struct expression *right, *orig;
741 struct symbol *type;
742 sval_t sval;
743 int param;
744 char buf[64];
746 type = get_type(expr->left);
747 if (!type || type->type != SYM_PTR)
748 return NULL;
750 right = strip_expr(expr->right);
751 if (right->type != EXPR_BINOP || right->op != '-')
752 return NULL;
754 if (!get_value(right->right, &sval) ||
755 sval.value < 0 || sval.value > MTAG_OFFSET_MASK)
756 return NULL;
758 orig = get_assigned_expr(right->left);
759 if (!orig)
760 return NULL;
761 if (orig->type != EXPR_SYMBOL)
762 return NULL;
763 param = get_param_num_from_sym(orig->symbol);
764 if (param < 0)
765 return NULL;
767 snprintf(buf, sizeof(buf), "(%lld<~$%d)", sval.value, param);
768 *sym = orig->symbol;
769 return alloc_string(buf);
772 const char *get_container_of_str(struct expression *expr)
774 struct smatch_state *state;
776 state = get_state_expr(my_id, expr);
777 if (!state)
778 return NULL;
779 if (!strstr(state->name, "<~$"))
780 return NULL;
781 return state->name;
784 static void match_assign(struct expression *expr)
786 struct symbol *param_sym;
787 char *param_name;
789 if (expr->op != '=')
790 return;
792 /* __in_fake_parameter_assign is included deliberately */
793 if (is_fake_call(expr->right) ||
794 __in_fake_struct_assign)
795 return;
797 param_name = get_param_name_sym(expr->right, &param_sym);
798 if (param_name && param_sym)
799 goto set_state;
801 param_name = handle_container_of_assign(expr, &param_sym);
802 if (param_name && param_sym)
803 goto set_state;
805 goto free;
807 set_state:
808 set_state_expr(my_id, expr->left, alloc_var_sym_state(param_name, param_sym));
809 free:
810 free_string(param_name);
813 bool get_offset_param(const char *ret_str, int *offset, int *param)
815 const char *p;
817 if (!ret_str)
818 return false;
819 p = strstr(ret_str, "[(");
820 if (!p)
821 return false;
822 p += 2;
823 *offset = atoi(p);
824 p = strstr(p, "<~$");
825 if (!p)
826 return false;
827 p += 3;
828 if (!isdigit(p[0]))
829 return false;
830 *param = atoi(p);
831 return true;;
834 static void return_str_hook(struct expression *expr, const char *ret_str)
836 struct expression *call, *arg;
837 struct symbol *sym;
838 int offset, param;
839 char buf[32];
841 if (!expr || expr->type != EXPR_ASSIGNMENT)
842 return;
843 call = expr;
844 while (call && call->type == EXPR_ASSIGNMENT)
845 call = strip_expr(call->right);
846 if (!call || call->type != EXPR_CALL)
847 return;
849 if (!get_offset_param(ret_str, &offset, &param))
850 return;
852 arg = get_argument_from_call_expr(call->args, param);
853 arg = strip_expr(arg);
854 if (!arg)
855 return;
857 /* fixme this could be better */
858 if (arg->type != EXPR_SYMBOL)
859 return;
860 sym = arg->symbol;
862 param = get_param_num(arg);
863 if (param < 0)
864 return;
866 snprintf(buf, sizeof(buf), "(%d<~$%d)", offset, param);
867 set_state_expr(my_id, expr->left, alloc_var_sym_state(buf, sym));
870 void register_param_key(int id)
872 my_id = id;
874 set_dynamic_states(my_id);
875 add_hook(&match_assign, ASSIGNMENT_HOOK_AFTER);
876 add_return_string_hook(return_str_hook);
877 add_modification_hook(my_id, &undef);