1#include <stdio.h>
2#include <stdlib.h>
3# if defined(VGO_linux)
4#include <endian.h>
5# elif defined(VGO_darwin)
6#include <machine/endian.h>
7# endif
8#include "../../VEX/pub/libvex.h"
9
10Bool return_false(void*cb, Addr ad)
11{
12   return False;
13}
14UInt return_0(void *cb, VexRegisterUpdates* pxControl,
15              const VexGuestExtents *vge)
16{
17   return 0;
18}
19
20__attribute__ ((noreturn))
21static void failure_exit()
22{
23   fflush(stdout);
24   fprintf(stderr, "//// failure exit called by libVEX\n");
25   exit(1);
26}
27
28__attribute__ ((noreturn))
29static void failure_dispcalled()
30{
31   fflush(stdout);
32   fprintf(stderr, "//// unexpected call to a disp function by libVEX\n");
33   exit(1);
34}
35
36static void log_bytes (const HChar* chars, SizeT nbytes )
37{
38   printf("%*s", (int)nbytes, chars);
39}
40
41// Returns the endness of the system we are running on.
42// We use that as the endness of arch that supports both
43// little and big endian.
44static VexEndness running_endness (void)
45{
46#if __BYTE_ORDER == __LITTLE_ENDIAN
47   return VexEndnessLE;
48#elif __BYTE_ORDER == __BIG_ENDIAN
49   return VexEndnessBE;
50#else
51   fprintf(stderr, "cannot determine endianess\n");
52   exit(1);
53#endif
54}
55
56// noinline, as this function is also the one we decode.
57__attribute__((noinline)) static void get_guest_arch(VexArch    *ga)
58{
59#if defined(VGA_x86)
60   *ga = VexArchX86;
61#elif defined(VGA_amd64)
62   *ga = VexArchAMD64;
63#elif defined(VGA_arm)
64   *ga = VexArchARM;
65#elif defined(VGA_arm64)
66   *ga = VexArchARM64;
67#elif defined(VGA_ppc32)
68   *ga = VexArchPPC32;
69#elif defined(VGA_ppc64be) || defined(VGA_ppc64le)
70   *ga = VexArchPPC64;
71#elif defined(VGA_s390x)
72   *ga = VexArchS390X;
73#elif defined(VGA_mips32)
74   *ga = VexArchMIPS32;
75#elif defined(VGA_mips64)
76   *ga = VexArchMIPS64;
77#elif defined(VGA_tilegx)
78   *ga = VexArchTILEGX;
79#else
80   missing arch;
81#endif
82}
83
84static VexEndness arch_endness (VexArch va) {
85   switch (va) {
86   case VexArch_INVALID: failure_exit();
87   case VexArchX86:    return VexEndnessLE;
88   case VexArchAMD64:  return VexEndnessLE;
89   case VexArchARM:    return VexEndnessLE;
90   case VexArchARM64:  return VexEndnessLE;
91   case VexArchPPC32:  return VexEndnessBE;
92   case VexArchPPC64:
93      /* ppc64 supports BE or LE at run time. So, on a LE system,
94         returns LE, on a BE system, return BE. */
95      return running_endness();
96   case VexArchS390X:  return VexEndnessBE;
97   case VexArchMIPS32:
98   case VexArchMIPS64:
99      /* mips32/64 supports BE or LE, but at compile time.
100         If mips64 is compiled on a non mips system, the VEX lib
101         is missing bit and pieces of code related to endianess.
102         The mandatory code for this test is then compiled as BE.
103         So, if this test runs on a mips system, returns the
104         running endianess. Otherwise, returns BE as this one
105         has the more chances to work. */
106      {
107         VexArch ga;
108         get_guest_arch( &ga);
109
110         if (ga == VexArchMIPS64 || ga == VexArchMIPS32)
111            return running_endness();
112         else
113            return VexEndnessBE;
114      }
115   case VexArchTILEGX: return VexEndnessLE;
116   default: failure_exit();
117   }
118}
119
120/* returns whatever kind of hwcaps needed to make
121   the host and/or guest VexArch happy. */
122static UInt arch_hwcaps (VexArch va) {
123   switch (va) {
124   case VexArch_INVALID: failure_exit();
125   case VexArchX86:    return 0;
126   case VexArchAMD64:  return 0;
127   case VexArchARM:    return 7;
128   case VexArchARM64:  return 0;
129   case VexArchPPC32:  return 0;
130   case VexArchPPC64:  return 0;
131   case VexArchS390X:  return VEX_HWCAPS_S390X_LDISP;
132   case VexArchMIPS32: return 0;
133   case VexArchMIPS64: return 0;
134   case VexArchTILEGX: return 0;
135   default: failure_exit();
136   }
137}
138
139static Bool mode64 (VexArch va) {
140   switch (va) {
141   case VexArch_INVALID: failure_exit();
142   case VexArchX86:    return False;
143   case VexArchAMD64:  return True;
144   case VexArchARM:    return False;
145   case VexArchARM64:  return True;
146   case VexArchPPC32:  return False;
147   case VexArchPPC64:  return True;
148   case VexArchS390X:  return True;
149   case VexArchMIPS32: return False;
150   case VexArchMIPS64: return True;
151   case VexArchTILEGX: return True;
152   default: failure_exit();
153   }
154}
155
156static void show_vta(char *msg, VexTranslateArgs *vta)
157{
158   printf("//// %s translating guest %s(%d) %s %dbits to host %s(%d)"
159          " %s %dbits\n",
160          msg,
161          LibVEX_ppVexArch(vta->arch_guest),
162          vta->arch_guest,
163          LibVEX_ppVexEndness(arch_endness(vta->arch_guest)),
164          mode64(vta->arch_guest) ? 64 : 32,
165          LibVEX_ppVexArch(vta->arch_host),
166          vta->arch_host,
167          LibVEX_ppVexEndness(arch_endness(vta->arch_host)),
168          mode64(vta->arch_host) ? 64 : 32);
169}
170
171
172int main(int argc, char **argv)
173{
174   const int multiarch = argc > 1 ? atoi(argv[1]) : 0;
175   // 0 means: do not do multiarch
176   // > 0 means: do multiarch
177   // > VexArch_INVALID means: do multiarch, only and specifically
178   // with the host arch  equal to multiarch
179   // (ugly interface, but hey, that is for testing only special cases only).
180   const int endness_may_differ = argc > 2 ? atoi(argv[2]) : 0;
181   const int wordsize_may_differ = argc > 3 ? atoi(argv[3]) : 0;
182   // Note: if multiarch > VexArch_INVALID, then endness_may_differ
183   // and wordsize_may_differ are ignored.
184
185   // So, here are examples of usage:
186   //  * run only host == guest:
187   //     ./libvexmultiarch_test
188   //     ./libvex_test
189   //  * run all combinations (this will abort very soon :):
190   //     ./libvexmultiarch_test 1 1 1
191   //  * run all combinations that are supposed to  work by default :
192   //     ./libvexmultiarch_test 1 0 0
193   //  * run a specific host arch (e.g. 1028 i.e. VexArchARM64)
194   //     ./libvexmultiarch_test 1028
195   //  * show how a single arch VEX lib reports its failure when host != guest
196   //     ./libvex_test 1 0 0
197
198
199   VexArch guest_arch;
200   VexEndness guest_endness;
201
202   VexControl vcon;
203
204   VexGuestExtents  vge;
205   VexTranslateArgs vta;
206   VexTranslateResult vtr;
207
208   UChar host_bytes[10000];
209   Int   host_bytes_used;
210
211   LibVEX_default_VexControl(&vcon);
212   LibVEX_Init (failure_exit, log_bytes, 3, &vcon);
213
214   get_guest_arch (&guest_arch);
215   guest_endness = arch_endness (guest_arch);
216
217   LibVEX_default_VexArchInfo(&vta.archinfo_guest);
218   LibVEX_default_VexArchInfo(&vta.archinfo_host);
219   LibVEX_default_VexAbiInfo (&vta.abiinfo_both);
220
221   // Use some values that makes AMD64 happy.
222   vta.abiinfo_both.guest_stack_redzone_size = 128;
223
224   // Use some values that makes ARM64 happy.
225   vta.archinfo_guest.arm64_dMinLine_lg2_szB = 6;
226   vta.archinfo_guest.arm64_iMinLine_lg2_szB = 6;
227
228   // Prepare first for a translation where guest == host
229   // We will translate the get_guest_arch function
230   vta.arch_guest                 = guest_arch;
231   vta.archinfo_guest.endness     = guest_endness;
232   vta.archinfo_guest.hwcaps      = arch_hwcaps (vta.arch_guest);
233   vta.arch_host                  = guest_arch;
234   vta.archinfo_host.endness      = guest_endness;
235   vta.archinfo_host.hwcaps       = arch_hwcaps (vta.arch_host);
236   vta.callback_opaque            = NULL;
237   vta.guest_bytes                = (UChar*) get_guest_arch;
238   vta.guest_bytes_addr           = (Addr) get_guest_arch;
239   vta.chase_into_ok              = return_false;
240   vta.guest_extents              = &vge;
241   vta.host_bytes                 = host_bytes;
242   vta.host_bytes_size            = sizeof host_bytes;
243   vta.host_bytes_used            = &host_bytes_used;
244   vta.instrument1                = NULL;
245   vta.instrument2                = NULL;
246   vta.finaltidy                  = NULL;
247   vta.needs_self_check           = return_0;
248   vta.preamble_function          = NULL;
249   vta.traceflags                 = 0xFFFFFFFF;
250   vta.sigill_diag                = False;
251   vta.addProfInc                 = False;
252   vta.disp_cp_chain_me_to_slowEP = failure_dispcalled;
253   vta.disp_cp_chain_me_to_fastEP = failure_dispcalled;
254   vta.disp_cp_xindir             = failure_dispcalled;
255   vta.disp_cp_xassisted          = failure_dispcalled;
256
257
258   show_vta("host == guest", &vta);
259   vtr = LibVEX_Translate ( &vta );
260   if (vtr.status != VexTransOK)
261      return 1;
262
263   // Now, try various combinations, if told to do so:
264   //   host            != guest,
265   //   endness(host)   != endness(guest)     (not well supported)
266   //   wordsize (host) != wordsize (guest)   (not well supported)
267   // The not well supported combinations are not run, unless requested
268   // explicitely via command line arguments.
269   if (multiarch) {
270      VexArch va;
271      for (va = VexArchX86; va <= VexArchTILEGX; va++) {
272         vta.arch_host = va;
273         vta.archinfo_host.endness = arch_endness (vta.arch_host);
274         vta.archinfo_host.hwcaps = arch_hwcaps (vta.arch_host);
275         if (arch_endness(va) != arch_endness(guest_arch)
276             && !endness_may_differ
277             && multiarch != va) {
278            show_vta("skipped (endness differs)", &vta);
279            continue;
280         }
281         if (mode64(va) != mode64(guest_arch)
282             && !wordsize_may_differ
283             && multiarch != va) {
284            show_vta("skipped (word size differs)", &vta);
285            continue;
286         }
287         if (multiarch > VexArch_INVALID
288             && multiarch != va) {
289            show_vta("skipped (!= specific requested arch)", &vta);
290            continue;
291         }
292         show_vta ("doing", &vta);
293         vtr = LibVEX_Translate ( &vta );
294         if (vtr.status != VexTransOK)
295            return 1;
296      }
297   }
298
299   printf ("//// libvex testing normal exit\n");
300   return 0;
301}
302