philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 3 | # if defined(VGO_linux) |
philippe | 203a35d | 2015-04-19 15:43:53 +0000 | [diff] [blame] | 4 | #include <endian.h> |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 5 | # elif defined(VGO_darwin) |
rhyskidd | 76e04ec | 2015-04-30 23:39:10 +0000 | [diff] [blame] | 6 | #include <machine/endian.h> |
| 7 | # endif |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 8 | #include "../../VEX/pub/libvex.h" |
| 9 | |
| 10 | Bool return_false(void*cb, Addr ad) |
| 11 | { |
| 12 | return False; |
| 13 | } |
| 14 | UInt return_0(void *cb, VexRegisterUpdates* pxControl, |
| 15 | const VexGuestExtents *vge) |
| 16 | { |
| 17 | return 0; |
| 18 | } |
| 19 | |
| 20 | __attribute__ ((noreturn)) |
| 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)) |
| 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 | |
| 36 | static void log_bytes (const HChar* chars, SizeT nbytes ) |
| 37 | { |
| 38 | printf("%*s", (int)nbytes, chars); |
| 39 | } |
| 40 | |
philippe | 203a35d | 2015-04-19 15:43:53 +0000 | [diff] [blame] | 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. |
| 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. |
| 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 | |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 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; |
philippe | 203a35d | 2015-04-19 15:43:53 +0000 | [diff] [blame] | 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(); |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 96 | case VexArchS390X: return VexEndnessBE; |
philippe | 203a35d | 2015-04-19 15:43:53 +0000 | [diff] [blame] | 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 | } |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 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. */ |
| 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; |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame^] | 132 | case VexArchMIPS32: return VEX_PRID_COMP_MIPS; |
| 133 | case VexArchMIPS64: return VEX_PRID_COMP_MIPS; |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 134 | case VexArchTILEGX: return 0; |
| 135 | default: failure_exit(); |
| 136 | } |
| 137 | } |
| 138 | |
| 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 | |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 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 | |
| 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 | |
mjw | 0bfd39c | 2015-09-09 13:40:23 +0000 | [diff] [blame] | 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 | |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 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 | } |
philippe | ffcfa7a | 2015-04-11 14:32:25 +0000 | [diff] [blame] | 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 | } |