helper: cache get_member_name()
[smatch.git] / smatch_kernel_irq_context.c
blob56c6036197f8ed1ea80abea0bb5ef8668bef920d
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 bool is_irq_handler(void)
49 int found = 0;
51 if (!cur_func_sym)
52 return false;
54 run_sql(db_set_irq, &found,
55 "select * from fn_data_link where file = 0x%llx and function = '%s' and static = %d and type = %d;",
56 (cur_func_sym->ctype.modifiers & MOD_STATIC) ? get_base_file_id() : 0,
57 cur_func_sym->ident->name,
58 !!(cur_func_sym->ctype.modifiers & MOD_STATIC),
59 IRQ_CONTEXT);
61 return found;
64 static void match_declaration(struct symbol *sym)
66 if (!is_irq_handler())
67 return;
69 set_state(my_id, "irq_context", NULL, &true_state);
72 static void match_request_irq(struct expression *expr, const char *name, struct symbol *sym, void *data)
74 struct expression *handler;
75 sval_t sval = int_zero;
77 while (expr && expr->type == EXPR_ASSIGNMENT)
78 expr = strip_expr(expr->right);
79 if (!expr || expr->type != EXPR_CALL)
80 return;
82 handler = get_argument_from_call_expr(expr->args, 1);
83 if (!get_implied_value(handler, &sval))
84 return;
86 sql_insert_fn_data_link(handler, IRQ_CONTEXT, -1, "", "");
89 static void match_request_threaded_irq(struct expression *expr, const char *name, struct symbol *sym, void *data)
91 struct expression *thread;
93 while (expr && expr->type == EXPR_ASSIGNMENT)
94 expr = strip_expr(expr->right);
95 if (!expr || expr->type != EXPR_CALL)
96 return;
98 thread = get_argument_from_call_expr(expr->args, 2);
99 if (!expr_is_zero(thread))
100 return;
101 if (get_function() && strcmp(get_function(), "request_irq") == 0)
102 return;
104 sm_warning("why call request_threaded_irq() with a NULL thread");
107 static void match_in_irq(struct expression *expr)
109 char *macro = get_macro_name(expr->pos);
111 if (!macro || strcmp(macro, "in_irq") != 0)
112 return;
113 set_true_false_states(my_id, "irq_context", NULL, NULL, &undefined);
116 static bool is_ignored_fn(struct expression *expr)
118 char *fn;
119 bool ret = false;
121 fn = get_fnptr_name(expr->fn);
122 if (!fn)
123 return false;
125 if (strcmp(fn, "bus_for_each_drv") == 0 ||
126 strcmp(fn, "call_mmap") == 0 ||
127 strcmp(fn, "(struct comedi_subdevice)->cancel") == 0 ||
128 strcmp(fn, "(struct flexcop_device)->read_ibi_reg") == 0 ||
129 strcmp(fn, "(struct irqaction)->handler") == 0 || /* called from __handle_irq_event_percpu() */
130 strcmp(fn, "(struct spi_message)->complete") == 0 ||
131 strcmp(fn, "(struct usb_gadget_driver)->setup") == 0 ||
132 strcmp(fn, "(struct v4l2_subdev_core_ops)->interrupt_service_routine") == 0 ||
133 strcmp(fn, "call_mmap") == 0)
134 ret = true;
136 free_string(fn);
137 return ret;
140 static void match_call_info(struct expression *expr)
142 if (!in_irq_context())
143 return;
145 if (is_ignored_fn(expr))
146 return;
148 sql_insert_caller_info(expr, IRQ_CONTEXT, -1, "", is_irq_handler() ? "<- IRQ handler" : "");
151 static void select_call_info(const char *name, struct symbol *sym, char *key, char *value)
153 set_state(my_id, "irq_context", NULL, &true_state);
156 void register_kernel_irq_context(int id)
158 if (option_project != PROJ_KERNEL)
159 return;
161 my_id = id;
163 add_function_param_key_hook("request_irq", &match_request_irq, 1, "$", NULL);
164 add_function_param_key_hook("request_threaded_irq", &match_request_threaded_irq, 1, "$", NULL);
165 add_hook(&match_in_irq, CONDITION_HOOK);
167 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
168 select_caller_info_hook(&select_call_info, IRQ_CONTEXT);
169 add_hook(&match_declaration, DECLARATION_HOOK);