2 * Copyright (C) 2014 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_extra.h"
27 DECLARE_PTR_LIST(state_stack
, struct smatch_state
);
28 struct state_stack
*state_at_start
;
30 static int readl_has_been_called
;
33 static int is_readl_call(struct expression
*expr
)
37 expr
= strip_expr(expr
);
38 if (expr
->type
!= EXPR_CALL
)
40 if (expr
->fn
->type
!= EXPR_SYMBOL
)
42 sym
= expr
->fn
->symbol
;
43 if (!sym
|| !sym
->ident
)
45 if (strcmp(sym
->ident
->name
, "readl") != 0)
50 static int is_readl(struct expression
*expr
)
52 if (is_readl_call(expr
))
54 if (get_state_expr(my_id
, expr
) == &readl
)
59 static void match_assign(struct expression
*expr
)
61 if (is_readl(expr
->right
))
62 set_state_expr(my_id
, expr
->left
, &readl
);
63 else if (get_state_expr(my_id
, expr
->left
))
64 set_state_expr(my_id
, expr
->left
, &undefined
);
67 static int condition_depends_on_readl(struct expression
*expr
)
69 if (expr
->type
== EXPR_BINOP
) {
70 if (condition_depends_on_readl(expr
->left
))
72 if (condition_depends_on_readl(expr
->right
))
81 static void check_condition(struct expression
*expr
)
85 if (!condition_depends_on_readl(expr
))
87 readl_has_been_called
= 1;
88 set_true_false_states(my_id
, "depends on", NULL
, &readl_ff
, &readl_00
);
91 static void match_return(struct expression
*expr
)
98 struct smatch_state
*tmp
;
100 if (!readl_has_been_called
)
103 FOR_EACH_PTR(state_at_start
, tmp
) {
104 REPLACE_CURRENT_PTR(tmp
, NULL
);
109 static void push_state_at_start(struct smatch_state
*state
)
111 add_ptr_list(&state_at_start
, state
);
114 static struct smatch_state
*pop_state_at_start(void)
116 struct smatch_state
*state
;
118 state
= last_ptr_list((struct ptr_list
*)state_at_start
);
119 delete_ptr_list_last((struct ptr_list
**)&state_at_start
);
123 static void before_loop(struct statement
*stmt
)
125 struct smatch_state
*state
;
127 if (!stmt
|| stmt
->type
!= STMT_ITERATOR
)
129 if (ptr_list_empty(state_at_start
))
131 state
= get_state(my_id
, "depends on", NULL
);
132 push_state_at_start(state
);
135 static void after_loop(struct statement
*stmt
)
137 struct smatch_state
*old_state
;
139 if (!stmt
|| stmt
->type
!= STMT_ITERATOR
)
141 old_state
= pop_state_at_start();
142 if (old_state
== &readl_00
)
146 if (get_state(my_id
, "depends on", NULL
) != &readl_00
)
148 sm_msg("warn: this loop depends on readl() succeeding");
151 void check_readl_infinite_loops(int id
)
153 if (option_project
!= PROJ_KERNEL
)
158 add_hook(match_assign
, ASSIGNMENT_HOOK
);
159 add_hook(check_condition
, CONDITION_HOOK
);
161 add_hook(&match_return
, RETURN_HOOK
);
163 add_hook(before_loop
, STMT_HOOK
);
164 add_hook(after_loop
, STMT_HOOK_AFTER
);