summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Johnson <peter@tortall.net>2001-11-01 02:36:22 +0000
committerPeter Johnson <peter@tortall.net>2001-11-01 02:36:22 +0000
commitad7cbcea04cd2011d352f0e3a9984f43fdfd565f (patch)
treefba022727f74b96e9810deba12ecee6728896e76
parent00788fa80c52d3d8683fff6b2216bd59ad2acbdd (diff)
downloadyasm-ad7cbcea04cd2011d352f0e3a9984f43fdfd565f.tar.gz
Add memory expressions tests (checkea).
Split off errwarn functions so that they can be overridden in test cases. svn path=/trunk/yasm/; revision=309
-rw-r--r--libyasm/tests/Makefile.am39
-rw-r--r--libyasm/tests/memexpr_test.c422
-rw-r--r--src/Makefile.am7
-rw-r--r--src/tests/Makefile.am39
-rw-r--r--src/tests/memexpr_test.c422
5 files changed, 906 insertions, 23 deletions
diff --git a/libyasm/tests/Makefile.am b/libyasm/tests/Makefile.am
index 51edfab3..9c7d9920 100644
--- a/libyasm/tests/Makefile.am
+++ b/libyasm/tests/Makefile.am
@@ -6,34 +6,53 @@ if CHECK
TESTS = \
bitvect_test \
bytecode_test \
- floatnum_test
+ floatnum_test \
+ memexpr_test
noinst_PROGRAMS = \
bitvect_test \
bytecode_test \
- floatnum_test
+ floatnum_test \
+ memexpr_test
+
else
TESTS =
noinst_PROGRAMS =
endif
+LDADD = \
+ $(top_builddir)/check/libcheck.a \
+ $(top_builddir)/src/parsers/nasm/libparser.a \
+ $(top_builddir)/src/preprocs/raw/libpreproc.a \
+ $(top_builddir)/src/optimizers/dbg/liboptimizer.a \
+ $(top_builddir)/src/objfmts/dbg/libobjfmt.a \
+ $(top_builddir)/src/libyasm.a \
+ $(INTLLIBS)
+
bitvect_test_SOURCES = \
bitvect_test.c
+bitvect_test_LDADD = \
+ $(top_builddir)/src/errwarn.o \
+ $(LDADD)
+
bytecode_test_SOURCES = \
bytecode_test.c
+bytecode_test_LDADD = \
+ $(top_builddir)/src/errwarn.o \
+ $(LDADD)
+
floatnum_test_SOURCES = \
floatnum_test.c
+floatnum_test_LDADD = \
+ $(top_builddir)/src/errwarn.o \
+ $(LDADD)
+
+memexpr_test_SOURCES = \
+ memexpr_test.c
+
INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/check \
-I$(top_builddir)/intl
-LDADD = \
- $(top_builddir)/check/libcheck.a \
- $(top_builddir)/src/parsers/nasm/libparser.a \
- $(top_builddir)/src/preprocs/raw/libpreproc.a \
- $(top_builddir)/src/optimizers/dbg/liboptimizer.a \
- $(top_builddir)/src/objfmts/dbg/libobjfmt.a \
- $(top_builddir)/src/libyasm.a \
- $(INTLLIBS)
diff --git a/libyasm/tests/memexpr_test.c b/libyasm/tests/memexpr_test.c
new file mode 100644
index 00000000..6e0ae89d
--- /dev/null
+++ b/libyasm/tests/memexpr_test.c
@@ -0,0 +1,422 @@
+/* $IdPath$
+ *
+ * Copyright (C) 2001 Peter Johnson
+ *
+ * This file is part of YASM.
+ *
+ * YASM 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.
+ *
+ * YASM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <stdio.h>
+
+#include "check.h"
+
+#include "bitvect.h"
+
+#include "errwarn.h"
+
+#include "expr.h"
+#include "intnum.h"
+#include "floatnum.h"
+
+typedef enum {
+ REG_AX = 0,
+ REG_CX = 1,
+ REG_DX = 2,
+ REG_BX = 3,
+ REG_SP = 4,
+ REG_BP = 5,
+ REG_SI = 6,
+ REG_DI = 7
+} reg16type;
+
+/* Memory expression building functions.
+ * These try to exactly match how a parser will build up the expr for _in,
+ * and exactly what the output expr should be for _out.
+ */
+
+/* [5] */
+static expr *
+gen_5_in(void)
+{
+ return expr_new_ident(ExprInt(intnum_new_int(5)));
+}
+#define gen_5_out gen_5_in
+/* [1.2] */
+static expr *
+gen_1pt2_in(void)
+{
+ return expr_new_ident(ExprFloat(floatnum_new("1.2")));
+}
+/* No _out, it's invalid */
+/* [ecx] */
+static expr *
+gen_ecx_in(void)
+{
+ return expr_new_ident(ExprReg(REG_CX, 32));
+}
+#define gen_ecx_out NULL
+/* [di] */
+static expr *
+gen_di_in(void)
+{
+ return expr_new_ident(ExprReg(REG_DI, 16));
+}
+#define gen_di_out NULL
+/* [di-si+si+126] */
+static expr *
+gen_dimsipsip126_in(void)
+{
+ return expr_new_tree(
+ expr_new_tree(
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_DI, 16)),
+ EXPR_SUB,
+ expr_new_ident(ExprReg(REG_SI, 16))),
+ EXPR_ADD,
+ expr_new_ident(ExprReg(REG_SI, 16))),
+ EXPR_ADD,
+ expr_new_ident(ExprInt(intnum_new_int(126))));
+}
+#define gen_dimsipsip126_out NULL
+/* [bx-(bx-di)+bx-2] */
+static expr *
+gen_bxmqbxmdiqpbxm2_in(void)
+{
+ return expr_new_tree(
+ expr_new_tree(
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_BX, 16)),
+ EXPR_SUB,
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_BX, 16)),
+ EXPR_SUB,
+ expr_new_ident(ExprReg(REG_DI, 16)))),
+ EXPR_ADD,
+ expr_new_ident(ExprReg(REG_BX, 16))),
+ EXPR_SUB,
+ expr_new_ident(ExprInt(intnum_new_int(2))));
+}
+static expr *
+gen_bxmqbxmdiqpbxm2_out(void)
+{
+ return expr_new_ident(ExprInt(intnum_new_int(-2)));
+}
+/* [bp] */
+static expr *
+gen_bp_in(void)
+{
+ return expr_new_ident(ExprReg(REG_BP, 16));
+}
+#define gen_bp_out NULL
+/* [bp*1+500] */
+static expr *
+gen_bpx1p500_in(void)
+{
+ return expr_new_tree(
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_BP, 16)),
+ EXPR_MUL,
+ expr_new_ident(ExprInt(intnum_new_int(1)))),
+ EXPR_ADD,
+ expr_new_ident(ExprInt(intnum_new_int(500))));
+}
+static expr *
+gen_bpx1p500_out(void)
+{
+ return expr_new_ident(ExprInt(intnum_new_int(500)));
+}
+
+typedef struct CheckEA_InOut {
+ /* Function to generate input/output expr. */
+ expr *(*expr_gen)(void);
+ unsigned char addrsize;
+ unsigned char bits;
+ unsigned char nosplit;
+ unsigned char displen;
+ unsigned char modrm;
+ unsigned char v_modrm;
+ unsigned char n_modrm;
+ unsigned char sib;
+ unsigned char v_sib;
+ unsigned char n_sib;
+} CheckEA_InOut;
+
+typedef struct CheckEA_Entry {
+ const char *ascii; /* Text description of input */
+ CheckEA_InOut in; /* Input Parameter Values */
+ int retval; /* Return value */
+ CheckEA_InOut out; /* Correct output Parameter Values
+ (N/A if retval=0) */
+} CheckEA_Entry;
+
+/* Values used for tests */
+static CheckEA_Entry bits16_vals[] = {
+ {
+ "[5]",
+ {gen_5_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1, 0, 0, 0}
+ },
+ {
+ "a16 [5]",
+ {gen_5_in , 16, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1, 0, 0, 0}
+ },
+ {
+ "a32 [5]",
+ {gen_5_in , 32, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1, 1}
+ },
+ {
+ "[word 5]",
+ {gen_5_in , 0, 16, 0, 2, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1, 0, 0, 0}
+ },
+ {
+ "[dword 5]",
+ {gen_5_in , 0, 16, 0, 4, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1, 1}
+ },
+ {
+ "a16 [dword 5]",
+ {gen_5_in, 16, 16, 0, 4, 0, 0, 1, 0, 0, 0xff},
+ 0,
+ {NULL , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ /* should error */
+ {
+ "[di+1.2]",
+ {gen_1pt2_in, 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 0,
+ {NULL , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ {
+ "[ecx]",
+ {gen_ecx_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_ecx_out, 32, 16, 0, 0, 0x01, 1, 1, 0, 0, 0}
+ },
+ /* should error */
+ {
+ "a16 [ecx]",
+ {gen_ecx_in, 16, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 0,
+ {NULL , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ {
+ "[di]",
+ {gen_di_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_di_out, 16, 16, 0, 0, 0x05, 1, 1, 0, 0, 0}
+ },
+ {
+ "[di-si+si+126]",
+ {gen_dimsipsip126_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_dimsipsip126_out, 16, 16, 0, 1, 0x45, 1, 1, 0, 0, 0}
+ },
+ {
+ "[bx-(bx-di)+bx-2]",
+ {gen_bxmqbxmdiqpbxm2_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_bxmqbxmdiqpbxm2_out, 16, 16, 0, 1, 0x41, 1, 1, 0, 0, 0}
+ },
+ {
+ "[bp]",
+ {gen_bp_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_bp_out, 16, 16, 0, 1, 0x46, 1, 1, 0, 0, 0}
+ },
+ {
+ "[bp*1+500]",
+ {gen_bpx1p500_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_bpx1p500_out, 16, 16, 0, 2, 0x86, 1, 1, 0, 0, 0}
+ },
+};
+
+/* input expression */
+expr *expn;
+
+/* failure messages */
+static char result_msg[1024];
+
+int error_triggered;
+
+/* Replace errwarn functions */
+void InternalError_(const char *file, unsigned int line, const char *msg)
+{
+ exit(EXIT_FAILURE);
+}
+
+void
+Fatal(fatal_num num)
+{
+ exit(EXIT_FAILURE);
+}
+
+void
+Error(const char *msg, ...)
+{
+ error_triggered = 1;
+}
+
+void
+Warning(const char *msg, ...)
+{
+}
+
+void
+ErrorAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+ error_triggered = 1;
+}
+
+void
+WarningAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+}
+
+static int
+checkea_check(CheckEA_Entry *val)
+{
+ CheckEA_InOut chk = val->in; /* local structure copy of inputs */
+ int retval;
+
+ error_triggered = 0;
+
+ /* execute function and check return value */
+ retval = expr_checkea(&expn, &chk.addrsize, chk.bits, chk.nosplit,
+ &chk.displen, &chk.modrm, &chk.v_modrm, &chk.n_modrm,
+ &chk.sib, &chk.v_sib, &chk.n_sib);
+ if (retval != val->retval) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "return value", val->retval, retval);
+ return 1;
+ }
+
+ /* If returned 0 (failure), check to see if ErrorAt() was called */
+ if (retval == 0) {
+ if (error_triggered == 0) {
+ sprintf(result_msg, "%s: didn't call ErrorAt() and returned 0",
+ val->ascii);
+ return 1;
+ }
+
+ return 0; /* don't check other return values */
+ }
+
+ /* check expr result */
+ /* TODO */
+
+ /* Check other outputs */
+ if (chk.addrsize != val->out.addrsize) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "addrsize", (int)val->out.addrsize,
+ (int)chk.addrsize);
+ return 1;
+ }
+ if (chk.displen != val->out.displen) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "displen", (int)val->out.displen,
+ (int)chk.displen);
+ return 1;
+ }
+ if (chk.modrm != val->out.modrm) {
+ sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+ val->ascii, "modrm", (int)val->out.modrm, (int)chk.modrm);
+ return 1;
+ }
+ if (chk.v_modrm != val->out.v_modrm) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "v_modrm", (int)val->out.v_modrm,
+ (int)chk.v_modrm);
+ return 1;
+ }
+ if (chk.n_modrm != val->out.n_modrm) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "n_modrm", (int)val->out.n_modrm,
+ (int)chk.n_modrm);
+ return 1;
+ }
+ if (chk.sib != val->out.sib) {
+ sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+ val->ascii, "sib", (int)val->out.sib, (int)chk.sib);
+ return 1;
+ }
+ if (chk.v_sib != val->out.v_sib) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "v_sib", (int)val->out.v_sib, (int)chk.v_sib);
+ return 1;
+ }
+ if (chk.n_sib != val->out.n_sib) {
+ sprintf(result_msg, "%s: incorrect %s (expected %x, got %x)",
+ val->ascii, "n_sib", (int)val->out.n_sib, (int)chk.n_sib);
+ return 1;
+ }
+ return 0;
+}
+
+START_TEST(test_checkea_bits16)
+{
+ CheckEA_Entry *vals = bits16_vals;
+ int i, num = sizeof(bits16_vals)/sizeof(CheckEA_Entry);
+
+ for (i=0; i<num; i++) {
+ expn = vals[i].in.expr_gen();
+ fail_unless(checkea_check(&vals[i]) == 0, result_msg);
+ expr_delete(expn);
+ }
+}
+END_TEST
+
+static Suite *
+memexpr_suite(void)
+{
+ Suite *s = suite_create("memexpr");
+ TCase *tc_checkea = tcase_create("checkea");
+
+ suite_add_tcase(s, tc_checkea);
+ tcase_add_test(tc_checkea, test_checkea_bits16);
+
+ return s;
+}
+
+int
+main(void)
+{
+ int nf;
+ Suite *s = memexpr_suite();
+ SRunner *sr = srunner_create(s);
+ BitVector_Boot();
+ srunner_run_all(sr, CRNORMAL);
+ nf = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ suite_free(s);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 16dc8998..30d5aa31 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,7 +6,10 @@ INCLUDES = -I$(top_builddir)/intl
bin_PROGRAMS = yasm
-yasm_SOURCES = main.c
+yasm_SOURCES = \
+ main.c \
+ errwarn.c \
+ errwarn.h
yasm_LDADD = \
parsers/nasm/libparser.a \
@@ -21,8 +24,6 @@ noinst_LIBRARIES = libyasm.a
libyasm_a_SOURCES = \
bytecode.c \
bytecode.h \
- errwarn.c \
- errwarn.h \
expr.c \
expr.h \
symrec.c \
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 51edfab3..9c7d9920 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -6,34 +6,53 @@ if CHECK
TESTS = \
bitvect_test \
bytecode_test \
- floatnum_test
+ floatnum_test \
+ memexpr_test
noinst_PROGRAMS = \
bitvect_test \
bytecode_test \
- floatnum_test
+ floatnum_test \
+ memexpr_test
+
else
TESTS =
noinst_PROGRAMS =
endif
+LDADD = \
+ $(top_builddir)/check/libcheck.a \
+ $(top_builddir)/src/parsers/nasm/libparser.a \
+ $(top_builddir)/src/preprocs/raw/libpreproc.a \
+ $(top_builddir)/src/optimizers/dbg/liboptimizer.a \
+ $(top_builddir)/src/objfmts/dbg/libobjfmt.a \
+ $(top_builddir)/src/libyasm.a \
+ $(INTLLIBS)
+
bitvect_test_SOURCES = \
bitvect_test.c
+bitvect_test_LDADD = \
+ $(top_builddir)/src/errwarn.o \
+ $(LDADD)
+
bytecode_test_SOURCES = \
bytecode_test.c
+bytecode_test_LDADD = \
+ $(top_builddir)/src/errwarn.o \
+ $(LDADD)
+
floatnum_test_SOURCES = \
floatnum_test.c
+floatnum_test_LDADD = \
+ $(top_builddir)/src/errwarn.o \
+ $(LDADD)
+
+memexpr_test_SOURCES = \
+ memexpr_test.c
+
INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/check \
-I$(top_builddir)/intl
-LDADD = \
- $(top_builddir)/check/libcheck.a \
- $(top_builddir)/src/parsers/nasm/libparser.a \
- $(top_builddir)/src/preprocs/raw/libpreproc.a \
- $(top_builddir)/src/optimizers/dbg/liboptimizer.a \
- $(top_builddir)/src/objfmts/dbg/libobjfmt.a \
- $(top_builddir)/src/libyasm.a \
- $(INTLLIBS)
diff --git a/src/tests/memexpr_test.c b/src/tests/memexpr_test.c
new file mode 100644
index 00000000..6e0ae89d
--- /dev/null
+++ b/src/tests/memexpr_test.c
@@ -0,0 +1,422 @@
+/* $IdPath$
+ *
+ * Copyright (C) 2001 Peter Johnson
+ *
+ * This file is part of YASM.
+ *
+ * YASM 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.
+ *
+ * YASM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <stdio.h>
+
+#include "check.h"
+
+#include "bitvect.h"
+
+#include "errwarn.h"
+
+#include "expr.h"
+#include "intnum.h"
+#include "floatnum.h"
+
+typedef enum {
+ REG_AX = 0,
+ REG_CX = 1,
+ REG_DX = 2,
+ REG_BX = 3,
+ REG_SP = 4,
+ REG_BP = 5,
+ REG_SI = 6,
+ REG_DI = 7
+} reg16type;
+
+/* Memory expression building functions.
+ * These try to exactly match how a parser will build up the expr for _in,
+ * and exactly what the output expr should be for _out.
+ */
+
+/* [5] */
+static expr *
+gen_5_in(void)
+{
+ return expr_new_ident(ExprInt(intnum_new_int(5)));
+}
+#define gen_5_out gen_5_in
+/* [1.2] */
+static expr *
+gen_1pt2_in(void)
+{
+ return expr_new_ident(ExprFloat(floatnum_new("1.2")));
+}
+/* No _out, it's invalid */
+/* [ecx] */
+static expr *
+gen_ecx_in(void)
+{
+ return expr_new_ident(ExprReg(REG_CX, 32));
+}
+#define gen_ecx_out NULL
+/* [di] */
+static expr *
+gen_di_in(void)
+{
+ return expr_new_ident(ExprReg(REG_DI, 16));
+}
+#define gen_di_out NULL
+/* [di-si+si+126] */
+static expr *
+gen_dimsipsip126_in(void)
+{
+ return expr_new_tree(
+ expr_new_tree(
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_DI, 16)),
+ EXPR_SUB,
+ expr_new_ident(ExprReg(REG_SI, 16))),
+ EXPR_ADD,
+ expr_new_ident(ExprReg(REG_SI, 16))),
+ EXPR_ADD,
+ expr_new_ident(ExprInt(intnum_new_int(126))));
+}
+#define gen_dimsipsip126_out NULL
+/* [bx-(bx-di)+bx-2] */
+static expr *
+gen_bxmqbxmdiqpbxm2_in(void)
+{
+ return expr_new_tree(
+ expr_new_tree(
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_BX, 16)),
+ EXPR_SUB,
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_BX, 16)),
+ EXPR_SUB,
+ expr_new_ident(ExprReg(REG_DI, 16)))),
+ EXPR_ADD,
+ expr_new_ident(ExprReg(REG_BX, 16))),
+ EXPR_SUB,
+ expr_new_ident(ExprInt(intnum_new_int(2))));
+}
+static expr *
+gen_bxmqbxmdiqpbxm2_out(void)
+{
+ return expr_new_ident(ExprInt(intnum_new_int(-2)));
+}
+/* [bp] */
+static expr *
+gen_bp_in(void)
+{
+ return expr_new_ident(ExprReg(REG_BP, 16));
+}
+#define gen_bp_out NULL
+/* [bp*1+500] */
+static expr *
+gen_bpx1p500_in(void)
+{
+ return expr_new_tree(
+ expr_new_tree(
+ expr_new_ident(ExprReg(REG_BP, 16)),
+ EXPR_MUL,
+ expr_new_ident(ExprInt(intnum_new_int(1)))),
+ EXPR_ADD,
+ expr_new_ident(ExprInt(intnum_new_int(500))));
+}
+static expr *
+gen_bpx1p500_out(void)
+{
+ return expr_new_ident(ExprInt(intnum_new_int(500)));
+}
+
+typedef struct CheckEA_InOut {
+ /* Function to generate input/output expr. */
+ expr *(*expr_gen)(void);
+ unsigned char addrsize;
+ unsigned char bits;
+ unsigned char nosplit;
+ unsigned char displen;
+ unsigned char modrm;
+ unsigned char v_modrm;
+ unsigned char n_modrm;
+ unsigned char sib;
+ unsigned char v_sib;
+ unsigned char n_sib;
+} CheckEA_InOut;
+
+typedef struct CheckEA_Entry {
+ const char *ascii; /* Text description of input */
+ CheckEA_InOut in; /* Input Parameter Values */
+ int retval; /* Return value */
+ CheckEA_InOut out; /* Correct output Parameter Values
+ (N/A if retval=0) */
+} CheckEA_Entry;
+
+/* Values used for tests */
+static CheckEA_Entry bits16_vals[] = {
+ {
+ "[5]",
+ {gen_5_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1, 0, 0, 0}
+ },
+ {
+ "a16 [5]",
+ {gen_5_in , 16, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1, 0, 0, 0}
+ },
+ {
+ "a32 [5]",
+ {gen_5_in , 32, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1, 1}
+ },
+ {
+ "[word 5]",
+ {gen_5_in , 0, 16, 0, 2, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 16, 16, 0, 2, 0x06, 1, 1, 0, 0, 0}
+ },
+ {
+ "[dword 5]",
+ {gen_5_in , 0, 16, 0, 4, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_5_out, 32, 16, 0, 4, 0x05, 1, 1, 0x25, 1, 1}
+ },
+ {
+ "a16 [dword 5]",
+ {gen_5_in, 16, 16, 0, 4, 0, 0, 1, 0, 0, 0xff},
+ 0,
+ {NULL , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ /* should error */
+ {
+ "[di+1.2]",
+ {gen_1pt2_in, 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 0,
+ {NULL , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ {
+ "[ecx]",
+ {gen_ecx_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_ecx_out, 32, 16, 0, 0, 0x01, 1, 1, 0, 0, 0}
+ },
+ /* should error */
+ {
+ "a16 [ecx]",
+ {gen_ecx_in, 16, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 0,
+ {NULL , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ },
+ {
+ "[di]",
+ {gen_di_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_di_out, 16, 16, 0, 0, 0x05, 1, 1, 0, 0, 0}
+ },
+ {
+ "[di-si+si+126]",
+ {gen_dimsipsip126_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_dimsipsip126_out, 16, 16, 0, 1, 0x45, 1, 1, 0, 0, 0}
+ },
+ {
+ "[bx-(bx-di)+bx-2]",
+ {gen_bxmqbxmdiqpbxm2_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_bxmqbxmdiqpbxm2_out, 16, 16, 0, 1, 0x41, 1, 1, 0, 0, 0}
+ },
+ {
+ "[bp]",
+ {gen_bp_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_bp_out, 16, 16, 0, 1, 0x46, 1, 1, 0, 0, 0}
+ },
+ {
+ "[bp*1+500]",
+ {gen_bpx1p500_in , 0, 16, 0, 0, 0, 0, 1, 0, 0, 0xff},
+ 1,
+ {gen_bpx1p500_out, 16, 16, 0, 2, 0x86, 1, 1, 0, 0, 0}
+ },
+};
+
+/* input expression */
+expr *expn;
+
+/* failure messages */
+static char result_msg[1024];
+
+int error_triggered;
+
+/* Replace errwarn functions */
+void InternalError_(const char *file, unsigned int line, const char *msg)
+{
+ exit(EXIT_FAILURE);
+}
+
+void
+Fatal(fatal_num num)
+{
+ exit(EXIT_FAILURE);
+}
+
+void
+Error(const char *msg, ...)
+{
+ error_triggered = 1;
+}
+
+void
+Warning(const char *msg, ...)
+{
+}
+
+void
+ErrorAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+ error_triggered = 1;
+}
+
+void
+WarningAt(const char *filename, unsigned long line, const char *fmt, ...)
+{
+}
+
+static int
+checkea_check(CheckEA_Entry *val)
+{
+ CheckEA_InOut chk = val->in; /* local structure copy of inputs */
+ int retval;
+
+ error_triggered = 0;
+
+ /* execute function and check return value */
+ retval = expr_checkea(&expn, &chk.addrsize, chk.bits, chk.nosplit,
+ &chk.displen, &chk.modrm, &chk.v_modrm, &chk.n_modrm,
+ &chk.sib, &chk.v_sib, &chk.n_sib);
+ if (retval != val->retval) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "return value", val->retval, retval);
+ return 1;
+ }
+
+ /* If returned 0 (failure), check to see if ErrorAt() was called */
+ if (retval == 0) {
+ if (error_triggered == 0) {
+ sprintf(result_msg, "%s: didn't call ErrorAt() and returned 0",
+ val->ascii);
+ return 1;
+ }
+
+ return 0; /* don't check other return values */
+ }
+
+ /* check expr result */
+ /* TODO */
+
+ /* Check other outputs */
+ if (chk.addrsize != val->out.addrsize) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "addrsize", (int)val->out.addrsize,
+ (int)chk.addrsize);
+ return 1;
+ }
+ if (chk.displen != val->out.displen) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "displen", (int)val->out.displen,
+ (int)chk.displen);
+ return 1;
+ }
+ if (chk.modrm != val->out.modrm) {
+ sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+ val->ascii, "modrm", (int)val->out.modrm, (int)chk.modrm);
+ return 1;
+ }
+ if (chk.v_modrm != val->out.v_modrm) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "v_modrm", (int)val->out.v_modrm,
+ (int)chk.v_modrm);
+ return 1;
+ }
+ if (chk.n_modrm != val->out.n_modrm) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "n_modrm", (int)val->out.n_modrm,
+ (int)chk.n_modrm);
+ return 1;
+ }
+ if (chk.sib != val->out.sib) {
+ sprintf(result_msg, "%s: incorrect %s (expected %03o, got %03o)",
+ val->ascii, "sib", (int)val->out.sib, (int)chk.sib);
+ return 1;
+ }
+ if (chk.v_sib != val->out.v_sib) {
+ sprintf(result_msg, "%s: incorrect %s (expected %d, got %d)",
+ val->ascii, "v_sib", (int)val->out.v_sib, (int)chk.v_sib);
+ return 1;
+ }
+ if (chk.n_sib != val->out.n_sib) {
+ sprintf(result_msg, "%s: incorrect %s (expected %x, got %x)",
+ val->ascii, "n_sib", (int)val->out.n_sib, (int)chk.n_sib);
+ return 1;
+ }
+ return 0;
+}
+
+START_TEST(test_checkea_bits16)
+{
+ CheckEA_Entry *vals = bits16_vals;
+ int i, num = sizeof(bits16_vals)/sizeof(CheckEA_Entry);
+
+ for (i=0; i<num; i++) {
+ expn = vals[i].in.expr_gen();
+ fail_unless(checkea_check(&vals[i]) == 0, result_msg);
+ expr_delete(expn);
+ }
+}
+END_TEST
+
+static Suite *
+memexpr_suite(void)
+{
+ Suite *s = suite_create("memexpr");
+ TCase *tc_checkea = tcase_create("checkea");
+
+ suite_add_tcase(s, tc_checkea);
+ tcase_add_test(tc_checkea, test_checkea_bits16);
+
+ return s;
+}
+
+int
+main(void)
+{
+ int nf;
+ Suite *s = memexpr_suite();
+ SRunner *sr = srunner_create(s);
+ BitVector_Boot();
+ srunner_run_all(sr, CRNORMAL);
+ nf = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ suite_free(s);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}