Home | History | Annotate | Download | only in tests
      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 
     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 
     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 endianness\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 #else
     78    missing arch;
     79 #endif
     80 }
     81 
     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. */
    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 
    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 
    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 
    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