• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
LibVEX_InitIRI(const IRICB * iricb_in)54 LibVEX_InitIRI(const IRICB *iricb_in)
55 {
56    iricb = *iricb_in;  // copy in
57 }
58 
59 
60 static IRExpr *
load_aux(IREndness endian,IRType type,IRExpr * addr)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 *
load(IREndness endian,IRType type,HWord haddr)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
store_aux(IRSB * irsb,IREndness endian,IRExpr * addr,IRExpr * data)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
store(IRSB * irsb,IREndness endian,HWord haddr,IRExpr * data)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
vex_inject_ir(IRSB * irsb,IREndness endian)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