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
19 #include "smatch_slist.h"
23 bool in_irq_context(void)
25 if (has_possible_state(my_id
, "irq_context", NULL
, &true_state
))
30 void clear_irq_context(void)
32 struct smatch_state
*state
;
34 state
= get_state(my_id
, "irq_context", NULL
);
37 set_state(my_id
, "irq_context", NULL
, &undefined
);
40 static int db_set_irq(void *_found
, int argc
, char **argv
, char **azColName
)
47 static void match_declaration(struct symbol
*sym
)
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
),
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
)
74 handler
= get_argument_from_call_expr(expr
->args
, 1);
75 if (!get_implied_value(handler
, &sval
))
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
)
90 thread
= get_argument_from_call_expr(expr
->args
, 2);
91 if (!expr_is_zero(thread
))
93 if (get_function() && strcmp(get_function(), "request_irq") == 0)
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)
105 set_true_false_states(my_id
, "irq_context", NULL
, NULL
, &undefined
);
108 static bool is_ignored_fn(struct expression
*expr
)
113 fn
= get_fnptr_name(expr
->fn
);
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)
131 static void match_call_info(struct expression
*expr
)
133 if (!in_irq_context())
136 if (is_ignored_fn(expr
))
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
)
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
);