2 * Copyright 2024 Linaro Ltd.
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_extra.h"
20 #include "smatch_slist.h"
27 static struct smatch_state
*get_opposite(struct smatch_state
*state
)
36 static struct stree
*start_states
;
38 static void set_start_state(const char *name
, struct smatch_state
*start
)
40 struct smatch_state
*orig
;
45 if (get_state(my_id
, name
, NULL
))
48 orig
= get_state_stree(start_states
, my_id
, name
, NULL
);
50 set_state_stree(&start_states
, my_id
, name
, NULL
, start
);
51 else if (orig
!= start
)
52 set_state_stree(&start_states
, my_id
, name
, NULL
, &undefined
);
55 static struct smatch_state
*get_start_state(struct sm_state
*sm
)
57 struct smatch_state
*orig
;
62 orig
= get_state_stree(start_states
, my_id
, sm
->name
, sm
->sym
);
68 static void update_state(const char *member
, struct smatch_state
*state
)
70 set_start_state(member
, get_opposite(state
));
71 set_state(my_id
, member
, NULL
, state
);
74 static void update_expr(struct expression
*expr
, struct smatch_state
*state
)
80 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
81 expr
= strip_expr(expr
->unop
);
83 member
= get_member_name(expr
);
87 update_state(member
, state
);
90 static void lock_hook(struct lock_info
*info
, struct expression
*expr
, const char *name
, struct symbol
*sym
)
92 update_expr(expr
, &lock
);
95 static void unlock_hook(struct lock_info
*info
, struct expression
*expr
, const char *name
, struct symbol
*sym
)
97 update_expr(expr
, &unlock
);
100 bool locking_type_is_start_state(void)
106 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
109 if (sm
->state
!= get_start_state(sm
))
111 } END_FOR_EACH_SM(sm
);
116 static int get_db_type(struct sm_state
*sm
)
118 if (sm
->state
== &lock
)
120 if (sm
->state
== &unlock
)
126 static bool is_clean_transition(struct sm_state
*sm
)
128 struct smatch_state
*start
;
130 start
= get_start_state(sm
);
133 if (start
== get_opposite(sm
->state
))
138 static void match_return_info(int return_id
, char *return_ranges
, struct expression
*expr
)
143 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
144 type
= get_db_type(sm
);
146 sm_msg("%s: type=%d sm='%s' clean=%d", __func__
,
147 type
, show_sm(sm
), is_clean_transition(sm
));
151 if (!is_clean_transition(sm
))
154 sql_insert_return_states(return_id
, return_ranges
, type
,
156 } END_FOR_EACH_SM(sm
);
159 static void db_param_locked(struct expression
*expr
, int param
, char *key
, char *value
)
161 while (expr
&& expr
->type
== EXPR_ASSIGNMENT
)
162 expr
= strip_expr(expr
->right
);
163 if (expr
&& expr
->type
== EXPR_CALL
&& is_locking_primitive_expr(expr
->fn
))
166 update_state(key
, &lock
);
169 static void db_param_unlocked(struct expression
*expr
, int param
, char *key
, char *value
)
171 while (expr
&& expr
->type
== EXPR_ASSIGNMENT
)
172 expr
= strip_expr(expr
->right
);
173 if (expr
&& expr
->type
== EXPR_CALL
&& is_locking_primitive_expr(expr
->fn
))
176 update_state(key
, &unlock
);
179 void register_locking_type(int id
)
183 add_function_data((unsigned long *)&start_states
);
185 add_lock_hook(&lock_hook
);
186 add_unlock_hook(&unlock_hook
);
187 add_restore_hook(&unlock_hook
);
189 select_return_states_hook(TYPE_LOCK2
, &db_param_locked
);
190 select_return_states_hook(TYPE_UNLOCK2
, &db_param_unlocked
);
192 add_split_return_callback(match_return_info
);