Makefile: turn on -Wno-switch
[smatch.git] / smatch_address.c
blob370d2c6c5a0a894240d04ebf41ff0536f5d3af01
1 /*
2 * Copyright (C) 2015 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
18 #include "smatch.h"
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
22 static bool is_non_null_array(struct expression *expr)
24 struct symbol *type;
25 struct symbol *sym;
26 struct symbol *tmp;
27 char *name;
28 int i;
30 type = get_type(expr);
31 if (!type || type->type != SYM_ARRAY)
32 return 0;
33 if (expr->type == EXPR_SYMBOL)
34 return 1;
35 if (implied_not_equal(expr, 0))
36 return 1;
38 /* verify that it's not the first member of the struct */
39 if (expr->type != EXPR_DEREF || !expr->member)
40 return 0;
41 name = expr_to_var_sym(expr, &sym);
42 free_string(name);
43 if (!name || !sym)
44 return 0;
45 type = get_real_base_type(sym);
46 if (!type || type->type != SYM_PTR)
47 return 0;
48 type = get_real_base_type(type);
49 if (type->type != SYM_STRUCT)
50 return 0;
52 i = 0;
53 FOR_EACH_PTR(type->symbol_list, tmp) {
54 i++;
55 if (!tmp->ident)
56 continue;
57 if (strcmp(expr->member->name, tmp->ident->name) == 0) {
58 if (i == 1)
59 return 0;
60 return 1;
62 } END_FOR_EACH_PTR(tmp);
64 return 0;
67 int get_member_offset(struct symbol *type, char *member_name)
69 struct symbol *tmp;
70 int offset;
72 if (type->type != SYM_STRUCT)
73 return -1;
75 offset = 0;
76 FOR_EACH_PTR(type->symbol_list, tmp) {
77 if (!type->ctype.attribute->is_packed)
78 offset = ALIGN(offset, tmp->ctype.alignment);
79 if (tmp->ident && tmp->ident->name &&
80 strcmp(member_name, tmp->ident->name) == 0) {
81 return offset;
83 offset += type_bytes(tmp);
84 } END_FOR_EACH_PTR(tmp);
85 return -1;
88 int get_member_offset_from_deref(struct expression *expr)
90 struct symbol *type;
91 struct ident *member;
92 int offset;
94 if (expr->type != EXPR_DEREF) /* hopefully, this doesn't happen */
95 return -1;
97 if (expr->member_offset >= 0)
98 return expr->member_offset;
100 member = expr->member;
101 if (!member || !member->name)
102 return -1;
104 type = get_type(expr->deref);
105 if (!type || type->type != SYM_STRUCT)
106 return -1;
108 offset = get_member_offset(type, member->name);
109 if (offset >= 0)
110 expr->member_offset = offset;
111 return offset;
114 static void add_offset_to_min(struct range_list **rl, int offset)
116 sval_t sval, max;
117 struct range_list *orig = *rl;
118 struct range_list *offset_rl;
119 struct range_list *big_rl;
120 struct range_list *tmp;
123 * I don't know. I guess I want to preserve the upper value because
124 * that has no information. Only the lower value is interesting.
127 if (!orig)
128 return;
129 sval = rl_min(orig); /* get the type */
130 sval.value = offset;
132 offset_rl = alloc_rl(sval, sval);
133 tmp = rl_binop(orig, '+', offset_rl);
135 max = rl_max(orig);
136 /* if we actually "know" the max then preserve it. */
137 if (max.value < 100000) {
138 *rl = tmp;
139 return;
141 sval.value = 0;
142 big_rl = alloc_rl(sval, max);
144 *rl = rl_intersection(tmp, big_rl);
147 static struct range_list *where_allocated_rl(struct symbol *sym)
149 if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)) {
150 if (sym->initializer)
151 return alloc_rl(data_seg_min, data_seg_max);
152 else
153 return alloc_rl(bss_seg_min, bss_seg_max);
155 return alloc_rl(stack_seg_min, stack_seg_max);
158 int get_address_rl(struct expression *expr, struct range_list **rl)
160 expr = strip_expr(expr);
161 if (!expr)
162 return 0;
164 if (expr->type == EXPR_STRING) {
165 *rl = alloc_rl(text_seg_min, text_seg_max);
166 return 1;
169 if (expr->type == EXPR_PREOP && expr->op == '&') {
170 struct expression *unop;
172 unop = strip_expr(expr->unop);
173 if (unop->type == EXPR_SYMBOL) {
174 *rl = where_allocated_rl(unop->symbol);
175 return 1;
178 if (unop->type == EXPR_DEREF) {
179 int offset = get_member_offset_from_deref(unop);
181 unop = strip_expr(unop->unop);
182 if (unop->type == EXPR_SYMBOL) {
183 *rl = where_allocated_rl(unop->symbol);
184 } else if (unop->type == EXPR_PREOP && unop->op == '*') {
185 unop = strip_expr(unop->unop);
186 get_absolute_rl(unop, rl);
187 } else {
188 return 0;
191 add_offset_to_min(rl, offset);
192 return 1;
195 return 0;
198 if (is_non_null_array(expr)) {
199 *rl = alloc_rl(array_min_sval, array_max_sval);
200 return 1;
203 return 0;