2 * Copyright (C) 2017 Oracle. All rights reserved.
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 * One problem that I have is that it's really hard to track how pointers are
20 * passed around. For example, it would be nice to know that the probe() and
21 * remove() functions get the same pci_dev pointer. It would be good to know
22 * what pointers we're passing to the open() and close() functions. But that
23 * information gets lost in a call tree full of function pointer calls.
25 * I think the first step is to start naming specific pointers. So when a
26 * pointer is allocated, then it gets a tag. So calls to kmalloc() generate a
27 * tag. But we might not use that, because there might be a better name like
28 * framebuffer_alloc(). The framebuffer_alloc() is interesting because there is
29 * one per driver and it's passed around to all the file operations.
31 * Perhaps we could make a list of functions like framebuffer_alloc() which take
32 * a size and say that those are the interesting alloc functions.
34 * Another place where we would maybe name the pointer is when they are passed
35 * to the probe(). Because that's an important pointer, since there is one
36 * per driver (sort of).
38 * My vision is that you could take a pointer and trace it back to a global. So
39 * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
40 * tag. You could follow that one back and so on. Also when we pass a pointer
41 * to a function that would be recorded as sort of a link or path or something.
46 #include "smatch_slist.h"
47 #include "smatch_extra.h"
49 #include <openssl/md5.h>
53 static mtag_t
str_to_tag(const char *str
)
55 unsigned char c
[MD5_DIGEST_LENGTH
];
56 unsigned long long *tag
= (unsigned long long *)&c
;
62 MD5_Update(&mdContext
, str
, len
);
63 MD5_Final(c
, &mdContext
);
65 *tag
&= ~MTAG_ALIAS_BIT
;
66 *tag
&= ~MTAG_OFFSET_MASK
;
74 } allocator_info
[] = {
81 static bool is_mtag_call(struct expression
*expr
)
83 struct expression
*arg
;
87 if (expr
->type
!= EXPR_CALL
||
88 expr
->fn
->type
!= EXPR_SYMBOL
||
92 for (i
= 0; i
< ARRAY_SIZE(allocator_info
); i
++) {
93 if (strcmp(expr
->fn
->symbol
->ident
->name
, allocator_info
[i
].name
) == 0)
96 if (i
== ARRAY_SIZE(allocator_info
))
99 arg
= get_argument_from_call_expr(expr
->args
, allocator_info
[i
].size_arg
);
100 if (!get_implied_value(arg
, &sval
))
106 struct smatch_state
*swap_mtag_return(struct expression
*expr
, struct smatch_state
*state
)
108 struct expression
*left
, *right
;
109 char *left_name
, *right_name
;
110 struct symbol
*left_sym
;
111 struct range_list
*rl
;
116 if (!expr
|| expr
->type
!= EXPR_ASSIGNMENT
|| expr
->op
!= '=')
119 if (!estate_rl(state
) || strcmp(state
->name
, "0,4096-ptr_max") != 0)
122 left
= strip_expr(expr
->left
);
123 right
= strip_expr(expr
->right
);
125 if (!is_mtag_call(right
))
128 left_name
= expr_to_str_sym(left
, &left_sym
);
129 if (!left_name
|| !left_sym
)
131 right_name
= expr_to_str(right
);
133 snprintf(buf
, sizeof(buf
), "%s %s %s %s", get_filename(), get_function(),
134 left_name
, right_name
);
135 tag
= str_to_tag(buf
);
136 tag_sval
.type
= estate_type(state
);
137 tag_sval
.uvalue
= tag
;
139 rl
= rl_filter(estate_rl(state
), valid_ptr_rl
);
141 add_range(&rl
, tag_sval
, tag_sval
);
143 sql_insert_mtag_about(tag
, left_name
, buf
);
145 free_string(left_name
);
146 free_string(right_name
);
148 return alloc_estate_rl(rl
);
151 int get_string_mtag(struct expression
*expr
, mtag_t
*tag
)
155 if (expr
->type
!= EXPR_STRING
|| !expr
->string
)
158 /* I was worried about collisions so I added a xor */
159 xor = str_to_tag("__smatch string");
160 *tag
= str_to_tag(expr
->string
->data
);
166 int get_toplevel_mtag(struct symbol
*sym
, mtag_t
*tag
)
174 !(sym
->ctype
.modifiers
& MOD_TOPLEVEL
))
177 snprintf(buf
, sizeof(buf
), "%s %s",
178 (sym
->ctype
.modifiers
& MOD_STATIC
) ? get_filename() : "extern",
180 *tag
= str_to_tag(buf
);
184 int get_deref_mtag(struct expression
*expr
, mtag_t
*tag
)
186 mtag_t container_tag
, member_tag
;
190 * I'm not totally sure what I'm doing...
192 * This is supposed to get something like "global_var->ptr", but I don't
193 * feel like it's complete at all.
197 if (!get_mtag(expr
->unop
, &container_tag
))
200 offset
= get_member_offset_from_deref(expr
);
204 if (!mtag_map_select_tag(container_tag
, -offset
, &member_tag
))
211 static void global_variable(struct symbol
*sym
)
215 if (!get_toplevel_mtag(sym
, &tag
))
218 sql_insert_mtag_about(tag
,
220 (sym
->ctype
.modifiers
& MOD_STATIC
) ? get_filename() : "extern");
223 static int get_array_mtag_offset(struct expression
*expr
, mtag_t
*tag
, int *offset
)
225 struct expression
*array
, *offset_expr
;
232 array
= get_array_base(expr
);
235 type
= get_type(array
);
236 if (!type
|| type
->type
!= SYM_ARRAY
)
238 type
= get_real_base_type(type
);
239 if (!type_bytes(type
))
242 if (!get_mtag(array
, tag
))
245 offset_expr
= get_array_offset(expr
);
246 if (!get_value(offset_expr
, &sval
))
248 *offset
= sval
.value
* type_bytes(type
);
253 static int get_implied_mtag_offset(struct expression
*expr
, mtag_t
*tag
, int *offset
)
255 struct smatch_state
*state
;
259 type
= get_type(expr
);
260 if (!type_is_ptr(type
))
262 state
= get_extra_state(expr
);
263 if (!state
|| !estate_get_single_value(state
, &sval
) || sval
.value
== 0)
266 *tag
= sval
.uvalue
& ~MTAG_OFFSET_MASK
;
267 *offset
= sval
.uvalue
& MTAG_OFFSET_MASK
;
271 static int get_mtag_cnt
;
272 int get_mtag(struct expression
*expr
, mtag_t
*tag
)
274 struct smatch_state
*state
;
277 expr
= strip_expr(expr
);
281 if (get_mtag_cnt
> 0)
286 switch (expr
->type
) {
288 if (get_string_mtag(expr
, tag
)) {
294 if (get_toplevel_mtag(expr
->symbol
, tag
)) {
300 if (get_deref_mtag(expr
, tag
)) {
307 state
= get_state_expr(my_id
, expr
);
311 *tag
= *(mtag_t
*)state
->data
;
321 int get_mtag_offset(struct expression
*expr
, mtag_t
*tag
, int *offset
)
327 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '*')
328 return get_mtag_offset(expr
->unop
, tag
, offset
);
329 if (get_implied_mtag_offset(expr
, tag
, offset
))
331 if (!get_mtag(expr
, tag
))
333 expr
= strip_expr(expr
);
334 if (expr
->type
== EXPR_SYMBOL
) {
338 val
= get_member_offset_from_deref(expr
);
345 struct range_list
*swap_mtag_seed(struct expression
*expr
, struct range_list
*rl
)
352 if (!rl_to_sval(rl
, &sval
))
354 if (sval
.type
->type
!= SYM_PTR
|| sval
.uvalue
!= MTAG_SEED
)
357 name
= expr_to_str(expr
);
358 snprintf(buf
, sizeof(buf
), "%s %s %s", get_filename(), get_function(), name
);
360 tag
= str_to_tag(buf
);
362 return alloc_rl(sval
, sval
);
365 int create_mtag_alias(mtag_t tag
, struct expression
*expr
, mtag_t
*new)
368 int lines_from_start
;
372 * We need the alias to be unique. It's not totally required that it
373 * be the same from one DB build to then next, but it makes debugging
381 lines_from_start
= expr
->pos
.line
- cur_func_sym
->pos
.line
;
382 str
= expr_to_str(expr
);
383 snprintf(buf
, sizeof(buf
), "%lld %d %s", tag
, lines_from_start
, str
);
386 *new = str_to_tag(buf
);
387 sql_insert_mtag_alias(tag
, *new);
392 int expr_to_mtag_offset(struct expression
*expr
, mtag_t
*tag
, int *offset
)
396 expr
= strip_expr(expr
);
401 return get_array_mtag_offset(expr
, tag
, offset
);
403 if (expr
->type
== EXPR_DEREF
) {
404 *offset
= get_member_offset_from_deref(expr
);
407 return get_mtag(expr
->deref
, tag
);
410 if (get_implied_mtag_offset(expr
, tag
, offset
))
413 return get_mtag(expr
, tag
);
416 int get_mtag_sval(struct expression
*expr
, sval_t
*sval
)
422 if (bits_in_pointer
!= 64)
425 expr
= strip_expr(expr
);
427 type
= get_type(expr
);
428 if (!type_is_ptr(type
))
431 * There are only three options:
433 * 1) An array address:
435 * 2) An address like so:
436 * p = &my_struct->member;
442 if (expr
->type
== EXPR_STRING
&& get_string_mtag(expr
, &tag
))
445 if (expr
->type
== EXPR_SYMBOL
&&
446 (type
->type
== SYM_ARRAY
|| type
->type
== SYM_FN
) &&
447 get_toplevel_mtag(expr
->symbol
, &tag
))
450 if (get_implied_mtag_offset(expr
, &tag
, &offset
))
453 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '&')
455 expr
= strip_expr(expr
->unop
);
457 if (!expr_to_mtag_offset(expr
, &tag
, &offset
))
459 if (offset
> MTAG_OFFSET_MASK
)
460 offset
= MTAG_OFFSET_MASK
;
464 sval
->uvalue
= tag
| offset
;
469 static struct expression
*remove_dereference(struct expression
*expr
)
471 expr
= strip_expr(expr
);
475 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '*')
476 return strip_expr(expr
->unop
);
477 return preop_expression(expr
, '&');
480 int get_mtag_addr_sval(struct expression
*expr
, sval_t
*sval
)
482 return get_mtag_sval(remove_dereference(expr
), sval
);
485 void register_mtag(int id
)
491 * The mtag stuff only works on 64 systems because we store the
492 * information in the pointer itself.
493 * bit 63 : set for alias mtags
494 * bit 62-12: mtag hash
498 if (bits_in_pointer
!= 64)
501 add_hook(&global_variable
, BASE_HOOK
);