#include "smatch.h"
#include "smatch_slist.h"
#include "smatch_extra.h"
static int my_id;
static int link_id;
static struct smatch_state *alloc_my_state(const char *name, struct symbol *sym)
{
struct smatch_state *state;
state = __alloc_smatch_state(0);
state->name = alloc_sname(name);
state->data = sym;
return state;
}
static void undef(struct sm_state *sm, struct expression *mod_expr)
{
if (__in_fake_parameter_assign)
return;
set_state(my_id, sm->name, sm->sym, &undefined);
}
char *map_call_to_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
{
struct smatch_state *state;
int skip;
char buf[256];
skip = sym->ident->len + 2;
state = get_state(my_id, sym->ident->name, sym);
if (!state || !state->data)
return NULL;
snprintf(buf, sizeof(buf), "%s->%s", state->name, name + skip);
*new_sym = state->data;
return alloc_string(buf);
}
static char *map_my_state_long_to_short(struct sm_state *sm, const char *name, struct symbol *sym, struct symbol **new_sym, bool stack)
{
int len;
char buf[256];
if (sm->state->data != sym)
return NULL;
len = strlen(sm->state->name);
if (strncmp(name, sm->state->name, len) != 0)
return NULL;
if (name[len] == '.')
return NULL;
if (!stack && name[len] != '-')
return NULL;
snprintf(buf, sizeof(buf), "%s%s", sm->name, name + len);
*new_sym = sm->sym;
return alloc_string(buf);
}
char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
{
char *ret;
struct sm_state *sm;
*new_sym = NULL;
FOR_EACH_SM(__get_cur_stree(), sm) {
if (sm->owner == my_id) {
ret = map_my_state_long_to_short(sm, name, sym, new_sym, use_stack);
if (ret) {
if (local_debug)
sm_msg("%s: my_state: name = '%s' sm = '%s'",
__func__, name, show_sm(sm));
return ret;
}
continue;
}
} END_FOR_EACH_SM(sm);
return NULL;
}
char *map_call_to_param_name_sym(struct expression *expr, struct symbol **sym)
{
char *name;
struct symbol *start_sym;
struct smatch_state *state;
*sym = NULL;
name = expr_to_str_sym(expr, &start_sym);
if (!name)
return NULL;
if (expr->type == EXPR_CALL)
start_sym = expr_to_sym(expr->fn);
state = get_state(my_id, name, start_sym);
free_string(name);
if (!state || !state->data)
return NULL;
*sym = state->data;
return alloc_string(state->name);
}
static void store_mapping_helper(char *left_name, struct symbol *left_sym, struct expression *call, const char *return_string)
{
const char *p = return_string;
char *close;
int param;
struct expression *arg, *new;
char *right_name;
struct symbol *right_sym;
char buf[256];
while (*p && *p != '[')
p++;
if (!*p)
return;
p++;
if (*p != '$')
return;
snprintf(buf, sizeof(buf), "%s", p);
close = strchr(buf, ']');
if (!close)
return;
*close = '\0';
param = atoi(buf + 1);
arg = get_argument_from_call_expr(call->args, param);
if (!arg)
return;
new = gen_expression_from_key(arg, buf);
if (!new)
return;
right_name = expr_to_var_sym(new, &right_sym);
if (!right_name || !right_sym)
goto free;
set_state(my_id, left_name, left_sym, alloc_my_state(right_name, right_sym));
store_link(link_id, right_name, right_sym, left_name, left_sym);
free:
free_string(right_name);
}
void __add_return_to_param_mapping(struct expression *expr, const char *return_string)
{
struct expression *call;
char *left_name = NULL;
struct symbol *left_sym;
if (expr->type == EXPR_ASSIGNMENT) {
left_name = expr_to_var_sym(expr->left, &left_sym);
if (!left_name || !left_sym)
goto free;
call = strip_expr(expr->right);
if (call->type != EXPR_CALL)
goto free;
store_mapping_helper(left_name, left_sym, call, return_string);
goto free;
}
if (expr->type == EXPR_CALL &&
expr_get_parent_stmt(expr) &&
expr_get_parent_stmt(expr)->type == STMT_RETURN) {
call = strip_expr(expr);
left_sym = expr_to_sym(call->fn);
if (!left_sym)
return;
left_name = expr_to_str(call);
if (!left_name)
return;
store_mapping_helper(left_name, left_sym, call, return_string);
goto free;
}
free:
free_string(left_name);
}
void register_return_to_param(int id)
{
my_id = id;
set_dynamic_states(my_id);
add_modification_hook(my_id, &undef);
}
void register_return_to_param_links(int id)
{
link_id = id;
set_up_link_functions(my_id, link_id);
}