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 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 
     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. */
    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 
    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 
    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 
    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