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
19 * The param/key stuff is changes "0/$->foo" into a name/sym pair.
20 * It also handles more complicated mappings like container_of(param).
21 * The problem with the current implementation of the container_of()
22 * code in 2023 is that it does stuff like (1624<~$0)->sk.sk_write_queue.next
23 * where 1624 is the number of bytes. It's difficult to write that kind
26 * We also need to be able to handle things like netdev_priv(). When you
27 * allocate a netdev struct then you have to specify how much space you need
28 * for your private data and it allocates a enough data to hold everything.
29 * the netdev_priv() function returns a pointer to beyond the end of the
30 * netdev struct. So the container_of() macro subtracts and the netdev_priv()
37 #include "smatch_extra.h"
38 #include "smatch_slist.h"
42 char *swap_names(const char *orig
, const char *remove
, const char *add
)
47 bool is_star
= false; /* fixme: this should be star_cnt */
62 while(orig
[offset
] == '*' || orig
[offset
] == '&' || orig
[offset
] == '(')
66 if (len
+ offset
> strlen(orig
))
68 if (orig
[offset
+ len
] == '\0')
70 else if (orig
[offset
+ len
] != '-')
72 if (strncmp(orig
+ offset
, remove
, len
) != 0)
75 if (!is_star
&& is_end
)
78 ret
= snprintf(buf
, sizeof(buf
), "%.*s%s%s%s", offset
, orig
,
80 is_end
? "" : (is_addr
? "." : "->"),
81 is_end
? "" : orig
+ offset
+ 2 + len
);
82 if (ret
>= sizeof(buf
))
84 return alloc_string(buf
);
87 static char *swap_with_param(const char *name
, struct symbol
*sym
, struct symbol
**sym_p
)
89 struct smatch_state
*state
;
90 struct var_sym
*var_sym
;
94 * Say you know that "foo = bar;" and you have a state "foo->baz" then
95 * we can just substitute "bar" for "foo" giving "bar->baz".
98 if (!sym
|| !sym
->ident
)
101 state
= get_state(my_id
, sym
->ident
->name
, sym
);
102 if (!state
|| !state
->data
)
104 var_sym
= state
->data
;
106 ret
= swap_names(name
, sym
->ident
->name
, var_sym
->var
);
110 *sym_p
= var_sym
->sym
;
114 struct expression
*map_container_of_to_simpler_expr_key(struct expression
*expr
, const char *orig_key
, char **new_key
)
116 struct expression
*container
;
118 char *p
= (char *)orig_key
;
124 bool no_member
= false;
126 expr
= strip_expr(expr
);
127 if (expr
->type
!= EXPR_DEREF
&&
128 (expr
->type
!= EXPR_PREOP
&& expr
->op
== '&'))
132 if (*p
== '(' && isdigit(*(p
+ 1))) {
134 offset
= strtoul(p
+ 1, &p
, 10);
135 if (!p
|| strncmp(p
, "<~$", 3) != 0)
140 param
= strtoul(p
+ 1, &p
, 10);
146 if (strcmp(p
, ")") == 0) {
151 if (strncmp(p
, ")->", 3) != 0)
158 if (!no_member
&& *p
== '\0')
161 if (offset
== get_member_offset_from_deref(expr
)) {
162 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&') {
163 expr
= strip_expr(expr
->unop
);
164 if (expr
->type
!= EXPR_DEREF
)
166 expr
= strip_expr(expr
->deref
);
167 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '*')
169 container
= expr
->unop
;
172 container
= expr
->deref
;
174 container
= get_stored_container(expr
, offset
);
181 *new_key
= alloc_sname("$");
185 ret
= snprintf(buf
, sizeof(buf
), "%.*s$%s%s", (int)(start
- orig_key
), orig_key
, arrow
? "->" : ".", p
);
186 if (ret
>= sizeof(buf
))
188 *new_key
= alloc_sname(buf
);
193 struct expression
*map_netdev_priv_to_simpler_expr_key(struct expression
*expr
, const char *orig_key
, char **new_key
)
195 struct expression
*priv
;
200 priv
= get_netdev_priv(expr
);
203 if (priv
->type
!= EXPR_SYMBOL
|| !priv
->symbol_name
)
206 p
= strstr(orig_key
, "r netdev_priv($)");
210 if (diff
== 1) /* remove () */
211 snprintf(buf
, sizeof(buf
), "$%s", orig_key
+ 18);
213 snprintf(buf
, sizeof(buf
), "%.*s$%s", diff
, orig_key
, orig_key
+ diff
+ 16);
214 *new_key
= alloc_sname(buf
);
218 char *get_variable_from_key(struct expression
*arg
, const char *key
, struct symbol
**sym
)
223 bool address
= false;
225 bool add_dot
= false;
228 // FIXME: this function has been marked for being made static
229 // Use get_name_sym_from_param_key().
237 arg
= strip_expr(arg
);
239 if (strcmp(key
, "$") == 0)
240 return expr_to_var_sym(arg
, sym
);
242 if (strcmp(key
, "*$") == 0) {
243 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&') {
244 arg
= strip_expr(arg
->unop
);
245 return expr_to_var_sym(arg
, sym
);
247 tmp
= expr_to_var_sym(arg
, sym
);
250 ret
= snprintf(buf
, sizeof(buf
), "*%s", tmp
);
252 if (ret
>= sizeof(buf
))
254 return alloc_string(buf
);
258 if (strncmp(key
, "(*$)", 4) == 0) {
259 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&') {
260 arg
= strip_expr(arg
->unop
);
261 snprintf(buf
, sizeof(buf
), "$%s", key
+ 4);
262 return get_variable_from_key(arg
, buf
, sym
);
264 tmp
= expr_to_var_sym(arg
, sym
);
267 ret
= snprintf(buf
, sizeof(buf
), "(*%s)%s", tmp
, key
+ 4);
269 if (ret
>= sizeof(buf
))
271 return alloc_string(buf
);
275 if (strstr(key
, "<~$")) {
276 struct expression
*expr
;
277 char *new_key
= NULL
;
279 expr
= map_container_of_to_simpler_expr_key(arg
, key
, &new_key
);
284 *sym
= expr_to_sym(expr
);
289 if (strstr(key
, "(r netdev_priv($))")) {
290 struct expression
*expr
;
291 char *new_key
= NULL
;
293 expr
= map_netdev_priv_to_simpler_expr_key(arg
, key
, &new_key
);
298 *sym
= expr_to_sym(expr
);
303 while (key
[0] == '*') {
314 * FIXME: This is a hack.
315 * We should be able to parse expressions like (*$)->foo and *$->foo.
317 type
= get_type(arg
);
318 if (is_struct_ptr(type
))
321 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&' && star_cnt
&& !add_dot
) {
322 arg
= strip_expr(arg
->unop
);
326 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&') {
327 arg
= strip_expr(arg
->unop
);
328 tmp
= expr_to_var_sym(arg
, sym
);
331 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s%s.%s",
332 address
? "&" : "", star_cnt
, "**********",
334 if (ret
>= sizeof(buf
))
336 return alloc_string(buf
);
339 tmp
= expr_to_var_sym(arg
, sym
);
342 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s%s%s",
343 address
? "&" : "", star_cnt
, "**********", tmp
, key
+ 1);
345 if (ret
>= sizeof(buf
))
347 return alloc_string(buf
);
350 bool split_param_key(const char *value
, int *param
, char *key
, int len
)
355 l
= snprintf(key
, len
, "%s", value
);
360 while (*p
&& *p
!= '$')
367 if (*param
< 0 || *param
> 99)
376 memmove(p
- skip
, p
, l
- (p
- key
) + 1);
381 bool get_implied_rl_from_call_str(struct expression
*expr
, const char *data
, struct range_list
**rl
)
383 struct smatch_state
*state
;
384 struct expression
*arg
;
390 while (expr
->type
== EXPR_ASSIGNMENT
)
392 if (expr
->type
!= EXPR_CALL
)
395 if (!split_param_key(data
, ¶m
, buf
, sizeof(buf
)))
398 if (strcmp(buf
, "$") == 0) {
399 arg
= get_argument_from_call_expr(expr
->args
, param
);
402 return get_implied_rl(arg
, rl
);
405 name
= get_name_sym_from_param_key(expr
, param
, buf
, &sym
);
409 state
= get_state(SMATCH_EXTRA
, name
, sym
);
410 if (!estate_rl(state
))
412 *rl
= estate_rl(state
);
416 char *get_chunk_from_key(struct expression
*arg
, char *key
, struct symbol
**sym
, struct var_sym_list
**vsl
)
420 if (strcmp("$", key
) == 0)
421 return expr_to_chunk_sym_vsl(arg
, sym
, vsl
);
422 return get_variable_from_key(arg
, key
, sym
);
425 static char *state_name_to_param_name(const char *state_name
, const char *param_name
)
427 bool address
= false;
434 * Normally what happens is that we map "*foo->bar" to "*param->bar"
435 * but with container_of() there is no notation for that in C and it's
436 * just a Smatch invention. So in that case, the state name is the
439 if (strstr(state_name
, "<~$"))
440 return (char *)state_name
;
442 if (strstr(state_name
, "r netdev_priv($)"))
443 return (char *)state_name
;
445 name_len
= strlen(param_name
);
447 while (state_name
[0] == '*') {
452 if (state_name
[0] == '&') {
457 /* ten out of ten stars! */
461 if (strncmp(state_name
, "(*", 2) == 0 &&
462 strncmp(state_name
+ 2, param_name
, name_len
) == 0 &&
463 state_name
[name_len
+ 2] == ')') {
464 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s(*$)%s",
466 star_cnt
, "**********",
467 state_name
+ name_len
+ 3);
468 if (ret
>= sizeof(buf
))
470 return alloc_sname(buf
);
473 if (strcmp(state_name
, param_name
) == 0) {
474 snprintf(buf
, sizeof(buf
), "%s%.*s$",
476 star_cnt
, "**********");
477 return alloc_sname(buf
);
480 /* check for '-' from "->" */
481 if (strncmp(state_name
, param_name
, name_len
) == 0 &&
482 state_name
[name_len
] == '-') {
483 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s$%s",
485 star_cnt
, "**********",
486 state_name
+ name_len
);
487 if (ret
>= sizeof(buf
))
489 return alloc_sname(buf
);
494 char *get_param_name_var_sym(const char *name
, struct symbol
*sym
)
496 if (!sym
|| !sym
->ident
)
499 return state_name_to_param_name(name
, sym
->ident
->name
);
502 const char *get_mtag_name_var_sym(const char *state_name
, struct symbol
*sym
)
505 const char *sym_name
;
507 static char buf
[256];
510 * mtag_name is different from param_name because mtags can be a struct
511 * instead of a struct pointer. But we want to treat it like a pointer
512 * because really an mtag is a pointer. Or in other words, if you pass
513 * a struct foo then you want to talk about foo.bar but with an mtag
514 * you want to refer to it as foo->bar.
518 if (!sym
|| !sym
->ident
)
521 type
= get_real_base_type(sym
);
522 if (type
&& type
->type
== SYM_BASETYPE
)
525 sym_name
= sym
->ident
->name
;
526 name_len
= strlen(sym_name
);
528 if (state_name
[name_len
] == '.' && /* check for '-' from "->" */
529 strncmp(state_name
, sym_name
, name_len
) == 0) {
530 snprintf(buf
, sizeof(buf
), "$->%s", state_name
+ name_len
+ 1);
534 return state_name_to_param_name(state_name
, sym_name
);
537 const char *get_mtag_name_expr(struct expression
*expr
)
541 const char *ret
= NULL
;
543 name
= expr_to_var_sym(expr
, &sym
);
547 ret
= get_mtag_name_var_sym(name
, sym
);
553 char *get_param_name(struct sm_state
*sm
)
555 return get_param_name_var_sym(sm
->name
, sm
->sym
);
558 char *get_param_var_sym_var_sym(const char *name
, struct symbol
*sym
, struct expression
*ret_expr
, struct symbol
**sym_p
)
560 struct smatch_state
*state
;
561 struct var_sym
*var_sym
;
566 // FIXME was modified...
568 param
= get_param_num_from_sym(sym
);
571 return alloc_string(name
);
574 state
= get_state(my_id
, name
, sym
);
575 if (state
&& state
->data
) {
576 var_sym
= state
->data
;
580 *sym_p
= var_sym
->sym
;
581 return alloc_string(var_sym
->var
);
584 /* One would think that handling container_of() should be done here
585 * but it it's quite tricky because we only have a name and a sym
586 * and none of the assignments have been handled yet, either here or
587 * in smatch_assignments.c. On the other hand handling container_of()
588 * in the assignment hook has the advantage that it saves resources and
589 * it should work fine because of the fake assignments which we do.
592 return swap_with_param(name
, sym
, sym_p
);
595 char *get_param_name_sym(struct expression
*expr
, struct symbol
**sym_p
)
598 const char *ret
= NULL
;
601 name
= expr_to_var_sym(expr
, &sym
);
605 ret
= get_param_var_sym_var_sym(name
, sym
, NULL
, sym_p
);
608 return alloc_string(ret
);
611 int get_return_param_key_from_var_sym(const char *name
, struct symbol
*sym
,
612 struct expression
*ret_expr
,
615 const char *param_name
;
616 struct symbol
*ret_sym
;
622 ret_str
= expr_to_str_sym(ret_expr
, &ret_sym
);
623 if (ret_str
&& ret_sym
== sym
) {
624 param_name
= state_name_to_param_name(name
, ret_str
);
626 free_string(ret_str
);
632 free_string(ret_str
);
637 int get_param_key_from_var_sym(const char *name
, struct symbol
*sym
,
638 struct expression
*ret_expr
,
641 const char *param_name
;
643 struct symbol
*other_sym
;
649 /* straight forward param match */
650 param
= get_param_num_from_sym(sym
);
652 param_name
= get_param_name_var_sym(name
, sym
);
660 param
= get_return_param_key_from_var_sym(name
, sym
, ret_expr
, key
);
664 other_name
= get_param_var_sym_var_sym(name
, sym
, ret_expr
, &other_sym
);
665 if (!other_name
|| !other_sym
)
667 param
= get_param_num_from_sym(other_sym
);
671 param_name
= get_param_name_var_sym(other_name
, other_sym
);
680 int get_param_key_from_sm(struct sm_state
*sm
, struct expression
*ret_expr
,
683 return get_param_key_from_var_sym(sm
->name
, sm
->sym
, ret_expr
, key
);
686 int get_param_key_from_expr(struct expression
*expr
, struct expression
*ret_expr
,
694 name
= expr_to_var_sym(expr
, &sym
);
698 ret
= get_param_key_from_var_sym(name
, sym
, ret_expr
, key
);
704 const char *get_param_key_swap_dollar(struct expression
*expr
)
711 sm
= get_sm_state_expr(my_id
, expr
);
712 if (!sm
|| slist_has_state(sm
->possible
, &undefined
))
715 param
= get_param_key_from_expr(expr
, NULL
, &key
);
719 p
= strchr(key
, '$');
723 snprintf(buf
, sizeof(buf
), "%.*s%d%s", (int)(p
- key
+ 1), key
, param
, p
+ 1);
724 return alloc_sname(buf
);
727 int map_to_param(const char *name
, struct symbol
*sym
)
729 return get_param_key_from_var_sym(name
, sym
, NULL
, NULL
);
732 int get_param_num_from_sym(struct symbol
*sym
)
738 return UNKNOWN_SCOPE
;
740 if (sym
->ctype
.modifiers
& MOD_TOPLEVEL
) {
741 if (sym
->ctype
.modifiers
& MOD_STATIC
)
750 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
754 } END_FOR_EACH_PTR(tmp
);
758 int get_param_num(struct expression
*expr
)
764 return UNKNOWN_SCOPE
;
765 name
= expr_to_var_sym(expr
, &sym
);
768 return UNKNOWN_SCOPE
;
769 return get_param_num_from_sym(sym
);
772 struct symbol
*get_param_sym_from_num(int num
)
781 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, sym
) {
784 } END_FOR_EACH_PTR(sym
);
788 struct expression
*get_function_param(struct expression
*expr
, int param
)
790 struct expression
*call
;
793 sm_msg("internal: null call_expr. param=%d", param
);
798 while (call
->type
== EXPR_ASSIGNMENT
)
799 call
= strip_expr(call
->right
);
801 if (call
->type
!= EXPR_CALL
)
808 if (expr
->type
== EXPR_ASSIGNMENT
&& expr
->op
== '=')
813 return get_argument_from_call_expr(call
->args
, param
);
816 char *get_name_sym_from_param_key(struct expression
*expr
, int param
, const char *key
, struct symbol
**sym
)
818 struct expression
*arg
;
824 if (param
== -2) // Really? Is this sane?
825 return alloc_string(key
);
827 arg
= get_function_param(expr
, param
);
831 name
= get_variable_from_key(arg
, key
, sym
);
832 if (!name
|| (sym
&& !*sym
))
841 static char *handle_container_of_assign(struct expression
*expr
, struct symbol
**sym
)
843 struct expression
*right
, *orig
;
849 type
= get_type(expr
->left
);
850 if (!type
|| type
->type
!= SYM_PTR
)
853 right
= strip_expr(expr
->right
);
854 if (right
->type
!= EXPR_BINOP
|| right
->op
!= '-')
857 if (!get_value(right
->right
, &sval
) ||
858 sval
.value
< 0 || sval
.value
> MTAG_OFFSET_MASK
)
861 orig
= get_assigned_expr(right
->left
);
864 if (orig
->type
!= EXPR_SYMBOL
)
866 param
= get_param_num_from_sym(orig
->symbol
);
870 snprintf(buf
, sizeof(buf
), "(%lld<~$%d)", sval
.value
, param
);
872 return alloc_string(buf
);
875 static char *handle_netdev_priv_assign(struct expression
*expr
, struct symbol
**sym
)
877 struct expression
*right
, *arg
;
880 if (option_project
!= PROJ_KERNEL
)
883 if (!expr
|| expr
->type
!= EXPR_ASSIGNMENT
)
885 right
= strip_expr(expr
->right
);
886 if (!right
|| right
->type
!= EXPR_CALL
)
889 if (!sym_name_is("netdev_priv", right
->fn
))
892 arg
= get_argument_from_call_expr(right
->args
, 0);
893 arg
= strip_expr(arg
);
894 if (!arg
|| arg
->type
!= EXPR_SYMBOL
)
897 /* This isn't necessarily tied to a param */
898 snprintf(buf
, sizeof(buf
), "(r netdev_priv($))");
900 return alloc_string(buf
);
903 const char *get_container_of_str(struct expression
*expr
)
905 struct smatch_state
*state
;
907 state
= get_state_expr(my_id
, expr
);
910 if (!strstr(state
->name
, "<~$"))
915 static void match_assign(struct expression
*expr
)
917 struct symbol
*param_sym
;
923 /* __in_fake_parameter_assign is included deliberately */
924 if (is_fake_call(expr
->right
) ||
925 __in_fake_struct_assign
)
928 param_name
= get_param_name_sym(expr
->right
, ¶m_sym
);
929 if (param_name
&& param_sym
)
932 param_name
= handle_container_of_assign(expr
, ¶m_sym
);
933 if (param_name
&& param_sym
)
936 param_name
= handle_netdev_priv_assign(expr
, ¶m_sym
);
937 if (param_name
&& param_sym
)
943 set_state_expr(my_id
, expr
->left
, alloc_var_sym_state(param_name
, param_sym
));
945 free_string(param_name
);
948 bool get_offset_param(const char *ret_str
, int *offset
, int *param
)
954 p
= strstr(ret_str
, "[(");
959 p
= strstr(p
, "<~$");
969 static void return_str_hook(struct expression
*expr
, const char *ret_str
)
971 struct expression
*call
, *arg
;
976 if (!expr
|| expr
->type
!= EXPR_ASSIGNMENT
)
979 while (call
&& call
->type
== EXPR_ASSIGNMENT
)
980 call
= strip_expr(call
->right
);
981 if (!call
|| call
->type
!= EXPR_CALL
)
984 if (!get_offset_param(ret_str
, &offset
, ¶m
))
987 arg
= get_argument_from_call_expr(call
->args
, param
);
988 arg
= strip_expr(arg
);
992 /* fixme this could be better */
993 if (arg
->type
!= EXPR_SYMBOL
)
997 param
= get_param_num(arg
);
1001 snprintf(buf
, sizeof(buf
), "(%d<~$%d)", offset
, param
);
1002 set_state_expr(my_id
, expr
->left
, alloc_var_sym_state(buf
, sym
));
1005 void register_param_key(int id
)
1009 set_dynamic_states(my_id
);
1010 add_hook(&match_assign
, ASSIGNMENT_HOOK_AFTER
);
1011 add_return_string_hook(return_str_hook
);
1012 add_modification_hook(my_id
, &set_undefined
);