#include "smatch.h"
enum data_type {
NO_DATA,
EXPR_PTR,
STMT_PTR,
SYMBOL_PTR,
SYM_LIST_PTR,
};
struct hook_container {
int hook_type;
int owner;
void *fn;
};
ALLOCATOR(hook_container, "hook functions");
DECLARE_PTR_LIST(hook_func_list, struct hook_container);
typedef void (expr_func)(struct expression *expr);
typedef void (stmt_func)(struct statement *stmt);
typedef void (sym_func)(struct symbol *sym);
typedef void (sym_list_func)(struct symbol_list *sym_list);
static struct hook_func_list *merge_funcs;
static struct hook_func_list *unmatched_state_funcs;
static struct hook_func_list *hook_array[NUM_HOOKS] = {};
static const enum data_type data_types[NUM_HOOKS] = {
[EXPR_HOOK] = EXPR_PTR,
[EXPR_HOOK_AFTER] = EXPR_PTR,
[STMT_HOOK] = STMT_PTR,
[STMT_HOOK_AFTER] = STMT_PTR,
[SYM_HOOK] = EXPR_PTR,
[STRING_HOOK] = EXPR_PTR,
[DECLARATION_HOOK] = SYMBOL_PTR,
[ASSIGNMENT_HOOK] = EXPR_PTR,
[ASSIGNMENT_HOOK_AFTER] = EXPR_PTR,
[RAW_ASSIGNMENT_HOOK] = EXPR_PTR,
[GLOBAL_ASSIGNMENT_HOOK] = EXPR_PTR,
[CALL_ASSIGNMENT_HOOK] = EXPR_PTR,
[MACRO_ASSIGNMENT_HOOK] = EXPR_PTR,
[BINOP_HOOK] = EXPR_PTR,
[OP_HOOK] = EXPR_PTR,
[LOGIC_HOOK] = EXPR_PTR,
[PRELOOP_HOOK] = STMT_PTR,
[CONDITION_HOOK] = EXPR_PTR,
[SELECT_HOOK] = EXPR_PTR,
[WHOLE_CONDITION_HOOK] = EXPR_PTR,
[FUNCTION_CALL_HOOK] = EXPR_PTR,
[CALL_HOOK_AFTER_INLINE] = EXPR_PTR,
[FUNCTION_CALL_HOOK_AFTER_DB] = EXPR_PTR,
[DEREF_HOOK] = EXPR_PTR,
[CASE_HOOK] = NO_DATA,
[ASM_HOOK] = STMT_PTR,
[CAST_HOOK] = EXPR_PTR,
[SIZEOF_HOOK] = EXPR_PTR,
[BASE_HOOK] = SYMBOL_PTR,
[FUNC_DEF_HOOK] = SYMBOL_PTR,
[AFTER_DEF_HOOK] = SYMBOL_PTR,
[END_FUNC_HOOK] = SYMBOL_PTR,
[AFTER_FUNC_HOOK] = SYMBOL_PTR,
[RETURN_HOOK] = EXPR_PTR,
[INLINE_FN_START] = EXPR_PTR,
[INLINE_FN_END] = EXPR_PTR,
[END_FILE_HOOK] = SYM_LIST_PTR,
};
void (**pre_merge_hooks)(struct sm_state *cur, struct sm_state *other);
struct scope_container {
void *fn;
void *data;
};
ALLOCATOR(scope_container, "scope hook functions");
DECLARE_PTR_LIST(scope_hook_list, struct scope_container);
DECLARE_PTR_LIST(scope_hook_stack, struct scope_hook_list);
static struct scope_hook_stack *scope_hooks;
void add_hook(void *func, enum hook_type type)
{
struct hook_container *container = __alloc_hook_container(0);
container->hook_type = type;
container->fn = func;
add_ptr_list(&hook_array[type], container);
}
void add_merge_hook(int client_id, merge_func_t *func)
{
struct hook_container *container = __alloc_hook_container(0);
container->owner = client_id;
container->fn = func;
add_ptr_list(&merge_funcs, container);
}
void add_unmatched_state_hook(int client_id, unmatched_func_t *func)
{
struct hook_container *container = __alloc_hook_container(0);
container->owner = client_id;
container->fn = func;
add_ptr_list(&unmatched_state_funcs, container);
}
void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *cur, struct sm_state *other))
{
pre_merge_hooks[client_id] = hook;
}
static void pass_expr_to_client(void *fn, void *data)
{
((expr_func *)fn)((struct expression *)data);
}
static void pass_stmt_to_client(void *fn, void *data)
{
((stmt_func *)fn)((struct statement *)data);
}
static void pass_sym_to_client(void *fn, void *data)
{
((sym_func *)fn)((struct symbol *)data);
}
static void pass_sym_list_to_client(void *fn, void *data)
{
((sym_list_func *)fn)((struct symbol_list *)data);
}
void __pass_to_client(void *data, enum hook_type type)
{
struct hook_container *container;
FOR_EACH_PTR(hook_array[type], container) {
switch (data_types[type]) {
case EXPR_PTR:
pass_expr_to_client(container->fn, data);
break;
case STMT_PTR:
pass_stmt_to_client(container->fn, data);
break;
case SYMBOL_PTR:
pass_sym_to_client(container->fn, data);
break;
case SYM_LIST_PTR:
pass_sym_list_to_client(container->fn, data);
break;
}
} END_FOR_EACH_PTR(container);
}
void __pass_case_to_client(struct expression *switch_expr,
struct range_list *rl)
{
typedef void (case_func)(struct expression *switch_expr,
struct range_list *rl);
struct hook_container *container;
FOR_EACH_PTR(hook_array[CASE_HOOK], container) {
((case_func *)container->fn)(switch_expr, rl);
} END_FOR_EACH_PTR(container);
}
int __has_merge_function(int client_id)
{
struct hook_container *tmp;
FOR_EACH_PTR(merge_funcs, tmp) {
if (tmp->owner == client_id)
return 1;
} END_FOR_EACH_PTR(tmp);
return 0;
}
struct smatch_state *__client_merge_function(int owner,
struct smatch_state *s1,
struct smatch_state *s2)
{
struct smatch_state *tmp_state;
struct hook_container *tmp;
if (!s2 || (s1 && strcmp(s2->name, s1->name) < 0)) {
tmp_state = s1;
s1 = s2;
s2 = tmp_state;
}
FOR_EACH_PTR(merge_funcs, tmp) {
if (tmp->owner == owner)
return ((merge_func_t *)tmp->fn)(s1, s2);
} END_FOR_EACH_PTR(tmp);
return &undefined;
}
struct smatch_state *__client_unmatched_state_function(struct sm_state *sm)
{
struct hook_container *tmp;
FOR_EACH_PTR(unmatched_state_funcs, tmp) {
if (tmp->owner == sm->owner)
return ((unmatched_func_t *)tmp->fn)(sm);
} END_FOR_EACH_PTR(tmp);
return &undefined;
}
void call_pre_merge_hook(struct sm_state *cur, struct sm_state *other)
{
if (cur->owner >= num_checks)
return;
if (pre_merge_hooks[cur->owner])
pre_merge_hooks[cur->owner](cur, other);
}
static struct scope_hook_list *pop_scope_hook_list(struct scope_hook_stack **stack)
{
struct scope_hook_list *hook_list;
hook_list = last_ptr_list((struct ptr_list *)*stack);
delete_ptr_list_last((struct ptr_list **)stack);
return hook_list;
}
static void push_scope_hook_list(struct scope_hook_stack **stack, struct scope_hook_list *l)
{
add_ptr_list(stack, l);
}
void add_scope_hook(scope_hook *fn, void *data)
{
struct scope_hook_list *hook_list;
struct scope_container *new;
if (!scope_hooks)
return;
hook_list = pop_scope_hook_list(&scope_hooks);
new = __alloc_scope_container(0);
new->fn = fn;
new->data = data;
add_ptr_list(&hook_list, new);
push_scope_hook_list(&scope_hooks, hook_list);
}
void __push_scope_hooks(void)
{
push_scope_hook_list(&scope_hooks, NULL);
}
void __call_scope_hooks(void)
{
struct scope_hook_list *hook_list;
struct scope_container *tmp;
if (!scope_hooks)
return;
hook_list = pop_scope_hook_list(&scope_hooks);
FOR_EACH_PTR(hook_list, tmp) {
((scope_hook *)tmp->fn)(tmp->data);
__free_scope_container(tmp);
} END_FOR_EACH_PTR(tmp);
}
void allocate_hook_memory(void)
{
pre_merge_hooks = malloc(num_checks * sizeof(*pre_merge_hooks));
memset(pre_merge_hooks, 0, num_checks * sizeof(*pre_merge_hooks));
}