db/kernel.return_fixes: add more guard lock annotations
[smatch.git] / smatch_kernel_irq_context.c
blob55dc145aab0796af7f4e0020787a279f80ab8463
1 /*
2 * Copyright 2023 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
18 #include "smatch.h"
19 #include "smatch_slist.h"
21 static int my_id;
23 bool in_irq_context(void)
25 if (has_possible_state(my_id, "irq_context", NULL, &true_state))
26 return true;
27 return false;
30 void clear_irq_context(void)
32 struct smatch_state *state;
34 state = get_state(my_id, "irq_context", NULL);
35 if (!state)
36 return;
37 set_state(my_id, "irq_context", NULL, &undefined);
40 static int db_set_irq(void *_found, int argc, char **argv, char **azColName)
42 int *found = _found;
43 *found = true;
44 return 0;
47 static void match_declaration(struct symbol *sym)
49 int found = 0;
51 run_sql(db_set_irq, &found,
52 "select * from fn_data_link where file = 0x%llx and function = '%s' and static = %d and type = %d;",
53 (cur_func_sym->ctype.modifiers & MOD_STATIC) ? get_base_file_id() : 0,
54 cur_func_sym->ident->name,
55 !!(cur_func_sym->ctype.modifiers & MOD_STATIC),
56 IRQ_CONTEXT);
58 if (!found)
59 return;
61 set_state(my_id, "irq_context", NULL, &true_state);
64 static void match_request_irq(struct expression *expr, const char *name, struct symbol *sym, void *data)
66 struct expression *handler;
67 sval_t sval = int_zero;
69 while (expr && expr->type == EXPR_ASSIGNMENT)
70 expr = strip_expr(expr->right);
71 if (!expr || expr->type != EXPR_CALL)
72 return;
74 handler = get_argument_from_call_expr(expr->args, 1);
75 if (!get_implied_value(handler, &sval))
76 return;
78 sql_insert_fn_data_link(handler, IRQ_CONTEXT, -1, "", "");
81 static void match_request_threaded_irq(struct expression *expr, const char *name, struct symbol *sym, void *data)
83 struct expression *thread;
85 while (expr && expr->type == EXPR_ASSIGNMENT)
86 expr = strip_expr(expr->right);
87 if (!expr || expr->type != EXPR_CALL)
88 return;
90 thread = get_argument_from_call_expr(expr->args, 2);
91 if (!expr_is_zero(thread))
92 return;
93 if (get_function() && strcmp(get_function(), "request_irq") == 0)
94 return;
96 sm_warning("why call request_threaded_irq() with a NULL thread");
99 static void match_in_irq(struct expression *expr)
101 char *macro = get_macro_name(expr->pos);
103 if (!macro || strcmp(macro, "in_irq") != 0)
104 return;
105 set_true_false_states(my_id, "irq_context", NULL, NULL, &undefined);
108 static bool is_ignored_fn(struct expression *expr)
110 char *fn;
111 bool ret = false;
113 fn = get_fnptr_name(expr->fn);
114 if (!fn)
115 return false;
117 if (strcmp(fn, "bus_for_each_drv") == 0 ||
118 strcmp(fn, "call_mmap") == 0 ||
119 strcmp(fn, "(struct comedi_subdevice)->cancel") == 0 ||
120 strcmp(fn, "(struct flexcop_device)->read_ibi_reg") == 0 ||
121 strcmp(fn, "(struct spi_message)->complete") == 0 ||
122 strcmp(fn, "(struct usb_gadget_driver)->setup") == 0 ||
123 strcmp(fn, "(struct v4l2_subdev_core_ops)->interrupt_service_routine") == 0 ||
124 strcmp(fn, "call_mmap") == 0)
125 ret = true;
127 free_string(fn);
128 return ret;
131 static void match_call_info(struct expression *expr)
133 if (!in_irq_context())
134 return;
136 if (is_ignored_fn(expr))
137 return;
139 sql_insert_caller_info(expr, IRQ_CONTEXT, -1, "", "");
142 static void select_call_info(const char *name, struct symbol *sym, char *key, char *value)
144 set_state(my_id, "irq_context", NULL, &true_state);
147 void register_kernel_irq_context(int id)
149 if (option_project != PROJ_KERNEL)
150 return;
152 my_id = id;
154 add_function_param_key_hook("request_irq", &match_request_irq, 1, "$", NULL);
155 add_function_param_key_hook("request_threaded_irq", &match_request_threaded_irq, 1, "$", NULL);
156 add_hook(&match_in_irq, CONDITION_HOOK);
158 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
159 select_caller_info_hook(&select_call_info, IRQ_CONTEXT);
160 add_hook(&match_declaration, DECLARATION_HOOK);