--- /dev/null	Fri Dec 21 15:00:37 2018
+++ new/usr/src/tools/smatch/src/smatch_var_sym.c	Fri Dec 21 15:00:37 2018
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2013 Oracle.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
+ */
+
+#include "smatch.h"
+
+ALLOCATOR(var_sym, "var_sym structs");
+
+struct var_sym *alloc_var_sym(const char *var, struct symbol *sym)
+{
+	struct var_sym *tmp;
+
+	tmp = __alloc_var_sym(0);
+	tmp->var = alloc_string(var);
+	tmp->sym = sym;
+	return tmp;
+}
+
+struct var_sym_list *expr_to_vsl(struct expression *expr)
+{
+	struct expression *unop;
+	struct var_sym_list *ret = NULL;
+	char *var;
+	struct symbol *sym;
+
+	expr = strip_expr(expr);
+	if (!expr)
+		return NULL;
+
+	if ((expr->type == EXPR_PREOP && expr->op == '*')) {
+		unop = strip_expr(expr->unop);
+
+		if (unop->type == EXPR_SYMBOL)
+			goto one_var;
+		return expr_to_vsl(unop);
+	}
+
+	if (expr->type == EXPR_BINOP ||
+	    expr->type == EXPR_LOGICAL ||
+	    expr->type == EXPR_COMPARE) {
+		struct var_sym_list *left, *right;
+
+		left = expr_to_vsl(expr->left);
+		right = expr_to_vsl(expr->right);
+		ret = combine_var_sym_lists(left, right);
+		free_var_syms_and_list(&left);
+		free_var_syms_and_list(&right);
+		return ret;
+	}
+
+	if (expr->type == EXPR_DEREF)
+		return expr_to_vsl(expr->deref);
+
+one_var:
+	var = expr_to_var_sym(expr, &sym);
+	if (!var || !sym) {
+		free_string(var);
+		return NULL;
+	}
+	add_var_sym(&ret, var, sym);
+	return ret;
+}
+
+int cmp_var_sym(const struct var_sym *a, const struct var_sym *b)
+{
+	int ret;
+
+	if (a == b)
+		return 0;
+	if (!b)
+		return -1;
+	if (!a)
+		return 1;
+
+	ret = strcmp(a->var, b->var);
+	if (ret < 0)
+		return -1;
+	if (ret > 0)
+		return 1;
+
+	if (!b->sym && a->sym)
+		return -1;
+	if (!a->sym && b->sym)
+		return 1;
+	if (a->sym < b->sym)
+		return -1;
+	if (a->sym > b->sym)
+		return 1;
+
+	return 0;
+}
+
+void add_var_sym(struct var_sym_list **list, const char *var, struct symbol *sym)
+{
+	struct var_sym *tmp, *new;
+
+	if (in_var_sym_list(*list, var, sym))
+		return;
+	new = alloc_var_sym(var, sym);
+
+	FOR_EACH_PTR(*list, tmp) {
+		if (cmp_var_sym(tmp, new) < 0)
+			continue;
+		else if (cmp_var_sym(tmp, new) == 0) {
+			return;
+		} else {
+			INSERT_CURRENT(new, tmp);
+			return;
+		}
+	} END_FOR_EACH_PTR(tmp);
+	add_ptr_list(list, new);
+}
+
+void add_var_sym_expr(struct var_sym_list **list, struct expression *expr)
+{
+	char *var;
+	struct symbol *sym;
+
+	var = expr_to_var_sym(expr, &sym);
+	if (!var || !sym)
+		goto free;
+	add_var_sym(list, var, sym);
+free:
+	free_string(var);
+}
+
+static void free_var_sym(struct var_sym *vs)
+{
+	free_string(vs->var);
+	__free_var_sym(vs);
+}
+
+void del_var_sym(struct var_sym_list **list, const char *var, struct symbol *sym)
+{
+	struct var_sym *tmp;
+
+	FOR_EACH_PTR(*list, tmp) {
+		if (tmp->sym == sym && strcmp(tmp->var, var) == 0) {
+			DELETE_CURRENT_PTR(tmp);
+			free_var_sym(tmp);
+			return;
+		}
+	} END_FOR_EACH_PTR(tmp);
+}
+
+int in_var_sym_list(struct var_sym_list *list, const char *var, struct symbol *sym)
+{
+	struct var_sym *tmp;
+
+	FOR_EACH_PTR(list, tmp) {
+		if (tmp->sym == sym && strcmp(tmp->var, var) == 0)
+			return 1;
+	} END_FOR_EACH_PTR(tmp);
+	return 0;
+}
+
+struct var_sym_list *clone_var_sym_list(struct var_sym_list *from_vsl)
+{
+	struct var_sym *tmp, *clone_vs;
+	struct var_sym_list *to_vsl = NULL;
+
+	FOR_EACH_PTR(from_vsl, tmp) {
+		clone_vs = alloc_var_sym(tmp->var, tmp->sym);
+		add_ptr_list(&to_vsl, clone_vs);
+	} END_FOR_EACH_PTR(tmp);
+	return to_vsl;
+}
+
+void merge_var_sym_list(struct var_sym_list **dest, struct var_sym_list *src)
+{
+	struct var_sym *tmp;
+
+	FOR_EACH_PTR(src, tmp) {
+		add_var_sym(dest, tmp->var, tmp->sym);
+	} END_FOR_EACH_PTR(tmp);
+}
+
+struct var_sym_list *combine_var_sym_lists(struct var_sym_list *one, struct var_sym_list *two)
+{
+	struct var_sym_list *to_vsl;
+
+	to_vsl = clone_var_sym_list(one);
+	merge_var_sym_list(&to_vsl, two);
+	return to_vsl;
+}
+
+int var_sym_lists_equiv(struct var_sym_list *one, struct var_sym_list *two)
+{
+	struct var_sym *one_tmp, *two_tmp;
+
+	if (one == two)
+		return 1;
+
+	if (ptr_list_size((struct ptr_list *)one) != ptr_list_size((struct ptr_list *)two))
+		return 0;
+
+	PREPARE_PTR_LIST(one, one_tmp);
+	PREPARE_PTR_LIST(two, two_tmp);
+	for (;;) {
+		if (!one_tmp && !two_tmp)
+			return 1;
+		if (one_tmp->sym != two_tmp->sym)
+			return 0;
+		if (strcmp(one_tmp->var, two_tmp->var) != 0)
+			return 0;
+		NEXT_PTR_LIST(one_tmp);
+		NEXT_PTR_LIST(two_tmp);
+	}
+	FINISH_PTR_LIST(two_tmp);
+	FINISH_PTR_LIST(one_tmp);
+
+	return 1;
+}
+
+void free_var_sym_list(struct var_sym_list **list)
+{
+	__free_ptr_list((struct ptr_list **)list);
+}
+
+void free_var_syms_and_list(struct var_sym_list **list)
+{
+	struct var_sym *tmp;
+
+	FOR_EACH_PTR(*list, tmp) {
+		free_var_sym(tmp);
+	} END_FOR_EACH_PTR(tmp);
+	free_var_sym_list(list);
+}
+
