2 * Copyright (C) 2012 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
27 } alloc_functions
[] = {
33 {"__vmalloc_node", 0},
36 static struct range_list_stack
*rl_stack
;
37 static struct string_list
*op_list
;
39 static void push_op(char c
)
45 add_ptr_list(&op_list
, p
);
48 static char pop_op(void)
54 sm_perror("%s: no op_list", __func__
);
58 p
= last_ptr_list((struct ptr_list
*)op_list
);
60 delete_ptr_list_last((struct ptr_list
**)&op_list
);
67 static int op_precedence(char c
)
81 static int top_op_precedence(void)
88 p
= last_ptr_list((struct ptr_list
*)op_list
);
89 return op_precedence(p
[0]);
92 static void rl_pop_until(char c
)
95 struct range_list
*left
, *right
;
96 struct range_list
*res
;
98 while (top_op_precedence() && op_precedence(c
) <= top_op_precedence()) {
100 right
= pop_rl(&rl_stack
);
101 left
= pop_rl(&rl_stack
);
102 res
= rl_binop(left
, op
, right
);
104 res
= alloc_whole_rl(&llong_ctype
);
105 push_rl(&rl_stack
, res
);
109 static void rl_discard_stacks(void)
117 static int read_rl_from_var(struct expression
*call
, const char *p
, const char **end
, struct range_list
**rl
)
119 struct expression
*arg
;
120 struct smatch_state
*state
;
128 param
= strtol(p
, (char **)&p
, 10);
130 arg
= get_argument_from_call_expr(call
->args
, param
);
134 if (*p
!= '-' && *p
!= '.') {
135 get_absolute_rl(arg
, rl
);
140 *end
= strchr(p
, ' ');
142 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&') {
143 arg
= strip_expr(arg
->unop
);
151 name
= expr_to_var_sym(arg
, &sym
);
154 snprintf(buf
, sizeof(buf
), "%s%s", name
, star
? "->" : ".");
157 if (*end
- p
+ strlen(buf
) >= sizeof(buf
))
159 strncat(buf
, p
, *end
- p
);
161 state
= get_state(SMATCH_EXTRA
, buf
, sym
);
164 *rl
= estate_rl(state
);
168 static int read_var_num(struct expression
*call
, const char *p
, const char **end
, struct range_list
**rl
)
176 return read_rl_from_var(call
, p
, end
, rl
);
178 sval
.type
= &llong_ctype
;
179 sval
.value
= strtoll(p
, (char **)end
, 10);
182 *rl
= alloc_rl(sval
, sval
);
186 static const char *read_op(const char *p
)
202 int parse_call_math_rl(struct expression
*call
, const char *math
, struct range_list
**rl
)
204 struct range_list
*tmp
;
207 /* try to implement shunting yard algorithm. */
212 sm_msg("parsing %s", c
);
214 /* read a number and push it onto the number stack */
215 if (!read_var_num(call
, c
, &c
, &tmp
))
217 push_rl(&rl_stack
, tmp
);
220 sm_msg("val = %s remaining = %s", show_rl(tmp
), c
);
224 if (*c
== ']' && *(c
+ 1) == '\0')
232 sm_msg("op = %c remaining = %s", *c
, c
);
240 *rl
= pop_rl(&rl_stack
);
247 int parse_call_math(struct expression
*call
, char *math
, sval_t
*sval
)
249 struct range_list
*rl
;
251 if (!parse_call_math_rl(call
, math
, &rl
))
253 if (!rl_to_sval(rl
, sval
))
258 static struct smatch_state
*alloc_state_sname(char *sname
)
260 struct smatch_state
*state
;
262 state
= __alloc_smatch_state(0);
264 state
->data
= INT_PTR(1);
268 static int get_arg_number(struct expression
*expr
)
274 expr
= strip_expr(expr
);
275 if (expr
->type
!= EXPR_SYMBOL
)
280 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, arg
) {
284 } END_FOR_EACH_PTR(arg
);
289 static int format_name_sym_helper(char *buf
, int remaining
, char *name
, struct symbol
*sym
)
296 if (!name
|| !sym
|| !sym
->ident
)
298 arg
= get_param_num_from_sym(sym
);
301 if (param_was_set_var_sym(name
, sym
))
304 param_name
= sym
->ident
->name
;
305 name_len
= strlen(param_name
);
307 if (name
[name_len
] == '\0')
308 ret
= snprintf(buf
, remaining
, "$%d", arg
);
309 else if (name
[name_len
] == '-')
310 ret
= snprintf(buf
, remaining
, "$%d%s", arg
, name
+ name_len
);
325 static int format_variable_helper(char *buf
, int remaining
, struct expression
*expr
)
330 name
= expr_to_var_sym(expr
, &sym
);
331 if (param_was_set_var_sym(name
, sym
))
333 return format_name_sym_helper(buf
, remaining
, name
, sym
);
336 static int format_call_to_param_mapping(char *buf
, int remaining
, struct expression
*expr
)
341 name
= map_call_to_param_name_sym(expr
, &sym
);
342 if (param_was_set_var_sym(name
, sym
))
344 return format_name_sym_helper(buf
, remaining
, name
, sym
);
347 static int is_mtag_sval(sval_t sval
)
349 if (!is_ptr_type(sval
.type
))
351 if (sval_cmp(sval
, valid_ptr_min_sval
) >= 0 &&
352 sval_cmp(sval
, valid_ptr_max_sval
) <= 0)
357 static int format_expr_helper(char *buf
, int remaining
, struct expression
*expr
)
368 if (expr
->type
== EXPR_BINOP
) {
369 ret
= format_expr_helper(cur
, remaining
, expr
->left
);
377 ret
= snprintf(cur
, remaining
, " %s ", show_special(expr
->op
));
383 ret
= format_expr_helper(cur
, remaining
, expr
->right
);
393 if (get_implied_value(expr
, &sval
) && !is_mtag_sval(sval
)) {
394 ret
= snprintf(cur
, remaining
, "%s", sval_to_str(sval
));
401 if (expr
->type
== EXPR_CALL
)
402 return format_call_to_param_mapping(cur
, remaining
, expr
);
404 return format_variable_helper(cur
, remaining
, expr
);
407 static char *format_expr(struct expression
*expr
)
412 ret
= format_expr_helper(buf
, sizeof(buf
), expr
);
416 return alloc_sname(buf
);
419 char *get_value_in_terms_of_parameter_math(struct expression
*expr
)
421 struct expression
*tmp
;
426 tmp
= get_assigned_expr(expr
);
429 if (param_was_set(expr
))
432 if (get_implied_value(expr
, &dummy
))
435 ret
= format_expr_helper(buf
, sizeof(buf
), expr
);
439 return alloc_sname(buf
);
442 char *get_value_in_terms_of_parameter_math_var_sym(const char *name
, struct symbol
*sym
)
444 struct expression
*tmp
, *expr
;
449 expr
= get_assigned_expr_name_sym(name
, sym
);
452 while ((tmp
= get_assigned_expr(expr
))) {
453 expr
= strip_expr(tmp
);
458 ret
= format_expr_helper(buf
, sizeof(buf
), expr
);
462 return alloc_sname(buf
);
466 static void match_alloc(const char *fn
, struct expression
*expr
, void *_size_arg
)
468 int size_arg
= PTR_INT(_size_arg
);
469 struct expression
*right
;
470 struct expression
*size_expr
;
473 right
= strip_expr(expr
->right
);
474 size_expr
= get_argument_from_call_expr(right
->args
, size_arg
);
476 sname
= format_expr(size_expr
);
479 set_state_expr(my_id
, expr
->left
, alloc_state_sname(sname
));
482 static char *swap_format(struct expression
*call
, char *format
)
487 struct expression
*arg
;
492 if (format
[0] == '$' && format
[2] == '\0') {
493 param
= strtol(format
+ 1, NULL
, 10);
494 arg
= get_argument_from_call_expr(call
->args
, param
);
497 return format_expr(arg
);
506 param
= strtol(p
, (char **)&p
, 10);
507 arg
= get_argument_from_call_expr(call
->args
, param
);
510 param
= get_arg_number(arg
);
512 ret
= snprintf(out
, buf
+ sizeof(buf
) - out
, "$%ld", param
);
514 if (out
>= buf
+ sizeof(buf
))
516 } else if (get_implied_value(arg
, &sval
)) {
517 ret
= snprintf(out
, buf
+ sizeof(buf
) - out
, "%s", sval_to_str(sval
));
519 if (out
>= buf
+ sizeof(buf
))
532 return alloc_sname(buf
);
535 static char *buf_size_recipe
;
536 static int db_buf_size_callback(void *unused
, int argc
, char **argv
, char **azColName
)
541 if (!buf_size_recipe
)
542 buf_size_recipe
= alloc_sname(argv
[0]);
543 else if (strcmp(buf_size_recipe
, argv
[0]) != 0)
544 buf_size_recipe
= alloc_sname("invalid");
548 static char *get_allocation_recipe_from_call(struct expression
*expr
)
551 static char sql_filter
[1024];
554 if (is_fake_call(expr
))
556 expr
= strip_expr(expr
);
557 if (expr
->fn
->type
!= EXPR_SYMBOL
)
559 sym
= expr
->fn
->symbol
;
563 for (i
= 0; i
< ARRAY_SIZE(alloc_functions
); i
++) {
564 if (strcmp(sym
->ident
->name
, alloc_functions
[i
].func
) == 0) {
567 snprintf(buf
, sizeof(buf
), "$%d", alloc_functions
[i
].param
);
568 buf_size_recipe
= alloc_sname(buf
);
569 return swap_format(expr
, buf_size_recipe
);
573 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
574 snprintf(sql_filter
, 1024, "file = '%s' and function = '%s';",
575 get_filename(), sym
->ident
->name
);
577 snprintf(sql_filter
, 1024, "function = '%s' and static = 0;",
581 buf_size_recipe
= NULL
;
582 run_sql(db_buf_size_callback
, NULL
,
583 "select value from return_states where type=%d and %s",
584 BUF_SIZE
, sql_filter
);
585 if (!buf_size_recipe
|| strcmp(buf_size_recipe
, "invalid") == 0)
587 return swap_format(expr
, buf_size_recipe
);
590 static void match_call_assignment(struct expression
*expr
)
594 sname
= get_allocation_recipe_from_call(expr
->right
);
597 set_state_expr(my_id
, expr
->left
, alloc_state_sname(sname
));
600 static void match_returns_call(int return_id
, char *return_ranges
, struct expression
*call
)
604 sname
= get_allocation_recipe_from_call(call
);
606 sm_msg("sname = %s", sname
);
610 sql_insert_return_states(return_id
, return_ranges
, BUF_SIZE
, -1, "",
614 static void print_returned_allocations(int return_id
, char *return_ranges
, struct expression
*expr
)
616 struct expression
*tmp
;
617 struct smatch_state
*state
;
622 expr
= strip_expr(expr
);
623 while ((tmp
= get_assigned_expr(expr
))) {
624 if (cnt
++ > 5) /* assignments to self cause infinite loops */
626 expr
= strip_expr(tmp
);
631 if (expr
->type
== EXPR_CALL
) {
632 match_returns_call(return_id
, return_ranges
, expr
);
636 name
= expr_to_var_sym(expr
, &sym
);
640 state
= get_state(my_id
, name
, sym
);
641 if (!state
|| !state
->data
)
644 sql_insert_return_states(return_id
, return_ranges
, BUF_SIZE
, -1, "",
650 void register_parse_call_math(int id
)
656 for (i
= 0; i
< ARRAY_SIZE(alloc_functions
); i
++)
657 add_function_assign_hook(alloc_functions
[i
].func
, &match_alloc
,
658 INT_PTR(alloc_functions
[i
].param
));
659 add_hook(&match_call_assignment
, CALL_ASSIGNMENT_HOOK
);
660 add_split_return_callback(print_returned_allocations
);