• 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-2017  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 mkU16(v)  IRExpr_Const(IRConst_U16(v))
40 #define mkU32(v)  IRExpr_Const(IRConst_U32(v))
41 #define mkU64(v)  IRExpr_Const(IRConst_U64(v))
42 #define unop(kind, a)  IRExpr_Unop(kind, a)
43 #define binop(kind, a1, a2)  IRExpr_Binop(kind, a1, a2)
44 #define triop(kind, a1, a2, a3)  IRExpr_Triop(kind, a1, a2, a3)
45 #define qop(kind, a1, a2, a3, a4)  IRExpr_Qop(kind, a1, a2, a3, a4)
46 #define stmt(irsb, st)  addStmtToIRSB(irsb, st)
47 
48 
49 /* The IR Injection Control Block. vex_inject_ir will query its contents
50    to construct IR statements for testing purposes. */
51 static IRICB iricb;
52 
53 
54 void
LibVEX_InitIRI(const IRICB * iricb_in)55 LibVEX_InitIRI(const IRICB *iricb_in)
56 {
57    iricb = *iricb_in;  // copy in
58 }
59 
60 
61 static IRExpr *
load_aux(IREndness endian,IRType type,IRExpr * addr)62 load_aux(IREndness endian, IRType type, IRExpr *addr)
63 {
64    if (type == Ity_D64) {
65       /* The insn selectors do not support loading a DFP value from memory.
66          So we need to fix it here by loading an integer value and
67          reinterpreting it as DFP. */
68       return unop(Iop_ReinterpI64asD64,
69                   IRExpr_Load(endian, Ity_I64, addr));
70    }
71    if (type == Ity_I1) {
72       /* A Boolean value is stored as a 32-bit entity (see store_aux). */
73       return unop(Iop_32to1, IRExpr_Load(endian, Ity_I32, addr));
74    }
75 
76    return IRExpr_Load(endian, type, addr);
77 }
78 
79 
80 /* Load a value from memory. Loads of more than 8 byte are split into
81    a series of 8-byte loads and combined using appropriate IROps. */
82 static IRExpr *
load(IREndness endian,IRType type,HWord haddr)83 load(IREndness endian, IRType type, HWord haddr)
84 {
85    IROp concat;
86    IRExpr *addr, *next_addr;
87 
88    vassert(type == Ity_I1 || sizeofIRType(type) <= 16);
89 
90    if (VEX_HOST_WORDSIZE == 8) {
91       addr = mkU64(haddr);
92       next_addr = binop(Iop_Add64, addr, mkU64(8));
93    } else if (VEX_HOST_WORDSIZE == 4) {
94       addr = mkU32(haddr);
95       next_addr = binop(Iop_Add32, addr, mkU32(8));
96    } else {
97       vpanic("invalid #bytes for address");
98    }
99 
100    switch (type) {
101    case Ity_I128: concat = Iop_64HLto128;   type = Ity_I64; goto load128;
102    case Ity_F128: concat = Iop_F64HLtoF128; type = Ity_F64; goto load128;
103    case Ity_D128: concat = Iop_D64HLtoD128; type = Ity_D64; goto load128;
104 
105    load128:
106      /* Two loads of 64 bit each. */
107       if (endian == Iend_BE) {
108          /* The more significant bits are at the lower address. */
109          return binop(concat,
110                       load_aux(endian, type, addr),
111                       load_aux(endian, type, next_addr));
112       } else {
113          /* The more significant bits are at the higher address. */
114          return binop(concat,
115                       load_aux(endian, type, next_addr),
116                       load_aux(endian, type, addr));
117       }
118 
119    default:
120       return load_aux(endian, type, addr);
121    }
122 }
123 
124 
125 static void
store_aux(IRSB * irsb,IREndness endian,IRExpr * addr,IRExpr * data)126 store_aux(IRSB *irsb, IREndness endian, IRExpr *addr, IRExpr *data)
127 {
128    if (typeOfIRExpr(irsb->tyenv, data) == Ity_D64) {
129       /* The insn selectors do not support writing a DFP value to memory.
130          So we need to fix it here by reinterpreting the DFP value as an
131          integer and storing that. */
132       data = unop(Iop_ReinterpD64asI64, data);
133    }
134    if (typeOfIRExpr(irsb->tyenv, data) == Ity_I1) {
135       /* We cannot store a single bit. So we store it in a 32-bit container.
136          See also load_aux. */
137       data = unop(Iop_1Uto32, data);
138    }
139    stmt(irsb, IRStmt_Store(endian, addr, data));
140 }
141 
142 
143 /* Store a value to memory. If a value requires more than 8 bytes a series
144    of 8-byte stores will be generated. */
145 static __inline__ void
store(IRSB * irsb,IREndness endian,HWord haddr,IRExpr * data)146 store(IRSB *irsb, IREndness endian, HWord haddr, IRExpr *data)
147 {
148    IROp high, low;
149    IRExpr *addr, *next_addr;
150 
151    if (VEX_HOST_WORDSIZE == 8) {
152       addr = mkU64(haddr);
153       next_addr = binop(Iop_Add64, addr, mkU64(8));
154    } else if (VEX_HOST_WORDSIZE == 4) {
155       addr = mkU32(haddr);
156       next_addr = binop(Iop_Add32, addr, mkU32(8));
157    } else {
158       vpanic("invalid #bytes for address");
159    }
160 
161    IRType type = typeOfIRExpr(irsb->tyenv, data);
162 
163    vassert(type == Ity_I1 || sizeofIRType(type) <= 16);
164 
165    switch (type) {
166    case Ity_I128: high = Iop_128HIto64;   low = Iop_128to64;     goto store128;
167    case Ity_F128: high = Iop_F128HItoF64; low = Iop_F128LOtoF64; goto store128;
168    case Ity_D128: high = Iop_D128HItoD64; low = Iop_D128LOtoD64; goto store128;
169 
170    store128:
171      /* Two stores of 64 bit each. */
172       if (endian == Iend_BE) {
173          /* The more significant bits are at the lower address. */
174          store_aux(irsb, endian, addr, unop(high, data));
175          store_aux(irsb, endian, next_addr, unop(low, data));
176       } else {
177          /* The more significant bits are at the higher address. */
178          store_aux(irsb, endian, addr, unop(low, data));
179          store_aux(irsb, endian, next_addr, unop(high, data));
180       }
181       return;
182 
183    default:
184       store_aux(irsb, endian, addr, data);
185       return;
186    }
187 }
188 
189 
190 /* Inject IR stmts depending on the data provided in the control
191    block iricb. */
192 void
vex_inject_ir(IRSB * irsb,IREndness endian)193 vex_inject_ir(IRSB *irsb, IREndness endian)
194 {
195    IRExpr *data, *rounding_mode, *opnd1, *opnd2, *opnd3, *opnd4;
196 
197    rounding_mode = NULL;
198    if (iricb.rounding_mode != NO_ROUNDING_MODE) {
199       rounding_mode = mkU32(iricb.rounding_mode);
200    }
201 
202    switch (iricb.num_operands) {
203    case 1:
204       opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
205       if (rounding_mode)
206          data = binop(iricb.op, rounding_mode, opnd1);
207       else
208          data = unop(iricb.op, opnd1);
209       break;
210 
211    case 2:
212       opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
213       /* HACK, compiler warning ‘opnd2’ may be used uninitialized */
214       opnd2 = opnd1;
215 
216       /* immediate_index = 0  immediate value is not used.
217        * immediate_index = 2  opnd2 is an immediate value.
218        */
219       vassert(iricb.immediate_index == 0 || iricb.immediate_index == 2);
220 
221       if (iricb.immediate_index == 2) {
222          vassert((iricb.t_opnd2 == Ity_I8) || (iricb.t_opnd2 == Ity_I16)
223                  || (iricb.t_opnd2 == Ity_I32));
224 
225          /* Interpret the memory as an ULong. */
226          if (iricb.immediate_type == Ity_I8) {
227             opnd2 = mkU8(*((ULong *)iricb.opnd2));
228          } else if (iricb.immediate_type == Ity_I16) {
229             opnd2 = mkU16(*((ULong *)iricb.opnd2));
230          } else if (iricb.immediate_type == Ity_I32) {
231             opnd2 = mkU32(*((ULong *)iricb.opnd2));
232          }
233       } else {
234          opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
235       }
236 
237       if (rounding_mode)
238          data = triop(iricb.op, rounding_mode, opnd1, opnd2);
239       else
240          data = binop(iricb.op, opnd1, opnd2);
241       break;
242 
243    case 3:
244       opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
245       opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
246       /* HACK, compiler warning ‘opnd3’ may be used uninitialized */
247       opnd3 = opnd2;
248 
249       /* immediate_index = 0  immediate value is not used.
250        * immediate_index = 3  opnd3 is an immediate value.
251        */
252       vassert(iricb.immediate_index == 0 || iricb.immediate_index == 3);
253 
254       if (iricb.immediate_index == 3) {
255          vassert((iricb.t_opnd3 == Ity_I8) || (iricb.t_opnd3 == Ity_I16)
256                  || (iricb.t_opnd2 == Ity_I32));
257 
258          if (iricb.immediate_type == Ity_I8) {
259             opnd3 = mkU8(*((ULong *)iricb.opnd3));
260          } else if (iricb.immediate_type == Ity_I16) {
261             opnd3 = mkU16(*((ULong *)iricb.opnd3));
262          } else if (iricb.immediate_type == Ity_I32) {
263             opnd3 = mkU32(*((ULong *)iricb.opnd3));
264          }
265       } else {
266          opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
267       }
268       if (rounding_mode)
269          data = qop(iricb.op, rounding_mode, opnd1, opnd2, opnd3);
270       else
271          data = triop(iricb.op, opnd1, opnd2, opnd3);
272       break;
273 
274    case 4:
275       vassert(rounding_mode == NULL);
276       opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
277       opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
278       opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
279       /* HACK, compiler warning ‘opnd4’ may be used uninitialized */
280       opnd4 = opnd3;
281 
282       /* immediate_index = 0  immediate value is not used.
283        * immediate_index = 4  opnd4 is an immediate value.
284        */
285       vassert(iricb.immediate_index == 0 || iricb.immediate_index == 4);
286 
287       if (iricb.immediate_index == 4) {
288          vassert((iricb.t_opnd3 == Ity_I8) || (iricb.t_opnd3 == Ity_I16)
289                  || (iricb.t_opnd2 == Ity_I32));
290 
291          if (iricb.immediate_type == Ity_I8) {
292             opnd4 = mkU8(*((ULong *)iricb.opnd4));
293          } else if (iricb.immediate_type == Ity_I16) {
294             opnd4 = mkU16(*((ULong *)iricb.opnd4));
295          } else if (iricb.immediate_type == Ity_I32) {
296             opnd4 = mkU32(*((ULong *)iricb.opnd4));
297          }
298       } else {
299          opnd4 = load(endian, iricb.t_opnd4, iricb.opnd4);
300       }
301       data = qop(iricb.op, opnd1, opnd2, opnd3, opnd4);
302       break;
303 
304    default:
305       vpanic("unsupported operator");
306    }
307 
308    store(irsb, endian, iricb.result, data);
309 
310    if (0) {
311       vex_printf("BEGIN inject\n");
312       if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
313          ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
314       } else if (sizeofIRType(iricb.t_result) == 16) {
315          ppIRStmt(irsb->stmts[irsb->stmts_used - 2]);
316          vex_printf("\n");
317          ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
318       }
319       vex_printf("\nEND inject\n");
320    }
321 }
322 
323 /*---------------------------------------------------------------*/
324 /*--- end                                         ir_inject.c ---*/
325 /*---------------------------------------------------------------*/
326