#include "smatch.h"
#include "smatch_extra.h"
#include "smatch_slist.h"
static int my_id;
struct tag_assign_info {
mtag_t tag;
int offset;
};
ALLOCATOR(tag_assign_info, "tag name offset");
static struct smatch_state *alloc_tag_data_state(mtag_t tag, char *name, int offset)
{
struct smatch_state *state;
struct tag_assign_info *data;
data = __alloc_tag_assign_info(0);
data->tag = tag;
data->offset = offset;
state = __alloc_smatch_state(0);
state->name = alloc_sname(name);
state->data = data;
return state;
}
struct smatch_state *merge_tag_info(struct smatch_state *s1, struct smatch_state *s2)
{
if (s1 == &undefined)
return s2;
if (s2 == &undefined)
return s1;
return &merged;
}
static void match_assign(struct expression *expr)
{
struct expression *left;
struct symbol *right_sym;
char *name;
mtag_t tag;
int offset;
int param;
if (expr->op != '=')
return;
left = strip_expr(expr->left);
if (is_local_variable(left))
return;
right_sym = expr_to_sym(expr->right);
if (!right_sym)
return;
param = get_param_num_from_sym(right_sym);
if (param < 0)
return;
if (!expr_to_mtag_offset(left, &tag, &offset))
return;
name = expr_to_str(left);
if (!name)
return;
set_state_expr(my_id, expr->right, alloc_tag_data_state(tag, name, offset));
free_string(name);
}
static void propogate_assignment(struct expression *expr, mtag_t tag, int offset, int param, char *key)
{
struct expression *arg;
int orig_param;
char buf[32];
char *name;
struct symbol *sym;
arg = get_argument_from_call_expr(expr->args, param);
if (!arg)
return;
name = get_variable_from_key(arg, key, &sym);
if (!name || !sym)
goto free;
orig_param = get_param_num_from_sym(sym);
if (orig_param < 0)
goto free;
snprintf(buf, sizeof(buf), "$->[%d]", offset);
set_state(my_id, name, sym, alloc_tag_data_state(tag, buf, offset));
free:
free_string(name);
}
static void assign_to_alias(struct expression *expr, int param, mtag_t tag, int offset, char *key)
{
struct expression *arg, *gen_expr;
struct range_list *rl;
mtag_t arg_tag;
mtag_t alias;
int arg_offset;
arg = get_argument_from_call_expr(expr->args, param);
if (!arg)
return;
gen_expr = gen_expression_from_key(arg, key);
if (!gen_expr)
return;
get_absolute_rl(gen_expr, &rl);
if (!create_mtag_alias(tag, expr, &alias))
return;
if (expr_to_mtag_offset(gen_expr, &arg_tag, &arg_offset) &&
arg_offset < MTAG_OFFSET_MASK)
sql_insert_mtag_map(alias, offset, arg_tag, arg_offset);
}
static void call_does_mtag_assign(struct expression *expr, int param, char *key, char *value)
{
char *p;
mtag_t tag;
int offset;
while (expr->type == EXPR_ASSIGNMENT)
expr = strip_expr(expr->right);
if (expr->type != EXPR_CALL)
return;
tag = strtoul(value, NULL, 10);
p = strchr(value, '+');
if (!p)
return;
offset = atoi(p + 1);
propogate_assignment(expr, tag, offset, param, key);
assign_to_alias(expr, param, tag, offset, key);
}
static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr)
{
struct sm_state *sm;
struct tag_assign_info *data;
char buf[256];
const char *param_name;
int param;
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
if (!sm->state->data)
continue;
param = get_param_num_from_sym(sm->sym);
if (param < 0)
continue;
param_name = get_param_name(sm);
if (!param_name)
continue;
data = sm->state->data;
snprintf(buf, sizeof(buf), "%lld+%d", data->tag, data->offset);
sql_insert_return_states(return_id, return_ranges, MTAG_ASSIGN, param, param_name, buf);
} END_FOR_EACH_SM(sm);
}
void register_param_to_mtag_data(int id)
{
my_id = id;
set_dynamic_states(my_id);
add_hook(&match_assign, ASSIGNMENT_HOOK);
select_return_states_hook(MTAG_ASSIGN, &call_does_mtag_assign);
add_merge_hook(my_id, &merge_tag_info);
add_split_return_callback(&print_stored_to_mtag);
}