blob: 30e9caa2314795809597bd7fe4d97bc5bb51ea53 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
sewardjbb686272006-01-22 20:12:45 +00003/*--- Interface to LibVEX_Translate, and the SP-update pass ---*/
njn3cbfbc12005-05-13 23:11:40 +00004/*--- m_translate.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +00005/*--------------------------------------------------------------------*/
6
7/*
njnb9c427c2004-12-01 14:14:42 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
sewardjde4a1d02002-03-22 01:27:54 +000010
sewardj03f8d3f2012-08-05 15:46:46 +000011 Copyright (C) 2000-2012 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +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., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
njnc7561b92005-06-19 01:24:32 +000032#include "pub_core_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000033#include "pub_core_vki.h"
sewardj55f9d1a2005-04-25 11:11:44 +000034#include "pub_core_aspacemgr.h"
sewardje2d1e672005-11-12 23:10:48 +000035
sewardj0ec07f32006-01-12 12:32:32 +000036#include "pub_core_machine.h" // VG_(fnptr_to_fnentry)
37 // VG_(get_SP)
38 // VG_(machine_get_VexArchInfo)
njn97405b22005-06-02 03:39:33 +000039#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000040#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000041#include "pub_core_libcprint.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_core_options.h"
sewardj45f4e7c2005-09-27 19:20:21 +000043
sewardj0ec07f32006-01-12 12:32:32 +000044#include "pub_core_debuginfo.h" // VG_(get_fnname_w_offset)
45#include "pub_core_redir.h" // VG_(redir_do_lookup)
sewardj45f4e7c2005-09-27 19:20:21 +000046
sewardj0ec07f32006-01-12 12:32:32 +000047#include "pub_core_signals.h" // VG_(synth_fault_{perms,mapping}
48#include "pub_core_stacks.h" // VG_(unknown_SP_update)()
49#include "pub_core_tooliface.h" // VG_(tdict)
50
njn8bddf582005-05-13 23:40:55 +000051#include "pub_core_translate.h"
52#include "pub_core_transtab.h"
sewardj0ec07f32006-01-12 12:32:32 +000053#include "pub_core_dispatch.h" // VG_(run_innerloop__dispatch_{un}profiled)
54 // VG_(run_a_noredir_translation__return_point)
sewardj274807d2005-12-15 14:07:07 +000055
sewardj6c591e12011-04-11 16:17:51 +000056#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
sewardj34593e52006-01-17 01:57:33 +000057#include "pub_core_threadstate.h" // VexGuestArchState
sewardj4a0009c2006-10-17 01:52:05 +000058#include "pub_core_trampoline.h" // VG_(ppctoc_magic_redirect_return_stub)
sewardj34593e52006-01-17 01:57:33 +000059
sewardj7cf4e6b2008-05-01 20:24:26 +000060#include "pub_core_execontext.h" // VG_(make_depth_1_ExeContext_from_Addr)
61
sewardj3b290482011-05-06 21:02:55 +000062#include "pub_core_gdbserver.h" // VG_(tool_instrument_then_gdbserver_if_needed)
sewardjde4a1d02002-03-22 01:27:54 +000063
njna1f783f2005-06-18 03:44:34 +000064/*------------------------------------------------------------*/
njn42c83552005-12-05 20:45:59 +000065/*--- Stats ---*/
66/*------------------------------------------------------------*/
67
68static UInt n_SP_updates_fast = 0;
69static UInt n_SP_updates_generic_known = 0;
70static UInt n_SP_updates_generic_unknown = 0;
71
72void VG_(print_translation_stats) ( void )
73{
sewardj8a5c06b2011-09-30 07:11:13 +000074 Char buf[7];
njn42c83552005-12-05 20:45:59 +000075 UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known
76 + n_SP_updates_generic_unknown;
77 VG_(percentify)(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
78 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +000079 "translate: fast SP updates identified: %'u (%s)\n",
njn42c83552005-12-05 20:45:59 +000080 n_SP_updates_fast, buf );
81
82 VG_(percentify)(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
83 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +000084 "translate: generic_known SP updates identified: %'u (%s)\n",
njn42c83552005-12-05 20:45:59 +000085 n_SP_updates_generic_known, buf );
86
87 VG_(percentify)(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf);
88 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +000089 "translate: generic_unknown SP updates identified: %'u (%s)\n",
njn42c83552005-12-05 20:45:59 +000090 n_SP_updates_generic_unknown, buf );
91}
92
93/*------------------------------------------------------------*/
sewardj8b635a42004-11-22 19:01:47 +000094/*--- %SP-update pass ---*/
nethercotebee3fd92004-08-02 15:17:43 +000095/*------------------------------------------------------------*/
96
njna1f783f2005-06-18 03:44:34 +000097static Bool need_to_handle_SP_assignment(void)
98{
sewardjf5c8e372006-02-12 15:42:20 +000099 return ( VG_(tdict).track_new_mem_stack_4 ||
100 VG_(tdict).track_die_mem_stack_4 ||
101 VG_(tdict).track_new_mem_stack_8 ||
102 VG_(tdict).track_die_mem_stack_8 ||
103 VG_(tdict).track_new_mem_stack_12 ||
104 VG_(tdict).track_die_mem_stack_12 ||
105 VG_(tdict).track_new_mem_stack_16 ||
106 VG_(tdict).track_die_mem_stack_16 ||
107 VG_(tdict).track_new_mem_stack_32 ||
108 VG_(tdict).track_die_mem_stack_32 ||
109 VG_(tdict).track_new_mem_stack_112 ||
110 VG_(tdict).track_die_mem_stack_112 ||
111 VG_(tdict).track_new_mem_stack_128 ||
112 VG_(tdict).track_die_mem_stack_128 ||
113 VG_(tdict).track_new_mem_stack_144 ||
114 VG_(tdict).track_die_mem_stack_144 ||
115 VG_(tdict).track_new_mem_stack_160 ||
116 VG_(tdict).track_die_mem_stack_160 ||
117 VG_(tdict).track_new_mem_stack ||
118 VG_(tdict).track_die_mem_stack );
njna1f783f2005-06-18 03:44:34 +0000119}
120
njn5096a392005-12-13 20:05:00 +0000121// - The SP aliases are held in an array which is used as a circular buffer.
122// This misses very few constant updates of SP (ie. < 0.1%) while using a
123// small, constant structure that will also never fill up and cause
124// execution to abort.
125// - Unused slots have a .temp value of 'IRTemp_INVALID'.
126// - 'next_SP_alias_slot' is the index where the next alias will be stored.
127// - If the buffer fills, we circle around and start over-writing
128// non-IRTemp_INVALID values. This is rare, and the overwriting of a
129// value that would have subsequently be used is even rarer.
130// - Every slot below next_SP_alias_slot holds a non-IRTemp_INVALID value.
131// The rest either all won't (if we haven't yet circled around) or all
132// will (if we have circled around).
njn9b007f62003-04-07 14:40:25 +0000133
njn5096a392005-12-13 20:05:00 +0000134typedef
135 struct {
136 IRTemp temp;
137 Long delta;
138 }
139 SP_Alias;
140
141// With 32 slots the buffer fills very rarely -- eg. once in a run of GCC.
142// And I've tested with smaller values and the wrap-around case works ok.
143#define N_ALIASES 32
144static SP_Alias SP_aliases[N_ALIASES];
145static Int next_SP_alias_slot = 0;
146
147static void clear_SP_aliases(void)
148{
149 Int i;
150 for (i = 0; i < N_ALIASES; i++) {
151 SP_aliases[i].temp = IRTemp_INVALID;
152 SP_aliases[i].delta = 0;
153 }
154 next_SP_alias_slot = 0;
155}
156
157static void add_SP_alias(IRTemp temp, Long delta)
158{
159 vg_assert(temp != IRTemp_INVALID);
160 SP_aliases[ next_SP_alias_slot ].temp = temp;
161 SP_aliases[ next_SP_alias_slot ].delta = delta;
162 next_SP_alias_slot++;
163 if (N_ALIASES == next_SP_alias_slot) next_SP_alias_slot = 0;
164}
165
166static Bool get_SP_delta(IRTemp temp, ULong* delta)
167{
168 Int i; // i must be signed!
169 vg_assert(IRTemp_INVALID != temp);
170 // Search backwards between current buffer position and the start.
171 for (i = next_SP_alias_slot-1; i >= 0; i--) {
172 if (temp == SP_aliases[i].temp) {
173 *delta = SP_aliases[i].delta;
174 return True;
175 }
176 }
177 // Search backwards between the end and the current buffer position.
178 for (i = N_ALIASES-1; i >= next_SP_alias_slot; i--) {
179 if (temp == SP_aliases[i].temp) {
180 *delta = SP_aliases[i].delta;
181 return True;
182 }
183 }
184 return False;
185}
186
187static void update_SP_aliases(Long delta)
188{
189 Int i;
190 for (i = 0; i < N_ALIASES; i++) {
191 if (SP_aliases[i].temp == IRTemp_INVALID) {
192 return;
193 }
194 SP_aliases[i].delta += delta;
195 }
196}
197
sewardj7cf4e6b2008-05-01 20:24:26 +0000198/* Given a guest IP, get an origin tag for a 1-element stack trace,
199 and wrap it up in an IR atom that can be passed as the origin-tag
200 value for a stack-adjustment helper function. */
201static IRExpr* mk_ecu_Expr ( Addr64 guest_IP )
202{
203 UInt ecu;
204 ExeContext* ec
205 = VG_(make_depth_1_ExeContext_from_Addr)( (Addr)guest_IP );
206 vg_assert(ec);
207 ecu = VG_(get_ECU_from_ExeContext)( ec );
208 vg_assert(VG_(is_plausible_ECU)(ecu));
209 /* This is always safe to do, since ecu is only 32 bits, and
210 HWord is 32 or 64. */
211 return mkIRExpr_HWord( (HWord)ecu );
212}
213
sewardj3b290482011-05-06 21:02:55 +0000214/* When gdbserver is activated, the translation of a block must
215 first be done by the tool function, then followed by a pass
216 which (if needed) instruments the code for gdbserver.
217*/
218static
219IRSB* tool_instrument_then_gdbserver_if_needed ( VgCallbackClosure* closureV,
220 IRSB* sb_in,
221 VexGuestLayout* layout,
222 VexGuestExtents* vge,
223 IRType gWordTy,
224 IRType hWordTy )
225{
226 return VG_(instrument_for_gdbserver_if_needed)
227 (VG_(tdict).tool_instrument (closureV,
228 sb_in,
229 layout,
230 vge,
231 gWordTy,
232 hWordTy),
233 layout,
234 vge,
235 gWordTy,
236 hWordTy);
237}
njn5096a392005-12-13 20:05:00 +0000238
239/* For tools that want to know about SP changes, this pass adds
nethercote996901a2004-08-03 13:29:09 +0000240 in the appropriate hooks. We have to do it after the tool's
njn5096a392005-12-13 20:05:00 +0000241 instrumentation, so the tool doesn't have to worry about the C calls
njn9b007f62003-04-07 14:40:25 +0000242 it adds in, and we must do it before register allocation because
njn5096a392005-12-13 20:05:00 +0000243 spilled temps make it much harder to work out the SP deltas.
244 This it is done with Vex's "second instrumentation" pass.
sewardjde4a1d02002-03-22 01:27:54 +0000245
njn5096a392005-12-13 20:05:00 +0000246 Basically, we look for GET(SP)/PUT(SP) pairs and track constant
247 increments/decrements of SP between them. (This requires tracking one or
248 more "aliases", which are not exact aliases but instead are tempregs
249 whose value is equal to the SP's plus or minus a known constant.)
250 If all the changes to SP leading up to a PUT(SP) are by known, small
251 constants, we can do a specific call to eg. new_mem_stack_4, otherwise
252 we fall back to the case that handles an unknown SP change.
sewardj2831b512007-11-11 18:56:39 +0000253
254 There is some extra complexity to deal correctly with updates to
255 only parts of SP. Bizarre, but it has been known to happen.
njn5096a392005-12-13 20:05:00 +0000256*/
sewardjde4a1d02002-03-22 01:27:54 +0000257static
sewardj0b9d74a2006-12-24 02:24:11 +0000258IRSB* vg_SP_update_pass ( void* closureV,
259 IRSB* sb_in,
sewardj4ba057c2005-10-18 12:04:18 +0000260 VexGuestLayout* layout,
sewardj4ba057c2005-10-18 12:04:18 +0000261 VexGuestExtents* vge,
262 IRType gWordTy,
263 IRType hWordTy )
sewardjde4a1d02002-03-22 01:27:54 +0000264{
sewardj2eecb742012-06-01 16:11:41 +0000265 Int i, j, k, minoff_ST, maxoff_ST, sizeof_SP, offset_SP;
sewardj2831b512007-11-11 18:56:39 +0000266 Int first_SP, last_SP, first_Put, last_Put;
sewardj0b9d74a2006-12-24 02:24:11 +0000267 IRDirty *dcall, *d;
268 IRStmt* st;
269 IRExpr* e;
270 IRRegArray* descr;
271 IRType typeof_SP;
272 Long delta, con;
sewardjde4a1d02002-03-22 01:27:54 +0000273
sewardj7cf4e6b2008-05-01 20:24:26 +0000274 /* Set up stuff for tracking the guest IP */
275 Bool curr_IP_known = False;
276 Addr64 curr_IP = 0;
277
sewardj8b635a42004-11-22 19:01:47 +0000278 /* Set up BB */
sewardj0b9d74a2006-12-24 02:24:11 +0000279 IRSB* bb = emptyIRSB();
280 bb->tyenv = deepCopyIRTypeEnv(sb_in->tyenv);
281 bb->next = deepCopyIRExpr(sb_in->next);
282 bb->jumpkind = sb_in->jumpkind;
sewardj291849f2012-04-20 23:58:55 +0000283 bb->offsIP = sb_in->offsIP;
sewardjde4a1d02002-03-22 01:27:54 +0000284
sewardj7cf97ee2004-11-28 14:25:01 +0000285 delta = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000286
sewardj7cf97ee2004-11-28 14:25:01 +0000287 sizeof_SP = layout->sizeof_SP;
288 offset_SP = layout->offset_SP;
289 typeof_SP = sizeof_SP==4 ? Ity_I32 : Ity_I64;
sewardj8b635a42004-11-22 19:01:47 +0000290 vg_assert(sizeof_SP == 4 || sizeof_SP == 8);
sewardjde4a1d02002-03-22 01:27:54 +0000291
sewardj7cf4e6b2008-05-01 20:24:26 +0000292 /* --- Start of #defines --- */
293
sewardj8b635a42004-11-22 19:01:47 +0000294# define IS_ADD(op) (sizeof_SP==4 ? ((op)==Iop_Add32) : ((op)==Iop_Add64))
295# define IS_SUB(op) (sizeof_SP==4 ? ((op)==Iop_Sub32) : ((op)==Iop_Sub64))
sewardjde4a1d02002-03-22 01:27:54 +0000296
sewardj8b635a42004-11-22 19:01:47 +0000297# define IS_ADD_OR_SUB(op) (IS_ADD(op) || IS_SUB(op))
sewardjde4a1d02002-03-22 01:27:54 +0000298
sewardj8b635a42004-11-22 19:01:47 +0000299# define GET_CONST(con) \
300 (sizeof_SP==4 ? (Long)(Int)(con->Ico.U32) \
301 : (Long)(con->Ico.U64))
sewardjde4a1d02002-03-22 01:27:54 +0000302
sewardj7cf4e6b2008-05-01 20:24:26 +0000303# define DO_NEW(syze, tmpp) \
sewardj8b635a42004-11-22 19:01:47 +0000304 do { \
sewardj7cf4e6b2008-05-01 20:24:26 +0000305 Bool vanilla, w_ecu; \
306 vg_assert(curr_IP_known); \
307 vanilla = NULL != VG_(tdict).track_new_mem_stack_##syze; \
308 w_ecu = NULL != VG_(tdict).track_new_mem_stack_##syze##_w_ECU; \
309 vg_assert(!(vanilla && w_ecu)); /* can't have both */ \
310 if (!(vanilla || w_ecu)) \
311 goto generic; \
312 \
313 /* I don't know if it's really necessary to say that the */ \
314 /* call reads the stack pointer. But anyway, we do. */ \
315 if (w_ecu) { \
316 dcall = unsafeIRDirty_0_N( \
317 2/*regparms*/, \
318 "track_new_mem_stack_" #syze "_w_ECU", \
319 VG_(fnptr_to_fnentry)( \
320 VG_(tdict).track_new_mem_stack_##syze##_w_ECU ), \
321 mkIRExprVec_2(IRExpr_RdTmp(tmpp), \
322 mk_ecu_Expr(curr_IP)) \
323 ); \
324 } else { \
325 dcall = unsafeIRDirty_0_N( \
326 1/*regparms*/, \
327 "track_new_mem_stack_" #syze , \
328 VG_(fnptr_to_fnentry)( \
329 VG_(tdict).track_new_mem_stack_##syze ), \
330 mkIRExprVec_1(IRExpr_RdTmp(tmpp)) \
331 ); \
332 } \
333 dcall->nFxState = 1; \
334 dcall->fxState[0].fx = Ifx_Read; \
335 dcall->fxState[0].offset = layout->offset_SP; \
336 dcall->fxState[0].size = layout->sizeof_SP; \
sewardj2eecb742012-06-01 16:11:41 +0000337 dcall->fxState[0].nRepeats = 0; \
338 dcall->fxState[0].repeatLen = 0; \
sewardj7cf4e6b2008-05-01 20:24:26 +0000339 \
340 addStmtToIRSB( bb, IRStmt_Dirty(dcall) ); \
341 \
342 tl_assert(syze > 0); \
343 update_SP_aliases(syze); \
344 \
345 n_SP_updates_fast++; \
346 \
347 } while (0)
348
349# define DO_DIE(syze, tmpp) \
350 do { \
351 if (!VG_(tdict).track_die_mem_stack_##syze) \
sewardj8b635a42004-11-22 19:01:47 +0000352 goto generic; \
353 \
354 /* I don't know if it's really necessary to say that the */ \
355 /* call reads the stack pointer. But anyway, we do. */ \
356 dcall = unsafeIRDirty_0_N( \
357 1/*regparms*/, \
sewardj7cf4e6b2008-05-01 20:24:26 +0000358 "track_die_mem_stack_" #syze, \
sewardj53ee1fc2005-12-23 02:29:58 +0000359 VG_(fnptr_to_fnentry)( \
sewardj7cf4e6b2008-05-01 20:24:26 +0000360 VG_(tdict).track_die_mem_stack_##syze ), \
sewardj0b9d74a2006-12-24 02:24:11 +0000361 mkIRExprVec_1(IRExpr_RdTmp(tmpp)) \
sewardj8b635a42004-11-22 19:01:47 +0000362 ); \
363 dcall->nFxState = 1; \
364 dcall->fxState[0].fx = Ifx_Read; \
365 dcall->fxState[0].offset = layout->offset_SP; \
366 dcall->fxState[0].size = layout->sizeof_SP; \
sewardj2eecb742012-06-01 16:11:41 +0000367 dcall->fxState[0].nRepeats = 0; \
368 dcall->fxState[0].repeatLen = 0; \
sewardj8b635a42004-11-22 19:01:47 +0000369 \
sewardj0b9d74a2006-12-24 02:24:11 +0000370 addStmtToIRSB( bb, IRStmt_Dirty(dcall) ); \
njn42c83552005-12-05 20:45:59 +0000371 \
sewardj7cf4e6b2008-05-01 20:24:26 +0000372 tl_assert(syze > 0); \
373 update_SP_aliases(-(syze)); \
njn5096a392005-12-13 20:05:00 +0000374 \
njn42c83552005-12-05 20:45:59 +0000375 n_SP_updates_fast++; \
376 \
sewardj8b635a42004-11-22 19:01:47 +0000377 } while (0)
sewardjde4a1d02002-03-22 01:27:54 +0000378
sewardj7cf4e6b2008-05-01 20:24:26 +0000379 /* --- End of #defines --- */
380
njn5096a392005-12-13 20:05:00 +0000381 clear_SP_aliases();
382
sewardj0b9d74a2006-12-24 02:24:11 +0000383 for (i = 0; i < sb_in->stmts_used; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000384
sewardj0b9d74a2006-12-24 02:24:11 +0000385 st = sb_in->stmts[i];
sewardjde4a1d02002-03-22 01:27:54 +0000386
sewardj7cf4e6b2008-05-01 20:24:26 +0000387 if (st->tag == Ist_IMark) {
388 curr_IP_known = True;
389 curr_IP = st->Ist.IMark.addr;
390 }
391
sewardj8b635a42004-11-22 19:01:47 +0000392 /* t = Get(sp): curr = t, delta = 0 */
sewardj0b9d74a2006-12-24 02:24:11 +0000393 if (st->tag != Ist_WrTmp) goto case2;
394 e = st->Ist.WrTmp.data;
sewardj8b635a42004-11-22 19:01:47 +0000395 if (e->tag != Iex_Get) goto case2;
396 if (e->Iex.Get.offset != offset_SP) goto case2;
397 if (e->Iex.Get.ty != typeof_SP) goto case2;
sewardj2831b512007-11-11 18:56:39 +0000398 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
sewardj0b9d74a2006-12-24 02:24:11 +0000399 add_SP_alias(st->Ist.WrTmp.tmp, 0);
400 addStmtToIRSB( bb, st );
sewardj8b635a42004-11-22 19:01:47 +0000401 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000402
sewardj8b635a42004-11-22 19:01:47 +0000403 case2:
404 /* t' = curr +/- const: curr = t', delta +=/-= const */
sewardj0b9d74a2006-12-24 02:24:11 +0000405 if (st->tag != Ist_WrTmp) goto case3;
406 e = st->Ist.WrTmp.data;
sewardj8b635a42004-11-22 19:01:47 +0000407 if (e->tag != Iex_Binop) goto case3;
sewardj0b9d74a2006-12-24 02:24:11 +0000408 if (e->Iex.Binop.arg1->tag != Iex_RdTmp) goto case3;
409 if (!get_SP_delta(e->Iex.Binop.arg1->Iex.RdTmp.tmp, &delta)) goto case3;
sewardj8b635a42004-11-22 19:01:47 +0000410 if (e->Iex.Binop.arg2->tag != Iex_Const) goto case3;
411 if (!IS_ADD_OR_SUB(e->Iex.Binop.op)) goto case3;
njn5096a392005-12-13 20:05:00 +0000412 con = GET_CONST(e->Iex.Binop.arg2->Iex.Const.con);
sewardj2831b512007-11-11 18:56:39 +0000413 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
njn5096a392005-12-13 20:05:00 +0000414 if (IS_ADD(e->Iex.Binop.op)) {
sewardj0b9d74a2006-12-24 02:24:11 +0000415 add_SP_alias(st->Ist.WrTmp.tmp, delta + con);
njn5096a392005-12-13 20:05:00 +0000416 } else {
sewardj0b9d74a2006-12-24 02:24:11 +0000417 add_SP_alias(st->Ist.WrTmp.tmp, delta - con);
njn5096a392005-12-13 20:05:00 +0000418 }
sewardj0b9d74a2006-12-24 02:24:11 +0000419 addStmtToIRSB( bb, st );
sewardj8b635a42004-11-22 19:01:47 +0000420 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000421
sewardj8b635a42004-11-22 19:01:47 +0000422 case3:
423 /* t' = curr: curr = t' */
sewardj0b9d74a2006-12-24 02:24:11 +0000424 if (st->tag != Ist_WrTmp) goto case4;
425 e = st->Ist.WrTmp.data;
426 if (e->tag != Iex_RdTmp) goto case4;
427 if (!get_SP_delta(e->Iex.RdTmp.tmp, &delta)) goto case4;
sewardj2831b512007-11-11 18:56:39 +0000428 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
sewardj0b9d74a2006-12-24 02:24:11 +0000429 add_SP_alias(st->Ist.WrTmp.tmp, delta);
430 addStmtToIRSB( bb, st );
sewardj8b635a42004-11-22 19:01:47 +0000431 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000432
sewardj8b635a42004-11-22 19:01:47 +0000433 case4:
434 /* Put(sp) = curr */
sewardj2831b512007-11-11 18:56:39 +0000435 /* More generally, we must correctly handle a Put which writes
436 any part of SP, not just the case where all of SP is
437 written. */
sewardj8b635a42004-11-22 19:01:47 +0000438 if (st->tag != Ist_Put) goto case5;
sewardj2831b512007-11-11 18:56:39 +0000439 first_SP = offset_SP;
440 last_SP = first_SP + sizeof_SP - 1;
441 first_Put = st->Ist.Put.offset;
442 last_Put = first_Put
443 + sizeofIRType( typeOfIRExpr( bb->tyenv, st->Ist.Put.data ))
444 - 1;
445 vg_assert(first_SP <= last_SP);
446 vg_assert(first_Put <= last_Put);
447
448 if (last_Put < first_SP || last_SP < first_Put)
449 goto case5; /* no overlap */
450
451 if (st->Ist.Put.data->tag == Iex_RdTmp
452 && get_SP_delta(st->Ist.Put.data->Iex.RdTmp.tmp, &delta)) {
sewardj0b9d74a2006-12-24 02:24:11 +0000453 IRTemp tttmp = st->Ist.Put.data->Iex.RdTmp.tmp;
sewardj2831b512007-11-11 18:56:39 +0000454 /* Why should the following assertion hold? Because any
455 alias added by put_SP_alias must be of a temporary which
456 has the same type as typeof_SP, and whose value is a Get
457 at exactly offset_SP of size typeof_SP. Each call to
458 put_SP_alias is immediately preceded by an assertion that
459 we are putting in a binding for a correctly-typed
460 temporary. */
461 vg_assert( typeOfIRTemp(bb->tyenv, tttmp) == typeof_SP );
462 /* From the same type-and-offset-correctness argument, if
463 we found a useable alias, it must for an "exact" write of SP. */
464 vg_assert(first_SP == first_Put);
465 vg_assert(last_SP == last_Put);
sewardj8b635a42004-11-22 19:01:47 +0000466 switch (delta) {
sewardj0b9d74a2006-12-24 02:24:11 +0000467 case 0: addStmtToIRSB(bb,st); continue;
sewardj7cf4e6b2008-05-01 20:24:26 +0000468 case 4: DO_DIE( 4, tttmp); addStmtToIRSB(bb,st); continue;
469 case -4: DO_NEW( 4, tttmp); addStmtToIRSB(bb,st); continue;
470 case 8: DO_DIE( 8, tttmp); addStmtToIRSB(bb,st); continue;
471 case -8: DO_NEW( 8, tttmp); addStmtToIRSB(bb,st); continue;
472 case 12: DO_DIE( 12, tttmp); addStmtToIRSB(bb,st); continue;
473 case -12: DO_NEW( 12, tttmp); addStmtToIRSB(bb,st); continue;
474 case 16: DO_DIE( 16, tttmp); addStmtToIRSB(bb,st); continue;
475 case -16: DO_NEW( 16, tttmp); addStmtToIRSB(bb,st); continue;
476 case 32: DO_DIE( 32, tttmp); addStmtToIRSB(bb,st); continue;
477 case -32: DO_NEW( 32, tttmp); addStmtToIRSB(bb,st); continue;
478 case 112: DO_DIE( 112, tttmp); addStmtToIRSB(bb,st); continue;
479 case -112: DO_NEW( 112, tttmp); addStmtToIRSB(bb,st); continue;
480 case 128: DO_DIE( 128, tttmp); addStmtToIRSB(bb,st); continue;
481 case -128: DO_NEW( 128, tttmp); addStmtToIRSB(bb,st); continue;
482 case 144: DO_DIE( 144, tttmp); addStmtToIRSB(bb,st); continue;
483 case -144: DO_NEW( 144, tttmp); addStmtToIRSB(bb,st); continue;
484 case 160: DO_DIE( 160, tttmp); addStmtToIRSB(bb,st); continue;
485 case -160: DO_NEW( 160, tttmp); addStmtToIRSB(bb,st); continue;
njn42c83552005-12-05 20:45:59 +0000486 default:
sewardjbb686272006-01-22 20:12:45 +0000487 /* common values for ppc64: 144 128 160 112 176 */
njn42c83552005-12-05 20:45:59 +0000488 n_SP_updates_generic_known++;
489 goto generic;
sewardjde4a1d02002-03-22 01:27:54 +0000490 }
sewardj8b635a42004-11-22 19:01:47 +0000491 } else {
sewardj2831b512007-11-11 18:56:39 +0000492 /* Deal with an unknown update to SP. We're here because
493 either:
494 (1) the Put does not exactly cover SP; it is a partial update.
495 Highly unlikely, but has been known to happen for 16-bit
496 Windows apps running on Wine, doing 16-bit adjustments to
497 %sp.
498 (2) the Put does exactly cover SP, but we are unable to
499 determine how the value relates to the old SP. In any
500 case, we cannot assume that the Put.data value is a tmp;
501 we must assume it can be anything allowed in flat IR (tmp
502 or const).
503 */
sewardj7cf4e6b2008-05-01 20:24:26 +0000504 IRTemp old_SP;
njn42c83552005-12-05 20:45:59 +0000505 n_SP_updates_generic_unknown++;
506
njn5096a392005-12-13 20:05:00 +0000507 // Nb: if all is well, this generic case will typically be
508 // called something like every 1000th SP update. If it's more than
509 // that, the above code may be missing some cases.
sewardj8b635a42004-11-22 19:01:47 +0000510 generic:
sewardj7cf4e6b2008-05-01 20:24:26 +0000511 /* Pass both the old and new SP values to this helper. Also,
512 pass an origin tag, even if it isn't needed. */
sewardj2a99cf62004-11-24 10:44:19 +0000513 old_SP = newIRTemp(bb->tyenv, typeof_SP);
sewardj0b9d74a2006-12-24 02:24:11 +0000514 addStmtToIRSB(
sewardj2a99cf62004-11-24 10:44:19 +0000515 bb,
sewardj0b9d74a2006-12-24 02:24:11 +0000516 IRStmt_WrTmp( old_SP, IRExpr_Get(offset_SP, typeof_SP) )
sewardj2a99cf62004-11-24 10:44:19 +0000517 );
sewardjde4a1d02002-03-22 01:27:54 +0000518
sewardj2831b512007-11-11 18:56:39 +0000519 /* Now we know what the old value of SP is. But knowing the new
520 value is a bit tricky if there is a partial write. */
521 if (first_Put == first_SP && last_Put == last_SP) {
522 /* The common case, an exact write to SP. So st->Ist.Put.data
523 does hold the new value; simple. */
sewardj7cf4e6b2008-05-01 20:24:26 +0000524 vg_assert(curr_IP_known);
sewardj2831b512007-11-11 18:56:39 +0000525 dcall = unsafeIRDirty_0_N(
sewardj7cf4e6b2008-05-01 20:24:26 +0000526 3/*regparms*/,
sewardj2831b512007-11-11 18:56:39 +0000527 "VG_(unknown_SP_update)",
528 VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
sewardj7cf4e6b2008-05-01 20:24:26 +0000529 mkIRExprVec_3( IRExpr_RdTmp(old_SP), st->Ist.Put.data,
530 mk_ecu_Expr(curr_IP) )
sewardj2831b512007-11-11 18:56:39 +0000531 );
532 addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
533 /* don't forget the original assignment */
534 addStmtToIRSB( bb, st );
535 } else {
536 /* We have a partial update to SP. We need to know what
537 the new SP will be, and hand that to the helper call,
538 but when the helper call happens, SP must hold the
539 value it had before the update. Tricky.
540 Therefore use the following kludge:
541 1. do the partial SP update (Put)
542 2. Get the new SP value into a tmp, new_SP
543 3. Put old_SP
544 4. Call the helper
545 5. Put new_SP
546 */
547 IRTemp new_SP;
548 /* 1 */
549 addStmtToIRSB( bb, st );
550 /* 2 */
551 new_SP = newIRTemp(bb->tyenv, typeof_SP);
552 addStmtToIRSB(
553 bb,
554 IRStmt_WrTmp( new_SP, IRExpr_Get(offset_SP, typeof_SP) )
555 );
556 /* 3 */
557 addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(old_SP) ));
558 /* 4 */
sewardj7cf4e6b2008-05-01 20:24:26 +0000559 vg_assert(curr_IP_known);
sewardj2831b512007-11-11 18:56:39 +0000560 dcall = unsafeIRDirty_0_N(
sewardj7cf4e6b2008-05-01 20:24:26 +0000561 3/*regparms*/,
sewardj2831b512007-11-11 18:56:39 +0000562 "VG_(unknown_SP_update)",
563 VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
sewardj7cf4e6b2008-05-01 20:24:26 +0000564 mkIRExprVec_3( IRExpr_RdTmp(old_SP),
565 IRExpr_RdTmp(new_SP),
566 mk_ecu_Expr(curr_IP) )
sewardj2831b512007-11-11 18:56:39 +0000567 );
568 addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
569 /* 5 */
570 addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(new_SP) ));
571 }
sewardj2a99cf62004-11-24 10:44:19 +0000572
sewardj2831b512007-11-11 18:56:39 +0000573 /* Forget what we already know. */
njn5096a392005-12-13 20:05:00 +0000574 clear_SP_aliases();
sewardj2831b512007-11-11 18:56:39 +0000575
576 /* If this is a Put of a tmp that exactly updates SP,
577 start tracking aliases against this tmp. */
578
579 if (first_Put == first_SP && last_Put == last_SP
580 && st->Ist.Put.data->tag == Iex_RdTmp) {
581 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.Put.data->Iex.RdTmp.tmp)
582 == typeof_SP );
583 add_SP_alias(st->Ist.Put.data->Iex.RdTmp.tmp, 0);
584 }
sewardj8b635a42004-11-22 19:01:47 +0000585 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000586 }
587
sewardj8b635a42004-11-22 19:01:47 +0000588 case5:
589 /* PutI or Dirty call which overlaps SP: complain. We can't
590 deal with SP changing in weird ways (well, we can, but not at
591 this time of night). */
592 if (st->tag == Ist_PutI) {
floriand39b0222012-05-31 15:48:13 +0000593 descr = st->Ist.PutI.details->descr;
sewardj8b635a42004-11-22 19:01:47 +0000594 minoff_ST = descr->base;
sewardj2831b512007-11-11 18:56:39 +0000595 maxoff_ST = descr->base
596 + descr->nElems * sizeofIRType(descr->elemTy) - 1;
597 if (!(offset_SP > maxoff_ST
598 || (offset_SP + sizeof_SP - 1) < minoff_ST))
sewardj8b635a42004-11-22 19:01:47 +0000599 goto complain;
sewardjde4a1d02002-03-22 01:27:54 +0000600 }
sewardj8b635a42004-11-22 19:01:47 +0000601 if (st->tag == Ist_Dirty) {
602 d = st->Ist.Dirty.details;
603 for (j = 0; j < d->nFxState; j++) {
sewardj8b635a42004-11-22 19:01:47 +0000604 if (d->fxState[j].fx == Ifx_Read || d->fxState[j].fx == Ifx_None)
605 continue;
sewardj2eecb742012-06-01 16:11:41 +0000606 /* Enumerate the described state segments */
607 for (k = 0; k < 1 + d->fxState[j].nRepeats; k++) {
608 minoff_ST = d->fxState[j].offset + k * d->fxState[j].repeatLen;
609 maxoff_ST = minoff_ST + d->fxState[j].size - 1;
610 if (!(offset_SP > maxoff_ST
611 || (offset_SP + sizeof_SP - 1) < minoff_ST))
612 goto complain;
613 }
sewardj8b635a42004-11-22 19:01:47 +0000614 }
615 }
sewardjde4a1d02002-03-22 01:27:54 +0000616
sewardj8b635a42004-11-22 19:01:47 +0000617 /* well, not interesting. Just copy and keep going. */
sewardj0b9d74a2006-12-24 02:24:11 +0000618 addStmtToIRSB( bb, st );
sewardjde4a1d02002-03-22 01:27:54 +0000619
sewardj0b9d74a2006-12-24 02:24:11 +0000620 } /* for (i = 0; i < sb_in->stmts_used; i++) */
sewardjde4a1d02002-03-22 01:27:54 +0000621
sewardj8b635a42004-11-22 19:01:47 +0000622 return bb;
sewardjde4a1d02002-03-22 01:27:54 +0000623
sewardj8b635a42004-11-22 19:01:47 +0000624 complain:
625 VG_(core_panic)("vg_SP_update_pass: PutI or Dirty which overlaps SP");
sewardjde4a1d02002-03-22 01:27:54 +0000626
sewardj7cf4e6b2008-05-01 20:24:26 +0000627#undef IS_ADD
628#undef IS_SUB
629#undef IS_ADD_OR_SUB
630#undef GET_CONST
631#undef DO_NEW
632#undef DO_DIE
sewardjde4a1d02002-03-22 01:27:54 +0000633}
sewardj7c4b6042003-06-14 15:47:15 +0000634
sewardjde4a1d02002-03-22 01:27:54 +0000635/*------------------------------------------------------------*/
636/*--- Main entry point for the JITter. ---*/
637/*------------------------------------------------------------*/
638
sewardjd2b70dc2005-10-14 17:22:31 +0000639/* Extra comments re self-checking translations and self-modifying
640 code. (JRS 14 Oct 05).
641
642 There are 3 modes:
643 (1) no checking: all code assumed to be not self-modifying
644 (2) partial: known-problematic situations get a self-check
645 (3) full checking: all translations get a self-check
646
647 As currently implemented, the default is (2). (3) is always safe,
648 but very slow. (1) works mostly, but fails for gcc nested-function
649 code which uses trampolines on the stack; this situation is
650 detected and handled by (2).
651
652 ----------
653
654 A more robust and transparent solution, which is not currently
655 implemented, is a variant of (2): if a translation is made from an
656 area which aspacem says does not have 'w' permission, then it can
657 be non-self-checking. Otherwise, it needs a self-check.
658
659 This is complicated by Vex's basic-block chasing. If a self-check
660 is requested, then Vex will not chase over basic block boundaries
661 (it's too complex). However there is still a problem if it chases
662 from a non-'w' area into a 'w' area.
663
664 I think the right thing to do is:
665
666 - if a translation request starts in a 'w' area, ask for a
667 self-checking translation, and do not allow any chasing (make
668 chase_into_ok return False). Note that the latter is redundant
669 in the sense that Vex won't chase anyway in this situation.
670
671 - if a translation request starts in a non-'w' area, do not ask for
672 a self-checking translation. However, do not allow chasing (as
673 determined by chase_into_ok) to go into a 'w' area.
674
675 The result of this is that all code inside 'w' areas is self
676 checking.
677
678 To complete the trick, there is a caveat: we must watch the
679 client's mprotect calls. If pages are changed from non-'w' to 'w'
680 then we should throw away all translations which intersect the
681 affected area, so as to force them to be redone with self-checks.
682
683 ----------
684
685 The above outlines the conditions under which bb chasing is allowed
686 from a self-modifying-code point of view. There are other
687 situations pertaining to function redirection in which it is
688 necessary to disallow chasing, but those fall outside the scope of
689 this comment.
690*/
691
sewardj34593e52006-01-17 01:57:33 +0000692
sewardj8b635a42004-11-22 19:01:47 +0000693/* Vex dumps the final code in here. Then we can copy it off
694 wherever we like. */
sewardj4a0009c2006-10-17 01:52:05 +0000695/* 60000: should agree with assertion in VG_(add_to_transtab) in
696 m_transtab.c. */
697#define N_TMPBUF 60000
sewardj8b635a42004-11-22 19:01:47 +0000698static UChar tmpbuf[N_TMPBUF];
699
sewardj34593e52006-01-17 01:57:33 +0000700
sewardj8b635a42004-11-22 19:01:47 +0000701/* Function pointers we must supply to LibVEX in order that it
702 can bomb out and emit messages under Valgrind's control. */
703__attribute__ ((noreturn))
704static
705void failure_exit ( void )
706{
sewardjbf426512005-01-17 18:35:30 +0000707 LibVEX_ShowAllocStats();
sewardjc621f762004-11-26 13:49:59 +0000708 VG_(core_panic)("LibVEX called failure_exit().");
sewardj8b635a42004-11-22 19:01:47 +0000709}
710
711static
sewardjb5f6f512005-03-10 23:59:00 +0000712void log_bytes ( HChar* bytes, Int nbytes )
sewardj8b635a42004-11-22 19:01:47 +0000713{
714 Int i;
715 for (i = 0; i < nbytes-3; i += 4)
716 VG_(printf)("%c%c%c%c", bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]);
717 for (; i < nbytes; i++)
718 VG_(printf)("%c", bytes[i]);
719}
720
njn25e49d8e72002-09-23 09:36:25 +0000721
sewardj34593e52006-01-17 01:57:33 +0000722/* --------- Various helper functions for translation --------- */
sewardj8b635a42004-11-22 19:01:47 +0000723
sewardj45f4e7c2005-09-27 19:20:21 +0000724/* Look for reasons to disallow making translations from the given
725 segment. */
726
sewardj4a0009c2006-10-17 01:52:05 +0000727static Bool translations_allowable_from_seg ( NSegment const* seg )
sewardj45f4e7c2005-09-27 19:20:21 +0000728{
sewardj5db15402012-06-07 09:13:21 +0000729# if defined(VGA_x86) || defined(VGA_s390x) || defined(VGA_mips32)
sewardj45f4e7c2005-09-27 19:20:21 +0000730 Bool allowR = True;
731# else
732 Bool allowR = False;
733# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000734 return seg != NULL
tom1da86fe2009-10-12 13:53:12 +0000735 && (seg->kind == SkAnonC || seg->kind == SkFileC || seg->kind == SkShmC)
sewardj45f4e7c2005-09-27 19:20:21 +0000736 && (seg->hasX || (seg->hasR && allowR));
737}
738
739
sewardj6dbcc632011-06-07 21:39:28 +0000740/* Produce a bitmask stating which of the supplied extents needs a
741 self-check. See documentation of
742 VexTranslateArgs::needs_self_check for more details about the
743 return convention. */
sewardj45f4e7c2005-09-27 19:20:21 +0000744
sewardj6dbcc632011-06-07 21:39:28 +0000745static UInt needs_self_check ( void* closureV,
746 VexGuestExtents* vge )
sewardj34593e52006-01-17 01:57:33 +0000747{
sewardj6dbcc632011-06-07 21:39:28 +0000748 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
749 UInt i, bitset;
750
751 vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
752 bitset = 0;
753
754 for (i = 0; i < vge->n_used; i++) {
755 Bool check = False;
756 Addr addr = (Addr)vge->base[i];
757 SizeT len = (SizeT)vge->len[i];
758 NSegment const* segA = NULL;
759
760# if defined(VGO_darwin)
761 // GrP fixme hack - dyld i386 IMPORT gets rewritten.
762 // To really do this correctly, we'd need to flush the
763 // translation cache whenever a segment became +WX.
764 segA = VG_(am_find_nsegment)(addr);
765 if (segA && segA->hasX && segA->hasW)
766 check = True;
767# endif
768
769 if (!check) {
770 switch (VG_(clo_smc_check)) {
771 case Vg_SmcNone:
772 /* never check (except as per Darwin hack above) */
773 break;
774 case Vg_SmcAll:
775 /* always check */
776 check = True;
777 break;
778 case Vg_SmcStack: {
779 /* check if the address is in the same segment as this
780 thread's stack pointer */
781 Addr sp = VG_(get_SP)(closure->tid);
782 if (!segA) {
783 segA = VG_(am_find_nsegment)(addr);
784 }
785 NSegment const* segSP = VG_(am_find_nsegment)(sp);
786 if (segA && segSP && segA == segSP)
787 check = True;
788 break;
789 }
790 case Vg_SmcAllNonFile: {
791 /* check if any part of the extent is not in a
792 file-mapped segment */
793 if (!segA) {
794 segA = VG_(am_find_nsegment)(addr);
795 }
796 if (segA && segA->kind == SkFileC && segA->start <= addr
797 && (len == 0 || addr + len <= segA->end + 1)) {
798 /* in a file-mapped segment; skip the check */
799 } else {
800 check = True;
801 }
802 break;
803 }
804 default:
805 vg_assert(0);
806 }
807 }
808
809 if (check)
810 bitset |= (1 << i);
njnf76d27a2009-05-28 01:53:07 +0000811 }
sewardj6dbcc632011-06-07 21:39:28 +0000812
813 return bitset;
sewardj34593e52006-01-17 01:57:33 +0000814}
815
816
817/* This is a callback passed to LibVEX_Translate. It stops Vex from
818 chasing into function entry points that we wish to redirect.
819 Chasing across them obviously defeats the redirect mechanism, with
sewardj6dbcc632011-06-07 21:39:28 +0000820 bad effects for Memcheck, Helgrind, DRD, Massif, and possibly others.
sewardj447f2a12005-07-07 13:52:53 +0000821*/
sewardj34593e52006-01-17 01:57:33 +0000822static Bool chase_into_ok ( void* closureV, Addr64 addr64 )
sewardj8b635a42004-11-22 19:01:47 +0000823{
sewardj34593e52006-01-17 01:57:33 +0000824 Addr addr = (Addr)addr64;
sewardj4a0009c2006-10-17 01:52:05 +0000825 NSegment const* seg = VG_(am_find_nsegment)(addr);
sewardj45f4e7c2005-09-27 19:20:21 +0000826
sewardj447f2a12005-07-07 13:52:53 +0000827 /* Work through a list of possibilities why we might not want to
828 allow a chase. */
sewardj447f2a12005-07-07 13:52:53 +0000829
sewardj34593e52006-01-17 01:57:33 +0000830 /* Destination not in a plausible segment? */
sewardj45f4e7c2005-09-27 19:20:21 +0000831 if (!translations_allowable_from_seg(seg))
832 goto dontchase;
833
sewardj447f2a12005-07-07 13:52:53 +0000834 /* Destination is redirected? */
sewardj0ec07f32006-01-12 12:32:32 +0000835 if (addr != VG_(redir_do_lookup)(addr, NULL))
sewardj447f2a12005-07-07 13:52:53 +0000836 goto dontchase;
837
sewardj4a0009c2006-10-17 01:52:05 +0000838# if defined(VG_PLAT_USES_PPCTOC)
839 /* This needs to be at the start of its own block. Don't chase. Re
840 ULong_to_Ptr, be careful to ensure we only compare 32 bits on a
841 32-bit target.*/
842 if (ULong_to_Ptr(addr64)
843 == (void*)&VG_(ppctoc_magic_redirect_return_stub))
sewardj34593e52006-01-17 01:57:33 +0000844 goto dontchase;
845# endif
846
sewardj5f76de02007-02-11 05:08:06 +0000847 /* overly conservative, but .. don't chase into the distinguished
848 address that m_transtab uses as an empty-slot marker for
849 VG_(tt_fast). */
850 if (addr == TRANSTAB_BOGUS_GUEST_ADDR)
851 goto dontchase;
852
floriancabcace2011-07-16 02:09:36 +0000853# if defined(VGA_s390x)
854 /* Never chase into an EX instruction. Generating IR for EX causes
855 a round-trip through the scheduler including VG_(discard_translations).
856 And that's expensive as shown by perf/tinycc.c:
857 Chasing into EX increases the number of EX translations from 21 to
858 102666 causing a 7x runtime increase for "none" and a 3.2x runtime
859 increase for memcheck. */
860 if (((UChar *)ULong_to_Ptr(addr))[0] == 0x44 || /* EX */
861 ((UChar *)ULong_to_Ptr(addr))[0] == 0xC6) /* EXRL */
862 goto dontchase;
863# endif
864
sewardj447f2a12005-07-07 13:52:53 +0000865 /* well, ok then. go on and chase. */
866 return True;
867
868 vg_assert(0);
869 /*NOTREACHED*/
870
871 dontchase:
njn8a7b41b2007-09-23 00:51:24 +0000872 if (0) VG_(printf)("not chasing into 0x%lx\n", addr);
sewardj447f2a12005-07-07 13:52:53 +0000873 return False;
sewardj8b635a42004-11-22 19:01:47 +0000874}
875
sewardj447f2a12005-07-07 13:52:53 +0000876
sewardj4a0009c2006-10-17 01:52:05 +0000877/* --------------- helpers for with-TOC platforms --------------- */
878
sewardj6e9de462011-06-28 07:25:29 +0000879/* NOTE: with-TOC platforms are: ppc64-linux. */
sewardjdfbaa222006-01-18 04:25:20 +0000880
sewardjd68ac3e2006-01-20 14:31:57 +0000881static IRExpr* mkU64 ( ULong n ) {
sewardj34593e52006-01-17 01:57:33 +0000882 return IRExpr_Const(IRConst_U64(n));
883}
sewardjd68ac3e2006-01-20 14:31:57 +0000884static IRExpr* mkU32 ( UInt n ) {
885 return IRExpr_Const(IRConst_U32(n));
886}
sewardj4a0009c2006-10-17 01:52:05 +0000887
888#if defined(VG_PLAT_USES_PPCTOC)
sewardjd68ac3e2006-01-20 14:31:57 +0000889static IRExpr* mkU8 ( UChar n ) {
890 return IRExpr_Const(IRConst_U8(n));
891}
sewardj4a0009c2006-10-17 01:52:05 +0000892static IRExpr* narrowTo32 ( IRTypeEnv* tyenv, IRExpr* e ) {
893 if (typeOfIRExpr(tyenv, e) == Ity_I32) {
894 return e;
895 } else {
896 vg_assert(typeOfIRExpr(tyenv, e) == Ity_I64);
897 return IRExpr_Unop(Iop_64to32, e);
898 }
899}
900
901/* Generate code to push word-typed expression 'e' onto this thread's
902 redir stack, checking for stack overflow and generating code to
903 bomb out if so. */
sewardj34593e52006-01-17 01:57:33 +0000904
sewardj0b9d74a2006-12-24 02:24:11 +0000905static void gen_PUSH ( IRSB* bb, IRExpr* e )
sewardj34593e52006-01-17 01:57:33 +0000906{
sewardj0b9d74a2006-12-24 02:24:11 +0000907 IRRegArray* descr;
908 IRTemp t1;
909 IRExpr* one;
sewardj34593e52006-01-17 01:57:33 +0000910
sewardj6e9de462011-06-28 07:25:29 +0000911# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +0000912 Int stack_size = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
913 Int offB_REDIR_SP = offsetof(VexGuestPPC64State,guest_REDIR_SP);
914 Int offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +0000915 Int offB_EMNOTE = offsetof(VexGuestPPC64State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +0000916 Int offB_CIA = offsetof(VexGuestPPC64State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +0000917 Bool is64 = True;
918 IRType ty_Word = Ity_I64;
919 IROp op_CmpNE = Iop_CmpNE64;
920 IROp op_Sar = Iop_Sar64;
921 IROp op_Sub = Iop_Sub64;
922 IROp op_Add = Iop_Add64;
923 IRExpr*(*mkU)(ULong) = mkU64;
924 vg_assert(VG_WORDSIZE == 8);
925# else
926 Int stack_size = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
927 Int offB_REDIR_SP = offsetof(VexGuestPPC32State,guest_REDIR_SP);
928 Int offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +0000929 Int offB_EMNOTE = offsetof(VexGuestPPC32State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +0000930 Int offB_CIA = offsetof(VexGuestPPC32State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +0000931 Bool is64 = False;
932 IRType ty_Word = Ity_I32;
933 IROp op_CmpNE = Iop_CmpNE32;
934 IROp op_Sar = Iop_Sar32;
935 IROp op_Sub = Iop_Sub32;
936 IROp op_Add = Iop_Add32;
937 IRExpr*(*mkU)(UInt) = mkU32;
938 vg_assert(VG_WORDSIZE == 4);
939# endif
940
941 vg_assert(sizeof(void*) == VG_WORDSIZE);
942 vg_assert(sizeof(Word) == VG_WORDSIZE);
943 vg_assert(sizeof(Addr) == VG_WORDSIZE);
944
sewardj0b9d74a2006-12-24 02:24:11 +0000945 descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
sewardj4a0009c2006-10-17 01:52:05 +0000946 t1 = newIRTemp( bb->tyenv, ty_Word );
947 one = mkU(1);
948
949 vg_assert(typeOfIRExpr(bb->tyenv, e) == ty_Word);
sewardj34593e52006-01-17 01:57:33 +0000950
951 /* t1 = guest_REDIR_SP + 1 */
sewardj0b9d74a2006-12-24 02:24:11 +0000952 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +0000953 bb,
sewardj0b9d74a2006-12-24 02:24:11 +0000954 IRStmt_WrTmp(
sewardj34593e52006-01-17 01:57:33 +0000955 t1,
sewardj4a0009c2006-10-17 01:52:05 +0000956 IRExpr_Binop(op_Add, IRExpr_Get( offB_REDIR_SP, ty_Word ), one)
sewardj34593e52006-01-17 01:57:33 +0000957 )
958 );
959
sewardjd68ac3e2006-01-20 14:31:57 +0000960 /* Bomb out if t1 >=s stack_size, that is, (stack_size-1)-t1 <s 0.
961 The destination (0) is a bit bogus but it doesn't matter since
962 this is an unrecoverable error and will lead to Valgrind
florian2e497412012-08-26 03:22:09 +0000963 shutting down. _EMNOTE is set regardless - that's harmless
sewardjd68ac3e2006-01-20 14:31:57 +0000964 since is only has a meaning if the exit is taken. */
sewardj0b9d74a2006-12-24 02:24:11 +0000965 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +0000966 bb,
florian2e497412012-08-26 03:22:09 +0000967 IRStmt_Put(offB_EMNOTE, mkU32(EmWarn_PPC64_redir_overflow))
sewardjd68ac3e2006-01-20 14:31:57 +0000968 );
sewardj0b9d74a2006-12-24 02:24:11 +0000969 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +0000970 bb,
971 IRStmt_Exit(
972 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +0000973 op_CmpNE,
sewardjd68ac3e2006-01-20 14:31:57 +0000974 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +0000975 op_Sar,
sewardj0b9d74a2006-12-24 02:24:11 +0000976 IRExpr_Binop(op_Sub,mkU(stack_size-1),IRExpr_RdTmp(t1)),
sewardj4a0009c2006-10-17 01:52:05 +0000977 mkU8(8 * VG_WORDSIZE - 1)
sewardjd68ac3e2006-01-20 14:31:57 +0000978 ),
sewardj4a0009c2006-10-17 01:52:05 +0000979 mkU(0)
sewardjd68ac3e2006-01-20 14:31:57 +0000980 ),
981 Ijk_EmFail,
sewardj291849f2012-04-20 23:58:55 +0000982 is64 ? IRConst_U64(0) : IRConst_U32(0),
983 offB_CIA
sewardjd68ac3e2006-01-20 14:31:57 +0000984 )
985 );
sewardj34593e52006-01-17 01:57:33 +0000986
987 /* guest_REDIR_SP = t1 */
sewardj0b9d74a2006-12-24 02:24:11 +0000988 addStmtToIRSB(bb, IRStmt_Put(offB_REDIR_SP, IRExpr_RdTmp(t1)));
sewardj34593e52006-01-17 01:57:33 +0000989
990 /* guest_REDIR_STACK[t1+0] = e */
sewardj4a0009c2006-10-17 01:52:05 +0000991 /* PutI/GetI have I32-typed indexes regardless of guest word size */
sewardj0b9d74a2006-12-24 02:24:11 +0000992 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +0000993 bb,
floriand39b0222012-05-31 15:48:13 +0000994 IRStmt_PutI(mkIRPutI(descr,
995 narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0, e)));
sewardj34593e52006-01-17 01:57:33 +0000996}
997
sewardj4a0009c2006-10-17 01:52:05 +0000998
999/* Generate code to pop a word-sized value from this thread's redir
1000 stack, binding it to a new temporary, which is returned. As with
1001 gen_PUSH, an overflow check is also performed. */
1002
sewardj0b9d74a2006-12-24 02:24:11 +00001003static IRTemp gen_POP ( IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001004{
sewardj6e9de462011-06-28 07:25:29 +00001005# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +00001006 Int stack_size = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
1007 Int offB_REDIR_SP = offsetof(VexGuestPPC64State,guest_REDIR_SP);
1008 Int offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +00001009 Int offB_EMNOTE = offsetof(VexGuestPPC64State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +00001010 Int offB_CIA = offsetof(VexGuestPPC64State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +00001011 Bool is64 = True;
1012 IRType ty_Word = Ity_I64;
1013 IROp op_CmpNE = Iop_CmpNE64;
1014 IROp op_Sar = Iop_Sar64;
1015 IROp op_Sub = Iop_Sub64;
1016 IRExpr*(*mkU)(ULong) = mkU64;
1017# else
1018 Int stack_size = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
1019 Int offB_REDIR_SP = offsetof(VexGuestPPC32State,guest_REDIR_SP);
1020 Int offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +00001021 Int offB_EMNOTE = offsetof(VexGuestPPC32State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +00001022 Int offB_CIA = offsetof(VexGuestPPC32State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +00001023 Bool is64 = False;
1024 IRType ty_Word = Ity_I32;
1025 IROp op_CmpNE = Iop_CmpNE32;
1026 IROp op_Sar = Iop_Sar32;
1027 IROp op_Sub = Iop_Sub32;
1028 IRExpr*(*mkU)(UInt) = mkU32;
1029# endif
sewardj34593e52006-01-17 01:57:33 +00001030
sewardj0b9d74a2006-12-24 02:24:11 +00001031 IRRegArray* descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
1032 IRTemp t1 = newIRTemp( bb->tyenv, ty_Word );
1033 IRTemp res = newIRTemp( bb->tyenv, ty_Word );
1034 IRExpr* one = mkU(1);
sewardj4a0009c2006-10-17 01:52:05 +00001035
1036 vg_assert(sizeof(void*) == VG_WORDSIZE);
1037 vg_assert(sizeof(Word) == VG_WORDSIZE);
1038 vg_assert(sizeof(Addr) == VG_WORDSIZE);
sewardj34593e52006-01-17 01:57:33 +00001039
1040 /* t1 = guest_REDIR_SP */
sewardj0b9d74a2006-12-24 02:24:11 +00001041 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001042 bb,
sewardj0b9d74a2006-12-24 02:24:11 +00001043 IRStmt_WrTmp( t1, IRExpr_Get( offB_REDIR_SP, ty_Word ) )
sewardj34593e52006-01-17 01:57:33 +00001044 );
1045
sewardjd68ac3e2006-01-20 14:31:57 +00001046 /* Bomb out if t1 < 0. Same comments as gen_PUSH apply. */
sewardj0b9d74a2006-12-24 02:24:11 +00001047 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +00001048 bb,
florian2e497412012-08-26 03:22:09 +00001049 IRStmt_Put(offB_EMNOTE, mkU32(EmWarn_PPC64_redir_underflow))
sewardjd68ac3e2006-01-20 14:31:57 +00001050 );
sewardj0b9d74a2006-12-24 02:24:11 +00001051 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +00001052 bb,
1053 IRStmt_Exit(
1054 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +00001055 op_CmpNE,
sewardjd68ac3e2006-01-20 14:31:57 +00001056 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +00001057 op_Sar,
sewardj0b9d74a2006-12-24 02:24:11 +00001058 IRExpr_RdTmp(t1),
sewardj4a0009c2006-10-17 01:52:05 +00001059 mkU8(8 * VG_WORDSIZE - 1)
sewardjd68ac3e2006-01-20 14:31:57 +00001060 ),
sewardj4a0009c2006-10-17 01:52:05 +00001061 mkU(0)
sewardjd68ac3e2006-01-20 14:31:57 +00001062 ),
1063 Ijk_EmFail,
sewardj291849f2012-04-20 23:58:55 +00001064 is64 ? IRConst_U64(0) : IRConst_U32(0),
1065 offB_CIA
sewardjd68ac3e2006-01-20 14:31:57 +00001066 )
1067 );
sewardj34593e52006-01-17 01:57:33 +00001068
1069 /* res = guest_REDIR_STACK[t1+0] */
sewardj4a0009c2006-10-17 01:52:05 +00001070 /* PutI/GetI have I32-typed indexes regardless of guest word size */
sewardj0b9d74a2006-12-24 02:24:11 +00001071 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001072 bb,
sewardj0b9d74a2006-12-24 02:24:11 +00001073 IRStmt_WrTmp(
sewardj34593e52006-01-17 01:57:33 +00001074 res,
sewardj0b9d74a2006-12-24 02:24:11 +00001075 IRExpr_GetI(descr, narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0)
sewardj34593e52006-01-17 01:57:33 +00001076 )
1077 );
1078
1079 /* guest_REDIR_SP = t1-1 */
sewardj0b9d74a2006-12-24 02:24:11 +00001080 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001081 bb,
sewardj0b9d74a2006-12-24 02:24:11 +00001082 IRStmt_Put(offB_REDIR_SP, IRExpr_Binop(op_Sub, IRExpr_RdTmp(t1), one))
sewardj34593e52006-01-17 01:57:33 +00001083 );
1084
1085 return res;
1086}
1087
sewardj4a0009c2006-10-17 01:52:05 +00001088/* Generate code to push LR and R2 onto this thread's redir stack,
1089 then set R2 to the new value (which is the TOC pointer to be used
1090 for the duration of the replacement function, as determined by
1091 m_debuginfo), and set LR to the magic return stub, so we get to
1092 intercept the return and restore R2 and L2 to the values saved
1093 here. */
1094
sewardj0b9d74a2006-12-24 02:24:11 +00001095static void gen_push_and_set_LR_R2 ( IRSB* bb, Addr64 new_R2_value )
sewardj34593e52006-01-17 01:57:33 +00001096{
sewardj6e9de462011-06-28 07:25:29 +00001097# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +00001098 Addr64 bogus_RA = (Addr64)&VG_(ppctoc_magic_redirect_return_stub);
1099 Int offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1100 Int offB_LR = offsetof(VexGuestPPC64State,guest_LR);
sewardj34593e52006-01-17 01:57:33 +00001101 gen_PUSH( bb, IRExpr_Get(offB_LR, Ity_I64) );
1102 gen_PUSH( bb, IRExpr_Get(offB_GPR2, Ity_I64) );
sewardj0b9d74a2006-12-24 02:24:11 +00001103 addStmtToIRSB( bb, IRStmt_Put( offB_LR, mkU64( bogus_RA )) );
1104 addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, mkU64( new_R2_value )) );
sewardj4a0009c2006-10-17 01:52:05 +00001105
sewardj4a0009c2006-10-17 01:52:05 +00001106# else
1107# error Platform is not TOC-afflicted, fortunately
1108# endif
sewardj34593e52006-01-17 01:57:33 +00001109}
1110
sewardj0b9d74a2006-12-24 02:24:11 +00001111static void gen_pop_R2_LR_then_bLR ( IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001112{
sewardj6e9de462011-06-28 07:25:29 +00001113# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +00001114 Int offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1115 Int offB_LR = offsetof(VexGuestPPC64State,guest_LR);
sewardj291849f2012-04-20 23:58:55 +00001116 Int offB_CIA = offsetof(VexGuestPPC64State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +00001117 IRTemp old_R2 = newIRTemp( bb->tyenv, Ity_I64 );
1118 IRTemp old_LR = newIRTemp( bb->tyenv, Ity_I64 );
sewardj34593e52006-01-17 01:57:33 +00001119 /* Restore R2 */
1120 old_R2 = gen_POP( bb );
sewardj0b9d74a2006-12-24 02:24:11 +00001121 addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, IRExpr_RdTmp(old_R2)) );
sewardj34593e52006-01-17 01:57:33 +00001122 /* Restore LR */
1123 old_LR = gen_POP( bb );
sewardj0b9d74a2006-12-24 02:24:11 +00001124 addStmtToIRSB( bb, IRStmt_Put( offB_LR, IRExpr_RdTmp(old_LR)) );
sewardj34593e52006-01-17 01:57:33 +00001125 /* Branch to LR */
1126 /* re boring, we arrived here precisely because a wrapped fn did a
1127 blr (hence Ijk_Ret); so we should just mark this jump as Boring,
sewardj4a0009c2006-10-17 01:52:05 +00001128 else one _Call will have resulted in two _Rets. */
sewardj34593e52006-01-17 01:57:33 +00001129 bb->jumpkind = Ijk_Boring;
sewardj291849f2012-04-20 23:58:55 +00001130 bb->next = IRExpr_Binop(Iop_And64, IRExpr_RdTmp(old_LR), mkU64(~(3ULL)));
1131 bb->offsIP = offB_CIA;
sewardj4a0009c2006-10-17 01:52:05 +00001132# else
1133# error Platform is not TOC-afflicted, fortunately
1134# endif
sewardj34593e52006-01-17 01:57:33 +00001135}
1136
1137static
sewardj0b9d74a2006-12-24 02:24:11 +00001138Bool mk_preamble__ppctoc_magic_return_stub ( void* closureV, IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001139{
sewardj0283bae2006-01-22 01:15:36 +00001140 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
sewardj0b9d74a2006-12-24 02:24:11 +00001141 /* Since we're creating the entire IRSB right here, give it a
sewardj0283bae2006-01-22 01:15:36 +00001142 proper IMark, as it won't get one any other way, and cachegrind
1143 will barf if it doesn't have one (fair enough really). */
sewardj80e88b02011-05-28 15:34:17 +00001144 addStmtToIRSB( bb, IRStmt_IMark( closure->readdr, 4, 0 ) );
sewardj0283bae2006-01-22 01:15:36 +00001145 /* Generate the magic sequence:
1146 pop R2 from hidden stack
1147 pop LR from hidden stack
1148 goto LR
1149 */
sewardj34593e52006-01-17 01:57:33 +00001150 gen_pop_R2_LR_then_bLR(bb);
1151 return True; /* True == this is the entire BB; don't disassemble any
1152 real insns into it - just hand it directly to
1153 optimiser/instrumenter/backend. */
1154}
1155#endif
1156
sewardj4a0009c2006-10-17 01:52:05 +00001157/* --------------- END helpers for with-TOC platforms --------------- */
sewardj34593e52006-01-17 01:57:33 +00001158
sewardj4a0009c2006-10-17 01:52:05 +00001159
1160/* This is the IR preamble generator used for replacement
sewardj0283bae2006-01-22 01:15:36 +00001161 functions. It adds code to set the guest_NRADDR{_GPR2} to zero
sewardj34593e52006-01-17 01:57:33 +00001162 (technically not necessary, but facilitates detecting mixups in
sewardj0283bae2006-01-22 01:15:36 +00001163 which a replacement function has been erroneously declared using
1164 VG_REPLACE_FUNCTION_Z{U,Z} when instead it should have been written
1165 using VG_WRAP_FUNCTION_Z{U,Z}).
sewardj34593e52006-01-17 01:57:33 +00001166
sewardj4a0009c2006-10-17 01:52:05 +00001167 On with-TOC platforms the follow hacks are also done: LR and R2 are
1168 pushed onto a hidden stack, R2 is set to the correct value for the
1169 replacement function, and LR is set to point at the magic
1170 return-stub address. Setting LR causes the return of the
1171 wrapped/redirected function to lead to our magic return stub, which
1172 restores LR and R2 from said stack and returns for real.
sewardjdfbaa222006-01-18 04:25:20 +00001173
sewardjb8b79ad2008-03-03 01:35:41 +00001174 VG_(get_StackTrace_wrk) understands that the LR value may point to
1175 the return stub address, and that in that case it can get the real
1176 LR value from the hidden stack instead. */
sewardj34593e52006-01-17 01:57:33 +00001177static
sewardj0b9d74a2006-12-24 02:24:11 +00001178Bool mk_preamble__set_NRADDR_to_zero ( void* closureV, IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001179{
sewardj34593e52006-01-17 01:57:33 +00001180 Int nraddr_szB
1181 = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1182 vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
sewardj4a0009c2006-10-17 01:52:05 +00001183 vg_assert(nraddr_szB == VG_WORDSIZE);
sewardj0b9d74a2006-12-24 02:24:11 +00001184 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001185 bb,
1186 IRStmt_Put(
1187 offsetof(VexGuestArchState,guest_NRADDR),
sewardj0283bae2006-01-22 01:15:36 +00001188 nraddr_szB == 8 ? mkU64(0) : mkU32(0)
sewardj34593e52006-01-17 01:57:33 +00001189 )
1190 );
sewardj5db15402012-06-07 09:13:21 +00001191# if defined(VGP_mips32_linux)
1192 // t9 needs to be set to point to the start of the redirected function.
1193 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1194 Int offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
1195 addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
1196# endif
sewardj4a0009c2006-10-17 01:52:05 +00001197# if defined(VG_PLAT_USES_PPCTOC)
sewardj0283bae2006-01-22 01:15:36 +00001198 { VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
sewardj0b9d74a2006-12-24 02:24:11 +00001199 addStmtToIRSB(
sewardj0283bae2006-01-22 01:15:36 +00001200 bb,
1201 IRStmt_Put(
1202 offsetof(VexGuestArchState,guest_NRADDR_GPR2),
sewardj4a0009c2006-10-17 01:52:05 +00001203 VG_WORDSIZE==8 ? mkU64(0) : mkU32(0)
sewardj0283bae2006-01-22 01:15:36 +00001204 )
1205 );
1206 gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1207 }
sewardj34593e52006-01-17 01:57:33 +00001208# endif
1209 return False;
1210}
1211
1212/* Ditto, except set guest_NRADDR to nraddr (the un-redirected guest
1213 address). This is needed for function wrapping - so the wrapper
1214 can read _NRADDR and find the address of the function being
sewardj4a0009c2006-10-17 01:52:05 +00001215 wrapped. On toc-afflicted platforms we must also snarf r2. */
sewardj34593e52006-01-17 01:57:33 +00001216static
sewardj0b9d74a2006-12-24 02:24:11 +00001217Bool mk_preamble__set_NRADDR_to_nraddr ( void* closureV, IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001218{
1219 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1220 Int nraddr_szB
1221 = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1222 vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
sewardj4a0009c2006-10-17 01:52:05 +00001223 vg_assert(nraddr_szB == VG_WORDSIZE);
sewardj0b9d74a2006-12-24 02:24:11 +00001224 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001225 bb,
1226 IRStmt_Put(
1227 offsetof(VexGuestArchState,guest_NRADDR),
1228 nraddr_szB == 8
1229 ? IRExpr_Const(IRConst_U64( closure->nraddr ))
1230 : IRExpr_Const(IRConst_U32( (UInt)closure->nraddr ))
1231 )
1232 );
sewardj5db15402012-06-07 09:13:21 +00001233# if defined(VGP_mips32_linux)
1234 // t9 needs to be set to point to the start of the redirected function.
1235 Int offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
1236 addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
1237# endif
sewardj6e9de462011-06-28 07:25:29 +00001238# if defined(VGP_ppc64_linux)
sewardj0b9d74a2006-12-24 02:24:11 +00001239 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +00001240 bb,
1241 IRStmt_Put(
1242 offsetof(VexGuestArchState,guest_NRADDR_GPR2),
1243 IRExpr_Get(offsetof(VexGuestArchState,guest_GPR2),
sewardj4a0009c2006-10-17 01:52:05 +00001244 VG_WORDSIZE==8 ? Ity_I64 : Ity_I32)
sewardjd68ac3e2006-01-20 14:31:57 +00001245 )
1246 );
sewardj34593e52006-01-17 01:57:33 +00001247 gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1248# endif
1249 return False;
1250}
1251
sewardj4a0009c2006-10-17 01:52:05 +00001252/* --- Helpers to do with PPC related stack redzones. --- */
1253
1254__attribute__((unused))
1255static Bool const_True ( Addr64 guest_addr )
1256{
1257 return True;
1258}
1259
sewardj34593e52006-01-17 01:57:33 +00001260/* --------------- main translation function --------------- */
1261
sewardj0ec07f32006-01-12 12:32:32 +00001262/* Note: see comments at top of m_redir.c for the Big Picture on how
1263 redirections are managed. */
1264
sewardj34593e52006-01-17 01:57:33 +00001265typedef
1266 enum {
1267 /* normal translation, redir neither requested nor inhibited */
1268 T_Normal,
1269 /* redir translation, function-wrap (set _NRADDR) style */
1270 T_Redir_Wrap,
1271 /* redir translation, replacement (don't set _NRADDR) style */
1272 T_Redir_Replace,
1273 /* a translation in which redir is specifically disallowed */
1274 T_NoRedir
1275 }
1276 T_Kind;
1277
1278/* Translate the basic block beginning at NRADDR, and add it to the
1279 translation cache & translation table. Unless
1280 DEBUGGING_TRANSLATION is true, in which case the call is being done
1281 for debugging purposes, so (a) throw away the translation once it
1282 is made, and (b) produce a load of debugging output. If
1283 ALLOW_REDIRECTION is False, do not attempt redirection of NRADDR,
1284 and also, put the resulting translation into the no-redirect tt/tc
1285 instead of the normal one.
1286
1287 TID is the identity of the thread requesting this translation.
1288*/
1289
sewardjfa8ec112005-01-19 11:55:34 +00001290Bool VG_(translate) ( ThreadId tid,
sewardj34593e52006-01-17 01:57:33 +00001291 Addr64 nraddr,
sewardjfa8ec112005-01-19 11:55:34 +00001292 Bool debugging_translation,
njn394213a2005-06-19 18:38:24 +00001293 Int debugging_verbosity,
sewardj0ec07f32006-01-12 12:32:32 +00001294 ULong bbs_done,
1295 Bool allow_redirection )
sewardjde4a1d02002-03-22 01:27:54 +00001296{
sewardj34593e52006-01-17 01:57:33 +00001297 Addr64 addr;
1298 T_Kind kind;
sewardje2d1e672005-11-12 23:10:48 +00001299 Int tmpbuf_used, verbosity, i;
sewardj0b9d74a2006-12-24 02:24:11 +00001300 Bool (*preamble_fn)(void*,IRSB*);
sewardje2d1e672005-11-12 23:10:48 +00001301 VexArch vex_arch;
1302 VexArchInfo vex_archinfo;
sewardj0b9d74a2006-12-24 02:24:11 +00001303 VexAbiInfo vex_abiinfo;
sewardje2d1e672005-11-12 23:10:48 +00001304 VexGuestExtents vge;
sewardj274807d2005-12-15 14:07:07 +00001305 VexTranslateArgs vta;
sewardje2d1e672005-11-12 23:10:48 +00001306 VexTranslateResult tres;
sewardj34593e52006-01-17 01:57:33 +00001307 VgCallbackClosure closure;
njn36932cb2005-05-11 22:45:48 +00001308
sewardj8b635a42004-11-22 19:01:47 +00001309 /* Make sure Vex is initialised right. */
sewardje2d1e672005-11-12 23:10:48 +00001310
sewardj8b635a42004-11-22 19:01:47 +00001311 static Bool vex_init_done = False;
1312
1313 if (!vex_init_done) {
1314 LibVEX_Init ( &failure_exit, &log_bytes,
1315 1, /* debug_paranoia */
1316 False, /* valgrind support */
1317 &VG_(clo_vex_control) );
1318 vex_init_done = True;
1319 }
1320
sewardj34593e52006-01-17 01:57:33 +00001321 /* Establish the translation kind and actual guest address to
1322 start from. Sets (addr,kind). */
sewardj0ec07f32006-01-12 12:32:32 +00001323 if (allow_redirection) {
sewardj34593e52006-01-17 01:57:33 +00001324 Bool isWrap;
1325 Addr64 tmp = VG_(redir_do_lookup)( nraddr, &isWrap );
1326 if (tmp == nraddr) {
1327 /* no redirection found */
1328 addr = nraddr;
1329 kind = T_Normal;
1330 } else {
1331 /* found a redirect */
1332 addr = tmp;
1333 kind = isWrap ? T_Redir_Wrap : T_Redir_Replace;
1334 }
sewardj0ec07f32006-01-12 12:32:32 +00001335 } else {
sewardj34593e52006-01-17 01:57:33 +00001336 addr = nraddr;
1337 kind = T_NoRedir;
sewardj0ec07f32006-01-12 12:32:32 +00001338 }
fitzhardinge98abfc72003-12-16 02:05:15 +00001339
sewardj34593e52006-01-17 01:57:33 +00001340 /* Established: (nraddr, addr, kind) */
sewardj0ec07f32006-01-12 12:32:32 +00001341
sewardj34593e52006-01-17 01:57:33 +00001342 /* Printing redirection info. */
1343
1344 if ((kind == T_Redir_Wrap || kind == T_Redir_Replace)
sewardj0ec07f32006-01-12 12:32:32 +00001345 && (VG_(clo_verbosity) >= 2 || VG_(clo_trace_redir))) {
sewardjfa8ec112005-01-19 11:55:34 +00001346 Bool ok;
sewardje318d0b2012-02-28 18:02:41 +00001347 Char name1[512] = "";
1348 Char name2[512] = "";
sewardjfa8ec112005-01-19 11:55:34 +00001349 name1[0] = name2[0] = 0;
sewardje318d0b2012-02-28 18:02:41 +00001350 ok = VG_(get_fnname_w_offset)(nraddr, name1, 512);
njnbe73f432005-03-26 21:34:45 +00001351 if (!ok) VG_(strcpy)(name1, "???");
sewardje318d0b2012-02-28 18:02:41 +00001352 ok = VG_(get_fnname_w_offset)(addr, name2, 512);
njnbe73f432005-03-26 21:34:45 +00001353 if (!ok) VG_(strcpy)(name2, "???");
njn3f04d242005-03-20 18:21:14 +00001354 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00001355 "REDIR: 0x%llx (%s) redirected to 0x%llx (%s)\n",
sewardj34593e52006-01-17 01:57:33 +00001356 nraddr, name1,
1357 addr, name2 );
nethercote59a122d2004-08-03 17:16:51 +00001358 }
sewardj25c7c3a2003-07-10 00:17:58 +00001359
njn25e49d8e72002-09-23 09:36:25 +00001360 if (!debugging_translation)
sewardj45f4e7c2005-09-27 19:20:21 +00001361 VG_TRACK( pre_mem_read, Vg_CoreTranslate,
sewardj34593e52006-01-17 01:57:33 +00001362 tid, "(translator)", addr, 1 );
sewardjde4a1d02002-03-22 01:27:54 +00001363
sewardj85ac6d42005-02-23 11:36:56 +00001364 /* If doing any code printing, print a basic block start marker */
1365 if (VG_(clo_trace_flags) || debugging_translation) {
sewardje318d0b2012-02-28 18:02:41 +00001366 Char fnname[512] = "UNKNOWN_FUNCTION";
1367 VG_(get_fnname_w_offset)(addr, fnname, 512);
sewardj227fd912011-10-21 04:59:56 +00001368 const UChar* objname = "UNKNOWN_OBJECT";
1369 OffT objoff = 0;
1370 DebugInfo* di = VG_(find_DebugInfo)( addr );
1371 if (di) {
1372 objname = VG_(DebugInfo_get_filename)(di);
1373 objoff = addr - VG_(DebugInfo_get_text_bias)(di);
1374 }
1375 vg_assert(objname);
sewardj85ac6d42005-02-23 11:36:56 +00001376 VG_(printf)(
sewardj291849f2012-04-20 23:58:55 +00001377 "==== SB %d (evchecks %lld) [tid %d] 0x%llx %s %s+0x%llx\n",
sewardj227fd912011-10-21 04:59:56 +00001378 VG_(get_bbs_translated)(), bbs_done, (Int)tid, addr,
1379 fnname, objname, (ULong)objoff
1380 );
sewardj85ac6d42005-02-23 11:36:56 +00001381 }
1382
sewardj45f4e7c2005-09-27 19:20:21 +00001383 /* Are we allowed to translate here? */
1384
sewardj4a0009c2006-10-17 01:52:05 +00001385 { /* BEGIN new scope specially for 'seg' */
1386 NSegment const* seg = VG_(am_find_nsegment)(addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001387
sewardj5f76de02007-02-11 05:08:06 +00001388 if ( (!translations_allowable_from_seg(seg))
1389 || addr == TRANSTAB_BOGUS_GUEST_ADDR ) {
sewardj4a0009c2006-10-17 01:52:05 +00001390 if (VG_(clo_trace_signals))
sewardja5940262007-09-10 16:28:38 +00001391 VG_(message)(Vg_DebugMsg, "translations not allowed here (0x%llx)"
sewardj738856f2009-07-15 14:48:32 +00001392 " - throwing SEGV\n", addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001393 /* U R busted, sonny. Place your hands on your head and step
1394 away from the orig_addr. */
fitzhardinge98abfc72003-12-16 02:05:15 +00001395 /* Code address is bad - deliver a signal instead */
sewardj45f4e7c2005-09-27 19:20:21 +00001396 if (seg != NULL) {
1397 /* There's some kind of segment at the requested place, but we
1398 aren't allowed to execute code here. */
sewardj3b290482011-05-06 21:02:55 +00001399 if (debugging_translation)
1400 VG_(printf)("translations not allowed here (segment not executable)"
1401 "(0x%llx)\n", addr);
1402 else
1403 VG_(synth_fault_perms)(tid, addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001404 } else {
1405 /* There is no segment at all; we are attempting to execute in
1406 the middle of nowhere. */
sewardj3b290482011-05-06 21:02:55 +00001407 if (debugging_translation)
1408 VG_(printf)("translations not allowed here (no segment)"
1409 "(0x%llx)\n", addr);
1410 else
1411 VG_(synth_fault_mapping)(tid, addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001412 }
nethercote4d714382004-10-13 09:47:24 +00001413 return False;
sewardj45f4e7c2005-09-27 19:20:21 +00001414 }
sewardjde4a1d02002-03-22 01:27:54 +00001415
njn25e49d8e72002-09-23 09:36:25 +00001416 /* True if a debug trans., or if bit N set in VG_(clo_trace_codegen). */
sewardjc771b292004-11-30 18:55:21 +00001417 verbosity = 0;
sewardj167d4e32004-12-31 01:14:04 +00001418 if (debugging_translation) {
sewardjfa8ec112005-01-19 11:55:34 +00001419 verbosity = debugging_verbosity;
sewardj167d4e32004-12-31 01:14:04 +00001420 }
1421 else
sewardjfa8ec112005-01-19 11:55:34 +00001422 if ( (VG_(clo_trace_flags) > 0
florian29e022d2012-07-02 21:13:34 +00001423 && VG_(get_bbs_translated)() <= VG_(clo_trace_notabove)
sewardj167d4e32004-12-31 01:14:04 +00001424 && VG_(get_bbs_translated)() >= VG_(clo_trace_notbelow) )) {
sewardjfa8ec112005-01-19 11:55:34 +00001425 verbosity = VG_(clo_trace_flags);
sewardj167d4e32004-12-31 01:14:04 +00001426 }
njn25e49d8e72002-09-23 09:36:25 +00001427
sewardj34593e52006-01-17 01:57:33 +00001428 /* Figure out which preamble-mangling callback to send. */
1429 preamble_fn = NULL;
1430 if (kind == T_Redir_Replace)
1431 preamble_fn = mk_preamble__set_NRADDR_to_zero;
1432 else
1433 if (kind == T_Redir_Wrap)
1434 preamble_fn = mk_preamble__set_NRADDR_to_nraddr;
sewardj4a0009c2006-10-17 01:52:05 +00001435
1436# if defined(VG_PLAT_USES_PPCTOC)
1437 if (ULong_to_Ptr(nraddr)
1438 == (void*)&VG_(ppctoc_magic_redirect_return_stub)) {
sewardj34593e52006-01-17 01:57:33 +00001439 /* If entering the special return stub, this means a wrapped or
1440 redirected function is returning. Make this translation one
1441 which restores R2 and LR from the thread's hidden redir
1442 stack, and branch to the (restored) link register, thereby
1443 really causing the function to return. */
1444 vg_assert(kind == T_Normal);
1445 vg_assert(nraddr == addr);
sewardj4a0009c2006-10-17 01:52:05 +00001446 preamble_fn = mk_preamble__ppctoc_magic_return_stub;
1447 }
sewardj34593e52006-01-17 01:57:33 +00001448# endif
1449
sewardje2d1e672005-11-12 23:10:48 +00001450 /* ------ Actually do the translation. ------ */
njn51d827b2005-05-09 01:02:08 +00001451 tl_assert2(VG_(tdict).tool_instrument,
1452 "you forgot to set VgToolInterface function 'tool_instrument'");
sewardj7be55092005-08-01 23:25:55 +00001453
sewardje2d1e672005-11-12 23:10:48 +00001454 /* Get the CPU info established at startup. */
1455 VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
1456
sewardj0b9d74a2006-12-24 02:24:11 +00001457 /* Set up 'abiinfo' structure with stuff Vex needs to know about
sewardj4a0009c2006-10-17 01:52:05 +00001458 the guest and host ABIs. */
1459
sewardj0b9d74a2006-12-24 02:24:11 +00001460 LibVEX_default_VexAbiInfo( &vex_abiinfo );
1461 vex_abiinfo.guest_stack_redzone_size = VG_STACK_REDZONE_SZB;
sewardj4a0009c2006-10-17 01:52:05 +00001462
sewardjc0b20392008-12-04 00:07:30 +00001463# if defined(VGP_amd64_linux)
1464 vex_abiinfo.guest_amd64_assume_fs_is_zero = True;
1465# endif
njnf76d27a2009-05-28 01:53:07 +00001466# if defined(VGP_amd64_darwin)
1467 vex_abiinfo.guest_amd64_assume_gs_is_0x60 = True;
1468# endif
sewardj4a0009c2006-10-17 01:52:05 +00001469# if defined(VGP_ppc32_linux)
sewardj0b9d74a2006-12-24 02:24:11 +00001470 vex_abiinfo.guest_ppc_zap_RZ_at_blr = False;
1471 vex_abiinfo.guest_ppc_zap_RZ_at_bl = NULL;
1472 vex_abiinfo.host_ppc32_regalign_int64_args = True;
sewardj4a0009c2006-10-17 01:52:05 +00001473# endif
1474# if defined(VGP_ppc64_linux)
sewardj0b9d74a2006-12-24 02:24:11 +00001475 vex_abiinfo.guest_ppc_zap_RZ_at_blr = True;
1476 vex_abiinfo.guest_ppc_zap_RZ_at_bl = const_True;
1477 vex_abiinfo.host_ppc_calls_use_fndescrs = True;
sewardj4a0009c2006-10-17 01:52:05 +00001478# endif
sewardj4a0009c2006-10-17 01:52:05 +00001479
sewardj34593e52006-01-17 01:57:33 +00001480 /* Set up closure args. */
1481 closure.tid = tid;
1482 closure.nraddr = nraddr;
1483 closure.readdr = addr;
sewardj7be55092005-08-01 23:25:55 +00001484
sewardj0ec07f32006-01-12 12:32:32 +00001485 /* Set up args for LibVEX_Translate. */
sewardj274807d2005-12-15 14:07:07 +00001486 vta.arch_guest = vex_arch;
1487 vta.archinfo_guest = vex_archinfo;
1488 vta.arch_host = vex_arch;
1489 vta.archinfo_host = vex_archinfo;
sewardj0b9d74a2006-12-24 02:24:11 +00001490 vta.abiinfo_both = vex_abiinfo;
sewardj291849f2012-04-20 23:58:55 +00001491 vta.callback_opaque = (void*)&closure;
sewardj34593e52006-01-17 01:57:33 +00001492 vta.guest_bytes = (UChar*)ULong_to_Ptr(addr);
1493 vta.guest_bytes_addr = (Addr64)addr;
sewardj274807d2005-12-15 14:07:07 +00001494 vta.chase_into_ok = chase_into_ok;
1495 vta.guest_extents = &vge;
1496 vta.host_bytes = tmpbuf;
1497 vta.host_bytes_size = N_TMPBUF;
1498 vta.host_bytes_used = &tmpbuf_used;
sewardj34593e52006-01-17 01:57:33 +00001499 { /* At this point we have to reconcile Vex's view of the
1500 instrumentation callback - which takes a void* first argument
1501 - with Valgrind's view, in which the first arg is a
1502 VgCallbackClosure*. Hence the following longwinded casts.
1503 They are entirely legal but longwinded so as to maximise the
1504 chance of the C typechecker picking up any type snafus. */
sewardj0b9d74a2006-12-24 02:24:11 +00001505 IRSB*(*f)(VgCallbackClosure*,
1506 IRSB*,VexGuestLayout*,VexGuestExtents*,
sewardj34593e52006-01-17 01:57:33 +00001507 IRType,IRType)
sewardj3b290482011-05-06 21:02:55 +00001508 = VG_(clo_vgdb) != Vg_VgdbNo
1509 ? tool_instrument_then_gdbserver_if_needed
1510 : VG_(tdict).tool_instrument;
sewardj0b9d74a2006-12-24 02:24:11 +00001511 IRSB*(*g)(void*,
1512 IRSB*,VexGuestLayout*,VexGuestExtents*,
sewardj34593e52006-01-17 01:57:33 +00001513 IRType,IRType)
sewardj0b9d74a2006-12-24 02:24:11 +00001514 = (IRSB*(*)(void*,IRSB*,VexGuestLayout*,VexGuestExtents*,IRType,IRType))f;
sewardj291849f2012-04-20 23:58:55 +00001515 vta.instrument1 = g;
sewardj34593e52006-01-17 01:57:33 +00001516 }
1517 /* No need for type kludgery here. */
sewardj291849f2012-04-20 23:58:55 +00001518 vta.instrument2 = need_to_handle_SP_assignment()
1519 ? vg_SP_update_pass
1520 : NULL;
1521 vta.finaltidy = VG_(needs).final_IR_tidy_pass
1522 ? VG_(tdict).tool_final_IR_tidy_pass
1523 : NULL;
1524 vta.needs_self_check = needs_self_check;
1525 vta.preamble_function = preamble_fn;
1526 vta.traceflags = verbosity;
1527 vta.addProfInc = VG_(clo_profile_flags) > 0
1528 && kind != T_NoRedir;
sewardj274807d2005-12-15 14:07:07 +00001529
sewardj291849f2012-04-20 23:58:55 +00001530 /* Set up the dispatch continuation-point info. If this is a
1531 no-redir translation then it cannot be chained, and the chain-me
1532 points are set to NULL to indicate that. The indir point must
1533 also be NULL, since we can't allow this translation to do an
1534 indir transfer -- that would take it back into the main
1535 translation cache too.
sewardj0ec07f32006-01-12 12:32:32 +00001536
sewardj291849f2012-04-20 23:58:55 +00001537 All this is because no-redir translations live outside the main
1538 translation cache (in a secondary one) and chaining them would
1539 involve more adminstrative complexity that isn't worth the
1540 hassle, because we don't expect them to get used often. So
1541 don't bother. */
1542 if (allow_redirection) {
1543 vta.disp_cp_chain_me_to_slowEP
1544 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_slowEP) );
1545 vta.disp_cp_chain_me_to_fastEP
1546 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_fastEP) );
1547 vta.disp_cp_xindir
1548 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xindir) );
1549 } else {
1550 vta.disp_cp_chain_me_to_slowEP = NULL;
1551 vta.disp_cp_chain_me_to_fastEP = NULL;
1552 vta.disp_cp_xindir = NULL;
sewardj12740272011-05-29 09:34:30 +00001553 }
sewardj291849f2012-04-20 23:58:55 +00001554 /* This doesn't involve chaining and so is always allowable. */
1555 vta.disp_cp_xassisted
1556 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xassisted) );
sewardj274807d2005-12-15 14:07:07 +00001557
1558 /* Sheesh. Finally, actually _do_ the translation! */
1559 tres = LibVEX_Translate ( &vta );
njn25e49d8e72002-09-23 09:36:25 +00001560
sewardj6dbcc632011-06-07 21:39:28 +00001561 vg_assert(tres.status == VexTransOK);
1562 vg_assert(tres.n_sc_extents >= 0 && tres.n_sc_extents <= 3);
sewardj8b635a42004-11-22 19:01:47 +00001563 vg_assert(tmpbuf_used <= N_TMPBUF);
1564 vg_assert(tmpbuf_used > 0);
sewardjde4a1d02002-03-22 01:27:54 +00001565
sewardj45f4e7c2005-09-27 19:20:21 +00001566 /* Tell aspacem of all segments that have had translations taken
1567 from them. Optimisation: don't re-look up vge.base[0] since seg
1568 should already point to it. */
1569
sewardj34593e52006-01-17 01:57:33 +00001570 vg_assert( vge.base[0] == (Addr64)addr );
sewardj4a0009c2006-10-17 01:52:05 +00001571 /* set 'translations taken from this segment' flag */
1572 VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( (NSegment*)seg );
1573 } /* END new scope specially for 'seg' */
sewardj45f4e7c2005-09-27 19:20:21 +00001574
1575 for (i = 1; i < vge.n_used; i++) {
sewardj4a0009c2006-10-17 01:52:05 +00001576 NSegment const* seg
1577 = VG_(am_find_nsegment)( vge.base[i] );
1578 /* set 'translations taken from this segment' flag */
1579 VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( (NSegment*)seg );
sewardj45f4e7c2005-09-27 19:20:21 +00001580 }
1581
nethercote59a122d2004-08-03 17:16:51 +00001582 /* Copy data at trans_addr into the translation cache. */
sewardj8b635a42004-11-22 19:01:47 +00001583 vg_assert(tmpbuf_used > 0 && tmpbuf_used < 65536);
nethercote59a122d2004-08-03 17:16:51 +00001584
1585 // If debugging, don't do anything with the translated block; we
1586 // only did this for the debugging output produced along the way.
1587 if (!debugging_translation) {
sewardj0ec07f32006-01-12 12:32:32 +00001588
sewardj34593e52006-01-17 01:57:33 +00001589 if (kind != T_NoRedir) {
sewardj0ec07f32006-01-12 12:32:32 +00001590 // Put it into the normal TT/TC structures. This is the
1591 // normal case.
1592
sewardj34593e52006-01-17 01:57:33 +00001593 // Note that we use nraddr (the non-redirected address), not
1594 // addr, which might have been changed by the redirection
sewardj0ec07f32006-01-12 12:32:32 +00001595 VG_(add_to_transtab)( &vge,
sewardj34593e52006-01-17 01:57:33 +00001596 nraddr,
sewardj0ec07f32006-01-12 12:32:32 +00001597 (Addr)(&tmpbuf[0]),
1598 tmpbuf_used,
sewardj291849f2012-04-20 23:58:55 +00001599 tres.n_sc_extents > 0,
1600 tres.offs_profInc,
sewardjb7301c62012-04-24 11:50:49 +00001601 tres.n_guest_instrs,
sewardj291849f2012-04-20 23:58:55 +00001602 vex_arch );
sewardj0ec07f32006-01-12 12:32:32 +00001603 } else {
sewardj291849f2012-04-20 23:58:55 +00001604 vg_assert(tres.offs_profInc == -1); /* -1 == unset */
sewardj0ec07f32006-01-12 12:32:32 +00001605 VG_(add_to_unredir_transtab)( &vge,
sewardj34593e52006-01-17 01:57:33 +00001606 nraddr,
sewardj0ec07f32006-01-12 12:32:32 +00001607 (Addr)(&tmpbuf[0]),
njn1dcee092009-02-24 03:07:37 +00001608 tmpbuf_used );
sewardj0ec07f32006-01-12 12:32:32 +00001609 }
sewardjde4a1d02002-03-22 01:27:54 +00001610 }
nethercote59a122d2004-08-03 17:16:51 +00001611
nethercote4d714382004-10-13 09:47:24 +00001612 return True;
sewardjde4a1d02002-03-22 01:27:54 +00001613}
1614
1615/*--------------------------------------------------------------------*/
njn3cbfbc12005-05-13 23:11:40 +00001616/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00001617/*--------------------------------------------------------------------*/