11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2006 Dan Carpenter.
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  * You have a lists of states.  kernel = locked, foo = NULL, ...
201f5207b7SJohn Levon  * When you hit an if {} else {} statement then you swap the list
211f5207b7SJohn Levon  * of states for a different list of states.  The lists are stored
221f5207b7SJohn Levon  * on stacks.
231f5207b7SJohn Levon  *
241f5207b7SJohn Levon  * At the beginning of this file there are list of the stacks that
251f5207b7SJohn Levon  * we use.  Each function in this file does something to one of
261f5207b7SJohn Levon  * of the stacks.
271f5207b7SJohn Levon  *
281f5207b7SJohn Levon  * So the smatch_flow.c understands code but it doesn't understand states.
291f5207b7SJohn Levon  * smatch_flow calls functions in this file.  This file calls functions
301f5207b7SJohn Levon  * in smatch_slist.c which just has boring generic plumbing for handling
311f5207b7SJohn Levon  * state lists.  But really it's this file where all the magic happens.
321f5207b7SJohn Levon  */
331f5207b7SJohn Levon 
341f5207b7SJohn Levon #include <stdlib.h>
351f5207b7SJohn Levon #include <stdio.h>
361f5207b7SJohn Levon #include "smatch.h"
371f5207b7SJohn Levon #include "smatch_slist.h"
381f5207b7SJohn Levon #include "smatch_extra.h"
391f5207b7SJohn Levon 
401f5207b7SJohn Levon struct smatch_state undefined = { .name = "undefined" };
411f5207b7SJohn Levon struct smatch_state ghost = { .name = "ghost" };
421f5207b7SJohn Levon struct smatch_state merged = { .name = "merged" };
431f5207b7SJohn Levon struct smatch_state true_state = { .name = "true" };
441f5207b7SJohn Levon struct smatch_state false_state = { .name = "false" };
451f5207b7SJohn Levon 
461f5207b7SJohn Levon static struct stree *cur_stree; /* current states */
47c85f09ccSJohn Levon static struct stree *fast_overlay;
481f5207b7SJohn Levon 
491f5207b7SJohn Levon static struct stree_stack *true_stack; /* states after a t/f branch */
501f5207b7SJohn Levon static struct stree_stack *false_stack;
511f5207b7SJohn Levon static struct stree_stack *pre_cond_stack; /* states before a t/f branch */
521f5207b7SJohn Levon 
531f5207b7SJohn Levon static struct stree_stack *cond_true_stack; /* states affected by a branch */
541f5207b7SJohn Levon static struct stree_stack *cond_false_stack;
551f5207b7SJohn Levon 
561f5207b7SJohn Levon static struct stree_stack *fake_cur_stree_stack;
571f5207b7SJohn Levon static int read_only;
581f5207b7SJohn Levon 
591f5207b7SJohn Levon static struct stree_stack *break_stack;
601f5207b7SJohn Levon static struct stree_stack *fake_break_stack;
611f5207b7SJohn Levon static struct stree_stack *switch_stack;
621f5207b7SJohn Levon static struct range_list_stack *remaining_cases;
631f5207b7SJohn Levon static struct stree_stack *default_stack;
641f5207b7SJohn Levon static struct stree_stack *continue_stack;
651f5207b7SJohn Levon 
661f5207b7SJohn Levon static struct named_stree_stack *goto_stack;
671f5207b7SJohn Levon 
681f5207b7SJohn Levon static struct ptr_list *backup;
691f5207b7SJohn Levon 
701f5207b7SJohn Levon int option_debug;
711f5207b7SJohn Levon 
__print_cur_stree(void)721f5207b7SJohn Levon void __print_cur_stree(void)
731f5207b7SJohn Levon {
741f5207b7SJohn Levon 	__print_stree(cur_stree);
751f5207b7SJohn Levon }
761f5207b7SJohn Levon 
__print_states(const char * owner)77*6523a3aaSJohn Levon bool __print_states(const char *owner)
78*6523a3aaSJohn Levon {
79*6523a3aaSJohn Levon 	struct sm_state *sm;
80*6523a3aaSJohn Levon 	bool found = false;
81*6523a3aaSJohn Levon 
82*6523a3aaSJohn Levon 	if (!owner)
83*6523a3aaSJohn Levon 		return false;
84*6523a3aaSJohn Levon 
85*6523a3aaSJohn Levon 	FOR_EACH_SM(__get_cur_stree(), sm) {
86*6523a3aaSJohn Levon 		if (!strstr(check_name(sm->owner), owner))
87*6523a3aaSJohn Levon 			continue;
88*6523a3aaSJohn Levon 		sm_msg("%s", show_sm(sm));
89*6523a3aaSJohn Levon 		found = true;
90*6523a3aaSJohn Levon 	} END_FOR_EACH_SM(sm);
91*6523a3aaSJohn Levon 
92*6523a3aaSJohn Levon 	return found;
93*6523a3aaSJohn Levon }
94*6523a3aaSJohn Levon 
unreachable(void)951f5207b7SJohn Levon int unreachable(void)
961f5207b7SJohn Levon {
971f5207b7SJohn Levon 	if (!cur_stree)
981f5207b7SJohn Levon 		return 1;
991f5207b7SJohn Levon 	return 0;
1001f5207b7SJohn Levon }
1011f5207b7SJohn Levon 
__set_cur_stree_readonly(void)102c85f09ccSJohn Levon void __set_cur_stree_readonly(void)
103c85f09ccSJohn Levon {
104c85f09ccSJohn Levon 	read_only++;
105c85f09ccSJohn Levon }
106c85f09ccSJohn Levon 
__set_cur_stree_writable(void)107c85f09ccSJohn Levon void __set_cur_stree_writable(void)
108c85f09ccSJohn Levon {
109c85f09ccSJohn Levon 	read_only--;
110c85f09ccSJohn Levon }
111c85f09ccSJohn Levon 
112*6523a3aaSJohn Levon DECLARE_PTR_LIST(check_tracker_list, check_tracker_hook *);
113*6523a3aaSJohn Levon static struct check_tracker_list **tracker_hooks;
114*6523a3aaSJohn Levon 
add_check_tracker(const char * check_name,check_tracker_hook * fn)115*6523a3aaSJohn Levon void add_check_tracker(const char *check_name, check_tracker_hook *fn)
116*6523a3aaSJohn Levon {
117*6523a3aaSJohn Levon 	check_tracker_hook **p;
118*6523a3aaSJohn Levon 	int owner;
119*6523a3aaSJohn Levon 
120*6523a3aaSJohn Levon 	owner = id_from_name(check_name);
121*6523a3aaSJohn Levon 	if (!owner) {
122*6523a3aaSJohn Levon 		printf("check not found.  '%s'\n", check_name);
123*6523a3aaSJohn Levon 		return;
124*6523a3aaSJohn Levon 	}
125*6523a3aaSJohn Levon 
126*6523a3aaSJohn Levon 	p = malloc(sizeof(check_tracker_hook *));
127*6523a3aaSJohn Levon 	*p = fn;
128*6523a3aaSJohn Levon 	add_ptr_list(&tracker_hooks[owner], p);
129*6523a3aaSJohn Levon }
130*6523a3aaSJohn Levon 
call_tracker_hooks(int owner,const char * name,struct symbol * sym,struct smatch_state * state)131*6523a3aaSJohn Levon static void call_tracker_hooks(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
132*6523a3aaSJohn Levon {
133*6523a3aaSJohn Levon 	struct check_tracker_list *hooks;
134*6523a3aaSJohn Levon 	check_tracker_hook **fn;
135*6523a3aaSJohn Levon 
136*6523a3aaSJohn Levon 	if ((unsigned short)owner == USHRT_MAX)
137*6523a3aaSJohn Levon 		return;
138*6523a3aaSJohn Levon 
139*6523a3aaSJohn Levon 	hooks = tracker_hooks[owner];
140*6523a3aaSJohn Levon 	FOR_EACH_PTR(hooks, fn) {
141*6523a3aaSJohn Levon 		(*fn)(owner, name, sym, state);
142*6523a3aaSJohn Levon 	} END_FOR_EACH_PTR(fn);
143*6523a3aaSJohn Levon }
144*6523a3aaSJohn Levon 
allocate_tracker_array(int num_checks)145*6523a3aaSJohn Levon void allocate_tracker_array(int num_checks)
146*6523a3aaSJohn Levon {
147*6523a3aaSJohn Levon 	tracker_hooks = malloc(num_checks * sizeof(void *));
148*6523a3aaSJohn Levon 	memset(tracker_hooks, 0, num_checks * sizeof(void *));
149*6523a3aaSJohn Levon }
150*6523a3aaSJohn Levon 
set_state(int owner,const char * name,struct symbol * sym,struct smatch_state * state)1511f5207b7SJohn Levon struct sm_state *set_state(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
1521f5207b7SJohn Levon {
1531f5207b7SJohn Levon 	struct sm_state *ret;
1541f5207b7SJohn Levon 
155efe51d0cSJohn Levon 	if (!name || !state)
1561f5207b7SJohn Levon 		return NULL;
1571f5207b7SJohn Levon 
1581f5207b7SJohn Levon 	if (read_only)
1591f5207b7SJohn Levon 		sm_perror("cur_stree is read only.");
1601f5207b7SJohn Levon 
1611f5207b7SJohn Levon 	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
1621f5207b7SJohn Levon 		struct smatch_state *s;
1631f5207b7SJohn Levon 
164efe51d0cSJohn Levon 		s = __get_state(owner, name, sym);
1651f5207b7SJohn Levon 		if (!s)
1661f5207b7SJohn Levon 			sm_msg("%s new [%s] '%s' %s", __func__,
1671f5207b7SJohn Levon 			       check_name(owner), name, show_state(state));
1681f5207b7SJohn Levon 		else
1691f5207b7SJohn Levon 			sm_msg("%s change [%s] '%s' %s => %s",
1701f5207b7SJohn Levon 				__func__, check_name(owner), name, show_state(s),
1711f5207b7SJohn Levon 				show_state(state));
1721f5207b7SJohn Levon 	}
1731f5207b7SJohn Levon 
174*6523a3aaSJohn Levon 	call_tracker_hooks(owner, name, sym, state);
175*6523a3aaSJohn Levon 
1761f5207b7SJohn Levon 	if (owner != -1 && unreachable())
1771f5207b7SJohn Levon 		return NULL;
1781f5207b7SJohn Levon 
1791f5207b7SJohn Levon 	if (fake_cur_stree_stack)
1801f5207b7SJohn Levon 		set_state_stree_stack(&fake_cur_stree_stack, owner, name, sym, state);
1811f5207b7SJohn Levon 
1821f5207b7SJohn Levon 	ret = set_state_stree(&cur_stree, owner, name, sym, state);
1831f5207b7SJohn Levon 
1841f5207b7SJohn Levon 	return ret;
1851f5207b7SJohn Levon }
1861f5207b7SJohn Levon 
set_state_expr(int owner,struct expression * expr,struct smatch_state * state)1871f5207b7SJohn Levon struct sm_state *set_state_expr(int owner, struct expression *expr, struct smatch_state *state)
1881f5207b7SJohn Levon {
1891f5207b7SJohn Levon 	char *name;
1901f5207b7SJohn Levon 	struct symbol *sym;
1911f5207b7SJohn Levon 	struct sm_state *ret = NULL;
1921f5207b7SJohn Levon 
1931f5207b7SJohn Levon 	expr = strip_expr(expr);
1941f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
1951f5207b7SJohn Levon 	if (!name || !sym)
1961f5207b7SJohn Levon 		goto free;
1971f5207b7SJohn Levon 	ret = set_state(owner, name, sym, state);
1981f5207b7SJohn Levon free:
1991f5207b7SJohn Levon 	free_string(name);
2001f5207b7SJohn Levon 	return ret;
2011f5207b7SJohn Levon }
2021f5207b7SJohn Levon 
__swap_cur_stree(struct stree * stree)203c85f09ccSJohn Levon struct stree *__swap_cur_stree(struct stree *stree)
2041f5207b7SJohn Levon {
205c85f09ccSJohn Levon 	struct stree *orig = cur_stree;
206c85f09ccSJohn Levon 
2071f5207b7SJohn Levon 	cur_stree = stree;
208c85f09ccSJohn Levon 	return orig;
2091f5207b7SJohn Levon }
2101f5207b7SJohn Levon 
__push_fake_cur_stree(void)2111f5207b7SJohn Levon void __push_fake_cur_stree(void)
2121f5207b7SJohn Levon {
2131f5207b7SJohn Levon 	push_stree(&fake_cur_stree_stack, NULL);
2141f5207b7SJohn Levon 	__save_pre_cond_states();
2151f5207b7SJohn Levon }
2161f5207b7SJohn Levon 
__pop_fake_cur_stree(void)2171f5207b7SJohn Levon struct stree *__pop_fake_cur_stree(void)
2181f5207b7SJohn Levon {
2191f5207b7SJohn Levon 	if (!fake_cur_stree_stack)
2201f5207b7SJohn Levon 		sm_perror("popping too many fake cur strees.");
2211f5207b7SJohn Levon 	__use_pre_cond_states();
2221f5207b7SJohn Levon 	return pop_stree(&fake_cur_stree_stack);
2231f5207b7SJohn Levon }
2241f5207b7SJohn Levon 
__free_fake_cur_stree(void)2251f5207b7SJohn Levon void __free_fake_cur_stree(void)
2261f5207b7SJohn Levon {
2271f5207b7SJohn Levon 	struct stree *stree;
2281f5207b7SJohn Levon 
2291f5207b7SJohn Levon 	stree = __pop_fake_cur_stree();
2301f5207b7SJohn Levon 	free_stree(&stree);
2311f5207b7SJohn Levon }
2321f5207b7SJohn Levon 
__set_fake_cur_stree_fast(struct stree * stree)2331f5207b7SJohn Levon void __set_fake_cur_stree_fast(struct stree *stree)
2341f5207b7SJohn Levon {
235c85f09ccSJohn Levon 	if (fast_overlay) {
236c85f09ccSJohn Levon 		sm_perror("cannot nest fast overlay");
237c85f09ccSJohn Levon 		return;
238c85f09ccSJohn Levon 	}
239c85f09ccSJohn Levon 	fast_overlay = stree;
240c85f09ccSJohn Levon 	set_fast_math_only();
2411f5207b7SJohn Levon }
2421f5207b7SJohn Levon 
__pop_fake_cur_stree_fast(void)2431f5207b7SJohn Levon void __pop_fake_cur_stree_fast(void)
2441f5207b7SJohn Levon {
245c85f09ccSJohn Levon 	fast_overlay = NULL;
246c85f09ccSJohn Levon 	clear_fast_math_only();
2471f5207b7SJohn Levon }
2481f5207b7SJohn Levon 
__merge_stree_into_cur(struct stree * stree)2491f5207b7SJohn Levon void __merge_stree_into_cur(struct stree *stree)
2501f5207b7SJohn Levon {
2511f5207b7SJohn Levon 	struct sm_state *sm;
2521f5207b7SJohn Levon 	struct sm_state *orig;
2531f5207b7SJohn Levon 	struct sm_state *merged;
2541f5207b7SJohn Levon 
2551f5207b7SJohn Levon 	FOR_EACH_SM(stree, sm) {
2561f5207b7SJohn Levon 		orig = get_sm_state(sm->owner, sm->name, sm->sym);
2571f5207b7SJohn Levon 		if (orig)
2581f5207b7SJohn Levon 			merged = merge_sm_states(orig, sm);
2591f5207b7SJohn Levon 		else
2601f5207b7SJohn Levon 			merged = sm;
2611f5207b7SJohn Levon 		__set_sm(merged);
2621f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
2631f5207b7SJohn Levon }
2641f5207b7SJohn Levon 
__set_sm(struct sm_state * sm)2651f5207b7SJohn Levon void __set_sm(struct sm_state *sm)
2661f5207b7SJohn Levon {
2671f5207b7SJohn Levon 	if (read_only)
2681f5207b7SJohn Levon 		sm_perror("cur_stree is read only.");
2691f5207b7SJohn Levon 
2701f5207b7SJohn Levon 	if (option_debug ||
2711f5207b7SJohn Levon 	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
2721f5207b7SJohn Levon 		struct smatch_state *s;
2731f5207b7SJohn Levon 
274efe51d0cSJohn Levon 		s = __get_state(sm->owner, sm->name, sm->sym);
2751f5207b7SJohn Levon 		if (!s)
2761f5207b7SJohn Levon 			sm_msg("%s new %s", __func__, show_sm(sm));
2771f5207b7SJohn Levon 		else
2781f5207b7SJohn Levon 			sm_msg("%s change %s (was %s)",	__func__, show_sm(sm),
2791f5207b7SJohn Levon 			       show_state(s));
2801f5207b7SJohn Levon 	}
2811f5207b7SJohn Levon 
2821f5207b7SJohn Levon 	if (unreachable())
2831f5207b7SJohn Levon 		return;
2841f5207b7SJohn Levon 
2851f5207b7SJohn Levon 	if (fake_cur_stree_stack)
2861f5207b7SJohn Levon 		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
2871f5207b7SJohn Levon 
2881f5207b7SJohn Levon 	overwrite_sm_state_stree(&cur_stree, sm);
2891f5207b7SJohn Levon }
2901f5207b7SJohn Levon 
__set_sm_cur_stree(struct sm_state * sm)2911f5207b7SJohn Levon void __set_sm_cur_stree(struct sm_state *sm)
2921f5207b7SJohn Levon {
2931f5207b7SJohn Levon 	if (read_only)
2941f5207b7SJohn Levon 		sm_perror("cur_stree is read only.");
2951f5207b7SJohn Levon 
2961f5207b7SJohn Levon 	if (option_debug ||
2971f5207b7SJohn Levon 	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
2981f5207b7SJohn Levon 		struct smatch_state *s;
2991f5207b7SJohn Levon 
300efe51d0cSJohn Levon 		s = __get_state(sm->owner, sm->name, sm->sym);
3011f5207b7SJohn Levon 		if (!s)
3021f5207b7SJohn Levon 			sm_msg("%s new %s", __func__, show_sm(sm));
3031f5207b7SJohn Levon 		else
3041f5207b7SJohn Levon 			sm_msg("%s change %s (was %s)",
3051f5207b7SJohn Levon 				__func__, show_sm(sm), show_state(s));
3061f5207b7SJohn Levon 	}
3071f5207b7SJohn Levon 
3081f5207b7SJohn Levon 	if (unreachable())
3091f5207b7SJohn Levon 		return;
3101f5207b7SJohn Levon 
3111f5207b7SJohn Levon 	overwrite_sm_state_stree(&cur_stree, sm);
3121f5207b7SJohn Levon }
3131f5207b7SJohn Levon 
__set_sm_fake_stree(struct sm_state * sm)3141f5207b7SJohn Levon void __set_sm_fake_stree(struct sm_state *sm)
3151f5207b7SJohn Levon {
3161f5207b7SJohn Levon 	if (read_only)
3171f5207b7SJohn Levon 		sm_perror("cur_stree is read only.");
3181f5207b7SJohn Levon 
3191f5207b7SJohn Levon 	if (option_debug ||
3201f5207b7SJohn Levon 	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
3211f5207b7SJohn Levon 		struct smatch_state *s;
3221f5207b7SJohn Levon 
323efe51d0cSJohn Levon 		s = __get_state(sm->owner, sm->name, sm->sym);
3241f5207b7SJohn Levon 		if (!s)
3251f5207b7SJohn Levon 			sm_msg("%s new %s", __func__, show_sm(sm));
3261f5207b7SJohn Levon 		else
3271f5207b7SJohn Levon 			sm_msg("%s change %s (was %s)",
3281f5207b7SJohn Levon 				__func__, show_sm(sm), show_state(s));
3291f5207b7SJohn Levon 	}
3301f5207b7SJohn Levon 
3311f5207b7SJohn Levon 	if (unreachable())
3321f5207b7SJohn Levon 		return;
3331f5207b7SJohn Levon 
3341f5207b7SJohn Levon 	overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
3351f5207b7SJohn Levon }
3361f5207b7SJohn Levon 
3371f5207b7SJohn Levon 
3381f5207b7SJohn Levon typedef void (get_state_hook)(int owner, const char *name, struct symbol *sym);
3391f5207b7SJohn Levon DECLARE_PTR_LIST(fn_list, get_state_hook *);
3401f5207b7SJohn Levon static struct fn_list *get_state_hooks;
3411f5207b7SJohn Levon 
add_get_state_hook(get_state_hook * fn)3421f5207b7SJohn Levon void add_get_state_hook(get_state_hook *fn)
3431f5207b7SJohn Levon {
3441f5207b7SJohn Levon 	get_state_hook **p = malloc(sizeof(get_state_hook *));
3451f5207b7SJohn Levon 	*p = fn;
3461f5207b7SJohn Levon 	add_ptr_list(&get_state_hooks, p);
3471f5207b7SJohn Levon }
3481f5207b7SJohn Levon 
call_get_state_hooks(int owner,const char * name,struct symbol * sym)3491f5207b7SJohn Levon static void call_get_state_hooks(int owner, const char *name, struct symbol *sym)
3501f5207b7SJohn Levon {
3511f5207b7SJohn Levon 	static int recursion;
3521f5207b7SJohn Levon 	get_state_hook **fn;
3531f5207b7SJohn Levon 
3541f5207b7SJohn Levon 	if (recursion)
3551f5207b7SJohn Levon 		return;
3561f5207b7SJohn Levon 	recursion = 1;
3571f5207b7SJohn Levon 
3581f5207b7SJohn Levon 	FOR_EACH_PTR(get_state_hooks, fn) {
3591f5207b7SJohn Levon 		(*fn)(owner, name, sym);
3601f5207b7SJohn Levon 	} END_FOR_EACH_PTR(fn);
3611f5207b7SJohn Levon 
3621f5207b7SJohn Levon 	recursion = 0;
3631f5207b7SJohn Levon }
3641f5207b7SJohn Levon 
__get_state(int owner,const char * name,struct symbol * sym)3651f5207b7SJohn Levon struct smatch_state *__get_state(int owner, const char *name, struct symbol *sym)
3661f5207b7SJohn Levon {
367c85f09ccSJohn Levon 	struct sm_state *sm;
368c85f09ccSJohn Levon 
369c85f09ccSJohn Levon 	sm = get_sm_state(owner, name, sym);
370c85f09ccSJohn Levon 	if (!sm)
371c85f09ccSJohn Levon 		return NULL;
372c85f09ccSJohn Levon 	return sm->state;
3731f5207b7SJohn Levon }
3741f5207b7SJohn Levon 
get_state(int owner,const char * name,struct symbol * sym)3751f5207b7SJohn Levon struct smatch_state *get_state(int owner, const char *name, struct symbol *sym)
3761f5207b7SJohn Levon {
3771f5207b7SJohn Levon 	call_get_state_hooks(owner, name, sym);
3781f5207b7SJohn Levon 
3791f5207b7SJohn Levon 	return __get_state(owner, name, sym);
3801f5207b7SJohn Levon }
3811f5207b7SJohn Levon 
get_state_expr(int owner,struct expression * expr)3821f5207b7SJohn Levon struct smatch_state *get_state_expr(int owner, struct expression *expr)
3831f5207b7SJohn Levon {
3841f5207b7SJohn Levon 	char *name;
3851f5207b7SJohn Levon 	struct symbol *sym;
3861f5207b7SJohn Levon 	struct smatch_state *ret = NULL;
3871f5207b7SJohn Levon 
3881f5207b7SJohn Levon 	expr = strip_expr(expr);
3891f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
3901f5207b7SJohn Levon 	if (!name || !sym)
3911f5207b7SJohn Levon 		goto free;
3921f5207b7SJohn Levon 	ret = get_state(owner, name, sym);
3931f5207b7SJohn Levon free:
3941f5207b7SJohn Levon 	free_string(name);
3951f5207b7SJohn Levon 	return ret;
3961f5207b7SJohn Levon }
3971f5207b7SJohn Levon 
get_possible_states(int owner,const char * name,struct symbol * sym)3981f5207b7SJohn Levon struct state_list *get_possible_states(int owner, const char *name, struct symbol *sym)
3991f5207b7SJohn Levon {
4001f5207b7SJohn Levon 	struct sm_state *sms;
4011f5207b7SJohn Levon 
4021f5207b7SJohn Levon 	sms = get_sm_state_stree(cur_stree, owner, name, sym);
4031f5207b7SJohn Levon 	if (sms)
4041f5207b7SJohn Levon 		return sms->possible;
4051f5207b7SJohn Levon 	return NULL;
4061f5207b7SJohn Levon }
4071f5207b7SJohn Levon 
get_possible_states_expr(int owner,struct expression * expr)4081f5207b7SJohn Levon struct state_list *get_possible_states_expr(int owner, struct expression *expr)
4091f5207b7SJohn Levon {
4101f5207b7SJohn Levon 	char *name;
4111f5207b7SJohn Levon 	struct symbol *sym;
4121f5207b7SJohn Levon 	struct state_list *ret = NULL;
4131f5207b7SJohn Levon 
4141f5207b7SJohn Levon 	expr = strip_expr(expr);
4151f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
4161f5207b7SJohn Levon 	if (!name || !sym)
4171f5207b7SJohn Levon 		goto free;
4181f5207b7SJohn Levon 	ret = get_possible_states(owner, name, sym);
4191f5207b7SJohn Levon free:
4201f5207b7SJohn Levon 	free_string(name);
4211f5207b7SJohn Levon 	return ret;
4221f5207b7SJohn Levon }
4231f5207b7SJohn Levon 
get_sm_state(int owner,const char * name,struct symbol * sym)4241f5207b7SJohn Levon struct sm_state *get_sm_state(int owner, const char *name, struct symbol *sym)
4251f5207b7SJohn Levon {
426c85f09ccSJohn Levon 	struct sm_state *ret;
427c85f09ccSJohn Levon 
428c85f09ccSJohn Levon 	ret = get_sm_state_stree(fast_overlay, owner, name, sym);
429c85f09ccSJohn Levon 	if (ret)
430c85f09ccSJohn Levon 		return ret;
431c85f09ccSJohn Levon 
4321f5207b7SJohn Levon 	return get_sm_state_stree(cur_stree, owner, name, sym);
4331f5207b7SJohn Levon }
4341f5207b7SJohn Levon 
get_sm_state_expr(int owner,struct expression * expr)4351f5207b7SJohn Levon struct sm_state *get_sm_state_expr(int owner, struct expression *expr)
4361f5207b7SJohn Levon {
4371f5207b7SJohn Levon 	char *name;
4381f5207b7SJohn Levon 	struct symbol *sym;
4391f5207b7SJohn Levon 	struct sm_state *ret = NULL;
4401f5207b7SJohn Levon 
4411f5207b7SJohn Levon 	expr = strip_expr(expr);
4421f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
4431f5207b7SJohn Levon 	if (!name || !sym)
4441f5207b7SJohn Levon 		goto free;
4451f5207b7SJohn Levon 	ret = get_sm_state(owner, name, sym);
4461f5207b7SJohn Levon free:
4471f5207b7SJohn Levon 	free_string(name);
4481f5207b7SJohn Levon 	return ret;
4491f5207b7SJohn Levon }
4501f5207b7SJohn Levon 
delete_state(int owner,const char * name,struct symbol * sym)4511f5207b7SJohn Levon void delete_state(int owner, const char *name, struct symbol *sym)
4521f5207b7SJohn Levon {
4531f5207b7SJohn Levon 	delete_state_stree(&cur_stree, owner, name, sym);
4541f5207b7SJohn Levon 	if (cond_true_stack) {
4551f5207b7SJohn Levon 		delete_state_stree_stack(&pre_cond_stack, owner, name, sym);
4561f5207b7SJohn Levon 		delete_state_stree_stack(&cond_true_stack, owner, name, sym);
4571f5207b7SJohn Levon 		delete_state_stree_stack(&cond_false_stack, owner, name, sym);
4581f5207b7SJohn Levon 	}
4591f5207b7SJohn Levon }
4601f5207b7SJohn Levon 
delete_state_expr(int owner,struct expression * expr)4611f5207b7SJohn Levon void delete_state_expr(int owner, struct expression *expr)
4621f5207b7SJohn Levon {
4631f5207b7SJohn Levon 	char *name;
4641f5207b7SJohn Levon 	struct symbol *sym;
4651f5207b7SJohn Levon 
4661f5207b7SJohn Levon 	expr = strip_expr(expr);
4671f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
4681f5207b7SJohn Levon 	if (!name || !sym)
4691f5207b7SJohn Levon 		goto free;
4701f5207b7SJohn Levon 	delete_state(owner, name, sym);
4711f5207b7SJohn Levon free:
4721f5207b7SJohn Levon 	free_string(name);
4731f5207b7SJohn Levon }
4741f5207b7SJohn Levon 
delete_all_states_stree_sym(struct stree ** stree,struct symbol * sym)4751f5207b7SJohn Levon static void delete_all_states_stree_sym(struct stree **stree, struct symbol *sym)
4761f5207b7SJohn Levon {
4771f5207b7SJohn Levon 	struct state_list *slist = NULL;
4781f5207b7SJohn Levon 	struct sm_state *sm;
4791f5207b7SJohn Levon 
4801f5207b7SJohn Levon 	FOR_EACH_SM(*stree, sm) {
4811f5207b7SJohn Levon 		if (sm->sym == sym)
4821f5207b7SJohn Levon 			add_ptr_list(&slist, sm);
4831f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
4841f5207b7SJohn Levon 
4851f5207b7SJohn Levon 	FOR_EACH_PTR(slist, sm) {
4861f5207b7SJohn Levon 		delete_state_stree(stree, sm->owner, sm->name, sm->sym);
4871f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sm);
4881f5207b7SJohn Levon 
4891f5207b7SJohn Levon 	free_slist(&slist);
4901f5207b7SJohn Levon }
4911f5207b7SJohn Levon 
delete_all_states_stree_stack_sym(struct stree_stack ** stack,struct symbol * sym)4921f5207b7SJohn Levon static void delete_all_states_stree_stack_sym(struct stree_stack **stack, struct symbol *sym)
4931f5207b7SJohn Levon {
4941f5207b7SJohn Levon 	struct stree *stree;
4951f5207b7SJohn Levon 
4961f5207b7SJohn Levon 	if (!*stack)
4971f5207b7SJohn Levon 		return;
4981f5207b7SJohn Levon 
4991f5207b7SJohn Levon 	stree = pop_stree(stack);
5001f5207b7SJohn Levon 	delete_all_states_stree_sym(&stree, sym);
5011f5207b7SJohn Levon 	push_stree(stack, stree);
5021f5207b7SJohn Levon }
5031f5207b7SJohn Levon 
__delete_all_states_sym(struct symbol * sym)5041f5207b7SJohn Levon void __delete_all_states_sym(struct symbol *sym)
5051f5207b7SJohn Levon {
5061f5207b7SJohn Levon 	delete_all_states_stree_sym(&cur_stree, sym);
5071f5207b7SJohn Levon 
5081f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&true_stack, sym);
5091f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&true_stack, sym);
5101f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&false_stack, sym);
5111f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&pre_cond_stack, sym);
5121f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&cond_true_stack, sym);
5131f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&cond_false_stack, sym);
5141f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&fake_cur_stree_stack, sym);
5151f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&break_stack, sym);
5161f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&fake_break_stack, sym);
5171f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&switch_stack, sym);
5181f5207b7SJohn Levon 	delete_all_states_stree_stack_sym(&continue_stack, sym);
5191f5207b7SJohn Levon 
5201f5207b7SJohn Levon 	/*
5211f5207b7SJohn Levon 	 * deleting from the goto stack is problematic because we don't know
5221f5207b7SJohn Levon 	 * if the label is in scope and also we need the value for --two-passes.
5231f5207b7SJohn Levon 	 */
5241f5207b7SJohn Levon }
5251f5207b7SJohn Levon 
get_all_states_from_stree(int owner,struct stree * source)5261f5207b7SJohn Levon struct stree *get_all_states_from_stree(int owner, struct stree *source)
5271f5207b7SJohn Levon {
5281f5207b7SJohn Levon 	struct stree *ret = NULL;
5291f5207b7SJohn Levon 	struct sm_state *tmp;
5301f5207b7SJohn Levon 
5311f5207b7SJohn Levon 	FOR_EACH_SM(source, tmp) {
5321f5207b7SJohn Levon 		if (tmp->owner == owner)
5331f5207b7SJohn Levon 			avl_insert(&ret, tmp);
5341f5207b7SJohn Levon 	} END_FOR_EACH_SM(tmp);
5351f5207b7SJohn Levon 
5361f5207b7SJohn Levon 	return ret;
5371f5207b7SJohn Levon }
5381f5207b7SJohn Levon 
get_all_states_stree(int owner)5391f5207b7SJohn Levon struct stree *get_all_states_stree(int owner)
5401f5207b7SJohn Levon {
5411f5207b7SJohn Levon 	return get_all_states_from_stree(owner, cur_stree);
5421f5207b7SJohn Levon }
5431f5207b7SJohn Levon 
__get_cur_stree(void)5441f5207b7SJohn Levon struct stree *__get_cur_stree(void)
5451f5207b7SJohn Levon {
5461f5207b7SJohn Levon 	return cur_stree;
5471f5207b7SJohn Levon }
5481f5207b7SJohn Levon 
is_reachable(void)5491f5207b7SJohn Levon int is_reachable(void)
5501f5207b7SJohn Levon {
5511f5207b7SJohn Levon 	if (cur_stree)
5521f5207b7SJohn Levon 		return 1;
5531f5207b7SJohn Levon 	return 0;
5541f5207b7SJohn Levon }
5551f5207b7SJohn Levon 
set_true_false_states(int owner,const char * name,struct symbol * sym,struct smatch_state * true_state,struct smatch_state * false_state)5561f5207b7SJohn Levon void set_true_false_states(int owner, const char *name, struct symbol *sym,
5571f5207b7SJohn Levon 			   struct smatch_state *true_state,
5581f5207b7SJohn Levon 			   struct smatch_state *false_state)
5591f5207b7SJohn Levon {
5601f5207b7SJohn Levon 	if (read_only)
5611f5207b7SJohn Levon 		sm_perror("cur_stree is read only.");
5621f5207b7SJohn Levon 
5631f5207b7SJohn Levon 	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
5641f5207b7SJohn Levon 		struct smatch_state *tmp;
5651f5207b7SJohn Levon 
566efe51d0cSJohn Levon 		tmp = __get_state(owner, name, sym);
5671f5207b7SJohn Levon 		sm_msg("%s [%s] '%s'.  Was %s.  Now T:%s F:%s", __func__,
5681f5207b7SJohn Levon 		       check_name(owner),  name, show_state(tmp),
5691f5207b7SJohn Levon 		       show_state(true_state), show_state(false_state));
5701f5207b7SJohn Levon 	}
5711f5207b7SJohn Levon 
5721f5207b7SJohn Levon 	if (unreachable())
5731f5207b7SJohn Levon 		return;
5741f5207b7SJohn Levon 
5751f5207b7SJohn Levon 	if (!cond_false_stack || !cond_true_stack) {
5761f5207b7SJohn Levon 		sm_perror("missing true/false stacks");
5771f5207b7SJohn Levon 		return;
5781f5207b7SJohn Levon 	}
5791f5207b7SJohn Levon 
5801f5207b7SJohn Levon 	if (true_state)
5811f5207b7SJohn Levon 		set_state_stree_stack(&cond_true_stack, owner, name, sym, true_state);
5821f5207b7SJohn Levon 	if (false_state)
5831f5207b7SJohn Levon 		set_state_stree_stack(&cond_false_stack, owner, name, sym, false_state);
5841f5207b7SJohn Levon }
5851f5207b7SJohn Levon 
set_true_false_states_expr(int owner,struct expression * expr,struct smatch_state * true_state,struct smatch_state * false_state)5861f5207b7SJohn Levon void set_true_false_states_expr(int owner, struct expression *expr,
5871f5207b7SJohn Levon 			   struct smatch_state *true_state,
5881f5207b7SJohn Levon 			   struct smatch_state *false_state)
5891f5207b7SJohn Levon {
5901f5207b7SJohn Levon 	char *name;
5911f5207b7SJohn Levon 	struct symbol *sym;
5921f5207b7SJohn Levon 
5931f5207b7SJohn Levon 	expr = strip_expr(expr);
5941f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
5951f5207b7SJohn Levon 	if (!name || !sym)
5961f5207b7SJohn Levon 		goto free;
5971f5207b7SJohn Levon 	set_true_false_states(owner, name, sym, true_state, false_state);
5981f5207b7SJohn Levon free:
5991f5207b7SJohn Levon 	free_string(name);
6001f5207b7SJohn Levon }
6011f5207b7SJohn Levon 
__set_true_false_sm(struct sm_state * true_sm,struct sm_state * false_sm)6021f5207b7SJohn Levon void __set_true_false_sm(struct sm_state *true_sm, struct sm_state *false_sm)
6031f5207b7SJohn Levon {
6041f5207b7SJohn Levon 	int owner;
6051f5207b7SJohn Levon 	const char *name;
6061f5207b7SJohn Levon 	struct symbol *sym;
6071f5207b7SJohn Levon 
6081f5207b7SJohn Levon 	if (!true_sm && !false_sm)
6091f5207b7SJohn Levon 		return;
6101f5207b7SJohn Levon 
6111f5207b7SJohn Levon 	if (unreachable())
6121f5207b7SJohn Levon 		return;
6131f5207b7SJohn Levon 
6141f5207b7SJohn Levon 	owner = true_sm ? true_sm->owner : false_sm->owner;
6151f5207b7SJohn Levon 	name = true_sm ? true_sm->name : false_sm->name;
6161f5207b7SJohn Levon 	sym = true_sm ? true_sm->sym : false_sm->sym;
6171f5207b7SJohn Levon 	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
6181f5207b7SJohn Levon 		struct smatch_state *tmp;
6191f5207b7SJohn Levon 
620efe51d0cSJohn Levon 		tmp = __get_state(owner, name, sym);
6211f5207b7SJohn Levon 		sm_msg("%s [%s] '%s'.  Was %s.  Now T:%s F:%s", __func__,
6221f5207b7SJohn Levon 		       check_name(owner),  name, show_state(tmp),
6231f5207b7SJohn Levon 		       show_state(true_sm ? true_sm->state : NULL),
6241f5207b7SJohn Levon 		       show_state(false_sm ? false_sm->state : NULL));
6251f5207b7SJohn Levon 	}
6261f5207b7SJohn Levon 
6271f5207b7SJohn Levon 	if (!cond_false_stack || !cond_true_stack) {
6281f5207b7SJohn Levon 		sm_perror("missing true/false stacks");
6291f5207b7SJohn Levon 		return;
6301f5207b7SJohn Levon 	}
6311f5207b7SJohn Levon 
6321f5207b7SJohn Levon 	if (true_sm)
6331f5207b7SJohn Levon 		overwrite_sm_state_stree_stack(&cond_true_stack, true_sm);
6341f5207b7SJohn Levon 	if (false_sm)
6351f5207b7SJohn Levon 		overwrite_sm_state_stree_stack(&cond_false_stack, false_sm);
6361f5207b7SJohn Levon }
6371f5207b7SJohn Levon 
nullify_path(void)6381f5207b7SJohn Levon void nullify_path(void)
6391f5207b7SJohn Levon {
6401f5207b7SJohn Levon 	if (fake_cur_stree_stack) {
6411f5207b7SJohn Levon 		__free_fake_cur_stree();
6421f5207b7SJohn Levon 		__push_fake_cur_stree();
6431f5207b7SJohn Levon 	}
6441f5207b7SJohn Levon 	free_stree(&cur_stree);
6451f5207b7SJohn Levon }
6461f5207b7SJohn Levon 
__match_nullify_path_hook(const char * fn,struct expression * expr,void * unused)6471f5207b7SJohn Levon void __match_nullify_path_hook(const char *fn, struct expression *expr,
6481f5207b7SJohn Levon 			       void *unused)
6491f5207b7SJohn Levon {
6501f5207b7SJohn Levon 	nullify_path();
6511f5207b7SJohn Levon }
6521f5207b7SJohn Levon 
6531f5207b7SJohn Levon /*
6541f5207b7SJohn Levon  * At the start of every function we mark the path
6551f5207b7SJohn Levon  * as unnull.  That way there is always at least one state
6561f5207b7SJohn Levon  * in the cur_stree until nullify_path is called.  This
6571f5207b7SJohn Levon  * is used in merge_slist() for the first null check.
6581f5207b7SJohn Levon  */
__unnullify_path(void)6591f5207b7SJohn Levon void __unnullify_path(void)
6601f5207b7SJohn Levon {
6611f5207b7SJohn Levon 	if (!cur_stree)
6621f5207b7SJohn Levon 		set_state(-1, "unnull_path", NULL, &true_state);
6631f5207b7SJohn Levon }
6641f5207b7SJohn Levon 
__path_is_null(void)6651f5207b7SJohn Levon int __path_is_null(void)
6661f5207b7SJohn Levon {
6671f5207b7SJohn Levon 	if (cur_stree)
6681f5207b7SJohn Levon 		return 0;
6691f5207b7SJohn Levon 	return 1;
6701f5207b7SJohn Levon }
6711f5207b7SJohn Levon 
check_stree_stack_free(struct stree_stack ** stack)6721f5207b7SJohn Levon static void check_stree_stack_free(struct stree_stack **stack)
6731f5207b7SJohn Levon {
6741f5207b7SJohn Levon 	if (*stack) {
6751f5207b7SJohn Levon 		sm_perror("stack not empty");
6761f5207b7SJohn Levon 		free_stack_and_strees(stack);
6771f5207b7SJohn Levon 	}
6781f5207b7SJohn Levon }
6791f5207b7SJohn Levon 
save_all_states(void)6801f5207b7SJohn Levon void save_all_states(void)
6811f5207b7SJohn Levon {
682c85f09ccSJohn Levon 	__add_ptr_list(&backup, cur_stree);
6831f5207b7SJohn Levon 	cur_stree = NULL;
6841f5207b7SJohn Levon 
685c85f09ccSJohn Levon 	__add_ptr_list(&backup, true_stack);
6861f5207b7SJohn Levon 	true_stack = NULL;
687c85f09ccSJohn Levon 	__add_ptr_list(&backup, false_stack);
6881f5207b7SJohn Levon 	false_stack = NULL;
689c85f09ccSJohn Levon 	__add_ptr_list(&backup, pre_cond_stack);
6901f5207b7SJohn Levon 	pre_cond_stack = NULL;
6911f5207b7SJohn Levon 
692c85f09ccSJohn Levon 	__add_ptr_list(&backup, cond_true_stack);
6931f5207b7SJohn Levon 	cond_true_stack = NULL;
694c85f09ccSJohn Levon 	__add_ptr_list(&backup, cond_false_stack);
6951f5207b7SJohn Levon 	cond_false_stack = NULL;
6961f5207b7SJohn Levon 
697c85f09ccSJohn Levon 	__add_ptr_list(&backup, fake_cur_stree_stack);
6981f5207b7SJohn Levon 	fake_cur_stree_stack = NULL;
6991f5207b7SJohn Levon 
700c85f09ccSJohn Levon 	__add_ptr_list(&backup, break_stack);
7011f5207b7SJohn Levon 	break_stack = NULL;
702c85f09ccSJohn Levon 	__add_ptr_list(&backup, fake_break_stack);
7031f5207b7SJohn Levon 	fake_break_stack = NULL;
7041f5207b7SJohn Levon 
705c85f09ccSJohn Levon 	__add_ptr_list(&backup, switch_stack);
7061f5207b7SJohn Levon 	switch_stack = NULL;
707c85f09ccSJohn Levon 	__add_ptr_list(&backup, remaining_cases);
7081f5207b7SJohn Levon 	remaining_cases = NULL;
709c85f09ccSJohn Levon 	__add_ptr_list(&backup, default_stack);
7101f5207b7SJohn Levon 	default_stack = NULL;
711c85f09ccSJohn Levon 	__add_ptr_list(&backup, continue_stack);
7121f5207b7SJohn Levon 	continue_stack = NULL;
7131f5207b7SJohn Levon 
714c85f09ccSJohn Levon 	__add_ptr_list(&backup, goto_stack);
7151f5207b7SJohn Levon 	goto_stack = NULL;
7161f5207b7SJohn Levon }
7171f5207b7SJohn Levon 
pop_backup(void)7181f5207b7SJohn Levon static void *pop_backup(void)
7191f5207b7SJohn Levon {
7201f5207b7SJohn Levon 	void *ret;
7211f5207b7SJohn Levon 
7221f5207b7SJohn Levon 	ret = last_ptr_list(backup);
7231f5207b7SJohn Levon 	delete_ptr_list_last(&backup);
7241f5207b7SJohn Levon 	return ret;
7251f5207b7SJohn Levon }
7261f5207b7SJohn Levon 
restore_all_states(void)7271f5207b7SJohn Levon void restore_all_states(void)
7281f5207b7SJohn Levon {
7291f5207b7SJohn Levon 	goto_stack = pop_backup();
7301f5207b7SJohn Levon 
7311f5207b7SJohn Levon 	continue_stack = pop_backup();
7321f5207b7SJohn Levon 	default_stack = pop_backup();
7331f5207b7SJohn Levon 	remaining_cases = pop_backup();
7341f5207b7SJohn Levon 	switch_stack = pop_backup();
7351f5207b7SJohn Levon 	fake_break_stack = pop_backup();
7361f5207b7SJohn Levon 	break_stack = pop_backup();
7371f5207b7SJohn Levon 
7381f5207b7SJohn Levon 	fake_cur_stree_stack = pop_backup();
7391f5207b7SJohn Levon 
7401f5207b7SJohn Levon 	cond_false_stack = pop_backup();
7411f5207b7SJohn Levon 	cond_true_stack = pop_backup();
7421f5207b7SJohn Levon 
7431f5207b7SJohn Levon 	pre_cond_stack = pop_backup();
7441f5207b7SJohn Levon 	false_stack = pop_backup();
7451f5207b7SJohn Levon 	true_stack = pop_backup();
7461f5207b7SJohn Levon 
7471f5207b7SJohn Levon 	cur_stree = pop_backup();
7481f5207b7SJohn Levon }
7491f5207b7SJohn Levon 
free_goto_stack(void)7501f5207b7SJohn Levon void free_goto_stack(void)
7511f5207b7SJohn Levon {
7521f5207b7SJohn Levon 	struct named_stree *named_stree;
7531f5207b7SJohn Levon 
7541f5207b7SJohn Levon 	FOR_EACH_PTR(goto_stack, named_stree) {
7551f5207b7SJohn Levon 		free_stree(&named_stree->stree);
7561f5207b7SJohn Levon 	} END_FOR_EACH_PTR(named_stree);
7571f5207b7SJohn Levon 	__free_ptr_list((struct ptr_list **)&goto_stack);
7581f5207b7SJohn Levon }
7591f5207b7SJohn Levon 
clear_all_states(void)7601f5207b7SJohn Levon void clear_all_states(void)
7611f5207b7SJohn Levon {
7621f5207b7SJohn Levon 	nullify_path();
7631f5207b7SJohn Levon 	check_stree_stack_free(&true_stack);
7641f5207b7SJohn Levon 	check_stree_stack_free(&false_stack);
7651f5207b7SJohn Levon 	check_stree_stack_free(&pre_cond_stack);
7661f5207b7SJohn Levon 	check_stree_stack_free(&cond_true_stack);
7671f5207b7SJohn Levon 	check_stree_stack_free(&cond_false_stack);
7681f5207b7SJohn Levon 	check_stree_stack_free(&break_stack);
7691f5207b7SJohn Levon 	check_stree_stack_free(&fake_break_stack);
7701f5207b7SJohn Levon 	check_stree_stack_free(&switch_stack);
7711f5207b7SJohn Levon 	check_stree_stack_free(&continue_stack);
7721f5207b7SJohn Levon 	check_stree_stack_free(&fake_cur_stree_stack);
7731f5207b7SJohn Levon 
7741f5207b7SJohn Levon 	free_goto_stack();
7751f5207b7SJohn Levon 
7761f5207b7SJohn Levon 	free_every_single_sm_state();
7771f5207b7SJohn Levon 	free_tmp_expressions();
7781f5207b7SJohn Levon }
7791f5207b7SJohn Levon 
__push_cond_stacks(void)7801f5207b7SJohn Levon void __push_cond_stacks(void)
7811f5207b7SJohn Levon {
7821f5207b7SJohn Levon 	push_stree(&cond_true_stack, NULL);
7831f5207b7SJohn Levon 	push_stree(&cond_false_stack, NULL);
7841f5207b7SJohn Levon 	__push_fake_cur_stree();
7851f5207b7SJohn Levon }
7861f5207b7SJohn Levon 
__fold_in_set_states(void)7871f5207b7SJohn Levon void __fold_in_set_states(void)
7881f5207b7SJohn Levon {
7891f5207b7SJohn Levon 	struct stree *new_states;
7901f5207b7SJohn Levon 	struct sm_state *sm;
7911f5207b7SJohn Levon 
7921f5207b7SJohn Levon 	new_states = __pop_fake_cur_stree();
7931f5207b7SJohn Levon 	FOR_EACH_SM(new_states, sm) {
7941f5207b7SJohn Levon 		__set_sm(sm);
7951f5207b7SJohn Levon 		__set_true_false_sm(sm, sm);
7961f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
7971f5207b7SJohn Levon 	free_stree(&new_states);
7981f5207b7SJohn Levon }
7991f5207b7SJohn Levon 
__free_set_states(void)8001f5207b7SJohn Levon void __free_set_states(void)
8011f5207b7SJohn Levon {
8021f5207b7SJohn Levon 	struct stree *new_states;
8031f5207b7SJohn Levon 
8041f5207b7SJohn Levon 	new_states = __pop_fake_cur_stree();
8051f5207b7SJohn Levon 	free_stree(&new_states);
8061f5207b7SJohn Levon }
8071f5207b7SJohn Levon 
__copy_cond_true_states(void)8081f5207b7SJohn Levon struct stree *__copy_cond_true_states(void)
8091f5207b7SJohn Levon {
8101f5207b7SJohn Levon 	struct stree *ret;
8111f5207b7SJohn Levon 
8121f5207b7SJohn Levon 	ret = pop_stree(&cond_true_stack);
8131f5207b7SJohn Levon 	push_stree(&cond_true_stack, clone_stree(ret));
8141f5207b7SJohn Levon 	return ret;
8151f5207b7SJohn Levon }
8161f5207b7SJohn Levon 
__copy_cond_false_states(void)8171f5207b7SJohn Levon struct stree *__copy_cond_false_states(void)
8181f5207b7SJohn Levon {
8191f5207b7SJohn Levon 	struct stree *ret;
8201f5207b7SJohn Levon 
8211f5207b7SJohn Levon 	ret = pop_stree(&cond_false_stack);
8221f5207b7SJohn Levon 	push_stree(&cond_false_stack, clone_stree(ret));
8231f5207b7SJohn Levon 	return ret;
8241f5207b7SJohn Levon }
8251f5207b7SJohn Levon 
__pop_cond_true_stack(void)8261f5207b7SJohn Levon struct stree *__pop_cond_true_stack(void)
8271f5207b7SJohn Levon {
8281f5207b7SJohn Levon 	return pop_stree(&cond_true_stack);
8291f5207b7SJohn Levon }
8301f5207b7SJohn Levon 
__pop_cond_false_stack(void)8311f5207b7SJohn Levon struct stree *__pop_cond_false_stack(void)
8321f5207b7SJohn Levon {
8331f5207b7SJohn Levon 	return pop_stree(&cond_false_stack);
8341f5207b7SJohn Levon }
8351f5207b7SJohn Levon 
8361f5207b7SJohn Levon /*
8371f5207b7SJohn Levon  * This combines the pre cond states with either the true or false states.
8381f5207b7SJohn Levon  * For example:
8391f5207b7SJohn Levon  * a = kmalloc() ; if (a !! foo(a)
8401f5207b7SJohn Levon  * In the pre state a is possibly null.  In the true state it is non null.
8411f5207b7SJohn Levon  * In the false state it is null.  Combine the pre and the false to get
8421f5207b7SJohn Levon  * that when we call 'foo', 'a' is null.
8431f5207b7SJohn Levon  */
__use_cond_stack(struct stree_stack ** stack)8441f5207b7SJohn Levon static void __use_cond_stack(struct stree_stack **stack)
8451f5207b7SJohn Levon {
8461f5207b7SJohn Levon 	struct stree *stree;
8471f5207b7SJohn Levon 
8481f5207b7SJohn Levon 	free_stree(&cur_stree);
8491f5207b7SJohn Levon 
8501f5207b7SJohn Levon 	cur_stree = pop_stree(&pre_cond_stack);
8511f5207b7SJohn Levon 	push_stree(&pre_cond_stack, clone_stree(cur_stree));
8521f5207b7SJohn Levon 
8531f5207b7SJohn Levon 	stree = pop_stree(stack);
8541f5207b7SJohn Levon 	overwrite_stree(stree, &cur_stree);
8551f5207b7SJohn Levon 	push_stree(stack, stree);
8561f5207b7SJohn Levon }
8571f5207b7SJohn Levon 
__use_pre_cond_states(void)8581f5207b7SJohn Levon void __use_pre_cond_states(void)
8591f5207b7SJohn Levon {
8601f5207b7SJohn Levon 	free_stree(&cur_stree);
8611f5207b7SJohn Levon 	cur_stree = pop_stree(&pre_cond_stack);
8621f5207b7SJohn Levon }
8631f5207b7SJohn Levon 
__use_cond_true_states(void)8641f5207b7SJohn Levon void __use_cond_true_states(void)
8651f5207b7SJohn Levon {
8661f5207b7SJohn Levon 	__use_cond_stack(&cond_true_stack);
8671f5207b7SJohn Levon }
8681f5207b7SJohn Levon 
__use_cond_false_states(void)8691f5207b7SJohn Levon void __use_cond_false_states(void)
8701f5207b7SJohn Levon {
8711f5207b7SJohn Levon 	__use_cond_stack(&cond_false_stack);
8721f5207b7SJohn Levon }
8731f5207b7SJohn Levon 
__negate_cond_stacks(void)8741f5207b7SJohn Levon void __negate_cond_stacks(void)
8751f5207b7SJohn Levon {
8761f5207b7SJohn Levon 	struct stree *old_false, *old_true;
8771f5207b7SJohn Levon 
8781f5207b7SJohn Levon 	old_false = pop_stree(&cond_false_stack);
8791f5207b7SJohn Levon 	old_true = pop_stree(&cond_true_stack);
8801f5207b7SJohn Levon 	push_stree(&cond_false_stack, old_true);
8811f5207b7SJohn Levon 	push_stree(&cond_true_stack, old_false);
8821f5207b7SJohn Levon }
8831f5207b7SJohn Levon 
__and_cond_states(void)8841f5207b7SJohn Levon void __and_cond_states(void)
8851f5207b7SJohn Levon {
8861f5207b7SJohn Levon 	and_stree_stack(&cond_true_stack);
8871f5207b7SJohn Levon 	or_stree_stack(&pre_cond_stack, cur_stree, &cond_false_stack);
8881f5207b7SJohn Levon }
8891f5207b7SJohn Levon 
__or_cond_states(void)8901f5207b7SJohn Levon void __or_cond_states(void)
8911f5207b7SJohn Levon {
8921f5207b7SJohn Levon 	or_stree_stack(&pre_cond_stack, cur_stree, &cond_true_stack);
8931f5207b7SJohn Levon 	and_stree_stack(&cond_false_stack);
8941f5207b7SJohn Levon }
8951f5207b7SJohn Levon 
__save_pre_cond_states(void)8961f5207b7SJohn Levon void __save_pre_cond_states(void)
8971f5207b7SJohn Levon {
8981f5207b7SJohn Levon 	push_stree(&pre_cond_stack, clone_stree(cur_stree));
8991f5207b7SJohn Levon }
9001f5207b7SJohn Levon 
__discard_pre_cond_states(void)9011f5207b7SJohn Levon void __discard_pre_cond_states(void)
9021f5207b7SJohn Levon {
9031f5207b7SJohn Levon 	struct stree *tmp;
9041f5207b7SJohn Levon 
9051f5207b7SJohn Levon 	tmp = pop_stree(&pre_cond_stack);
9061f5207b7SJohn Levon 	free_stree(&tmp);
9071f5207b7SJohn Levon }
9081f5207b7SJohn Levon 
__get_true_states(void)9091f5207b7SJohn Levon struct stree *__get_true_states(void)
9101f5207b7SJohn Levon {
9111f5207b7SJohn Levon 	return clone_stree(top_stree(cond_true_stack));
9121f5207b7SJohn Levon }
9131f5207b7SJohn Levon 
__get_false_states(void)9141f5207b7SJohn Levon struct stree *__get_false_states(void)
9151f5207b7SJohn Levon {
9161f5207b7SJohn Levon 	return clone_stree(top_stree(cond_false_stack));
9171f5207b7SJohn Levon }
9181f5207b7SJohn Levon 
__use_cond_states(void)9191f5207b7SJohn Levon void __use_cond_states(void)
9201f5207b7SJohn Levon {
9211f5207b7SJohn Levon 	struct stree *pre, *pre_clone, *true_states, *false_states;
9221f5207b7SJohn Levon 
9231f5207b7SJohn Levon 	pre = pop_stree(&pre_cond_stack);
9241f5207b7SJohn Levon 	pre_clone = clone_stree(pre);
9251f5207b7SJohn Levon 
9261f5207b7SJohn Levon 	true_states = pop_stree(&cond_true_stack);
9271f5207b7SJohn Levon 	overwrite_stree(true_states, &pre);
9281f5207b7SJohn Levon 	free_stree(&true_states);
9291f5207b7SJohn Levon 	/* we use the true states right away */
9301f5207b7SJohn Levon 	free_stree(&cur_stree);
9311f5207b7SJohn Levon 	cur_stree = pre;
9321f5207b7SJohn Levon 
9331f5207b7SJohn Levon 	false_states = pop_stree(&cond_false_stack);
9341f5207b7SJohn Levon 	overwrite_stree(false_states, &pre_clone);
9351f5207b7SJohn Levon 	free_stree(&false_states);
9361f5207b7SJohn Levon 	push_stree(&false_stack, pre_clone);
9371f5207b7SJohn Levon }
9381f5207b7SJohn Levon 
__push_true_states(void)9391f5207b7SJohn Levon void __push_true_states(void)
9401f5207b7SJohn Levon {
9411f5207b7SJohn Levon 	push_stree(&true_stack, clone_stree(cur_stree));
9421f5207b7SJohn Levon }
9431f5207b7SJohn Levon 
__use_false_states(void)9441f5207b7SJohn Levon void __use_false_states(void)
9451f5207b7SJohn Levon {
9461f5207b7SJohn Levon 	free_stree(&cur_stree);
9471f5207b7SJohn Levon 	cur_stree = pop_stree(&false_stack);
9481f5207b7SJohn Levon }
9491f5207b7SJohn Levon 
__discard_false_states(void)9501f5207b7SJohn Levon void __discard_false_states(void)
9511f5207b7SJohn Levon {
9521f5207b7SJohn Levon 	struct stree *stree;
9531f5207b7SJohn Levon 
9541f5207b7SJohn Levon 	stree = pop_stree(&false_stack);
9551f5207b7SJohn Levon 	free_stree(&stree);
9561f5207b7SJohn Levon }
9571f5207b7SJohn Levon 
__merge_false_states(void)9581f5207b7SJohn Levon void __merge_false_states(void)
9591f5207b7SJohn Levon {
9601f5207b7SJohn Levon 	struct stree *stree;
9611f5207b7SJohn Levon 
9621f5207b7SJohn Levon 	stree = pop_stree(&false_stack);
9631f5207b7SJohn Levon 	merge_stree(&cur_stree, stree);
9641f5207b7SJohn Levon 	free_stree(&stree);
9651f5207b7SJohn Levon }
9661f5207b7SJohn Levon 
9671f5207b7SJohn Levon /*
9681f5207b7SJohn Levon  * This function probably seemed common sensical when I wrote it but, oh wow,
9691f5207b7SJohn Levon  * does it look subtle in retrospect.  Say we set a state on one side of the if
9701f5207b7SJohn Levon  * else path but not on the other, then what we should record in the fake stree
9711f5207b7SJohn Levon  * is the merged state.
9721f5207b7SJohn Levon  *
9731f5207b7SJohn Levon  * This function relies on the fact that the we always set the cur_stree as well
9741f5207b7SJohn Levon  * and we already have the infrastructure to merge things correctly into the
9751f5207b7SJohn Levon  * cur_stree.
9761f5207b7SJohn Levon  *
9771f5207b7SJohn Levon  * So instead of merging fake strees together which is probably a lot of work,
9781f5207b7SJohn Levon  * we just use it as a list of set states and look up the actual current values
9791f5207b7SJohn Levon  * in the cur_stree.
9801f5207b7SJohn Levon  *
9811f5207b7SJohn Levon  */
update_stree_with_merged(struct stree ** stree)9821f5207b7SJohn Levon static void update_stree_with_merged(struct stree **stree)
9831f5207b7SJohn Levon {
9841f5207b7SJohn Levon 	struct state_list *slist = NULL;
9851f5207b7SJohn Levon 	struct sm_state *sm, *new;
9861f5207b7SJohn Levon 
9871f5207b7SJohn Levon 	FOR_EACH_SM(*stree, sm) {
9881f5207b7SJohn Levon 		new = get_sm_state(sm->owner, sm->name, sm->sym);
9891f5207b7SJohn Levon 		if (!new)  /* This can happen if we go out of scope */
9901f5207b7SJohn Levon 			continue;
9911f5207b7SJohn Levon 		add_ptr_list(&slist, new);
9921f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
9931f5207b7SJohn Levon 
9941f5207b7SJohn Levon 	FOR_EACH_PTR(slist, sm) {
9951f5207b7SJohn Levon 		overwrite_sm_state_stree(stree, sm);
9961f5207b7SJohn Levon 	} END_FOR_EACH_PTR(sm);
9971f5207b7SJohn Levon 
9981f5207b7SJohn Levon 	free_slist(&slist);
9991f5207b7SJohn Levon }
10001f5207b7SJohn Levon 
update_fake_stree_with_merged(void)10011f5207b7SJohn Levon static void update_fake_stree_with_merged(void)
10021f5207b7SJohn Levon {
10031f5207b7SJohn Levon 	struct stree *stree;
10041f5207b7SJohn Levon 
10051f5207b7SJohn Levon 	if (!fake_cur_stree_stack)
10061f5207b7SJohn Levon 		return;
10071f5207b7SJohn Levon 	stree = pop_stree(&fake_cur_stree_stack);
10081f5207b7SJohn Levon 	update_stree_with_merged(&stree);
10091f5207b7SJohn Levon 	push_stree(&fake_cur_stree_stack, stree);
10101f5207b7SJohn Levon }
10111f5207b7SJohn Levon 
__merge_true_states(void)10121f5207b7SJohn Levon void __merge_true_states(void)
10131f5207b7SJohn Levon {
10141f5207b7SJohn Levon 	struct stree *stree;
10151f5207b7SJohn Levon 
10161f5207b7SJohn Levon 	stree = pop_stree(&true_stack);
10171f5207b7SJohn Levon 	merge_stree(&cur_stree, stree);
10181f5207b7SJohn Levon 	update_fake_stree_with_merged();
10191f5207b7SJohn Levon 	free_stree(&stree);
10201f5207b7SJohn Levon }
10211f5207b7SJohn Levon 
__push_continues(void)10221f5207b7SJohn Levon void __push_continues(void)
10231f5207b7SJohn Levon {
10241f5207b7SJohn Levon 	push_stree(&continue_stack, NULL);
10251f5207b7SJohn Levon }
10261f5207b7SJohn Levon 
__discard_continues(void)10271f5207b7SJohn Levon void __discard_continues(void)
10281f5207b7SJohn Levon {
10291f5207b7SJohn Levon 	struct stree *stree;
10301f5207b7SJohn Levon 
10311f5207b7SJohn Levon 	stree = pop_stree(&continue_stack);
10321f5207b7SJohn Levon 	free_stree(&stree);
10331f5207b7SJohn Levon }
10341f5207b7SJohn Levon 
__process_continues(void)10351f5207b7SJohn Levon void __process_continues(void)
10361f5207b7SJohn Levon {
10371f5207b7SJohn Levon 	struct stree *stree;
10381f5207b7SJohn Levon 
10391f5207b7SJohn Levon 	stree = pop_stree(&continue_stack);
10401f5207b7SJohn Levon 	if (!stree)
10411f5207b7SJohn Levon 		stree = clone_stree(cur_stree);
10421f5207b7SJohn Levon 	else
10431f5207b7SJohn Levon 		merge_stree(&stree, cur_stree);
10441f5207b7SJohn Levon 
10451f5207b7SJohn Levon 	push_stree(&continue_stack, stree);
10461f5207b7SJohn Levon }
10471f5207b7SJohn Levon 
__merge_continues(void)10481f5207b7SJohn Levon void __merge_continues(void)
10491f5207b7SJohn Levon {
10501f5207b7SJohn Levon 	struct stree *stree;
10511f5207b7SJohn Levon 
10521f5207b7SJohn Levon 	stree = pop_stree(&continue_stack);
10531f5207b7SJohn Levon 	merge_stree(&cur_stree, stree);
10541f5207b7SJohn Levon 	free_stree(&stree);
10551f5207b7SJohn Levon }
10561f5207b7SJohn Levon 
__push_breaks(void)10571f5207b7SJohn Levon void __push_breaks(void)
10581f5207b7SJohn Levon {
10591f5207b7SJohn Levon 	push_stree(&break_stack, NULL);
10601f5207b7SJohn Levon 	if (fake_cur_stree_stack)
10611f5207b7SJohn Levon 		push_stree(&fake_break_stack, NULL);
10621f5207b7SJohn Levon }
10631f5207b7SJohn Levon 
__process_breaks(void)10641f5207b7SJohn Levon void __process_breaks(void)
10651f5207b7SJohn Levon {
10661f5207b7SJohn Levon 	struct stree *stree;
10671f5207b7SJohn Levon 
10681f5207b7SJohn Levon 	stree = pop_stree(&break_stack);
10691f5207b7SJohn Levon 	if (!stree)
10701f5207b7SJohn Levon 		stree = clone_stree(cur_stree);
10711f5207b7SJohn Levon 	else
10721f5207b7SJohn Levon 		merge_stree(&stree, cur_stree);
10731f5207b7SJohn Levon 	push_stree(&break_stack, stree);
10741f5207b7SJohn Levon 
10751f5207b7SJohn Levon 	if (!fake_cur_stree_stack)
10761f5207b7SJohn Levon 		return;
10771f5207b7SJohn Levon 
10781f5207b7SJohn Levon 	stree = pop_stree(&fake_break_stack);
10791f5207b7SJohn Levon 	if (!stree)
10801f5207b7SJohn Levon 		stree = clone_stree(top_stree(fake_cur_stree_stack));
10811f5207b7SJohn Levon 	else
10821f5207b7SJohn Levon 		merge_stree(&stree, top_stree(fake_cur_stree_stack));
10831f5207b7SJohn Levon 	push_stree(&fake_break_stack, stree);
10841f5207b7SJohn Levon }
10851f5207b7SJohn Levon 
__has_breaks(void)10861f5207b7SJohn Levon int __has_breaks(void)
10871f5207b7SJohn Levon {
10881f5207b7SJohn Levon 	struct stree *stree;
10891f5207b7SJohn Levon 	int ret;
10901f5207b7SJohn Levon 
10911f5207b7SJohn Levon 	stree = pop_stree(&break_stack);
10921f5207b7SJohn Levon 	ret = !!stree;
10931f5207b7SJohn Levon 	push_stree(&break_stack, stree);
10941f5207b7SJohn Levon 	return ret;
10951f5207b7SJohn Levon }
10961f5207b7SJohn Levon 
__merge_breaks(void)10971f5207b7SJohn Levon void __merge_breaks(void)
10981f5207b7SJohn Levon {
10991f5207b7SJohn Levon 	struct stree *stree;
11001f5207b7SJohn Levon 	struct sm_state *sm;
11011f5207b7SJohn Levon 
11021f5207b7SJohn Levon 	stree = pop_stree(&break_stack);
11031f5207b7SJohn Levon 	merge_stree(&cur_stree, stree);
11041f5207b7SJohn Levon 	free_stree(&stree);
11051f5207b7SJohn Levon 
11061f5207b7SJohn Levon 	if (!fake_cur_stree_stack)
11071f5207b7SJohn Levon 		return;
11081f5207b7SJohn Levon 
11091f5207b7SJohn Levon 	stree = pop_stree(&fake_break_stack);
11101f5207b7SJohn Levon 	update_stree_with_merged(&stree);
11111f5207b7SJohn Levon 	FOR_EACH_SM(stree, sm) {
11121f5207b7SJohn Levon 		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
11131f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
11141f5207b7SJohn Levon 	free_stree(&stree);
11151f5207b7SJohn Levon }
11161f5207b7SJohn Levon 
__use_breaks(void)11171f5207b7SJohn Levon void __use_breaks(void)
11181f5207b7SJohn Levon {
11191f5207b7SJohn Levon 	struct stree *stree;
11201f5207b7SJohn Levon 	struct sm_state *sm;
11211f5207b7SJohn Levon 
11221f5207b7SJohn Levon 	free_stree(&cur_stree);
11231f5207b7SJohn Levon 	cur_stree = pop_stree(&break_stack);
11241f5207b7SJohn Levon 
11251f5207b7SJohn Levon 	if (!fake_cur_stree_stack)
11261f5207b7SJohn Levon 		return;
11271f5207b7SJohn Levon 	stree = pop_stree(&fake_break_stack);
11281f5207b7SJohn Levon 	FOR_EACH_SM(stree, sm) {
11291f5207b7SJohn Levon 		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
11301f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
11311f5207b7SJohn Levon 	free_stree(&stree);
11321f5207b7SJohn Levon 
11331f5207b7SJohn Levon 
11341f5207b7SJohn Levon }
11351f5207b7SJohn Levon 
__save_switch_states(struct expression * switch_expr)11361f5207b7SJohn Levon void __save_switch_states(struct expression *switch_expr)
11371f5207b7SJohn Levon {
11381f5207b7SJohn Levon 	struct range_list *rl;
11391f5207b7SJohn Levon 
11401f5207b7SJohn Levon 	get_absolute_rl(switch_expr, &rl);
11411f5207b7SJohn Levon 
11421f5207b7SJohn Levon 	push_rl(&remaining_cases, rl);
11431f5207b7SJohn Levon 	push_stree(&switch_stack, clone_stree(cur_stree));
11441f5207b7SJohn Levon }
11451f5207b7SJohn Levon 
have_remaining_cases(void)11461f5207b7SJohn Levon int have_remaining_cases(void)
11471f5207b7SJohn Levon {
11481f5207b7SJohn Levon 	return !!top_rl(remaining_cases);
11491f5207b7SJohn Levon }
11501f5207b7SJohn Levon 
__merge_switches(struct expression * switch_expr,struct range_list * case_rl)11511f5207b7SJohn Levon void __merge_switches(struct expression *switch_expr, struct range_list *case_rl)
11521f5207b7SJohn Levon {
11531f5207b7SJohn Levon 	struct stree *stree;
11541f5207b7SJohn Levon 	struct stree *implied_stree;
11551f5207b7SJohn Levon 
11561f5207b7SJohn Levon 	stree = pop_stree(&switch_stack);
11575a0e240fSJohn Levon 	if (!stree) {
11585a0e240fSJohn Levon 		/*
11595a0e240fSJohn Levon 		 * If the cur_stree was NULL before the start of the switch
11605a0e240fSJohn Levon 		 * statement then we don't want to unnullify it.
11615a0e240fSJohn Levon 		 *
11625a0e240fSJohn Levon 		 */
11635a0e240fSJohn Levon 		push_stree(&switch_stack, stree);
11645a0e240fSJohn Levon 		return;
11655a0e240fSJohn Levon 	}
11661f5207b7SJohn Levon 	implied_stree = __implied_case_stree(switch_expr, case_rl, &remaining_cases, &stree);
11671f5207b7SJohn Levon 	merge_stree(&cur_stree, implied_stree);
11681f5207b7SJohn Levon 	free_stree(&implied_stree);
11691f5207b7SJohn Levon 	push_stree(&switch_stack, stree);
11701f5207b7SJohn Levon }
11711f5207b7SJohn Levon 
__discard_switches(void)11721f5207b7SJohn Levon void __discard_switches(void)
11731f5207b7SJohn Levon {
11741f5207b7SJohn Levon 	struct stree *stree;
11751f5207b7SJohn Levon 
11761f5207b7SJohn Levon 	pop_rl(&remaining_cases);
11771f5207b7SJohn Levon 	stree = pop_stree(&switch_stack);
11781f5207b7SJohn Levon 	free_stree(&stree);
11791f5207b7SJohn Levon }
11801f5207b7SJohn Levon 
__push_default(void)11811f5207b7SJohn Levon void __push_default(void)
11821f5207b7SJohn Levon {
11831f5207b7SJohn Levon 	push_stree(&default_stack, NULL);
11841f5207b7SJohn Levon }
11851f5207b7SJohn Levon 
__set_default(void)11861f5207b7SJohn Levon void __set_default(void)
11871f5207b7SJohn Levon {
11881f5207b7SJohn Levon 	set_state_stree_stack(&default_stack, 0, "has_default", NULL, &true_state);
11891f5207b7SJohn Levon }
11901f5207b7SJohn Levon 
__pop_default(void)11911f5207b7SJohn Levon int __pop_default(void)
11921f5207b7SJohn Levon {
11931f5207b7SJohn Levon 	struct stree *stree;
11941f5207b7SJohn Levon 
11951f5207b7SJohn Levon 	stree = pop_stree(&default_stack);
11961f5207b7SJohn Levon 	if (stree) {
11971f5207b7SJohn Levon 		free_stree(&stree);
11981f5207b7SJohn Levon 		return 1;
11991f5207b7SJohn Levon 	}
12001f5207b7SJohn Levon 	return 0;
12011f5207b7SJohn Levon }
12021f5207b7SJohn Levon 
alloc_named_stree(const char * name,struct symbol * sym,struct stree * stree)12031f5207b7SJohn Levon static struct named_stree *alloc_named_stree(const char *name, struct symbol *sym, struct stree *stree)
12041f5207b7SJohn Levon {
12051f5207b7SJohn Levon 	struct named_stree *named_stree = __alloc_named_stree(0);
12061f5207b7SJohn Levon 
12071f5207b7SJohn Levon 	named_stree->name = (char *)name;
12081f5207b7SJohn Levon 	named_stree->stree = stree;
12091f5207b7SJohn Levon 	named_stree->sym = sym;
12101f5207b7SJohn Levon 	return named_stree;
12111f5207b7SJohn Levon }
12121f5207b7SJohn Levon 
__save_gotos(const char * name,struct symbol * sym)12131f5207b7SJohn Levon void __save_gotos(const char *name, struct symbol *sym)
12141f5207b7SJohn Levon {
12151f5207b7SJohn Levon 	struct stree **stree;
12161f5207b7SJohn Levon 	struct stree *clone;
12171f5207b7SJohn Levon 
12181f5207b7SJohn Levon 	stree = get_named_stree(goto_stack, name, sym);
12191f5207b7SJohn Levon 	if (stree) {
12201f5207b7SJohn Levon 		merge_stree(stree, cur_stree);
12211f5207b7SJohn Levon 		return;
12221f5207b7SJohn Levon 	} else {
12231f5207b7SJohn Levon 		struct named_stree *named_stree;
12241f5207b7SJohn Levon 
12251f5207b7SJohn Levon 		clone = clone_stree(cur_stree);
12261f5207b7SJohn Levon 		named_stree = alloc_named_stree(name, sym, clone);
12271f5207b7SJohn Levon 		add_ptr_list(&goto_stack, named_stree);
12281f5207b7SJohn Levon 	}
12291f5207b7SJohn Levon }
12301f5207b7SJohn Levon 
__merge_gotos(const char * name,struct symbol * sym)12311f5207b7SJohn Levon void __merge_gotos(const char *name, struct symbol *sym)
12321f5207b7SJohn Levon {
12331f5207b7SJohn Levon 	struct stree **stree;
12341f5207b7SJohn Levon 
12351f5207b7SJohn Levon 	stree = get_named_stree(goto_stack, name, sym);
12361f5207b7SJohn Levon 	if (stree)
12371f5207b7SJohn Levon 		merge_stree(&cur_stree, *stree);
12381f5207b7SJohn Levon }
1239