11f5207b7SJohn Levon /*
21f5207b7SJohn Levon * Copyright (C) 2017 Oracle. All rights reserved.
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 * One problem that I have is that it's really hard to track how pointers are
201f5207b7SJohn Levon * passed around. For example, it would be nice to know that the probe() and
211f5207b7SJohn Levon * remove() functions get the same pci_dev pointer. It would be good to know
221f5207b7SJohn Levon * what pointers we're passing to the open() and close() functions. But that
231f5207b7SJohn Levon * information gets lost in a call tree full of function pointer calls.
241f5207b7SJohn Levon *
251f5207b7SJohn Levon * I think the first step is to start naming specific pointers. So when a
261f5207b7SJohn Levon * pointer is allocated, then it gets a tag. So calls to kmalloc() generate a
271f5207b7SJohn Levon * tag. But we might not use that, because there might be a better name like
281f5207b7SJohn Levon * framebuffer_alloc(). The framebuffer_alloc() is interesting because there is
291f5207b7SJohn Levon * one per driver and it's passed around to all the file operations.
301f5207b7SJohn Levon *
311f5207b7SJohn Levon * Perhaps we could make a list of functions like framebuffer_alloc() which take
321f5207b7SJohn Levon * a size and say that those are the interesting alloc functions.
331f5207b7SJohn Levon *
341f5207b7SJohn Levon * Another place where we would maybe name the pointer is when they are passed
351f5207b7SJohn Levon * to the probe(). Because that's an important pointer, since there is one
361f5207b7SJohn Levon * per driver (sort of).
371f5207b7SJohn Levon *
381f5207b7SJohn Levon * My vision is that you could take a pointer and trace it back to a global. So
391f5207b7SJohn Levon * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
401f5207b7SJohn Levon * tag. You could follow that one back and so on. Also when we pass a pointer
411f5207b7SJohn Levon * to a function that would be recorded as sort of a link or path or something.
421f5207b7SJohn Levon *
431f5207b7SJohn Levon */
441f5207b7SJohn Levon
451f5207b7SJohn Levon #include "smatch.h"
461f5207b7SJohn Levon #include "smatch_slist.h"
471f5207b7SJohn Levon #include "smatch_extra.h"
481f5207b7SJohn Levon
49*6ff4183cSAndy Fiddaman #include <md5.h>
501f5207b7SJohn Levon
511f5207b7SJohn Levon static int my_id;
521f5207b7SJohn Levon
str_to_mtag(const char * str)5331ad075eSJohn Levon mtag_t str_to_mtag(const char *str)
541f5207b7SJohn Levon {
551f5207b7SJohn Levon unsigned char c[MD5_DIGEST_LENGTH];
561f5207b7SJohn Levon unsigned long long *tag = (unsigned long long *)&c;
571f5207b7SJohn Levon int len;
581f5207b7SJohn Levon
591f5207b7SJohn Levon len = strlen(str);
60*6ff4183cSAndy Fiddaman md5_calc(c, str, len);
611f5207b7SJohn Levon
621f5207b7SJohn Levon *tag &= ~MTAG_ALIAS_BIT;
631f5207b7SJohn Levon *tag &= ~MTAG_OFFSET_MASK;
641f5207b7SJohn Levon
651f5207b7SJohn Levon return *tag;
661f5207b7SJohn Levon }
671f5207b7SJohn Levon
save_allocator(void * _allocator,int argc,char ** argv,char ** azColName)686523a3aaSJohn Levon static int save_allocator(void *_allocator, int argc, char **argv, char **azColName)
696523a3aaSJohn Levon {
706523a3aaSJohn Levon char **allocator = _allocator;
716523a3aaSJohn Levon
726523a3aaSJohn Levon if (*allocator) {
736523a3aaSJohn Levon if (strcmp(*allocator, argv[0]) == 0)
746523a3aaSJohn Levon return 0;
756523a3aaSJohn Levon /* should be impossible */
766523a3aaSJohn Levon free_string(*allocator);
776523a3aaSJohn Levon *allocator = alloc_string("unknown");
786523a3aaSJohn Levon return 0;
796523a3aaSJohn Levon }
806523a3aaSJohn Levon *allocator = alloc_string(argv[0]);
816523a3aaSJohn Levon return 0;
826523a3aaSJohn Levon }
836523a3aaSJohn Levon
get_allocator_info_from_tag(mtag_t tag)846523a3aaSJohn Levon char *get_allocator_info_from_tag(mtag_t tag)
856523a3aaSJohn Levon {
866523a3aaSJohn Levon char *allocator = NULL;
876523a3aaSJohn Levon
886523a3aaSJohn Levon run_sql(save_allocator, &allocator,
896523a3aaSJohn Levon "select value from mtag_info where tag = %lld and type = %d;",
906523a3aaSJohn Levon tag, ALLOCATOR);
916523a3aaSJohn Levon
926523a3aaSJohn Levon return allocator;
936523a3aaSJohn Levon }
946523a3aaSJohn Levon
get_allocator_info(struct expression * expr,struct smatch_state * state)956523a3aaSJohn Levon static char *get_allocator_info(struct expression *expr, struct smatch_state *state)
96efe51d0cSJohn Levon {
97efe51d0cSJohn Levon sval_t sval;
98efe51d0cSJohn Levon
996523a3aaSJohn Levon if (expr->type != EXPR_ASSIGNMENT)
1006523a3aaSJohn Levon return NULL;
1016523a3aaSJohn Levon if (estate_get_single_value(state, &sval))
1026523a3aaSJohn Levon return get_allocator_info_from_tag(sval.value);
1036523a3aaSJohn Levon
1046523a3aaSJohn Levon expr = strip_expr(expr->right);
105efe51d0cSJohn Levon if (expr->type != EXPR_CALL ||
1066523a3aaSJohn Levon !expr->fn ||
1076523a3aaSJohn Levon expr->fn->type != EXPR_SYMBOL)
1086523a3aaSJohn Levon return NULL;
1096523a3aaSJohn Levon return expr_to_str(expr->fn);
1106523a3aaSJohn Levon }
111efe51d0cSJohn Levon
update_mtag_info(struct expression * expr,mtag_t tag,const char * left_name,const char * tag_info,struct smatch_state * state)1126523a3aaSJohn Levon static void update_mtag_info(struct expression *expr, mtag_t tag,
1136523a3aaSJohn Levon const char *left_name, const char *tag_info,
1146523a3aaSJohn Levon struct smatch_state *state)
1156523a3aaSJohn Levon {
1166523a3aaSJohn Levon char *allocator;
117efe51d0cSJohn Levon
1186523a3aaSJohn Levon sql_insert_mtag_about(tag, left_name, tag_info);
119efe51d0cSJohn Levon
1206523a3aaSJohn Levon allocator = get_allocator_info(expr, state);
1216523a3aaSJohn Levon if (allocator)
1226523a3aaSJohn Levon sql_insert_mtag_info(tag, ALLOCATOR, allocator);
123efe51d0cSJohn Levon }
124efe51d0cSJohn Levon
get_mtag_return(struct expression * expr,struct smatch_state * state)1256523a3aaSJohn Levon struct smatch_state *get_mtag_return(struct expression *expr, struct smatch_state *state)
1261f5207b7SJohn Levon {
1271f5207b7SJohn Levon struct expression *left, *right;
1281f5207b7SJohn Levon char *left_name, *right_name;
1291f5207b7SJohn Levon struct symbol *left_sym;
130efe51d0cSJohn Levon struct range_list *rl;
1311f5207b7SJohn Levon char buf[256];
1321f5207b7SJohn Levon mtag_t tag;
133efe51d0cSJohn Levon sval_t tag_sval;
1341f5207b7SJohn Levon
135efe51d0cSJohn Levon if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
1366523a3aaSJohn Levon return NULL;
1376523a3aaSJohn Levon if (!is_fresh_alloc(expr->right))
1386523a3aaSJohn Levon return NULL;
1396523a3aaSJohn Levon if (!rl_intersection(estate_rl(state), valid_ptr_rl))
1406523a3aaSJohn Levon return NULL;
1411f5207b7SJohn Levon
1421f5207b7SJohn Levon left = strip_expr(expr->left);
1431f5207b7SJohn Levon right = strip_expr(expr->right);
144efe51d0cSJohn Levon
1451f5207b7SJohn Levon left_name = expr_to_str_sym(left, &left_sym);
146efe51d0cSJohn Levon if (!left_name || !left_sym)
1476523a3aaSJohn Levon return NULL;
1481f5207b7SJohn Levon right_name = expr_to_str(right);
1491f5207b7SJohn Levon
1501f5207b7SJohn Levon snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
1511f5207b7SJohn Levon left_name, right_name);
15231ad075eSJohn Levon tag = str_to_mtag(buf);
153efe51d0cSJohn Levon tag_sval.type = estate_type(state);
154efe51d0cSJohn Levon tag_sval.uvalue = tag;
1551f5207b7SJohn Levon
156efe51d0cSJohn Levon rl = rl_filter(estate_rl(state), valid_ptr_rl);
157efe51d0cSJohn Levon rl = clone_rl(rl);
158efe51d0cSJohn Levon add_range(&rl, tag_sval, tag_sval);
1591f5207b7SJohn Levon
1606523a3aaSJohn Levon update_mtag_info(expr, tag, left_name, buf, state);
1611f5207b7SJohn Levon
1621f5207b7SJohn Levon free_string(left_name);
1631f5207b7SJohn Levon free_string(right_name);
164efe51d0cSJohn Levon
165efe51d0cSJohn Levon return alloc_estate_rl(rl);
1661f5207b7SJohn Levon }
1671f5207b7SJohn Levon
get_string_mtag(struct expression * expr,mtag_t * tag)1681f5207b7SJohn Levon int get_string_mtag(struct expression *expr, mtag_t *tag)
1691f5207b7SJohn Levon {
1701f5207b7SJohn Levon mtag_t xor;
1711f5207b7SJohn Levon
1721f5207b7SJohn Levon if (expr->type != EXPR_STRING || !expr->string)
1731f5207b7SJohn Levon return 0;
1741f5207b7SJohn Levon
1751f5207b7SJohn Levon /* I was worried about collisions so I added a xor */
17631ad075eSJohn Levon xor = str_to_mtag("__smatch string");
17731ad075eSJohn Levon *tag = str_to_mtag(expr->string->data);
1781f5207b7SJohn Levon *tag = *tag ^ xor;
1791f5207b7SJohn Levon
1801f5207b7SJohn Levon return 1;
1811f5207b7SJohn Levon }
1821f5207b7SJohn Levon
get_toplevel_mtag(struct symbol * sym,mtag_t * tag)1831f5207b7SJohn Levon int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
1841f5207b7SJohn Levon {
1851f5207b7SJohn Levon char buf[256];
1861f5207b7SJohn Levon
1871f5207b7SJohn Levon if (!sym)
1881f5207b7SJohn Levon return 0;
1891f5207b7SJohn Levon
1901f5207b7SJohn Levon if (!sym->ident ||
1911f5207b7SJohn Levon !(sym->ctype.modifiers & MOD_TOPLEVEL))
1921f5207b7SJohn Levon return 0;
1931f5207b7SJohn Levon
1941f5207b7SJohn Levon snprintf(buf, sizeof(buf), "%s %s",
1951f5207b7SJohn Levon (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
1961f5207b7SJohn Levon sym->ident->name);
19731ad075eSJohn Levon *tag = str_to_mtag(buf);
1981f5207b7SJohn Levon return 1;
1991f5207b7SJohn Levon }
2001f5207b7SJohn Levon
get_symbol_mtag(struct symbol * sym,mtag_t * tag)201efe51d0cSJohn Levon bool get_symbol_mtag(struct symbol *sym, mtag_t *tag)
2021f5207b7SJohn Levon {
203efe51d0cSJohn Levon char buf[256];
2041f5207b7SJohn Levon
205efe51d0cSJohn Levon if (!sym || !sym->ident)
206efe51d0cSJohn Levon return false;
2071f5207b7SJohn Levon
208efe51d0cSJohn Levon if (get_toplevel_mtag(sym, tag))
209efe51d0cSJohn Levon return true;
2101f5207b7SJohn Levon
211efe51d0cSJohn Levon if (get_param_num_from_sym(sym) >= 0)
212efe51d0cSJohn Levon return false;
2131f5207b7SJohn Levon
214efe51d0cSJohn Levon snprintf(buf, sizeof(buf), "%s %s %s",
215efe51d0cSJohn Levon get_filename(), get_function(), sym->ident->name);
21631ad075eSJohn Levon *tag = str_to_mtag(buf);
217efe51d0cSJohn Levon return true;
2181f5207b7SJohn Levon }
2191f5207b7SJohn Levon
global_variable(struct symbol * sym)2201f5207b7SJohn Levon static void global_variable(struct symbol *sym)
2211f5207b7SJohn Levon {
2221f5207b7SJohn Levon mtag_t tag;
2231f5207b7SJohn Levon
2241f5207b7SJohn Levon if (!get_toplevel_mtag(sym, &tag))
2251f5207b7SJohn Levon return;
2261f5207b7SJohn Levon
2271f5207b7SJohn Levon sql_insert_mtag_about(tag,
2281f5207b7SJohn Levon sym->ident->name,
2291f5207b7SJohn Levon (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
2301f5207b7SJohn Levon }
2311f5207b7SJohn Levon
get_array_mtag_offset(struct expression * expr,mtag_t * tag,int * offset)2321f5207b7SJohn Levon static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
2331f5207b7SJohn Levon {
2341f5207b7SJohn Levon struct expression *array, *offset_expr;
2351f5207b7SJohn Levon struct symbol *type;
2361f5207b7SJohn Levon sval_t sval;
237efe51d0cSJohn Levon int start_offset;
2381f5207b7SJohn Levon
2391f5207b7SJohn Levon if (!is_array(expr))
2401f5207b7SJohn Levon return 0;
2411f5207b7SJohn Levon
2421f5207b7SJohn Levon array = get_array_base(expr);
2431f5207b7SJohn Levon if (!array)
2441f5207b7SJohn Levon return 0;
2451f5207b7SJohn Levon type = get_type(array);
2461f5207b7SJohn Levon if (!type || type->type != SYM_ARRAY)
2471f5207b7SJohn Levon return 0;
2481f5207b7SJohn Levon type = get_real_base_type(type);
2491f5207b7SJohn Levon if (!type_bytes(type))
2501f5207b7SJohn Levon return 0;
2511f5207b7SJohn Levon
252efe51d0cSJohn Levon if (!expr_to_mtag_offset(array, tag, &start_offset))
2531f5207b7SJohn Levon return 0;
2541f5207b7SJohn Levon
2551f5207b7SJohn Levon offset_expr = get_array_offset(expr);
2561f5207b7SJohn Levon if (!get_value(offset_expr, &sval))
2571f5207b7SJohn Levon return 0;
258efe51d0cSJohn Levon *offset = start_offset + sval.value * type_bytes(type);
2591f5207b7SJohn Levon
2601f5207b7SJohn Levon return 1;
2611f5207b7SJohn Levon }
2621f5207b7SJohn Levon
swap_mtag_seed(struct expression * expr,struct range_list * rl)263efe51d0cSJohn Levon struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl)
2641f5207b7SJohn Levon {
265efe51d0cSJohn Levon char buf[256];
266efe51d0cSJohn Levon char *name;
2671f5207b7SJohn Levon sval_t sval;
268efe51d0cSJohn Levon mtag_t tag;
2691f5207b7SJohn Levon
270efe51d0cSJohn Levon if (!rl_to_sval(rl, &sval))
271efe51d0cSJohn Levon return rl;
272efe51d0cSJohn Levon if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED)
273efe51d0cSJohn Levon return rl;
2741f5207b7SJohn Levon
275efe51d0cSJohn Levon name = expr_to_str(expr);
276efe51d0cSJohn Levon snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name);
277efe51d0cSJohn Levon free_string(name);
27831ad075eSJohn Levon tag = str_to_mtag(buf);
279efe51d0cSJohn Levon sval.value = tag;
280efe51d0cSJohn Levon return alloc_rl(sval, sval);
2811f5207b7SJohn Levon }
2821f5207b7SJohn Levon
create_mtag_alias(mtag_t tag,struct expression * expr,mtag_t * new)2831f5207b7SJohn Levon int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
2841f5207b7SJohn Levon {
2851f5207b7SJohn Levon char buf[256];
2861f5207b7SJohn Levon int lines_from_start;
2871f5207b7SJohn Levon char *str;
2881f5207b7SJohn Levon
2891f5207b7SJohn Levon /*
2901f5207b7SJohn Levon * We need the alias to be unique. It's not totally required that it
2911f5207b7SJohn Levon * be the same from one DB build to then next, but it makes debugging
2921f5207b7SJohn Levon * a bit simpler.
2931f5207b7SJohn Levon *
2941f5207b7SJohn Levon */
2951f5207b7SJohn Levon
2961f5207b7SJohn Levon if (!cur_func_sym)
2971f5207b7SJohn Levon return 0;
2981f5207b7SJohn Levon
2991f5207b7SJohn Levon lines_from_start = expr->pos.line - cur_func_sym->pos.line;
3001f5207b7SJohn Levon str = expr_to_str(expr);
3011f5207b7SJohn Levon snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
3021f5207b7SJohn Levon free_string(str);
3031f5207b7SJohn Levon
30431ad075eSJohn Levon *new = str_to_mtag(buf);
3051f5207b7SJohn Levon sql_insert_mtag_alias(tag, *new);
3061f5207b7SJohn Levon
3071f5207b7SJohn Levon return 1;
3081f5207b7SJohn Levon }
3091f5207b7SJohn Levon
get_implied_mtag_offset(struct expression * expr,mtag_t * tag,int * offset)310efe51d0cSJohn Levon static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
311efe51d0cSJohn Levon {
312efe51d0cSJohn Levon struct smatch_state *state;
313efe51d0cSJohn Levon struct symbol *type;
314efe51d0cSJohn Levon sval_t sval;
315efe51d0cSJohn Levon
316efe51d0cSJohn Levon type = get_type(expr);
317efe51d0cSJohn Levon if (!type_is_ptr(type))
318efe51d0cSJohn Levon return 0;
319efe51d0cSJohn Levon state = get_extra_state(expr);
320efe51d0cSJohn Levon if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
321efe51d0cSJohn Levon return 0;
322efe51d0cSJohn Levon
323efe51d0cSJohn Levon *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
324efe51d0cSJohn Levon *offset = sval.uvalue & MTAG_OFFSET_MASK;
325efe51d0cSJohn Levon return 1;
326efe51d0cSJohn Levon }
327efe51d0cSJohn Levon
328efe51d0cSJohn Levon /*
329efe51d0cSJohn Levon * The point of this function is to give you the mtag and the offset so
330efe51d0cSJohn Levon * you can look up the data in the DB. It takes an expression.
331efe51d0cSJohn Levon *
332efe51d0cSJohn Levon * So say you give it "foo->bar". Then it would give you the offset of "bar"
333efe51d0cSJohn Levon * and the implied value of "foo". Or if you lookup "*foo" then the offset is
334efe51d0cSJohn Levon * zero and we look up the implied value of "foo. But if the expression is
335efe51d0cSJohn Levon * foo, then if "foo" is a global variable, then we get the mtag and the offset
336efe51d0cSJohn Levon * is zero. If "foo" is a local variable, then there is nothing to look up in
337efe51d0cSJohn Levon * the mtag_data table because that's handled by smatch_extra.c to this returns
338efe51d0cSJohn Levon * false.
339efe51d0cSJohn Levon *
340efe51d0cSJohn Levon */
expr_to_mtag_offset(struct expression * expr,mtag_t * tag,int * offset)3411f5207b7SJohn Levon int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
3421f5207b7SJohn Levon {
343efe51d0cSJohn Levon *tag = 0;
3441f5207b7SJohn Levon *offset = 0;
3451f5207b7SJohn Levon
346efe51d0cSJohn Levon if (bits_in_pointer != 64)
347efe51d0cSJohn Levon return 0;
348efe51d0cSJohn Levon
3491f5207b7SJohn Levon expr = strip_expr(expr);
3501f5207b7SJohn Levon if (!expr)
3511f5207b7SJohn Levon return 0;
3521f5207b7SJohn Levon
3531f5207b7SJohn Levon if (is_array(expr))
3541f5207b7SJohn Levon return get_array_mtag_offset(expr, tag, offset);
3551f5207b7SJohn Levon
356efe51d0cSJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') {
357efe51d0cSJohn Levon expr = strip_expr(expr->unop);
358efe51d0cSJohn Levon return get_implied_mtag_offset(expr, tag, offset);
359efe51d0cSJohn Levon } else if (expr->type == EXPR_DEREF) {
360efe51d0cSJohn Levon int tmp, tmp_offset = 0;
361efe51d0cSJohn Levon
362efe51d0cSJohn Levon while (expr->type == EXPR_DEREF) {
363efe51d0cSJohn Levon tmp = get_member_offset_from_deref(expr);
364efe51d0cSJohn Levon if (tmp < 0)
365efe51d0cSJohn Levon return 0;
366efe51d0cSJohn Levon tmp_offset += tmp;
367c85f09ccSJohn Levon expr = strip_expr(expr->deref);
368efe51d0cSJohn Levon }
369efe51d0cSJohn Levon *offset = tmp_offset;
370efe51d0cSJohn Levon if (expr->type == EXPR_PREOP && expr->op == '*') {
371efe51d0cSJohn Levon expr = strip_expr(expr->unop);
372efe51d0cSJohn Levon
373efe51d0cSJohn Levon if (get_implied_mtag_offset(expr, tag, &tmp_offset)) {
374efe51d0cSJohn Levon // FIXME: look it up recursively?
375efe51d0cSJohn Levon if (tmp_offset)
376efe51d0cSJohn Levon return 0;
377efe51d0cSJohn Levon return 1;
378efe51d0cSJohn Levon }
3791f5207b7SJohn Levon return 0;
380efe51d0cSJohn Levon } else if (expr->type == EXPR_SYMBOL) {
381efe51d0cSJohn Levon return get_symbol_mtag(expr->symbol, tag);
382efe51d0cSJohn Levon }
383efe51d0cSJohn Levon return 0;
384efe51d0cSJohn Levon } else if (expr->type == EXPR_SYMBOL) {
385efe51d0cSJohn Levon return get_symbol_mtag(expr->symbol, tag);
3861f5207b7SJohn Levon }
387efe51d0cSJohn Levon return 0;
3881f5207b7SJohn Levon }
3891f5207b7SJohn Levon
390efe51d0cSJohn Levon /*
391efe51d0cSJohn Levon * This function takes an address and returns an sval. Let's take some
392efe51d0cSJohn Levon * example things you might pass to it:
393efe51d0cSJohn Levon * foo->bar:
394efe51d0cSJohn Levon * If we were only called from smatch_math, we wouldn't need to bother with
395efe51d0cSJohn Levon * this because it's already been looked up in smatch_extra.c but this is
396efe51d0cSJohn Levon * also called from other places so we have to check smatch_extra.c.
397efe51d0cSJohn Levon * &foo
398efe51d0cSJohn Levon * If "foo" is global return the mtag for "foo".
399efe51d0cSJohn Levon * &foo.bar
400efe51d0cSJohn Levon * If "foo" is global return the mtag for "foo" + the offset of ".bar".
401efe51d0cSJohn Levon * It also handles string literals.
402efe51d0cSJohn Levon *
403efe51d0cSJohn Levon */
get_mtag_sval(struct expression * expr,sval_t * sval)4041f5207b7SJohn Levon int get_mtag_sval(struct expression *expr, sval_t *sval)
4051f5207b7SJohn Levon {
4061f5207b7SJohn Levon struct symbol *type;
4071f5207b7SJohn Levon mtag_t tag;
4081f5207b7SJohn Levon int offset = 0;
4091f5207b7SJohn Levon
4101f5207b7SJohn Levon if (bits_in_pointer != 64)
4111f5207b7SJohn Levon return 0;
4121f5207b7SJohn Levon
4131f5207b7SJohn Levon expr = strip_expr(expr);
4141f5207b7SJohn Levon
4151f5207b7SJohn Levon type = get_type(expr);
4161f5207b7SJohn Levon if (!type_is_ptr(type))
4171f5207b7SJohn Levon return 0;
4181f5207b7SJohn Levon /*
419efe51d0cSJohn Levon * There are several options:
4201f5207b7SJohn Levon *
421efe51d0cSJohn Levon * If the expr is a string literal, that's an address/mtag.
422efe51d0cSJohn Levon * SYM_ARRAY and SYM_FN are mtags. There are "&foo" type addresses.
423efe51d0cSJohn Levon * And there are saved pointers "p = &foo;"
4241f5207b7SJohn Levon *
4251f5207b7SJohn Levon */
4261f5207b7SJohn Levon
4271f5207b7SJohn Levon if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
4281f5207b7SJohn Levon goto found;
4291f5207b7SJohn Levon
430efe51d0cSJohn Levon if (expr->type == EXPR_SYMBOL &&
431efe51d0cSJohn Levon (type->type == SYM_ARRAY || type->type == SYM_FN) &&
432efe51d0cSJohn Levon get_toplevel_mtag(expr->symbol, &tag))
4331f5207b7SJohn Levon goto found;
4341f5207b7SJohn Levon
435efe51d0cSJohn Levon if (expr->type == EXPR_PREOP && expr->op == '&') {
436efe51d0cSJohn Levon expr = strip_expr(expr->unop);
437efe51d0cSJohn Levon if (expr_to_mtag_offset(expr, &tag, &offset))
438efe51d0cSJohn Levon goto found;
439efe51d0cSJohn Levon return 0;
440efe51d0cSJohn Levon }
441efe51d0cSJohn Levon
4421f5207b7SJohn Levon if (get_implied_mtag_offset(expr, &tag, &offset))
4431f5207b7SJohn Levon goto found;
4441f5207b7SJohn Levon
445efe51d0cSJohn Levon return 0;
446efe51d0cSJohn Levon found:
447efe51d0cSJohn Levon if (offset >= MTAG_OFFSET_MASK)
4481f5207b7SJohn Levon return 0;
4491f5207b7SJohn Levon
4501f5207b7SJohn Levon sval->type = type;
4511f5207b7SJohn Levon sval->uvalue = tag | offset;
4521f5207b7SJohn Levon
4531f5207b7SJohn Levon return 1;
4541f5207b7SJohn Levon }
4551f5207b7SJohn Levon
register_mtag(int id)4561f5207b7SJohn Levon void register_mtag(int id)
4571f5207b7SJohn Levon {
4581f5207b7SJohn Levon my_id = id;
4591f5207b7SJohn Levon
4601f5207b7SJohn Levon
4611f5207b7SJohn Levon /*
4621f5207b7SJohn Levon * The mtag stuff only works on 64 systems because we store the
4631f5207b7SJohn Levon * information in the pointer itself.
4641f5207b7SJohn Levon * bit 63 : set for alias mtags
4651f5207b7SJohn Levon * bit 62-12: mtag hash
4661f5207b7SJohn Levon * bit 11-0 : offset
4671f5207b7SJohn Levon *
4681f5207b7SJohn Levon */
4691f5207b7SJohn Levon
4701f5207b7SJohn Levon add_hook(&global_variable, BASE_HOOK);
4711f5207b7SJohn Levon }
472