1 /* -*- mode: C; c-basic-offset: 3; -*- */ 2 3 #include <assert.h> 4 #include "memcheck.h" // VALGRIND_SET_VBITS 5 #include "vtest.h" 6 7 8 /* Return a completely initialised control block */ 9 IRICB 10 new_iricb(const irop_t *op, test_data_t *data) 11 { 12 IRICB cb; 13 14 cb.op = op->op; 15 cb.result = (HWord)&data->result.value; 16 cb.opnd1 = (HWord)&data->opnds[0].value; 17 cb.opnd2 = (HWord)&data->opnds[1].value; 18 cb.opnd3 = (HWord)&data->opnds[2].value; 19 cb.opnd4 = (HWord)&data->opnds[3].value; 20 cb.t_result = data->result.type; 21 cb.t_opnd1 = data->opnds[0].type; 22 cb.t_opnd2 = data->opnds[1].type; 23 cb.t_opnd3 = data->opnds[2].type; 24 cb.t_opnd4 = data->opnds[3].type; 25 26 cb.rounding_mode = data->rounding_mode; 27 28 cb.num_operands = get_num_operands(op->op); 29 30 cb.shift_amount_is_immediate = op->shift_amount_is_immediate; 31 32 return cb; 33 } 34 35 36 /* Ity_I1 values cannot be stored or loaded. So vex_inject_ir will load/store 37 such a value from/to a 4-byte container. It uses 32to1 and 1Uto32, 38 respectively. */ 39 static void 40 valgrind_set_vbits(opnd_t *opnd) 41 { 42 unsigned rc, num_bytes; 43 44 /* 1-bit wide values cannot be read. So we read a 4 bytes here */ 45 num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type); 46 rc = VALGRIND_SET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes); 47 assert(rc == 1); 48 49 // Make sure the v-bits were set correctly 50 vbits_t actual = { .num_bits = opnd->vbits.num_bits }; 51 rc = VALGRIND_GET_VBITS(&opnd->value, &actual.bits, num_bytes); 52 assert(rc == 1); 53 54 assert(equal_vbits(opnd->vbits, actual)); 55 } 56 57 58 static void 59 valgrind_get_vbits(opnd_t *opnd) 60 { 61 unsigned rc, num_bytes; 62 63 /* 1-bit wide values cannot be stored. So we store them by writing a 64 single byte */ 65 num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type); 66 opnd->vbits.num_bits = bitsof_irtype(opnd->type); 67 rc = VALGRIND_GET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes); 68 assert(rc == 1); 69 } 70 71 72 /* Insert a client request that will initialize VEX for IR injection */ 73 void 74 valgrind_vex_init_for_iri(IRICB *cb) 75 { 76 VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__VEX_INIT_FOR_IRI, cb, 0,0,0,0); 77 } 78 79 80 /* Insert a special opcode that will cause VEX to inject an IR stmt based 81 on the information passed in the IRICB (in valgrind_vex_init_for_iri). */ 82 static void 83 valgrind_vex_inject_ir(void) 84 { 85 VALGRIND_VEX_INJECT_IR(); 86 } 87 88 89 /* Execute the test under valgrind. Well, yes, we're not really executing 90 it here, just preparing for it... */ 91 void 92 valgrind_execute_test(const irop_t *op, test_data_t *data) 93 { 94 unsigned i, num_operands; 95 96 if (verbose > 2) printf("---------- Running a test\n"); 97 num_operands = get_num_operands(op->op); 98 99 for (i = 0; i < num_operands; ++i) { 100 valgrind_set_vbits(&data->opnds[i]); 101 if (verbose > 2) { 102 printf("opnd #%u: ", i); 103 print_opnd(stdout, &data->opnds[i]); 104 printf("\n"); 105 } 106 } 107 if (verbose > 2) 108 if (data->rounding_mode != NO_ROUNDING_MODE) 109 printf("rounding mode %u\n", data->rounding_mode); 110 111 valgrind_vex_inject_ir(); 112 valgrind_get_vbits(&data->result); 113 if (verbose > 2) { 114 printf("result: "); 115 print_opnd(stdout, &data->result); 116 printf("\n"); 117 } 118 } 119