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