1 #include "smatch.h"
   2 #include "smatch_extra.h"
   3 
   4 DECLARE_ALLOCATOR(sname);
   5 __ALLOCATOR(struct expression, "temporary expr", tmp_expression);
   6 
   7 static struct position get_cur_pos(void)
   8 {
   9         static struct position pos;
  10         static struct position none;
  11         struct expression *expr;
  12         struct statement *stmt;
  13 
  14         expr = last_ptr_list((struct ptr_list *)big_expression_stack);
  15         stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
  16         if (expr)
  17                 pos = expr->pos;
  18         else if (stmt)
  19                 pos = stmt->pos;
  20         else
  21                 pos = none;
  22         return pos;
  23 }
  24 
  25 struct expression *alloc_tmp_expression(struct position pos, int type)
  26 {
  27         struct expression *expr;
  28 
  29         expr = __alloc_tmp_expression(0);
  30         expr->smatch_flags |= Fake;
  31         expr->type = type;
  32         expr->pos = pos;
  33         return expr;
  34 }
  35 
  36 void free_tmp_expressions(void)
  37 {
  38         clear_tmp_expression_alloc();
  39 }
  40 
  41 struct expression *zero_expr(void)
  42 {
  43         struct expression *zero;
  44 
  45         zero = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
  46         zero->value = 0;
  47         zero->ctype = &int_ctype;
  48         return zero;
  49 }
  50 
  51 struct expression *value_expr(long long val)
  52 {
  53         struct expression *expr;
  54 
  55         if (!val)
  56                 return zero_expr();
  57 
  58         expr = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
  59         expr->value = val;
  60         expr->ctype = &llong_ctype;
  61         return expr;
  62 }
  63 
  64 struct expression *member_expression(struct expression *deref, int op, struct ident *member)
  65 {
  66         struct expression *expr;
  67 
  68         expr = alloc_tmp_expression(deref->pos, EXPR_DEREF);
  69         expr->op = op;
  70         expr->deref = deref;
  71         expr->member = member;
  72         expr->member_offset = -1;
  73         return expr;
  74 }
  75 
  76 struct expression *preop_expression(struct expression *expr, int op)
  77 {
  78         struct expression *preop;
  79 
  80         preop = alloc_tmp_expression(expr->pos, EXPR_PREOP);
  81         preop->unop = expr;
  82         preop->op = op;
  83         return preop;
  84 }
  85 
  86 struct expression *deref_expression(struct expression *expr)
  87 {
  88         if (expr->type == EXPR_BINOP)
  89                 expr = preop_expression(expr, '(');
  90         return preop_expression(expr, '*');
  91 }
  92 
  93 struct expression *assign_expression(struct expression *left, int op, struct expression *right)
  94 {
  95         struct expression *expr;
  96 
  97         if (!right)
  98                 return NULL;
  99 
 100         /* FIXME: make this a tmp expression. */
 101         expr = alloc_expression(right->pos, EXPR_ASSIGNMENT);
 102         expr->op = op;
 103         expr->left = left;
 104         expr->right = right;
 105         return expr;
 106 }
 107 
 108 struct expression *binop_expression(struct expression *left, int op, struct expression *right)
 109 {
 110         struct expression *expr;
 111 
 112         expr = alloc_tmp_expression(right->pos, EXPR_BINOP);
 113         expr->op = op;
 114         expr->left = left;
 115         expr->right = right;
 116         return expr;
 117 }
 118 
 119 struct expression *array_element_expression(struct expression *array, struct expression *offset)
 120 {
 121         struct expression *expr;
 122 
 123         expr = binop_expression(array, '+', offset);
 124         return deref_expression(expr);
 125 }
 126 
 127 struct expression *symbol_expression(struct symbol *sym)
 128 {
 129         struct expression *expr;
 130 
 131         expr = alloc_tmp_expression(sym->pos, EXPR_SYMBOL);
 132         expr->symbol = sym;
 133         expr->symbol_name = sym->ident;
 134         return expr;
 135 }
 136 
 137 struct expression *compare_expression(struct expression *left, int op, struct expression *right)
 138 {
 139         struct expression *expr;
 140 
 141         expr = alloc_tmp_expression(get_cur_pos(), EXPR_COMPARE);
 142         expr->op = op;
 143         expr->left = left;
 144         expr->right = right;
 145         return expr;
 146 }
 147 
 148 struct expression *string_expression(char *str)
 149 {
 150         struct expression *ret;
 151         struct string *string;
 152         int len;
 153 
 154         len = strlen(str) + 1;
 155         string = (void *)__alloc_sname(4 + len);
 156         string->length = len;
 157         string->immutable = 0;
 158         memcpy(string->data, str, len);
 159 
 160         ret = alloc_tmp_expression(get_cur_pos(), EXPR_STRING);
 161         ret->wide = 0;
 162         ret->string = string;
 163 
 164         return ret;
 165 }
 166 
 167 struct expression *call_expression(struct expression *fn, struct expression_list *args)
 168 {
 169         struct expression *expr;
 170 
 171         expr = alloc_tmp_expression(fn->pos, EXPR_CALL);
 172         expr->fn = fn;
 173         expr->args = args;
 174 
 175         return expr;
 176 }
 177 
 178 static struct expression *get_expression_from_base_and_str(struct expression *base, const char *addition)
 179 {
 180         struct expression *ret = NULL;
 181         struct token *token, *prev, *end;
 182         char *alloc;
 183 
 184         if (addition[0] == '\0')
 185                 return base;
 186 
 187         alloc = alloc_string_newline(addition);
 188 
 189         token = tokenize_buffer(alloc, strlen(alloc), &end);
 190         if (!token)
 191                 goto free;
 192         if (token_type(token) != TOKEN_STREAMBEGIN)
 193                 goto free;
 194         token = token->next;
 195 
 196         ret = base;
 197         while (token_type(token) == TOKEN_SPECIAL &&
 198                (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
 199                 prev = token;
 200                 token = token->next;
 201                 if (token_type(token) != TOKEN_IDENT)
 202                         goto free;
 203                 switch (prev->special) {
 204                 case SPECIAL_DEREFERENCE:
 205                         ret = deref_expression(ret);
 206                         ret = member_expression(ret, '*', token->ident);
 207                         break;
 208                 case '.':
 209                         ret = member_expression(ret, '.', token->ident);
 210                         break;
 211                 default:
 212                         goto free;
 213                 }
 214                 token = token->next;
 215         }
 216 
 217         if (token_type(token) != TOKEN_STREAMEND)
 218                 goto free;
 219 
 220 free:
 221         free_string(alloc);
 222 
 223         return ret;
 224 }
 225 
 226 struct expression *gen_expression_from_name_sym(const char *name, struct symbol *sym)
 227 {
 228         struct expression *base;
 229         int skip = 0;
 230         struct expression *ret;
 231 
 232         if (!name || !sym)
 233                 return NULL;
 234 
 235         base = symbol_expression(sym);
 236         while (name[skip] != '\0' && name[skip] != '.' && name[skip] != '-')
 237                 skip++;
 238 
 239         ret = get_expression_from_base_and_str(base, name + skip);
 240         if (ret) {
 241                 char *new = expr_to_str(ret);
 242 
 243                 /*
 244                  * FIXME: this sometimes changes "foo->bar.a.b->c" into
 245                  * "foo->bar.a.b.c".  I don't know why...  :(
 246                  *
 247                  */
 248                 if (!new || strcmp(name, new) != 0)
 249                         return NULL;
 250         }
 251         return ret;
 252 }
 253 
 254 struct expression *gen_expression_from_key(struct expression *arg, const char *key)
 255 {
 256         struct expression *ret;
 257         struct token *token, *prev, *end;
 258         const char *p = key;
 259         char buf[4095];
 260         char *alloc;
 261         size_t len;
 262 
 263         /* The idea is that we can parse either $0->foo or $->foo */
 264         if (key[0] != '$')
 265                 return NULL;
 266         p++;
 267         while (*p >= '0' && *p <= '9')
 268                 p++;
 269         len = snprintf(buf, sizeof(buf), "%s\n", p);
 270         alloc = alloc_string(buf);
 271 
 272         token = tokenize_buffer(alloc, len, &end);
 273         if (!token)
 274                 return NULL;
 275         if (token_type(token) != TOKEN_STREAMBEGIN)
 276                 return NULL;
 277         token = token->next;
 278 
 279         ret = arg;
 280         while (token_type(token) == TOKEN_SPECIAL &&
 281                (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
 282                 prev = token;
 283                 token = token->next;
 284                 if (token_type(token) != TOKEN_IDENT)
 285                         return NULL;
 286                 ret = deref_expression(ret);
 287                 ret = member_expression(ret,
 288                                         (prev->special == SPECIAL_DEREFERENCE) ? '*' : '.',
 289                                         token->ident);
 290                 token = token->next;
 291         }
 292 
 293         if (token_type(token) != TOKEN_STREAMEND)
 294                 return NULL;
 295 
 296         return ret;
 297 }
 298 
 299 void expr_set_parent_expr(struct expression *expr, struct expression *parent)
 300 {
 301         if (!expr)
 302                 return;
 303         if (parent->smatch_flags & Fake)
 304                 return;
 305 
 306         expr->parent = (unsigned long)parent | 0x1UL;
 307 }
 308 
 309 void expr_set_parent_stmt(struct expression *expr, struct statement *parent)
 310 {
 311         if (!expr)
 312                 return;
 313         expr->parent = (unsigned long)parent;
 314 }
 315 
 316 struct expression *expr_get_parent_expr(struct expression *expr)
 317 {
 318         if (!expr)
 319                 return NULL;
 320         if (!(expr->parent & 0x1UL))
 321                 return NULL;
 322         return (struct expression *)(expr->parent & ~0x1UL);
 323 }
 324 
 325 struct statement *expr_get_parent_stmt(struct expression *expr)
 326 {
 327         if (!expr)
 328                 return NULL;
 329         if (expr->parent & 0x1UL)
 330                 return NULL;
 331         return (struct statement *)expr->parent;
 332 }
 333