xref: /illumos-gate/usr/src/tools/smatch/src/smatch_parse_call_math.c (revision c85f09cc92abd00c84e58ec9f0f5d942906cb713)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2012 Oracle.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon #include "smatch.h"
191f5207b7SJohn Levon #include "smatch_slist.h"
201f5207b7SJohn Levon #include "smatch_extra.h"
211f5207b7SJohn Levon 
221f5207b7SJohn Levon static int my_id;
231f5207b7SJohn Levon 
241f5207b7SJohn Levon struct {
251f5207b7SJohn Levon 	const char *func;
261f5207b7SJohn Levon 	int param;
271f5207b7SJohn Levon } alloc_functions[] = {
281f5207b7SJohn Levon 	{"kmalloc", 0},
291f5207b7SJohn Levon 	{"kzalloc", 0},
301f5207b7SJohn Levon 	{"__kmalloc", 0},
311f5207b7SJohn Levon 	{"vmalloc", 0},
321f5207b7SJohn Levon 	{"__vmalloc", 0},
331f5207b7SJohn Levon 	{"__vmalloc_node", 0},
341f5207b7SJohn Levon };
351f5207b7SJohn Levon 
361f5207b7SJohn Levon static struct range_list_stack *rl_stack;
371f5207b7SJohn Levon static struct string_list *op_list;
381f5207b7SJohn Levon 
push_op(char c)391f5207b7SJohn Levon static void push_op(char c)
401f5207b7SJohn Levon {
411f5207b7SJohn Levon 	char *p;
421f5207b7SJohn Levon 
431f5207b7SJohn Levon 	p = malloc(1);
441f5207b7SJohn Levon 	p[0] = c;
451f5207b7SJohn Levon 	add_ptr_list(&op_list, p);
461f5207b7SJohn Levon }
471f5207b7SJohn Levon 
pop_op(void)481f5207b7SJohn Levon static char pop_op(void)
491f5207b7SJohn Levon {
501f5207b7SJohn Levon 	char *p;
511f5207b7SJohn Levon 	char c;
521f5207b7SJohn Levon 
531f5207b7SJohn Levon 	if (!op_list) {
541f5207b7SJohn Levon 		sm_perror("%s: no op_list", __func__);
551f5207b7SJohn Levon 		return '\0';
561f5207b7SJohn Levon 	}
571f5207b7SJohn Levon 
581f5207b7SJohn Levon 	p = last_ptr_list((struct ptr_list *)op_list);
591f5207b7SJohn Levon 
601f5207b7SJohn Levon 	delete_ptr_list_last((struct ptr_list **)&op_list);
611f5207b7SJohn Levon 	c = p[0];
621f5207b7SJohn Levon 	free(p);
631f5207b7SJohn Levon 
641f5207b7SJohn Levon 	return c;
651f5207b7SJohn Levon }
661f5207b7SJohn Levon 
op_precedence(char c)671f5207b7SJohn Levon static int op_precedence(char c)
681f5207b7SJohn Levon {
691f5207b7SJohn Levon 	switch (c) {
701f5207b7SJohn Levon 	case '+':
711f5207b7SJohn Levon 	case '-':
721f5207b7SJohn Levon 		return 1;
731f5207b7SJohn Levon 	case '*':
741f5207b7SJohn Levon 	case '/':
751f5207b7SJohn Levon 		return 2;
761f5207b7SJohn Levon 	default:
771f5207b7SJohn Levon 		return 0;
781f5207b7SJohn Levon 	}
791f5207b7SJohn Levon }
801f5207b7SJohn Levon 
top_op_precedence(void)811f5207b7SJohn Levon static int top_op_precedence(void)
821f5207b7SJohn Levon {
831f5207b7SJohn Levon 	char *p;
841f5207b7SJohn Levon 
851f5207b7SJohn Levon 	if (!op_list)
861f5207b7SJohn Levon 		return 0;
871f5207b7SJohn Levon 
881f5207b7SJohn Levon 	p = last_ptr_list((struct ptr_list *)op_list);
891f5207b7SJohn Levon 	return op_precedence(p[0]);
901f5207b7SJohn Levon }
911f5207b7SJohn Levon 
rl_pop_until(char c)921f5207b7SJohn Levon static void rl_pop_until(char c)
931f5207b7SJohn Levon {
941f5207b7SJohn Levon 	char op;
951f5207b7SJohn Levon 	struct range_list *left, *right;
961f5207b7SJohn Levon 	struct range_list *res;
971f5207b7SJohn Levon 
981f5207b7SJohn Levon 	while (top_op_precedence() && op_precedence(c) <= top_op_precedence()) {
991f5207b7SJohn Levon 		op = pop_op();
1001f5207b7SJohn Levon 		right = pop_rl(&rl_stack);
1011f5207b7SJohn Levon 		left = pop_rl(&rl_stack);
1021f5207b7SJohn Levon 		res = rl_binop(left, op, right);
1031f5207b7SJohn Levon 		if (!res)
1041f5207b7SJohn Levon 			res = alloc_whole_rl(&llong_ctype);
1051f5207b7SJohn Levon 		push_rl(&rl_stack, res);
1061f5207b7SJohn Levon 	}
1071f5207b7SJohn Levon }
1081f5207b7SJohn Levon 
rl_discard_stacks(void)1091f5207b7SJohn Levon static void rl_discard_stacks(void)
1101f5207b7SJohn Levon {
1111f5207b7SJohn Levon 	while (op_list)
1121f5207b7SJohn Levon 		pop_op();
1131f5207b7SJohn Levon 	while (rl_stack)
1141f5207b7SJohn Levon 		pop_rl(&rl_stack);
1151f5207b7SJohn Levon }
1161f5207b7SJohn Levon 
read_rl_from_var(struct expression * call,const char * p,const char ** end,struct range_list ** rl)117efe51d0cSJohn Levon static int read_rl_from_var(struct expression *call, const char *p, const char **end, struct range_list **rl)
1181f5207b7SJohn Levon {
1191f5207b7SJohn Levon 	struct expression *arg;
1201f5207b7SJohn Levon 	struct smatch_state *state;
1211f5207b7SJohn Levon 	long param;
1221f5207b7SJohn Levon 	char *name;
1231f5207b7SJohn Levon 	struct symbol *sym;
1241f5207b7SJohn Levon 	char buf[256];
1251f5207b7SJohn Levon 	int star;
1261f5207b7SJohn Levon 
1271f5207b7SJohn Levon 	p++;
128efe51d0cSJohn Levon 	param = strtol(p, (char **)&p, 10);
1291f5207b7SJohn Levon 
1301f5207b7SJohn Levon 	arg = get_argument_from_call_expr(call->args, param);
1311f5207b7SJohn Levon 	if (!arg)
1321f5207b7SJohn Levon 		return 0;
1331f5207b7SJohn Levon 
1341f5207b7SJohn Levon 	if (*p != '-' && *p != '.') {
1351f5207b7SJohn Levon 		get_absolute_rl(arg, rl);
1361f5207b7SJohn Levon 		*end = p;
1371f5207b7SJohn Levon 		return 1;
1381f5207b7SJohn Levon 	}
1391f5207b7SJohn Levon 
1401f5207b7SJohn Levon 	*end = strchr(p, ' ');
1411f5207b7SJohn Levon 
1421f5207b7SJohn Levon 	if (arg->type == EXPR_PREOP && arg->op == '&') {
1431f5207b7SJohn Levon 		arg = strip_expr(arg->unop);
1441f5207b7SJohn Levon 		star = 0;
1451f5207b7SJohn Levon 		p++;
1461f5207b7SJohn Levon 	} else {
1471f5207b7SJohn Levon 		star = 1;
1481f5207b7SJohn Levon 		p += 2;
1491f5207b7SJohn Levon 	}
1501f5207b7SJohn Levon 
1511f5207b7SJohn Levon 	name = expr_to_var_sym(arg, &sym);
1521f5207b7SJohn Levon 	if (!name)
1531f5207b7SJohn Levon 		return 0;
1541f5207b7SJohn Levon 	snprintf(buf, sizeof(buf), "%s%s", name, star ? "->" : ".");
1551f5207b7SJohn Levon 	free_string(name);
1561f5207b7SJohn Levon 
1571f5207b7SJohn Levon 	if (*end - p + strlen(buf) >= sizeof(buf))
1581f5207b7SJohn Levon 		return 0;
1591f5207b7SJohn Levon 	strncat(buf, p, *end - p);
1601f5207b7SJohn Levon 
1611f5207b7SJohn Levon 	state = get_state(SMATCH_EXTRA, buf, sym);
1621f5207b7SJohn Levon 	if (!state)
1631f5207b7SJohn Levon 		return 0;
1641f5207b7SJohn Levon 	*rl = estate_rl(state);
1651f5207b7SJohn Levon 	return 1;
1661f5207b7SJohn Levon }
1671f5207b7SJohn Levon 
read_var_num(struct expression * call,const char * p,const char ** end,struct range_list ** rl)168efe51d0cSJohn Levon static int read_var_num(struct expression *call, const char *p, const char **end, struct range_list **rl)
1691f5207b7SJohn Levon {
1701f5207b7SJohn Levon 	sval_t sval;
1711f5207b7SJohn Levon 
1721f5207b7SJohn Levon 	while (*p == ' ')
1731f5207b7SJohn Levon 		p++;
1741f5207b7SJohn Levon 
1751f5207b7SJohn Levon 	if (*p == '$')
1761f5207b7SJohn Levon 		return read_rl_from_var(call, p, end, rl);
1771f5207b7SJohn Levon 
1781f5207b7SJohn Levon 	sval.type = &llong_ctype;
179efe51d0cSJohn Levon 	sval.value = strtoll(p, (char **)end, 10);
1801f5207b7SJohn Levon 	if (*end == p)
1811f5207b7SJohn Levon 		return 0;
1821f5207b7SJohn Levon 	*rl = alloc_rl(sval, sval);
1831f5207b7SJohn Levon 	return 1;
1841f5207b7SJohn Levon }
1851f5207b7SJohn Levon 
read_op(const char * p)186efe51d0cSJohn Levon static const char *read_op(const char *p)
1871f5207b7SJohn Levon {
1881f5207b7SJohn Levon 	while (*p == ' ')
1891f5207b7SJohn Levon 		p++;
1901f5207b7SJohn Levon 
1911f5207b7SJohn Levon 	switch (*p) {
1921f5207b7SJohn Levon 	case '+':
1931f5207b7SJohn Levon 	case '-':
1941f5207b7SJohn Levon 	case '*':
1951f5207b7SJohn Levon 	case '/':
1961f5207b7SJohn Levon 		return p;
1971f5207b7SJohn Levon 	default:
1981f5207b7SJohn Levon 		return NULL;
1991f5207b7SJohn Levon 	}
2001f5207b7SJohn Levon }
2011f5207b7SJohn Levon 
parse_call_math_rl(struct expression * call,const char * math,struct range_list ** rl)202efe51d0cSJohn Levon int parse_call_math_rl(struct expression *call, const char *math, struct range_list **rl)
2031f5207b7SJohn Levon {
2041f5207b7SJohn Levon 	struct range_list *tmp;
205efe51d0cSJohn Levon 	const char *c;
2061f5207b7SJohn Levon 
2071f5207b7SJohn Levon 	/* try to implement shunting yard algorithm. */
2081f5207b7SJohn Levon 
209efe51d0cSJohn Levon 	c = math;
2101f5207b7SJohn Levon 	while (1) {
2111f5207b7SJohn Levon 		if (option_debug)
2121f5207b7SJohn Levon 			sm_msg("parsing %s", c);
2131f5207b7SJohn Levon 
2141f5207b7SJohn Levon 		/* read a number and push it onto the number stack */
2151f5207b7SJohn Levon 		if (!read_var_num(call, c, &c, &tmp))
2161f5207b7SJohn Levon 			goto fail;
2171f5207b7SJohn Levon 		push_rl(&rl_stack, tmp);
2181f5207b7SJohn Levon 
2191f5207b7SJohn Levon 		if (option_debug)
2201f5207b7SJohn Levon 			sm_msg("val = %s remaining = %s", show_rl(tmp), c);
2211f5207b7SJohn Levon 
2221f5207b7SJohn Levon 		if (!*c)
2231f5207b7SJohn Levon 			break;
2241f5207b7SJohn Levon 		if (*c == ']' && *(c + 1) == '\0')
2251f5207b7SJohn Levon 			break;
2261f5207b7SJohn Levon 
2271f5207b7SJohn Levon 		c = read_op(c);
2281f5207b7SJohn Levon 		if (!c)
2291f5207b7SJohn Levon 			goto fail;
2301f5207b7SJohn Levon 
2311f5207b7SJohn Levon 		if (option_debug)
2321f5207b7SJohn Levon 			sm_msg("op = %c remaining = %s", *c, c);
2331f5207b7SJohn Levon 
2341f5207b7SJohn Levon 		rl_pop_until(*c);
2351f5207b7SJohn Levon 		push_op(*c);
2361f5207b7SJohn Levon 		c++;
2371f5207b7SJohn Levon 	}
2381f5207b7SJohn Levon 
2391f5207b7SJohn Levon 	rl_pop_until(0);
2401f5207b7SJohn Levon 	*rl = pop_rl(&rl_stack);
2411f5207b7SJohn Levon 	return 1;
2421f5207b7SJohn Levon fail:
2431f5207b7SJohn Levon 	rl_discard_stacks();
2441f5207b7SJohn Levon 	return 0;
2451f5207b7SJohn Levon }
2461f5207b7SJohn Levon 
parse_call_math(struct expression * call,char * math,sval_t * sval)2471f5207b7SJohn Levon int parse_call_math(struct expression *call, char *math, sval_t *sval)
2481f5207b7SJohn Levon {
2491f5207b7SJohn Levon 	struct range_list *rl;
2501f5207b7SJohn Levon 
2511f5207b7SJohn Levon 	if (!parse_call_math_rl(call, math, &rl))
2521f5207b7SJohn Levon 		return 0;
2531f5207b7SJohn Levon 	if (!rl_to_sval(rl, sval))
2541f5207b7SJohn Levon 		return 0;
2551f5207b7SJohn Levon 	return 1;
2561f5207b7SJohn Levon }
2571f5207b7SJohn Levon 
alloc_state_sname(char * sname)2581f5207b7SJohn Levon static struct smatch_state *alloc_state_sname(char *sname)
2591f5207b7SJohn Levon {
2601f5207b7SJohn Levon 	struct smatch_state *state;
2611f5207b7SJohn Levon 
2621f5207b7SJohn Levon 	state = __alloc_smatch_state(0);
2631f5207b7SJohn Levon 	state->name = sname;
2641f5207b7SJohn Levon 	state->data = INT_PTR(1);
2651f5207b7SJohn Levon 	return state;
2661f5207b7SJohn Levon }
2671f5207b7SJohn Levon 
get_arg_number(struct expression * expr)2681f5207b7SJohn Levon static int get_arg_number(struct expression *expr)
2691f5207b7SJohn Levon {
2701f5207b7SJohn Levon 	struct symbol *sym;
2711f5207b7SJohn Levon 	struct symbol *arg;
2721f5207b7SJohn Levon 	int i;
2731f5207b7SJohn Levon 
2741f5207b7SJohn Levon 	expr = strip_expr(expr);
2751f5207b7SJohn Levon 	if (expr->type != EXPR_SYMBOL)
2761f5207b7SJohn Levon 		return -1;
2771f5207b7SJohn Levon 	sym = expr->symbol;
2781f5207b7SJohn Levon 
2791f5207b7SJohn Levon 	i = 0;
2801f5207b7SJohn Levon 	FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
2811f5207b7SJohn Levon 		if (arg == sym)
2821f5207b7SJohn Levon 			return i;
2831f5207b7SJohn Levon 		i++;
2841f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
2851f5207b7SJohn Levon 
2861f5207b7SJohn Levon 	return -1;
2871f5207b7SJohn Levon }
2881f5207b7SJohn Levon 
format_name_sym_helper(char * buf,int remaining,char * name,struct symbol * sym)2891f5207b7SJohn Levon static int format_name_sym_helper(char *buf, int remaining, char *name, struct symbol *sym)
2901f5207b7SJohn Levon {
2911f5207b7SJohn Levon 	int ret = 0;
2921f5207b7SJohn Levon 	int arg;
2931f5207b7SJohn Levon 	char *param_name;
2941f5207b7SJohn Levon 	int name_len;
2951f5207b7SJohn Levon 
2961f5207b7SJohn Levon 	if (!name || !sym || !sym->ident)
2971f5207b7SJohn Levon 		goto free;
2981f5207b7SJohn Levon 	arg = get_param_num_from_sym(sym);
2991f5207b7SJohn Levon 	if (arg < 0)
3001f5207b7SJohn Levon 		goto free;
3011f5207b7SJohn Levon 	if (param_was_set_var_sym(name, sym))
3021f5207b7SJohn Levon 		goto free;
3031f5207b7SJohn Levon 
3041f5207b7SJohn Levon 	param_name = sym->ident->name;
3051f5207b7SJohn Levon 	name_len = strlen(param_name);
3061f5207b7SJohn Levon 
3071f5207b7SJohn Levon 	if (name[name_len] == '\0')
3081f5207b7SJohn Levon 		ret = snprintf(buf, remaining, "$%d", arg);
3091f5207b7SJohn Levon 	else if (name[name_len] == '-')
3101f5207b7SJohn Levon 		ret = snprintf(buf, remaining, "$%d%s", arg, name + name_len);
3111f5207b7SJohn Levon 	else
3121f5207b7SJohn Levon 		goto free;
3131f5207b7SJohn Levon 
3141f5207b7SJohn Levon 	remaining -= ret;
3151f5207b7SJohn Levon 	if (remaining <= 0)
3161f5207b7SJohn Levon 		ret = 0;
3171f5207b7SJohn Levon 
3181f5207b7SJohn Levon free:
3191f5207b7SJohn Levon 	free_string(name);
3201f5207b7SJohn Levon 
3211f5207b7SJohn Levon 	return ret;
3221f5207b7SJohn Levon 
3231f5207b7SJohn Levon }
3241f5207b7SJohn Levon 
format_variable_helper(char * buf,int remaining,struct expression * expr)3251f5207b7SJohn Levon static int format_variable_helper(char *buf, int remaining, struct expression *expr)
3261f5207b7SJohn Levon {
3271f5207b7SJohn Levon 	char *name;
3281f5207b7SJohn Levon 	struct symbol *sym;
3291f5207b7SJohn Levon 
3301f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
3311f5207b7SJohn Levon 	if (param_was_set_var_sym(name, sym))
3321f5207b7SJohn Levon 		return 0;
3331f5207b7SJohn Levon 	return format_name_sym_helper(buf, remaining, name, sym);
3341f5207b7SJohn Levon }
3351f5207b7SJohn Levon 
format_call_to_param_mapping(char * buf,int remaining,struct expression * expr)3361f5207b7SJohn Levon static int format_call_to_param_mapping(char *buf, int remaining, struct expression *expr)
3371f5207b7SJohn Levon {
3381f5207b7SJohn Levon 	char *name;
3391f5207b7SJohn Levon 	struct symbol *sym;
3401f5207b7SJohn Levon 
3411f5207b7SJohn Levon 	name = map_call_to_param_name_sym(expr, &sym);
3421f5207b7SJohn Levon 	if (param_was_set_var_sym(name, sym))
3431f5207b7SJohn Levon 		return 0;
3441f5207b7SJohn Levon 	return format_name_sym_helper(buf, remaining, name, sym);
3451f5207b7SJohn Levon }
3461f5207b7SJohn Levon 
is_mtag_sval(sval_t sval)347efe51d0cSJohn Levon static int is_mtag_sval(sval_t sval)
348efe51d0cSJohn Levon {
349efe51d0cSJohn Levon 	if (!is_ptr_type(sval.type))
350efe51d0cSJohn Levon 		return 0;
351efe51d0cSJohn Levon 	if (sval_cmp(sval, valid_ptr_min_sval) >= 0 &&
352efe51d0cSJohn Levon 	    sval_cmp(sval, valid_ptr_max_sval) <= 0)
353efe51d0cSJohn Levon 		return 1;
354efe51d0cSJohn Levon 	return 0;
355efe51d0cSJohn Levon }
356efe51d0cSJohn Levon 
format_expr_helper(char * buf,int remaining,struct expression * expr)3571f5207b7SJohn Levon static int format_expr_helper(char *buf, int remaining, struct expression *expr)
3581f5207b7SJohn Levon {
3591f5207b7SJohn Levon 	sval_t sval;
3601f5207b7SJohn Levon 	int ret;
3611f5207b7SJohn Levon 	char *cur;
3621f5207b7SJohn Levon 
3631f5207b7SJohn Levon 	if (!expr)
3641f5207b7SJohn Levon 		return 0;
3651f5207b7SJohn Levon 
3661f5207b7SJohn Levon 	cur = buf;
3671f5207b7SJohn Levon 
3681f5207b7SJohn Levon 	if (expr->type == EXPR_BINOP) {
3691f5207b7SJohn Levon 		ret = format_expr_helper(cur, remaining, expr->left);
3701f5207b7SJohn Levon 		if (ret == 0)
3711f5207b7SJohn Levon 			return 0;
3721f5207b7SJohn Levon 		remaining -= ret;
3731f5207b7SJohn Levon 		if (remaining <= 0)
3741f5207b7SJohn Levon 			return 0;
3751f5207b7SJohn Levon 		cur += ret;
3761f5207b7SJohn Levon 
3771f5207b7SJohn Levon 		ret = snprintf(cur, remaining, " %s ", show_special(expr->op));
3781f5207b7SJohn Levon 		remaining -= ret;
3791f5207b7SJohn Levon 		if (remaining <= 0)
3801f5207b7SJohn Levon 			return 0;
3811f5207b7SJohn Levon 		cur += ret;
3821f5207b7SJohn Levon 
3831f5207b7SJohn Levon 		ret = format_expr_helper(cur, remaining, expr->right);
3841f5207b7SJohn Levon 		if (ret == 0)
3851f5207b7SJohn Levon 			return 0;
3861f5207b7SJohn Levon 		remaining -= ret;
3871f5207b7SJohn Levon 		if (remaining <= 0)
3881f5207b7SJohn Levon 			return 0;
3891f5207b7SJohn Levon 		cur += ret;
3901f5207b7SJohn Levon 		return cur - buf;
3911f5207b7SJohn Levon 	}
3921f5207b7SJohn Levon 
393efe51d0cSJohn Levon 	if (!param_was_set(expr) && get_implied_value(expr, &sval) && !is_mtag_sval(sval)) {
3941f5207b7SJohn Levon 		ret = snprintf(cur, remaining, "%s", sval_to_str(sval));
3951f5207b7SJohn Levon 		remaining -= ret;
3961f5207b7SJohn Levon 		if (remaining <= 0)
3971f5207b7SJohn Levon 			return 0;
3981f5207b7SJohn Levon 		return ret;
3991f5207b7SJohn Levon 	}
4001f5207b7SJohn Levon 
4011f5207b7SJohn Levon 	if (expr->type == EXPR_CALL)
4021f5207b7SJohn Levon 		return format_call_to_param_mapping(cur, remaining, expr);
4031f5207b7SJohn Levon 
4041f5207b7SJohn Levon 	return format_variable_helper(cur, remaining, expr);
4051f5207b7SJohn Levon }
4061f5207b7SJohn Levon 
format_expr(struct expression * expr)4071f5207b7SJohn Levon static char *format_expr(struct expression *expr)
4081f5207b7SJohn Levon {
4091f5207b7SJohn Levon 	char buf[256] = "";
4101f5207b7SJohn Levon 	int ret;
4111f5207b7SJohn Levon 
4121f5207b7SJohn Levon 	ret = format_expr_helper(buf, sizeof(buf), expr);
4131f5207b7SJohn Levon 	if (ret == 0)
4141f5207b7SJohn Levon 		return NULL;
4151f5207b7SJohn Levon 
4161f5207b7SJohn Levon 	return alloc_sname(buf);
4171f5207b7SJohn Levon }
4181f5207b7SJohn Levon 
get_value_in_terms_of_parameter_math(struct expression * expr)4191f5207b7SJohn Levon char *get_value_in_terms_of_parameter_math(struct expression *expr)
4201f5207b7SJohn Levon {
4211f5207b7SJohn Levon 	struct expression *tmp;
4221f5207b7SJohn Levon 	char buf[256] = "";
4231f5207b7SJohn Levon 	sval_t dummy;
4241f5207b7SJohn Levon 	int ret;
4251f5207b7SJohn Levon 
4261f5207b7SJohn Levon 	tmp = get_assigned_expr(expr);
4271f5207b7SJohn Levon 	if (tmp)
4281f5207b7SJohn Levon 		expr = tmp;
4291f5207b7SJohn Levon 	if (param_was_set(expr))
4301f5207b7SJohn Levon 		return NULL;
4311f5207b7SJohn Levon 
4321f5207b7SJohn Levon 	if (get_implied_value(expr, &dummy))
4331f5207b7SJohn Levon 		return NULL;
4341f5207b7SJohn Levon 
4351f5207b7SJohn Levon 	ret = format_expr_helper(buf, sizeof(buf), expr);
4361f5207b7SJohn Levon 	if (ret == 0)
4371f5207b7SJohn Levon 		return NULL;
4381f5207b7SJohn Levon 
4391f5207b7SJohn Levon 	return alloc_sname(buf);
4401f5207b7SJohn Levon }
4411f5207b7SJohn Levon 
get_value_in_terms_of_parameter_math_var_sym(const char * name,struct symbol * sym)4421f5207b7SJohn Levon char *get_value_in_terms_of_parameter_math_var_sym(const char *name, struct symbol *sym)
4431f5207b7SJohn Levon {
4441f5207b7SJohn Levon 	struct expression *tmp, *expr;
4451f5207b7SJohn Levon 	char buf[256] = "";
4461f5207b7SJohn Levon 	int ret;
4471f5207b7SJohn Levon 	int cnt = 0;
448efe51d0cSJohn Levon 	sval_t sval;
4491f5207b7SJohn Levon 
4501f5207b7SJohn Levon 	expr = get_assigned_expr_name_sym(name, sym);
4511f5207b7SJohn Levon 	if (!expr)
4521f5207b7SJohn Levon 		return NULL;
4531f5207b7SJohn Levon 	while ((tmp = get_assigned_expr(expr))) {
4541f5207b7SJohn Levon 		expr = strip_expr(tmp);
4551f5207b7SJohn Levon 		if (++cnt > 3)
4561f5207b7SJohn Levon 			break;
4571f5207b7SJohn Levon 	}
4581f5207b7SJohn Levon 
459efe51d0cSJohn Levon 	if (get_implied_value(expr, &sval))
460efe51d0cSJohn Levon 		return NULL;
461efe51d0cSJohn Levon 
4621f5207b7SJohn Levon 	ret = format_expr_helper(buf, sizeof(buf), expr);
4631f5207b7SJohn Levon 	if (ret == 0)
4641f5207b7SJohn Levon 		return NULL;
4651f5207b7SJohn Levon 
4661f5207b7SJohn Levon 	return alloc_sname(buf);
4671f5207b7SJohn Levon 
4681f5207b7SJohn Levon }
4691f5207b7SJohn Levon 
match_alloc(const char * fn,struct expression * expr,void * _size_arg)4701f5207b7SJohn Levon static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
4711f5207b7SJohn Levon {
4721f5207b7SJohn Levon 	int size_arg = PTR_INT(_size_arg);
4731f5207b7SJohn Levon 	struct expression *right;
4741f5207b7SJohn Levon 	struct expression *size_expr;
4751f5207b7SJohn Levon 	char *sname;
4761f5207b7SJohn Levon 
4771f5207b7SJohn Levon 	right = strip_expr(expr->right);
4781f5207b7SJohn Levon 	size_expr = get_argument_from_call_expr(right->args, size_arg);
4791f5207b7SJohn Levon 
4801f5207b7SJohn Levon 	sname = format_expr(size_expr);
4811f5207b7SJohn Levon 	if (!sname)
4821f5207b7SJohn Levon 		return;
4831f5207b7SJohn Levon 	set_state_expr(my_id, expr->left, alloc_state_sname(sname));
4841f5207b7SJohn Levon }
4851f5207b7SJohn Levon 
swap_format(struct expression * call,char * format)4861f5207b7SJohn Levon static char *swap_format(struct expression *call, char *format)
4871f5207b7SJohn Levon {
4881f5207b7SJohn Levon 	char buf[256];
4891f5207b7SJohn Levon 	sval_t sval;
4901f5207b7SJohn Levon 	long param;
4911f5207b7SJohn Levon 	struct expression *arg;
4921f5207b7SJohn Levon 	char *p;
4931f5207b7SJohn Levon 	char *out;
4941f5207b7SJohn Levon 	int ret;
4951f5207b7SJohn Levon 
4961f5207b7SJohn Levon 	if (format[0] == '$' && format[2] == '\0') {
4971f5207b7SJohn Levon 		param = strtol(format + 1, NULL, 10);
4981f5207b7SJohn Levon 		arg = get_argument_from_call_expr(call->args, param);
4991f5207b7SJohn Levon 		if (!arg)
5001f5207b7SJohn Levon 			return NULL;
5011f5207b7SJohn Levon 		return format_expr(arg);
5021f5207b7SJohn Levon 	}
5031f5207b7SJohn Levon 
5041f5207b7SJohn Levon 	buf[0] = '\0';
5051f5207b7SJohn Levon 	p = format;
5061f5207b7SJohn Levon 	out = buf;
5071f5207b7SJohn Levon 	while (*p) {
5081f5207b7SJohn Levon 		if (*p == '$') {
5091f5207b7SJohn Levon 			p++;
510efe51d0cSJohn Levon 			param = strtol(p, (char **)&p, 10);
5111f5207b7SJohn Levon 			arg = get_argument_from_call_expr(call->args, param);
5121f5207b7SJohn Levon 			if (!arg)
5131f5207b7SJohn Levon 				return NULL;
5141f5207b7SJohn Levon 			param = get_arg_number(arg);
5151f5207b7SJohn Levon 			if (param >= 0) {
5161f5207b7SJohn Levon 				ret = snprintf(out, buf + sizeof(buf) - out, "$%ld", param);
5171f5207b7SJohn Levon 				out += ret;
5181f5207b7SJohn Levon 				if (out >= buf + sizeof(buf))
5191f5207b7SJohn Levon 					return NULL;
5201f5207b7SJohn Levon 			} else if (get_implied_value(arg, &sval)) {
5211f5207b7SJohn Levon 				ret = snprintf(out, buf + sizeof(buf) - out, "%s", sval_to_str(sval));
5221f5207b7SJohn Levon 				out += ret;
5231f5207b7SJohn Levon 				if (out >= buf + sizeof(buf))
5241f5207b7SJohn Levon 					return NULL;
5251f5207b7SJohn Levon 			} else {
5261f5207b7SJohn Levon 				return NULL;
5271f5207b7SJohn Levon 			}
5281f5207b7SJohn Levon 		}
5291f5207b7SJohn Levon 		*out = *p;
5301f5207b7SJohn Levon 		p++;
5311f5207b7SJohn Levon 		out++;
5321f5207b7SJohn Levon 	}
5331f5207b7SJohn Levon 	if (buf[0] == '\0')
5341f5207b7SJohn Levon 		return NULL;
5351f5207b7SJohn Levon 	*out = '\0';
5361f5207b7SJohn Levon 	return alloc_sname(buf);
5371f5207b7SJohn Levon }
5381f5207b7SJohn Levon 
5391f5207b7SJohn Levon static char *buf_size_recipe;
db_buf_size_callback(void * unused,int argc,char ** argv,char ** azColName)5401f5207b7SJohn Levon static int db_buf_size_callback(void *unused, int argc, char **argv, char **azColName)
5411f5207b7SJohn Levon {
5421f5207b7SJohn Levon 	if (argc != 1)
5431f5207b7SJohn Levon 		return 0;
5441f5207b7SJohn Levon 
5451f5207b7SJohn Levon 	if (!buf_size_recipe)
5461f5207b7SJohn Levon 		buf_size_recipe = alloc_sname(argv[0]);
5471f5207b7SJohn Levon 	else if (strcmp(buf_size_recipe, argv[0]) != 0)
5481f5207b7SJohn Levon 		buf_size_recipe = alloc_sname("invalid");
5491f5207b7SJohn Levon 	return 0;
5501f5207b7SJohn Levon }
5511f5207b7SJohn Levon 
get_allocation_recipe_from_call(struct expression * expr)5521f5207b7SJohn Levon static char *get_allocation_recipe_from_call(struct expression *expr)
5531f5207b7SJohn Levon {
5541f5207b7SJohn Levon 	struct symbol *sym;
5551f5207b7SJohn Levon 	static char sql_filter[1024];
5561f5207b7SJohn Levon 	int i;
5571f5207b7SJohn Levon 
5581f5207b7SJohn Levon 	if (is_fake_call(expr))
5591f5207b7SJohn Levon 		return NULL;
5601f5207b7SJohn Levon 	expr = strip_expr(expr);
5611f5207b7SJohn Levon 	if (expr->fn->type != EXPR_SYMBOL)
5621f5207b7SJohn Levon 		return NULL;
5631f5207b7SJohn Levon 	sym = expr->fn->symbol;
5641f5207b7SJohn Levon 	if (!sym)
5651f5207b7SJohn Levon 		return NULL;
5661f5207b7SJohn Levon 
5671f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(alloc_functions); i++) {
5681f5207b7SJohn Levon 		if (strcmp(sym->ident->name, alloc_functions[i].func) == 0) {
5691f5207b7SJohn Levon 			char buf[32];
5701f5207b7SJohn Levon 
5711f5207b7SJohn Levon 			snprintf(buf, sizeof(buf), "$%d", alloc_functions[i].param);
5721f5207b7SJohn Levon 			buf_size_recipe = alloc_sname(buf);
5731f5207b7SJohn Levon 			return swap_format(expr, buf_size_recipe);
5741f5207b7SJohn Levon 		}
5751f5207b7SJohn Levon 	}
5761f5207b7SJohn Levon 
5771f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_STATIC) {
5781f5207b7SJohn Levon 		snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
5791f5207b7SJohn Levon 			 get_filename(), sym->ident->name);
5801f5207b7SJohn Levon 	} else {
5811f5207b7SJohn Levon 		snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
5821f5207b7SJohn Levon 				sym->ident->name);
5831f5207b7SJohn Levon 	}
5841f5207b7SJohn Levon 
5851f5207b7SJohn Levon 	buf_size_recipe = NULL;
5861f5207b7SJohn Levon 	run_sql(db_buf_size_callback, NULL,
5871f5207b7SJohn Levon 		"select value from return_states where type=%d and %s",
5881f5207b7SJohn Levon 		BUF_SIZE, sql_filter);
5891f5207b7SJohn Levon 	if (!buf_size_recipe || strcmp(buf_size_recipe, "invalid") == 0)
5901f5207b7SJohn Levon 		return NULL;
591*c85f09ccSJohn Levon 	/* Known sizes should be handled in smatch_buf_size.c */
592*c85f09ccSJohn Levon 	if (!strchr(buf_size_recipe, '$'))
593*c85f09ccSJohn Levon 		return NULL;
5941f5207b7SJohn Levon 	return swap_format(expr, buf_size_recipe);
5951f5207b7SJohn Levon }
5961f5207b7SJohn Levon 
match_call_assignment(struct expression * expr)5971f5207b7SJohn Levon static void match_call_assignment(struct expression *expr)
5981f5207b7SJohn Levon {
5991f5207b7SJohn Levon 	char *sname;
6001f5207b7SJohn Levon 
6011f5207b7SJohn Levon 	sname = get_allocation_recipe_from_call(expr->right);
6021f5207b7SJohn Levon 	if (!sname)
6031f5207b7SJohn Levon 		return;
6041f5207b7SJohn Levon 	set_state_expr(my_id, expr->left, alloc_state_sname(sname));
6051f5207b7SJohn Levon }
6061f5207b7SJohn Levon 
get_allocation_math(struct expression * expr)607*c85f09ccSJohn Levon const char *get_allocation_math(struct expression *expr)
6081f5207b7SJohn Levon {
6091f5207b7SJohn Levon 	struct expression *tmp;
6101f5207b7SJohn Levon 	struct smatch_state *state;
6111f5207b7SJohn Levon 	int cnt = 0;
6121f5207b7SJohn Levon 
6131f5207b7SJohn Levon 	expr = strip_expr(expr);
6141f5207b7SJohn Levon 	while ((tmp = get_assigned_expr(expr))) {
6151f5207b7SJohn Levon 		if (cnt++ > 5)  /* assignments to self cause infinite loops */
6161f5207b7SJohn Levon 			break;
6171f5207b7SJohn Levon 		expr = strip_expr(tmp);
6181f5207b7SJohn Levon 	}
6191f5207b7SJohn Levon 	if (!expr)
620*c85f09ccSJohn Levon 		return NULL;
6211f5207b7SJohn Levon 
622*c85f09ccSJohn Levon 	if (expr->type == EXPR_CALL)
623*c85f09ccSJohn Levon 		return get_allocation_recipe_from_call(expr);
6241f5207b7SJohn Levon 
625*c85f09ccSJohn Levon 	state = get_state_expr(my_id, expr);
6261f5207b7SJohn Levon 	if (!state || !state->data)
627*c85f09ccSJohn Levon 		return NULL;
6281f5207b7SJohn Levon 
629*c85f09ccSJohn Levon 	return state->name;
6301f5207b7SJohn Levon }
6311f5207b7SJohn Levon 
register_parse_call_math(int id)6321f5207b7SJohn Levon void register_parse_call_math(int id)
6331f5207b7SJohn Levon {
6341f5207b7SJohn Levon 	int i;
6351f5207b7SJohn Levon 
6361f5207b7SJohn Levon 	my_id = id;
6371f5207b7SJohn Levon 
638efe51d0cSJohn Levon 	set_dynamic_states(my_id);
639efe51d0cSJohn Levon 
6401f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(alloc_functions); i++)
6411f5207b7SJohn Levon 		add_function_assign_hook(alloc_functions[i].func, &match_alloc,
6421f5207b7SJohn Levon 				         INT_PTR(alloc_functions[i].param));
6431f5207b7SJohn Levon 	add_hook(&match_call_assignment, CALL_ASSIGNMENT_HOOK);
6441f5207b7SJohn Levon }
6451f5207b7SJohn Levon 
646