11f5207b7SJohn Levon /* 21f5207b7SJohn Levon * Copyright (C) 2006 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 * Miscellaneous helper functions. 201f5207b7SJohn Levon */ 211f5207b7SJohn Levon 221f5207b7SJohn Levon #include <stdlib.h> 231f5207b7SJohn Levon #include <stdio.h> 241f5207b7SJohn Levon #include "allocate.h" 251f5207b7SJohn Levon #include "smatch.h" 261f5207b7SJohn Levon #include "smatch_extra.h" 271f5207b7SJohn Levon #include "smatch_slist.h" 281f5207b7SJohn Levon 291f5207b7SJohn Levon #define VAR_LEN 512 301f5207b7SJohn Levon 311f5207b7SJohn Levon char *alloc_string(const char *str) 321f5207b7SJohn Levon { 331f5207b7SJohn Levon char *tmp; 341f5207b7SJohn Levon 351f5207b7SJohn Levon if (!str) 361f5207b7SJohn Levon return NULL; 371f5207b7SJohn Levon tmp = malloc(strlen(str) + 1); 381f5207b7SJohn Levon strcpy(tmp, str); 391f5207b7SJohn Levon return tmp; 401f5207b7SJohn Levon } 411f5207b7SJohn Levon 42c85f09ccSJohn Levon char *alloc_string_newline(const char *str) 43c85f09ccSJohn Levon { 44c85f09ccSJohn Levon char *tmp; 45c85f09ccSJohn Levon int len; 46c85f09ccSJohn Levon 47c85f09ccSJohn Levon if (!str) 48c85f09ccSJohn Levon return NULL; 49c85f09ccSJohn Levon len = strlen(str); 50c85f09ccSJohn Levon tmp = malloc(len + 2); 51c85f09ccSJohn Levon snprintf(tmp, len + 2, "%s\n", str); 52c85f09ccSJohn Levon return tmp; 53c85f09ccSJohn Levon } 54c85f09ccSJohn Levon 551f5207b7SJohn Levon void free_string(char *str) 561f5207b7SJohn Levon { 571f5207b7SJohn Levon free(str); 581f5207b7SJohn Levon } 591f5207b7SJohn Levon 601f5207b7SJohn Levon void remove_parens(char *str) 611f5207b7SJohn Levon { 621f5207b7SJohn Levon char *src, *dst; 631f5207b7SJohn Levon 641f5207b7SJohn Levon dst = src = str; 651f5207b7SJohn Levon while (*src != '\0') { 661f5207b7SJohn Levon if (*src == '(' || *src == ')') { 671f5207b7SJohn Levon src++; 681f5207b7SJohn Levon continue; 691f5207b7SJohn Levon } 701f5207b7SJohn Levon *dst++ = *src++; 711f5207b7SJohn Levon } 721f5207b7SJohn Levon *dst = *src; 731f5207b7SJohn Levon } 741f5207b7SJohn Levon 751f5207b7SJohn Levon struct smatch_state *alloc_state_num(int num) 761f5207b7SJohn Levon { 771f5207b7SJohn Levon struct smatch_state *state; 781f5207b7SJohn Levon static char buff[256]; 791f5207b7SJohn Levon 801f5207b7SJohn Levon state = __alloc_smatch_state(0); 811f5207b7SJohn Levon snprintf(buff, 255, "%d", num); 821f5207b7SJohn Levon buff[255] = '\0'; 831f5207b7SJohn Levon state->name = alloc_string(buff); 841f5207b7SJohn Levon state->data = INT_PTR(num); 851f5207b7SJohn Levon return state; 861f5207b7SJohn Levon } 871f5207b7SJohn Levon 881f5207b7SJohn Levon struct smatch_state *alloc_state_str(const char *name) 891f5207b7SJohn Levon { 901f5207b7SJohn Levon struct smatch_state *state; 911f5207b7SJohn Levon 921f5207b7SJohn Levon state = __alloc_smatch_state(0); 931f5207b7SJohn Levon state->name = alloc_string(name); 941f5207b7SJohn Levon return state; 951f5207b7SJohn Levon } 961f5207b7SJohn Levon 97efe51d0cSJohn Levon struct smatch_state *merge_str_state(struct smatch_state *s1, struct smatch_state *s2) 98efe51d0cSJohn Levon { 99efe51d0cSJohn Levon if (!s1->name || !s2->name) 100efe51d0cSJohn Levon return &merged; 101efe51d0cSJohn Levon if (strcmp(s1->name, s2->name) == 0) 102efe51d0cSJohn Levon return s1; 103efe51d0cSJohn Levon return &merged; 104efe51d0cSJohn Levon } 105efe51d0cSJohn Levon 1061f5207b7SJohn Levon struct smatch_state *alloc_state_expr(struct expression *expr) 1071f5207b7SJohn Levon { 1081f5207b7SJohn Levon struct smatch_state *state; 1091f5207b7SJohn Levon char *name; 1101f5207b7SJohn Levon 1111f5207b7SJohn Levon expr = strip_expr(expr); 1121f5207b7SJohn Levon name = expr_to_str(expr); 113efe51d0cSJohn Levon if (!name) 114efe51d0cSJohn Levon return NULL; 115efe51d0cSJohn Levon 116efe51d0cSJohn Levon state = __alloc_smatch_state(0); 1171f5207b7SJohn Levon state->name = alloc_sname(name); 1181f5207b7SJohn Levon free_string(name); 1191f5207b7SJohn Levon state->data = expr; 1201f5207b7SJohn Levon return state; 1211f5207b7SJohn Levon } 1221f5207b7SJohn Levon 1231f5207b7SJohn Levon void append(char *dest, const char *data, int buff_len) 1241f5207b7SJohn Levon { 1251f5207b7SJohn Levon strncat(dest, data, buff_len - strlen(dest) - 1); 1261f5207b7SJohn Levon } 1271f5207b7SJohn Levon 1281f5207b7SJohn Levon /* 1291f5207b7SJohn Levon * If you have "foo(a, b, 1);" then use 1301f5207b7SJohn Levon * get_argument_from_call_expr(expr, 0) to return the expression for 1311f5207b7SJohn Levon * a. Yes, it does start counting from 0. 1321f5207b7SJohn Levon */ 1331f5207b7SJohn Levon struct expression *get_argument_from_call_expr(struct expression_list *args, 1341f5207b7SJohn Levon int num) 1351f5207b7SJohn Levon { 1361f5207b7SJohn Levon struct expression *expr; 1371f5207b7SJohn Levon int i = 0; 1381f5207b7SJohn Levon 1391f5207b7SJohn Levon if (!args) 1401f5207b7SJohn Levon return NULL; 1411f5207b7SJohn Levon 1421f5207b7SJohn Levon FOR_EACH_PTR(args, expr) { 1431f5207b7SJohn Levon if (i == num) 1441f5207b7SJohn Levon return expr; 1451f5207b7SJohn Levon i++; 1461f5207b7SJohn Levon } END_FOR_EACH_PTR(expr); 1471f5207b7SJohn Levon return NULL; 1481f5207b7SJohn Levon } 1491f5207b7SJohn Levon 1501f5207b7SJohn Levon static struct expression *get_array_expr(struct expression *expr) 1511f5207b7SJohn Levon { 1521f5207b7SJohn Levon struct expression *parent; 1531f5207b7SJohn Levon struct symbol *type; 1541f5207b7SJohn Levon 1551f5207b7SJohn Levon if (expr->type != EXPR_BINOP || expr->op != '+') 1561f5207b7SJohn Levon return NULL; 1571f5207b7SJohn Levon 1581f5207b7SJohn Levon type = get_type(expr->left); 1591f5207b7SJohn Levon if (!type) 1601f5207b7SJohn Levon return NULL; 1611f5207b7SJohn Levon if (type->type == SYM_ARRAY) 1621f5207b7SJohn Levon return expr->left; 1631f5207b7SJohn Levon if (type->type != SYM_PTR) 1641f5207b7SJohn Levon return NULL; 1651f5207b7SJohn Levon 1661f5207b7SJohn Levon parent = expr_get_parent_expr(expr); 1671f5207b7SJohn Levon if (!parent) /* Sometimes we haven't set up the ->parent yet. FIXME!! */ 1681f5207b7SJohn Levon return expr->left; 1691f5207b7SJohn Levon if (parent->type == EXPR_PREOP && parent->op == '*') 1701f5207b7SJohn Levon return expr->left; 1711f5207b7SJohn Levon 1721f5207b7SJohn Levon return NULL; 1731f5207b7SJohn Levon } 1741f5207b7SJohn Levon 1751f5207b7SJohn Levon static void __get_variable_from_expr(struct symbol **sym_ptr, char *buf, 1761f5207b7SJohn Levon struct expression *expr, int len, 1771f5207b7SJohn Levon int *complicated, int no_parens) 1781f5207b7SJohn Levon { 1791f5207b7SJohn Levon 1801f5207b7SJohn Levon 1811f5207b7SJohn Levon if (!expr) { 1821f5207b7SJohn Levon /* can't happen on valid code */ 1831f5207b7SJohn Levon *complicated = 1; 1841f5207b7SJohn Levon return; 1851f5207b7SJohn Levon } 1861f5207b7SJohn Levon 1871f5207b7SJohn Levon switch (expr->type) { 1881f5207b7SJohn Levon case EXPR_DEREF: { 1891f5207b7SJohn Levon struct expression *deref; 1901f5207b7SJohn Levon int op; 1911f5207b7SJohn Levon 1921f5207b7SJohn Levon deref = expr->deref; 1931f5207b7SJohn Levon op = deref->op; 194efe51d0cSJohn Levon if (deref->type == EXPR_PREOP && op == '*') { 1951f5207b7SJohn Levon struct expression *unop = strip_expr(deref->unop); 1961f5207b7SJohn Levon 1971f5207b7SJohn Levon if (unop->type == EXPR_PREOP && unop->op == '&') { 1981f5207b7SJohn Levon deref = unop->unop; 1991f5207b7SJohn Levon op = '.'; 2001f5207b7SJohn Levon } else { 201efe51d0cSJohn Levon if (!is_pointer(deref) && !is_pointer(deref->unop)) 2021f5207b7SJohn Levon op = '.'; 203efe51d0cSJohn Levon deref = deref->unop; 2041f5207b7SJohn Levon } 2051f5207b7SJohn Levon } 2061f5207b7SJohn Levon 2071f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, deref, len, complicated, no_parens); 2081f5207b7SJohn Levon 2091f5207b7SJohn Levon if (op == '*') 2101f5207b7SJohn Levon append(buf, "->", len); 2111f5207b7SJohn Levon else 2121f5207b7SJohn Levon append(buf, ".", len); 2131f5207b7SJohn Levon 2141f5207b7SJohn Levon if (expr->member) 2151f5207b7SJohn Levon append(buf, expr->member->name, len); 2161f5207b7SJohn Levon else 2171f5207b7SJohn Levon append(buf, "unknown_member", len); 2181f5207b7SJohn Levon 2191f5207b7SJohn Levon return; 2201f5207b7SJohn Levon } 2211f5207b7SJohn Levon case EXPR_SYMBOL: 2221f5207b7SJohn Levon if (expr->symbol_name) 2231f5207b7SJohn Levon append(buf, expr->symbol_name->name, len); 2241f5207b7SJohn Levon if (sym_ptr) { 2251f5207b7SJohn Levon if (*sym_ptr) 2261f5207b7SJohn Levon *complicated = 1; 2271f5207b7SJohn Levon *sym_ptr = expr->symbol; 2281f5207b7SJohn Levon } 2291f5207b7SJohn Levon return; 2301f5207b7SJohn Levon case EXPR_PREOP: { 2311f5207b7SJohn Levon const char *tmp; 2321f5207b7SJohn Levon 2331f5207b7SJohn Levon if (get_expression_statement(expr)) { 2341f5207b7SJohn Levon *complicated = 2; 2351f5207b7SJohn Levon return; 2361f5207b7SJohn Levon } 2371f5207b7SJohn Levon 2381f5207b7SJohn Levon if (expr->op == '(') { 2391f5207b7SJohn Levon if (!no_parens && expr->unop->type != EXPR_SYMBOL) 2401f5207b7SJohn Levon append(buf, "(", len); 2411f5207b7SJohn Levon } else if (expr->op != '*' || !get_array_expr(expr->unop)) { 2421f5207b7SJohn Levon tmp = show_special(expr->op); 2431f5207b7SJohn Levon append(buf, tmp, len); 2441f5207b7SJohn Levon } 2451f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, expr->unop, 2461f5207b7SJohn Levon len, complicated, no_parens); 2471f5207b7SJohn Levon 2481f5207b7SJohn Levon if (expr->op == '(' && !no_parens && expr->unop->type != EXPR_SYMBOL) 2491f5207b7SJohn Levon append(buf, ")", len); 2501f5207b7SJohn Levon 2511f5207b7SJohn Levon if (expr->op == SPECIAL_DECREMENT || 2521f5207b7SJohn Levon expr->op == SPECIAL_INCREMENT) 2531f5207b7SJohn Levon *complicated = 1; 2541f5207b7SJohn Levon 2551f5207b7SJohn Levon return; 2561f5207b7SJohn Levon } 2571f5207b7SJohn Levon case EXPR_POSTOP: { 2581f5207b7SJohn Levon const char *tmp; 2591f5207b7SJohn Levon 2601f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, expr->unop, 2611f5207b7SJohn Levon len, complicated, no_parens); 2621f5207b7SJohn Levon tmp = show_special(expr->op); 2631f5207b7SJohn Levon append(buf, tmp, len); 2641f5207b7SJohn Levon 2651f5207b7SJohn Levon if (expr->op == SPECIAL_DECREMENT || expr->op == SPECIAL_INCREMENT) 2661f5207b7SJohn Levon *complicated = 1; 2671f5207b7SJohn Levon return; 2681f5207b7SJohn Levon } 2691f5207b7SJohn Levon case EXPR_ASSIGNMENT: 2701f5207b7SJohn Levon case EXPR_COMPARE: 2711f5207b7SJohn Levon case EXPR_LOGICAL: 2721f5207b7SJohn Levon case EXPR_BINOP: { 2731f5207b7SJohn Levon char tmp[10]; 2741f5207b7SJohn Levon struct expression *array_expr; 2751f5207b7SJohn Levon 2761f5207b7SJohn Levon *complicated = 1; 2771f5207b7SJohn Levon array_expr = get_array_expr(expr); 2781f5207b7SJohn Levon if (array_expr) { 2791f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, array_expr, len, complicated, no_parens); 2801f5207b7SJohn Levon append(buf, "[", len); 2811f5207b7SJohn Levon } else { 2821f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, expr->left, len, complicated, no_parens); 2831f5207b7SJohn Levon snprintf(tmp, sizeof(tmp), " %s ", show_special(expr->op)); 2841f5207b7SJohn Levon append(buf, tmp, len); 2851f5207b7SJohn Levon } 2861f5207b7SJohn Levon __get_variable_from_expr(NULL, buf, expr->right, len, complicated, no_parens); 2871f5207b7SJohn Levon if (array_expr) 2881f5207b7SJohn Levon append(buf, "]", len); 2891f5207b7SJohn Levon return; 2901f5207b7SJohn Levon } 2911f5207b7SJohn Levon case EXPR_VALUE: { 292c85f09ccSJohn Levon sval_t sval = {}; 2931f5207b7SJohn Levon char tmp[25]; 2941f5207b7SJohn Levon 2951f5207b7SJohn Levon *complicated = 1; 296c85f09ccSJohn Levon if (!get_value(expr, &sval)) 297c85f09ccSJohn Levon return; 298c85f09ccSJohn Levon snprintf(tmp, 25, "%s", sval_to_numstr(sval)); 2991f5207b7SJohn Levon append(buf, tmp, len); 3001f5207b7SJohn Levon return; 3011f5207b7SJohn Levon } 302*5a0e240fSJohn Levon case EXPR_FVALUE: { 303*5a0e240fSJohn Levon sval_t sval = {}; 304*5a0e240fSJohn Levon char tmp[25]; 305*5a0e240fSJohn Levon 306*5a0e240fSJohn Levon *complicated = 1; 307*5a0e240fSJohn Levon if (!get_value(expr, &sval)) 308*5a0e240fSJohn Levon return; 309*5a0e240fSJohn Levon snprintf(tmp, 25, "%s", sval_to_numstr(sval)); 310*5a0e240fSJohn Levon append(buf, tmp, len); 311*5a0e240fSJohn Levon return; 312*5a0e240fSJohn Levon } 3131f5207b7SJohn Levon case EXPR_STRING: 3141f5207b7SJohn Levon append(buf, "\"", len); 3151f5207b7SJohn Levon if (expr->string) 3161f5207b7SJohn Levon append(buf, expr->string->data, len); 3171f5207b7SJohn Levon append(buf, "\"", len); 3181f5207b7SJohn Levon return; 3191f5207b7SJohn Levon case EXPR_CALL: { 3201f5207b7SJohn Levon struct expression *tmp; 3211f5207b7SJohn Levon int i; 3221f5207b7SJohn Levon 3231f5207b7SJohn Levon *complicated = 1; 3241f5207b7SJohn Levon __get_variable_from_expr(NULL, buf, expr->fn, len, complicated, no_parens); 3251f5207b7SJohn Levon append(buf, "(", len); 3261f5207b7SJohn Levon i = 0; 3271f5207b7SJohn Levon FOR_EACH_PTR(expr->args, tmp) { 3281f5207b7SJohn Levon if (i++) 3291f5207b7SJohn Levon append(buf, ", ", len); 3301f5207b7SJohn Levon __get_variable_from_expr(NULL, buf, tmp, len, complicated, no_parens); 3311f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 3321f5207b7SJohn Levon append(buf, ")", len); 3331f5207b7SJohn Levon return; 3341f5207b7SJohn Levon } 3351f5207b7SJohn Levon case EXPR_CAST: 3361f5207b7SJohn Levon case EXPR_FORCE_CAST: 3371f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, 3381f5207b7SJohn Levon expr->cast_expression, len, 3391f5207b7SJohn Levon complicated, no_parens); 3401f5207b7SJohn Levon return; 3411f5207b7SJohn Levon case EXPR_SIZEOF: { 3421f5207b7SJohn Levon sval_t sval; 3431f5207b7SJohn Levon int size; 3441f5207b7SJohn Levon char tmp[25]; 3451f5207b7SJohn Levon 3461f5207b7SJohn Levon if (expr->cast_type && get_base_type(expr->cast_type)) { 3471f5207b7SJohn Levon size = type_bytes(get_base_type(expr->cast_type)); 3481f5207b7SJohn Levon snprintf(tmp, 25, "%d", size); 3491f5207b7SJohn Levon append(buf, tmp, len); 3501f5207b7SJohn Levon } else if (get_value(expr, &sval)) { 3511f5207b7SJohn Levon snprintf(tmp, 25, "%s", sval_to_str(sval)); 3521f5207b7SJohn Levon append(buf, tmp, len); 3531f5207b7SJohn Levon } 3541f5207b7SJohn Levon return; 3551f5207b7SJohn Levon } 3561f5207b7SJohn Levon case EXPR_IDENTIFIER: 3571f5207b7SJohn Levon *complicated = 1; 3581f5207b7SJohn Levon if (expr->expr_ident) 3591f5207b7SJohn Levon append(buf, expr->expr_ident->name, len); 3601f5207b7SJohn Levon return; 3611f5207b7SJohn Levon default: 3621f5207b7SJohn Levon *complicated = 1; 3631f5207b7SJohn Levon //printf("unknown type = %d\n", expr->type); 3641f5207b7SJohn Levon return; 3651f5207b7SJohn Levon } 3661f5207b7SJohn Levon } 3671f5207b7SJohn Levon 3681f5207b7SJohn Levon struct expr_str_cache_results { 3691f5207b7SJohn Levon struct expression *expr; 3701f5207b7SJohn Levon int no_parens; 3711f5207b7SJohn Levon char str[VAR_LEN]; 3721f5207b7SJohn Levon struct symbol *sym; 3731f5207b7SJohn Levon int complicated; 3741f5207b7SJohn Levon }; 3751f5207b7SJohn Levon 3761f5207b7SJohn Levon static void get_variable_from_expr(struct symbol **sym_ptr, char *buf, 3771f5207b7SJohn Levon struct expression *expr, int len, 3781f5207b7SJohn Levon int *complicated, int no_parens) 3791f5207b7SJohn Levon { 3801f5207b7SJohn Levon static struct expr_str_cache_results cached[8]; 3811f5207b7SJohn Levon struct symbol *tmp_sym = NULL; 3821f5207b7SJohn Levon static int idx; 3831f5207b7SJohn Levon int i; 3841f5207b7SJohn Levon 3851f5207b7SJohn Levon for (i = 0; i < ARRAY_SIZE(cached); i++) { 3861f5207b7SJohn Levon if (expr == cached[i].expr && 3871f5207b7SJohn Levon no_parens == cached[i].no_parens) { 3881f5207b7SJohn Levon strncpy(buf, cached[i].str, len); 3891f5207b7SJohn Levon if (sym_ptr) 3901f5207b7SJohn Levon *sym_ptr = cached[i].sym; 3911f5207b7SJohn Levon *complicated = cached[i].complicated; 3921f5207b7SJohn Levon return; 3931f5207b7SJohn Levon } 3941f5207b7SJohn Levon } 3951f5207b7SJohn Levon 3961f5207b7SJohn Levon __get_variable_from_expr(&tmp_sym, buf, expr, len, complicated, no_parens); 3971f5207b7SJohn Levon if (sym_ptr) 3981f5207b7SJohn Levon *sym_ptr = tmp_sym; 3991f5207b7SJohn Levon 4001f5207b7SJohn Levon cached[idx].expr = expr; 4011f5207b7SJohn Levon cached[idx].no_parens = no_parens; 4021f5207b7SJohn Levon strncpy(cached[idx].str, buf, VAR_LEN); 4031f5207b7SJohn Levon cached[idx].sym = tmp_sym; 4041f5207b7SJohn Levon cached[idx].complicated = *complicated; 4051f5207b7SJohn Levon 4061f5207b7SJohn Levon idx = (idx + 1) % ARRAY_SIZE(cached); 4071f5207b7SJohn Levon } 4081f5207b7SJohn Levon 4091f5207b7SJohn Levon /* 4101f5207b7SJohn Levon * This is returns a stylized "c looking" representation of the 4111f5207b7SJohn Levon * variable name. 4121f5207b7SJohn Levon * 4131f5207b7SJohn Levon * It uses the same buffer every time so you have to save the result 4141f5207b7SJohn Levon * yourself if you want to keep it. 4151f5207b7SJohn Levon * 4161f5207b7SJohn Levon */ 4171f5207b7SJohn Levon 4181f5207b7SJohn Levon char *expr_to_str_sym(struct expression *expr, struct symbol **sym_ptr) 4191f5207b7SJohn Levon { 4201f5207b7SJohn Levon static char var_name[VAR_LEN]; 4211f5207b7SJohn Levon int complicated = 0; 4221f5207b7SJohn Levon 4231f5207b7SJohn Levon if (sym_ptr) 4241f5207b7SJohn Levon *sym_ptr = NULL; 4251f5207b7SJohn Levon var_name[0] = '\0'; 4261f5207b7SJohn Levon 4271f5207b7SJohn Levon if (!expr) 4281f5207b7SJohn Levon return NULL; 4291f5207b7SJohn Levon get_variable_from_expr(sym_ptr, var_name, expr, sizeof(var_name), 4301f5207b7SJohn Levon &complicated, 0); 4311f5207b7SJohn Levon if (complicated < 2) 4321f5207b7SJohn Levon return alloc_string(var_name); 4331f5207b7SJohn Levon else 4341f5207b7SJohn Levon return NULL; 4351f5207b7SJohn Levon } 4361f5207b7SJohn Levon 4371f5207b7SJohn Levon char *expr_to_str(struct expression *expr) 4381f5207b7SJohn Levon { 4391f5207b7SJohn Levon return expr_to_str_sym(expr, NULL); 4401f5207b7SJohn Levon } 4411f5207b7SJohn Levon 4421f5207b7SJohn Levon /* 4431f5207b7SJohn Levon * get_variable_from_expr_simple() only returns simple variables. 4441f5207b7SJohn Levon * If it's a complicated variable like a->foo[x] instead of just 'a->foo' 4451f5207b7SJohn Levon * then it returns NULL. 4461f5207b7SJohn Levon */ 4471f5207b7SJohn Levon char *expr_to_var_sym(struct expression *expr, 4481f5207b7SJohn Levon struct symbol **sym_ptr) 4491f5207b7SJohn Levon { 4501f5207b7SJohn Levon static char var_name[VAR_LEN]; 4511f5207b7SJohn Levon int complicated = 0; 4521f5207b7SJohn Levon 4531f5207b7SJohn Levon if (sym_ptr) 4541f5207b7SJohn Levon *sym_ptr = NULL; 4551f5207b7SJohn Levon var_name[0] = '\0'; 4561f5207b7SJohn Levon 4571f5207b7SJohn Levon if (!expr) 4581f5207b7SJohn Levon return NULL; 4591f5207b7SJohn Levon expr = strip_expr(expr); 4601f5207b7SJohn Levon get_variable_from_expr(sym_ptr, var_name, expr, sizeof(var_name), 4611f5207b7SJohn Levon &complicated, 1); 4621f5207b7SJohn Levon 4631f5207b7SJohn Levon if (complicated) { 4641f5207b7SJohn Levon if (sym_ptr) 4651f5207b7SJohn Levon *sym_ptr = NULL; 4661f5207b7SJohn Levon return NULL; 4671f5207b7SJohn Levon } 4681f5207b7SJohn Levon return alloc_string(var_name); 4691f5207b7SJohn Levon } 4701f5207b7SJohn Levon 4711f5207b7SJohn Levon char *expr_to_var(struct expression *expr) 4721f5207b7SJohn Levon { 4731f5207b7SJohn Levon return expr_to_var_sym(expr, NULL); 4741f5207b7SJohn Levon } 4751f5207b7SJohn Levon 4761f5207b7SJohn Levon struct symbol *expr_to_sym(struct expression *expr) 4771f5207b7SJohn Levon { 4781f5207b7SJohn Levon struct symbol *sym; 4791f5207b7SJohn Levon char *name; 4801f5207b7SJohn Levon 4811f5207b7SJohn Levon name = expr_to_var_sym(expr, &sym); 4821f5207b7SJohn Levon free_string(name); 4831f5207b7SJohn Levon return sym; 4841f5207b7SJohn Levon } 4851f5207b7SJohn Levon 4861f5207b7SJohn Levon int get_complication_score(struct expression *expr) 4871f5207b7SJohn Levon { 4881f5207b7SJohn Levon expr = strip_expr(expr); 4891f5207b7SJohn Levon 4901f5207b7SJohn Levon /* 4911f5207b7SJohn Levon * Don't forget to keep get_complication_score() and store_all_links() 4921f5207b7SJohn Levon * in sync. 4931f5207b7SJohn Levon * 4941f5207b7SJohn Levon */ 4951f5207b7SJohn Levon 4961f5207b7SJohn Levon if (!expr) 4971f5207b7SJohn Levon return 990; 4981f5207b7SJohn Levon 4991f5207b7SJohn Levon switch (expr->type) { 5001f5207b7SJohn Levon case EXPR_CALL: 5011f5207b7SJohn Levon return 991; 5021f5207b7SJohn Levon case EXPR_COMPARE: 5031f5207b7SJohn Levon case EXPR_BINOP: 5041f5207b7SJohn Levon return get_complication_score(expr->left) + 5051f5207b7SJohn Levon get_complication_score(expr->right); 5061f5207b7SJohn Levon case EXPR_SYMBOL: 5071f5207b7SJohn Levon return 1; 5081f5207b7SJohn Levon case EXPR_PREOP: 5091f5207b7SJohn Levon if (expr->op == '*' || expr->op == '(') 5101f5207b7SJohn Levon return get_complication_score(expr->unop); 5111f5207b7SJohn Levon return 993; 5121f5207b7SJohn Levon case EXPR_DEREF: 5131f5207b7SJohn Levon return get_complication_score(expr->deref); 5141f5207b7SJohn Levon case EXPR_VALUE: 5151f5207b7SJohn Levon case EXPR_SIZEOF: 5161f5207b7SJohn Levon return 0; 5171f5207b7SJohn Levon default: 5181f5207b7SJohn Levon return 994; 5191f5207b7SJohn Levon } 5201f5207b7SJohn Levon } 5211f5207b7SJohn Levon 5221f5207b7SJohn Levon struct expression *reorder_expr_alphabetically(struct expression *expr) 5231f5207b7SJohn Levon { 5241f5207b7SJohn Levon struct expression *ret; 5251f5207b7SJohn Levon char *left, *right; 5261f5207b7SJohn Levon 5271f5207b7SJohn Levon if (expr->type != EXPR_BINOP) 5281f5207b7SJohn Levon return expr; 5291f5207b7SJohn Levon if (expr->op != '+' && expr->op != '*') 5301f5207b7SJohn Levon return expr; 5311f5207b7SJohn Levon 5321f5207b7SJohn Levon left = expr_to_var(expr->left); 5331f5207b7SJohn Levon right = expr_to_var(expr->right); 5341f5207b7SJohn Levon ret = expr; 5351f5207b7SJohn Levon if (!left || !right) 5361f5207b7SJohn Levon goto free; 5371f5207b7SJohn Levon if (strcmp(left, right) <= 0) 5381f5207b7SJohn Levon goto free; 5391f5207b7SJohn Levon 5401f5207b7SJohn Levon ret = binop_expression(expr->right, expr->op, expr->left); 5411f5207b7SJohn Levon free: 5421f5207b7SJohn Levon free_string(left); 5431f5207b7SJohn Levon free_string(right); 5441f5207b7SJohn Levon 5451f5207b7SJohn Levon return ret; 5461f5207b7SJohn Levon } 5471f5207b7SJohn Levon 5481f5207b7SJohn Levon char *expr_to_chunk_helper(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl) 5491f5207b7SJohn Levon { 5501f5207b7SJohn Levon struct var_sym_list *tmp_vsl; 5511f5207b7SJohn Levon char *name; 5521f5207b7SJohn Levon struct symbol *tmp; 5531f5207b7SJohn Levon int score; 5541f5207b7SJohn Levon 5551f5207b7SJohn Levon if (vsl) 5561f5207b7SJohn Levon *vsl = NULL; 5571f5207b7SJohn Levon if (sym) 5581f5207b7SJohn Levon *sym = NULL; 5591f5207b7SJohn Levon 5601f5207b7SJohn Levon expr = strip_parens(expr); 5611f5207b7SJohn Levon if (!expr) 5621f5207b7SJohn Levon return NULL; 5631f5207b7SJohn Levon 5641f5207b7SJohn Levon name = expr_to_var_sym(expr, &tmp); 5651f5207b7SJohn Levon if (name && tmp) { 5661f5207b7SJohn Levon if (sym) 5671f5207b7SJohn Levon *sym = tmp; 5681f5207b7SJohn Levon if (vsl) 569efe51d0cSJohn Levon add_var_sym(vsl, name, tmp); 5701f5207b7SJohn Levon return name; 5711f5207b7SJohn Levon } 5721f5207b7SJohn Levon free_string(name); 5731f5207b7SJohn Levon 5741f5207b7SJohn Levon score = get_complication_score(expr); 5751f5207b7SJohn Levon if (score <= 0 || score > 2) 5761f5207b7SJohn Levon return NULL; 5771f5207b7SJohn Levon 5781f5207b7SJohn Levon tmp_vsl = expr_to_vsl(expr); 5791f5207b7SJohn Levon if (vsl) { 5801f5207b7SJohn Levon *vsl = tmp_vsl; 5811f5207b7SJohn Levon if (!*vsl) 5821f5207b7SJohn Levon return NULL; 5831f5207b7SJohn Levon } 5841f5207b7SJohn Levon if (sym) { 5851f5207b7SJohn Levon if (ptr_list_size((struct ptr_list *)tmp_vsl) == 1) { 5861f5207b7SJohn Levon struct var_sym *vs; 5871f5207b7SJohn Levon 5881f5207b7SJohn Levon vs = first_ptr_list((struct ptr_list *)tmp_vsl); 5891f5207b7SJohn Levon *sym = vs->sym; 5901f5207b7SJohn Levon } 5911f5207b7SJohn Levon } 5921f5207b7SJohn Levon 5931f5207b7SJohn Levon expr = reorder_expr_alphabetically(expr); 5941f5207b7SJohn Levon 5951f5207b7SJohn Levon return expr_to_str(expr); 5961f5207b7SJohn Levon } 5971f5207b7SJohn Levon 5981f5207b7SJohn Levon char *expr_to_known_chunk_sym(struct expression *expr, struct symbol **sym) 5991f5207b7SJohn Levon { 6001f5207b7SJohn Levon return expr_to_chunk_helper(expr, sym, NULL); 6011f5207b7SJohn Levon } 6021f5207b7SJohn Levon 6031f5207b7SJohn Levon char *expr_to_chunk_sym_vsl(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl) 6041f5207b7SJohn Levon { 6051f5207b7SJohn Levon return expr_to_chunk_helper(expr, sym, vsl); 6061f5207b7SJohn Levon } 6071f5207b7SJohn Levon 6081f5207b7SJohn Levon int sym_name_is(const char *name, struct expression *expr) 6091f5207b7SJohn Levon { 6101f5207b7SJohn Levon if (!expr) 6111f5207b7SJohn Levon return 0; 6121f5207b7SJohn Levon if (expr->type != EXPR_SYMBOL) 6131f5207b7SJohn Levon return 0; 6141f5207b7SJohn Levon if (!strcmp(expr->symbol_name->name, name)) 6151f5207b7SJohn Levon return 1; 6161f5207b7SJohn Levon return 0; 6171f5207b7SJohn Levon } 6181f5207b7SJohn Levon 619c85f09ccSJohn Levon int expr_is_zero(struct expression *expr) 6201f5207b7SJohn Levon { 6211f5207b7SJohn Levon sval_t sval; 6221f5207b7SJohn Levon 6231f5207b7SJohn Levon if (get_value(expr, &sval) && sval.value == 0) 6241f5207b7SJohn Levon return 1; 6251f5207b7SJohn Levon return 0; 6261f5207b7SJohn Levon } 6271f5207b7SJohn Levon 6281f5207b7SJohn Levon int is_array(struct expression *expr) 6291f5207b7SJohn Levon { 6301f5207b7SJohn Levon struct symbol *type; 6311f5207b7SJohn Levon 6321f5207b7SJohn Levon expr = strip_expr(expr); 6331f5207b7SJohn Levon if (!expr) 6341f5207b7SJohn Levon return 0; 6351f5207b7SJohn Levon 6361f5207b7SJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') { 6371f5207b7SJohn Levon expr = strip_expr(expr->unop); 6381f5207b7SJohn Levon if (!expr) 6391f5207b7SJohn Levon return 0; 6401f5207b7SJohn Levon if (expr->type == EXPR_BINOP && expr->op == '+') 6411f5207b7SJohn Levon return 1; 6421f5207b7SJohn Levon } 6431f5207b7SJohn Levon 6441f5207b7SJohn Levon if (expr->type != EXPR_BINOP || expr->op != '+') 6451f5207b7SJohn Levon return 0; 6461f5207b7SJohn Levon 6471f5207b7SJohn Levon type = get_type(expr->left); 6481f5207b7SJohn Levon if (!type || type->type != SYM_ARRAY) 6491f5207b7SJohn Levon return 0; 6501f5207b7SJohn Levon 6511f5207b7SJohn Levon return 1; 6521f5207b7SJohn Levon } 6531f5207b7SJohn Levon 6541f5207b7SJohn Levon struct expression *get_array_base(struct expression *expr) 6551f5207b7SJohn Levon { 6561f5207b7SJohn Levon if (!is_array(expr)) 6571f5207b7SJohn Levon return NULL; 6581f5207b7SJohn Levon expr = strip_expr(expr); 6591f5207b7SJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') 6601f5207b7SJohn Levon expr = strip_expr(expr->unop); 6611f5207b7SJohn Levon if (expr->type != EXPR_BINOP || expr->op != '+') 6621f5207b7SJohn Levon return NULL; 6631f5207b7SJohn Levon return strip_parens(expr->left); 6641f5207b7SJohn Levon } 6651f5207b7SJohn Levon 6661f5207b7SJohn Levon struct expression *get_array_offset(struct expression *expr) 6671f5207b7SJohn Levon { 6681f5207b7SJohn Levon if (!is_array(expr)) 6691f5207b7SJohn Levon return NULL; 6701f5207b7SJohn Levon expr = strip_expr(expr); 6711f5207b7SJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') 6721f5207b7SJohn Levon expr = strip_expr(expr->unop); 6731f5207b7SJohn Levon if (expr->type != EXPR_BINOP || expr->op != '+') 6741f5207b7SJohn Levon return NULL; 6751f5207b7SJohn Levon return strip_parens(expr->right); 6761f5207b7SJohn Levon } 6771f5207b7SJohn Levon 6781f5207b7SJohn Levon const char *show_state(struct smatch_state *state) 6791f5207b7SJohn Levon { 6801f5207b7SJohn Levon if (!state) 6811f5207b7SJohn Levon return NULL; 6821f5207b7SJohn Levon return state->name; 6831f5207b7SJohn Levon } 6841f5207b7SJohn Levon 6851f5207b7SJohn Levon struct statement *get_expression_statement(struct expression *expr) 6861f5207b7SJohn Levon { 6871f5207b7SJohn Levon /* What are those things called? if (({....; ret;})) { ...*/ 6881f5207b7SJohn Levon 6891f5207b7SJohn Levon if (expr->type != EXPR_PREOP) 6901f5207b7SJohn Levon return NULL; 6911f5207b7SJohn Levon if (expr->op != '(') 6921f5207b7SJohn Levon return NULL; 6931f5207b7SJohn Levon if (!expr->unop) 6941f5207b7SJohn Levon return NULL; 6951f5207b7SJohn Levon if (expr->unop->type != EXPR_STATEMENT) 6961f5207b7SJohn Levon return NULL; 6971f5207b7SJohn Levon if (expr->unop->statement->type != STMT_COMPOUND) 6981f5207b7SJohn Levon return NULL; 6991f5207b7SJohn Levon return expr->unop->statement; 7001f5207b7SJohn Levon } 7011f5207b7SJohn Levon 7021f5207b7SJohn Levon struct expression *strip_parens(struct expression *expr) 7031f5207b7SJohn Levon { 7041f5207b7SJohn Levon if (!expr) 7051f5207b7SJohn Levon return NULL; 7061f5207b7SJohn Levon 7071f5207b7SJohn Levon if (expr->type == EXPR_PREOP) { 7081f5207b7SJohn Levon if (!expr->unop) 7091f5207b7SJohn Levon return expr; /* parsing invalid code */ 7101f5207b7SJohn Levon 7111f5207b7SJohn Levon if (expr->op == '(' && expr->unop->type == EXPR_STATEMENT && 7121f5207b7SJohn Levon expr->unop->statement->type == STMT_COMPOUND) 7131f5207b7SJohn Levon return expr; 7141f5207b7SJohn Levon if (expr->op == '(') 7151f5207b7SJohn Levon return strip_parens(expr->unop); 7161f5207b7SJohn Levon } 7171f5207b7SJohn Levon return expr; 7181f5207b7SJohn Levon } 7191f5207b7SJohn Levon 7201f5207b7SJohn Levon static struct expression *strip_expr_helper(struct expression *expr, bool set_parent) 7211f5207b7SJohn Levon { 7221f5207b7SJohn Levon if (!expr) 7231f5207b7SJohn Levon return NULL; 7241f5207b7SJohn Levon 7251f5207b7SJohn Levon switch (expr->type) { 7261f5207b7SJohn Levon case EXPR_FORCE_CAST: 7271f5207b7SJohn Levon case EXPR_CAST: 7281f5207b7SJohn Levon if (set_parent) 7291f5207b7SJohn Levon expr_set_parent_expr(expr->cast_expression, expr); 7301f5207b7SJohn Levon 7311f5207b7SJohn Levon if (!expr->cast_expression) 7321f5207b7SJohn Levon return expr; 7331f5207b7SJohn Levon return strip_expr_helper(expr->cast_expression, set_parent); 7341f5207b7SJohn Levon case EXPR_PREOP: { 7351f5207b7SJohn Levon struct expression *unop; 7361f5207b7SJohn Levon 7371f5207b7SJohn Levon if (!expr->unop) /* parsing invalid code */ 7381f5207b7SJohn Levon return expr; 7391f5207b7SJohn Levon if (set_parent) 7401f5207b7SJohn Levon expr_set_parent_expr(expr->unop, expr); 7411f5207b7SJohn Levon 7421f5207b7SJohn Levon 7431f5207b7SJohn Levon if (expr->op == '(' && expr->unop->type == EXPR_STATEMENT && 7441f5207b7SJohn Levon expr->unop->statement->type == STMT_COMPOUND) 7451f5207b7SJohn Levon return expr; 7461f5207b7SJohn Levon 7471f5207b7SJohn Levon unop = strip_expr_helper(expr->unop, set_parent); 7481f5207b7SJohn Levon 7491f5207b7SJohn Levon if (expr->op == '*' && unop && 7501f5207b7SJohn Levon unop->type == EXPR_PREOP && unop->op == '&') { 7511f5207b7SJohn Levon struct symbol *type = get_type(unop->unop); 7521f5207b7SJohn Levon 7531f5207b7SJohn Levon if (type && type->type == SYM_ARRAY) 7541f5207b7SJohn Levon return expr; 7551f5207b7SJohn Levon return strip_expr_helper(unop->unop, set_parent); 7561f5207b7SJohn Levon } 7571f5207b7SJohn Levon 7581f5207b7SJohn Levon if (expr->op == '(') 7591f5207b7SJohn Levon return unop; 7601f5207b7SJohn Levon 7611f5207b7SJohn Levon return expr; 7621f5207b7SJohn Levon } 7631f5207b7SJohn Levon case EXPR_CONDITIONAL: 7641f5207b7SJohn Levon if (known_condition_true(expr->conditional)) { 7651f5207b7SJohn Levon if (expr->cond_true) { 7661f5207b7SJohn Levon if (set_parent) 7671f5207b7SJohn Levon expr_set_parent_expr(expr->cond_true, expr); 7681f5207b7SJohn Levon return strip_expr_helper(expr->cond_true, set_parent); 7691f5207b7SJohn Levon } 7701f5207b7SJohn Levon if (set_parent) 7711f5207b7SJohn Levon expr_set_parent_expr(expr->conditional, expr); 7721f5207b7SJohn Levon return strip_expr_helper(expr->conditional, set_parent); 7731f5207b7SJohn Levon } 7741f5207b7SJohn Levon if (known_condition_false(expr->conditional)) { 7751f5207b7SJohn Levon if (set_parent) 7761f5207b7SJohn Levon expr_set_parent_expr(expr->cond_false, expr); 7771f5207b7SJohn Levon return strip_expr_helper(expr->cond_false, set_parent); 7781f5207b7SJohn Levon } 7791f5207b7SJohn Levon return expr; 7801f5207b7SJohn Levon case EXPR_CALL: 7811f5207b7SJohn Levon if (sym_name_is("__builtin_expect", expr->fn) || 7821f5207b7SJohn Levon sym_name_is("__builtin_bswap16", expr->fn) || 7831f5207b7SJohn Levon sym_name_is("__builtin_bswap32", expr->fn) || 7841f5207b7SJohn Levon sym_name_is("__builtin_bswap64", expr->fn)) { 7851f5207b7SJohn Levon expr = get_argument_from_call_expr(expr->args, 0); 7861f5207b7SJohn Levon return strip_expr_helper(expr, set_parent); 7871f5207b7SJohn Levon } 7881f5207b7SJohn Levon return expr; 7891f5207b7SJohn Levon } 7901f5207b7SJohn Levon return expr; 7911f5207b7SJohn Levon } 7921f5207b7SJohn Levon 7931f5207b7SJohn Levon struct expression *strip_expr(struct expression *expr) 7941f5207b7SJohn Levon { 7951f5207b7SJohn Levon return strip_expr_helper(expr, false); 7961f5207b7SJohn Levon } 7971f5207b7SJohn Levon 7981f5207b7SJohn Levon struct expression *strip_expr_set_parent(struct expression *expr) 7991f5207b7SJohn Levon { 8001f5207b7SJohn Levon return strip_expr_helper(expr, true); 8011f5207b7SJohn Levon } 8021f5207b7SJohn Levon 8031f5207b7SJohn Levon static void delete_state_tracker(struct tracker *t) 8041f5207b7SJohn Levon { 8051f5207b7SJohn Levon delete_state(t->owner, t->name, t->sym); 8061f5207b7SJohn Levon __free_tracker(t); 8071f5207b7SJohn Levon } 8081f5207b7SJohn Levon 8091f5207b7SJohn Levon void scoped_state(int my_id, const char *name, struct symbol *sym) 8101f5207b7SJohn Levon { 8111f5207b7SJohn Levon struct tracker *t; 8121f5207b7SJohn Levon 8131f5207b7SJohn Levon t = alloc_tracker(my_id, name, sym); 8141f5207b7SJohn Levon add_scope_hook((scope_hook *)&delete_state_tracker, t); 8151f5207b7SJohn Levon } 8161f5207b7SJohn Levon 8171f5207b7SJohn Levon int is_error_return(struct expression *expr) 8181f5207b7SJohn Levon { 8191f5207b7SJohn Levon struct symbol *cur_func = cur_func_sym; 8201f5207b7SJohn Levon struct range_list *rl; 8211f5207b7SJohn Levon sval_t sval; 8221f5207b7SJohn Levon 8231f5207b7SJohn Levon if (!expr) 8241f5207b7SJohn Levon return 0; 8251f5207b7SJohn Levon if (cur_func->type != SYM_NODE) 8261f5207b7SJohn Levon return 0; 8271f5207b7SJohn Levon cur_func = get_base_type(cur_func); 8281f5207b7SJohn Levon if (cur_func->type != SYM_FN) 8291f5207b7SJohn Levon return 0; 8301f5207b7SJohn Levon cur_func = get_base_type(cur_func); 8311f5207b7SJohn Levon if (cur_func == &void_ctype) 8321f5207b7SJohn Levon return 0; 8331f5207b7SJohn Levon if (option_project == PROJ_KERNEL && 8341f5207b7SJohn Levon get_implied_rl(expr, &rl) && 8351f5207b7SJohn Levon rl_type(rl) == &int_ctype && 8361f5207b7SJohn Levon sval_is_negative(rl_min(rl)) && 8371f5207b7SJohn Levon rl_max(rl).value == -1) 8381f5207b7SJohn Levon return 1; 8391f5207b7SJohn Levon if (!get_implied_value(expr, &sval)) 8401f5207b7SJohn Levon return 0; 8411f5207b7SJohn Levon if (sval.value < 0) 8421f5207b7SJohn Levon return 1; 8431f5207b7SJohn Levon if (cur_func->type == SYM_PTR && sval.value == 0) 8441f5207b7SJohn Levon return 1; 8451f5207b7SJohn Levon return 0; 8461f5207b7SJohn Levon } 8471f5207b7SJohn Levon 848c85f09ccSJohn Levon int getting_address(struct expression *expr) 8491f5207b7SJohn Levon { 850c85f09ccSJohn Levon int deref_count = 0; 8511f5207b7SJohn Levon 852c85f09ccSJohn Levon while ((expr = expr_get_parent_expr(expr))) { 853c85f09ccSJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') { 854c85f09ccSJohn Levon /* &foo->bar->baz dereferences "foo->bar" */ 855c85f09ccSJohn Levon if (deref_count == 0) 856c85f09ccSJohn Levon deref_count++; 857c85f09ccSJohn Levon return false; 858c85f09ccSJohn Levon } 859c85f09ccSJohn Levon if (expr->type == EXPR_PREOP && expr->op == '&') 860c85f09ccSJohn Levon return true; 861c85f09ccSJohn Levon } 862c85f09ccSJohn Levon return false; 8631f5207b7SJohn Levon } 8641f5207b7SJohn Levon 8651f5207b7SJohn Levon int get_struct_and_member(struct expression *expr, const char **type, const char **member) 8661f5207b7SJohn Levon { 8671f5207b7SJohn Levon struct symbol *sym; 8681f5207b7SJohn Levon 8691f5207b7SJohn Levon expr = strip_expr(expr); 8701f5207b7SJohn Levon if (expr->type != EXPR_DEREF) 8711f5207b7SJohn Levon return 0; 8721f5207b7SJohn Levon if (!expr->member) 8731f5207b7SJohn Levon return 0; 8741f5207b7SJohn Levon 8751f5207b7SJohn Levon sym = get_type(expr->deref); 8761f5207b7SJohn Levon if (!sym) 8771f5207b7SJohn Levon return 0; 8781f5207b7SJohn Levon if (sym->type == SYM_UNION) 8791f5207b7SJohn Levon return 0; 8801f5207b7SJohn Levon if (!sym->ident) 8811f5207b7SJohn Levon return 0; 8821f5207b7SJohn Levon 8831f5207b7SJohn Levon *type = sym->ident->name; 8841f5207b7SJohn Levon *member = expr->member->name; 8851f5207b7SJohn Levon return 1; 8861f5207b7SJohn Levon } 8871f5207b7SJohn Levon 8881f5207b7SJohn Levon char *get_member_name(struct expression *expr) 8891f5207b7SJohn Levon { 8901f5207b7SJohn Levon char buf[256]; 8911f5207b7SJohn Levon struct symbol *sym; 8921f5207b7SJohn Levon 8931f5207b7SJohn Levon expr = strip_expr(expr); 8941f5207b7SJohn Levon if (!expr || expr->type != EXPR_DEREF) 8951f5207b7SJohn Levon return NULL; 8961f5207b7SJohn Levon if (!expr->member) 8971f5207b7SJohn Levon return NULL; 8981f5207b7SJohn Levon 8991f5207b7SJohn Levon sym = get_type(expr->deref); 9001f5207b7SJohn Levon if (!sym) 9011f5207b7SJohn Levon return NULL; 9021f5207b7SJohn Levon if (sym->type == SYM_UNION) { 9031f5207b7SJohn Levon snprintf(buf, sizeof(buf), "(union %s)->%s", 9041f5207b7SJohn Levon sym->ident ? sym->ident->name : "anonymous", 9051f5207b7SJohn Levon expr->member->name); 9061f5207b7SJohn Levon return alloc_string(buf); 9071f5207b7SJohn Levon } 908efe51d0cSJohn Levon if (!sym->ident) { 909efe51d0cSJohn Levon struct expression *deref; 910efe51d0cSJohn Levon char *full, *outer; 911efe51d0cSJohn Levon int len; 912efe51d0cSJohn Levon 913efe51d0cSJohn Levon /* 914efe51d0cSJohn Levon * If we're in an anonymous struct then maybe we can find an 915efe51d0cSJohn Levon * outer struct name to use as a name. This code should be 916efe51d0cSJohn Levon * recursive and cleaner. I am not very proud of it. 917efe51d0cSJohn Levon * 918efe51d0cSJohn Levon */ 919efe51d0cSJohn Levon 920efe51d0cSJohn Levon deref = expr->deref; 921efe51d0cSJohn Levon if (deref->type != EXPR_DEREF || !deref->member) 922efe51d0cSJohn Levon return NULL; 923efe51d0cSJohn Levon sym = get_type(deref->deref); 924efe51d0cSJohn Levon if (!sym || sym->type != SYM_STRUCT || !sym->ident) 925efe51d0cSJohn Levon return NULL; 926efe51d0cSJohn Levon 927efe51d0cSJohn Levon full = expr_to_str(expr); 928efe51d0cSJohn Levon if (!full) 929efe51d0cSJohn Levon return NULL; 930efe51d0cSJohn Levon deref = deref->deref; 931efe51d0cSJohn Levon if (deref->type == EXPR_PREOP && deref->op == '*') 932efe51d0cSJohn Levon deref = deref->unop; 933efe51d0cSJohn Levon outer = expr_to_str(deref); 934efe51d0cSJohn Levon if (!outer) { 935efe51d0cSJohn Levon free_string(full); 936efe51d0cSJohn Levon return NULL; 937efe51d0cSJohn Levon } 938efe51d0cSJohn Levon len = strlen(outer); 939efe51d0cSJohn Levon if (strncmp(outer, full, len) != 0) { 940efe51d0cSJohn Levon free_string(full); 941efe51d0cSJohn Levon free_string(outer); 942efe51d0cSJohn Levon return NULL; 943efe51d0cSJohn Levon } 944efe51d0cSJohn Levon if (full[len] == '-' && full[len + 1] == '>') 945efe51d0cSJohn Levon len += 2; 946efe51d0cSJohn Levon if (full[len] == '.') 947efe51d0cSJohn Levon len++; 948efe51d0cSJohn Levon snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, full + len); 949efe51d0cSJohn Levon free_string(outer); 950efe51d0cSJohn Levon free_string(full); 951efe51d0cSJohn Levon 952efe51d0cSJohn Levon return alloc_string(buf); 953efe51d0cSJohn Levon } 9541f5207b7SJohn Levon snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, expr->member->name); 9551f5207b7SJohn Levon return alloc_string(buf); 9561f5207b7SJohn Levon } 9571f5207b7SJohn Levon 9581f5207b7SJohn Levon int cmp_pos(struct position pos1, struct position pos2) 9591f5207b7SJohn Levon { 9601f5207b7SJohn Levon /* the stream position is ... */ 9611f5207b7SJohn Levon if (pos1.stream > pos2.stream) 9621f5207b7SJohn Levon return -1; 9631f5207b7SJohn Levon if (pos1.stream < pos2.stream) 9641f5207b7SJohn Levon return 1; 9651f5207b7SJohn Levon 9661f5207b7SJohn Levon if (pos1.line < pos2.line) 9671f5207b7SJohn Levon return -1; 9681f5207b7SJohn Levon if (pos1.line > pos2.line) 9691f5207b7SJohn Levon return 1; 9701f5207b7SJohn Levon 9711f5207b7SJohn Levon if (pos1.pos < pos2.pos) 9721f5207b7SJohn Levon return -1; 9731f5207b7SJohn Levon if (pos1.pos > pos2.pos) 9741f5207b7SJohn Levon return 1; 9751f5207b7SJohn Levon 9761f5207b7SJohn Levon return 0; 9771f5207b7SJohn Levon } 9781f5207b7SJohn Levon 9791f5207b7SJohn Levon int positions_eq(struct position pos1, struct position pos2) 9801f5207b7SJohn Levon { 9811f5207b7SJohn Levon if (pos1.line != pos2.line) 9821f5207b7SJohn Levon return 0; 9831f5207b7SJohn Levon if (pos1.pos != pos2.pos) 9841f5207b7SJohn Levon return 0; 9851f5207b7SJohn Levon if (pos1.stream != pos2.stream) 9861f5207b7SJohn Levon return 0; 9871f5207b7SJohn Levon return 1; 9881f5207b7SJohn Levon } 9891f5207b7SJohn Levon 9901f5207b7SJohn Levon struct statement *get_current_statement(void) 9911f5207b7SJohn Levon { 9921f5207b7SJohn Levon struct statement *prev, *tmp; 9931f5207b7SJohn Levon 9941f5207b7SJohn Levon prev = last_ptr_list((struct ptr_list *)big_statement_stack); 9951f5207b7SJohn Levon 9961f5207b7SJohn Levon if (!prev || !get_macro_name(prev->pos)) 9971f5207b7SJohn Levon return prev; 9981f5207b7SJohn Levon 9991f5207b7SJohn Levon FOR_EACH_PTR_REVERSE(big_statement_stack, tmp) { 10001f5207b7SJohn Levon if (positions_eq(tmp->pos, prev->pos)) 10011f5207b7SJohn Levon continue; 10021f5207b7SJohn Levon if (prev->pos.line > tmp->pos.line) 10031f5207b7SJohn Levon return prev; 10041f5207b7SJohn Levon return tmp; 10051f5207b7SJohn Levon } END_FOR_EACH_PTR_REVERSE(tmp); 10061f5207b7SJohn Levon return prev; 10071f5207b7SJohn Levon } 10081f5207b7SJohn Levon 10091f5207b7SJohn Levon struct statement *get_prev_statement(void) 10101f5207b7SJohn Levon { 10111f5207b7SJohn Levon struct statement *tmp; 10121f5207b7SJohn Levon int i; 10131f5207b7SJohn Levon 10141f5207b7SJohn Levon i = 0; 10151f5207b7SJohn Levon FOR_EACH_PTR_REVERSE(big_statement_stack, tmp) { 10161f5207b7SJohn Levon if (i++ == 1) 10171f5207b7SJohn Levon return tmp; 10181f5207b7SJohn Levon } END_FOR_EACH_PTR_REVERSE(tmp); 10191f5207b7SJohn Levon return NULL; 10201f5207b7SJohn Levon } 10211f5207b7SJohn Levon 10221f5207b7SJohn Levon struct expression *get_last_expr_from_expression_stmt(struct expression *expr) 10231f5207b7SJohn Levon { 10241f5207b7SJohn Levon struct statement *stmt; 10251f5207b7SJohn Levon struct statement *last_stmt; 10261f5207b7SJohn Levon 10271f5207b7SJohn Levon while (expr->type == EXPR_PREOP && expr->op == '(') 10281f5207b7SJohn Levon expr = expr->unop; 10291f5207b7SJohn Levon if (expr->type != EXPR_STATEMENT) 10301f5207b7SJohn Levon return NULL; 10311f5207b7SJohn Levon stmt = expr->statement; 10321f5207b7SJohn Levon if (!stmt) 10331f5207b7SJohn Levon return NULL; 10341f5207b7SJohn Levon if (stmt->type == STMT_COMPOUND) { 10351f5207b7SJohn Levon last_stmt = last_ptr_list((struct ptr_list *)stmt->stmts); 10361f5207b7SJohn Levon if (!last_stmt) 10371f5207b7SJohn Levon return NULL; 10381f5207b7SJohn Levon if (last_stmt->type == STMT_LABEL) 10391f5207b7SJohn Levon last_stmt = last_stmt->label_statement; 10401f5207b7SJohn Levon if (last_stmt->type != STMT_EXPRESSION) 10411f5207b7SJohn Levon return NULL; 10421f5207b7SJohn Levon return last_stmt->expression; 10431f5207b7SJohn Levon } 10441f5207b7SJohn Levon if (stmt->type == STMT_EXPRESSION) 10451f5207b7SJohn Levon return stmt->expression; 10461f5207b7SJohn Levon return NULL; 10471f5207b7SJohn Levon } 10481f5207b7SJohn Levon 10491f5207b7SJohn Levon int get_param_num_from_sym(struct symbol *sym) 10501f5207b7SJohn Levon { 10511f5207b7SJohn Levon struct symbol *tmp; 10521f5207b7SJohn Levon int i; 10531f5207b7SJohn Levon 10541f5207b7SJohn Levon if (!cur_func_sym) 10551f5207b7SJohn Levon return -1; 10561f5207b7SJohn Levon 10571f5207b7SJohn Levon i = 0; 10581f5207b7SJohn Levon FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) { 10591f5207b7SJohn Levon if (tmp == sym) 10601f5207b7SJohn Levon return i; 10611f5207b7SJohn Levon i++; 10621f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 10631f5207b7SJohn Levon return -1; 10641f5207b7SJohn Levon } 10651f5207b7SJohn Levon 10661f5207b7SJohn Levon int get_param_num(struct expression *expr) 10671f5207b7SJohn Levon { 10681f5207b7SJohn Levon struct symbol *sym; 10691f5207b7SJohn Levon char *name; 10701f5207b7SJohn Levon 10711f5207b7SJohn Levon if (!cur_func_sym) 10721f5207b7SJohn Levon return -1; 10731f5207b7SJohn Levon name = expr_to_var_sym(expr, &sym); 10741f5207b7SJohn Levon free_string(name); 10751f5207b7SJohn Levon if (!sym) 10761f5207b7SJohn Levon return -1; 10771f5207b7SJohn Levon return get_param_num_from_sym(sym); 10781f5207b7SJohn Levon } 10791f5207b7SJohn Levon 1080*5a0e240fSJohn Levon struct symbol *get_param_sym_from_num(int num) 1081*5a0e240fSJohn Levon { 1082*5a0e240fSJohn Levon struct symbol *sym; 1083*5a0e240fSJohn Levon int i; 1084*5a0e240fSJohn Levon 1085*5a0e240fSJohn Levon if (!cur_func_sym) 1086*5a0e240fSJohn Levon return NULL; 1087*5a0e240fSJohn Levon 1088*5a0e240fSJohn Levon i = 0; 1089*5a0e240fSJohn Levon FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) { 1090*5a0e240fSJohn Levon if (i++ == num) 1091*5a0e240fSJohn Levon return sym; 1092*5a0e240fSJohn Levon } END_FOR_EACH_PTR(sym); 1093*5a0e240fSJohn Levon return NULL; 1094*5a0e240fSJohn Levon } 1095*5a0e240fSJohn Levon 10961f5207b7SJohn Levon int ms_since(struct timeval *start) 10971f5207b7SJohn Levon { 10981f5207b7SJohn Levon struct timeval end; 10991f5207b7SJohn Levon double diff; 11001f5207b7SJohn Levon 11011f5207b7SJohn Levon gettimeofday(&end, NULL); 11021f5207b7SJohn Levon diff = (end.tv_sec - start->tv_sec) * 1000.0; 11031f5207b7SJohn Levon diff += (end.tv_usec - start->tv_usec) / 1000.0; 11041f5207b7SJohn Levon return (int)diff; 11051f5207b7SJohn Levon } 11061f5207b7SJohn Levon 11071f5207b7SJohn Levon int parent_is_gone_var_sym(const char *name, struct symbol *sym) 11081f5207b7SJohn Levon { 11091f5207b7SJohn Levon if (!name || !sym) 11101f5207b7SJohn Levon return 0; 11111f5207b7SJohn Levon 11121f5207b7SJohn Levon if (parent_is_null_var_sym(name, sym) || 11131f5207b7SJohn Levon parent_is_free_var_sym(name, sym)) 11141f5207b7SJohn Levon return 1; 11151f5207b7SJohn Levon return 0; 11161f5207b7SJohn Levon } 11171f5207b7SJohn Levon 11181f5207b7SJohn Levon int parent_is_gone(struct expression *expr) 11191f5207b7SJohn Levon { 11201f5207b7SJohn Levon struct symbol *sym; 11211f5207b7SJohn Levon char *var; 11221f5207b7SJohn Levon int ret = 0; 11231f5207b7SJohn Levon 11241f5207b7SJohn Levon expr = strip_expr(expr); 11251f5207b7SJohn Levon var = expr_to_var_sym(expr, &sym); 11261f5207b7SJohn Levon if (!var || !sym) 11271f5207b7SJohn Levon goto free; 11281f5207b7SJohn Levon ret = parent_is_gone_var_sym(var, sym); 11291f5207b7SJohn Levon free: 11301f5207b7SJohn Levon free_string(var); 11311f5207b7SJohn Levon return ret; 11321f5207b7SJohn Levon } 11331f5207b7SJohn Levon 11341f5207b7SJohn Levon int invert_op(int op) 11351f5207b7SJohn Levon { 11361f5207b7SJohn Levon switch (op) { 11371f5207b7SJohn Levon case '*': 11381f5207b7SJohn Levon return '/'; 11391f5207b7SJohn Levon case '/': 11401f5207b7SJohn Levon return '*'; 11411f5207b7SJohn Levon case '+': 11421f5207b7SJohn Levon return '-'; 11431f5207b7SJohn Levon case '-': 11441f5207b7SJohn Levon return '+'; 11451f5207b7SJohn Levon case SPECIAL_LEFTSHIFT: 11461f5207b7SJohn Levon return SPECIAL_RIGHTSHIFT; 11471f5207b7SJohn Levon case SPECIAL_RIGHTSHIFT: 11481f5207b7SJohn Levon return SPECIAL_LEFTSHIFT; 11491f5207b7SJohn Levon } 11501f5207b7SJohn Levon return 0; 11511f5207b7SJohn Levon } 11521f5207b7SJohn Levon 1153efe51d0cSJohn Levon int op_remove_assign(int op) 1154efe51d0cSJohn Levon { 1155efe51d0cSJohn Levon switch (op) { 1156efe51d0cSJohn Levon case SPECIAL_ADD_ASSIGN: 1157efe51d0cSJohn Levon return '+'; 1158efe51d0cSJohn Levon case SPECIAL_SUB_ASSIGN: 1159efe51d0cSJohn Levon return '-'; 1160efe51d0cSJohn Levon case SPECIAL_MUL_ASSIGN: 1161efe51d0cSJohn Levon return '*'; 1162efe51d0cSJohn Levon case SPECIAL_DIV_ASSIGN: 1163efe51d0cSJohn Levon return '/'; 1164efe51d0cSJohn Levon case SPECIAL_MOD_ASSIGN: 1165efe51d0cSJohn Levon return '%'; 1166efe51d0cSJohn Levon case SPECIAL_AND_ASSIGN: 1167efe51d0cSJohn Levon return '&'; 1168efe51d0cSJohn Levon case SPECIAL_OR_ASSIGN: 1169efe51d0cSJohn Levon return '|'; 1170efe51d0cSJohn Levon case SPECIAL_XOR_ASSIGN: 1171efe51d0cSJohn Levon return '^'; 1172efe51d0cSJohn Levon case SPECIAL_SHL_ASSIGN: 1173efe51d0cSJohn Levon return SPECIAL_LEFTSHIFT; 1174efe51d0cSJohn Levon case SPECIAL_SHR_ASSIGN: 1175efe51d0cSJohn Levon return SPECIAL_RIGHTSHIFT; 1176efe51d0cSJohn Levon default: 1177efe51d0cSJohn Levon return op; 1178efe51d0cSJohn Levon } 1179efe51d0cSJohn Levon } 1180efe51d0cSJohn Levon 11811f5207b7SJohn Levon int expr_equiv(struct expression *one, struct expression *two) 11821f5207b7SJohn Levon { 11831f5207b7SJohn Levon struct symbol *one_sym = NULL; 11841f5207b7SJohn Levon struct symbol *two_sym = NULL; 11851f5207b7SJohn Levon char *one_name = NULL; 11861f5207b7SJohn Levon char *two_name = NULL; 11871f5207b7SJohn Levon int ret = 0; 11881f5207b7SJohn Levon 11891f5207b7SJohn Levon if (!one || !two) 11901f5207b7SJohn Levon return 0; 11911f5207b7SJohn Levon if (one->type != two->type) 11921f5207b7SJohn Levon return 0; 11931f5207b7SJohn Levon if (is_fake_call(one) || is_fake_call(two)) 11941f5207b7SJohn Levon return 0; 11951f5207b7SJohn Levon 11961f5207b7SJohn Levon one_name = expr_to_str_sym(one, &one_sym); 11971f5207b7SJohn Levon if (!one_name) 11981f5207b7SJohn Levon goto free; 11991f5207b7SJohn Levon two_name = expr_to_str_sym(two, &two_sym); 12001f5207b7SJohn Levon if (!two_name) 12011f5207b7SJohn Levon goto free; 12021f5207b7SJohn Levon if (one_sym != two_sym) 12031f5207b7SJohn Levon goto free; 12041f5207b7SJohn Levon /* 12051f5207b7SJohn Levon * This is a terrible hack because expr_to_str() sometimes gives up in 12061f5207b7SJohn Levon * the middle and just returns what it has. If you see a () you know 12071f5207b7SJohn Levon * the string is bogus. 12081f5207b7SJohn Levon */ 12091f5207b7SJohn Levon if (strstr(one_name, "()")) 12101f5207b7SJohn Levon goto free; 12111f5207b7SJohn Levon if (strcmp(one_name, two_name) == 0) 12121f5207b7SJohn Levon ret = 1; 12131f5207b7SJohn Levon free: 12141f5207b7SJohn Levon free_string(one_name); 12151f5207b7SJohn Levon free_string(two_name); 12161f5207b7SJohn Levon return ret; 12171f5207b7SJohn Levon } 12181f5207b7SJohn Levon 12191f5207b7SJohn Levon void push_int(struct int_stack **stack, int num) 12201f5207b7SJohn Levon { 12211f5207b7SJohn Levon int *munged; 12221f5207b7SJohn Levon 12231f5207b7SJohn Levon /* 12241f5207b7SJohn Levon * Just put the int on directly instead of a pointer to the int. 12251f5207b7SJohn Levon * Shift it to the left because Sparse uses the last two bits. 12261f5207b7SJohn Levon * This is sort of a dirty hack, yes. 12271f5207b7SJohn Levon */ 12281f5207b7SJohn Levon 12291f5207b7SJohn Levon munged = INT_PTR(num << 2); 12301f5207b7SJohn Levon 12311f5207b7SJohn Levon add_ptr_list(stack, munged); 12321f5207b7SJohn Levon } 12331f5207b7SJohn Levon 12341f5207b7SJohn Levon int pop_int(struct int_stack **stack) 12351f5207b7SJohn Levon { 12361f5207b7SJohn Levon int *num; 12371f5207b7SJohn Levon 12381f5207b7SJohn Levon num = last_ptr_list((struct ptr_list *)*stack); 12391f5207b7SJohn Levon delete_ptr_list_last((struct ptr_list **)stack); 12401f5207b7SJohn Levon 12411f5207b7SJohn Levon return PTR_INT(num) >> 2; 12421f5207b7SJohn Levon } 1243