Add 2 tests none/tests/libvex_test and libvexmultiarch_test

The objective of libvex_test is to verify that the VEX lib
can be used in 'single arch mode' (host == guest).

The objective of libvexmultiarch_test is to verify that the VEX lib
can be used in 'multi arch mode' (freely choose host and guest).
(but not many combinations are working: if wordsize or endianess
differs, then libVEX quickly asserts somewhere).

libvex_test.c is somewhat bizarre, as it uses the architecture
for which we have compiled as the guest, and use a 'foreign' arch
as the host.
That allows to avoid having to define in the test a bunch
of arch specific asm instructions : the test just decode a part
of its own code, and translate it to other archs.

By default, only the combination host == guest is run.
Arguments must be given to run other combinations.
See libvex_test.c for a description on how to specify which combinations
to run.

LibVEX host != guest does not (yet?) work when endianess or word size differs
between host and guest.

Also, currently, TILEGX host is not working properly (unless guest is also
TILEGX), as the evcheck instructions generated differs according to
the offset of the host_EvC_{FAILADDR,COUNTER}.

So, using TILEGX as host is only done when guest is also TILEGX.

Note that it is possible to specify a specific host arch to use.
For example, to force TILEGX to be used, do:
./none/tests/libvexmultiarch_test 1034
(where 1034 is the decimal value corresponding to the enum VexArchTILEGX.
This currently aborts with:
...
------------------------ Assembly ------------------------

EvCheck   (evCheck) ld r11, 8(r50); addli r11, r11, -1; st r11, 8(r50); bgez r11, nofail; jalr *(r50); nofail:

vex: priv/host_tilegx_defs.c:2353 (emit_TILEGXInstr): Assertion `evCheckSzB_TILEGX() == (UChar*)p - (UChar*)p0' failed.
//// failure exit called by libVEX
Whe TILEGX is fixed, we can remove the specific condition that avoids using
TILEGX as host.


Small changes have been done on VEX to allow more combinations
to work:
* host_mips_defs.c : when not compiled on mips,
  a lot of mips specific code is not compiled at all, because
  one of _MIPSEL or _MIPSEB must be defined to have either the
  little endian code or big endian code.
  emit32 function must however work to use mips as host.
  So, for this function, if _MIPSEL is not defined, then
  the big endian code is compiled in by default.
  (the mips endianess should probably be handled like the ppc
   endianess, for which the endianness to use is decided at runtime).

* host_arm64_isel.c : addition of a 'do not emit anything' for
   ABI HINT (avoid an assert e.g. for amd64 guest, arm64 host)

* libvex_guest_amd64.h : when I was still hoping mixing amd64 and x86,
  a first assert was firing up due to size/alignment
  of VexGuestAMD64State when compiled in 32 bits.
  => addition of pad elements to ensure the size and alignment
  of VexGuestAMD64State stays the same when compiled in 32 and
  64 bits (the 64 bits layout is unchanged).


The new tests have been run on x86/amd64/ppc64/s390x.
It is very well possible that the tests will fail on untested archs
(ppc32 or mips* or arm* or tilegx)
(e.g. because the hardcoded hwcaps in libvex_test.c are not ok).
It should be relatively trivial to fix these hwcaps problems.
Some other problems might be less easy to understand and fix 
(e.g. similar to the TILEGX evcheck or mips emit32 problem).



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15084 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am
index fb1db5d..8997064 100644
--- a/none/tests/Makefile.am
+++ b/none/tests/Makefile.am
@@ -109,6 +109,8 @@
 	gxx304.stderr.exp gxx304.vgtest \
 	ifunc.stderr.exp ifunc.stdout.exp ifunc.vgtest \
 	ioctl_moans.stderr.exp ioctl_moans.vgtest \
+	libvex_test.stderr.exp libvex_test.vgtest \
+	libvexmultiarch_test.stderr.exp libvexmultiarch_test.vgtest \
 	manythreads.stdout.exp manythreads.stderr.exp manythreads.vgtest \
 	map_unaligned.stderr.exp map_unaligned.vgtest \
 	map_unmap.stderr.exp map_unmap.stdout.exp map_unmap.vgtest \
@@ -183,6 +185,8 @@
 	fdleak_socketpair \
 	floored fork fucomip \
 	ioctl_moans \
+	libvex_test \
+	libvexmultiarch_test \
 	manythreads \
 	mmap_fcntl_bug \
 	munmap_exe map_unaligned map_unmap mq \
@@ -240,6 +244,11 @@
  nestedfns_CFLAGS	= $(AM_CFLAGS)
  mq_LDADD		= -lrt
 endif
+libvex_test_LDADD       = ../../VEX/libvex-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a
+libvexmultiarch_test_LDADD = \
+	../../VEX/libvexmultiarch-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a \
+	../../VEX/libvex-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a
+libvexmultiarch_test_SOURCES = libvex_test.c
 pth_atfork1_LDADD	= -lpthread
 pth_blockedsig_LDADD	= -lpthread
 pth_cancel1_CFLAGS	= $(AM_CFLAGS) -Wno-shadow
diff --git a/none/tests/libvex_test.c b/none/tests/libvex_test.c
new file mode 100644
index 0000000..4bf6024
--- /dev/null
+++ b/none/tests/libvex_test.c
@@ -0,0 +1,266 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "../../VEX/pub/libvex.h"
+
+Bool return_false(void*cb, Addr ad)
+{
+   return False;
+}
+UInt return_0(void *cb, VexRegisterUpdates* pxControl,
+              const VexGuestExtents *vge)
+{
+   return 0;
+}
+
+__attribute__ ((noreturn))
+static void failure_exit()
+{
+   fflush(stdout);
+   fprintf(stderr, "//// failure exit called by libVEX\n");
+   exit(1);
+}
+
+__attribute__ ((noreturn))
+static void failure_dispcalled()
+{
+   fflush(stdout);
+   fprintf(stderr, "//// unexpected call to a disp function by libVEX\n");
+   exit(1);
+}
+
+static void log_bytes (const HChar* chars, SizeT nbytes )
+{
+   printf("%*s", (int)nbytes, chars);
+}
+
+static VexEndness arch_endness (VexArch va) {
+   switch (va) {
+   case VexArch_INVALID: failure_exit();
+   case VexArchX86:    return VexEndnessLE;
+   case VexArchAMD64:  return VexEndnessLE;
+   case VexArchARM:    return VexEndnessLE;
+   case VexArchARM64:  return VexEndnessLE;
+   case VexArchPPC32:  return VexEndnessBE;
+   case VexArchPPC64:  return VexEndnessBE;
+   case VexArchS390X:  return VexEndnessBE;
+   case VexArchMIPS32: return VexEndnessBE;
+   case VexArchMIPS64: return VexEndnessBE;
+   case VexArchTILEGX: return VexEndnessLE;
+   default: failure_exit();
+   }
+}
+
+/* returns whatever kind of hwcaps needed to make
+   the host and/or guest VexArch happy. */
+static UInt arch_hwcaps (VexArch va) {
+   switch (va) {
+   case VexArch_INVALID: failure_exit();
+   case VexArchX86:    return 0;
+   case VexArchAMD64:  return 0;
+   case VexArchARM:    return 7;
+   case VexArchARM64:  return 0;
+   case VexArchPPC32:  return 0;
+   case VexArchPPC64:  return 0;
+   case VexArchS390X:  return VEX_HWCAPS_S390X_LDISP;
+   case VexArchMIPS32: return 0;
+   case VexArchMIPS64: return 0;
+   case VexArchTILEGX: return 0;
+   default: failure_exit();
+   }
+}
+
+static Bool mode64 (VexArch va) {
+   switch (va) {
+   case VexArch_INVALID: failure_exit();
+   case VexArchX86:    return False;
+   case VexArchAMD64:  return True;
+   case VexArchARM:    return False;
+   case VexArchARM64:  return True;
+   case VexArchPPC32:  return False;
+   case VexArchPPC64:  return True;
+   case VexArchS390X:  return True;
+   case VexArchMIPS32: return False;
+   case VexArchMIPS64: return True;
+   case VexArchTILEGX: return True;
+   default: failure_exit();
+   }
+}
+
+// noinline, as this function is also the one we decode.
+__attribute__((noinline)) void get_guest_arch(VexArch    *ga)
+{
+#if defined(VGA_x86)
+   *ga = VexArchX86;
+#elif defined(VGA_amd64)
+   *ga = VexArchAMD64;
+#elif defined(VGA_arm)
+   *ga = VexArchARM;
+#elif defined(VGA_arm64)
+   *ga = VexArchARM64;
+#elif defined(VGA_ppc32)
+   *ga = VexArchPPC32;
+#elif defined(VGA_ppc64be) || defined(VGA_ppc64le) 
+   *ga = VexArchPPC64;
+#elif defined(VGA_s390x)
+   *ga = VexArchS390X;
+#elif defined(VGA_mips32)
+   *ga = VexArchMIPS32;
+#elif defined(VGA_mips64)
+   *ga = VexArchMIPS64;
+#elif defined(VGA_tilegx)
+   *ga = VexArchTILEGX;
+#else
+   missing arch;
+#endif
+}
+
+static void show_vta(char *msg, VexTranslateArgs *vta)
+{
+   printf("//// %s translating guest %s(%d) %s %dbits to host %s(%d)"
+          " %s %dbits\n",
+          msg,
+          LibVEX_ppVexArch(vta->arch_guest),
+          vta->arch_guest,
+          LibVEX_ppVexEndness(arch_endness(vta->arch_guest)),
+          mode64(vta->arch_guest) ? 64 : 32,
+          LibVEX_ppVexArch(vta->arch_host),
+          vta->arch_host,
+          LibVEX_ppVexEndness(arch_endness(vta->arch_host)),
+          mode64(vta->arch_host) ? 64 : 32);
+}
+
+
+int main(int argc, char **argv)
+{
+   const int multiarch = argc > 1 ? atoi(argv[1]) : 0;
+   // 0 means: do not do multiarch
+   // > 0 means: do multiarch
+   // > VexArch_INVALID means: do multiarch, only and specifically
+   // with the host arch  equal to multiarch
+   // (ugly interface, but hey, that is for testing only special cases only).
+   const int endness_may_differ = argc > 2 ? atoi(argv[2]) : 0;
+   const int wordsize_may_differ = argc > 3 ? atoi(argv[3]) : 0;
+   // Note: if multiarch > VexArch_INVALID, then endness_may_differ
+   // and wordsize_may_differ are ignored.
+
+   // So, here are examples of usage:
+   //  * run only host == guest:
+   //     ./libvexmultiarch_test
+   //     ./libvex_test
+   //  * run all combinations (this will abort very soon :):
+   //     ./libvexmultiarch_test 1 1 1
+   //  * run all combinations that are supposed to  work by default :
+   //     ./libvexmultiarch_test 1 0 0
+   //  * run a specific host arch (e.g. 1028 i.e. VexArchARM64)
+   //     ./libvexmultiarch_test 1028
+   //  * show how a single arch VEX lib reports its failure when host != guest
+   //     ./libvex_test 1 0 0
+   
+
+   VexArch guest_arch;
+   VexEndness guest_endness;
+
+   VexControl vcon;
+
+   VexGuestExtents  vge;
+   VexTranslateArgs vta;
+   VexTranslateResult vtr;
+
+   UChar host_bytes[10000];
+   Int   host_bytes_used;
+
+   LibVEX_default_VexControl(&vcon);
+   LibVEX_Init (failure_exit, log_bytes, 3, &vcon);
+
+   get_guest_arch (&guest_arch);
+   guest_endness = arch_endness (guest_arch);
+   
+   LibVEX_default_VexArchInfo(&vta.archinfo_guest);
+   LibVEX_default_VexArchInfo(&vta.archinfo_host);
+   LibVEX_default_VexAbiInfo (&vta.abiinfo_both);
+
+   // Use some values that makes AMD64 happy.
+   vta.abiinfo_both.guest_stack_redzone_size = 128;
+
+   // Prepare first for a translation where guest == host
+   // We will translate the get_guest_arch function
+   vta.arch_guest                 = guest_arch;
+   vta.archinfo_guest.endness     = guest_endness;
+   vta.archinfo_guest.hwcaps      = arch_hwcaps (vta.arch_guest);
+   vta.arch_host                  = guest_arch;
+   vta.archinfo_host.endness      = guest_endness;
+   vta.archinfo_host.hwcaps       = arch_hwcaps (vta.arch_host);
+   vta.callback_opaque            = NULL;
+   vta.guest_bytes                = (UChar*) get_guest_arch;
+   vta.guest_bytes_addr           = (Addr) get_guest_arch;
+   vta.chase_into_ok              = return_false;
+   vta.guest_extents              = &vge;
+   vta.host_bytes                 = host_bytes;
+   vta.host_bytes_size            = sizeof host_bytes;
+   vta.host_bytes_used            = &host_bytes_used;
+   vta.instrument1                = NULL;
+   vta.instrument2                = NULL;
+   vta.finaltidy                  = NULL;
+   vta.needs_self_check           = return_0;
+   vta.preamble_function          = NULL;
+   vta.traceflags                 = 0xFFFFFFFF;
+   vta.sigill_diag                = False;
+   vta.addProfInc                 = False;
+   vta.disp_cp_chain_me_to_slowEP = failure_dispcalled;
+   vta.disp_cp_chain_me_to_fastEP = failure_dispcalled;
+   vta.disp_cp_xindir             = failure_dispcalled;
+   vta.disp_cp_xassisted          = failure_dispcalled;
+
+   
+   show_vta("host == guest", &vta);
+   vtr = LibVEX_Translate ( &vta );
+   if (vtr.status != VexTransOK) 
+      return 1;
+
+   // Now, try various combinations, if told to do so:
+   //   host            != guest, 
+   //   endness(host)   != endness(guest)     (not well supported)
+   //   wordsize (host) != wordsize (guest)   (not well supported)
+   // The not well supported combinations are not run, unless requested
+   // explicitely via command line arguments.
+   if (multiarch) {
+      VexArch va;
+      for (va = VexArchX86; va <= VexArchTILEGX; va++) {
+         vta.arch_host = va;
+         vta.archinfo_host.endness = arch_endness (vta.arch_host);
+         vta.archinfo_host.hwcaps = arch_hwcaps (vta.arch_host);
+         if (arch_endness(va) != arch_endness(guest_arch) 
+             && !endness_may_differ
+             && multiarch != va) {
+            show_vta("skipped (endness differs)", &vta);
+            continue;
+         }
+         if (mode64(va) != mode64(guest_arch) 
+             && !wordsize_may_differ
+             && multiarch != va) {
+            show_vta("skipped (word size differs)", &vta);
+            continue;
+         }
+         // Special condition for VexArchTILEGX that is not yet ready
+         // to run in multiarch as an host for different guest.
+         if (va == VexArchTILEGX
+             && guest_arch != VexArchTILEGX
+             && multiarch != va) {
+            show_vta("skipped (TILEGX host and guest != TILEGX)", &vta);
+            continue;
+         }
+         if (multiarch > VexArch_INVALID
+             && multiarch != va) {
+            show_vta("skipped (!= specific requested arch)", &vta);
+            continue;
+         }
+         show_vta ("doing", &vta);
+         vtr = LibVEX_Translate ( &vta );
+         if (vtr.status != VexTransOK) 
+            return 1;
+      }
+   }
+
+   printf ("//// libvex testing normal exit\n");
+   return 0;
+}
diff --git a/none/tests/libvex_test.stderr.exp b/none/tests/libvex_test.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/libvex_test.stderr.exp
diff --git a/none/tests/libvex_test.vgtest b/none/tests/libvex_test.vgtest
new file mode 100644
index 0000000..90c03b4
--- /dev/null
+++ b/none/tests/libvex_test.vgtest
@@ -0,0 +1,4 @@
+vgopts: -q
+prog: libvex_test
+stdout_filter: ../../gdbserver_tests/filter_make_empty
+
diff --git a/none/tests/libvexmultiarch_test.stderr.exp b/none/tests/libvexmultiarch_test.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/libvexmultiarch_test.stderr.exp
diff --git a/none/tests/libvexmultiarch_test.vgtest b/none/tests/libvexmultiarch_test.vgtest
new file mode 100644
index 0000000..5e314b6
--- /dev/null
+++ b/none/tests/libvexmultiarch_test.vgtest
@@ -0,0 +1,7 @@
+vgopts: -q
+prog: libvexmultiarch_test
+# below args means:
+#     multiarch endness_may_differ   word_size_may_differ
+args: 1         0                    0
+stdout_filter: ../../gdbserver_tests/filter_make_empty
+