2 * Copyright (C) 2017 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 #include "smatch_slist.h"
23 static struct stree
*used_stree
;
24 static struct stree_stack
*saved_stack
;
28 int get_param_from_container_of(struct expression
*expr
)
30 struct expression
*param_expr
;
36 type
= get_type(expr
);
37 if (!type
|| type
->type
!= SYM_PTR
)
40 expr
= strip_expr(expr
);
41 if (expr
->type
!= EXPR_BINOP
|| expr
->op
!= '-')
44 if (!get_value(expr
->right
, &sval
))
46 if (sval
.value
< 0 || sval
.value
> 4096)
49 param_expr
= get_assigned_expr(expr
->left
);
52 param
= get_param_num(param_expr
);
59 int get_offset_from_container_of(struct expression
*expr
)
61 struct expression
*param_expr
;
67 type
= get_type(expr
);
68 if (!type
|| type
->type
!= SYM_PTR
)
71 expr
= strip_expr(expr
);
72 if (expr
->type
!= EXPR_BINOP
|| expr
->op
!= '-')
75 if (!get_value(expr
->right
, &sval
))
77 if (sval
.value
< 0 || sval
.value
> 4096)
80 param_expr
= get_assigned_expr(expr
->left
);
83 param
= get_param_num(param_expr
);
90 static int get_container_arg(struct symbol
*sym
)
92 struct expression
*__mptr
;
95 if (!sym
|| !sym
->ident
)
98 __mptr
= get_assigned_expr_name_sym(sym
->ident
->name
, sym
);
99 param
= get_param_from_container_of(__mptr
);
104 static int get_container_offset(struct symbol
*sym
)
106 struct expression
*__mptr
;
109 if (!sym
|| !sym
->ident
)
112 __mptr
= get_assigned_expr_name_sym(sym
->ident
->name
, sym
);
113 offset
= get_offset_from_container_of(__mptr
);
118 static char *get_container_name(struct sm_state
*sm
, int offset
)
120 static char buf
[256];
123 name
= get_param_name(sm
);
128 snprintf(buf
, sizeof(buf
), "$(-%d)%s", offset
, name
+ 1);
129 else if (name
[0] == '*' || name
[1] == '$')
130 snprintf(buf
, sizeof(buf
), "*$(-%d)%s", offset
, name
+ 2);
137 static void get_state_hook(int owner
, const char *name
, struct symbol
*sym
)
143 if (__in_fake_assign
)
146 arg
= get_container_arg(sym
);
148 set_state_stree(&used_stree
, my_id
, name
, sym
, &used
);
151 static void set_param_used(struct expression
*call
, struct expression
*arg
, char *key
, char *unused
)
157 name
= get_variable_from_key(arg
, key
, &sym
);
161 arg_nr
= get_container_arg(sym
);
163 set_state(my_id
, name
, sym
, &used
);
168 static void process_states(void)
170 struct sm_state
*tmp
;
174 FOR_EACH_SM(used_stree
, tmp
) {
175 arg
= get_container_arg(tmp
->sym
);
176 offset
= get_container_offset(tmp
->sym
);
177 if (arg
< 0 || offset
< 0)
179 name
= get_container_name(tmp
, offset
);
182 sql_insert_call_implies(PARAM_USED
, arg
, name
, "");
183 } END_FOR_EACH_SM(tmp
);
185 free_stree(&used_stree
);
188 static void match_function_def(struct symbol
*sym
)
190 free_stree(&used_stree
);
193 static void match_save_states(struct expression
*expr
)
195 push_stree(&saved_stack
, used_stree
);
199 static void match_restore_states(struct expression
*expr
)
201 free_stree(&used_stree
);
202 used_stree
= pop_stree(&saved_stack
);
205 static void print_returns_container_of(int return_id
, char *return_ranges
, struct expression
*expr
)
212 param
= get_param_from_container_of(expr
);
215 offset
= get_offset_from_container_of(expr
);
219 snprintf(key
, sizeof(key
), "%d", param
);
220 snprintf(value
, sizeof(value
), "-%d", offset
);
222 sql_insert_return_states(return_id
, return_ranges
, CONTAINER
, -1,
226 static void returns_container_of(struct expression
*expr
, int param
, char *key
, char *value
)
228 struct expression
*call
, *arg
;
232 if (expr
->type
!= EXPR_ASSIGNMENT
|| expr
->op
!= '=')
234 call
= strip_expr(expr
->right
);
235 if (call
->type
!= EXPR_CALL
)
240 offset
= atoi(value
);
242 arg
= get_argument_from_call_expr(call
->args
, param
);
245 if (arg
->type
!= EXPR_SYMBOL
)
247 param
= get_param_num(arg
);
250 snprintf(buf
, sizeof(buf
), "$(%d)", offset
);
251 sql_insert_call_implies(PARAM_USED
, param
, buf
, "");
254 void register_container_of(int id
)
258 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
260 add_get_state_hook(&get_state_hook
);
262 add_hook(&match_save_states
, INLINE_FN_START
);
263 add_hook(&match_restore_states
, INLINE_FN_END
);
265 select_call_implies_hook(PARAM_USED
, &set_param_used
);
266 all_return_states_hook(&process_states
);
268 add_split_return_callback(&print_returns_container_of
);
269 select_return_states_hook(CONTAINER
, &returns_container_of
);