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