1/* -*- mode: C; c-basic-offset: 3; -*- */ 2 3/*---------------------------------------------------------------*/ 4/*--- begin ir_inject.c ---*/ 5/*---------------------------------------------------------------*/ 6 7 8/* 9 This file is part of Valgrind, a dynamic binary instrumentation 10 framework. 11 12 Copyright (C) 2012-2013 Florian Krohm (britzel@acm.org) 13 14 This program is free software; you can redistribute it and/or 15 modify it under the terms of the GNU General Public License as 16 published by the Free Software Foundation; either version 2 of the 17 License, or (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, but 20 WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; if not, write to the Free Software 26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 27 02110-1301, USA. 28 29 The GNU General Public License is contained in the file COPYING. 30*/ 31 32#include "libvex_basictypes.h" 33#include "libvex_ir.h" 34#include "libvex.h" 35#include "main_util.h" 36 37/* Convenience macros for readibility */ 38#define mkU8(v) IRExpr_Const(IRConst_U8(v)) 39#define mkU32(v) IRExpr_Const(IRConst_U32(v)) 40#define mkU64(v) IRExpr_Const(IRConst_U64(v)) 41#define unop(kind, a) IRExpr_Unop(kind, a) 42#define binop(kind, a1, a2) IRExpr_Binop(kind, a1, a2) 43#define triop(kind, a1, a2, a3) IRExpr_Triop(kind, a1, a2, a3) 44#define qop(kind, a1, a2, a3, a4) IRExpr_Qop(kind, a1, a2, a3, a4) 45#define stmt(irsb, st) addStmtToIRSB(irsb, st) 46 47 48/* The IR Injection Control Block. vex_inject_ir will query its contents 49 to construct IR statements for testing purposes. */ 50static IRICB iricb; 51 52 53void 54LibVEX_InitIRI(const IRICB *iricb_in) 55{ 56 iricb = *iricb_in; // copy in 57} 58 59 60static IRExpr * 61load_aux(IREndness endian, IRType type, IRExpr *addr) 62{ 63 if (type == Ity_D64) { 64 /* The insn selectors do not support loading a DFP value from memory. 65 So we need to fix it here by loading an integer value and 66 reinterpreting it as DFP. */ 67 return unop(Iop_ReinterpI64asD64, 68 IRExpr_Load(endian, Ity_I64, addr)); 69 } 70 if (type == Ity_I1) { 71 /* A Boolean value is stored as a 32-bit entity (see store_aux). */ 72 return unop(Iop_32to1, IRExpr_Load(endian, Ity_I32, addr)); 73 } 74 75 return IRExpr_Load(endian, type, addr); 76} 77 78 79/* Load a value from memory. Loads of more than 8 byte are split into 80 a series of 8-byte loads and combined using appropriate IROps. */ 81static IRExpr * 82load(IREndness endian, IRType type, HWord haddr) 83{ 84 IROp concat; 85 IRExpr *addr, *next_addr; 86 87 vassert(type == Ity_I1 || sizeofIRType(type) <= 16); 88 89 if (VEX_HOST_WORDSIZE == 8) { 90 addr = mkU64(haddr); 91 next_addr = binop(Iop_Add64, addr, mkU64(8)); 92 } else if (VEX_HOST_WORDSIZE == 4) { 93 addr = mkU32(haddr); 94 next_addr = binop(Iop_Add32, addr, mkU32(8)); 95 } else { 96 vpanic("invalid #bytes for address"); 97 } 98 99 switch (type) { 100 case Ity_I128: concat = Iop_64HLto128; type = Ity_I64; goto load128; 101 case Ity_F128: concat = Iop_F64HLtoF128; type = Ity_F64; goto load128; 102 case Ity_D128: concat = Iop_D64HLtoD128; type = Ity_D64; goto load128; 103 104 load128: 105 /* Two loads of 64 bit each. */ 106 if (endian == Iend_BE) { 107 /* The more significant bits are at the lower address. */ 108 return binop(concat, 109 load_aux(endian, type, addr), 110 load_aux(endian, type, next_addr)); 111 } else { 112 /* The more significant bits are at the higher address. */ 113 return binop(concat, 114 load_aux(endian, type, next_addr), 115 load_aux(endian, type, addr)); 116 } 117 118 default: 119 return load_aux(endian, type, addr); 120 } 121} 122 123 124static void 125store_aux(IRSB *irsb, IREndness endian, IRExpr *addr, IRExpr *data) 126{ 127 if (typeOfIRExpr(irsb->tyenv, data) == Ity_D64) { 128 /* The insn selectors do not support writing a DFP value to memory. 129 So we need to fix it here by reinterpreting the DFP value as an 130 integer and storing that. */ 131 data = unop(Iop_ReinterpD64asI64, data); 132 } 133 if (typeOfIRExpr(irsb->tyenv, data) == Ity_I1) { 134 /* We cannot store a single bit. So we store it in a 32-bit container. 135 See also load_aux. */ 136 data = unop(Iop_1Uto32, data); 137 } 138 stmt(irsb, IRStmt_Store(endian, addr, data)); 139} 140 141 142/* Store a value to memory. If a value requires more than 8 bytes a series 143 of 8-byte stores will be generated. */ 144static void __inline__ 145store(IRSB *irsb, IREndness endian, HWord haddr, IRExpr *data) 146{ 147 IROp high, low; 148 IRExpr *addr, *next_addr; 149 150 if (VEX_HOST_WORDSIZE == 8) { 151 addr = mkU64(haddr); 152 next_addr = binop(Iop_Add64, addr, mkU64(8)); 153 } else if (VEX_HOST_WORDSIZE == 4) { 154 addr = mkU32(haddr); 155 next_addr = binop(Iop_Add32, addr, mkU32(8)); 156 } else { 157 vpanic("invalid #bytes for address"); 158 } 159 160 IRType type = typeOfIRExpr(irsb->tyenv, data); 161 162 vassert(type == Ity_I1 || sizeofIRType(type) <= 16); 163 164 switch (type) { 165 case Ity_I128: high = Iop_128HIto64; low = Iop_128to64; goto store128; 166 case Ity_F128: high = Iop_F128HItoF64; low = Iop_F128LOtoF64; goto store128; 167 case Ity_D128: high = Iop_D128HItoD64; low = Iop_D128LOtoD64; goto store128; 168 169 store128: 170 /* Two stores of 64 bit each. */ 171 if (endian == Iend_BE) { 172 /* The more significant bits are at the lower address. */ 173 store_aux(irsb, endian, addr, unop(high, data)); 174 store_aux(irsb, endian, next_addr, unop(low, data)); 175 } else { 176 /* The more significant bits are at the higher address. */ 177 store_aux(irsb, endian, addr, unop(low, data)); 178 store_aux(irsb, endian, next_addr, unop(high, data)); 179 } 180 return; 181 182 default: 183 store_aux(irsb, endian, addr, data); 184 return; 185 } 186} 187 188 189/* Inject IR stmts depending on the data provided in the control 190 block iricb. */ 191void 192vex_inject_ir(IRSB *irsb, IREndness endian) 193{ 194 IRExpr *data, *rounding_mode, *opnd1, *opnd2, *opnd3, *opnd4; 195 196 rounding_mode = NULL; 197 if (iricb.rounding_mode != NO_ROUNDING_MODE) { 198 rounding_mode = mkU32(iricb.rounding_mode); 199 } 200 201 switch (iricb.num_operands) { 202 case 1: 203 opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1); 204 if (rounding_mode) 205 data = binop(iricb.op, rounding_mode, opnd1); 206 else 207 data = unop(iricb.op, opnd1); 208 break; 209 210 case 2: 211 opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1); 212 213 if (iricb.shift_amount_is_immediate) { 214 // This implies that the IROp is a shift op 215 vassert(iricb.t_opnd2 == Ity_I8); 216 opnd2 = mkU8(*((Char *)iricb.opnd2)); 217 } else { 218 opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2); 219 } 220 221 if (rounding_mode) 222 data = triop(iricb.op, rounding_mode, opnd1, opnd2); 223 else 224 data = binop(iricb.op, opnd1, opnd2); 225 break; 226 227 case 3: 228 opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1); 229 opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2); 230 opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3); 231 if (rounding_mode) 232 data = qop(iricb.op, rounding_mode, opnd1, opnd2, opnd3); 233 else 234 data = triop(iricb.op, opnd1, opnd2, opnd3); 235 break; 236 237 case 4: 238 vassert(rounding_mode == NULL); 239 opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1); 240 opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2); 241 opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3); 242 opnd4 = load(endian, iricb.t_opnd4, iricb.opnd4); 243 data = qop(iricb.op, opnd1, opnd2, opnd3, opnd4); 244 break; 245 246 default: 247 vpanic("unsupported operator"); 248 } 249 250 store(irsb, endian, iricb.result, data); 251 252 if (0) { 253 vex_printf("BEGIN inject\n"); 254 if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) { 255 ppIRStmt(irsb->stmts[irsb->stmts_used - 1]); 256 } else if (sizeofIRType(iricb.t_result) == 16) { 257 ppIRStmt(irsb->stmts[irsb->stmts_used - 2]); 258 vex_printf("\n"); 259 ppIRStmt(irsb->stmts[irsb->stmts_used - 1]); 260 } 261 vex_printf("\nEND inject\n"); 262 } 263} 264 265/*---------------------------------------------------------------*/ 266/*--- end ir_inject.c ---*/ 267/*---------------------------------------------------------------*/ 268