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
20 #include "smatch_extra.h"
21 #include "smatch_slist.h"
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
)
35 bool is_star
= false; /* fixme: this should be star_cnt */
50 while(orig
[offset
] == '*' || orig
[offset
] == '&' || orig
[offset
] == '(')
54 if (len
+ offset
> strlen(orig
))
56 if (orig
[offset
+ len
] == '\0')
58 else if (orig
[offset
+ len
] != '-')
60 if (strncmp(orig
+ offset
, remove
, len
) != 0)
63 if (!is_star
&& is_end
)
66 ret
= snprintf(buf
, sizeof(buf
), "%.*s%s%s%s", offset
, orig
,
68 is_end
? "" : (is_addr
? "." : "->"),
69 is_end
? "" : orig
+ offset
+ 2 + len
);
70 if (ret
>= sizeof(buf
))
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
;
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
)
89 state
= get_state(my_id
, sym
->ident
->name
, sym
);
90 if (!state
|| !state
->data
)
92 var_sym
= state
->data
;
94 ret
= swap_names(name
, sym
->ident
->name
, var_sym
->var
);
98 *sym_p
= var_sym
->sym
;
102 struct expression
*map_container_of_to_simpler_expr_key(struct expression
*expr
, const char *orig_key
, char **new_key
)
104 struct expression
*container
;
106 char *p
= (char *)orig_key
;
113 expr
= strip_expr(expr
);
114 if (expr
->type
!= EXPR_DEREF
&&
115 (expr
->type
!= EXPR_PREOP
&& expr
->op
== '&'))
119 if (*p
== '(' && isdigit(*(p
+ 1))) {
121 offset
= strtoul(p
+ 1, &p
, 10);
122 if (!p
|| strncmp(p
, "<~$", 3) != 0)
127 param
= strtoul(p
+ 1, &p
, 10);
131 if (!p
|| strncmp(p
, ")->", 3) != 0)
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
)
146 expr
= strip_expr(expr
->deref
);
147 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '*')
149 container
= expr
->unop
;
152 container
= expr
->deref
;
154 container
= get_stored_container(expr
, offset
);
160 ret
= snprintf(buf
, sizeof(buf
), "%.*s$%s%s", (int)(start
- orig_key
), orig_key
, arrow
? "->" : ".", p
);
161 if (ret
>= sizeof(buf
))
163 *new_key
= alloc_sname(buf
);
168 char *get_variable_from_key(struct expression
*arg
, const char *key
, struct symbol
**sym
)
173 bool address
= false;
175 bool add_dot
= false;
178 // FIXME: this function has been marked for being made static
179 // Use get_name_sym_from_param_key().
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
);
197 tmp
= expr_to_var_sym(arg
, sym
);
200 ret
= snprintf(buf
, sizeof(buf
), "*%s", tmp
);
202 if (ret
>= sizeof(buf
))
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
);
214 tmp
= expr_to_var_sym(arg
, sym
);
217 ret
= snprintf(buf
, sizeof(buf
), "(*%s)%s", tmp
, key
+ 4);
219 if (ret
>= sizeof(buf
))
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
);
234 *sym
= expr_to_sym(expr
);
239 while (key
[0] == '*') {
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
))
257 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&' && star_cnt
&& !add_dot
) {
258 arg
= strip_expr(arg
->unop
);
262 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&') {
263 arg
= strip_expr(arg
->unop
);
264 tmp
= expr_to_var_sym(arg
, sym
);
267 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s%s.%s",
268 address
? "&" : "", star_cnt
, "**********",
270 if (ret
>= sizeof(buf
))
272 return alloc_string(buf
);
275 tmp
= expr_to_var_sym(arg
, sym
);
278 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s%s%s",
279 address
? "&" : "", star_cnt
, "**********", tmp
, key
+ 1);
281 if (ret
>= sizeof(buf
))
283 return alloc_string(buf
);
286 static bool split_param_key(const char *value
, int *param
, char *key
, int len
)
291 l
= snprintf(key
, len
, "%s", value
);
296 while (*p
&& *p
!= '$')
303 if (*param
< 0 || *param
> 99)
312 memmove(p
- skip
, p
, l
- (p
- key
) + 1);
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
;
326 while (expr
->type
== EXPR_ASSIGNMENT
)
328 if (expr
->type
!= EXPR_CALL
)
331 if (!split_param_key(data
, ¶m
, buf
, sizeof(buf
)))
334 if (strcmp(buf
, "$") == 0) {
335 arg
= get_argument_from_call_expr(expr
->args
, param
);
338 return get_implied_rl(arg
, rl
);
341 name
= get_name_sym_from_param_key(expr
, param
, buf
, &sym
);
345 state
= get_state(SMATCH_EXTRA
, name
, sym
);
346 if (!estate_rl(state
))
348 *rl
= estate_rl(state
);
352 char *get_chunk_from_key(struct expression
*arg
, char *key
, struct symbol
**sym
, struct var_sym_list
**vsl
)
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;
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
375 if (strstr(state_name
, "<~$"))
376 return (char *)state_name
;
378 name_len
= strlen(param_name
);
380 while (state_name
[0] == '*') {
385 if (state_name
[0] == '&') {
390 /* ten out of ten stars! */
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",
399 star_cnt
, "**********",
400 state_name
+ name_len
+ 3);
401 if (ret
>= sizeof(buf
))
403 return alloc_sname(buf
);
406 if (strcmp(state_name
, param_name
) == 0) {
407 snprintf(buf
, sizeof(buf
), "%s%.*s$",
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",
418 star_cnt
, "**********",
419 state_name
+ name_len
);
420 if (ret
>= sizeof(buf
))
422 return alloc_sname(buf
);
427 char *get_param_name_var_sym(const char *name
, struct symbol
*sym
)
429 if (!sym
|| !sym
->ident
)
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
)
438 const char *sym_name
;
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
)
454 type
= get_real_base_type(sym
);
455 if (type
&& type
->type
== SYM_BASETYPE
)
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);
467 return state_name_to_param_name(state_name
, sym_name
);
470 const char *get_mtag_name_expr(struct expression
*expr
)
474 const char *ret
= NULL
;
476 name
= expr_to_var_sym(expr
, &sym
);
480 ret
= get_mtag_name_var_sym(name
, sym
);
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
;
499 // FIXME was modified...
501 param
= get_param_num_from_sym(sym
);
504 return alloc_string(name
);
507 state
= get_state(my_id
, name
, sym
);
508 if (state
&& state
->data
) {
509 var_sym
= state
->data
;
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
)
531 const char *ret
= NULL
;
534 name
= expr_to_var_sym(expr
, &sym
);
538 ret
= get_param_var_sym_var_sym(name
, sym
, NULL
, sym_p
);
541 return alloc_string(ret
);
544 int get_param_key_from_var_sym(const char *name
, struct symbol
*sym
,
545 struct expression
*ret_expr
,
548 const char *param_name
;
550 struct symbol
*other_sym
;
556 /* straight forward param match */
557 param
= get_param_num_from_sym(sym
);
559 param_name
= get_param_name_var_sym(name
, sym
);
567 /* it's the return value */
569 struct symbol
*ret_sym
;
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
);
576 free_string(ret_str
);
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
)
588 param
= get_param_num_from_sym(other_sym
);
590 sm_msg("internal: '%s' parameter not found", other_name
);
594 param_name
= get_param_name_var_sym(other_name
, other_sym
);
603 int get_param_key_from_sm(struct sm_state
*sm
, struct expression
*ret_expr
,
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
,
617 name
= expr_to_var_sym(expr
, &sym
);
621 ret
= get_param_key_from_var_sym(name
, sym
, ret_expr
, key
);
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
)
638 return UNKNOWN_SCOPE
;
640 if (sym
->ctype
.modifiers
& MOD_TOPLEVEL
) {
641 if (sym
->ctype
.modifiers
& MOD_STATIC
)
648 sm_msg("warn: internal. problem with scope: %s",
649 sym
->ident
? sym
->ident
->name
: "<anon var>");
656 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
660 } END_FOR_EACH_PTR(tmp
);
664 int get_param_num(struct expression
*expr
)
670 return UNKNOWN_SCOPE
;
671 name
= expr_to_var_sym(expr
, &sym
);
674 return UNKNOWN_SCOPE
;
675 return get_param_num_from_sym(sym
);
678 struct symbol
*get_param_sym_from_num(int num
)
687 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, sym
) {
690 } END_FOR_EACH_PTR(sym
);
694 char *get_name_sym_from_param_key(struct expression
*expr
, int param
, const char *key
, struct symbol
**sym
)
696 struct expression
*call
, *arg
;
703 sm_msg("internal: null call_expr. param=%d key='%s'", param
, key
);
708 while (call
->type
== EXPR_ASSIGNMENT
)
709 call
= strip_expr(call
->right
);
711 if (call
->type
!= EXPR_CALL
)
715 expr
->type
== EXPR_ASSIGNMENT
&&
717 name
= get_variable_from_key(expr
->left
, key
, sym
);
718 if (!name
|| (sym
&& !*sym
))
720 } else if (param
>= 0) {
721 arg
= get_argument_from_call_expr(call
->args
, param
);
725 name
= get_variable_from_key(arg
, key
, sym
);
726 if (!name
|| (sym
&& !*sym
))
729 name
= alloc_string(key
);
738 static char *handle_container_of_assign(struct expression
*expr
, struct symbol
**sym
)
740 struct expression
*right
, *orig
;
746 type
= get_type(expr
->left
);
747 if (!type
|| type
->type
!= SYM_PTR
)
750 right
= strip_expr(expr
->right
);
751 if (right
->type
!= EXPR_BINOP
|| right
->op
!= '-')
754 if (!get_value(right
->right
, &sval
) ||
755 sval
.value
< 0 || sval
.value
> MTAG_OFFSET_MASK
)
758 orig
= get_assigned_expr(right
->left
);
761 if (orig
->type
!= EXPR_SYMBOL
)
763 param
= get_param_num_from_sym(orig
->symbol
);
767 snprintf(buf
, sizeof(buf
), "(%lld<~$%d)", sval
.value
, param
);
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
);
779 if (!strstr(state
->name
, "<~$"))
784 static void match_assign(struct expression
*expr
)
786 struct symbol
*param_sym
;
792 /* __in_fake_parameter_assign is included deliberately */
793 if (is_fake_call(expr
->right
) ||
794 __in_fake_struct_assign
)
797 param_name
= get_param_name_sym(expr
->right
, ¶m_sym
);
798 if (param_name
&& param_sym
)
801 param_name
= handle_container_of_assign(expr
, ¶m_sym
);
802 if (param_name
&& param_sym
)
808 set_state_expr(my_id
, expr
->left
, alloc_var_sym_state(param_name
, param_sym
));
810 free_string(param_name
);
813 bool get_offset_param(const char *ret_str
, int *offset
, int *param
)
819 p
= strstr(ret_str
, "[(");
824 p
= strstr(p
, "<~$");
834 static void return_str_hook(struct expression
*expr
, const char *ret_str
)
836 struct expression
*call
, *arg
;
841 if (!expr
|| expr
->type
!= EXPR_ASSIGNMENT
)
844 while (call
&& call
->type
== EXPR_ASSIGNMENT
)
845 call
= strip_expr(call
->right
);
846 if (!call
|| call
->type
!= EXPR_CALL
)
849 if (!get_offset_param(ret_str
, &offset
, ¶m
))
852 arg
= get_argument_from_call_expr(call
->args
, param
);
853 arg
= strip_expr(arg
);
857 /* fixme this could be better */
858 if (arg
->type
!= EXPR_SYMBOL
)
862 param
= get_param_num(arg
);
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
)
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
);