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
;
65 type
= get_type(expr
);
66 if (!type
|| type
->type
!= SYM_PTR
)
69 expr
= strip_expr(expr
);
70 if (expr
->type
!= EXPR_BINOP
|| expr
->op
!= '-')
73 if (!get_value(expr
->right
, &sval
))
75 if (sval
.value
< 0 || sval
.value
> 4096)
78 param_expr
= get_assigned_expr(expr
->left
);
85 static int get_container_arg(struct symbol
*sym
)
87 struct expression
*__mptr
;
90 if (!sym
|| !sym
->ident
)
93 __mptr
= get_assigned_expr_name_sym(sym
->ident
->name
, sym
);
94 param
= get_param_from_container_of(__mptr
);
99 static int get_container_offset(struct symbol
*sym
)
101 struct expression
*__mptr
;
104 if (!sym
|| !sym
->ident
)
107 __mptr
= get_assigned_expr_name_sym(sym
->ident
->name
, sym
);
108 offset
= get_offset_from_container_of(__mptr
);
113 static char *get_container_name(struct sm_state
*sm
, int offset
)
115 static char buf
[256];
118 name
= get_param_name(sm
);
123 snprintf(buf
, sizeof(buf
), "$(-%d)%s", offset
, name
+ 1);
124 else if (name
[0] == '*' || name
[1] == '$')
125 snprintf(buf
, sizeof(buf
), "*$(-%d)%s", offset
, name
+ 2);
132 static void get_state_hook(int owner
, const char *name
, struct symbol
*sym
)
138 if (__in_fake_assign
)
141 arg
= get_container_arg(sym
);
143 set_state_stree(&used_stree
, my_id
, name
, sym
, &used
);
146 static void set_param_used(struct expression
*call
, struct expression
*arg
, char *key
, char *unused
)
152 name
= get_variable_from_key(arg
, key
, &sym
);
156 arg_nr
= get_container_arg(sym
);
158 set_state(my_id
, name
, sym
, &used
);
163 static void process_states(void)
165 struct sm_state
*tmp
;
169 FOR_EACH_SM(used_stree
, tmp
) {
170 arg
= get_container_arg(tmp
->sym
);
171 offset
= get_container_offset(tmp
->sym
);
172 if (arg
< 0 || offset
< 0)
174 name
= get_container_name(tmp
, offset
);
177 sql_insert_call_implies(CONTAINER
, arg
, name
, "");
178 } END_FOR_EACH_SM(tmp
);
180 free_stree(&used_stree
);
183 static void match_function_def(struct symbol
*sym
)
185 free_stree(&used_stree
);
188 static void match_save_states(struct expression
*expr
)
190 push_stree(&saved_stack
, used_stree
);
194 static void match_restore_states(struct expression
*expr
)
196 free_stree(&used_stree
);
197 used_stree
= pop_stree(&saved_stack
);
200 static void print_returns_container_of(int return_id
, char *return_ranges
, struct expression
*expr
)
207 param
= get_param_from_container_of(expr
);
210 offset
= get_offset_from_container_of(expr
);
214 snprintf(key
, sizeof(key
), "%d", param
);
215 snprintf(value
, sizeof(value
), "-%d", offset
);
217 /* no need to add it to call_implies because it's not really param_used */
218 sql_insert_return_states(return_id
, return_ranges
, CONTAINER
, -1,
222 static void returns_container_of(struct expression
*expr
, int param
, char *key
, char *value
)
224 struct expression
*call
, *arg
;
228 if (expr
->type
!= EXPR_ASSIGNMENT
|| expr
->op
!= '=')
230 call
= strip_expr(expr
->right
);
231 if (call
->type
!= EXPR_CALL
)
236 offset
= atoi(value
);
238 arg
= get_argument_from_call_expr(call
->args
, param
);
241 if (arg
->type
!= EXPR_SYMBOL
)
243 param
= get_param_num(arg
);
246 snprintf(buf
, sizeof(buf
), "$(%d)", offset
);
247 sql_insert_call_implies(CONTAINER
, param
, buf
, "");
250 void register_container_of(int id
)
254 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
256 add_get_state_hook(&get_state_hook
);
258 add_hook(&match_save_states
, INLINE_FN_START
);
259 add_hook(&match_restore_states
, INLINE_FN_END
);
261 select_call_implies_hook(CONTAINER
, &set_param_used
);
262 all_return_states_hook(&process_states
);
264 add_split_return_callback(&print_returns_container_of
);
265 select_return_states_hook(CONTAINER
, &returns_container_of
);