2 * Copyright (C) 2017 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 * Take a look at request_threaded_irq(). It takes thread_fn and dev_id. Then
22 * action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
23 * action->thread_fn = thread_fn;
24 * action->dev_id = dev_id;
26 * It doesn't ever pass action back to the higher levels, but instead registers
27 * it with the lower levels.
29 * The kzalloc() allocation creates a new mtag. We don't know at this point
30 * what "thread_fn" and "dev_id" are because they come from many different
33 * So what we do is we pass the information back to the callers that thread_fn
34 * and dev_id are stored as a specific mtag data. Then when the callers *do*
35 * know what values are passed they create an mtag_alias. An mtag_alias is a
36 * many to one relationship. Then they store that in mtag_data using the
42 #include "smatch_extra.h"
43 #include "smatch_slist.h"
47 struct tag_assign_info
{
51 ALLOCATOR(tag_assign_info
, "tag name offset");
53 static struct smatch_state
*alloc_tag_data_state(mtag_t tag
, char *name
, int offset
)
55 struct smatch_state
*state
;
56 struct tag_assign_info
*data
;
58 data
= __alloc_tag_assign_info(0);
60 data
->offset
= offset
;
62 state
= __alloc_smatch_state(0);
63 state
->name
= alloc_sname(name
);
68 struct smatch_state
*merge_tag_info(struct smatch_state
*s1
, struct smatch_state
*s2
)
70 /* Basically ignore undefined states */
79 static void match_assign(struct expression
*expr
)
81 struct expression
*left
;
82 struct symbol
*right_sym
;
90 left
= strip_expr(expr
->left
);
91 right_sym
= expr_to_sym(expr
->right
);
95 param
= get_param_num_from_sym(right_sym
);
98 // FIXME: modify param_has_filter_data() to take a name/sym
99 if (!expr_to_mtag_offset(left
, &tag
, &offset
))
101 name
= expr_to_str(left
);
104 set_state_expr(my_id
, expr
->right
, alloc_tag_data_state(tag
, name
, offset
));
109 static void save_mtag_to_map(struct expression
*expr
, mtag_t tag
, int offset
, int param
, char *key
, char *value
)
111 struct expression
*arg
, *gen_expr
;
114 arg
= get_argument_from_call_expr(expr
->args
, param
);
118 gen_expr
= gen_expression_from_key(arg
, key
);
122 if (!get_mtag(gen_expr
, &arg_tag
))
126 sm_msg("finding mtag for '%s' %lld", expr_to_str(gen_expr
), arg_tag
);
130 static void propogate_assignment(struct expression
*expr
, mtag_t tag
, int offset
, int param
, char *key
)
132 struct expression
*arg
;
138 arg
= get_argument_from_call_expr(expr
->args
, param
);
141 name
= get_variable_from_key(arg
, key
, &sym
);
145 orig_param
= get_param_num_from_sym(sym
);
149 snprintf(buf
, sizeof(buf
), "$->[%d]", offset
);
150 set_state(my_id
, name
, sym
, alloc_tag_data_state(tag
, buf
, offset
));
155 static void assign_to_alias(struct expression
*expr
, int param
, mtag_t tag
, int offset
, char *key
)
157 struct expression
*arg
, *gen_expr
;
158 struct range_list
*rl
;
162 arg
= get_argument_from_call_expr(expr
->args
, param
);
166 gen_expr
= gen_expression_from_key(arg
, key
);
170 get_absolute_rl(gen_expr
, &rl
);
172 if (!create_mtag_alias(tag
, expr
, &alias
))
175 // insert_mtag_data(alias, offset, rl);
177 if (get_mtag(gen_expr
, &arg_tag
))
178 sql_insert_mtag_map(arg_tag
, -offset
, alias
);
181 static void call_does_mtag_assign(struct expression
*expr
, int param
, char *key
, char *value
)
187 while (expr
->type
== EXPR_ASSIGNMENT
)
188 expr
= strip_expr(expr
->right
);
189 if (expr
->type
!= EXPR_CALL
)
192 tag
= strtoul(value
, NULL
, 10);
193 p
= strchr(value
, '+');
196 offset
= atoi(p
+ 1);
198 // save_mtag_to_map(expr, tag, offset, param, key, value);
199 propogate_assignment(expr
, tag
, offset
, param
, key
);
200 assign_to_alias(expr
, param
, tag
, offset
, key
);
203 static void print_stored_to_mtag(int return_id
, char *return_ranges
, struct expression
*expr
)
206 struct tag_assign_info
*data
;
208 const char *param_name
;
211 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
212 if (!sm
->state
->data
)
215 param
= get_param_num_from_sym(sm
->sym
);
218 param_name
= get_param_name(sm
);
222 data
= sm
->state
->data
;
223 snprintf(buf
, sizeof(buf
), "%lld+%d", data
->tag
, data
->offset
);
224 sql_insert_return_states(return_id
, return_ranges
, MTAG_ASSIGN
, param
, param_name
, buf
);
225 } END_FOR_EACH_SM(sm
);
228 void register_param_to_mtag_data(int id
)
232 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
233 select_return_states_hook(MTAG_ASSIGN
, &call_does_mtag_assign
);
234 add_merge_hook(my_id
, &merge_tag_info
);
235 add_split_return_callback(&print_stored_to_mtag
);