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 if (is_fake_var(expr
->left
) || __in_fake_assign
)
92 left
= strip_expr(expr
->left
);
93 if (is_local_variable(left
))
95 right_sym
= expr_to_sym(expr
->right
);
99 param
= get_param_num_from_sym(right_sym
);
102 // FIXME: modify param_has_filter_data() to take a name/sym
103 if (!expr_to_mtag_offset(left
, &tag
, &offset
))
105 name
= expr_to_str(left
);
108 set_state_expr(my_id
, expr
->right
, alloc_tag_data_state(tag
, name
, offset
));
112 static void propogate_assignment(struct expression
*expr
, mtag_t tag
, int offset
, int param
, char *key
)
114 struct expression
*arg
;
120 arg
= get_argument_from_call_expr(expr
->args
, param
);
123 name
= get_variable_from_key(arg
, key
, &sym
);
127 orig_param
= get_param_num_from_sym(sym
);
131 snprintf(buf
, sizeof(buf
), "$->[%d]", offset
);
132 set_state(my_id
, name
, sym
, alloc_tag_data_state(tag
, buf
, offset
));
137 static void assign_to_alias(struct expression
*expr
, int param
, mtag_t tag
, int offset
, char *key
)
139 struct expression
*arg
, *gen_expr
;
140 struct range_list
*rl
;
145 arg
= get_argument_from_call_expr(expr
->args
, param
);
149 gen_expr
= gen_expression_from_key(arg
, key
);
153 get_absolute_rl(gen_expr
, &rl
);
155 if (!create_mtag_alias(tag
, expr
, &alias
))
158 // insert_mtag_data(alias, offset, rl);
160 // FIXME: is arg_offset handled correctly?
161 if (expr_to_mtag_offset(gen_expr
, &arg_tag
, &arg_offset
) &&
162 arg_offset
< MTAG_OFFSET_MASK
)
163 sql_insert_mtag_map(alias
, offset
, arg_tag
, arg_offset
);
166 static void call_does_mtag_assign(struct expression
*expr
, int param
, char *key
, char *value
)
172 while (expr
->type
== EXPR_ASSIGNMENT
)
173 expr
= strip_expr(expr
->right
);
174 if (expr
->type
!= EXPR_CALL
)
177 tag
= strtoul(value
, NULL
, 10);
178 p
= strchr(value
, '+');
181 offset
= atoi(p
+ 1);
183 // save_mtag_to_map(expr, tag, offset, param, key, value);
184 propogate_assignment(expr
, tag
, offset
, param
, key
);
185 assign_to_alias(expr
, param
, tag
, offset
, key
);
188 static void print_stored_to_mtag(int return_id
, char *return_ranges
, struct expression
*expr
)
191 struct tag_assign_info
*data
;
193 const char *param_name
;
196 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
197 if (!sm
->state
->data
)
200 param
= get_param_num_from_sym(sm
->sym
);
203 param_name
= get_param_name(sm
);
207 data
= sm
->state
->data
;
208 snprintf(buf
, sizeof(buf
), "%lld+%d", data
->tag
, data
->offset
);
209 sql_insert_return_states(return_id
, return_ranges
, MTAG_ASSIGN
, param
, param_name
, buf
);
210 } END_FOR_EACH_SM(sm
);
213 void register_param_to_mtag_data(int id
)
217 set_dynamic_states(my_id
);
218 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
219 select_return_states_hook(MTAG_ASSIGN
, &call_does_mtag_assign
);
220 add_merge_hook(my_id
, &merge_tag_info
);
221 add_split_return_callback(&print_stored_to_mtag
);