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-2015  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
new_iricb(const irop_t * op,test_data_t * data)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.shift_amount_is_immediate = op->shift_amount_is_immediate;
55 
56    return cb;
57 }
58 
59 
60 /* Ity_I1 values cannot be stored or loaded. So vex_inject_ir will load/store
61    such a value from/to a 4-byte container. It uses 32to1 and 1Uto32,
62    respectively. */
63 static void
valgrind_set_vbits(opnd_t * opnd)64 valgrind_set_vbits(opnd_t *opnd)
65 {
66    unsigned rc, num_bytes;
67 
68    /* 1-bit wide values cannot be read. So we read a 4 bytes here */
69    num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type);
70    rc = VALGRIND_SET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes);
71    assert(rc == 1);
72 
73    // Make sure the v-bits were set correctly
74    vbits_t actual = { .num_bits = opnd->vbits.num_bits };
75    rc = VALGRIND_GET_VBITS(&opnd->value, &actual.bits, num_bytes);
76    assert(rc == 1);
77 
78    assert(equal_vbits(opnd->vbits, actual));
79 }
80 
81 
82 static void
valgrind_get_vbits(opnd_t * opnd)83 valgrind_get_vbits(opnd_t *opnd)
84 {
85    unsigned rc, num_bytes;
86 
87    /* 1-bit wide values cannot be stored. So we store them by writing a
88       single byte */
89    num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type);
90    opnd->vbits.num_bits = bitsof_irtype(opnd->type);
91    rc = VALGRIND_GET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes);
92    assert(rc == 1);
93 }
94 
95 
96 /* Insert a client request that will initialize VEX for IR injection */
97 void
valgrind_vex_init_for_iri(IRICB * cb)98 valgrind_vex_init_for_iri(IRICB *cb)
99 {
100    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__VEX_INIT_FOR_IRI, cb, 0,0,0,0);
101 }
102 
103 
104 /* Insert a special opcode that will cause VEX to inject an IR stmt based
105    on the information passed in the IRICB (in valgrind_vex_init_for_iri). */
106 static void
valgrind_vex_inject_ir(void)107 valgrind_vex_inject_ir(void)
108 {
109    VALGRIND_VEX_INJECT_IR();
110 }
111 
112 
113 /* Execute the test under valgrind. Well, yes, we're not really executing
114    it here, just preparing for it... */
115 void
valgrind_execute_test(const irop_t * op,test_data_t * data)116 valgrind_execute_test(const irop_t *op, test_data_t *data)
117 {
118    unsigned i, num_operands;
119 
120    if (verbose > 2) printf("---------- Running a test\n");
121    num_operands = get_num_operands(op->op);
122 
123    for (i = 0; i < num_operands; ++i) {
124       valgrind_set_vbits(&data->opnds[i]);
125       if (verbose > 2) {
126          printf("opnd #%u:  ", i);
127          print_opnd(stdout, &data->opnds[i]);
128          printf("\n");
129       }
130    }
131    if (verbose > 2)
132       if (data->rounding_mode != NO_ROUNDING_MODE)
133          printf("rounding mode %u\n", data->rounding_mode);
134 
135    valgrind_vex_inject_ir();
136    valgrind_get_vbits(&data->result);
137    if (verbose > 2) {
138       printf("result:   ");
139       print_opnd(stdout, &data->result);
140       printf("\n");
141    }
142 }
143