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
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 endianness\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 #else
78 missing arch;
79 #endif
80 }
81
arch_endness(VexArch va)82 static VexEndness arch_endness (VexArch va) {
83 switch (va) {
84 case VexArch_INVALID: failure_exit();
85 case VexArchX86: return VexEndnessLE;
86 case VexArchAMD64: return VexEndnessLE;
87 case VexArchARM: return VexEndnessLE;
88 case VexArchARM64: return VexEndnessLE;
89 case VexArchPPC32: return VexEndnessBE;
90 case VexArchPPC64:
91 /* ppc64 supports BE or LE at run time. So, on a LE system,
92 returns LE, on a BE system, return BE. */
93 return running_endness();
94 case VexArchS390X: return VexEndnessBE;
95 case VexArchMIPS32:
96 case VexArchMIPS64:
97 /* mips32/64 supports BE or LE, but at compile time.
98 If mips64 is compiled on a non mips system, the VEX lib
99 is missing bit and pieces of code related to endianness.
100 The mandatory code for this test is then compiled as BE.
101 So, if this test runs on a mips system, returns the
102 running endianness. Otherwise, returns BE as this one
103 has the more chances to work. */
104 {
105 VexArch ga;
106 get_guest_arch( &ga);
107
108 if (ga == VexArchMIPS64 || ga == VexArchMIPS32)
109 return running_endness();
110 else
111 return VexEndnessBE;
112 }
113 default: failure_exit();
114 }
115 }
116
117 /* returns whatever kind of hwcaps needed to make
118 the host and/or guest VexArch happy. */
arch_hwcaps(VexArch va)119 static UInt arch_hwcaps (VexArch va) {
120 switch (va) {
121 case VexArch_INVALID: failure_exit();
122 case VexArchX86: return 0;
123 case VexArchAMD64: return 0;
124 case VexArchARM: return 7;
125 case VexArchARM64: return 0;
126 case VexArchPPC32: return 0;
127 case VexArchPPC64: return 0;
128 case VexArchS390X: return VEX_HWCAPS_S390X_LDISP;
129 case VexArchMIPS32: return VEX_PRID_COMP_MIPS;
130 case VexArchMIPS64: return VEX_PRID_COMP_MIPS;
131 default: failure_exit();
132 }
133 }
134
mode64(VexArch va)135 static Bool mode64 (VexArch va) {
136 switch (va) {
137 case VexArch_INVALID: failure_exit();
138 case VexArchX86: return False;
139 case VexArchAMD64: return True;
140 case VexArchARM: return False;
141 case VexArchARM64: return True;
142 case VexArchPPC32: return False;
143 case VexArchPPC64: return True;
144 case VexArchS390X: return True;
145 case VexArchMIPS32: return False;
146 case VexArchMIPS64: return True;
147 default: failure_exit();
148 }
149 }
150
show_vta(char * msg,VexTranslateArgs * vta)151 static void show_vta(char *msg, VexTranslateArgs *vta)
152 {
153 printf("//// %s translating guest %s(%d) %s %dbits to host %s(%d)"
154 " %s %dbits\n",
155 msg,
156 LibVEX_ppVexArch(vta->arch_guest),
157 vta->arch_guest,
158 LibVEX_ppVexEndness(arch_endness(vta->arch_guest)),
159 mode64(vta->arch_guest) ? 64 : 32,
160 LibVEX_ppVexArch(vta->arch_host),
161 vta->arch_host,
162 LibVEX_ppVexEndness(arch_endness(vta->arch_host)),
163 mode64(vta->arch_host) ? 64 : 32);
164 }
165
166
main(int argc,char ** argv)167 int main(int argc, char **argv)
168 {
169 const int multiarch = argc > 1 ? atoi(argv[1]) : 0;
170 // 0 means: do not do multiarch
171 // > 0 means: do multiarch
172 // > VexArch_INVALID means: do multiarch, only and specifically
173 // with the host arch equal to multiarch
174 // (ugly interface, but hey, that is for testing only special cases only).
175 const int endness_may_differ = argc > 2 ? atoi(argv[2]) : 0;
176 const int wordsize_may_differ = argc > 3 ? atoi(argv[3]) : 0;
177 // Note: if multiarch > VexArch_INVALID, then endness_may_differ
178 // and wordsize_may_differ are ignored.
179
180 // So, here are examples of usage:
181 // * run only host == guest:
182 // ./libvexmultiarch_test
183 // ./libvex_test
184 // * run all combinations (this will abort very soon :):
185 // ./libvexmultiarch_test 1 1 1
186 // * run all combinations that are supposed to work by default :
187 // ./libvexmultiarch_test 1 0 0
188 // * run a specific host arch (e.g. 1028 i.e. VexArchARM64)
189 // ./libvexmultiarch_test 1028
190 // * show how a single arch VEX lib reports its failure when host != guest
191 // ./libvex_test 1 0 0
192
193
194 VexArch guest_arch;
195 VexEndness guest_endness;
196
197 VexControl vcon;
198
199 VexGuestExtents vge;
200 VexTranslateArgs vta;
201 VexTranslateResult vtr;
202
203 UChar host_bytes[10000];
204 Int host_bytes_used;
205
206 LibVEX_default_VexControl(&vcon);
207 LibVEX_Init (failure_exit, log_bytes, 3, &vcon);
208
209 get_guest_arch (&guest_arch);
210 guest_endness = arch_endness (guest_arch);
211
212 LibVEX_default_VexArchInfo(&vta.archinfo_guest);
213 LibVEX_default_VexArchInfo(&vta.archinfo_host);
214 LibVEX_default_VexAbiInfo (&vta.abiinfo_both);
215
216 // Use some values that makes AMD64 happy.
217 vta.abiinfo_both.guest_stack_redzone_size = 128;
218
219 // Use some values that makes ARM64 happy.
220 vta.archinfo_guest.arm64_dMinLine_lg2_szB = 6;
221 vta.archinfo_guest.arm64_iMinLine_lg2_szB = 6;
222
223 // Prepare first for a translation where guest == host
224 // We will translate the get_guest_arch function
225 vta.arch_guest = guest_arch;
226 vta.archinfo_guest.endness = guest_endness;
227 vta.archinfo_guest.hwcaps = arch_hwcaps (vta.arch_guest);
228 vta.arch_host = guest_arch;
229 vta.archinfo_host.endness = guest_endness;
230 vta.archinfo_host.hwcaps = arch_hwcaps (vta.arch_host);
231 vta.callback_opaque = NULL;
232 vta.guest_bytes = (UChar*) get_guest_arch;
233 vta.guest_bytes_addr = (Addr) get_guest_arch;
234 vta.chase_into_ok = return_false;
235 vta.guest_extents = &vge;
236 vta.host_bytes = host_bytes;
237 vta.host_bytes_size = sizeof host_bytes;
238 vta.host_bytes_used = &host_bytes_used;
239 vta.instrument1 = NULL;
240 vta.instrument2 = NULL;
241 vta.finaltidy = NULL;
242 vta.needs_self_check = return_0;
243 vta.preamble_function = NULL;
244 vta.traceflags = 0xFFFFFFFF;
245 vta.sigill_diag = False;
246 vta.addProfInc = False;
247 vta.disp_cp_chain_me_to_slowEP = failure_dispcalled;
248 vta.disp_cp_chain_me_to_fastEP = failure_dispcalled;
249 vta.disp_cp_xindir = failure_dispcalled;
250 vta.disp_cp_xassisted = failure_dispcalled;
251
252
253 show_vta("host == guest", &vta);
254 vtr = LibVEX_Translate ( &vta );
255 if (vtr.status != VexTransOK)
256 return 1;
257
258 // Now, try various combinations, if told to do so:
259 // host != guest,
260 // endness(host) != endness(guest) (not well supported)
261 // wordsize (host) != wordsize (guest) (not well supported)
262 // The not well supported combinations are not run, unless requested
263 // explicitly via command line arguments.
264 if (multiarch) {
265 VexArch va;
266 for (va = VexArchX86; va <= VexArchMIPS64; va++) {
267 vta.arch_host = va;
268 vta.archinfo_host.endness = arch_endness (vta.arch_host);
269 vta.archinfo_host.hwcaps = arch_hwcaps (vta.arch_host);
270 if (arch_endness(va) != arch_endness(guest_arch)
271 && !endness_may_differ
272 && multiarch != va) {
273 show_vta("skipped (endness differs)", &vta);
274 continue;
275 }
276 if (mode64(va) != mode64(guest_arch)
277 && !wordsize_may_differ
278 && multiarch != va) {
279 show_vta("skipped (word size differs)", &vta);
280 continue;
281 }
282 if (multiarch > VexArch_INVALID
283 && multiarch != va) {
284 show_vta("skipped (!= specific requested arch)", &vta);
285 continue;
286 }
287 show_vta ("doing", &vta);
288 vtr = LibVEX_Translate ( &vta );
289 if (vtr.status != VexTransOK)
290 return 1;
291 }
292 }
293
294 printf ("//// libvex testing normal exit\n");
295 return 0;
296 }
297