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
{
52 ALLOCATOR(tag_assign_info
, "tag name offset");
54 static struct smatch_state
*alloc_tag_data_state(mtag_t tag
, char *data_name
, int offset
, int param
)
56 struct smatch_state
*state
;
57 struct tag_assign_info
*data
;
59 data
= __alloc_tag_assign_info(0);
61 data
->offset
= offset
;
64 state
= __alloc_smatch_state(0);
65 state
->name
= alloc_sname(data_name
);
70 struct smatch_state
*merge_tag_info(struct smatch_state
*s1
, struct smatch_state
*s2
)
72 /* Basically ignore undefined states */
81 static void match_assign(struct expression
*expr
)
83 struct expression
*left
, *right
;
91 left
= strip_expr(expr
->left
);
92 right
= strip_expr(expr
->right
);
94 if (right
->type
!= EXPR_SYMBOL
)
96 param
= get_param_num_from_sym(right
->symbol
);
99 // FIXME: modify param_has_filter_data() to take a name/sym
100 if (!expr_to_mtag_name_offset(left
, &tag
, &data_name
, &offset
))
102 set_state_expr(my_id
, left
, alloc_tag_data_state(tag
, data_name
, offset
, param
));
105 static int propogate_assignment(struct expression
*expr
, int param
, mtag_t tag
, int offset
)
107 struct expression
*arg
;
111 arg
= get_argument_from_call_expr(expr
->args
, param
);
114 if (arg
->type
!= EXPR_SYMBOL
)
116 orig_param
= get_param_num_from_sym(arg
->symbol
);
119 snprintf(buf
, sizeof(buf
), "$->[%d]", offset
);
120 set_state_expr(my_id
, arg
, alloc_tag_data_state(tag
, buf
, offset
, orig_param
));
124 static void assign_to_alias(struct expression
*expr
, int param
, mtag_t tag
, int offset
)
126 struct expression
*arg
;
127 struct range_list
*rl
;
131 arg
= get_argument_from_call_expr(expr
->args
, param
);
134 get_absolute_rl(arg
, &rl
);
136 if (!create_mtag_alias(tag
, expr
, &alias
))
139 insert_mtag_data(alias
, "", offset
, rl
);
141 if (get_mtag(arg
, &arg_tag
))
142 sql_insert_mtag_map(arg_tag
, -offset
, alias
);
145 static void call_does_mtag_assign(struct expression
*expr
, int param
, char *key
, char *value
)
151 while (expr
->type
== EXPR_ASSIGNMENT
)
152 expr
= strip_expr(expr
->right
);
153 if (expr
->type
!= EXPR_CALL
)
156 tag
= strtoul(value
, NULL
, 10);
157 p
= strchr(value
, '+');
160 offset
= atoi(p
+ 1);
162 if (propogate_assignment(expr
, param
, tag
, offset
))
165 assign_to_alias(expr
, param
, tag
, offset
);
168 static void print_stored_to_mtag(int return_id
, char *return_ranges
, struct expression
*expr
)
170 struct sm_state
*tmp
;
171 struct tag_assign_info
*data
;
174 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), tmp
) {
175 if (!tmp
->state
->data
)
177 data
= tmp
->state
->data
;
178 snprintf(buf
, sizeof(buf
), "%lld+%d", data
->tag
, data
->offset
);
179 sql_insert_return_states(return_id
, return_ranges
, MTAG_ASSIGN
, data
->param
, "$", buf
);
180 } END_FOR_EACH_SM(tmp
);
183 void register_param_to_mtag_data(int id
)
187 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
188 select_return_states_hook(MTAG_ASSIGN
, &call_does_mtag_assign
);
189 add_merge_hook(my_id
, &merge_tag_info
);
190 add_split_return_callback(&print_stored_to_mtag
);