Home | History | Annotate | Download | only in vbit-test
      1 /* -*- mode: C; c-basic-offset: 3; -*- */
      2 
      3 /*
      4    This file is part of MemCheck, a heavyweight Valgrind tool for
      5    detecting memory errors.
      6 
      7    Copyright (C) 2012-2017  Florian Krohm
      8 
      9    This program is free software; you can redistribute it and/or
     10    modify it under the terms of the GNU General Public License as
     11    published by the Free Software Foundation; either version 2 of the
     12    License, or (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful, but
     15    WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17    General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software
     21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     22    02111-1307, USA.
     23 
     24    The GNU General Public License is contained in the file COPYING.
     25 */
     26 
     27 #include <assert.h>
     28 #include "memcheck.h"  // VALGRIND_SET_VBITS
     29 #include "vtest.h"
     30 
     31 
     32 /* Return a completely initialised control block */
     33 IRICB
     34 new_iricb(const irop_t *op, test_data_t *data)
     35 {
     36    IRICB cb;
     37 
     38    cb.op = op->op;
     39    cb.result = (HWord)&data->result.value;
     40    cb.opnd1  = (HWord)&data->opnds[0].value;
     41    cb.opnd2  = (HWord)&data->opnds[1].value;
     42    cb.opnd3  = (HWord)&data->opnds[2].value;
     43    cb.opnd4  = (HWord)&data->opnds[3].value;
     44    cb.t_result = data->result.type;
     45    cb.t_opnd1  = data->opnds[0].type;
     46    cb.t_opnd2  = data->opnds[1].type;
     47    cb.t_opnd3  = data->opnds[2].type;
     48    cb.t_opnd4  = data->opnds[3].type;
     49 
     50    cb.rounding_mode = data->rounding_mode;
     51 
     52    cb.num_operands = get_num_operands(op->op);
     53 
     54    cb.immediate_index = op->immediate_index;
     55    cb.immediate_type  = op->immediate_type;
     56 
     57    return cb;
     58 }
     59 
     60 
     61 /* Ity_I1 values cannot be stored or loaded. So vex_inject_ir will load/store
     62    such a value from/to a 4-byte container. It uses 32to1 and 1Uto32,
     63    respectively. */
     64 static void
     65 valgrind_set_vbits(opnd_t *opnd)
     66 {
     67    unsigned rc, num_bytes;
     68 
     69    /* 1-bit wide values cannot be read. So we read a 4 bytes here */
     70    num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type);
     71    rc = VALGRIND_SET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes);
     72    assert(rc == 1);
     73 
     74    // Make sure the v-bits were set correctly
     75    vbits_t actual = { .num_bits = opnd->vbits.num_bits };
     76    rc = VALGRIND_GET_VBITS(&opnd->value, &actual.bits, num_bytes);
     77    assert(rc == 1);
     78 
     79    assert(equal_vbits(opnd->vbits, actual));
     80 }
     81 
     82 
     83 static void
     84 valgrind_get_vbits(opnd_t *opnd)
     85 {
     86    unsigned rc, num_bytes;
     87 
     88    /* 1-bit wide values cannot be stored. So we store them by writing a
     89       single byte */
     90    num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type);
     91    opnd->vbits.num_bits = bitsof_irtype(opnd->type);
     92    rc = VALGRIND_GET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes);
     93    assert(rc == 1);
     94 }
     95 
     96 
     97 /* Insert a client request that will initialize VEX for IR injection */
     98 void
     99 valgrind_vex_init_for_iri(IRICB *cb)
    100 {
    101    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__VEX_INIT_FOR_IRI, cb, 0,0,0,0);
    102 }
    103 
    104 
    105 /* Insert a special opcode that will cause VEX to inject an IR stmt based
    106    on the information passed in the IRICB (in valgrind_vex_init_for_iri). */
    107 static void
    108 valgrind_vex_inject_ir(void)
    109 {
    110    VALGRIND_VEX_INJECT_IR();
    111 }
    112 
    113 
    114 /* Execute the test under valgrind. Well, yes, we're not really executing
    115    it here, just preparing for it... */
    116 void
    117 valgrind_execute_test(const irop_t *op, test_data_t *data)
    118 {
    119    unsigned i, num_operands;
    120 
    121    if (verbose > 2) printf("---------- Running a test\n");
    122    num_operands = get_num_operands(op->op);
    123 
    124    for (i = 0; i < num_operands; ++i) {
    125       valgrind_set_vbits(&data->opnds[i]);
    126       if (verbose > 2) {
    127          printf("opnd #%u:  ", i);
    128          print_opnd(stdout, &data->opnds[i]);
    129          printf("\n");
    130       }
    131    }
    132    if (verbose > 2)
    133       if (data->rounding_mode != NO_ROUNDING_MODE)
    134          printf("rounding mode %u\n", data->rounding_mode);
    135 
    136    valgrind_vex_inject_ir();
    137    valgrind_get_vbits(&data->result);
    138    if (verbose > 2) {
    139       printf("result:   ");
    140       print_opnd(stdout, &data->result);
    141       printf("\n");
    142    }
    143 }
    144