#include <stdlib.h>
#include <stdio.h>
#include "allocate.h"
#include "smatch.h"
#include "smatch_extra.h"
#include "smatch_slist.h"
#define VAR_LEN 512
char *alloc_string(const char *str)
{
char *tmp;
if (!str)
return NULL;
tmp = malloc(strlen(str) + 1);
strcpy(tmp, str);
return tmp;
}
char *alloc_string_newline(const char *str)
{
char *tmp;
int len;
if (!str)
return NULL;
len = strlen(str);
tmp = malloc(len + 2);
snprintf(tmp, len + 2, "%s\n", str);
return tmp;
}
void free_string(char *str)
{
free(str);
}
void remove_parens(char *str)
{
char *src, *dst;
dst = src = str;
while (*src != '\0') {
if (*src == '(' || *src == ')') {
src++;
continue;
}
*dst++ = *src++;
}
*dst = *src;
}
struct smatch_state *alloc_state_num(int num)
{
struct smatch_state *state;
static char buff[256];
state = __alloc_smatch_state(0);
snprintf(buff, 255, "%d", num);
buff[255] = '\0';
state->name = alloc_string(buff);
state->data = INT_PTR(num);
return state;
}
struct smatch_state *alloc_state_str(const char *name)
{
struct smatch_state *state;
state = __alloc_smatch_state(0);
state->name = alloc_string(name);
return state;
}
struct smatch_state *merge_str_state(struct smatch_state *s1, struct smatch_state *s2)
{
if (!s1->name || !s2->name)
return &merged;
if (strcmp(s1->name, s2->name) == 0)
return s1;
return &merged;
}
struct smatch_state *alloc_state_expr(struct expression *expr)
{
struct smatch_state *state;
char *name;
expr = strip_expr(expr);
name = expr_to_str(expr);
if (!name)
return NULL;
state = __alloc_smatch_state(0);
state->name = alloc_sname(name);
free_string(name);
state->data = expr;
return state;
}
void append(char *dest, const char *data, int buff_len)
{
strncat(dest, data, buff_len - strlen(dest) - 1);
}
struct expression *get_argument_from_call_expr(struct expression_list *args,
int num)
{
struct expression *expr;
int i = 0;
if (!args)
return NULL;
FOR_EACH_PTR(args, expr) {
if (i == num)
return expr;
i++;
} END_FOR_EACH_PTR(expr);
return NULL;
}
struct expression *get_array_expr(struct expression *expr)
{
struct expression *parent;
struct symbol *type;
if (expr->type != EXPR_BINOP || expr->op != '+')
return NULL;
type = get_type(expr->left);
if (!type)
return NULL;
if (type->type == SYM_ARRAY)
return expr->left;
if (type->type != SYM_PTR)
return NULL;
parent = expr_get_parent_expr(expr);
if (!parent)
return expr->left;
if (parent->type == EXPR_PREOP && parent->op == '*')
return expr->left;
return NULL;
}
static void __get_variable_from_expr(struct symbol **sym_ptr, char *buf,
struct expression *expr, int len,
int *complicated)
{
if (!expr) {
*complicated = 1;
return;
}
switch (expr->type) {
case EXPR_DEREF: {
struct expression *deref;
int op;
deref = expr->deref;
op = deref->op;
if (deref->type == EXPR_PREOP && op == '*') {
struct expression *unop = strip_expr(deref->unop);
if (unop->type == EXPR_PREOP && unop->op == '&') {
deref = unop->unop;
op = '.';
} else {
if (!is_pointer(deref) && !is_pointer(deref->unop))
op = '.';
deref = deref->unop;
}
}
__get_variable_from_expr(sym_ptr, buf, deref, len, complicated);
if (op == '*')
append(buf, "->", len);
else
append(buf, ".", len);
if (expr->member)
append(buf, expr->member->name, len);
else
append(buf, "unknown_member", len);
return;
}
case EXPR_SYMBOL:
if (expr->symbol_name)
append(buf, expr->symbol_name->name, len);
if (sym_ptr) {
if (*sym_ptr)
*complicated = 1;
*sym_ptr = expr->symbol;
}
return;
case EXPR_PREOP: {
const char *tmp;
if (get_expression_statement(expr)) {
*complicated = 2;
return;
}
if (expr->op == '(') {
if (expr->unop->type != EXPR_SYMBOL)
append(buf, "(", len);
} else if (expr->op != '*' || !get_array_expr(expr->unop)) {
tmp = show_special(expr->op);
append(buf, tmp, len);
}
__get_variable_from_expr(sym_ptr, buf, expr->unop,
len, complicated);
if (expr->op == '(' && expr->unop->type != EXPR_SYMBOL)
append(buf, ")", len);
if (expr->op == SPECIAL_DECREMENT ||
expr->op == SPECIAL_INCREMENT)
*complicated = 1;
return;
}
case EXPR_POSTOP: {
const char *tmp;
__get_variable_from_expr(sym_ptr, buf, expr->unop,
len, complicated);
tmp = show_special(expr->op);
append(buf, tmp, len);
if (expr->op == SPECIAL_DECREMENT || expr->op == SPECIAL_INCREMENT)
*complicated = 1;
return;
}
case EXPR_ASSIGNMENT:
case EXPR_COMPARE:
case EXPR_LOGICAL:
case EXPR_BINOP: {
char tmp[10];
struct expression *array_expr;
*complicated = 1;
array_expr = get_array_expr(expr);
if (array_expr) {
__get_variable_from_expr(sym_ptr, buf, array_expr, len, complicated);
append(buf, "[", len);
} else {
__get_variable_from_expr(sym_ptr, buf, expr->left, len, complicated);
snprintf(tmp, sizeof(tmp), " %s ", show_special(expr->op));
append(buf, tmp, len);
}
__get_variable_from_expr(NULL, buf, expr->right, len, complicated);
if (array_expr)
append(buf, "]", len);
return;
}
case EXPR_VALUE: {
sval_t sval = {};
char tmp[25];
*complicated = 1;
if (!get_value(expr, &sval))
return;
snprintf(tmp, 25, "%s", sval_to_numstr(sval));
append(buf, tmp, len);
return;
}
case EXPR_FVALUE: {
sval_t sval = {};
char tmp[25];
*complicated = 1;
if (!get_value(expr, &sval))
return;
snprintf(tmp, 25, "%s", sval_to_numstr(sval));
append(buf, tmp, len);
return;
}
case EXPR_STRING:
append(buf, "\"", len);
if (expr->string)
append(buf, expr->string->data, len);
append(buf, "\"", len);
return;
case EXPR_CALL: {
struct expression *tmp;
int i;
*complicated = 1;
__get_variable_from_expr(NULL, buf, expr->fn, len, complicated);
append(buf, "(", len);
i = 0;
FOR_EACH_PTR(expr->args, tmp) {
if (i++)
append(buf, ", ", len);
__get_variable_from_expr(NULL, buf, tmp, len, complicated);
} END_FOR_EACH_PTR(tmp);
append(buf, ")", len);
return;
}
case EXPR_CAST:
case EXPR_FORCE_CAST:
__get_variable_from_expr(sym_ptr, buf,
expr->cast_expression, len,
complicated);
return;
case EXPR_SIZEOF: {
sval_t sval;
int size;
char tmp[25];
if (expr->cast_type && get_base_type(expr->cast_type)) {
size = type_bytes(get_base_type(expr->cast_type));
snprintf(tmp, 25, "%d", size);
append(buf, tmp, len);
} else if (get_value(expr, &sval)) {
snprintf(tmp, 25, "%s", sval_to_str(sval));
append(buf, tmp, len);
}
return;
}
case EXPR_IDENTIFIER:
*complicated = 1;
if (expr->expr_ident)
append(buf, expr->expr_ident->name, len);
return;
case EXPR_SELECT:
case EXPR_CONDITIONAL:
*complicated = 1;
append(buf, "(", len);
__get_variable_from_expr(NULL, buf, expr->conditional, len, complicated);
append(buf, ") ?", len);
if (expr->cond_true)
__get_variable_from_expr(NULL, buf, expr->cond_true, len, complicated);
append(buf, ":", len);
__get_variable_from_expr(NULL, buf, expr->cond_false, len, complicated);
return;
default: {
char tmp[64];
snprintf(tmp, sizeof(tmp), "$expr_%p(%d)", expr, expr->type);
append(buf, tmp, len);
*complicated = 1;
}
return;
}
}
struct expr_str_cache_results {
struct expression *expr;
char str[VAR_LEN];
struct symbol *sym;
int complicated;
};
static void get_variable_from_expr(struct symbol **sym_ptr, char *buf,
struct expression *expr, int len,
int *complicated)
{
static struct expr_str_cache_results cached[8];
struct symbol *tmp_sym = NULL;
static int idx;
int i;
for (i = 0; i < ARRAY_SIZE(cached); i++) {
if (expr == cached[i].expr) {
strncpy(buf, cached[i].str, len);
if (sym_ptr)
*sym_ptr = cached[i].sym;
*complicated = cached[i].complicated;
return;
}
}
__get_variable_from_expr(&tmp_sym, buf, expr, len, complicated);
if (sym_ptr)
*sym_ptr = tmp_sym;
if (expr->smatch_flags & Tmp)
return;
cached[idx].expr = expr;
strncpy(cached[idx].str, buf, VAR_LEN);
cached[idx].sym = tmp_sym;
cached[idx].complicated = *complicated;
idx = (idx + 1) % ARRAY_SIZE(cached);
}
char *expr_to_str_sym(struct expression *expr, struct symbol **sym_ptr)
{
static char var_name[VAR_LEN];
int complicated = 0;
if (sym_ptr)
*sym_ptr = NULL;
var_name[0] = '\0';
if (!expr)
return NULL;
get_variable_from_expr(sym_ptr, var_name, expr, sizeof(var_name),
&complicated);
if (complicated < 2)
return alloc_string(var_name);
else
return NULL;
}
char *expr_to_str(struct expression *expr)
{
return expr_to_str_sym(expr, NULL);
}
char *expr_to_var_sym(struct expression *expr,
struct symbol **sym_ptr)
{
static char var_name[VAR_LEN];
int complicated = 0;
if (sym_ptr)
*sym_ptr = NULL;
var_name[0] = '\0';
if (!expr)
return NULL;
expr = strip_expr(expr);
get_variable_from_expr(sym_ptr, var_name, expr, sizeof(var_name),
&complicated);
if (complicated) {
if (sym_ptr)
*sym_ptr = NULL;
return NULL;
}
return alloc_string(var_name);
}
char *expr_to_var(struct expression *expr)
{
return expr_to_var_sym(expr, NULL);
}
struct symbol *expr_to_sym(struct expression *expr)
{
struct symbol *sym;
char *name;
name = expr_to_var_sym(expr, &sym);
free_string(name);
return sym;
}
int get_complication_score(struct expression *expr)
{
expr = strip_expr(expr);
if (!expr)
return 990;
switch (expr->type) {
case EXPR_CALL:
return 991;
case EXPR_COMPARE:
case EXPR_BINOP:
return get_complication_score(expr->left) +
get_complication_score(expr->right);
case EXPR_SYMBOL:
return 1;
case EXPR_PREOP:
if (expr->op == '*' || expr->op == '(')
return get_complication_score(expr->unop);
return 993;
case EXPR_DEREF:
return get_complication_score(expr->deref);
case EXPR_VALUE:
case EXPR_SIZEOF:
return 0;
default:
return 994;
}
}
struct expression *reorder_expr_alphabetically(struct expression *expr)
{
struct expression *ret;
char *left, *right;
if (expr->type != EXPR_BINOP)
return expr;
if (expr->op != '+' && expr->op != '*')
return expr;
left = expr_to_var(expr->left);
right = expr_to_var(expr->right);
ret = expr;
if (!left || !right)
goto free;
if (strcmp(left, right) <= 0)
goto free;
ret = binop_expression(expr->right, expr->op, expr->left);
free:
free_string(left);
free_string(right);
return ret;
}
char *expr_to_chunk_helper(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl)
{
struct var_sym_list *tmp_vsl;
char *name;
struct symbol *tmp;
int score;
if (vsl)
*vsl = NULL;
if (sym)
*sym = NULL;
expr = strip_parens(expr);
if (!expr)
return NULL;
name = expr_to_var_sym(expr, &tmp);
if (name && tmp) {
if (sym)
*sym = tmp;
if (vsl)
add_var_sym(vsl, name, tmp);
return name;
}
free_string(name);
score = get_complication_score(expr);
if (score <= 0 || score > 2)
return NULL;
tmp_vsl = expr_to_vsl(expr);
if (vsl) {
*vsl = tmp_vsl;
if (!*vsl)
return NULL;
}
if (sym) {
if (ptr_list_size((struct ptr_list *)tmp_vsl) == 1) {
struct var_sym *vs;
vs = first_ptr_list((struct ptr_list *)tmp_vsl);
*sym = vs->sym;
}
}
expr = reorder_expr_alphabetically(expr);
return expr_to_str(expr);
}
char *expr_to_known_chunk_sym(struct expression *expr, struct symbol **sym)
{
return expr_to_chunk_helper(expr, sym, NULL);
}
char *expr_to_chunk_sym_vsl(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl)
{
return expr_to_chunk_helper(expr, sym, vsl);
}
int sym_name_is(const char *name, struct expression *expr)
{
if (!expr)
return 0;
if (expr->type != EXPR_SYMBOL)
return 0;
if (!strcmp(expr->symbol_name->name, name))
return 1;
return 0;
}
int expr_is_zero(struct expression *expr)
{
sval_t sval;
if (get_value(expr, &sval) && sval.value == 0)
return 1;
return 0;
}
int is_array(struct expression *expr)
{
struct symbol *type;
expr = strip_expr(expr);
if (!expr)
return 0;
if (expr->type == EXPR_PREOP && expr->op == '*') {
expr = strip_expr(expr->unop);
if (!expr)
return 0;
if (expr->type == EXPR_BINOP && expr->op == '+')
return 1;
}
if (expr->type != EXPR_BINOP || expr->op != '+')
return 0;
type = get_type(expr->left);
if (!type || type->type != SYM_ARRAY)
return 0;
return 1;
}
struct expression *get_array_base(struct expression *expr)
{
if (!is_array(expr))
return NULL;
expr = strip_expr(expr);
if (expr->type == EXPR_PREOP && expr->op == '*')
expr = strip_expr(expr->unop);
if (expr->type != EXPR_BINOP || expr->op != '+')
return NULL;
return strip_parens(expr->left);
}
struct expression *get_array_offset(struct expression *expr)
{
if (!is_array(expr))
return NULL;
expr = strip_expr(expr);
if (expr->type == EXPR_PREOP && expr->op == '*')
expr = strip_expr(expr->unop);
if (expr->type != EXPR_BINOP || expr->op != '+')
return NULL;
return strip_parens(expr->right);
}
const char *show_state(struct smatch_state *state)
{
if (!state)
return NULL;
return state->name;
}
struct statement *get_expression_statement(struct expression *expr)
{
if (expr->type != EXPR_PREOP)
return NULL;
if (expr->op != '(')
return NULL;
if (!expr->unop)
return NULL;
if (expr->unop->type != EXPR_STATEMENT)
return NULL;
if (expr->unop->statement->type != STMT_COMPOUND)
return NULL;
return expr->unop->statement;
}
struct expression *strip_parens(struct expression *expr)
{
if (!expr)
return NULL;
if (expr->type == EXPR_PREOP) {
if (!expr->unop)
return expr;
if (expr->op == '(' && expr->unop->type == EXPR_STATEMENT &&
expr->unop->statement->type == STMT_COMPOUND)
return expr;
if (expr->op == '(')
return strip_parens(expr->unop);
}
return expr;
}
static struct expression *strip_expr_helper(struct expression *expr, bool set_parent)
{
if (!expr)
return NULL;
switch (expr->type) {
case EXPR_FORCE_CAST:
case EXPR_CAST:
if (set_parent)
expr_set_parent_expr(expr->cast_expression, expr);
if (!expr->cast_expression)
return expr;
return strip_expr_helper(expr->cast_expression, set_parent);
case EXPR_PREOP: {
struct expression *unop;
if (!expr->unop)
return expr;
if (set_parent)
expr_set_parent_expr(expr->unop, expr);
if (expr->op == '(' && expr->unop->type == EXPR_STATEMENT &&
expr->unop->statement->type == STMT_COMPOUND)
return expr;
unop = strip_expr_helper(expr->unop, set_parent);
if (expr->op == '*' && unop &&
unop->type == EXPR_PREOP && unop->op == '&') {
struct symbol *type = get_type(unop->unop);
if (type && type->type == SYM_ARRAY)
return expr;
return strip_expr_helper(unop->unop, set_parent);
}
if (expr->op == '(')
return unop;
return expr;
}
case EXPR_CONDITIONAL:
if (known_condition_true(expr->conditional)) {
if (expr->cond_true) {
if (set_parent)
expr_set_parent_expr(expr->cond_true, expr);
return strip_expr_helper(expr->cond_true, set_parent);
}
if (set_parent)
expr_set_parent_expr(expr->conditional, expr);
return strip_expr_helper(expr->conditional, set_parent);
}
if (known_condition_false(expr->conditional)) {
if (set_parent)
expr_set_parent_expr(expr->cond_false, expr);
return strip_expr_helper(expr->cond_false, set_parent);
}
return expr;
case EXPR_CALL:
if (sym_name_is("__builtin_expect", expr->fn) ||
sym_name_is("__builtin_bswap16", expr->fn) ||
sym_name_is("__builtin_bswap32", expr->fn) ||
sym_name_is("__builtin_bswap64", expr->fn)) {
expr = get_argument_from_call_expr(expr->args, 0);
return strip_expr_helper(expr, set_parent);
}
return expr;
}
return expr;
}
struct expression *strip_expr(struct expression *expr)
{
return strip_expr_helper(expr, false);
}
struct expression *strip_expr_set_parent(struct expression *expr)
{
return strip_expr_helper(expr, true);
}
static void delete_state_tracker(struct tracker *t)
{
delete_state(t->owner, t->name, t->sym);
__free_tracker(t);
}
void scoped_state(int my_id, const char *name, struct symbol *sym)
{
struct tracker *t;
t = alloc_tracker(my_id, name, sym);
add_scope_hook((scope_hook *)&delete_state_tracker, t);
}
int is_error_return(struct expression *expr)
{
struct symbol *cur_func = cur_func_sym;
struct range_list *rl;
sval_t sval;
if (!expr)
return 0;
if (cur_func->type != SYM_NODE)
return 0;
cur_func = get_base_type(cur_func);
if (cur_func->type != SYM_FN)
return 0;
cur_func = get_base_type(cur_func);
if (cur_func == &void_ctype)
return 0;
if (option_project == PROJ_KERNEL &&
get_implied_rl(expr, &rl) &&
rl_type(rl) == &int_ctype &&
sval_is_negative(rl_min(rl)) &&
rl_max(rl).value == -1)
return 1;
if (!get_implied_value(expr, &sval))
return 0;
if (sval.value < 0)
return 1;
if (cur_func->type == SYM_PTR && sval.value == 0)
return 1;
return 0;
}
int getting_address(struct expression *expr)
{
int deref_count = 0;
while ((expr = expr_get_parent_expr(expr))) {
if (expr->type == EXPR_PREOP && expr->op == '*') {
if (deref_count == 0)
deref_count++;
return false;
}
if (expr->type == EXPR_PREOP && expr->op == '&')
return true;
}
return false;
}
int get_struct_and_member(struct expression *expr, const char **type, const char **member)
{
struct symbol *sym;
expr = strip_expr(expr);
if (expr->type != EXPR_DEREF)
return 0;
if (!expr->member)
return 0;
sym = get_type(expr->deref);
if (!sym)
return 0;
if (sym->type == SYM_UNION)
return 0;
if (!sym->ident)
return 0;
*type = sym->ident->name;
*member = expr->member->name;
return 1;
}
char *get_member_name(struct expression *expr)
{
char buf[256];
struct symbol *sym;
expr = strip_expr(expr);
if (!expr || expr->type != EXPR_DEREF)
return NULL;
if (!expr->member)
return NULL;
sym = get_type(expr->deref);
if (!sym)
return NULL;
if (sym->type == SYM_UNION) {
snprintf(buf, sizeof(buf), "(union %s)->%s",
sym->ident ? sym->ident->name : "anonymous",
expr->member->name);
return alloc_string(buf);
}
if (!sym->ident) {
struct expression *deref;
char *full, *outer;
int len;
deref = expr->deref;
if (deref->type != EXPR_DEREF || !deref->member)
return NULL;
sym = get_type(deref->deref);
if (!sym || sym->type != SYM_STRUCT || !sym->ident)
return NULL;
full = expr_to_str(expr);
if (!full)
return NULL;
deref = deref->deref;
if (deref->type == EXPR_PREOP && deref->op == '*')
deref = deref->unop;
outer = expr_to_str(deref);
if (!outer) {
free_string(full);
return NULL;
}
len = strlen(outer);
if (strncmp(outer, full, len) != 0) {
free_string(full);
free_string(outer);
return NULL;
}
if (full[len] == '-' && full[len + 1] == '>')
len += 2;
if (full[len] == '.')
len++;
snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, full + len);
free_string(outer);
free_string(full);
return alloc_string(buf);
}
snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, expr->member->name);
return alloc_string(buf);
}
int cmp_pos(struct position pos1, struct position pos2)
{
if (pos1.stream > pos2.stream)
return -1;
if (pos1.stream < pos2.stream)
return 1;
if (pos1.line < pos2.line)
return -1;
if (pos1.line > pos2.line)
return 1;
if (pos1.pos < pos2.pos)
return -1;
if (pos1.pos > pos2.pos)
return 1;
return 0;
}
int positions_eq(struct position pos1, struct position pos2)
{
if (pos1.line != pos2.line)
return 0;
if (pos1.pos != pos2.pos)
return 0;
if (pos1.stream != pos2.stream)
return 0;
return 1;
}
struct statement *get_current_statement(void)
{
struct statement *prev, *tmp;
prev = last_ptr_list((struct ptr_list *)big_statement_stack);
if (!prev || !get_macro_name(prev->pos))
return prev;
FOR_EACH_PTR_REVERSE(big_statement_stack, tmp) {
if (positions_eq(tmp->pos, prev->pos))
continue;
if (prev->pos.line > tmp->pos.line)
return prev;
return tmp;
} END_FOR_EACH_PTR_REVERSE(tmp);
return prev;
}
struct statement *get_prev_statement(void)
{
struct statement *tmp;
int i;
i = 0;
FOR_EACH_PTR_REVERSE(big_statement_stack, tmp) {
if (i++ == 1)
return tmp;
} END_FOR_EACH_PTR_REVERSE(tmp);
return NULL;
}
struct expression *get_last_expr_from_expression_stmt(struct expression *expr)
{
struct statement *stmt;
struct statement *last_stmt;
while (expr->type == EXPR_PREOP && expr->op == '(')
expr = expr->unop;
if (expr->type != EXPR_STATEMENT)
return NULL;
stmt = expr->statement;
if (!stmt)
return NULL;
if (stmt->type == STMT_COMPOUND) {
last_stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
if (!last_stmt)
return NULL;
if (last_stmt->type == STMT_LABEL)
last_stmt = last_stmt->label_statement;
if (last_stmt->type != STMT_EXPRESSION)
return NULL;
return last_stmt->expression;
}
if (stmt->type == STMT_EXPRESSION)
return stmt->expression;
return NULL;
}
int get_param_num_from_sym(struct symbol *sym)
{
struct symbol *tmp;
int i;
if (!sym)
return UNKNOWN_SCOPE;
if (sym->ctype.modifiers & MOD_TOPLEVEL) {
if (sym->ctype.modifiers & MOD_STATIC)
return FILE_SCOPE;
return GLOBAL_SCOPE;
}
if (!cur_func_sym) {
if (!parse_error) {
sm_msg("warn: internal. problem with scope: %s",
sym->ident ? sym->ident->name : "<anon var>");
}
return GLOBAL_SCOPE;
}
i = 0;
FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
if (tmp == sym)
return i;
i++;
} END_FOR_EACH_PTR(tmp);
return LOCAL_SCOPE;
}
int get_param_num(struct expression *expr)
{
struct symbol *sym;
char *name;
if (!cur_func_sym)
return UNKNOWN_SCOPE;
name = expr_to_var_sym(expr, &sym);
free_string(name);
if (!sym)
return UNKNOWN_SCOPE;
return get_param_num_from_sym(sym);
}
struct symbol *get_param_sym_from_num(int num)
{
struct symbol *sym;
int i;
if (!cur_func_sym)
return NULL;
i = 0;
FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) {
if (i++ == num)
return sym;
} END_FOR_EACH_PTR(sym);
return NULL;
}
int ms_since(struct timeval *start)
{
struct timeval end;
double diff;
gettimeofday(&end, NULL);
diff = (end.tv_sec - start->tv_sec) * 1000.0;
diff += (end.tv_usec - start->tv_usec) / 1000.0;
return (int)diff;
}
int parent_is_gone_var_sym(const char *name, struct symbol *sym)
{
if (!name || !sym)
return 0;
if (parent_is_null_var_sym(name, sym) ||
parent_is_free_var_sym(name, sym))
return 1;
return 0;
}
int parent_is_gone(struct expression *expr)
{
struct symbol *sym;
char *var;
int ret = 0;
expr = strip_expr(expr);
var = expr_to_var_sym(expr, &sym);
if (!var || !sym)
goto free;
ret = parent_is_gone_var_sym(var, sym);
free:
free_string(var);
return ret;
}
int invert_op(int op)
{
switch (op) {
case '*':
return '/';
case '/':
return '*';
case '+':
return '-';
case '-':
return '+';
case SPECIAL_LEFTSHIFT:
return SPECIAL_RIGHTSHIFT;
case SPECIAL_RIGHTSHIFT:
return SPECIAL_LEFTSHIFT;
}
return 0;
}
int op_remove_assign(int op)
{
switch (op) {
case SPECIAL_ADD_ASSIGN:
return '+';
case SPECIAL_SUB_ASSIGN:
return '-';
case SPECIAL_MUL_ASSIGN:
return '*';
case SPECIAL_DIV_ASSIGN:
return '/';
case SPECIAL_MOD_ASSIGN:
return '%';
case SPECIAL_AND_ASSIGN:
return '&';
case SPECIAL_OR_ASSIGN:
return '|';
case SPECIAL_XOR_ASSIGN:
return '^';
case SPECIAL_SHL_ASSIGN:
return SPECIAL_LEFTSHIFT;
case SPECIAL_SHR_ASSIGN:
return SPECIAL_RIGHTSHIFT;
default:
return op;
}
}
int expr_equiv(struct expression *one, struct expression *two)
{
struct symbol *one_sym = NULL;
struct symbol *two_sym = NULL;
char *one_name = NULL;
char *two_name = NULL;
int ret = 0;
if (!one || !two)
return 0;
if (one->type != two->type)
return 0;
if (is_fake_call(one) || is_fake_call(two))
return 0;
one_name = expr_to_str_sym(one, &one_sym);
if (!one_name)
goto free;
two_name = expr_to_str_sym(two, &two_sym);
if (!two_name)
goto free;
if (one_sym != two_sym)
goto free;
if (strstr(one_name, "()"))
goto free;
if (strcmp(one_name, two_name) == 0)
ret = 1;
free:
free_string(one_name);
free_string(two_name);
return ret;
}
void push_int(struct int_stack **stack, int num)
{
int *munged;
munged = INT_PTR(num << 2);
add_ptr_list(stack, munged);
}
int pop_int(struct int_stack **stack)
{
int *num;
num = last_ptr_list((struct ptr_list *)*stack);
delete_ptr_list_last((struct ptr_list **)stack);
return PTR_INT(num) >> 2;
}