11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2009 Dan Carpenter.
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 /*
191f5207b7SJohn Levon  * The idea here is that you have an expression and you
201f5207b7SJohn Levon  * want to know what the type is for that.
211f5207b7SJohn Levon  */
221f5207b7SJohn Levon 
231f5207b7SJohn Levon #include "smatch.h"
241f5207b7SJohn Levon #include "smatch_slist.h"
251f5207b7SJohn Levon 
261f5207b7SJohn Levon struct symbol *get_real_base_type(struct symbol *sym)
271f5207b7SJohn Levon {
281f5207b7SJohn Levon 	struct symbol *ret;
291f5207b7SJohn Levon 
301f5207b7SJohn Levon 	if (!sym)
311f5207b7SJohn Levon 		return NULL;
32*efe51d0cSJohn Levon 	if (sym->type == SYM_BASETYPE)
33*efe51d0cSJohn Levon 		return sym;
341f5207b7SJohn Levon 	ret = get_base_type(sym);
351f5207b7SJohn Levon 	if (!ret)
361f5207b7SJohn Levon 		return NULL;
371f5207b7SJohn Levon 	if (ret->type == SYM_RESTRICT || ret->type == SYM_NODE)
381f5207b7SJohn Levon 		return get_real_base_type(ret);
391f5207b7SJohn Levon 	return ret;
401f5207b7SJohn Levon }
411f5207b7SJohn Levon 
421f5207b7SJohn Levon int type_bytes(struct symbol *type)
431f5207b7SJohn Levon {
441f5207b7SJohn Levon 	int bits;
451f5207b7SJohn Levon 
461f5207b7SJohn Levon 	if (type && type->type == SYM_ARRAY)
471f5207b7SJohn Levon 		return array_bytes(type);
481f5207b7SJohn Levon 
491f5207b7SJohn Levon 	bits = type_bits(type);
501f5207b7SJohn Levon 	if (bits < 0)
511f5207b7SJohn Levon 		return 0;
521f5207b7SJohn Levon 	return bits_to_bytes(bits);
531f5207b7SJohn Levon }
541f5207b7SJohn Levon 
551f5207b7SJohn Levon int array_bytes(struct symbol *type)
561f5207b7SJohn Levon {
571f5207b7SJohn Levon 	if (!type || type->type != SYM_ARRAY)
581f5207b7SJohn Levon 		return 0;
591f5207b7SJohn Levon 	return bits_to_bytes(type->bit_size);
601f5207b7SJohn Levon }
611f5207b7SJohn Levon 
621f5207b7SJohn Levon static struct symbol *get_binop_type(struct expression *expr)
631f5207b7SJohn Levon {
641f5207b7SJohn Levon 	struct symbol *left, *right;
651f5207b7SJohn Levon 
661f5207b7SJohn Levon 	left = get_type(expr->left);
671f5207b7SJohn Levon 	if (!left)
681f5207b7SJohn Levon 		return NULL;
691f5207b7SJohn Levon 
701f5207b7SJohn Levon 	if (expr->op == SPECIAL_LEFTSHIFT ||
711f5207b7SJohn Levon 	    expr->op == SPECIAL_RIGHTSHIFT) {
721f5207b7SJohn Levon 		if (type_positive_bits(left) < 31)
731f5207b7SJohn Levon 			return &int_ctype;
741f5207b7SJohn Levon 		return left;
751f5207b7SJohn Levon 	}
761f5207b7SJohn Levon 	right = get_type(expr->right);
771f5207b7SJohn Levon 	if (!right)
781f5207b7SJohn Levon 		return NULL;
791f5207b7SJohn Levon 
80*efe51d0cSJohn Levon 	if (expr->op == '-' &&
81*efe51d0cSJohn Levon 	    (is_ptr_type(left) && is_ptr_type(right)))
82*efe51d0cSJohn Levon 		return ssize_t_ctype;
83*efe51d0cSJohn Levon 
841f5207b7SJohn Levon 	if (left->type == SYM_PTR || left->type == SYM_ARRAY)
851f5207b7SJohn Levon 		return left;
861f5207b7SJohn Levon 	if (right->type == SYM_PTR || right->type == SYM_ARRAY)
871f5207b7SJohn Levon 		return right;
881f5207b7SJohn Levon 
891f5207b7SJohn Levon 	if (type_positive_bits(left) < 31 && type_positive_bits(right) < 31)
901f5207b7SJohn Levon 		return &int_ctype;
911f5207b7SJohn Levon 
921f5207b7SJohn Levon 	if (type_positive_bits(left) > type_positive_bits(right))
931f5207b7SJohn Levon 		return left;
941f5207b7SJohn Levon 	return right;
951f5207b7SJohn Levon }
961f5207b7SJohn Levon 
971f5207b7SJohn Levon static struct symbol *get_type_symbol(struct expression *expr)
981f5207b7SJohn Levon {
991f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_SYMBOL || !expr->symbol)
1001f5207b7SJohn Levon 		return NULL;
1011f5207b7SJohn Levon 
1021f5207b7SJohn Levon 	return get_real_base_type(expr->symbol);
1031f5207b7SJohn Levon }
1041f5207b7SJohn Levon 
1051f5207b7SJohn Levon static struct symbol *get_member_symbol(struct symbol_list *symbol_list, struct ident *member)
1061f5207b7SJohn Levon {
1071f5207b7SJohn Levon 	struct symbol *tmp, *sub;
1081f5207b7SJohn Levon 
1091f5207b7SJohn Levon 	FOR_EACH_PTR(symbol_list, tmp) {
1101f5207b7SJohn Levon 		if (!tmp->ident) {
1111f5207b7SJohn Levon 			sub = get_real_base_type(tmp);
1121f5207b7SJohn Levon 			sub = get_member_symbol(sub->symbol_list, member);
1131f5207b7SJohn Levon 			if (sub)
1141f5207b7SJohn Levon 				return sub;
1151f5207b7SJohn Levon 			continue;
1161f5207b7SJohn Levon 		}
1171f5207b7SJohn Levon 		if (tmp->ident == member)
1181f5207b7SJohn Levon 			return tmp;
1191f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
1201f5207b7SJohn Levon 
1211f5207b7SJohn Levon 	return NULL;
1221f5207b7SJohn Levon }
1231f5207b7SJohn Levon 
1241f5207b7SJohn Levon static struct symbol *get_symbol_from_deref(struct expression *expr)
1251f5207b7SJohn Levon {
1261f5207b7SJohn Levon 	struct ident *member;
1271f5207b7SJohn Levon 	struct symbol *sym;
1281f5207b7SJohn Levon 
1291f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_DEREF)
1301f5207b7SJohn Levon 		return NULL;
1311f5207b7SJohn Levon 
1321f5207b7SJohn Levon 	member = expr->member;
1331f5207b7SJohn Levon 	sym = get_type(expr->deref);
1341f5207b7SJohn Levon 	if (!sym) {
1351f5207b7SJohn Levon 		// sm_msg("could not find struct type");
1361f5207b7SJohn Levon 		return NULL;
1371f5207b7SJohn Levon 	}
1381f5207b7SJohn Levon 	if (sym->type == SYM_PTR)
1391f5207b7SJohn Levon 		sym = get_real_base_type(sym);
1401f5207b7SJohn Levon 	sym = get_member_symbol(sym->symbol_list, member);
1411f5207b7SJohn Levon 	if (!sym)
1421f5207b7SJohn Levon 		return NULL;
1431f5207b7SJohn Levon 	return get_real_base_type(sym);
1441f5207b7SJohn Levon }
1451f5207b7SJohn Levon 
1461f5207b7SJohn Levon static struct symbol *get_return_type(struct expression *expr)
1471f5207b7SJohn Levon {
1481f5207b7SJohn Levon 	struct symbol *tmp;
1491f5207b7SJohn Levon 
1501f5207b7SJohn Levon 	tmp = get_type(expr->fn);
1511f5207b7SJohn Levon 	if (!tmp)
1521f5207b7SJohn Levon 		return NULL;
1531f5207b7SJohn Levon 	/* this is to handle __builtin_constant_p() */
1541f5207b7SJohn Levon 	if (tmp->type != SYM_FN)
1551f5207b7SJohn Levon 		tmp = get_base_type(tmp);
1561f5207b7SJohn Levon 	return get_real_base_type(tmp);
1571f5207b7SJohn Levon }
1581f5207b7SJohn Levon 
1591f5207b7SJohn Levon static struct symbol *get_expr_stmt_type(struct statement *stmt)
1601f5207b7SJohn Levon {
1611f5207b7SJohn Levon 	if (stmt->type != STMT_COMPOUND)
1621f5207b7SJohn Levon 		return NULL;
1631f5207b7SJohn Levon 	stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
1641f5207b7SJohn Levon 	if (stmt->type == STMT_LABEL)
1651f5207b7SJohn Levon 		stmt = stmt->label_statement;
1661f5207b7SJohn Levon 	if (stmt->type != STMT_EXPRESSION)
1671f5207b7SJohn Levon 		return NULL;
1681f5207b7SJohn Levon 	return get_type(stmt->expression);
1691f5207b7SJohn Levon }
1701f5207b7SJohn Levon 
1711f5207b7SJohn Levon static struct symbol *get_select_type(struct expression *expr)
1721f5207b7SJohn Levon {
1731f5207b7SJohn Levon 	struct symbol *one, *two;
1741f5207b7SJohn Levon 
1751f5207b7SJohn Levon 	one = get_type(expr->cond_true);
1761f5207b7SJohn Levon 	two = get_type(expr->cond_false);
1771f5207b7SJohn Levon 	if (!one || !two)
1781f5207b7SJohn Levon 		return NULL;
1791f5207b7SJohn Levon 	/*
1801f5207b7SJohn Levon 	 * This is a hack.  If the types are not equiv then we
1811f5207b7SJohn Levon 	 * really don't know the type.  But I think guessing is
1821f5207b7SJohn Levon 	 *  probably Ok here.
1831f5207b7SJohn Levon 	 */
1841f5207b7SJohn Levon 	if (type_positive_bits(one) > type_positive_bits(two))
1851f5207b7SJohn Levon 		return one;
1861f5207b7SJohn Levon 	return two;
1871f5207b7SJohn Levon }
1881f5207b7SJohn Levon 
1891f5207b7SJohn Levon struct symbol *get_pointer_type(struct expression *expr)
1901f5207b7SJohn Levon {
1911f5207b7SJohn Levon 	struct symbol *sym;
1921f5207b7SJohn Levon 
1931f5207b7SJohn Levon 	sym = get_type(expr);
1941f5207b7SJohn Levon 	if (!sym)
1951f5207b7SJohn Levon 		return NULL;
1961f5207b7SJohn Levon 	if (sym->type == SYM_NODE) {
1971f5207b7SJohn Levon 		sym = get_real_base_type(sym);
1981f5207b7SJohn Levon 		if (!sym)
1991f5207b7SJohn Levon 			return NULL;
2001f5207b7SJohn Levon 	}
2011f5207b7SJohn Levon 	if (sym->type != SYM_PTR && sym->type != SYM_ARRAY)
2021f5207b7SJohn Levon 		return NULL;
2031f5207b7SJohn Levon 	return get_real_base_type(sym);
2041f5207b7SJohn Levon }
2051f5207b7SJohn Levon 
2061f5207b7SJohn Levon static struct symbol *fake_pointer_sym(struct expression *expr)
2071f5207b7SJohn Levon {
2081f5207b7SJohn Levon 	struct symbol *sym;
2091f5207b7SJohn Levon 	struct symbol *base;
2101f5207b7SJohn Levon 
2111f5207b7SJohn Levon 	sym = alloc_symbol(expr->pos, SYM_PTR);
2121f5207b7SJohn Levon 	expr = expr->unop;
2131f5207b7SJohn Levon 	base = get_type(expr);
2141f5207b7SJohn Levon 	if (!base)
2151f5207b7SJohn Levon 		return NULL;
2161f5207b7SJohn Levon 	sym->ctype.base_type = base;
2171f5207b7SJohn Levon 	return sym;
2181f5207b7SJohn Levon }
2191f5207b7SJohn Levon 
2201f5207b7SJohn Levon static struct symbol *get_type_helper(struct expression *expr)
2211f5207b7SJohn Levon {
2221f5207b7SJohn Levon 	struct symbol *ret;
2231f5207b7SJohn Levon 
2241f5207b7SJohn Levon 	expr = strip_parens(expr);
2251f5207b7SJohn Levon 	if (!expr)
2261f5207b7SJohn Levon 		return NULL;
2271f5207b7SJohn Levon 
2281f5207b7SJohn Levon 	if (expr->ctype)
2291f5207b7SJohn Levon 		return expr->ctype;
2301f5207b7SJohn Levon 
2311f5207b7SJohn Levon 	switch (expr->type) {
2321f5207b7SJohn Levon 	case EXPR_STRING:
2331f5207b7SJohn Levon 		ret = &string_ctype;
2341f5207b7SJohn Levon 		break;
2351f5207b7SJohn Levon 	case EXPR_SYMBOL:
2361f5207b7SJohn Levon 		ret = get_type_symbol(expr);
2371f5207b7SJohn Levon 		break;
2381f5207b7SJohn Levon 	case EXPR_DEREF:
2391f5207b7SJohn Levon 		ret = get_symbol_from_deref(expr);
2401f5207b7SJohn Levon 		break;
2411f5207b7SJohn Levon 	case EXPR_PREOP:
2421f5207b7SJohn Levon 	case EXPR_POSTOP:
2431f5207b7SJohn Levon 		if (expr->op == '&')
2441f5207b7SJohn Levon 			ret = fake_pointer_sym(expr);
2451f5207b7SJohn Levon 		else if (expr->op == '*')
2461f5207b7SJohn Levon 			ret = get_pointer_type(expr->unop);
2471f5207b7SJohn Levon 		else
2481f5207b7SJohn Levon 			ret = get_type(expr->unop);
2491f5207b7SJohn Levon 		break;
2501f5207b7SJohn Levon 	case EXPR_ASSIGNMENT:
2511f5207b7SJohn Levon 		ret = get_type(expr->left);
2521f5207b7SJohn Levon 		break;
2531f5207b7SJohn Levon 	case EXPR_CAST:
2541f5207b7SJohn Levon 	case EXPR_FORCE_CAST:
2551f5207b7SJohn Levon 	case EXPR_IMPLIED_CAST:
2561f5207b7SJohn Levon 		ret = get_real_base_type(expr->cast_type);
2571f5207b7SJohn Levon 		break;
2581f5207b7SJohn Levon 	case EXPR_COMPARE:
2591f5207b7SJohn Levon 	case EXPR_BINOP:
2601f5207b7SJohn Levon 		ret = get_binop_type(expr);
2611f5207b7SJohn Levon 		break;
2621f5207b7SJohn Levon 	case EXPR_CALL:
2631f5207b7SJohn Levon 		ret = get_return_type(expr);
2641f5207b7SJohn Levon 		break;
2651f5207b7SJohn Levon 	case EXPR_STATEMENT:
2661f5207b7SJohn Levon 		ret = get_expr_stmt_type(expr->statement);
2671f5207b7SJohn Levon 		break;
2681f5207b7SJohn Levon 	case EXPR_CONDITIONAL:
2691f5207b7SJohn Levon 	case EXPR_SELECT:
2701f5207b7SJohn Levon 		ret = get_select_type(expr);
2711f5207b7SJohn Levon 		break;
2721f5207b7SJohn Levon 	case EXPR_SIZEOF:
2731f5207b7SJohn Levon 		ret = &ulong_ctype;
2741f5207b7SJohn Levon 		break;
2751f5207b7SJohn Levon 	case EXPR_LOGICAL:
2761f5207b7SJohn Levon 		ret = &int_ctype;
2771f5207b7SJohn Levon 		break;
278*efe51d0cSJohn Levon 	case EXPR_OFFSETOF:
279*efe51d0cSJohn Levon 		ret = &ulong_ctype;
280*efe51d0cSJohn Levon 		break;
2811f5207b7SJohn Levon 	default:
2821f5207b7SJohn Levon 		return NULL;
2831f5207b7SJohn Levon 	}
2841f5207b7SJohn Levon 
2851f5207b7SJohn Levon 	if (ret && ret->type == SYM_TYPEOF)
2861f5207b7SJohn Levon 		ret = get_type(ret->initializer);
2871f5207b7SJohn Levon 
2881f5207b7SJohn Levon 	expr->ctype = ret;
2891f5207b7SJohn Levon 	return ret;
2901f5207b7SJohn Levon }
2911f5207b7SJohn Levon 
2921f5207b7SJohn Levon static struct symbol *get_final_type_helper(struct expression *expr)
2931f5207b7SJohn Levon {
2941f5207b7SJohn Levon 	/*
295*efe51d0cSJohn Levon 	 * The problem is that I wrote a bunch of Smatch to think that
296*efe51d0cSJohn Levon 	 * you could do get_type() on an expression and it would give
297*efe51d0cSJohn Levon 	 * you what the comparison was type promoted to.  This is wrong
298*efe51d0cSJohn Levon 	 * but fixing it is a big of work...  Hence this horrible hack.
2991f5207b7SJohn Levon 	 *
3001f5207b7SJohn Levon 	 */
3011f5207b7SJohn Levon 
3021f5207b7SJohn Levon 	expr = strip_parens(expr);
3031f5207b7SJohn Levon 	if (!expr)
3041f5207b7SJohn Levon 		return NULL;
3051f5207b7SJohn Levon 
306*efe51d0cSJohn Levon 	if (expr->type == EXPR_COMPARE)
3071f5207b7SJohn Levon 		return &int_ctype;
3081f5207b7SJohn Levon 
3091f5207b7SJohn Levon 	return NULL;
3101f5207b7SJohn Levon }
3111f5207b7SJohn Levon 
3121f5207b7SJohn Levon struct symbol *get_type(struct expression *expr)
3131f5207b7SJohn Levon {
3141f5207b7SJohn Levon 	return get_type_helper(expr);
3151f5207b7SJohn Levon }
3161f5207b7SJohn Levon 
3171f5207b7SJohn Levon struct symbol *get_final_type(struct expression *expr)
3181f5207b7SJohn Levon {
3191f5207b7SJohn Levon 	struct symbol *ret;
3201f5207b7SJohn Levon 
3211f5207b7SJohn Levon 	ret = get_final_type_helper(expr);
3221f5207b7SJohn Levon 	if (ret)
3231f5207b7SJohn Levon 		return ret;
3241f5207b7SJohn Levon 	return get_type_helper(expr);
3251f5207b7SJohn Levon }
3261f5207b7SJohn Levon 
3271f5207b7SJohn Levon struct symbol *get_promoted_type(struct symbol *left, struct symbol *right)
3281f5207b7SJohn Levon {
3291f5207b7SJohn Levon 	struct symbol *ret = &int_ctype;
3301f5207b7SJohn Levon 
3311f5207b7SJohn Levon 	if (type_positive_bits(left) > type_positive_bits(ret))
3321f5207b7SJohn Levon 		ret = left;
3331f5207b7SJohn Levon 	if (type_positive_bits(right) > type_positive_bits(ret))
3341f5207b7SJohn Levon 		ret = right;
3351f5207b7SJohn Levon 
3361f5207b7SJohn Levon 	if (type_is_ptr(left))
3371f5207b7SJohn Levon 		ret = left;
3381f5207b7SJohn Levon 	if (type_is_ptr(right))
3391f5207b7SJohn Levon 		ret = right;
3401f5207b7SJohn Levon 
3411f5207b7SJohn Levon 	return ret;
3421f5207b7SJohn Levon }
3431f5207b7SJohn Levon 
3441f5207b7SJohn Levon int type_signed(struct symbol *base_type)
3451f5207b7SJohn Levon {
3461f5207b7SJohn Levon 	if (!base_type)
3471f5207b7SJohn Levon 		return 0;
3481f5207b7SJohn Levon 	if (base_type->ctype.modifiers & MOD_SIGNED)
3491f5207b7SJohn Levon 		return 1;
3501f5207b7SJohn Levon 	return 0;
3511f5207b7SJohn Levon }
3521f5207b7SJohn Levon 
3531f5207b7SJohn Levon int expr_unsigned(struct expression *expr)
3541f5207b7SJohn Levon {
3551f5207b7SJohn Levon 	struct symbol *sym;
3561f5207b7SJohn Levon 
3571f5207b7SJohn Levon 	sym = get_type(expr);
3581f5207b7SJohn Levon 	if (!sym)
3591f5207b7SJohn Levon 		return 0;
3601f5207b7SJohn Levon 	if (type_unsigned(sym))
3611f5207b7SJohn Levon 		return 1;
3621f5207b7SJohn Levon 	return 0;
3631f5207b7SJohn Levon }
3641f5207b7SJohn Levon 
3651f5207b7SJohn Levon int expr_signed(struct expression *expr)
3661f5207b7SJohn Levon {
3671f5207b7SJohn Levon 	struct symbol *sym;
3681f5207b7SJohn Levon 
3691f5207b7SJohn Levon 	sym = get_type(expr);
3701f5207b7SJohn Levon 	if (!sym)
3711f5207b7SJohn Levon 		return 0;
3721f5207b7SJohn Levon 	if (type_signed(sym))
3731f5207b7SJohn Levon 		return 1;
3741f5207b7SJohn Levon 	return 0;
3751f5207b7SJohn Levon }
3761f5207b7SJohn Levon 
3771f5207b7SJohn Levon int returns_unsigned(struct symbol *sym)
3781f5207b7SJohn Levon {
3791f5207b7SJohn Levon 	if (!sym)
3801f5207b7SJohn Levon 		return 0;
3811f5207b7SJohn Levon 	sym = get_base_type(sym);
3821f5207b7SJohn Levon 	if (!sym || sym->type != SYM_FN)
3831f5207b7SJohn Levon 		return 0;
3841f5207b7SJohn Levon 	sym = get_base_type(sym);
3851f5207b7SJohn Levon 	return type_unsigned(sym);
3861f5207b7SJohn Levon }
3871f5207b7SJohn Levon 
3881f5207b7SJohn Levon int is_pointer(struct expression *expr)
3891f5207b7SJohn Levon {
390*efe51d0cSJohn Levon 	return type_is_ptr(get_type(expr));
3911f5207b7SJohn Levon }
3921f5207b7SJohn Levon 
3931f5207b7SJohn Levon int returns_pointer(struct symbol *sym)
3941f5207b7SJohn Levon {
3951f5207b7SJohn Levon 	if (!sym)
3961f5207b7SJohn Levon 		return 0;
3971f5207b7SJohn Levon 	sym = get_base_type(sym);
3981f5207b7SJohn Levon 	if (!sym || sym->type != SYM_FN)
3991f5207b7SJohn Levon 		return 0;
4001f5207b7SJohn Levon 	sym = get_base_type(sym);
4011f5207b7SJohn Levon 	if (sym->type == SYM_PTR)
4021f5207b7SJohn Levon 		return 1;
4031f5207b7SJohn Levon 	return 0;
4041f5207b7SJohn Levon }
4051f5207b7SJohn Levon 
4061f5207b7SJohn Levon sval_t sval_type_max(struct symbol *base_type)
4071f5207b7SJohn Levon {
4081f5207b7SJohn Levon 	sval_t ret;
4091f5207b7SJohn Levon 
4101f5207b7SJohn Levon 	if (!base_type || !type_bits(base_type))
4111f5207b7SJohn Levon 		base_type = &llong_ctype;
4121f5207b7SJohn Levon 	ret.type = base_type;
4131f5207b7SJohn Levon 
4141f5207b7SJohn Levon 	ret.value = (~0ULL) >> (64 - type_positive_bits(base_type));
4151f5207b7SJohn Levon 	return ret;
4161f5207b7SJohn Levon }
4171f5207b7SJohn Levon 
4181f5207b7SJohn Levon sval_t sval_type_min(struct symbol *base_type)
4191f5207b7SJohn Levon {
4201f5207b7SJohn Levon 	sval_t ret;
4211f5207b7SJohn Levon 
4221f5207b7SJohn Levon 	if (!base_type || !type_bits(base_type))
4231f5207b7SJohn Levon 		base_type = &llong_ctype;
4241f5207b7SJohn Levon 	ret.type = base_type;
4251f5207b7SJohn Levon 
426*efe51d0cSJohn Levon 	if (type_unsigned(base_type) || is_ptr_type(base_type)) {
4271f5207b7SJohn Levon 		ret.value = 0;
4281f5207b7SJohn Levon 		return ret;
4291f5207b7SJohn Levon 	}
4301f5207b7SJohn Levon 
4311f5207b7SJohn Levon 	ret.value = (~0ULL) << type_positive_bits(base_type);
4321f5207b7SJohn Levon 
4331f5207b7SJohn Levon 	return ret;
4341f5207b7SJohn Levon }
4351f5207b7SJohn Levon 
4361f5207b7SJohn Levon int nr_bits(struct expression *expr)
4371f5207b7SJohn Levon {
4381f5207b7SJohn Levon 	struct symbol *type;
4391f5207b7SJohn Levon 
4401f5207b7SJohn Levon 	type = get_type(expr);
4411f5207b7SJohn Levon 	if (!type)
4421f5207b7SJohn Levon 		return 0;
4431f5207b7SJohn Levon 	return type_bits(type);
4441f5207b7SJohn Levon }
4451f5207b7SJohn Levon 
4461f5207b7SJohn Levon int is_void_pointer(struct expression *expr)
4471f5207b7SJohn Levon {
4481f5207b7SJohn Levon 	struct symbol *type;
4491f5207b7SJohn Levon 
4501f5207b7SJohn Levon 	type = get_type(expr);
4511f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
4521f5207b7SJohn Levon 		return 0;
4531f5207b7SJohn Levon 	type = get_real_base_type(type);
4541f5207b7SJohn Levon 	if (type == &void_ctype)
4551f5207b7SJohn Levon 		return 1;
4561f5207b7SJohn Levon 	return 0;
4571f5207b7SJohn Levon }
4581f5207b7SJohn Levon 
4591f5207b7SJohn Levon int is_char_pointer(struct expression *expr)
4601f5207b7SJohn Levon {
4611f5207b7SJohn Levon 	struct symbol *type;
4621f5207b7SJohn Levon 
4631f5207b7SJohn Levon 	type = get_type(expr);
4641f5207b7SJohn Levon 	if (!type || type->type != SYM_PTR)
4651f5207b7SJohn Levon 		return 0;
4661f5207b7SJohn Levon 	type = get_real_base_type(type);
4671f5207b7SJohn Levon 	if (type == &char_ctype)
4681f5207b7SJohn Levon 		return 1;
4691f5207b7SJohn Levon 	return 0;
4701f5207b7SJohn Levon }
4711f5207b7SJohn Levon 
4721f5207b7SJohn Levon int is_string(struct expression *expr)
4731f5207b7SJohn Levon {
4741f5207b7SJohn Levon 	expr = strip_expr(expr);
4751f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_STRING)
4761f5207b7SJohn Levon 		return 0;
4771f5207b7SJohn Levon 	if (expr->string)
4781f5207b7SJohn Levon 		return 1;
4791f5207b7SJohn Levon 	return 0;
4801f5207b7SJohn Levon }
4811f5207b7SJohn Levon 
4821f5207b7SJohn Levon int is_static(struct expression *expr)
4831f5207b7SJohn Levon {
4841f5207b7SJohn Levon 	char *name;
4851f5207b7SJohn Levon 	struct symbol *sym;
4861f5207b7SJohn Levon 	int ret = 0;
4871f5207b7SJohn Levon 
4881f5207b7SJohn Levon 	name = expr_to_str_sym(expr, &sym);
4891f5207b7SJohn Levon 	if (!name || !sym)
4901f5207b7SJohn Levon 		goto free;
4911f5207b7SJohn Levon 
4921f5207b7SJohn Levon 	if (sym->ctype.modifiers & MOD_STATIC)
4931f5207b7SJohn Levon 		ret = 1;
4941f5207b7SJohn Levon free:
4951f5207b7SJohn Levon 	free_string(name);
4961f5207b7SJohn Levon 	return ret;
4971f5207b7SJohn Levon }
4981f5207b7SJohn Levon 
4991f5207b7SJohn Levon int is_local_variable(struct expression *expr)
5001f5207b7SJohn Levon {
5011f5207b7SJohn Levon 	struct symbol *sym;
5021f5207b7SJohn Levon 	char *name;
5031f5207b7SJohn Levon 
5041f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
5051f5207b7SJohn Levon 	free_string(name);
5061f5207b7SJohn Levon 	if (!sym || !sym->scope || !sym->scope->token || !cur_func_sym)
5071f5207b7SJohn Levon 		return 0;
5081f5207b7SJohn Levon 	if (cmp_pos(sym->scope->token->pos, cur_func_sym->pos) < 0)
5091f5207b7SJohn Levon 		return 0;
5101f5207b7SJohn Levon 	if (is_static(expr))
5111f5207b7SJohn Levon 		return 0;
5121f5207b7SJohn Levon 	return 1;
5131f5207b7SJohn Levon }
5141f5207b7SJohn Levon 
5151f5207b7SJohn Levon int types_equiv(struct symbol *one, struct symbol *two)
5161f5207b7SJohn Levon {
5171f5207b7SJohn Levon 	if (!one && !two)
5181f5207b7SJohn Levon 		return 1;
5191f5207b7SJohn Levon 	if (!one || !two)
5201f5207b7SJohn Levon 		return 0;
5211f5207b7SJohn Levon 	if (one->type != two->type)
5221f5207b7SJohn Levon 		return 0;
5231f5207b7SJohn Levon 	if (one->type == SYM_PTR)
5241f5207b7SJohn Levon 		return types_equiv(get_real_base_type(one), get_real_base_type(two));
5251f5207b7SJohn Levon 	if (type_positive_bits(one) != type_positive_bits(two))
5261f5207b7SJohn Levon 		return 0;
5271f5207b7SJohn Levon 	return 1;
5281f5207b7SJohn Levon }
5291f5207b7SJohn Levon 
5301f5207b7SJohn Levon int fn_static(void)
5311f5207b7SJohn Levon {
5321f5207b7SJohn Levon 	return !!(cur_func_sym->ctype.modifiers & MOD_STATIC);
5331f5207b7SJohn Levon }
5341f5207b7SJohn Levon 
5351f5207b7SJohn Levon const char *global_static(void)
5361f5207b7SJohn Levon {
5371f5207b7SJohn Levon 	if (cur_func_sym->ctype.modifiers & MOD_STATIC)
5381f5207b7SJohn Levon 		return "static";
5391f5207b7SJohn Levon 	else
5401f5207b7SJohn Levon 		return "global";
5411f5207b7SJohn Levon }
5421f5207b7SJohn Levon 
5431f5207b7SJohn Levon struct symbol *cur_func_return_type(void)
5441f5207b7SJohn Levon {
5451f5207b7SJohn Levon 	struct symbol *sym;
5461f5207b7SJohn Levon 
5471f5207b7SJohn Levon 	sym = get_real_base_type(cur_func_sym);
5481f5207b7SJohn Levon 	if (!sym || sym->type != SYM_FN)
5491f5207b7SJohn Levon 		return NULL;
5501f5207b7SJohn Levon 	sym = get_real_base_type(sym);
5511f5207b7SJohn Levon 	return sym;
5521f5207b7SJohn Levon }
5531f5207b7SJohn Levon 
5541f5207b7SJohn Levon struct symbol *get_arg_type(struct expression *fn, int arg)
5551f5207b7SJohn Levon {
5561f5207b7SJohn Levon 	struct symbol *fn_type;
5571f5207b7SJohn Levon 	struct symbol *tmp;
5581f5207b7SJohn Levon 	struct symbol *arg_type;
5591f5207b7SJohn Levon 	int i;
5601f5207b7SJohn Levon 
5611f5207b7SJohn Levon 	fn_type = get_type(fn);
5621f5207b7SJohn Levon 	if (!fn_type)
5631f5207b7SJohn Levon 		return NULL;
5641f5207b7SJohn Levon 	if (fn_type->type == SYM_PTR)
5651f5207b7SJohn Levon 		fn_type = get_real_base_type(fn_type);
5661f5207b7SJohn Levon 	if (fn_type->type != SYM_FN)
5671f5207b7SJohn Levon 		return NULL;
5681f5207b7SJohn Levon 
5691f5207b7SJohn Levon 	i = 0;
5701f5207b7SJohn Levon 	FOR_EACH_PTR(fn_type->arguments, tmp) {
5711f5207b7SJohn Levon 		arg_type = get_real_base_type(tmp);
5721f5207b7SJohn Levon 		if (i == arg) {
5731f5207b7SJohn Levon 			return arg_type;
5741f5207b7SJohn Levon 		}
5751f5207b7SJohn Levon 		i++;
5761f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
5771f5207b7SJohn Levon 
5781f5207b7SJohn Levon 	return NULL;
5791f5207b7SJohn Levon }
5801f5207b7SJohn Levon 
5811f5207b7SJohn Levon static struct symbol *get_member_from_string(struct symbol_list *symbol_list, const char *name)
5821f5207b7SJohn Levon {
5831f5207b7SJohn Levon 	struct symbol *tmp, *sub;
5841f5207b7SJohn Levon 	int chunk_len;
5851f5207b7SJohn Levon 
5861f5207b7SJohn Levon 	if (strncmp(name, ".", 1) == 0)
5871f5207b7SJohn Levon 		name += 1;
588*efe51d0cSJohn Levon 	else if (strncmp(name, "->", 2) == 0)
5891f5207b7SJohn Levon 		name += 2;
5901f5207b7SJohn Levon 
5911f5207b7SJohn Levon 	FOR_EACH_PTR(symbol_list, tmp) {
5921f5207b7SJohn Levon 		if (!tmp->ident) {
5931f5207b7SJohn Levon 			sub = get_real_base_type(tmp);
5941f5207b7SJohn Levon 			sub = get_member_from_string(sub->symbol_list, name);
5951f5207b7SJohn Levon 			if (sub)
5961f5207b7SJohn Levon 				return sub;
5971f5207b7SJohn Levon 			continue;
5981f5207b7SJohn Levon 		}
5991f5207b7SJohn Levon 
6001f5207b7SJohn Levon 		if (strcmp(tmp->ident->name, name) == 0)
6011f5207b7SJohn Levon 			return tmp;
6021f5207b7SJohn Levon 
603*efe51d0cSJohn Levon 		chunk_len = tmp->ident->len;
6041f5207b7SJohn Levon 		if (strncmp(tmp->ident->name, name, chunk_len) == 0 &&
6051f5207b7SJohn Levon 		    (name[chunk_len] == '.' || name[chunk_len] == '-')) {
6061f5207b7SJohn Levon 			sub = get_real_base_type(tmp);
607*efe51d0cSJohn Levon 			if (sub->type == SYM_PTR)
608*efe51d0cSJohn Levon 				sub = get_real_base_type(sub);
6091f5207b7SJohn Levon 			return get_member_from_string(sub->symbol_list, name + chunk_len);
6101f5207b7SJohn Levon 		}
6111f5207b7SJohn Levon 
6121f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
6131f5207b7SJohn Levon 
6141f5207b7SJohn Levon 	return NULL;
6151f5207b7SJohn Levon }
6161f5207b7SJohn Levon 
6171f5207b7SJohn Levon struct symbol *get_member_type_from_key(struct expression *expr, const char *key)
6181f5207b7SJohn Levon {
6191f5207b7SJohn Levon 	struct symbol *sym;
6201f5207b7SJohn Levon 
6211f5207b7SJohn Levon 	if (strcmp(key, "$") == 0)
6221f5207b7SJohn Levon 		return get_type(expr);
6231f5207b7SJohn Levon 
6241f5207b7SJohn Levon 	if (strcmp(key, "*$") == 0) {
6251f5207b7SJohn Levon 		sym = get_type(expr);
6261f5207b7SJohn Levon 		if (!sym || sym->type != SYM_PTR)
6271f5207b7SJohn Levon 			return NULL;
6281f5207b7SJohn Levon 		return get_real_base_type(sym);
6291f5207b7SJohn Levon 	}
6301f5207b7SJohn Levon 
6311f5207b7SJohn Levon 	sym = get_type(expr);
6321f5207b7SJohn Levon 	if (!sym)
6331f5207b7SJohn Levon 		return NULL;
6341f5207b7SJohn Levon 	if (sym->type == SYM_PTR)
6351f5207b7SJohn Levon 		sym = get_real_base_type(sym);
6361f5207b7SJohn Levon 
6371f5207b7SJohn Levon 	key = key + 1;
6381f5207b7SJohn Levon 	sym = get_member_from_string(sym->symbol_list, key);
6391f5207b7SJohn Levon 	if (!sym)
6401f5207b7SJohn Levon 		return NULL;
6411f5207b7SJohn Levon 	return get_real_base_type(sym);
6421f5207b7SJohn Levon }
6431f5207b7SJohn Levon 
6441f5207b7SJohn Levon struct symbol *get_arg_type_from_key(struct expression *fn, int param, struct expression *arg, const char *key)
6451f5207b7SJohn Levon {
6461f5207b7SJohn Levon 	struct symbol *type;
6471f5207b7SJohn Levon 
6481f5207b7SJohn Levon 	if (!key)
6491f5207b7SJohn Levon 		return NULL;
6501f5207b7SJohn Levon 	if (strcmp(key, "$") == 0)
6511f5207b7SJohn Levon 		return get_arg_type(fn, param);
6521f5207b7SJohn Levon 	if (strcmp(key, "*$") == 0) {
6531f5207b7SJohn Levon 		type = get_arg_type(fn, param);
6541f5207b7SJohn Levon 		if (!type || type->type != SYM_PTR)
6551f5207b7SJohn Levon 			return NULL;
6561f5207b7SJohn Levon 		return get_real_base_type(type);
6571f5207b7SJohn Levon 	}
6581f5207b7SJohn Levon 	return get_member_type_from_key(arg, key);
6591f5207b7SJohn Levon }
6601f5207b7SJohn Levon 
6611f5207b7SJohn Levon int is_struct(struct expression *expr)
6621f5207b7SJohn Levon {
6631f5207b7SJohn Levon 	struct symbol *type;
6641f5207b7SJohn Levon 
6651f5207b7SJohn Levon 	type = get_type(expr);
6661f5207b7SJohn Levon 	if (type && type->type == SYM_STRUCT)
6671f5207b7SJohn Levon 		return 1;
6681f5207b7SJohn Levon 	return 0;
6691f5207b7SJohn Levon }
6701f5207b7SJohn Levon 
6711f5207b7SJohn Levon static struct {
6721f5207b7SJohn Levon 	struct symbol *sym;
6731f5207b7SJohn Levon 	const char *name;
6741f5207b7SJohn Levon } base_types[] = {
6751f5207b7SJohn Levon 	{&bool_ctype, "bool"},
6761f5207b7SJohn Levon 	{&void_ctype, "void"},
6771f5207b7SJohn Levon 	{&type_ctype, "type"},
6781f5207b7SJohn Levon 	{&char_ctype, "char"},
6791f5207b7SJohn Levon 	{&schar_ctype, "schar"},
6801f5207b7SJohn Levon 	{&uchar_ctype, "uchar"},
6811f5207b7SJohn Levon 	{&short_ctype, "short"},
6821f5207b7SJohn Levon 	{&sshort_ctype, "sshort"},
6831f5207b7SJohn Levon 	{&ushort_ctype, "ushort"},
6841f5207b7SJohn Levon 	{&int_ctype, "int"},
6851f5207b7SJohn Levon 	{&sint_ctype, "sint"},
6861f5207b7SJohn Levon 	{&uint_ctype, "uint"},
6871f5207b7SJohn Levon 	{&long_ctype, "long"},
6881f5207b7SJohn Levon 	{&slong_ctype, "slong"},
6891f5207b7SJohn Levon 	{&ulong_ctype, "ulong"},
6901f5207b7SJohn Levon 	{&llong_ctype, "llong"},
6911f5207b7SJohn Levon 	{&sllong_ctype, "sllong"},
6921f5207b7SJohn Levon 	{&ullong_ctype, "ullong"},
6931f5207b7SJohn Levon 	{&lllong_ctype, "lllong"},
6941f5207b7SJohn Levon 	{&slllong_ctype, "slllong"},
6951f5207b7SJohn Levon 	{&ulllong_ctype, "ulllong"},
6961f5207b7SJohn Levon 	{&float_ctype, "float"},
6971f5207b7SJohn Levon 	{&double_ctype, "double"},
6981f5207b7SJohn Levon 	{&ldouble_ctype, "ldouble"},
6991f5207b7SJohn Levon 	{&string_ctype, "string"},
7001f5207b7SJohn Levon 	{&ptr_ctype, "ptr"},
7011f5207b7SJohn Levon 	{&lazy_ptr_ctype, "lazy_ptr"},
7021f5207b7SJohn Levon 	{&incomplete_ctype, "incomplete"},
7031f5207b7SJohn Levon 	{&label_ctype, "label"},
7041f5207b7SJohn Levon 	{&bad_ctype, "bad"},
7051f5207b7SJohn Levon 	{&null_ctype, "null"},
7061f5207b7SJohn Levon };
7071f5207b7SJohn Levon 
7081f5207b7SJohn Levon static const char *base_type_str(struct symbol *sym)
7091f5207b7SJohn Levon {
7101f5207b7SJohn Levon 	int i;
7111f5207b7SJohn Levon 
7121f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(base_types); i++) {
7131f5207b7SJohn Levon 		if (sym == base_types[i].sym)
7141f5207b7SJohn Levon 			return base_types[i].name;
7151f5207b7SJohn Levon 	}
7161f5207b7SJohn Levon 	return "<unknown>";
7171f5207b7SJohn Levon }
7181f5207b7SJohn Levon 
7191f5207b7SJohn Levon static int type_str_helper(char *buf, int size, struct symbol *type)
7201f5207b7SJohn Levon {
7211f5207b7SJohn Levon 	int n;
7221f5207b7SJohn Levon 
7231f5207b7SJohn Levon 	if (!type)
7241f5207b7SJohn Levon 		return snprintf(buf, size, "<unknown>");
7251f5207b7SJohn Levon 
7261f5207b7SJohn Levon 	if (type->type == SYM_BASETYPE) {
727*efe51d0cSJohn Levon 		return snprintf(buf, size, "%s", base_type_str(type));
7281f5207b7SJohn Levon 	} else if (type->type == SYM_PTR) {
7291f5207b7SJohn Levon 		type = get_real_base_type(type);
7301f5207b7SJohn Levon 		n = type_str_helper(buf, size, type);
7311f5207b7SJohn Levon 		if (n > size)
7321f5207b7SJohn Levon 			return n;
7331f5207b7SJohn Levon 		return n + snprintf(buf + n, size - n, "*");
7341f5207b7SJohn Levon 	} else if (type->type == SYM_ARRAY) {
7351f5207b7SJohn Levon 		type = get_real_base_type(type);
7361f5207b7SJohn Levon 		n = type_str_helper(buf, size, type);
7371f5207b7SJohn Levon 		if (n > size)
7381f5207b7SJohn Levon 			return n;
7391f5207b7SJohn Levon 		return n + snprintf(buf + n, size - n, "[]");
7401f5207b7SJohn Levon 	} else if (type->type == SYM_STRUCT) {
7411f5207b7SJohn Levon 		return snprintf(buf, size, "struct %s", type->ident ? type->ident->name : "");
7421f5207b7SJohn Levon 	} else if (type->type == SYM_UNION) {
7431f5207b7SJohn Levon 		if (type->ident)
7441f5207b7SJohn Levon 			return snprintf(buf, size, "union %s", type->ident->name);
7451f5207b7SJohn Levon 		else
7461f5207b7SJohn Levon 			return snprintf(buf, size, "anonymous union");
7471f5207b7SJohn Levon 	} else if (type->type == SYM_FN) {
7481f5207b7SJohn Levon 		struct symbol *arg, *return_type, *arg_type;
7491f5207b7SJohn Levon 		int i;
7501f5207b7SJohn Levon 
7511f5207b7SJohn Levon 		return_type = get_real_base_type(type);
7521f5207b7SJohn Levon 		n = type_str_helper(buf, size, return_type);
7531f5207b7SJohn Levon 		if (n > size)
7541f5207b7SJohn Levon 			return n;
7551f5207b7SJohn Levon 		n += snprintf(buf + n, size - n, "(*)(");
7561f5207b7SJohn Levon 		if (n > size)
7571f5207b7SJohn Levon 			return n;
7581f5207b7SJohn Levon 
7591f5207b7SJohn Levon 		i = 0;
7601f5207b7SJohn Levon 		FOR_EACH_PTR(type->arguments, arg) {
7611f5207b7SJohn Levon 			if (i++)
7621f5207b7SJohn Levon 				n += snprintf(buf + n, size - n, ", ");
7631f5207b7SJohn Levon 			if (n > size)
7641f5207b7SJohn Levon 				return n;
7651f5207b7SJohn Levon 			arg_type = get_real_base_type(arg);
7661f5207b7SJohn Levon 			n += type_str_helper(buf + n, size - n, arg_type);
7671f5207b7SJohn Levon 			if (n > size)
7681f5207b7SJohn Levon 				return n;
7691f5207b7SJohn Levon 		} END_FOR_EACH_PTR(arg);
7701f5207b7SJohn Levon 
7711f5207b7SJohn Levon 		return n + snprintf(buf + n, size - n, ")");
7721f5207b7SJohn Levon 	} else if (type->type == SYM_NODE) {
7731f5207b7SJohn Levon 		n = snprintf(buf, size, "node {");
7741f5207b7SJohn Levon 		if (n > size)
7751f5207b7SJohn Levon 			return n;
7761f5207b7SJohn Levon 		type = get_real_base_type(type);
7771f5207b7SJohn Levon 		n += type_str_helper(buf + n, size - n, type);
7781f5207b7SJohn Levon 		if (n > size)
7791f5207b7SJohn Levon 			return n;
7801f5207b7SJohn Levon 		return n + snprintf(buf + n, size - n, "}");
781*efe51d0cSJohn Levon 	} else if (type->type == SYM_ENUM) {
782*efe51d0cSJohn Levon 		return snprintf(buf, size, "enum %s", type->ident ? type->ident->name : "<unknown>");
7831f5207b7SJohn Levon 	} else {
7841f5207b7SJohn Levon 		return snprintf(buf, size, "<type %d>", type->type);
7851f5207b7SJohn Levon 	}
7861f5207b7SJohn Levon }
7871f5207b7SJohn Levon 
7881f5207b7SJohn Levon char *type_to_str(struct symbol *type)
7891f5207b7SJohn Levon {
7901f5207b7SJohn Levon 	static char buf[256];
7911f5207b7SJohn Levon 
7921f5207b7SJohn Levon 	buf[0] = '\0';
7931f5207b7SJohn Levon 	type_str_helper(buf, sizeof(buf), type);
7941f5207b7SJohn Levon 	return buf;
7951f5207b7SJohn Levon }
796