1 #include <stdio.h>
2 #include <stdlib.h>
3 # if !defined(VGO_darwin)
4 #include <endian.h>
5 # else
6 #include <machine/endian.h>
7 # endif
8 #include "../../VEX/pub/libvex.h"
9
return_false(void * cb,Addr ad)10 Bool return_false(void*cb, Addr ad)
11 {
12 return False;
13 }
return_0(void * cb,VexRegisterUpdates * pxControl,const VexGuestExtents * vge)14 UInt return_0(void *cb, VexRegisterUpdates* pxControl,
15 const VexGuestExtents *vge)
16 {
17 return 0;
18 }
19
20 __attribute__ ((noreturn))
failure_exit()21 static void failure_exit()
22 {
23 fflush(stdout);
24 fprintf(stderr, "//// failure exit called by libVEX\n");
25 exit(1);
26 }
27
28 __attribute__ ((noreturn))
failure_dispcalled()29 static void failure_dispcalled()
30 {
31 fflush(stdout);
32 fprintf(stderr, "//// unexpected call to a disp function by libVEX\n");
33 exit(1);
34 }
35
log_bytes(const HChar * chars,SizeT nbytes)36 static 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.
running_endness(void)44 static 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.
get_guest_arch(VexArch * ga)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
arch_endness(VexArch va)84 static 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. */
arch_hwcaps(VexArch va)122 static 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
mode64(VexArch va)139 static 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
show_vta(char * msg,VexTranslateArgs * vta)156 static 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
main(int argc,char ** argv)172 int 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 // Prepare first for a translation where guest == host
225 // We will translate the get_guest_arch function
226 vta.arch_guest = guest_arch;
227 vta.archinfo_guest.endness = guest_endness;
228 vta.archinfo_guest.hwcaps = arch_hwcaps (vta.arch_guest);
229 vta.arch_host = guest_arch;
230 vta.archinfo_host.endness = guest_endness;
231 vta.archinfo_host.hwcaps = arch_hwcaps (vta.arch_host);
232 vta.callback_opaque = NULL;
233 vta.guest_bytes = (UChar*) get_guest_arch;
234 vta.guest_bytes_addr = (Addr) get_guest_arch;
235 vta.chase_into_ok = return_false;
236 vta.guest_extents = &vge;
237 vta.host_bytes = host_bytes;
238 vta.host_bytes_size = sizeof host_bytes;
239 vta.host_bytes_used = &host_bytes_used;
240 vta.instrument1 = NULL;
241 vta.instrument2 = NULL;
242 vta.finaltidy = NULL;
243 vta.needs_self_check = return_0;
244 vta.preamble_function = NULL;
245 vta.traceflags = 0xFFFFFFFF;
246 vta.sigill_diag = False;
247 vta.addProfInc = False;
248 vta.disp_cp_chain_me_to_slowEP = failure_dispcalled;
249 vta.disp_cp_chain_me_to_fastEP = failure_dispcalled;
250 vta.disp_cp_xindir = failure_dispcalled;
251 vta.disp_cp_xassisted = failure_dispcalled;
252
253
254 show_vta("host == guest", &vta);
255 vtr = LibVEX_Translate ( &vta );
256 if (vtr.status != VexTransOK)
257 return 1;
258
259 // Now, try various combinations, if told to do so:
260 // host != guest,
261 // endness(host) != endness(guest) (not well supported)
262 // wordsize (host) != wordsize (guest) (not well supported)
263 // The not well supported combinations are not run, unless requested
264 // explicitely via command line arguments.
265 if (multiarch) {
266 VexArch va;
267 for (va = VexArchX86; va <= VexArchTILEGX; va++) {
268 vta.arch_host = va;
269 vta.archinfo_host.endness = arch_endness (vta.arch_host);
270 vta.archinfo_host.hwcaps = arch_hwcaps (vta.arch_host);
271 if (arch_endness(va) != arch_endness(guest_arch)
272 && !endness_may_differ
273 && multiarch != va) {
274 show_vta("skipped (endness differs)", &vta);
275 continue;
276 }
277 if (mode64(va) != mode64(guest_arch)
278 && !wordsize_may_differ
279 && multiarch != va) {
280 show_vta("skipped (word size differs)", &vta);
281 continue;
282 }
283 if (multiarch > VexArch_INVALID
284 && multiarch != va) {
285 show_vta("skipped (!= specific requested arch)", &vta);
286 continue;
287 }
288 show_vta ("doing", &vta);
289 vtr = LibVEX_Translate ( &vta );
290 if (vtr.status != VexTransOK)
291 return 1;
292 }
293 }
294
295 printf ("//// libvex testing normal exit\n");
296 return 0;
297 }
298