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 150*6523a3aaSJohn Levon 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, 177*6523a3aaSJohn Levon int *complicated) 1781f5207b7SJohn Levon { 1791f5207b7SJohn Levon if (!expr) { 1801f5207b7SJohn Levon /* can't happen on valid code */ 1811f5207b7SJohn Levon *complicated = 1; 1821f5207b7SJohn Levon return; 1831f5207b7SJohn Levon } 1841f5207b7SJohn Levon 1851f5207b7SJohn Levon switch (expr->type) { 1861f5207b7SJohn Levon case EXPR_DEREF: { 1871f5207b7SJohn Levon struct expression *deref; 1881f5207b7SJohn Levon int op; 1891f5207b7SJohn Levon 1901f5207b7SJohn Levon deref = expr->deref; 1911f5207b7SJohn Levon op = deref->op; 192efe51d0cSJohn Levon if (deref->type == EXPR_PREOP && op == '*') { 1931f5207b7SJohn Levon struct expression *unop = strip_expr(deref->unop); 1941f5207b7SJohn Levon 1951f5207b7SJohn Levon if (unop->type == EXPR_PREOP && unop->op == '&') { 1961f5207b7SJohn Levon deref = unop->unop; 1971f5207b7SJohn Levon op = '.'; 1981f5207b7SJohn Levon } else { 199efe51d0cSJohn Levon if (!is_pointer(deref) && !is_pointer(deref->unop)) 2001f5207b7SJohn Levon op = '.'; 201efe51d0cSJohn Levon deref = deref->unop; 2021f5207b7SJohn Levon } 2031f5207b7SJohn Levon } 2041f5207b7SJohn Levon 205*6523a3aaSJohn Levon __get_variable_from_expr(sym_ptr, buf, deref, len, complicated); 2061f5207b7SJohn Levon 2071f5207b7SJohn Levon if (op == '*') 2081f5207b7SJohn Levon append(buf, "->", len); 2091f5207b7SJohn Levon else 2101f5207b7SJohn Levon append(buf, ".", len); 2111f5207b7SJohn Levon 2121f5207b7SJohn Levon if (expr->member) 2131f5207b7SJohn Levon append(buf, expr->member->name, len); 2141f5207b7SJohn Levon else 2151f5207b7SJohn Levon append(buf, "unknown_member", len); 2161f5207b7SJohn Levon 2171f5207b7SJohn Levon return; 2181f5207b7SJohn Levon } 2191f5207b7SJohn Levon case EXPR_SYMBOL: 2201f5207b7SJohn Levon if (expr->symbol_name) 2211f5207b7SJohn Levon append(buf, expr->symbol_name->name, len); 2221f5207b7SJohn Levon if (sym_ptr) { 2231f5207b7SJohn Levon if (*sym_ptr) 2241f5207b7SJohn Levon *complicated = 1; 2251f5207b7SJohn Levon *sym_ptr = expr->symbol; 2261f5207b7SJohn Levon } 2271f5207b7SJohn Levon return; 2281f5207b7SJohn Levon case EXPR_PREOP: { 2291f5207b7SJohn Levon const char *tmp; 2301f5207b7SJohn Levon 2311f5207b7SJohn Levon if (get_expression_statement(expr)) { 2321f5207b7SJohn Levon *complicated = 2; 2331f5207b7SJohn Levon return; 2341f5207b7SJohn Levon } 2351f5207b7SJohn Levon 2361f5207b7SJohn Levon if (expr->op == '(') { 237*6523a3aaSJohn Levon if (expr->unop->type != EXPR_SYMBOL) 2381f5207b7SJohn Levon append(buf, "(", len); 2391f5207b7SJohn Levon } else if (expr->op != '*' || !get_array_expr(expr->unop)) { 2401f5207b7SJohn Levon tmp = show_special(expr->op); 2411f5207b7SJohn Levon append(buf, tmp, len); 2421f5207b7SJohn Levon } 2431f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, expr->unop, 244*6523a3aaSJohn Levon len, complicated); 2451f5207b7SJohn Levon 246*6523a3aaSJohn Levon if (expr->op == '(' && expr->unop->type != EXPR_SYMBOL) 2471f5207b7SJohn Levon append(buf, ")", len); 2481f5207b7SJohn Levon 2491f5207b7SJohn Levon if (expr->op == SPECIAL_DECREMENT || 250*6523a3aaSJohn Levon expr->op == SPECIAL_INCREMENT) 2511f5207b7SJohn Levon *complicated = 1; 2521f5207b7SJohn Levon 2531f5207b7SJohn Levon return; 2541f5207b7SJohn Levon } 2551f5207b7SJohn Levon case EXPR_POSTOP: { 2561f5207b7SJohn Levon const char *tmp; 2571f5207b7SJohn Levon 2581f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, expr->unop, 259*6523a3aaSJohn Levon len, complicated); 2601f5207b7SJohn Levon tmp = show_special(expr->op); 2611f5207b7SJohn Levon append(buf, tmp, len); 2621f5207b7SJohn Levon 2631f5207b7SJohn Levon if (expr->op == SPECIAL_DECREMENT || expr->op == SPECIAL_INCREMENT) 2641f5207b7SJohn Levon *complicated = 1; 2651f5207b7SJohn Levon return; 2661f5207b7SJohn Levon } 2671f5207b7SJohn Levon case EXPR_ASSIGNMENT: 2681f5207b7SJohn Levon case EXPR_COMPARE: 2691f5207b7SJohn Levon case EXPR_LOGICAL: 2701f5207b7SJohn Levon case EXPR_BINOP: { 2711f5207b7SJohn Levon char tmp[10]; 2721f5207b7SJohn Levon struct expression *array_expr; 2731f5207b7SJohn Levon 2741f5207b7SJohn Levon *complicated = 1; 2751f5207b7SJohn Levon array_expr = get_array_expr(expr); 2761f5207b7SJohn Levon if (array_expr) { 277*6523a3aaSJohn Levon __get_variable_from_expr(sym_ptr, buf, array_expr, len, complicated); 2781f5207b7SJohn Levon append(buf, "[", len); 2791f5207b7SJohn Levon } else { 280*6523a3aaSJohn Levon __get_variable_from_expr(sym_ptr, buf, expr->left, len, complicated); 2811f5207b7SJohn Levon snprintf(tmp, sizeof(tmp), " %s ", show_special(expr->op)); 2821f5207b7SJohn Levon append(buf, tmp, len); 2831f5207b7SJohn Levon } 284*6523a3aaSJohn Levon __get_variable_from_expr(NULL, buf, expr->right, len, complicated); 2851f5207b7SJohn Levon if (array_expr) 2861f5207b7SJohn Levon append(buf, "]", len); 2871f5207b7SJohn Levon return; 2881f5207b7SJohn Levon } 2891f5207b7SJohn Levon case EXPR_VALUE: { 290c85f09ccSJohn Levon sval_t sval = {}; 2911f5207b7SJohn Levon char tmp[25]; 2921f5207b7SJohn Levon 2931f5207b7SJohn Levon *complicated = 1; 294c85f09ccSJohn Levon if (!get_value(expr, &sval)) 295c85f09ccSJohn Levon return; 296c85f09ccSJohn Levon snprintf(tmp, 25, "%s", sval_to_numstr(sval)); 2971f5207b7SJohn Levon append(buf, tmp, len); 2981f5207b7SJohn Levon return; 2991f5207b7SJohn Levon } 3005a0e240fSJohn Levon case EXPR_FVALUE: { 3015a0e240fSJohn Levon sval_t sval = {}; 3025a0e240fSJohn Levon char tmp[25]; 3035a0e240fSJohn Levon 3045a0e240fSJohn Levon *complicated = 1; 3055a0e240fSJohn Levon if (!get_value(expr, &sval)) 3065a0e240fSJohn Levon return; 3075a0e240fSJohn Levon snprintf(tmp, 25, "%s", sval_to_numstr(sval)); 3085a0e240fSJohn Levon append(buf, tmp, len); 3095a0e240fSJohn Levon return; 3105a0e240fSJohn Levon } 3111f5207b7SJohn Levon case EXPR_STRING: 3121f5207b7SJohn Levon append(buf, "\"", len); 3131f5207b7SJohn Levon if (expr->string) 3141f5207b7SJohn Levon append(buf, expr->string->data, len); 3151f5207b7SJohn Levon append(buf, "\"", len); 3161f5207b7SJohn Levon return; 3171f5207b7SJohn Levon case EXPR_CALL: { 3181f5207b7SJohn Levon struct expression *tmp; 3191f5207b7SJohn Levon int i; 3201f5207b7SJohn Levon 3211f5207b7SJohn Levon *complicated = 1; 322*6523a3aaSJohn Levon __get_variable_from_expr(NULL, buf, expr->fn, len, complicated); 3231f5207b7SJohn Levon append(buf, "(", len); 3241f5207b7SJohn Levon i = 0; 3251f5207b7SJohn Levon FOR_EACH_PTR(expr->args, tmp) { 3261f5207b7SJohn Levon if (i++) 3271f5207b7SJohn Levon append(buf, ", ", len); 328*6523a3aaSJohn Levon __get_variable_from_expr(NULL, buf, tmp, len, complicated); 3291f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 3301f5207b7SJohn Levon append(buf, ")", len); 3311f5207b7SJohn Levon return; 3321f5207b7SJohn Levon } 3331f5207b7SJohn Levon case EXPR_CAST: 3341f5207b7SJohn Levon case EXPR_FORCE_CAST: 3351f5207b7SJohn Levon __get_variable_from_expr(sym_ptr, buf, 3361f5207b7SJohn Levon expr->cast_expression, len, 337*6523a3aaSJohn Levon complicated); 3381f5207b7SJohn Levon return; 3391f5207b7SJohn Levon case EXPR_SIZEOF: { 3401f5207b7SJohn Levon sval_t sval; 3411f5207b7SJohn Levon int size; 3421f5207b7SJohn Levon char tmp[25]; 3431f5207b7SJohn Levon 3441f5207b7SJohn Levon if (expr->cast_type && get_base_type(expr->cast_type)) { 3451f5207b7SJohn Levon size = type_bytes(get_base_type(expr->cast_type)); 3461f5207b7SJohn Levon snprintf(tmp, 25, "%d", size); 3471f5207b7SJohn Levon append(buf, tmp, len); 3481f5207b7SJohn Levon } else if (get_value(expr, &sval)) { 3491f5207b7SJohn Levon snprintf(tmp, 25, "%s", sval_to_str(sval)); 3501f5207b7SJohn Levon append(buf, tmp, len); 3511f5207b7SJohn Levon } 3521f5207b7SJohn Levon return; 3531f5207b7SJohn Levon } 3541f5207b7SJohn Levon case EXPR_IDENTIFIER: 3551f5207b7SJohn Levon *complicated = 1; 3561f5207b7SJohn Levon if (expr->expr_ident) 3571f5207b7SJohn Levon append(buf, expr->expr_ident->name, len); 3581f5207b7SJohn Levon return; 359*6523a3aaSJohn Levon case EXPR_SELECT: 360*6523a3aaSJohn Levon case EXPR_CONDITIONAL: 3611f5207b7SJohn Levon *complicated = 1; 362*6523a3aaSJohn Levon append(buf, "(", len); 363*6523a3aaSJohn Levon __get_variable_from_expr(NULL, buf, expr->conditional, len, complicated); 364*6523a3aaSJohn Levon append(buf, ") ?", len); 365*6523a3aaSJohn Levon if (expr->cond_true) 366*6523a3aaSJohn Levon __get_variable_from_expr(NULL, buf, expr->cond_true, len, complicated); 367*6523a3aaSJohn Levon append(buf, ":", len); 368*6523a3aaSJohn Levon __get_variable_from_expr(NULL, buf, expr->cond_false, len, complicated); 369*6523a3aaSJohn Levon return; 370*6523a3aaSJohn Levon default: { 371*6523a3aaSJohn Levon char tmp[64]; 372*6523a3aaSJohn Levon 373*6523a3aaSJohn Levon snprintf(tmp, sizeof(tmp), "$expr_%p(%d)", expr, expr->type); 374*6523a3aaSJohn Levon append(buf, tmp, len); 375*6523a3aaSJohn Levon *complicated = 1; 376*6523a3aaSJohn Levon } 3771f5207b7SJohn Levon return; 3781f5207b7SJohn Levon } 3791f5207b7SJohn Levon } 3801f5207b7SJohn Levon 3811f5207b7SJohn Levon struct expr_str_cache_results { 3821f5207b7SJohn Levon struct expression *expr; 3831f5207b7SJohn Levon char str[VAR_LEN]; 3841f5207b7SJohn Levon struct symbol *sym; 3851f5207b7SJohn Levon int complicated; 3861f5207b7SJohn Levon }; 3871f5207b7SJohn Levon 3881f5207b7SJohn Levon static void get_variable_from_expr(struct symbol **sym_ptr, char *buf, 3891f5207b7SJohn Levon struct expression *expr, int len, 390*6523a3aaSJohn Levon int *complicated) 3911f5207b7SJohn Levon { 3921f5207b7SJohn Levon static struct expr_str_cache_results cached[8]; 3931f5207b7SJohn Levon struct symbol *tmp_sym = NULL; 3941f5207b7SJohn Levon static int idx; 3951f5207b7SJohn Levon int i; 3961f5207b7SJohn Levon 3971f5207b7SJohn Levon for (i = 0; i < ARRAY_SIZE(cached); i++) { 398*6523a3aaSJohn Levon if (expr == cached[i].expr) { 3991f5207b7SJohn Levon strncpy(buf, cached[i].str, len); 4001f5207b7SJohn Levon if (sym_ptr) 4011f5207b7SJohn Levon *sym_ptr = cached[i].sym; 4021f5207b7SJohn Levon *complicated = cached[i].complicated; 4031f5207b7SJohn Levon return; 4041f5207b7SJohn Levon } 4051f5207b7SJohn Levon } 4061f5207b7SJohn Levon 407*6523a3aaSJohn Levon __get_variable_from_expr(&tmp_sym, buf, expr, len, complicated); 4081f5207b7SJohn Levon if (sym_ptr) 4091f5207b7SJohn Levon *sym_ptr = tmp_sym; 4101f5207b7SJohn Levon 411*6523a3aaSJohn Levon if (expr->smatch_flags & Tmp) 412*6523a3aaSJohn Levon return; 413*6523a3aaSJohn Levon 4141f5207b7SJohn Levon cached[idx].expr = expr; 4151f5207b7SJohn Levon strncpy(cached[idx].str, buf, VAR_LEN); 4161f5207b7SJohn Levon cached[idx].sym = tmp_sym; 4171f5207b7SJohn Levon cached[idx].complicated = *complicated; 4181f5207b7SJohn Levon 4191f5207b7SJohn Levon idx = (idx + 1) % ARRAY_SIZE(cached); 4201f5207b7SJohn Levon } 4211f5207b7SJohn Levon 4221f5207b7SJohn Levon /* 4231f5207b7SJohn Levon * This is returns a stylized "c looking" representation of the 4241f5207b7SJohn Levon * variable name. 4251f5207b7SJohn Levon * 4261f5207b7SJohn Levon * It uses the same buffer every time so you have to save the result 4271f5207b7SJohn Levon * yourself if you want to keep it. 4281f5207b7SJohn Levon * 4291f5207b7SJohn Levon */ 4301f5207b7SJohn Levon 4311f5207b7SJohn Levon char *expr_to_str_sym(struct expression *expr, struct symbol **sym_ptr) 4321f5207b7SJohn Levon { 4331f5207b7SJohn Levon static char var_name[VAR_LEN]; 4341f5207b7SJohn Levon int complicated = 0; 4351f5207b7SJohn Levon 4361f5207b7SJohn Levon if (sym_ptr) 4371f5207b7SJohn Levon *sym_ptr = NULL; 4381f5207b7SJohn Levon var_name[0] = '\0'; 4391f5207b7SJohn Levon 4401f5207b7SJohn Levon if (!expr) 4411f5207b7SJohn Levon return NULL; 4421f5207b7SJohn Levon get_variable_from_expr(sym_ptr, var_name, expr, sizeof(var_name), 443*6523a3aaSJohn Levon &complicated); 4441f5207b7SJohn Levon if (complicated < 2) 4451f5207b7SJohn Levon return alloc_string(var_name); 4461f5207b7SJohn Levon else 4471f5207b7SJohn Levon return NULL; 4481f5207b7SJohn Levon } 4491f5207b7SJohn Levon 4501f5207b7SJohn Levon char *expr_to_str(struct expression *expr) 4511f5207b7SJohn Levon { 4521f5207b7SJohn Levon return expr_to_str_sym(expr, NULL); 4531f5207b7SJohn Levon } 4541f5207b7SJohn Levon 4551f5207b7SJohn Levon /* 4561f5207b7SJohn Levon * get_variable_from_expr_simple() only returns simple variables. 4571f5207b7SJohn Levon * If it's a complicated variable like a->foo[x] instead of just 'a->foo' 4581f5207b7SJohn Levon * then it returns NULL. 4591f5207b7SJohn Levon */ 4601f5207b7SJohn Levon char *expr_to_var_sym(struct expression *expr, 4611f5207b7SJohn Levon struct symbol **sym_ptr) 4621f5207b7SJohn Levon { 4631f5207b7SJohn Levon static char var_name[VAR_LEN]; 4641f5207b7SJohn Levon int complicated = 0; 4651f5207b7SJohn Levon 4661f5207b7SJohn Levon if (sym_ptr) 4671f5207b7SJohn Levon *sym_ptr = NULL; 4681f5207b7SJohn Levon var_name[0] = '\0'; 4691f5207b7SJohn Levon 4701f5207b7SJohn Levon if (!expr) 4711f5207b7SJohn Levon return NULL; 4721f5207b7SJohn Levon expr = strip_expr(expr); 4731f5207b7SJohn Levon get_variable_from_expr(sym_ptr, var_name, expr, sizeof(var_name), 474*6523a3aaSJohn Levon &complicated); 4751f5207b7SJohn Levon 4761f5207b7SJohn Levon if (complicated) { 4771f5207b7SJohn Levon if (sym_ptr) 4781f5207b7SJohn Levon *sym_ptr = NULL; 4791f5207b7SJohn Levon return NULL; 4801f5207b7SJohn Levon } 4811f5207b7SJohn Levon return alloc_string(var_name); 4821f5207b7SJohn Levon } 4831f5207b7SJohn Levon 4841f5207b7SJohn Levon char *expr_to_var(struct expression *expr) 4851f5207b7SJohn Levon { 4861f5207b7SJohn Levon return expr_to_var_sym(expr, NULL); 4871f5207b7SJohn Levon } 4881f5207b7SJohn Levon 4891f5207b7SJohn Levon struct symbol *expr_to_sym(struct expression *expr) 4901f5207b7SJohn Levon { 4911f5207b7SJohn Levon struct symbol *sym; 4921f5207b7SJohn Levon char *name; 4931f5207b7SJohn Levon 4941f5207b7SJohn Levon name = expr_to_var_sym(expr, &sym); 4951f5207b7SJohn Levon free_string(name); 4961f5207b7SJohn Levon return sym; 4971f5207b7SJohn Levon } 4981f5207b7SJohn Levon 4991f5207b7SJohn Levon int get_complication_score(struct expression *expr) 5001f5207b7SJohn Levon { 5011f5207b7SJohn Levon expr = strip_expr(expr); 5021f5207b7SJohn Levon 5031f5207b7SJohn Levon /* 5041f5207b7SJohn Levon * Don't forget to keep get_complication_score() and store_all_links() 5051f5207b7SJohn Levon * in sync. 5061f5207b7SJohn Levon * 5071f5207b7SJohn Levon */ 5081f5207b7SJohn Levon 5091f5207b7SJohn Levon if (!expr) 5101f5207b7SJohn Levon return 990; 5111f5207b7SJohn Levon 5121f5207b7SJohn Levon switch (expr->type) { 5131f5207b7SJohn Levon case EXPR_CALL: 5141f5207b7SJohn Levon return 991; 5151f5207b7SJohn Levon case EXPR_COMPARE: 5161f5207b7SJohn Levon case EXPR_BINOP: 5171f5207b7SJohn Levon return get_complication_score(expr->left) + 5181f5207b7SJohn Levon get_complication_score(expr->right); 5191f5207b7SJohn Levon case EXPR_SYMBOL: 5201f5207b7SJohn Levon return 1; 5211f5207b7SJohn Levon case EXPR_PREOP: 5221f5207b7SJohn Levon if (expr->op == '*' || expr->op == '(') 5231f5207b7SJohn Levon return get_complication_score(expr->unop); 5241f5207b7SJohn Levon return 993; 5251f5207b7SJohn Levon case EXPR_DEREF: 5261f5207b7SJohn Levon return get_complication_score(expr->deref); 5271f5207b7SJohn Levon case EXPR_VALUE: 5281f5207b7SJohn Levon case EXPR_SIZEOF: 5291f5207b7SJohn Levon return 0; 5301f5207b7SJohn Levon default: 5311f5207b7SJohn Levon return 994; 5321f5207b7SJohn Levon } 5331f5207b7SJohn Levon } 5341f5207b7SJohn Levon 5351f5207b7SJohn Levon struct expression *reorder_expr_alphabetically(struct expression *expr) 5361f5207b7SJohn Levon { 5371f5207b7SJohn Levon struct expression *ret; 5381f5207b7SJohn Levon char *left, *right; 5391f5207b7SJohn Levon 5401f5207b7SJohn Levon if (expr->type != EXPR_BINOP) 5411f5207b7SJohn Levon return expr; 5421f5207b7SJohn Levon if (expr->op != '+' && expr->op != '*') 5431f5207b7SJohn Levon return expr; 5441f5207b7SJohn Levon 5451f5207b7SJohn Levon left = expr_to_var(expr->left); 5461f5207b7SJohn Levon right = expr_to_var(expr->right); 5471f5207b7SJohn Levon ret = expr; 5481f5207b7SJohn Levon if (!left || !right) 5491f5207b7SJohn Levon goto free; 5501f5207b7SJohn Levon if (strcmp(left, right) <= 0) 5511f5207b7SJohn Levon goto free; 5521f5207b7SJohn Levon 5531f5207b7SJohn Levon ret = binop_expression(expr->right, expr->op, expr->left); 5541f5207b7SJohn Levon free: 5551f5207b7SJohn Levon free_string(left); 5561f5207b7SJohn Levon free_string(right); 5571f5207b7SJohn Levon 5581f5207b7SJohn Levon return ret; 5591f5207b7SJohn Levon } 5601f5207b7SJohn Levon 5611f5207b7SJohn Levon char *expr_to_chunk_helper(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl) 5621f5207b7SJohn Levon { 5631f5207b7SJohn Levon struct var_sym_list *tmp_vsl; 5641f5207b7SJohn Levon char *name; 5651f5207b7SJohn Levon struct symbol *tmp; 5661f5207b7SJohn Levon int score; 5671f5207b7SJohn Levon 5681f5207b7SJohn Levon if (vsl) 5691f5207b7SJohn Levon *vsl = NULL; 5701f5207b7SJohn Levon if (sym) 5711f5207b7SJohn Levon *sym = NULL; 5721f5207b7SJohn Levon 5731f5207b7SJohn Levon expr = strip_parens(expr); 5741f5207b7SJohn Levon if (!expr) 5751f5207b7SJohn Levon return NULL; 5761f5207b7SJohn Levon 5771f5207b7SJohn Levon name = expr_to_var_sym(expr, &tmp); 5781f5207b7SJohn Levon if (name && tmp) { 5791f5207b7SJohn Levon if (sym) 5801f5207b7SJohn Levon *sym = tmp; 5811f5207b7SJohn Levon if (vsl) 582efe51d0cSJohn Levon add_var_sym(vsl, name, tmp); 5831f5207b7SJohn Levon return name; 5841f5207b7SJohn Levon } 5851f5207b7SJohn Levon free_string(name); 5861f5207b7SJohn Levon 5871f5207b7SJohn Levon score = get_complication_score(expr); 5881f5207b7SJohn Levon if (score <= 0 || score > 2) 5891f5207b7SJohn Levon return NULL; 5901f5207b7SJohn Levon 5911f5207b7SJohn Levon tmp_vsl = expr_to_vsl(expr); 5921f5207b7SJohn Levon if (vsl) { 5931f5207b7SJohn Levon *vsl = tmp_vsl; 5941f5207b7SJohn Levon if (!*vsl) 5951f5207b7SJohn Levon return NULL; 5961f5207b7SJohn Levon } 5971f5207b7SJohn Levon if (sym) { 5981f5207b7SJohn Levon if (ptr_list_size((struct ptr_list *)tmp_vsl) == 1) { 5991f5207b7SJohn Levon struct var_sym *vs; 6001f5207b7SJohn Levon 6011f5207b7SJohn Levon vs = first_ptr_list((struct ptr_list *)tmp_vsl); 6021f5207b7SJohn Levon *sym = vs->sym; 6031f5207b7SJohn Levon } 6041f5207b7SJohn Levon } 6051f5207b7SJohn Levon 6061f5207b7SJohn Levon expr = reorder_expr_alphabetically(expr); 6071f5207b7SJohn Levon 6081f5207b7SJohn Levon return expr_to_str(expr); 6091f5207b7SJohn Levon } 6101f5207b7SJohn Levon 6111f5207b7SJohn Levon char *expr_to_known_chunk_sym(struct expression *expr, struct symbol **sym) 6121f5207b7SJohn Levon { 6131f5207b7SJohn Levon return expr_to_chunk_helper(expr, sym, NULL); 6141f5207b7SJohn Levon } 6151f5207b7SJohn Levon 6161f5207b7SJohn Levon char *expr_to_chunk_sym_vsl(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl) 6171f5207b7SJohn Levon { 6181f5207b7SJohn Levon return expr_to_chunk_helper(expr, sym, vsl); 6191f5207b7SJohn Levon } 6201f5207b7SJohn Levon 6211f5207b7SJohn Levon int sym_name_is(const char *name, struct expression *expr) 6221f5207b7SJohn Levon { 6231f5207b7SJohn Levon if (!expr) 6241f5207b7SJohn Levon return 0; 6251f5207b7SJohn Levon if (expr->type != EXPR_SYMBOL) 6261f5207b7SJohn Levon return 0; 6271f5207b7SJohn Levon if (!strcmp(expr->symbol_name->name, name)) 6281f5207b7SJohn Levon return 1; 6291f5207b7SJohn Levon return 0; 6301f5207b7SJohn Levon } 6311f5207b7SJohn Levon 632c85f09ccSJohn Levon int expr_is_zero(struct expression *expr) 6331f5207b7SJohn Levon { 6341f5207b7SJohn Levon sval_t sval; 6351f5207b7SJohn Levon 6361f5207b7SJohn Levon if (get_value(expr, &sval) && sval.value == 0) 6371f5207b7SJohn Levon return 1; 6381f5207b7SJohn Levon return 0; 6391f5207b7SJohn Levon } 6401f5207b7SJohn Levon 6411f5207b7SJohn Levon int is_array(struct expression *expr) 6421f5207b7SJohn Levon { 6431f5207b7SJohn Levon struct symbol *type; 6441f5207b7SJohn Levon 6451f5207b7SJohn Levon expr = strip_expr(expr); 6461f5207b7SJohn Levon if (!expr) 6471f5207b7SJohn Levon return 0; 6481f5207b7SJohn Levon 6491f5207b7SJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') { 6501f5207b7SJohn Levon expr = strip_expr(expr->unop); 6511f5207b7SJohn Levon if (!expr) 6521f5207b7SJohn Levon return 0; 6531f5207b7SJohn Levon if (expr->type == EXPR_BINOP && expr->op == '+') 6541f5207b7SJohn Levon return 1; 6551f5207b7SJohn Levon } 6561f5207b7SJohn Levon 6571f5207b7SJohn Levon if (expr->type != EXPR_BINOP || expr->op != '+') 6581f5207b7SJohn Levon return 0; 6591f5207b7SJohn Levon 6601f5207b7SJohn Levon type = get_type(expr->left); 6611f5207b7SJohn Levon if (!type || type->type != SYM_ARRAY) 6621f5207b7SJohn Levon return 0; 6631f5207b7SJohn Levon 6641f5207b7SJohn Levon return 1; 6651f5207b7SJohn Levon } 6661f5207b7SJohn Levon 6671f5207b7SJohn Levon struct expression *get_array_base(struct expression *expr) 6681f5207b7SJohn Levon { 6691f5207b7SJohn Levon if (!is_array(expr)) 6701f5207b7SJohn Levon return NULL; 6711f5207b7SJohn Levon expr = strip_expr(expr); 6721f5207b7SJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') 6731f5207b7SJohn Levon expr = strip_expr(expr->unop); 6741f5207b7SJohn Levon if (expr->type != EXPR_BINOP || expr->op != '+') 6751f5207b7SJohn Levon return NULL; 6761f5207b7SJohn Levon return strip_parens(expr->left); 6771f5207b7SJohn Levon } 6781f5207b7SJohn Levon 6791f5207b7SJohn Levon struct expression *get_array_offset(struct expression *expr) 6801f5207b7SJohn Levon { 6811f5207b7SJohn Levon if (!is_array(expr)) 6821f5207b7SJohn Levon return NULL; 6831f5207b7SJohn Levon expr = strip_expr(expr); 6841f5207b7SJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') 6851f5207b7SJohn Levon expr = strip_expr(expr->unop); 6861f5207b7SJohn Levon if (expr->type != EXPR_BINOP || expr->op != '+') 6871f5207b7SJohn Levon return NULL; 6881f5207b7SJohn Levon return strip_parens(expr->right); 6891f5207b7SJohn Levon } 6901f5207b7SJohn Levon 6911f5207b7SJohn Levon const char *show_state(struct smatch_state *state) 6921f5207b7SJohn Levon { 6931f5207b7SJohn Levon if (!state) 6941f5207b7SJohn Levon return NULL; 6951f5207b7SJohn Levon return state->name; 6961f5207b7SJohn Levon } 6971f5207b7SJohn Levon 6981f5207b7SJohn Levon struct statement *get_expression_statement(struct expression *expr) 6991f5207b7SJohn Levon { 7001f5207b7SJohn Levon /* What are those things called? if (({....; ret;})) { ...*/ 7011f5207b7SJohn Levon 7021f5207b7SJohn Levon if (expr->type != EXPR_PREOP) 7031f5207b7SJohn Levon return NULL; 7041f5207b7SJohn Levon if (expr->op != '(') 7051f5207b7SJohn Levon return NULL; 7061f5207b7SJohn Levon if (!expr->unop) 7071f5207b7SJohn Levon return NULL; 7081f5207b7SJohn Levon if (expr->unop->type != EXPR_STATEMENT) 7091f5207b7SJohn Levon return NULL; 7101f5207b7SJohn Levon if (expr->unop->statement->type != STMT_COMPOUND) 7111f5207b7SJohn Levon return NULL; 7121f5207b7SJohn Levon return expr->unop->statement; 7131f5207b7SJohn Levon } 7141f5207b7SJohn Levon 7151f5207b7SJohn Levon struct expression *strip_parens(struct expression *expr) 7161f5207b7SJohn Levon { 7171f5207b7SJohn Levon if (!expr) 7181f5207b7SJohn Levon return NULL; 7191f5207b7SJohn Levon 7201f5207b7SJohn Levon if (expr->type == EXPR_PREOP) { 7211f5207b7SJohn Levon if (!expr->unop) 7221f5207b7SJohn Levon return expr; /* parsing invalid code */ 7231f5207b7SJohn Levon 7241f5207b7SJohn Levon if (expr->op == '(' && expr->unop->type == EXPR_STATEMENT && 7251f5207b7SJohn Levon expr->unop->statement->type == STMT_COMPOUND) 7261f5207b7SJohn Levon return expr; 7271f5207b7SJohn Levon if (expr->op == '(') 7281f5207b7SJohn Levon return strip_parens(expr->unop); 7291f5207b7SJohn Levon } 7301f5207b7SJohn Levon return expr; 7311f5207b7SJohn Levon } 7321f5207b7SJohn Levon 7331f5207b7SJohn Levon static struct expression *strip_expr_helper(struct expression *expr, bool set_parent) 7341f5207b7SJohn Levon { 7351f5207b7SJohn Levon if (!expr) 7361f5207b7SJohn Levon return NULL; 7371f5207b7SJohn Levon 7381f5207b7SJohn Levon switch (expr->type) { 7391f5207b7SJohn Levon case EXPR_FORCE_CAST: 7401f5207b7SJohn Levon case EXPR_CAST: 7411f5207b7SJohn Levon if (set_parent) 7421f5207b7SJohn Levon expr_set_parent_expr(expr->cast_expression, expr); 7431f5207b7SJohn Levon 7441f5207b7SJohn Levon if (!expr->cast_expression) 7451f5207b7SJohn Levon return expr; 7461f5207b7SJohn Levon return strip_expr_helper(expr->cast_expression, set_parent); 7471f5207b7SJohn Levon case EXPR_PREOP: { 7481f5207b7SJohn Levon struct expression *unop; 7491f5207b7SJohn Levon 7501f5207b7SJohn Levon if (!expr->unop) /* parsing invalid code */ 7511f5207b7SJohn Levon return expr; 7521f5207b7SJohn Levon if (set_parent) 7531f5207b7SJohn Levon expr_set_parent_expr(expr->unop, expr); 7541f5207b7SJohn Levon 7551f5207b7SJohn Levon 7561f5207b7SJohn Levon if (expr->op == '(' && expr->unop->type == EXPR_STATEMENT && 7571f5207b7SJohn Levon expr->unop->statement->type == STMT_COMPOUND) 7581f5207b7SJohn Levon return expr; 7591f5207b7SJohn Levon 7601f5207b7SJohn Levon unop = strip_expr_helper(expr->unop, set_parent); 7611f5207b7SJohn Levon 7621f5207b7SJohn Levon if (expr->op == '*' && unop && 7631f5207b7SJohn Levon unop->type == EXPR_PREOP && unop->op == '&') { 7641f5207b7SJohn Levon struct symbol *type = get_type(unop->unop); 7651f5207b7SJohn Levon 7661f5207b7SJohn Levon if (type && type->type == SYM_ARRAY) 7671f5207b7SJohn Levon return expr; 7681f5207b7SJohn Levon return strip_expr_helper(unop->unop, set_parent); 7691f5207b7SJohn Levon } 7701f5207b7SJohn Levon 7711f5207b7SJohn Levon if (expr->op == '(') 7721f5207b7SJohn Levon return unop; 7731f5207b7SJohn Levon 7741f5207b7SJohn Levon return expr; 7751f5207b7SJohn Levon } 7761f5207b7SJohn Levon case EXPR_CONDITIONAL: 7771f5207b7SJohn Levon if (known_condition_true(expr->conditional)) { 7781f5207b7SJohn Levon if (expr->cond_true) { 7791f5207b7SJohn Levon if (set_parent) 7801f5207b7SJohn Levon expr_set_parent_expr(expr->cond_true, expr); 7811f5207b7SJohn Levon return strip_expr_helper(expr->cond_true, set_parent); 7821f5207b7SJohn Levon } 7831f5207b7SJohn Levon if (set_parent) 7841f5207b7SJohn Levon expr_set_parent_expr(expr->conditional, expr); 7851f5207b7SJohn Levon return strip_expr_helper(expr->conditional, set_parent); 7861f5207b7SJohn Levon } 7871f5207b7SJohn Levon if (known_condition_false(expr->conditional)) { 7881f5207b7SJohn Levon if (set_parent) 7891f5207b7SJohn Levon expr_set_parent_expr(expr->cond_false, expr); 7901f5207b7SJohn Levon return strip_expr_helper(expr->cond_false, set_parent); 7911f5207b7SJohn Levon } 7921f5207b7SJohn Levon return expr; 7931f5207b7SJohn Levon case EXPR_CALL: 7941f5207b7SJohn Levon if (sym_name_is("__builtin_expect", expr->fn) || 7951f5207b7SJohn Levon sym_name_is("__builtin_bswap16", expr->fn) || 7961f5207b7SJohn Levon sym_name_is("__builtin_bswap32", expr->fn) || 7971f5207b7SJohn Levon sym_name_is("__builtin_bswap64", expr->fn)) { 7981f5207b7SJohn Levon expr = get_argument_from_call_expr(expr->args, 0); 7991f5207b7SJohn Levon return strip_expr_helper(expr, set_parent); 8001f5207b7SJohn Levon } 8011f5207b7SJohn Levon return expr; 8021f5207b7SJohn Levon } 8031f5207b7SJohn Levon return expr; 8041f5207b7SJohn Levon } 8051f5207b7SJohn Levon 8061f5207b7SJohn Levon struct expression *strip_expr(struct expression *expr) 8071f5207b7SJohn Levon { 8081f5207b7SJohn Levon return strip_expr_helper(expr, false); 8091f5207b7SJohn Levon } 8101f5207b7SJohn Levon 8111f5207b7SJohn Levon struct expression *strip_expr_set_parent(struct expression *expr) 8121f5207b7SJohn Levon { 8131f5207b7SJohn Levon return strip_expr_helper(expr, true); 8141f5207b7SJohn Levon } 8151f5207b7SJohn Levon 8161f5207b7SJohn Levon static void delete_state_tracker(struct tracker *t) 8171f5207b7SJohn Levon { 8181f5207b7SJohn Levon delete_state(t->owner, t->name, t->sym); 8191f5207b7SJohn Levon __free_tracker(t); 8201f5207b7SJohn Levon } 8211f5207b7SJohn Levon 8221f5207b7SJohn Levon void scoped_state(int my_id, const char *name, struct symbol *sym) 8231f5207b7SJohn Levon { 8241f5207b7SJohn Levon struct tracker *t; 8251f5207b7SJohn Levon 8261f5207b7SJohn Levon t = alloc_tracker(my_id, name, sym); 8271f5207b7SJohn Levon add_scope_hook((scope_hook *)&delete_state_tracker, t); 8281f5207b7SJohn Levon } 8291f5207b7SJohn Levon 8301f5207b7SJohn Levon int is_error_return(struct expression *expr) 8311f5207b7SJohn Levon { 8321f5207b7SJohn Levon struct symbol *cur_func = cur_func_sym; 8331f5207b7SJohn Levon struct range_list *rl; 8341f5207b7SJohn Levon sval_t sval; 8351f5207b7SJohn Levon 8361f5207b7SJohn Levon if (!expr) 8371f5207b7SJohn Levon return 0; 8381f5207b7SJohn Levon if (cur_func->type != SYM_NODE) 8391f5207b7SJohn Levon return 0; 8401f5207b7SJohn Levon cur_func = get_base_type(cur_func); 8411f5207b7SJohn Levon if (cur_func->type != SYM_FN) 8421f5207b7SJohn Levon return 0; 8431f5207b7SJohn Levon cur_func = get_base_type(cur_func); 8441f5207b7SJohn Levon if (cur_func == &void_ctype) 8451f5207b7SJohn Levon return 0; 8461f5207b7SJohn Levon if (option_project == PROJ_KERNEL && 8471f5207b7SJohn Levon get_implied_rl(expr, &rl) && 8481f5207b7SJohn Levon rl_type(rl) == &int_ctype && 8491f5207b7SJohn Levon sval_is_negative(rl_min(rl)) && 8501f5207b7SJohn Levon rl_max(rl).value == -1) 8511f5207b7SJohn Levon return 1; 8521f5207b7SJohn Levon if (!get_implied_value(expr, &sval)) 8531f5207b7SJohn Levon return 0; 8541f5207b7SJohn Levon if (sval.value < 0) 8551f5207b7SJohn Levon return 1; 8561f5207b7SJohn Levon if (cur_func->type == SYM_PTR && sval.value == 0) 8571f5207b7SJohn Levon return 1; 8581f5207b7SJohn Levon return 0; 8591f5207b7SJohn Levon } 8601f5207b7SJohn Levon 861c85f09ccSJohn Levon int getting_address(struct expression *expr) 8621f5207b7SJohn Levon { 863c85f09ccSJohn Levon int deref_count = 0; 8641f5207b7SJohn Levon 865c85f09ccSJohn Levon while ((expr = expr_get_parent_expr(expr))) { 866c85f09ccSJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') { 867c85f09ccSJohn Levon /* &foo->bar->baz dereferences "foo->bar" */ 868c85f09ccSJohn Levon if (deref_count == 0) 869c85f09ccSJohn Levon deref_count++; 870c85f09ccSJohn Levon return false; 871c85f09ccSJohn Levon } 872c85f09ccSJohn Levon if (expr->type == EXPR_PREOP && expr->op == '&') 873c85f09ccSJohn Levon return true; 874c85f09ccSJohn Levon } 875c85f09ccSJohn Levon return false; 8761f5207b7SJohn Levon } 8771f5207b7SJohn Levon 8781f5207b7SJohn Levon int get_struct_and_member(struct expression *expr, const char **type, const char **member) 8791f5207b7SJohn Levon { 8801f5207b7SJohn Levon struct symbol *sym; 8811f5207b7SJohn Levon 8821f5207b7SJohn Levon expr = strip_expr(expr); 8831f5207b7SJohn Levon if (expr->type != EXPR_DEREF) 8841f5207b7SJohn Levon return 0; 8851f5207b7SJohn Levon if (!expr->member) 8861f5207b7SJohn Levon return 0; 8871f5207b7SJohn Levon 8881f5207b7SJohn Levon sym = get_type(expr->deref); 8891f5207b7SJohn Levon if (!sym) 8901f5207b7SJohn Levon return 0; 8911f5207b7SJohn Levon if (sym->type == SYM_UNION) 8921f5207b7SJohn Levon return 0; 8931f5207b7SJohn Levon if (!sym->ident) 8941f5207b7SJohn Levon return 0; 8951f5207b7SJohn Levon 8961f5207b7SJohn Levon *type = sym->ident->name; 8971f5207b7SJohn Levon *member = expr->member->name; 8981f5207b7SJohn Levon return 1; 8991f5207b7SJohn Levon } 9001f5207b7SJohn Levon 9011f5207b7SJohn Levon char *get_member_name(struct expression *expr) 9021f5207b7SJohn Levon { 9031f5207b7SJohn Levon char buf[256]; 9041f5207b7SJohn Levon struct symbol *sym; 9051f5207b7SJohn Levon 9061f5207b7SJohn Levon expr = strip_expr(expr); 9071f5207b7SJohn Levon if (!expr || expr->type != EXPR_DEREF) 9081f5207b7SJohn Levon return NULL; 9091f5207b7SJohn Levon if (!expr->member) 9101f5207b7SJohn Levon return NULL; 9111f5207b7SJohn Levon 9121f5207b7SJohn Levon sym = get_type(expr->deref); 9131f5207b7SJohn Levon if (!sym) 9141f5207b7SJohn Levon return NULL; 9151f5207b7SJohn Levon if (sym->type == SYM_UNION) { 9161f5207b7SJohn Levon snprintf(buf, sizeof(buf), "(union %s)->%s", 9171f5207b7SJohn Levon sym->ident ? sym->ident->name : "anonymous", 9181f5207b7SJohn Levon expr->member->name); 9191f5207b7SJohn Levon return alloc_string(buf); 9201f5207b7SJohn Levon } 921efe51d0cSJohn Levon if (!sym->ident) { 922efe51d0cSJohn Levon struct expression *deref; 923efe51d0cSJohn Levon char *full, *outer; 924efe51d0cSJohn Levon int len; 925efe51d0cSJohn Levon 926efe51d0cSJohn Levon /* 927efe51d0cSJohn Levon * If we're in an anonymous struct then maybe we can find an 928efe51d0cSJohn Levon * outer struct name to use as a name. This code should be 929efe51d0cSJohn Levon * recursive and cleaner. I am not very proud of it. 930efe51d0cSJohn Levon * 931efe51d0cSJohn Levon */ 932efe51d0cSJohn Levon 933efe51d0cSJohn Levon deref = expr->deref; 934efe51d0cSJohn Levon if (deref->type != EXPR_DEREF || !deref->member) 935efe51d0cSJohn Levon return NULL; 936efe51d0cSJohn Levon sym = get_type(deref->deref); 937efe51d0cSJohn Levon if (!sym || sym->type != SYM_STRUCT || !sym->ident) 938efe51d0cSJohn Levon return NULL; 939efe51d0cSJohn Levon 940efe51d0cSJohn Levon full = expr_to_str(expr); 941efe51d0cSJohn Levon if (!full) 942efe51d0cSJohn Levon return NULL; 943efe51d0cSJohn Levon deref = deref->deref; 944efe51d0cSJohn Levon if (deref->type == EXPR_PREOP && deref->op == '*') 945efe51d0cSJohn Levon deref = deref->unop; 946efe51d0cSJohn Levon outer = expr_to_str(deref); 947efe51d0cSJohn Levon if (!outer) { 948efe51d0cSJohn Levon free_string(full); 949efe51d0cSJohn Levon return NULL; 950efe51d0cSJohn Levon } 951efe51d0cSJohn Levon len = strlen(outer); 952efe51d0cSJohn Levon if (strncmp(outer, full, len) != 0) { 953efe51d0cSJohn Levon free_string(full); 954efe51d0cSJohn Levon free_string(outer); 955efe51d0cSJohn Levon return NULL; 956efe51d0cSJohn Levon } 957efe51d0cSJohn Levon if (full[len] == '-' && full[len + 1] == '>') 958efe51d0cSJohn Levon len += 2; 959efe51d0cSJohn Levon if (full[len] == '.') 960efe51d0cSJohn Levon len++; 961efe51d0cSJohn Levon snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, full + len); 962efe51d0cSJohn Levon free_string(outer); 963efe51d0cSJohn Levon free_string(full); 964efe51d0cSJohn Levon 965efe51d0cSJohn Levon return alloc_string(buf); 966efe51d0cSJohn Levon } 9671f5207b7SJohn Levon snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, expr->member->name); 9681f5207b7SJohn Levon return alloc_string(buf); 9691f5207b7SJohn Levon } 9701f5207b7SJohn Levon 9711f5207b7SJohn Levon int cmp_pos(struct position pos1, struct position pos2) 9721f5207b7SJohn Levon { 9731f5207b7SJohn Levon /* the stream position is ... */ 9741f5207b7SJohn Levon if (pos1.stream > pos2.stream) 9751f5207b7SJohn Levon return -1; 9761f5207b7SJohn Levon if (pos1.stream < pos2.stream) 9771f5207b7SJohn Levon return 1; 9781f5207b7SJohn Levon 9791f5207b7SJohn Levon if (pos1.line < pos2.line) 9801f5207b7SJohn Levon return -1; 9811f5207b7SJohn Levon if (pos1.line > pos2.line) 9821f5207b7SJohn Levon return 1; 9831f5207b7SJohn Levon 9841f5207b7SJohn Levon if (pos1.pos < pos2.pos) 9851f5207b7SJohn Levon return -1; 9861f5207b7SJohn Levon if (pos1.pos > pos2.pos) 9871f5207b7SJohn Levon return 1; 9881f5207b7SJohn Levon 9891f5207b7SJohn Levon return 0; 9901f5207b7SJohn Levon } 9911f5207b7SJohn Levon 9921f5207b7SJohn Levon int positions_eq(struct position pos1, struct position pos2) 9931f5207b7SJohn Levon { 9941f5207b7SJohn Levon if (pos1.line != pos2.line) 9951f5207b7SJohn Levon return 0; 9961f5207b7SJohn Levon if (pos1.pos != pos2.pos) 9971f5207b7SJohn Levon return 0; 9981f5207b7SJohn Levon if (pos1.stream != pos2.stream) 9991f5207b7SJohn Levon return 0; 10001f5207b7SJohn Levon return 1; 10011f5207b7SJohn Levon } 10021f5207b7SJohn Levon 10031f5207b7SJohn Levon struct statement *get_current_statement(void) 10041f5207b7SJohn Levon { 10051f5207b7SJohn Levon struct statement *prev, *tmp; 10061f5207b7SJohn Levon 10071f5207b7SJohn Levon prev = last_ptr_list((struct ptr_list *)big_statement_stack); 10081f5207b7SJohn Levon 10091f5207b7SJohn Levon if (!prev || !get_macro_name(prev->pos)) 10101f5207b7SJohn Levon return prev; 10111f5207b7SJohn Levon 10121f5207b7SJohn Levon FOR_EACH_PTR_REVERSE(big_statement_stack, tmp) { 10131f5207b7SJohn Levon if (positions_eq(tmp->pos, prev->pos)) 10141f5207b7SJohn Levon continue; 10151f5207b7SJohn Levon if (prev->pos.line > tmp->pos.line) 10161f5207b7SJohn Levon return prev; 10171f5207b7SJohn Levon return tmp; 10181f5207b7SJohn Levon } END_FOR_EACH_PTR_REVERSE(tmp); 10191f5207b7SJohn Levon return prev; 10201f5207b7SJohn Levon } 10211f5207b7SJohn Levon 10221f5207b7SJohn Levon struct statement *get_prev_statement(void) 10231f5207b7SJohn Levon { 10241f5207b7SJohn Levon struct statement *tmp; 10251f5207b7SJohn Levon int i; 10261f5207b7SJohn Levon 10271f5207b7SJohn Levon i = 0; 10281f5207b7SJohn Levon FOR_EACH_PTR_REVERSE(big_statement_stack, tmp) { 10291f5207b7SJohn Levon if (i++ == 1) 10301f5207b7SJohn Levon return tmp; 10311f5207b7SJohn Levon } END_FOR_EACH_PTR_REVERSE(tmp); 10321f5207b7SJohn Levon return NULL; 10331f5207b7SJohn Levon } 10341f5207b7SJohn Levon 10351f5207b7SJohn Levon struct expression *get_last_expr_from_expression_stmt(struct expression *expr) 10361f5207b7SJohn Levon { 10371f5207b7SJohn Levon struct statement *stmt; 10381f5207b7SJohn Levon struct statement *last_stmt; 10391f5207b7SJohn Levon 10401f5207b7SJohn Levon while (expr->type == EXPR_PREOP && expr->op == '(') 10411f5207b7SJohn Levon expr = expr->unop; 10421f5207b7SJohn Levon if (expr->type != EXPR_STATEMENT) 10431f5207b7SJohn Levon return NULL; 10441f5207b7SJohn Levon stmt = expr->statement; 10451f5207b7SJohn Levon if (!stmt) 10461f5207b7SJohn Levon return NULL; 10471f5207b7SJohn Levon if (stmt->type == STMT_COMPOUND) { 10481f5207b7SJohn Levon last_stmt = last_ptr_list((struct ptr_list *)stmt->stmts); 10491f5207b7SJohn Levon if (!last_stmt) 10501f5207b7SJohn Levon return NULL; 10511f5207b7SJohn Levon if (last_stmt->type == STMT_LABEL) 10521f5207b7SJohn Levon last_stmt = last_stmt->label_statement; 10531f5207b7SJohn Levon if (last_stmt->type != STMT_EXPRESSION) 10541f5207b7SJohn Levon return NULL; 10551f5207b7SJohn Levon return last_stmt->expression; 10561f5207b7SJohn Levon } 10571f5207b7SJohn Levon if (stmt->type == STMT_EXPRESSION) 10581f5207b7SJohn Levon return stmt->expression; 10591f5207b7SJohn Levon return NULL; 10601f5207b7SJohn Levon } 10611f5207b7SJohn Levon 10621f5207b7SJohn Levon int get_param_num_from_sym(struct symbol *sym) 10631f5207b7SJohn Levon { 10641f5207b7SJohn Levon struct symbol *tmp; 10651f5207b7SJohn Levon int i; 10661f5207b7SJohn Levon 1067*6523a3aaSJohn Levon if (!sym) 1068*6523a3aaSJohn Levon return UNKNOWN_SCOPE; 1069*6523a3aaSJohn Levon 1070*6523a3aaSJohn Levon if (sym->ctype.modifiers & MOD_TOPLEVEL) { 1071*6523a3aaSJohn Levon if (sym->ctype.modifiers & MOD_STATIC) 1072*6523a3aaSJohn Levon return FILE_SCOPE; 1073*6523a3aaSJohn Levon return GLOBAL_SCOPE; 1074*6523a3aaSJohn Levon } 1075*6523a3aaSJohn Levon 1076*6523a3aaSJohn Levon if (!cur_func_sym) { 1077*6523a3aaSJohn Levon if (!parse_error) { 1078*6523a3aaSJohn Levon sm_msg("warn: internal. problem with scope: %s", 1079*6523a3aaSJohn Levon sym->ident ? sym->ident->name : "<anon var>"); 1080*6523a3aaSJohn Levon } 1081*6523a3aaSJohn Levon return GLOBAL_SCOPE; 1082*6523a3aaSJohn Levon } 1083*6523a3aaSJohn Levon 10841f5207b7SJohn Levon 10851f5207b7SJohn Levon i = 0; 10861f5207b7SJohn Levon FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) { 10871f5207b7SJohn Levon if (tmp == sym) 10881f5207b7SJohn Levon return i; 10891f5207b7SJohn Levon i++; 10901f5207b7SJohn Levon } END_FOR_EACH_PTR(tmp); 1091*6523a3aaSJohn Levon return LOCAL_SCOPE; 10921f5207b7SJohn Levon } 10931f5207b7SJohn Levon 10941f5207b7SJohn Levon int get_param_num(struct expression *expr) 10951f5207b7SJohn Levon { 10961f5207b7SJohn Levon struct symbol *sym; 10971f5207b7SJohn Levon char *name; 10981f5207b7SJohn Levon 10991f5207b7SJohn Levon if (!cur_func_sym) 1100*6523a3aaSJohn Levon return UNKNOWN_SCOPE; 11011f5207b7SJohn Levon name = expr_to_var_sym(expr, &sym); 11021f5207b7SJohn Levon free_string(name); 11031f5207b7SJohn Levon if (!sym) 1104*6523a3aaSJohn Levon return UNKNOWN_SCOPE; 11051f5207b7SJohn Levon return get_param_num_from_sym(sym); 11061f5207b7SJohn Levon } 11071f5207b7SJohn Levon 11085a0e240fSJohn Levon struct symbol *get_param_sym_from_num(int num) 11095a0e240fSJohn Levon { 11105a0e240fSJohn Levon struct symbol *sym; 11115a0e240fSJohn Levon int i; 11125a0e240fSJohn Levon 11135a0e240fSJohn Levon if (!cur_func_sym) 11145a0e240fSJohn Levon return NULL; 11155a0e240fSJohn Levon 11165a0e240fSJohn Levon i = 0; 11175a0e240fSJohn Levon FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) { 11185a0e240fSJohn Levon if (i++ == num) 11195a0e240fSJohn Levon return sym; 11205a0e240fSJohn Levon } END_FOR_EACH_PTR(sym); 11215a0e240fSJohn Levon return NULL; 11225a0e240fSJohn Levon } 11235a0e240fSJohn Levon 11241f5207b7SJohn Levon int ms_since(struct timeval *start) 11251f5207b7SJohn Levon { 11261f5207b7SJohn Levon struct timeval end; 11271f5207b7SJohn Levon double diff; 11281f5207b7SJohn Levon 11291f5207b7SJohn Levon gettimeofday(&end, NULL); 11301f5207b7SJohn Levon diff = (end.tv_sec - start->tv_sec) * 1000.0; 11311f5207b7SJohn Levon diff += (end.tv_usec - start->tv_usec) / 1000.0; 11321f5207b7SJohn Levon return (int)diff; 11331f5207b7SJohn Levon } 11341f5207b7SJohn Levon 11351f5207b7SJohn Levon int parent_is_gone_var_sym(const char *name, struct symbol *sym) 11361f5207b7SJohn Levon { 11371f5207b7SJohn Levon if (!name || !sym) 11381f5207b7SJohn Levon return 0; 11391f5207b7SJohn Levon 11401f5207b7SJohn Levon if (parent_is_null_var_sym(name, sym) || 11411f5207b7SJohn Levon parent_is_free_var_sym(name, sym)) 11421f5207b7SJohn Levon return 1; 11431f5207b7SJohn Levon return 0; 11441f5207b7SJohn Levon } 11451f5207b7SJohn Levon 11461f5207b7SJohn Levon int parent_is_gone(struct expression *expr) 11471f5207b7SJohn Levon { 11481f5207b7SJohn Levon struct symbol *sym; 11491f5207b7SJohn Levon char *var; 11501f5207b7SJohn Levon int ret = 0; 11511f5207b7SJohn Levon 11521f5207b7SJohn Levon expr = strip_expr(expr); 11531f5207b7SJohn Levon var = expr_to_var_sym(expr, &sym); 11541f5207b7SJohn Levon if (!var || !sym) 11551f5207b7SJohn Levon goto free; 11561f5207b7SJohn Levon ret = parent_is_gone_var_sym(var, sym); 11571f5207b7SJohn Levon free: 11581f5207b7SJohn Levon free_string(var); 11591f5207b7SJohn Levon return ret; 11601f5207b7SJohn Levon } 11611f5207b7SJohn Levon 11621f5207b7SJohn Levon int invert_op(int op) 11631f5207b7SJohn Levon { 11641f5207b7SJohn Levon switch (op) { 11651f5207b7SJohn Levon case '*': 11661f5207b7SJohn Levon return '/'; 11671f5207b7SJohn Levon case '/': 11681f5207b7SJohn Levon return '*'; 11691f5207b7SJohn Levon case '+': 11701f5207b7SJohn Levon return '-'; 11711f5207b7SJohn Levon case '-': 11721f5207b7SJohn Levon return '+'; 11731f5207b7SJohn Levon case SPECIAL_LEFTSHIFT: 11741f5207b7SJohn Levon return SPECIAL_RIGHTSHIFT; 11751f5207b7SJohn Levon case SPECIAL_RIGHTSHIFT: 11761f5207b7SJohn Levon return SPECIAL_LEFTSHIFT; 11771f5207b7SJohn Levon } 11781f5207b7SJohn Levon return 0; 11791f5207b7SJohn Levon } 11801f5207b7SJohn Levon 1181efe51d0cSJohn Levon int op_remove_assign(int op) 1182efe51d0cSJohn Levon { 1183efe51d0cSJohn Levon switch (op) { 1184efe51d0cSJohn Levon case SPECIAL_ADD_ASSIGN: 1185efe51d0cSJohn Levon return '+'; 1186efe51d0cSJohn Levon case SPECIAL_SUB_ASSIGN: 1187efe51d0cSJohn Levon return '-'; 1188efe51d0cSJohn Levon case SPECIAL_MUL_ASSIGN: 1189efe51d0cSJohn Levon return '*'; 1190efe51d0cSJohn Levon case SPECIAL_DIV_ASSIGN: 1191efe51d0cSJohn Levon return '/'; 1192efe51d0cSJohn Levon case SPECIAL_MOD_ASSIGN: 1193efe51d0cSJohn Levon return '%'; 1194efe51d0cSJohn Levon case SPECIAL_AND_ASSIGN: 1195efe51d0cSJohn Levon return '&'; 1196efe51d0cSJohn Levon case SPECIAL_OR_ASSIGN: 1197efe51d0cSJohn Levon return '|'; 1198efe51d0cSJohn Levon case SPECIAL_XOR_ASSIGN: 1199efe51d0cSJohn Levon return '^'; 1200efe51d0cSJohn Levon case SPECIAL_SHL_ASSIGN: 1201efe51d0cSJohn Levon return SPECIAL_LEFTSHIFT; 1202efe51d0cSJohn Levon case SPECIAL_SHR_ASSIGN: 1203efe51d0cSJohn Levon return SPECIAL_RIGHTSHIFT; 1204efe51d0cSJohn Levon default: 1205efe51d0cSJohn Levon return op; 1206efe51d0cSJohn Levon } 1207efe51d0cSJohn Levon } 1208efe51d0cSJohn Levon 12091f5207b7SJohn Levon int expr_equiv(struct expression *one, struct expression *two) 12101f5207b7SJohn Levon { 12111f5207b7SJohn Levon struct symbol *one_sym = NULL; 12121f5207b7SJohn Levon struct symbol *two_sym = NULL; 12131f5207b7SJohn Levon char *one_name = NULL; 12141f5207b7SJohn Levon char *two_name = NULL; 12151f5207b7SJohn Levon int ret = 0; 12161f5207b7SJohn Levon 12171f5207b7SJohn Levon if (!one || !two) 12181f5207b7SJohn Levon return 0; 12191f5207b7SJohn Levon if (one->type != two->type) 12201f5207b7SJohn Levon return 0; 12211f5207b7SJohn Levon if (is_fake_call(one) || is_fake_call(two)) 12221f5207b7SJohn Levon return 0; 12231f5207b7SJohn Levon 12241f5207b7SJohn Levon one_name = expr_to_str_sym(one, &one_sym); 12251f5207b7SJohn Levon if (!one_name) 12261f5207b7SJohn Levon goto free; 12271f5207b7SJohn Levon two_name = expr_to_str_sym(two, &two_sym); 12281f5207b7SJohn Levon if (!two_name) 12291f5207b7SJohn Levon goto free; 12301f5207b7SJohn Levon if (one_sym != two_sym) 12311f5207b7SJohn Levon goto free; 12321f5207b7SJohn Levon /* 12331f5207b7SJohn Levon * This is a terrible hack because expr_to_str() sometimes gives up in 12341f5207b7SJohn Levon * the middle and just returns what it has. If you see a () you know 12351f5207b7SJohn Levon * the string is bogus. 12361f5207b7SJohn Levon */ 12371f5207b7SJohn Levon if (strstr(one_name, "()")) 12381f5207b7SJohn Levon goto free; 12391f5207b7SJohn Levon if (strcmp(one_name, two_name) == 0) 12401f5207b7SJohn Levon ret = 1; 12411f5207b7SJohn Levon free: 12421f5207b7SJohn Levon free_string(one_name); 12431f5207b7SJohn Levon free_string(two_name); 12441f5207b7SJohn Levon return ret; 12451f5207b7SJohn Levon } 12461f5207b7SJohn Levon 12471f5207b7SJohn Levon void push_int(struct int_stack **stack, int num) 12481f5207b7SJohn Levon { 12491f5207b7SJohn Levon int *munged; 12501f5207b7SJohn Levon 12511f5207b7SJohn Levon /* 12521f5207b7SJohn Levon * Just put the int on directly instead of a pointer to the int. 12531f5207b7SJohn Levon * Shift it to the left because Sparse uses the last two bits. 12541f5207b7SJohn Levon * This is sort of a dirty hack, yes. 12551f5207b7SJohn Levon */ 12561f5207b7SJohn Levon 12571f5207b7SJohn Levon munged = INT_PTR(num << 2); 12581f5207b7SJohn Levon 12591f5207b7SJohn Levon add_ptr_list(stack, munged); 12601f5207b7SJohn Levon } 12611f5207b7SJohn Levon 12621f5207b7SJohn Levon int pop_int(struct int_stack **stack) 12631f5207b7SJohn Levon { 12641f5207b7SJohn Levon int *num; 12651f5207b7SJohn Levon 12661f5207b7SJohn Levon num = last_ptr_list((struct ptr_list *)*stack); 12671f5207b7SJohn Levon delete_ptr_list_last((struct ptr_list **)stack); 12681f5207b7SJohn Levon 12691f5207b7SJohn Levon return PTR_INT(num) >> 2; 12701f5207b7SJohn Levon } 1271