blob: c127acad2b47f93db392a4d2f0c5e11ad84ecf9f [file] [log] [blame]
florian2245ce92012-08-28 16:49:30 +00001/* -*- 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
Elliott Hughesed398002017-06-21 14:41:24 -070012 Copyright (C) 2012-2017 Florian Krohm (britzel@acm.org)
florian2245ce92012-08-28 16:49:30 +000013
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 */
florian16d12b42012-09-13 19:33:24 +000038#define mkU8(v) IRExpr_Const(IRConst_U8(v))
Elliott Hughesa0664b92017-04-18 17:46:52 -070039#define mkU16(v) IRExpr_Const(IRConst_U16(v))
florian2245ce92012-08-28 16:49:30 +000040#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. */
51static IRICB iricb;
52
53
54void
55LibVEX_InitIRI(const IRICB *iricb_in)
56{
57 iricb = *iricb_in; // copy in
58}
59
60
61static IRExpr *
62load_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. */
82static IRExpr *
83load(IREndness endian, IRType type, HWord haddr)
84{
85 IROp concat;
86 IRExpr *addr, *next_addr;
87
floriandfc55f82012-08-29 17:40:52 +000088 vassert(type == Ity_I1 || sizeofIRType(type) <= 16);
89
florian2245ce92012-08-28 16:49:30 +000090 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);
floriandfc55f82012-08-29 17:40:52 +000095 next_addr = binop(Iop_Add32, addr, mkU32(8));
florian2245ce92012-08-28 16:49:30 +000096 } 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
125static void
126store_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
florianc23579d2013-02-07 03:28:52 +0000144 of 8-byte stores will be generated. */
florian54342272015-05-16 16:16:37 +0000145static __inline__ void
florian2245ce92012-08-28 16:49:30 +0000146store(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);
floriandfc55f82012-08-29 17:40:52 +0000156 next_addr = binop(Iop_Add32, addr, mkU32(8));
florian2245ce92012-08-28 16:49:30 +0000157 } else {
158 vpanic("invalid #bytes for address");
159 }
160
floriandfc55f82012-08-29 17:40:52 +0000161 IRType type = typeOfIRExpr(irsb->tyenv, data);
162
163 vassert(type == Ity_I1 || sizeofIRType(type) <= 16);
164
165 switch (type) {
florian2245ce92012-08-28 16:49:30 +0000166 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. */
192void
193vex_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);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700213 /* HACK, compiler warning ‘opnd2’ may be used uninitialized */
214 opnd2 = opnd1;
florian16d12b42012-09-13 19:33:24 +0000215
Elliott Hughesa0664b92017-04-18 17:46:52 -0700216 /* 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
floriancd9a1a42015-10-17 11:19:11 +0000225 /* Interpret the memory as an ULong. */
Elliott Hughesa0664b92017-04-18 17:46:52 -0700226 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 }
florian16d12b42012-09-13 19:33:24 +0000233 } else {
234 opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
235 }
236
florian2245ce92012-08-28 16:49:30 +0000237 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);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700246 /* 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 }
florian2245ce92012-08-28 16:49:30 +0000268 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);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700279 /* 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 }
florian2245ce92012-08-28 16:49:30 +0000301 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");
florianc23579d2013-02-07 03:28:52 +0000312 if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
florian2245ce92012-08-28 16:49:30 +0000313 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]);
florian2245ce92012-08-28 16:49:30 +0000318 }
florian84d1b242012-08-28 20:58:23 +0000319 vex_printf("\nEND inject\n");
florian2245ce92012-08-28 16:49:30 +0000320 }
321}
322
323/*---------------------------------------------------------------*/
324/*--- end ir_inject.c ---*/
325/*---------------------------------------------------------------*/