summaryrefslogtreecommitdiff
path: root/expr.c
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2013-01-15 08:32:18 -0800
committerAnas Nashif <anas.nashif@intel.com>2013-01-15 08:32:18 -0800
commit689b9dbb8d7f88ab91e7741932ed000b6e49be9a (patch)
tree463f5a1df8b2d35644c260e7bf6c8e0a26198af1 /expr.c
parent59749d048d9e452f049f9151735b5256756919c3 (diff)
downloadltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.tar.gz
ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.tar.bz2
ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.zip
Imported Upstream version 0.7.2upstream/0.7.2
Diffstat (limited to 'expr.c')
-rw-r--r--expr.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/expr.c b/expr.c
new file mode 100644
index 0000000..32860fd
--- /dev/null
+++ b/expr.c
@@ -0,0 +1,338 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+
+#include "expr.h"
+
+static void
+expr_init_common(struct expr_node *node, enum expr_node_kind kind)
+{
+ node->kind = kind;
+ node->lhs = NULL;
+ node->own_lhs = 0;
+ memset(&node->u, 0, sizeof(node->u));
+}
+
+void
+expr_init_self(struct expr_node *node)
+{
+ expr_init_common(node, EXPR_OP_SELF);
+}
+
+void
+expr_init_named(struct expr_node *node,
+ const char *name, int own_name)
+{
+ expr_init_common(node, EXPR_OP_NAMED);
+ node->u.name.s = name;
+ node->u.name.own = own_name;
+}
+
+void
+expr_init_argno(struct expr_node *node, size_t num)
+{
+ expr_init_common(node, EXPR_OP_ARGNO);
+ node->u.num = num;
+}
+
+void
+expr_init_const(struct expr_node *node, struct value *val)
+{
+ expr_init_common(node, EXPR_OP_CONST);
+ node->u.value = *val;
+}
+
+void
+expr_init_const_word(struct expr_node *node, long l,
+ struct arg_type_info *type, int own_type)
+{
+ struct value val;
+ value_init_detached(&val, NULL, type, own_type);
+ value_set_word(&val, l);
+ expr_init_const(node, &val);
+}
+
+void
+expr_init_index(struct expr_node *node,
+ struct expr_node *lhs, int own_lhs,
+ struct expr_node *rhs, int own_rhs)
+{
+ expr_init_common(node, EXPR_OP_INDEX);
+ node->lhs = lhs;
+ node->own_lhs = own_lhs;
+ node->u.node.n = rhs;
+ node->u.node.own = own_rhs;
+}
+
+void
+expr_init_up(struct expr_node *node, struct expr_node *lhs, int own_lhs)
+{
+ assert(lhs != NULL);
+ expr_init_common(node, EXPR_OP_UP);
+ node->lhs = lhs;
+ node->own_lhs = own_lhs;
+}
+
+void
+expr_init_cb1(struct expr_node *node,
+ int (*cb)(struct value *ret_value, struct value *value,
+ struct value_dict *arguments, void *data),
+ struct expr_node *lhs, int own_lhs, void *data)
+{
+ expr_init_common(node, EXPR_OP_CALL1);
+ node->lhs = lhs;
+ node->own_lhs = own_lhs;
+ node->u.call.u.cb1 = cb;
+ node->u.call.data = data;
+}
+
+void
+expr_init_cb2(struct expr_node *node,
+ int (*cb)(struct value *ret_value,
+ struct value *lhs, struct value *rhs,
+ struct value_dict *arguments, void *data),
+ struct expr_node *lhs, int own_lhs,
+ struct expr_node *rhs, int own_rhs, void *data)
+{
+ expr_init_common(node, EXPR_OP_CALL2);
+ node->lhs = lhs;
+ node->own_lhs = own_lhs;
+ node->u.call.rhs = rhs;
+ node->u.call.own_rhs = own_rhs;
+ node->u.call.u.cb2 = cb;
+ node->u.call.data = data;
+}
+
+static void
+release_expr(struct expr_node *node, int own)
+{
+ if (own) {
+ expr_destroy(node);
+ free(node);
+ }
+}
+
+void
+expr_destroy(struct expr_node *node)
+{
+ if (node == NULL)
+ return;
+
+ switch (node->kind) {
+ case EXPR_OP_ARGNO:
+ case EXPR_OP_SELF:
+ return;
+
+ case EXPR_OP_CONST:
+ value_destroy(&node->u.value);
+ return;
+
+ case EXPR_OP_NAMED:
+ if (node->u.name.own)
+ free((char *)node->u.name.s);
+ return;
+
+ case EXPR_OP_INDEX:
+ release_expr(node->lhs, node->own_lhs);
+ release_expr(node->u.node.n, node->u.node.own);
+ return;
+
+ case EXPR_OP_CALL2:
+ release_expr(node->u.call.rhs, node->u.call.own_rhs);
+ /* Fall through. */
+ case EXPR_OP_UP:
+ case EXPR_OP_CALL1:
+ release_expr(node->lhs, node->own_lhs);
+ return;
+ }
+
+ assert(!"Invalid value of node kind");
+ abort();
+}
+
+int
+expr_is_compile_constant(struct expr_node *node)
+{
+ return node->kind == EXPR_OP_CONST;
+}
+
+static int
+eval_up(struct expr_node *node, struct value *context,
+ struct value_dict *arguments, struct value *ret_value)
+{
+ if (expr_eval(node->lhs, context, arguments, ret_value) < 0)
+ return -1;
+ struct value *parent = value_get_parental_struct(ret_value);
+ if (parent == NULL) {
+ value_destroy(ret_value);
+ return -1;
+ }
+ *ret_value = *parent;
+ return 0;
+}
+
+static int
+eval_cb1(struct expr_node *node, struct value *context,
+ struct value_dict *arguments, struct value *ret_value)
+{
+ struct value val;
+ if (expr_eval(node->lhs, context, arguments, &val) < 0)
+ return -1;
+
+ int ret = 0;
+ if (node->u.call.u.cb1(ret_value, &val, arguments,
+ node->u.call.data) < 0)
+ ret = -1;
+
+ /* N.B. the callback must return its own value, or somehow
+ * clone the incoming argument. */
+ value_destroy(&val);
+ return ret;
+}
+
+static int
+eval_cb2(struct expr_node *node, struct value *context,
+ struct value_dict *arguments, struct value *ret_value)
+{
+ struct value lhs;
+ if (expr_eval(node->lhs, context, arguments, &lhs) < 0)
+ return -1;
+
+ struct value rhs;
+ if (expr_eval(node->u.call.rhs, context, arguments, &rhs) < 0) {
+ value_destroy(&lhs);
+ return -1;
+ }
+
+ int ret = 0;
+ if (node->u.call.u.cb2(ret_value, &lhs, &rhs, arguments,
+ node->u.call.data) < 0)
+ ret = -1;
+
+ /* N.B. the callback must return its own value, or somehow
+ * clone the incoming argument. */
+ value_destroy(&lhs);
+ value_destroy(&rhs);
+ return ret;
+}
+
+int
+eval_index(struct expr_node *node, struct value *context,
+ struct value_dict *arguments, struct value *ret_value)
+{
+ struct value lhs;
+ if (expr_eval(node->lhs, context, arguments, &lhs) < 0)
+ return -1;
+
+ long l;
+ if (expr_eval_word(node->u.node.n, context, arguments, &l) < 0) {
+ fail:
+ value_destroy(&lhs);
+ return -1;
+ }
+
+ if (value_init_element(ret_value, &lhs, (size_t)l) < 0)
+ goto fail;
+ return 0;
+}
+
+int
+expr_eval(struct expr_node *node, struct value *context,
+ struct value_dict *arguments, struct value *ret_value)
+{
+ switch (node->kind) {
+ struct value *valp;
+ case EXPR_OP_ARGNO:
+ valp = val_dict_get_num(arguments, node->u.num);
+ if (valp == NULL)
+ return -1;
+ *ret_value = *valp;
+ return 0;
+
+ case EXPR_OP_NAMED:
+ valp = val_dict_get_name(arguments, node->u.name.s);
+ if (valp == NULL)
+ return -1;
+ *ret_value = *valp;
+ return 0;
+
+ case EXPR_OP_SELF:
+ *ret_value = *context;
+ return 0;
+
+ case EXPR_OP_CONST:
+ *ret_value = node->u.value;
+ return 0;
+
+ case EXPR_OP_INDEX:
+ return eval_index(node, context, arguments, ret_value);
+
+ case EXPR_OP_UP:
+ return eval_up(node, context, arguments, ret_value);
+
+ case EXPR_OP_CALL1:
+ return eval_cb1(node, context, arguments, ret_value);
+
+ case EXPR_OP_CALL2:
+ return eval_cb2(node, context, arguments, ret_value);
+ }
+
+ assert(!"Unknown node kind.");
+ abort();
+}
+
+int
+expr_eval_word(struct expr_node *node, struct value *context,
+ struct value_dict *arguments, long *ret_value)
+{
+ struct value val;
+ if (expr_eval(node, context, arguments, &val) < 0)
+ return -1;
+ int ret = 0;
+ if (value_extract_word(&val, ret_value, arguments) < 0)
+ ret = -1;
+ value_destroy(&val);
+ return ret;
+}
+
+int
+expr_eval_constant(struct expr_node *node, long *valuep)
+{
+ assert(expr_is_compile_constant(node));
+ return expr_eval_word(node, NULL, NULL, valuep);
+}
+
+struct expr_node *
+expr_self(void)
+{
+ static struct expr_node *node = NULL;
+ if (node == NULL) {
+ node = malloc(sizeof(*node));
+ if (node == NULL)
+ error(1, errno, "malloc expr_self");
+ expr_init_self(node);
+ }
+ return node;
+}