11f5207bJohn Levon/*
21f5207bJohn Levon * Copyright (C) 2006 Dan Carpenter.
31f5207bJohn Levon *
41f5207bJohn Levon * This program is free software; you can redistribute it and/or
51f5207bJohn Levon * modify it under the terms of the GNU General Public License
61f5207bJohn Levon * as published by the Free Software Foundation; either version 2
71f5207bJohn Levon * of the License, or (at your option) any later version.
81f5207bJohn Levon *
91f5207bJohn Levon * This program is distributed in the hope that it will be useful,
101f5207bJohn Levon * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207bJohn Levon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207bJohn Levon * GNU General Public License for more details.
131f5207bJohn Levon *
141f5207bJohn Levon * You should have received a copy of the GNU General Public License
151f5207bJohn Levon * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207bJohn Levon */
171f5207bJohn Levon
181f5207bJohn Levon/*
191f5207bJohn Levon * You have a lists of states.  kernel = locked, foo = NULL, ...
201f5207bJohn Levon * When you hit an if {} else {} statement then you swap the list
211f5207bJohn Levon * of states for a different list of states.  The lists are stored
221f5207bJohn Levon * on stacks.
231f5207bJohn Levon *
241f5207bJohn Levon * At the beginning of this file there are list of the stacks that
251f5207bJohn Levon * we use.  Each function in this file does something to one of
261f5207bJohn Levon * of the stacks.
271f5207bJohn Levon *
281f5207bJohn Levon * So the smatch_flow.c understands code but it doesn't understand states.
291f5207bJohn Levon * smatch_flow calls functions in this file.  This file calls functions
301f5207bJohn Levon * in smatch_slist.c which just has boring generic plumbing for handling
311f5207bJohn Levon * state lists.  But really it's this file where all the magic happens.
321f5207bJohn Levon */
331f5207bJohn Levon
341f5207bJohn Levon#include <stdlib.h>
351f5207bJohn Levon#include <stdio.h>
361f5207bJohn Levon#include "smatch.h"
371f5207bJohn Levon#include "smatch_slist.h"
381f5207bJohn Levon#include "smatch_extra.h"
391f5207bJohn Levon
401f5207bJohn Levonstruct smatch_state undefined = { .name = "undefined" };
411f5207bJohn Levonstruct smatch_state ghost = { .name = "ghost" };
421f5207bJohn Levonstruct smatch_state merged = { .name = "merged" };
431f5207bJohn Levonstruct smatch_state true_state = { .name = "true" };
441f5207bJohn Levonstruct smatch_state false_state = { .name = "false" };
451f5207bJohn Levon
461f5207bJohn Levonstatic struct stree *cur_stree; /* current states */
47c85f09cJohn Levonstatic struct stree *fast_overlay;
481f5207bJohn Levon
491f5207bJohn Levonstatic struct stree_stack *true_stack; /* states after a t/f branch */
501f5207bJohn Levonstatic struct stree_stack *false_stack;
511f5207bJohn Levonstatic struct stree_stack *pre_cond_stack; /* states before a t/f branch */
521f5207bJohn Levon
531f5207bJohn Levonstatic struct stree_stack *cond_true_stack; /* states affected by a branch */
541f5207bJohn Levonstatic struct stree_stack *cond_false_stack;
551f5207bJohn Levon
561f5207bJohn Levonstatic struct stree_stack *fake_cur_stree_stack;
571f5207bJohn Levonstatic int read_only;
581f5207bJohn Levon
591f5207bJohn Levonstatic struct stree_stack *break_stack;
601f5207bJohn Levonstatic struct stree_stack *fake_break_stack;
611f5207bJohn Levonstatic struct stree_stack *switch_stack;
621f5207bJohn Levonstatic struct range_list_stack *remaining_cases;
631f5207bJohn Levonstatic struct stree_stack *default_stack;
641f5207bJohn Levonstatic struct stree_stack *continue_stack;
651f5207bJohn Levon
661f5207bJohn Levonstatic struct named_stree_stack *goto_stack;
671f5207bJohn Levon
681f5207bJohn Levonstatic struct ptr_list *backup;
691f5207bJohn Levon
701f5207bJohn Levonint option_debug;
711f5207bJohn Levon
721f5207bJohn Levonvoid __print_cur_stree(void)
731f5207bJohn Levon{
741f5207bJohn Levon	__print_stree(cur_stree);
751f5207bJohn Levon}
761f5207bJohn Levon
771f5207bJohn Levonint unreachable(void)
781f5207bJohn Levon{
791f5207bJohn Levon	if (!cur_stree)
801f5207bJohn Levon		return 1;
811f5207bJohn Levon	return 0;
821f5207bJohn Levon}
831f5207bJohn Levon
84c85f09cJohn Levonvoid __set_cur_stree_readonly(void)
85c85f09cJohn Levon{
86c85f09cJohn Levon	read_only++;
87c85f09cJohn Levon}
88c85f09cJohn Levon
89c85f09cJohn Levonvoid __set_cur_stree_writable(void)
90c85f09cJohn Levon{
91c85f09cJohn Levon	read_only--;
92c85f09cJohn Levon}
93c85f09cJohn Levon
941f5207bJohn Levonstruct sm_state *set_state(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
951f5207bJohn Levon{
961f5207bJohn Levon	struct sm_state *ret;
971f5207bJohn Levon
98efe51d0John Levon	if (!name || !state)
991f5207bJohn Levon		return NULL;
1001f5207bJohn Levon
1011f5207bJohn Levon	if (read_only)
1021f5207bJohn Levon		sm_perror("cur_stree is read only.");
1031f5207bJohn Levon
1041f5207bJohn Levon	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
1051f5207bJohn Levon		struct smatch_state *s;
1061f5207bJohn Levon
107efe51d0John Levon		s = __get_state(owner, name, sym);
1081f5207bJohn Levon		if (!s)
1091f5207bJohn Levon			sm_msg("%s new [%s] '%s' %s", __func__,
1101f5207bJohn Levon			       check_name(owner), name, show_state(state));
1111f5207bJohn Levon		else
1121f5207bJohn Levon			sm_msg("%s change [%s] '%s' %s => %s",
1131f5207bJohn Levon				__func__, check_name(owner), name, show_state(s),
1141f5207bJohn Levon				show_state(state));
1151f5207bJohn Levon	}
1161f5207bJohn Levon
1171f5207bJohn Levon	if (owner != -1 && unreachable())
1181f5207bJohn Levon		return NULL;
1191f5207bJohn Levon
1201f5207bJohn Levon	if (fake_cur_stree_stack)
1211f5207bJohn Levon		set_state_stree_stack(&fake_cur_stree_stack, owner, name, sym, state);
1221f5207bJohn Levon
1231f5207bJohn Levon	ret = set_state_stree(&cur_stree, owner, name, sym, state);
1241f5207bJohn Levon
1251f5207bJohn Levon	return ret;
1261f5207bJohn Levon}
1271f5207bJohn Levon
1281f5207bJohn Levonstruct sm_state *set_state_expr(int owner, struct expression *expr, struct smatch_state *state)
1291f5207bJohn Levon{
1301f5207bJohn Levon	char *name;
1311f5207bJohn Levon	struct symbol *sym;
1321f5207bJohn Levon	struct sm_state *ret = NULL;
1331f5207bJohn Levon
1341f5207bJohn Levon	expr = strip_expr(expr);
1351f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
1361f5207bJohn Levon	if (!name || !sym)
1371f5207bJohn Levon		goto free;
1381f5207bJohn Levon	ret = set_state(owner, name, sym, state);
1391f5207bJohn Levonfree:
1401f5207bJohn Levon	free_string(name);
1411f5207bJohn Levon	return ret;
1421f5207bJohn Levon}
1431f5207bJohn Levon
144c85f09cJohn Levonstruct stree *__swap_cur_stree(struct stree *stree)
1451f5207bJohn Levon{
146c85f09cJohn Levon	struct stree *orig = cur_stree;
147c85f09cJohn Levon
1481f5207bJohn Levon	cur_stree = stree;
149c85f09cJohn Levon	return orig;
1501f5207bJohn Levon}
1511f5207bJohn Levon
1521f5207bJohn Levonvoid __push_fake_cur_stree(void)
1531f5207bJohn Levon{
1541f5207bJohn Levon	push_stree(&fake_cur_stree_stack, NULL);
1551f5207bJohn Levon	__save_pre_cond_states();
1561f5207bJohn Levon}
1571f5207bJohn Levon
1581f5207bJohn Levonstruct stree *__pop_fake_cur_stree(void)
1591f5207bJohn Levon{
1601f5207bJohn Levon	if (!fake_cur_stree_stack)
1611f5207bJohn Levon		sm_perror("popping too many fake cur strees.");
1621f5207bJohn Levon	__use_pre_cond_states();
1631f5207bJohn Levon	return pop_stree(&fake_cur_stree_stack);
1641f5207bJohn Levon}
1651f5207bJohn Levon
1661f5207bJohn Levonvoid __free_fake_cur_stree(void)
1671f5207bJohn Levon{
1681f5207bJohn Levon	struct stree *stree;
1691f5207bJohn Levon
1701f5207bJohn Levon	stree = __pop_fake_cur_stree();
1711f5207bJohn Levon	free_stree(&stree);
1721f5207bJohn Levon}
1731f5207bJohn Levon
1741f5207bJohn Levonvoid __set_fake_cur_stree_fast(struct stree *stree)
1751f5207bJohn Levon{
176c85f09cJohn Levon	if (fast_overlay) {
177c85f09cJohn Levon		sm_perror("cannot nest fast overlay");
178c85f09cJohn Levon		return;
179c85f09cJohn Levon	}
180c85f09cJohn Levon	fast_overlay = stree;
181c85f09cJohn Levon	set_fast_math_only();
1821f5207bJohn Levon}
1831f5207bJohn Levon
1841f5207bJohn Levonvoid __pop_fake_cur_stree_fast(void)
1851f5207bJohn Levon{
186c85f09cJohn Levon	fast_overlay = NULL;
187c85f09cJohn Levon	clear_fast_math_only();
1881f5207bJohn Levon}
1891f5207bJohn Levon
1901f5207bJohn Levonvoid __merge_stree_into_cur(struct stree *stree)
1911f5207bJohn Levon{
1921f5207bJohn Levon	struct sm_state *sm;
1931f5207bJohn Levon	struct sm_state *orig;
1941f5207bJohn Levon	struct sm_state *merged;
1951f5207bJohn Levon
1961f5207bJohn Levon	FOR_EACH_SM(stree, sm) {
1971f5207bJohn Levon		orig = get_sm_state(sm->owner, sm->name, sm->sym);
1981f5207bJohn Levon		if (orig)
1991f5207bJohn Levon			merged = merge_sm_states(orig, sm);
2001f5207bJohn Levon		else
2011f5207bJohn Levon			merged = sm;
2021f5207bJohn Levon		__set_sm(merged);
2031f5207bJohn Levon	} END_FOR_EACH_SM(sm);
2041f5207bJohn Levon}
2051f5207bJohn Levon
2061f5207bJohn Levonvoid __set_sm(struct sm_state *sm)
2071f5207bJohn Levon{
2081f5207bJohn Levon	if (read_only)
2091f5207bJohn Levon		sm_perror("cur_stree is read only.");
2101f5207bJohn Levon
2111f5207bJohn Levon	if (option_debug ||
2121f5207bJohn Levon	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
2131f5207bJohn Levon		struct smatch_state *s;
2141f5207bJohn Levon
215efe51d0John Levon		s = __get_state(sm->owner, sm->name, sm->sym);
2161f5207bJohn Levon		if (!s)
2171f5207bJohn Levon			sm_msg("%s new %s", __func__, show_sm(sm));
2181f5207bJohn Levon		else
2191f5207bJohn Levon			sm_msg("%s change %s (was %s)",	__func__, show_sm(sm),
2201f5207bJohn Levon			       show_state(s));
2211f5207bJohn Levon	}
2221f5207bJohn Levon
2231f5207bJohn Levon	if (unreachable())
2241f5207bJohn Levon		return;
2251f5207bJohn Levon
2261f5207bJohn Levon	if (fake_cur_stree_stack)
2271f5207bJohn Levon		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
2281f5207bJohn Levon
2291f5207bJohn Levon	overwrite_sm_state_stree(&cur_stree, sm);
2301f5207bJohn Levon}
2311f5207bJohn Levon
2321f5207bJohn Levonvoid __set_sm_cur_stree(struct sm_state *sm)
2331f5207bJohn Levon{
2341f5207bJohn Levon	if (read_only)
2351f5207bJohn Levon		sm_perror("cur_stree is read only.");
2361f5207bJohn Levon
2371f5207bJohn Levon	if (option_debug ||
2381f5207bJohn Levon	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
2391f5207bJohn Levon		struct smatch_state *s;
2401f5207bJohn Levon
241efe51d0John Levon		s = __get_state(sm->owner, sm->name, sm->sym);
2421f5207bJohn Levon		if (!s)
2431f5207bJohn Levon			sm_msg("%s new %s", __func__, show_sm(sm));
2441f5207bJohn Levon		else
2451f5207bJohn Levon			sm_msg("%s change %s (was %s)",
2461f5207bJohn Levon				__func__, show_sm(sm), show_state(s));
2471f5207bJohn Levon	}
2481f5207bJohn Levon
2491f5207bJohn Levon	if (unreachable())
2501f5207bJohn Levon		return;
2511f5207bJohn Levon
2521f5207bJohn Levon	overwrite_sm_state_stree(&cur_stree, sm);
2531f5207bJohn Levon}
2541f5207bJohn Levon
2551f5207bJohn Levonvoid __set_sm_fake_stree(struct sm_state *sm)
2561f5207bJohn Levon{
2571f5207bJohn Levon	if (read_only)
2581f5207bJohn Levon		sm_perror("cur_stree is read only.");
2591f5207bJohn Levon
2601f5207bJohn Levon	if (option_debug ||
2611f5207bJohn Levon	    strcmp(check_name(sm->owner), option_debug_check) == 0) {
2621f5207bJohn Levon		struct smatch_state *s;
2631f5207bJohn Levon
264efe51d0John Levon		s = __get_state(sm->owner, sm->name, sm->sym);
2651f5207bJohn Levon		if (!s)
2661f5207bJohn Levon			sm_msg("%s new %s", __func__, show_sm(sm));
2671f5207bJohn Levon		else
2681f5207bJohn Levon			sm_msg("%s change %s (was %s)",
2691f5207bJohn Levon				__func__, show_sm(sm), show_state(s));
2701f5207bJohn Levon	}
2711f5207bJohn Levon
2721f5207bJohn Levon	if (unreachable())
2731f5207bJohn Levon		return;
2741f5207bJohn Levon
2751f5207bJohn Levon	overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
2761f5207bJohn Levon}
2771f5207bJohn Levon
2781f5207bJohn Levon
2791f5207bJohn Levontypedef void (get_state_hook)(int owner, const char *name, struct symbol *sym);
2801f5207bJohn LevonDECLARE_PTR_LIST(fn_list, get_state_hook *);
2811f5207bJohn Levonstatic struct fn_list *get_state_hooks;
2821f5207bJohn Levon
2831f5207bJohn Levonvoid add_get_state_hook(get_state_hook *fn)
2841f5207bJohn Levon{
2851f5207bJohn Levon	get_state_hook **p = malloc(sizeof(get_state_hook *));
2861f5207bJohn Levon	*p = fn;
2871f5207bJohn Levon	add_ptr_list(&get_state_hooks, p);
2881f5207bJohn Levon}
2891f5207bJohn Levon
2901f5207bJohn Levonstatic void call_get_state_hooks(int owner, const char *name, struct symbol *sym)
2911f5207bJohn Levon{
2921f5207bJohn Levon	static int recursion;
2931f5207bJohn Levon	get_state_hook **fn;
2941f5207bJohn Levon
2951f5207bJohn Levon	if (recursion)
2961f5207bJohn Levon		return;
2971f5207bJohn Levon	recursion = 1;
2981f5207bJohn Levon
2991f5207bJohn Levon	FOR_EACH_PTR(get_state_hooks, fn) {
3001f5207bJohn Levon		(*fn)(owner, name, sym);
3011f5207bJohn Levon	} END_FOR_EACH_PTR(fn);
3021f5207bJohn Levon
3031f5207bJohn Levon	recursion = 0;
3041f5207bJohn Levon}
3051f5207bJohn Levon
3061f5207bJohn Levonstruct smatch_state *__get_state(int owner, const char *name, struct symbol *sym)
3071f5207bJohn Levon{
308c85f09cJohn Levon	struct sm_state *sm;
309c85f09cJohn Levon
310c85f09cJohn Levon	sm = get_sm_state(owner, name, sym);
311c85f09cJohn Levon	if (!sm)
312c85f09cJohn Levon		return NULL;
313c85f09cJohn Levon	return sm->state;
3141f5207bJohn Levon}
3151f5207bJohn Levon
3161f5207bJohn Levonstruct smatch_state *get_state(int owner, const char *name, struct symbol *sym)
3171f5207bJohn Levon{
3181f5207bJohn Levon	call_get_state_hooks(owner, name, sym);
3191f5207bJohn Levon
3201f5207bJohn Levon	return __get_state(owner, name, sym);
3211f5207bJohn Levon}
3221f5207bJohn Levon
3231f5207bJohn Levonstruct smatch_state *get_state_expr(int owner, struct expression *expr)
3241f5207bJohn Levon{
3251f5207bJohn Levon	char *name;
3261f5207bJohn Levon	struct symbol *sym;
3271f5207bJohn Levon	struct smatch_state *ret = NULL;
3281f5207bJohn Levon
3291f5207bJohn Levon	expr = strip_expr(expr);
3301f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
3311f5207bJohn Levon	if (!name || !sym)
3321f5207bJohn Levon		goto free;
3331f5207bJohn Levon	ret = get_state(owner, name, sym);
3341f5207bJohn Levonfree:
3351f5207bJohn Levon	free_string(name);
3361f5207bJohn Levon	return ret;
3371f5207bJohn Levon}
3381f5207bJohn Levon
3391f5207bJohn Levonstruct state_list *get_possible_states(int owner, const char *name, struct symbol *sym)
3401f5207bJohn Levon{
3411f5207bJohn Levon	struct sm_state *sms;
3421f5207bJohn Levon
3431f5207bJohn Levon	sms = get_sm_state_stree(cur_stree, owner, name, sym);
3441f5207bJohn Levon	if (sms)
3451f5207bJohn Levon		return sms->possible;
3461f5207bJohn Levon	return NULL;
3471f5207bJohn Levon}
3481f5207bJohn Levon
3491f5207bJohn Levonstruct state_list *get_possible_states_expr(int owner, struct expression *expr)
3501f5207bJohn Levon{
3511f5207bJohn Levon	char *name;
3521f5207bJohn Levon	struct symbol *sym;
3531f5207bJohn Levon	struct state_list *ret = NULL;
3541f5207bJohn Levon
3551f5207bJohn Levon	expr = strip_expr(expr);
3561f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
3571f5207bJohn Levon	if (!name || !sym)
3581f5207bJohn Levon		goto free;
3591f5207bJohn Levon	ret = get_possible_states(owner, name, sym);
3601f5207bJohn Levonfree:
3611f5207bJohn Levon	free_string(name);
3621f5207bJohn Levon	return ret;
3631f5207bJohn Levon}
3641f5207bJohn Levon
3651f5207bJohn Levonstruct sm_state *get_sm_state(int owner, const char *name, struct symbol *sym)
3661f5207bJohn Levon{
367c85f09cJohn Levon	struct sm_state *ret;
368c85f09cJohn Levon
369c85f09cJohn Levon	ret = get_sm_state_stree(fast_overlay, owner, name, sym);
370c85f09cJohn Levon	if (ret)
371c85f09cJohn Levon		return ret;
372c85f09cJohn Levon
3731f5207bJohn Levon	return get_sm_state_stree(cur_stree, owner, name, sym);
3741f5207bJohn Levon}
3751f5207bJohn Levon
3761f5207bJohn Levonstruct sm_state *get_sm_state_expr(int owner, struct expression *expr)
3771f5207bJohn Levon{
3781f5207bJohn Levon	char *name;
3791f5207bJohn Levon	struct symbol *sym;
3801f5207bJohn Levon	struct sm_state *ret = NULL;
3811f5207bJohn Levon
3821f5207bJohn Levon	expr = strip_expr(expr);
3831f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
3841f5207bJohn Levon	if (!name || !sym)
3851f5207bJohn Levon		goto free;
3861f5207bJohn Levon	ret = get_sm_state(owner, name, sym);
3871f5207bJohn Levonfree:
3881f5207bJohn Levon	free_string(name);
3891f5207bJohn Levon	return ret;
3901f5207bJohn Levon}
3911f5207bJohn Levon
3921f5207bJohn Levonvoid delete_state(int owner, const char *name, struct symbol *sym)
3931f5207bJohn Levon{
3941f5207bJohn Levon	delete_state_stree(&cur_stree, owner, name, sym);
3951f5207bJohn Levon	if (cond_true_stack) {
3961f5207bJohn Levon		delete_state_stree_stack(&pre_cond_stack, owner, name, sym);
3971f5207bJohn Levon		delete_state_stree_stack(&cond_true_stack, owner, name, sym);
3981f5207bJohn Levon		delete_state_stree_stack(&cond_false_stack, owner, name, sym);
3991f5207bJohn Levon	}
4001f5207bJohn Levon}
4011f5207bJohn Levon
4021f5207bJohn Levonvoid delete_state_expr(int owner, struct expression *expr)
4031f5207bJohn Levon{
4041f5207bJohn Levon	char *name;
4051f5207bJohn Levon	struct symbol *sym;
4061f5207bJohn Levon
4071f5207bJohn Levon	expr = strip_expr(expr);
4081f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
4091f5207bJohn Levon	if (!name || !sym)
4101f5207bJohn Levon		goto free;
4111f5207bJohn Levon	delete_state(owner, name, sym);
4121f5207bJohn Levonfree:
4131f5207bJohn Levon	free_string(name);
4141f5207bJohn Levon}
4151f5207bJohn Levon
4161f5207bJohn Levonstatic void delete_all_states_stree_sym(struct stree **stree, struct symbol *sym)
4171f5207bJohn Levon{
4181f5207bJohn Levon	struct state_list *slist = NULL;
4191f5207bJohn Levon	struct sm_state *sm;
4201f5207bJohn Levon
4211f5207bJohn Levon	FOR_EACH_SM(*stree, sm) {
4221f5207bJohn Levon		if (sm->sym == sym)
4231f5207bJohn Levon			add_ptr_list(&slist, sm);
4241f5207bJohn Levon	} END_FOR_EACH_SM(sm);
4251f5207bJohn Levon
4261f5207bJohn Levon	FOR_EACH_PTR(slist, sm) {
4271f5207bJohn Levon		delete_state_stree(stree, sm->owner, sm->name, sm->sym);
4281f5207bJohn Levon	} END_FOR_EACH_PTR(sm);
4291f5207bJohn Levon
4301f5207bJohn Levon	free_slist(&slist);
4311f5207bJohn Levon}
4321f5207bJohn Levon
4331f5207bJohn Levonstatic void delete_all_states_stree_stack_sym(struct stree_stack **stack, struct symbol *sym)
4341f5207bJohn Levon{
4351f5207bJohn Levon	struct stree *stree;
4361f5207bJohn Levon
4371f5207bJohn Levon	if (!*stack)
4381f5207bJohn Levon		return;
4391f5207bJohn Levon
4401f5207bJohn Levon	stree = pop_stree(stack);
4411f5207bJohn Levon	delete_all_states_stree_sym(&stree, sym);
4421f5207bJohn Levon	push_stree(stack, stree);
4431f5207bJohn Levon}
4441f5207bJohn Levon
4451f5207bJohn Levonvoid __delete_all_states_sym(struct symbol *sym)
4461f5207bJohn Levon{
4471f5207bJohn Levon	delete_all_states_stree_sym(&cur_stree, sym);
4481f5207bJohn Levon
4491f5207bJohn Levon	delete_all_states_stree_stack_sym(&true_stack, sym);
4501f5207bJohn Levon	delete_all_states_stree_stack_sym(&true_stack, sym);
4511f5207bJohn Levon	delete_all_states_stree_stack_sym(&false_stack, sym);
4521f5207bJohn Levon	delete_all_states_stree_stack_sym(&pre_cond_stack, sym);
4531f5207bJohn Levon	delete_all_states_stree_stack_sym(&cond_true_stack, sym);
4541f5207bJohn Levon	delete_all_states_stree_stack_sym(&cond_false_stack, sym);
4551f5207bJohn Levon	delete_all_states_stree_stack_sym(&fake_cur_stree_stack, sym);
4561f5207bJohn Levon	delete_all_states_stree_stack_sym(&break_stack, sym);
4571f5207bJohn Levon	delete_all_states_stree_stack_sym(&fake_break_stack, sym);
4581f5207bJohn Levon	delete_all_states_stree_stack_sym(&switch_stack, sym);
4591f5207bJohn Levon	delete_all_states_stree_stack_sym(&continue_stack, sym);
4601f5207bJohn Levon
4611f5207bJohn Levon	/*
4621f5207bJohn Levon	 * deleting from the goto stack is problematic because we don't know
4631f5207bJohn Levon	 * if the label is in scope and also we need the value for --two-passes.
4641f5207bJohn Levon	 */
4651f5207bJohn Levon}
4661f5207bJohn Levon
4671f5207bJohn Levonstruct stree *get_all_states_from_stree(int owner, struct stree *source)
4681f5207bJohn Levon{
4691f5207bJohn Levon	struct stree *ret = NULL;
4701f5207bJohn Levon	struct sm_state *tmp;
4711f5207bJohn Levon
4721f5207bJohn Levon	FOR_EACH_SM(source, tmp) {
4731f5207bJohn Levon		if (tmp->owner == owner)
4741f5207bJohn Levon			avl_insert(&ret, tmp);
4751f5207bJohn Levon	} END_FOR_EACH_SM(tmp);
4761f5207bJohn Levon
4771f5207bJohn Levon	return ret;
4781f5207bJohn Levon}
4791f5207bJohn Levon
4801f5207bJohn Levonstruct stree *get_all_states_stree(int owner)
4811f5207bJohn Levon{
4821f5207bJohn Levon	return get_all_states_from_stree(owner, cur_stree);
4831f5207bJohn Levon}
4841f5207bJohn Levon
4851f5207bJohn Levonstruct stree *__get_cur_stree(void)
4861f5207bJohn Levon{
4871f5207bJohn Levon	return cur_stree;
4881f5207bJohn Levon}
4891f5207bJohn Levon
4901f5207bJohn Levonint is_reachable(void)
4911f5207bJohn Levon{
4921f5207bJohn Levon	if (cur_stree)
4931f5207bJohn Levon		return 1;
4941f5207bJohn Levon	return 0;
4951f5207bJohn Levon}
4961f5207bJohn Levon
4971f5207bJohn Levonvoid set_true_false_states(int owner, const char *name, struct symbol *sym,
4981f5207bJohn Levon			   struct smatch_state *true_state,
4991f5207bJohn Levon			   struct smatch_state *false_state)
5001f5207bJohn Levon{
5011f5207bJohn Levon	if (read_only)
5021f5207bJohn Levon		sm_perror("cur_stree is read only.");
5031f5207bJohn Levon
5041f5207bJohn Levon	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
5051f5207bJohn Levon		struct smatch_state *tmp;
5061f5207bJohn Levon
507efe51d0John Levon		tmp = __get_state(owner, name, sym);
5081f5207bJohn Levon		sm_msg("%s [%s] '%s'.  Was %s.  Now T:%s F:%s", __func__,
5091f5207bJohn Levon		       check_name(owner),  name, show_state(tmp),
5101f5207bJohn Levon		       show_state(true_state), show_state(false_state));
5111f5207bJohn Levon	}
5121f5207bJohn Levon
5131f5207bJohn Levon	if (unreachable())
5141f5207bJohn Levon		return;
5151f5207bJohn Levon
5161f5207bJohn Levon	if (!cond_false_stack || !cond_true_stack) {
5171f5207bJohn Levon		sm_perror("missing true/false stacks");
5181f5207bJohn Levon		return;
5191f5207bJohn Levon	}
5201f5207bJohn Levon
5211f5207bJohn Levon	if (true_state)
5221f5207bJohn Levon		set_state_stree_stack(&cond_true_stack, owner, name, sym, true_state);
5231f5207bJohn Levon	if (false_state)
5241f5207bJohn Levon		set_state_stree_stack(&cond_false_stack, owner, name, sym, false_state);
5251f5207bJohn Levon}
5261f5207bJohn Levon
5271f5207bJohn Levonvoid set_true_false_states_expr(int owner, struct expression *expr,
5281f5207bJohn Levon			   struct smatch_state *true_state,
5291f5207bJohn Levon			   struct smatch_state *false_state)
5301f5207bJohn Levon{
5311f5207bJohn Levon	char *name;
5321f5207bJohn Levon	struct symbol *sym;
5331f5207bJohn Levon
5341f5207bJohn Levon	expr = strip_expr(expr);
5351f5207bJohn Levon	name = expr_to_var_sym(expr, &sym);
5361f5207bJohn Levon	if (!name || !sym)
5371f5207bJohn Levon		goto free;
5381f5207bJohn Levon	set_true_false_states(owner, name, sym, true_state, false_state);
5391f5207bJohn Levonfree:
5401f5207bJohn Levon	free_string(name);
5411f5207bJohn Levon}
5421f5207bJohn Levon
5431f5207bJohn Levonvoid __set_true_false_sm(struct sm_state *true_sm, struct sm_state *false_sm)
5441f5207bJohn Levon{
5451f5207bJohn Levon	int owner;
5461f5207bJohn Levon	const char *name;
5471f5207bJohn Levon	struct symbol *sym;
5481f5207bJohn Levon
5491f5207bJohn Levon	if (!true_sm && !false_sm)
5501f5207bJohn Levon		return;
5511f5207bJohn Levon
5521f5207bJohn Levon	if (unreachable())
5531f5207bJohn Levon		return;
5541f5207bJohn Levon
5551f5207bJohn Levon	owner = true_sm ? true_sm->owner : false_sm->owner;
5561f5207bJohn Levon	name = true_sm ? true_sm->name : false_sm->name;
5571f5207bJohn Levon	sym = true_sm ? true_sm->sym : false_sm->sym;
5581f5207bJohn Levon	if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
5591f5207bJohn Levon		struct smatch_state *tmp;
5601f5207bJohn Levon
561efe51d0John Levon		tmp = __get_state(owner, name, sym);
5621f5207bJohn Levon		sm_msg("%s [%s] '%s'.  Was %s.  Now T:%s F:%s", __func__,
5631f5207bJohn Levon		       check_name(owner),  name, show_state(tmp),
5641f5207bJohn Levon		       show_state(true_sm ? true_sm->state : NULL),
5651f5207bJohn Levon		       show_state(false_sm ? false_sm->state : NULL));
5661f5207bJohn Levon	}
5671f5207bJohn Levon
5681f5207bJohn Levon	if (!cond_false_stack || !cond_true_stack) {
5691f5207bJohn Levon		sm_perror("missing true/false stacks");
5701f5207bJohn Levon		return;
5711f5207bJohn Levon	}
5721f5207bJohn Levon
5731f5207bJohn Levon	if (true_sm)
5741f5207bJohn Levon		overwrite_sm_state_stree_stack(&cond_true_stack, true_sm);
5751f5207bJohn Levon	if (false_sm)
5761f5207bJohn Levon		overwrite_sm_state_stree_stack(&cond_false_stack, false_sm);
5771f5207bJohn Levon}
5781f5207bJohn Levon
5791f5207bJohn Levonvoid nullify_path(void)
5801f5207bJohn Levon{
5811f5207bJohn Levon	if (fake_cur_stree_stack) {
5821f5207bJohn Levon		__free_fake_cur_stree();
5831f5207bJohn Levon		__push_fake_cur_stree();
5841f5207bJohn Levon	}
5851f5207bJohn Levon	free_stree(&cur_stree);
5861f5207bJohn Levon}
5871f5207bJohn Levon
5881f5207bJohn Levonvoid __match_nullify_path_hook(const char *fn, struct expression *expr,
5891f5207bJohn Levon			       void *unused)
5901f5207bJohn Levon{
5911f5207bJohn Levon	nullify_path();
5921f5207bJohn Levon}
5931f5207bJohn Levon
5941f5207bJohn Levon/*
5951f5207bJohn Levon * At the start of every function we mark the path
5961f5207bJohn Levon * as unnull.  That way there is always at least one state
5971f5207bJohn Levon * in the cur_stree until nullify_path is called.  This
5981f5207bJohn Levon * is used in merge_slist() for the first null check.
5991f5207bJohn Levon */
6001f5207bJohn Levonvoid __unnullify_path(void)
6011f5207bJohn Levon{
6021f5207bJohn Levon	if (!cur_stree)
6031f5207bJohn Levon		set_state(-1, "unnull_path", NULL, &true_state);
6041f5207bJohn Levon}
6051f5207bJohn Levon
6061f5207bJohn Levonint __path_is_null(void)
6071f5207bJohn Levon{
6081f5207bJohn Levon	if (cur_stree)
6091f5207bJohn Levon		return 0;
6101f5207bJohn Levon	return 1;
6111f5207bJohn Levon}
6121f5207bJohn Levon
6131f5207bJohn Levonstatic void check_stree_stack_free(struct stree_stack **stack)
6141f5207bJohn Levon{
6151f5207bJohn Levon	if (*stack) {
6161f5207bJohn Levon		sm_perror("stack not empty");
6171f5207bJohn Levon		free_stack_and_strees(stack);
6181f5207bJohn Levon	}
6191f5207bJohn Levon}
6201f5207bJohn Levon
6211f5207bJohn Levonvoid save_all_states(void)
6221f5207bJohn Levon{
623c85f09cJohn Levon	__add_ptr_list(&backup, cur_stree);
6241f5207bJohn Levon	cur_stree = NULL;
6251f5207bJohn Levon
626c85f09cJohn Levon	__add_ptr_list(&backup, true_stack);
6271f5207bJohn Levon	true_stack = NULL;
628c85f09cJohn Levon	__add_ptr_list(&backup, false_stack);
6291f5207bJohn Levon	false_stack = NULL;
630c85f09cJohn Levon	__add_ptr_list(&backup, pre_cond_stack);
6311f5207bJohn Levon	pre_cond_stack = NULL;
6321f5207bJohn Levon
633c85f09cJohn Levon	__add_ptr_list(&backup, cond_true_stack);
6341f5207bJohn Levon	cond_true_stack = NULL;
635c85f09cJohn Levon	__add_ptr_list(&backup, cond_false_stack);
6361f5207bJohn Levon	cond_false_stack = NULL;
6371f5207bJohn Levon
638c85f09cJohn Levon	__add_ptr_list(&backup, fake_cur_stree_stack);
6391f5207bJohn Levon	fake_cur_stree_stack = NULL;
6401f5207bJohn Levon
641c85f09cJohn Levon	__add_ptr_list(&backup, break_stack);
6421f5207bJohn Levon	break_stack = NULL;
643c85f09cJohn Levon	__add_ptr_list(&backup, fake_break_stack);
6441f5207bJohn Levon	fake_break_stack = NULL;
6451f5207bJohn Levon
646c85f09cJohn Levon	__add_ptr_list(&backup, switch_stack);
6471f5207bJohn Levon	switch_stack = NULL;
648c85f09cJohn Levon	__add_ptr_list(&backup, remaining_cases);
6491f5207bJohn Levon	remaining_cases = NULL;
650c85f09cJohn Levon	__add_ptr_list(&backup, default_stack);
6511f5207bJohn Levon	default_stack = NULL;
652c85f09cJohn Levon	__add_ptr_list(&backup, continue_stack);
6531f5207bJohn Levon	continue_stack = NULL;
6541f5207bJohn Levon
655c85f09cJohn Levon	__add_ptr_list(&backup, goto_stack);
6561f5207bJohn Levon	goto_stack = NULL;
6571f5207bJohn Levon}
6581f5207bJohn Levon
6591f5207bJohn Levonstatic void *pop_backup(void)
6601f5207bJohn Levon{
6611f5207bJohn Levon	void *ret;
6621f5207bJohn Levon
6631f5207bJohn Levon	ret = last_ptr_list(backup);
6641f5207bJohn Levon	delete_ptr_list_last(&backup);
6651f5207bJohn Levon	return ret;
6661f5207bJohn Levon}
6671f5207bJohn Levon
6681f5207bJohn Levonvoid restore_all_states(void)
6691f5207bJohn Levon{
6701f5207bJohn Levon	goto_stack = pop_backup();
6711f5207bJohn Levon
6721f5207bJohn Levon	continue_stack = pop_backup();
6731f5207bJohn Levon	default_stack = pop_backup();
6741f5207bJohn Levon	remaining_cases = pop_backup();
6751f5207bJohn Levon	switch_stack = pop_backup();
6761f5207bJohn Levon	fake_break_stack = pop_backup();
6771f5207bJohn Levon	break_stack = pop_backup();
6781f5207bJohn Levon
6791f5207bJohn Levon	fake_cur_stree_stack = pop_backup();
6801f5207bJohn Levon
6811f5207bJohn Levon	cond_false_stack = pop_backup();
6821f5207bJohn Levon	cond_true_stack = pop_backup();
6831f5207bJohn Levon
6841f5207bJohn Levon	pre_cond_stack = pop_backup();
6851f5207bJohn Levon	false_stack = pop_backup();
6861f5207bJohn Levon	true_stack = pop_backup();
6871f5207bJohn Levon
6881f5207bJohn Levon	cur_stree = pop_backup();
6891f5207bJohn Levon}
6901f5207bJohn Levon
6911f5207bJohn Levonvoid free_goto_stack(void)
6921f5207bJohn Levon{
6931f5207bJohn Levon	struct named_stree *named_stree;
6941f5207bJohn Levon
6951f5207bJohn Levon	FOR_EACH_PTR(goto_stack, named_stree) {
6961f5207bJohn Levon		free_stree(&named_stree->stree);
6971f5207bJohn Levon	} END_FOR_EACH_PTR(named_stree);
6981f5207bJohn Levon	__free_ptr_list((struct ptr_list **)&goto_stack);
6991f5207bJohn Levon}
7001f5207bJohn Levon
7011f5207bJohn Levonvoid clear_all_states(void)
7021f5207bJohn Levon{
7031f5207bJohn Levon	nullify_path();
7041f5207bJohn Levon	check_stree_stack_free(&true_stack);
7051f5207bJohn Levon	check_stree_stack_free(&false_stack);
7061f5207bJohn Levon	check_stree_stack_free(&pre_cond_stack);
7071f5207bJohn Levon	check_stree_stack_free(&cond_true_stack);
7081f5207bJohn Levon	check_stree_stack_free(&cond_false_stack);
7091f5207bJohn Levon	check_stree_stack_free(&break_stack);
7101f5207bJohn Levon	check_stree_stack_free(&fake_break_stack);
7111f5207bJohn Levon	check_stree_stack_free(&switch_stack);
7121f5207bJohn Levon	check_stree_stack_free(&continue_stack);
7131f5207bJohn Levon	check_stree_stack_free(&fake_cur_stree_stack);
7141f5207bJohn Levon
7151f5207bJohn Levon	free_goto_stack();
7161f5207bJohn Levon
7171f5207bJohn Levon	free_every_single_sm_state();
7181f5207bJohn Levon	free_tmp_expressions();
7191f5207bJohn Levon}
7201f5207bJohn Levon
7211f5207bJohn Levonvoid __push_cond_stacks(void)
7221f5207bJohn Levon{
7231f5207bJohn Levon	push_stree(&cond_true_stack, NULL);
7241f5207bJohn Levon	push_stree(&cond_false_stack, NULL);
7251f5207bJohn Levon	__push_fake_cur_stree();
7261f5207bJohn Levon}
7271f5207bJohn Levon
7281f5207bJohn Levonvoid __fold_in_set_states(void)
7291f5207bJohn Levon{
7301f5207bJohn Levon	struct stree *new_states;
7311f5207bJohn Levon	struct sm_state *sm;
7321f5207bJohn Levon
7331f5207bJohn Levon	new_states = __pop_fake_cur_stree();
7341f5207bJohn Levon	FOR_EACH_SM(new_states, sm) {
7351f5207bJohn Levon		__set_sm(sm);
7361f5207bJohn Levon		__set_true_false_sm(sm, sm);
7371f5207bJohn Levon	} END_FOR_EACH_SM(sm);
7381f5207bJohn Levon	free_stree(&new_states);
7391f5207bJohn Levon}
7401f5207bJohn Levon
7411f5207bJohn Levonvoid __free_set_states(void)
7421f5207bJohn Levon{
7431f5207bJohn Levon	struct stree *new_states;
7441f5207bJohn Levon
7451f5207bJohn Levon	new_states = __pop_fake_cur_stree();
7461f5207bJohn Levon	free_stree(&new_states);
7471f5207bJohn Levon}
7481f5207bJohn Levon
7491f5207bJohn Levonstruct stree *__copy_cond_true_states(void)
7501f5207bJohn Levon{
7511f5207bJohn Levon	struct stree *ret;
7521f5207bJohn Levon
7531f5207bJohn Levon	ret = pop_stree(&cond_true_stack);
7541f5207bJohn Levon	push_stree(&cond_true_stack, clone_stree(ret));
7551f5207bJohn Levon	return ret;
7561f5207bJohn Levon}
7571f5207bJohn Levon
7581f5207bJohn Levonstruct stree *__copy_cond_false_states(void)
7591f5207bJohn Levon{
7601f5207bJohn Levon	struct stree *ret;
7611f5207bJohn Levon
7621f5207bJohn Levon	ret = pop_stree(&cond_false_stack);
7631f5207bJohn Levon	push_stree(&cond_false_stack, clone_stree(ret));
7641f5207bJohn Levon	return ret;
7651f5207bJohn Levon}
7661f5207bJohn Levon
7671f5207bJohn Levonstruct stree *__pop_cond_true_stack(void)
7681f5207bJohn Levon{
7691f5207bJohn Levon	return pop_stree(&cond_true_stack);
7701f5207bJohn Levon}
7711f5207bJohn Levon
7721f5207bJohn Levonstruct stree *__pop_cond_false_stack(void)
7731f5207bJohn Levon{
7741f5207bJohn Levon	return pop_stree(&cond_false_stack);
7751f5207bJohn Levon}
7761f5207bJohn Levon
7771f5207bJohn Levon/*
7781f5207bJohn Levon * This combines the pre cond states with either the true or false states.
7791f5207bJohn Levon * For example:
7801f5207bJohn Levon * a = kmalloc() ; if (a !! foo(a)
7811f5207bJohn Levon * In the pre state a is possibly null.  In the true state it is non null.
7821f5207bJohn Levon * In the false state it is null.  Combine the pre and the false to get
7831f5207bJohn Levon * that when we call 'foo', 'a' is null.
7841f5207bJohn Levon */
7851f5207bJohn Levonstatic void __use_cond_stack(struct stree_stack **stack)
7861f5207bJohn Levon{
7871f5207bJohn Levon	struct stree *stree;
7881f5207bJohn Levon
7891f5207bJohn Levon	free_stree(&cur_stree);
7901f5207bJohn Levon
7911f5207bJohn Levon	cur_stree = pop_stree(&pre_cond_stack);
7921f5207bJohn Levon	push_stree(&pre_cond_stack, clone_stree(cur_stree));
7931f5207bJohn Levon
7941f5207bJohn Levon	stree = pop_stree(stack);
7951f5207bJohn Levon	overwrite_stree(stree, &cur_stree);
7961f5207bJohn Levon	push_stree(stack, stree);
7971f5207bJohn Levon}
7981f5207bJohn Levon
7991f5207bJohn Levonvoid __use_pre_cond_states(void)
8001f5207bJohn Levon{
8011f5207bJohn Levon	free_stree(&cur_stree);
8021f5207bJohn Levon	cur_stree = pop_stree(&pre_cond_stack);
8031f5207bJohn Levon}
8041f5207bJohn Levon
8051f5207bJohn Levonvoid __use_cond_true_states(void)
8061f5207bJohn Levon{
8071f5207bJohn Levon	__use_cond_stack(&cond_true_stack);
8081f5207bJohn Levon}
8091f5207bJohn Levon
8101f5207bJohn Levonvoid __use_cond_false_states(void)
8111f5207bJohn Levon{
8121f5207bJohn Levon	__use_cond_stack(&cond_false_stack);
8131f5207bJohn Levon}
8141f5207bJohn Levon
8151f5207bJohn Levonvoid __negate_cond_stacks(void)
8161f5207bJohn Levon{
8171f5207bJohn Levon	struct stree *old_false, *old_true;
8181f5207bJohn Levon
8191f5207bJohn Levon	old_false = pop_stree(&cond_false_stack);
8201f5207bJohn Levon	old_true = pop_stree(&cond_true_stack);
8211f5207bJohn Levon	push_stree(&cond_false_stack, old_true);
8221f5207bJohn Levon	push_stree(&cond_true_stack, old_false);
8231f5207bJohn Levon}
8241f5207bJohn Levon
8251f5207bJohn Levonvoid __and_cond_states(void)
8261f5207bJohn Levon{
8271f5207bJohn Levon	and_stree_stack(&cond_true_stack);
8281f5207bJohn Levon	or_stree_stack(&pre_cond_stack, cur_stree, &cond_false_stack);
8291f5207bJohn Levon}
8301f5207bJohn Levon
8311f5207bJohn Levonvoid __or_cond_states(void)
8321f5207bJohn Levon{
8331f5207bJohn Levon	or_stree_stack(&pre_cond_stack, cur_stree, &cond_true_stack);
8341f5207bJohn Levon	and_stree_stack(&cond_false_stack);
8351f5207bJohn Levon}
8361f5207bJohn Levon
8371f5207bJohn Levonvoid __save_pre_cond_states(void)
8381f5207bJohn Levon{
8391f5207bJohn Levon	push_stree(&pre_cond_stack, clone_stree(cur_stree));
8401f5207bJohn Levon}
8411f5207bJohn Levon
8421f5207bJohn Levonvoid __discard_pre_cond_states(void)
8431f5207bJohn Levon{
8441f5207bJohn Levon	struct stree *tmp;
8451f5207bJohn Levon
8461f5207bJohn Levon	tmp = pop_stree(&pre_cond_stack);
8471f5207bJohn Levon	free_stree(&tmp);
8481f5207bJohn Levon}
8491f5207bJohn Levon
8501f5207bJohn Levonstruct stree *__get_true_states(void)
8511f5207bJohn Levon{
8521f5207bJohn Levon	return clone_stree(top_stree(cond_true_stack));
8531f5207bJohn Levon}
8541f5207bJohn Levon
8551f5207bJohn Levonstruct stree *__get_false_states(void)
8561f5207bJohn Levon{
8571f5207bJohn Levon	return clone_stree(top_stree(cond_false_stack));
8581f5207bJohn Levon}
8591f5207bJohn Levon
8601f5207bJohn Levonvoid __use_cond_states(void)
8611f5207bJohn Levon{
8621f5207bJohn Levon	struct stree *pre, *pre_clone, *true_states, *false_states;
8631f5207bJohn Levon
8641f5207bJohn Levon	pre = pop_stree(&pre_cond_stack);
8651f5207bJohn Levon	pre_clone = clone_stree(pre);
8661f5207bJohn Levon
8671f5207bJohn Levon	true_states = pop_stree(&cond_true_stack);
8681f5207bJohn Levon	overwrite_stree(true_states, &pre);
8691f5207bJohn Levon	free_stree(&true_states);
8701f5207bJohn Levon	/* we use the true states right away */
8711f5207bJohn Levon	free_stree(&cur_stree);
8721f5207bJohn Levon	cur_stree = pre;
8731f5207bJohn Levon
8741f5207bJohn Levon	false_states = pop_stree(&cond_false_stack);
8751f5207bJohn Levon	overwrite_stree(false_states, &pre_clone);
8761f5207bJohn Levon	free_stree(&false_states);
8771f5207bJohn Levon	push_stree(&false_stack, pre_clone);
8781f5207bJohn Levon}
8791f5207bJohn Levon
8801f5207bJohn Levonvoid __push_true_states(void)
8811f5207bJohn Levon{
8821f5207bJohn Levon	push_stree(&true_stack, clone_stree(cur_stree));
8831f5207bJohn Levon}
8841f5207bJohn Levon
8851f5207bJohn Levonvoid __use_false_states(void)
8861f5207bJohn Levon{
8871f5207bJohn Levon	free_stree(&cur_stree);
8881f5207bJohn Levon	cur_stree = pop_stree(&false_stack);
8891f5207bJohn Levon}
8901f5207bJohn Levon
8911f5207bJohn Levonvoid __discard_false_states(void)
8921f5207bJohn Levon{
8931f5207bJohn Levon	struct stree *stree;
8941f5207bJohn Levon
8951f5207bJohn Levon	stree = pop_stree(&false_stack);
8961f5207bJohn Levon	free_stree(&stree);
8971f5207bJohn Levon}
8981f5207bJohn Levon
8991f5207bJohn Levonvoid __merge_false_states(void)
9001f5207bJohn Levon{
9011f5207bJohn Levon	struct stree *stree;
9021f5207bJohn Levon
9031f5207bJohn Levon	stree = pop_stree(&false_stack);
9041f5207bJohn Levon	merge_stree(&cur_stree, stree);
9051f5207bJohn Levon	free_stree(&stree);
9061f5207bJohn Levon}
9071f5207bJohn Levon
9081f5207bJohn Levon/*
9091f5207bJohn Levon * This function probably seemed common sensical when I wrote it but, oh wow,
9101f5207bJohn Levon * does it look subtle in retrospect.  Say we set a state on one side of the if
9111f5207bJohn Levon * else path but not on the other, then what we should record in the fake stree
9121f5207bJohn Levon * is the merged state.
9131f5207bJohn Levon *
9141f5207bJohn Levon * This function relies on the fact that the we always set the cur_stree as well
9151f5207bJohn Levon * and we already have the infrastructure to merge things correctly into the
9161f5207bJohn Levon * cur_stree.
9171f5207bJohn Levon *
9181f5207bJohn Levon * So instead of merging fake strees together which is probably a lot of work,
9191f5207bJohn Levon * we just use it as a list of set states and look up the actual current values
9201f5207bJohn Levon * in the cur_stree.
9211f5207bJohn Levon *
9221f5207bJohn Levon */
9231f5207bJohn Levonstatic void update_stree_with_merged(struct stree **stree)
9241f5207bJohn Levon{
9251f5207bJohn Levon	struct state_list *slist = NULL;
9261f5207bJohn Levon	struct sm_state *sm, *new;
9271f5207bJohn Levon
9281f5207bJohn Levon	FOR_EACH_SM(*stree, sm) {
9291f5207bJohn Levon		new = get_sm_state(sm->owner, sm->name, sm->sym);
9301f5207bJohn Levon		if (!new)  /* This can happen if we go out of scope */
9311f5207bJohn Levon			continue;
9321f5207bJohn Levon		add_ptr_list(&slist, new);
9331f5207bJohn Levon	} END_FOR_EACH_SM(sm);
9341f5207bJohn Levon
9351f5207bJohn Levon	FOR_EACH_PTR(slist, sm) {
9361f5207bJohn Levon		overwrite_sm_state_stree(stree, sm);
9371f5207bJohn Levon	} END_FOR_EACH_PTR(sm);
9381f5207bJohn Levon
9391f5207bJohn Levon	free_slist(&slist);
9401f5207bJohn Levon}
9411f5207bJohn Levon
9421f5207bJohn Levonstatic void update_fake_stree_with_merged(void)
9431f5207bJohn Levon{
9441f5207bJohn Levon	struct stree *stree;
9451f5207bJohn Levon
9461f5207bJohn Levon	if (!fake_cur_stree_stack)
9471f5207bJohn Levon		return;
9481f5207bJohn Levon	stree = pop_stree(&fake_cur_stree_stack);
9491f5207bJohn Levon	update_stree_with_merged(&stree);
9501f5207bJohn Levon	push_stree(&fake_cur_stree_stack, stree);
9511f5207bJohn Levon}
9521f5207bJohn Levon
9531f5207bJohn Levonvoid __merge_true_states(void)
9541f5207bJohn Levon{
9551f5207bJohn Levon	struct stree *stree;
9561f5207bJohn Levon
9571f5207bJohn Levon	stree = pop_stree(&true_stack);
9581f5207bJohn Levon	merge_stree(&cur_stree, stree);
9591f5207bJohn Levon	update_fake_stree_with_merged();
9601f5207bJohn Levon	free_stree(&stree);
9611f5207bJohn Levon}
9621f5207bJohn Levon
9631f5207bJohn Levonvoid __push_continues(void)
9641f5207bJohn Levon{
9651f5207bJohn Levon	push_stree(&continue_stack, NULL);
9661f5207bJohn Levon}
9671f5207bJohn Levon
9681f5207bJohn Levonvoid __discard_continues(void)
9691f5207bJohn Levon{
9701f5207bJohn Levon	struct stree *stree;
9711f5207bJohn Levon
9721f5207bJohn Levon	stree = pop_stree(&continue_stack);
9731f5207bJohn Levon	free_stree(&stree);
9741f5207bJohn Levon}
9751f5207bJohn Levon
9761f5207bJohn Levonvoid __process_continues(void)
9771f5207bJohn Levon{
9781f5207bJohn Levon	struct stree *stree;
9791f5207bJohn Levon
9801f5207bJohn Levon	stree = pop_stree(&continue_stack);
9811f5207bJohn Levon	if (!stree)
9821f5207bJohn Levon		stree = clone_stree(cur_stree);
9831f5207bJohn Levon	else
9841f5207bJohn Levon		merge_stree(&stree, cur_stree);
9851f5207bJohn Levon
9861f5207bJohn Levon	push_stree(&continue_stack, stree);
9871f5207bJohn Levon}
9881f5207bJohn Levon
9891f5207bJohn Levonvoid __merge_continues(void)
9901f5207bJohn Levon{
9911f5207bJohn Levon	struct stree *stree;
9921f5207bJohn Levon
9931f5207bJohn Levon	stree = pop_stree(&continue_stack);
9941f5207bJohn Levon	merge_stree(&cur_stree, stree);
9951f5207bJohn Levon	free_stree(&stree);
9961f5207bJohn Levon}
9971f5207bJohn Levon
9981f5207bJohn Levonvoid __push_breaks(void)
9991f5207bJohn Levon{
10001f5207bJohn Levon	push_stree(&break_stack, NULL);
10011f5207bJohn Levon	if (fake_cur_stree_stack)
10021f5207bJohn Levon		push_stree(&fake_break_stack, NULL);
10031f5207bJohn Levon}
10041f5207bJohn Levon
10051f5207bJohn Levonvoid __process_breaks(void)
10061f5207bJohn Levon{
10071f5207bJohn Levon	struct stree *stree;
10081f5207bJohn Levon
10091f5207bJohn Levon	stree = pop_stree(&break_stack);
10101f5207bJohn Levon	if (!stree)
10111f5207bJohn Levon		stree = clone_stree(cur_stree);
10121f5207bJohn Levon	else
10131f5207bJohn Levon		merge_stree(&stree, cur_stree);
10141f5207bJohn Levon	push_stree(&break_stack, stree);
10151f5207bJohn Levon
10161f5207bJohn Levon	if (!fake_cur_stree_stack)
10171f5207bJohn Levon		return;
10181f5207bJohn Levon
10191f5207bJohn Levon	stree = pop_stree(&fake_break_stack);
10201f5207bJohn Levon	if (!stree)
10211f5207bJohn Levon		stree = clone_stree(top_stree(fake_cur_stree_stack));
10221f5207bJohn Levon	else
10231f5207bJohn Levon		merge_stree(&stree, top_stree(fake_cur_stree_stack));
10241f5207bJohn Levon	push_stree(&fake_break_stack, stree);
10251f5207bJohn Levon}
10261f5207bJohn Levon
10271f5207bJohn Levonint __has_breaks(void)
10281f5207bJohn Levon{
10291f5207bJohn Levon	struct stree *stree;
10301f5207bJohn Levon	int ret;
10311f5207bJohn Levon
10321f5207bJohn Levon	stree = pop_stree(&break_stack);
10331f5207bJohn Levon	ret = !!stree;
10341f5207bJohn Levon	push_stree(&break_stack, stree);
10351f5207bJohn Levon	return ret;
10361f5207bJohn Levon}
10371f5207bJohn Levon
10381f5207bJohn Levonvoid __merge_breaks(void)
10391f5207bJohn Levon{
10401f5207bJohn Levon	struct stree *stree;
10411f5207bJohn Levon	struct sm_state *sm;
10421f5207bJohn Levon
10431f5207bJohn Levon	stree = pop_stree(&break_stack);
10441f5207bJohn Levon	merge_stree(&cur_stree, stree);
10451f5207bJohn Levon	free_stree(&stree);
10461f5207bJohn Levon
10471f5207bJohn Levon	if (!fake_cur_stree_stack)
10481f5207bJohn Levon		return;
10491f5207bJohn Levon
10501f5207bJohn Levon	stree = pop_stree(&fake_break_stack);
10511f5207bJohn Levon	update_stree_with_merged(&stree);
10521f5207bJohn Levon	FOR_EACH_SM(stree, sm) {
10531f5207bJohn Levon		overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm);
10541f5207bJohn Levon	} END_FOR_EACH_SM(sm);
10551f5207bJohn Levon	free_stree(&stree);
1056