1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*---------------------------------------------------------------*/
4 /*--- begin ir_inject.c ---*/
5 /*---------------------------------------------------------------*/
9 This file is part of Valgrind, a dynamic binary instrumentation
12 Copyright (C) 2012-2017 Florian Krohm (britzel@acm.org)
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.
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.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #include "libvex_basictypes.h"
31 #include "libvex_ir.h"
33 #include "main_util.h"
35 /* Convenience macros for readibility */
36 #define mkU8(v) IRExpr_Const(IRConst_U8(v))
37 #define mkU16(v) IRExpr_Const(IRConst_U16(v))
38 #define mkU32(v) IRExpr_Const(IRConst_U32(v))
39 #define mkU64(v) IRExpr_Const(IRConst_U64(v))
40 #define unop(kind, a) IRExpr_Unop(kind, a)
41 #define binop(kind, a1, a2) IRExpr_Binop(kind, a1, a2)
42 #define triop(kind, a1, a2, a3) IRExpr_Triop(kind, a1, a2, a3)
43 #define qop(kind, a1, a2, a3, a4) IRExpr_Qop(kind, a1, a2, a3, a4)
44 #define stmt(irsb, st) addStmtToIRSB(irsb, st)
47 /* The IR Injection Control Block. vex_inject_ir will query its contents
48 to construct IR statements for testing purposes. */
53 LibVEX_InitIRI(const IRICB
*iricb_in
)
55 iricb
= *iricb_in
; // copy in
60 load_aux(IREndness endian
, IRType type
, IRExpr
*addr
)
62 if (type
== Ity_D64
) {
63 /* The insn selectors do not support loading a DFP value from memory.
64 So we need to fix it here by loading an integer value and
65 reinterpreting it as DFP. */
66 return unop(Iop_ReinterpI64asD64
,
67 IRExpr_Load(endian
, Ity_I64
, addr
));
70 /* A Boolean value is stored as a 32-bit entity (see store_aux). */
71 return unop(Iop_32to1
, IRExpr_Load(endian
, Ity_I32
, addr
));
74 return IRExpr_Load(endian
, type
, addr
);
78 /* Load a value from memory. Loads of more than 8 byte are split into
79 a series of 8-byte loads and combined using appropriate IROps. */
81 load(IREndness endian
, IRType type
, HWord haddr
)
84 IRExpr
*addr
, *next_addr
;
86 vassert(type
== Ity_I1
|| sizeofIRType(type
) <= 16);
88 if (VEX_HOST_WORDSIZE
== 8 ||
89 (VEX_HOST_WORDSIZE
== 4 && sizeof(RegWord
) == 8)) {
91 next_addr
= binop(Iop_Add64
, addr
, mkU64(8));
92 } else if (VEX_HOST_WORDSIZE
== 4) {
94 next_addr
= binop(Iop_Add32
, addr
, mkU32(8));
96 vpanic("invalid #bytes for address");
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
;
105 /* Two loads of 64 bit each. */
106 if (endian
== Iend_BE
) {
107 /* The more significant bits are at the lower address. */
109 load_aux(endian
, type
, addr
),
110 load_aux(endian
, type
, next_addr
));
112 /* The more significant bits are at the higher address. */
114 load_aux(endian
, type
, next_addr
),
115 load_aux(endian
, type
, addr
));
119 return load_aux(endian
, type
, addr
);
125 store_aux(IRSB
*irsb
, IREndness endian
, IRExpr
*addr
, IRExpr
*data
)
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
);
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
);
138 stmt(irsb
, IRStmt_Store(endian
, addr
, data
));
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
)
148 IRExpr
*addr
, *next_addr
;
150 if (VEX_HOST_WORDSIZE
== 8 ||
151 (VEX_HOST_WORDSIZE
== 4 && sizeof(RegWord
) == 8)) {
153 next_addr
= binop(Iop_Add64
, addr
, mkU64(8));
154 } else if (VEX_HOST_WORDSIZE
== 4) {
156 next_addr
= binop(Iop_Add32
, addr
, mkU32(8));
158 vpanic("invalid #bytes for address");
161 IRType type
= typeOfIRExpr(irsb
->tyenv
, data
);
163 vassert(type
== Ity_I1
|| sizeofIRType(type
) <= 16);
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
;
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
));
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
));
184 store_aux(irsb
, endian
, addr
, data
);
190 /* Inject IR stmts depending on the data provided in the control
193 vex_inject_ir(IRSB
*irsb
, IREndness endian
)
195 IRExpr
*data
, *rounding_mode
, *opnd1
, *opnd2
, *opnd3
, *opnd4
;
197 rounding_mode
= NULL
;
198 if (iricb
.rounding_mode
!= NO_ROUNDING_MODE
) {
199 rounding_mode
= mkU32(iricb
.rounding_mode
);
202 switch (iricb
.num_operands
) {
204 opnd1
= load(endian
, iricb
.t_opnd1
, iricb
.opnd1
);
206 data
= binop(iricb
.op
, rounding_mode
, opnd1
);
208 data
= unop(iricb
.op
, opnd1
);
212 opnd1
= load(endian
, iricb
.t_opnd1
, iricb
.opnd1
);
213 /* HACK, compiler warning ‘opnd2’ may be used uninitialized */
216 /* immediate_index = 0 immediate value is not used.
217 * immediate_index = 2 opnd2 is an immediate value.
219 vassert(iricb
.immediate_index
== 0 || iricb
.immediate_index
== 2);
221 if (iricb
.immediate_index
== 2) {
222 vassert((iricb
.t_opnd2
== Ity_I8
) || (iricb
.t_opnd2
== Ity_I16
)
223 || (iricb
.t_opnd2
== Ity_I32
));
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
));
234 opnd2
= load(endian
, iricb
.t_opnd2
, iricb
.opnd2
);
238 data
= triop(iricb
.op
, rounding_mode
, opnd1
, opnd2
);
240 data
= binop(iricb
.op
, opnd1
, opnd2
);
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 */
249 /* immediate_index = 0 immediate value is not used.
250 * immediate_index = 3 opnd3 is an immediate value.
252 vassert(iricb
.immediate_index
== 0 || iricb
.immediate_index
== 3);
254 if (iricb
.immediate_index
== 3) {
255 vassert((iricb
.t_opnd3
== Ity_I8
) || (iricb
.t_opnd3
== Ity_I16
)
256 || (iricb
.t_opnd2
== Ity_I32
));
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
));
266 opnd3
= load(endian
, iricb
.t_opnd3
, iricb
.opnd3
);
269 data
= qop(iricb
.op
, rounding_mode
, opnd1
, opnd2
, opnd3
);
271 data
= triop(iricb
.op
, opnd1
, opnd2
, opnd3
);
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 */
282 /* immediate_index = 0 immediate value is not used.
283 * immediate_index = 4 opnd4 is an immediate value.
285 vassert(iricb
.immediate_index
== 0 || iricb
.immediate_index
== 4);
287 if (iricb
.immediate_index
== 4) {
288 vassert((iricb
.t_opnd3
== Ity_I8
) || (iricb
.t_opnd3
== Ity_I16
)
289 || (iricb
.t_opnd2
== Ity_I32
));
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
));
299 opnd4
= load(endian
, iricb
.t_opnd4
, iricb
.opnd4
);
301 data
= qop(iricb
.op
, opnd1
, opnd2
, opnd3
, opnd4
);
305 vpanic("unsupported operator");
308 store(irsb
, endian
, iricb
.result
, data
);
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]);
317 ppIRStmt(irsb
->stmts
[irsb
->stmts_used
- 1]);
319 vex_printf("\nEND inject\n");
323 /*---------------------------------------------------------------*/
324 /*--- end ir_inject.c ---*/
325 /*---------------------------------------------------------------*/