Home | History | Annotate | Download | only in priv
      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-2015  Florian Krohm   (britzel (at) 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. */
     50 static IRICB iricb;
     51 
     52 
     53 void
     54 LibVEX_InitIRI(const IRICB *iricb_in)
     55 {
     56    iricb = *iricb_in;  // copy in
     57 }
     58 
     59 
     60 static IRExpr *
     61 load_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. */
     81 static IRExpr *
     82 load(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 
    124 static void
    125 store_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. */
    144 static __inline__ void
    145 store(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. */
    191 void
    192 vex_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          /* Interpret the memory as an ULong. */
    217          opnd2 = mkU8(*((ULong *)iricb.opnd2));
    218       } else {
    219          opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
    220       }
    221 
    222       if (rounding_mode)
    223          data = triop(iricb.op, rounding_mode, opnd1, opnd2);
    224       else
    225          data = binop(iricb.op, opnd1, opnd2);
    226       break;
    227 
    228    case 3:
    229       opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
    230       opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
    231       opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
    232       if (rounding_mode)
    233          data = qop(iricb.op, rounding_mode, opnd1, opnd2, opnd3);
    234       else
    235          data = triop(iricb.op, opnd1, opnd2, opnd3);
    236       break;
    237 
    238    case 4:
    239       vassert(rounding_mode == NULL);
    240       opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
    241       opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
    242       opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
    243       opnd4 = load(endian, iricb.t_opnd4, iricb.opnd4);
    244       data = qop(iricb.op, opnd1, opnd2, opnd3, opnd4);
    245       break;
    246 
    247    default:
    248       vpanic("unsupported operator");
    249    }
    250 
    251    store(irsb, endian, iricb.result, data);
    252 
    253    if (0) {
    254       vex_printf("BEGIN inject\n");
    255       if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
    256          ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
    257       } else if (sizeofIRType(iricb.t_result) == 16) {
    258          ppIRStmt(irsb->stmts[irsb->stmts_used - 2]);
    259          vex_printf("\n");
    260          ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
    261       }
    262       vex_printf("\nEND inject\n");
    263    }
    264 }
    265 
    266 /*---------------------------------------------------------------*/
    267 /*--- end                                         ir_inject.c ---*/
    268 /*---------------------------------------------------------------*/
    269