blob: 99a9b81905cad22a90a179755676160d3e3fde7a [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
philippe3fad65b2012-10-02 20:35:21 +000064#include "libvex_emnote.h" // For PPC, EmWarn_PPC64_redir_underflow
65
njna1f783f2005-06-18 03:44:34 +000066/*------------------------------------------------------------*/
njn42c83552005-12-05 20:45:59 +000067/*--- Stats ---*/
68/*------------------------------------------------------------*/
69
70static UInt n_SP_updates_fast = 0;
71static UInt n_SP_updates_generic_known = 0;
72static UInt n_SP_updates_generic_unknown = 0;
73
74void VG_(print_translation_stats) ( void )
75{
floriandbb35842012-10-27 18:39:11 +000076 HChar buf[7];
njn42c83552005-12-05 20:45:59 +000077 UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known
78 + n_SP_updates_generic_unknown;
79 VG_(percentify)(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
80 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +000081 "translate: fast SP updates identified: %'u (%s)\n",
njn42c83552005-12-05 20:45:59 +000082 n_SP_updates_fast, buf );
83
84 VG_(percentify)(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
85 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +000086 "translate: generic_known SP updates identified: %'u (%s)\n",
njn42c83552005-12-05 20:45:59 +000087 n_SP_updates_generic_known, buf );
88
89 VG_(percentify)(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf);
90 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +000091 "translate: generic_unknown SP updates identified: %'u (%s)\n",
njn42c83552005-12-05 20:45:59 +000092 n_SP_updates_generic_unknown, buf );
93}
94
95/*------------------------------------------------------------*/
sewardj8b635a42004-11-22 19:01:47 +000096/*--- %SP-update pass ---*/
nethercotebee3fd92004-08-02 15:17:43 +000097/*------------------------------------------------------------*/
98
njna1f783f2005-06-18 03:44:34 +000099static Bool need_to_handle_SP_assignment(void)
100{
sewardjf5c8e372006-02-12 15:42:20 +0000101 return ( VG_(tdict).track_new_mem_stack_4 ||
102 VG_(tdict).track_die_mem_stack_4 ||
103 VG_(tdict).track_new_mem_stack_8 ||
104 VG_(tdict).track_die_mem_stack_8 ||
105 VG_(tdict).track_new_mem_stack_12 ||
106 VG_(tdict).track_die_mem_stack_12 ||
107 VG_(tdict).track_new_mem_stack_16 ||
108 VG_(tdict).track_die_mem_stack_16 ||
109 VG_(tdict).track_new_mem_stack_32 ||
110 VG_(tdict).track_die_mem_stack_32 ||
111 VG_(tdict).track_new_mem_stack_112 ||
112 VG_(tdict).track_die_mem_stack_112 ||
113 VG_(tdict).track_new_mem_stack_128 ||
114 VG_(tdict).track_die_mem_stack_128 ||
115 VG_(tdict).track_new_mem_stack_144 ||
116 VG_(tdict).track_die_mem_stack_144 ||
117 VG_(tdict).track_new_mem_stack_160 ||
118 VG_(tdict).track_die_mem_stack_160 ||
119 VG_(tdict).track_new_mem_stack ||
120 VG_(tdict).track_die_mem_stack );
njna1f783f2005-06-18 03:44:34 +0000121}
122
njn5096a392005-12-13 20:05:00 +0000123// - The SP aliases are held in an array which is used as a circular buffer.
124// This misses very few constant updates of SP (ie. < 0.1%) while using a
125// small, constant structure that will also never fill up and cause
126// execution to abort.
127// - Unused slots have a .temp value of 'IRTemp_INVALID'.
128// - 'next_SP_alias_slot' is the index where the next alias will be stored.
129// - If the buffer fills, we circle around and start over-writing
130// non-IRTemp_INVALID values. This is rare, and the overwriting of a
131// value that would have subsequently be used is even rarer.
132// - Every slot below next_SP_alias_slot holds a non-IRTemp_INVALID value.
133// The rest either all won't (if we haven't yet circled around) or all
134// will (if we have circled around).
njn9b007f62003-04-07 14:40:25 +0000135
njn5096a392005-12-13 20:05:00 +0000136typedef
137 struct {
138 IRTemp temp;
139 Long delta;
140 }
141 SP_Alias;
142
143// With 32 slots the buffer fills very rarely -- eg. once in a run of GCC.
144// And I've tested with smaller values and the wrap-around case works ok.
145#define N_ALIASES 32
146static SP_Alias SP_aliases[N_ALIASES];
147static Int next_SP_alias_slot = 0;
148
149static void clear_SP_aliases(void)
150{
151 Int i;
152 for (i = 0; i < N_ALIASES; i++) {
153 SP_aliases[i].temp = IRTemp_INVALID;
154 SP_aliases[i].delta = 0;
155 }
156 next_SP_alias_slot = 0;
157}
158
159static void add_SP_alias(IRTemp temp, Long delta)
160{
161 vg_assert(temp != IRTemp_INVALID);
162 SP_aliases[ next_SP_alias_slot ].temp = temp;
163 SP_aliases[ next_SP_alias_slot ].delta = delta;
164 next_SP_alias_slot++;
165 if (N_ALIASES == next_SP_alias_slot) next_SP_alias_slot = 0;
166}
167
florian19f91bb2012-11-10 22:29:54 +0000168static Bool get_SP_delta(IRTemp temp, Long* delta)
njn5096a392005-12-13 20:05:00 +0000169{
170 Int i; // i must be signed!
171 vg_assert(IRTemp_INVALID != temp);
172 // Search backwards between current buffer position and the start.
173 for (i = next_SP_alias_slot-1; i >= 0; i--) {
174 if (temp == SP_aliases[i].temp) {
175 *delta = SP_aliases[i].delta;
176 return True;
177 }
178 }
179 // Search backwards between the end and the current buffer position.
180 for (i = N_ALIASES-1; i >= next_SP_alias_slot; i--) {
181 if (temp == SP_aliases[i].temp) {
182 *delta = SP_aliases[i].delta;
183 return True;
184 }
185 }
186 return False;
187}
188
189static void update_SP_aliases(Long delta)
190{
191 Int i;
192 for (i = 0; i < N_ALIASES; i++) {
193 if (SP_aliases[i].temp == IRTemp_INVALID) {
194 return;
195 }
196 SP_aliases[i].delta += delta;
197 }
198}
199
sewardj7cf4e6b2008-05-01 20:24:26 +0000200/* Given a guest IP, get an origin tag for a 1-element stack trace,
201 and wrap it up in an IR atom that can be passed as the origin-tag
202 value for a stack-adjustment helper function. */
203static IRExpr* mk_ecu_Expr ( Addr64 guest_IP )
204{
205 UInt ecu;
206 ExeContext* ec
207 = VG_(make_depth_1_ExeContext_from_Addr)( (Addr)guest_IP );
208 vg_assert(ec);
209 ecu = VG_(get_ECU_from_ExeContext)( ec );
210 vg_assert(VG_(is_plausible_ECU)(ecu));
211 /* This is always safe to do, since ecu is only 32 bits, and
212 HWord is 32 or 64. */
213 return mkIRExpr_HWord( (HWord)ecu );
214}
215
sewardj3b290482011-05-06 21:02:55 +0000216/* When gdbserver is activated, the translation of a block must
217 first be done by the tool function, then followed by a pass
218 which (if needed) instruments the code for gdbserver.
219*/
220static
221IRSB* tool_instrument_then_gdbserver_if_needed ( VgCallbackClosure* closureV,
222 IRSB* sb_in,
223 VexGuestLayout* layout,
224 VexGuestExtents* vge,
florianca503be2012-10-07 21:59:42 +0000225 VexArchInfo* vai,
sewardj3b290482011-05-06 21:02:55 +0000226 IRType gWordTy,
227 IRType hWordTy )
228{
229 return VG_(instrument_for_gdbserver_if_needed)
230 (VG_(tdict).tool_instrument (closureV,
231 sb_in,
232 layout,
233 vge,
florianca503be2012-10-07 21:59:42 +0000234 vai,
sewardj3b290482011-05-06 21:02:55 +0000235 gWordTy,
236 hWordTy),
237 layout,
238 vge,
239 gWordTy,
240 hWordTy);
241}
njn5096a392005-12-13 20:05:00 +0000242
243/* For tools that want to know about SP changes, this pass adds
nethercote996901a2004-08-03 13:29:09 +0000244 in the appropriate hooks. We have to do it after the tool's
njn5096a392005-12-13 20:05:00 +0000245 instrumentation, so the tool doesn't have to worry about the C calls
njn9b007f62003-04-07 14:40:25 +0000246 it adds in, and we must do it before register allocation because
njn5096a392005-12-13 20:05:00 +0000247 spilled temps make it much harder to work out the SP deltas.
248 This it is done with Vex's "second instrumentation" pass.
sewardjde4a1d02002-03-22 01:27:54 +0000249
njn5096a392005-12-13 20:05:00 +0000250 Basically, we look for GET(SP)/PUT(SP) pairs and track constant
251 increments/decrements of SP between them. (This requires tracking one or
252 more "aliases", which are not exact aliases but instead are tempregs
253 whose value is equal to the SP's plus or minus a known constant.)
254 If all the changes to SP leading up to a PUT(SP) are by known, small
255 constants, we can do a specific call to eg. new_mem_stack_4, otherwise
256 we fall back to the case that handles an unknown SP change.
sewardj2831b512007-11-11 18:56:39 +0000257
258 There is some extra complexity to deal correctly with updates to
259 only parts of SP. Bizarre, but it has been known to happen.
njn5096a392005-12-13 20:05:00 +0000260*/
sewardjde4a1d02002-03-22 01:27:54 +0000261static
sewardj0b9d74a2006-12-24 02:24:11 +0000262IRSB* vg_SP_update_pass ( void* closureV,
263 IRSB* sb_in,
sewardj4ba057c2005-10-18 12:04:18 +0000264 VexGuestLayout* layout,
sewardj4ba057c2005-10-18 12:04:18 +0000265 VexGuestExtents* vge,
florianca503be2012-10-07 21:59:42 +0000266 VexArchInfo* vai,
sewardj4ba057c2005-10-18 12:04:18 +0000267 IRType gWordTy,
268 IRType hWordTy )
sewardjde4a1d02002-03-22 01:27:54 +0000269{
sewardj2eecb742012-06-01 16:11:41 +0000270 Int i, j, k, minoff_ST, maxoff_ST, sizeof_SP, offset_SP;
sewardj2831b512007-11-11 18:56:39 +0000271 Int first_SP, last_SP, first_Put, last_Put;
sewardj0b9d74a2006-12-24 02:24:11 +0000272 IRDirty *dcall, *d;
273 IRStmt* st;
274 IRExpr* e;
275 IRRegArray* descr;
276 IRType typeof_SP;
277 Long delta, con;
sewardjde4a1d02002-03-22 01:27:54 +0000278
sewardj7cf4e6b2008-05-01 20:24:26 +0000279 /* Set up stuff for tracking the guest IP */
280 Bool curr_IP_known = False;
281 Addr64 curr_IP = 0;
282
sewardj8b635a42004-11-22 19:01:47 +0000283 /* Set up BB */
sewardj0b9d74a2006-12-24 02:24:11 +0000284 IRSB* bb = emptyIRSB();
285 bb->tyenv = deepCopyIRTypeEnv(sb_in->tyenv);
286 bb->next = deepCopyIRExpr(sb_in->next);
287 bb->jumpkind = sb_in->jumpkind;
sewardj291849f2012-04-20 23:58:55 +0000288 bb->offsIP = sb_in->offsIP;
sewardjde4a1d02002-03-22 01:27:54 +0000289
sewardj7cf97ee2004-11-28 14:25:01 +0000290 delta = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000291
sewardj7cf97ee2004-11-28 14:25:01 +0000292 sizeof_SP = layout->sizeof_SP;
293 offset_SP = layout->offset_SP;
294 typeof_SP = sizeof_SP==4 ? Ity_I32 : Ity_I64;
sewardj8b635a42004-11-22 19:01:47 +0000295 vg_assert(sizeof_SP == 4 || sizeof_SP == 8);
sewardjde4a1d02002-03-22 01:27:54 +0000296
sewardj7cf4e6b2008-05-01 20:24:26 +0000297 /* --- Start of #defines --- */
298
sewardj8b635a42004-11-22 19:01:47 +0000299# define IS_ADD(op) (sizeof_SP==4 ? ((op)==Iop_Add32) : ((op)==Iop_Add64))
300# define IS_SUB(op) (sizeof_SP==4 ? ((op)==Iop_Sub32) : ((op)==Iop_Sub64))
sewardjde4a1d02002-03-22 01:27:54 +0000301
sewardj8b635a42004-11-22 19:01:47 +0000302# define IS_ADD_OR_SUB(op) (IS_ADD(op) || IS_SUB(op))
sewardjde4a1d02002-03-22 01:27:54 +0000303
sewardj8b635a42004-11-22 19:01:47 +0000304# define GET_CONST(con) \
305 (sizeof_SP==4 ? (Long)(Int)(con->Ico.U32) \
306 : (Long)(con->Ico.U64))
sewardjde4a1d02002-03-22 01:27:54 +0000307
sewardj7cf4e6b2008-05-01 20:24:26 +0000308# define DO_NEW(syze, tmpp) \
sewardj8b635a42004-11-22 19:01:47 +0000309 do { \
sewardj7cf4e6b2008-05-01 20:24:26 +0000310 Bool vanilla, w_ecu; \
311 vg_assert(curr_IP_known); \
312 vanilla = NULL != VG_(tdict).track_new_mem_stack_##syze; \
313 w_ecu = NULL != VG_(tdict).track_new_mem_stack_##syze##_w_ECU; \
314 vg_assert(!(vanilla && w_ecu)); /* can't have both */ \
315 if (!(vanilla || w_ecu)) \
316 goto generic; \
317 \
318 /* I don't know if it's really necessary to say that the */ \
319 /* call reads the stack pointer. But anyway, we do. */ \
320 if (w_ecu) { \
321 dcall = unsafeIRDirty_0_N( \
322 2/*regparms*/, \
323 "track_new_mem_stack_" #syze "_w_ECU", \
324 VG_(fnptr_to_fnentry)( \
325 VG_(tdict).track_new_mem_stack_##syze##_w_ECU ), \
326 mkIRExprVec_2(IRExpr_RdTmp(tmpp), \
327 mk_ecu_Expr(curr_IP)) \
328 ); \
329 } else { \
330 dcall = unsafeIRDirty_0_N( \
331 1/*regparms*/, \
332 "track_new_mem_stack_" #syze , \
333 VG_(fnptr_to_fnentry)( \
334 VG_(tdict).track_new_mem_stack_##syze ), \
335 mkIRExprVec_1(IRExpr_RdTmp(tmpp)) \
336 ); \
337 } \
338 dcall->nFxState = 1; \
339 dcall->fxState[0].fx = Ifx_Read; \
340 dcall->fxState[0].offset = layout->offset_SP; \
341 dcall->fxState[0].size = layout->sizeof_SP; \
sewardj2eecb742012-06-01 16:11:41 +0000342 dcall->fxState[0].nRepeats = 0; \
343 dcall->fxState[0].repeatLen = 0; \
sewardj7cf4e6b2008-05-01 20:24:26 +0000344 \
345 addStmtToIRSB( bb, IRStmt_Dirty(dcall) ); \
346 \
347 tl_assert(syze > 0); \
348 update_SP_aliases(syze); \
349 \
350 n_SP_updates_fast++; \
351 \
352 } while (0)
353
354# define DO_DIE(syze, tmpp) \
355 do { \
356 if (!VG_(tdict).track_die_mem_stack_##syze) \
sewardj8b635a42004-11-22 19:01:47 +0000357 goto generic; \
358 \
359 /* I don't know if it's really necessary to say that the */ \
360 /* call reads the stack pointer. But anyway, we do. */ \
361 dcall = unsafeIRDirty_0_N( \
362 1/*regparms*/, \
sewardj7cf4e6b2008-05-01 20:24:26 +0000363 "track_die_mem_stack_" #syze, \
sewardj53ee1fc2005-12-23 02:29:58 +0000364 VG_(fnptr_to_fnentry)( \
sewardj7cf4e6b2008-05-01 20:24:26 +0000365 VG_(tdict).track_die_mem_stack_##syze ), \
sewardj0b9d74a2006-12-24 02:24:11 +0000366 mkIRExprVec_1(IRExpr_RdTmp(tmpp)) \
sewardj8b635a42004-11-22 19:01:47 +0000367 ); \
368 dcall->nFxState = 1; \
369 dcall->fxState[0].fx = Ifx_Read; \
370 dcall->fxState[0].offset = layout->offset_SP; \
371 dcall->fxState[0].size = layout->sizeof_SP; \
sewardj2eecb742012-06-01 16:11:41 +0000372 dcall->fxState[0].nRepeats = 0; \
373 dcall->fxState[0].repeatLen = 0; \
sewardj8b635a42004-11-22 19:01:47 +0000374 \
sewardj0b9d74a2006-12-24 02:24:11 +0000375 addStmtToIRSB( bb, IRStmt_Dirty(dcall) ); \
njn42c83552005-12-05 20:45:59 +0000376 \
sewardj7cf4e6b2008-05-01 20:24:26 +0000377 tl_assert(syze > 0); \
378 update_SP_aliases(-(syze)); \
njn5096a392005-12-13 20:05:00 +0000379 \
njn42c83552005-12-05 20:45:59 +0000380 n_SP_updates_fast++; \
381 \
sewardj8b635a42004-11-22 19:01:47 +0000382 } while (0)
sewardjde4a1d02002-03-22 01:27:54 +0000383
sewardj7cf4e6b2008-05-01 20:24:26 +0000384 /* --- End of #defines --- */
385
njn5096a392005-12-13 20:05:00 +0000386 clear_SP_aliases();
387
sewardj0b9d74a2006-12-24 02:24:11 +0000388 for (i = 0; i < sb_in->stmts_used; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000389
sewardj0b9d74a2006-12-24 02:24:11 +0000390 st = sb_in->stmts[i];
sewardjde4a1d02002-03-22 01:27:54 +0000391
sewardj7cf4e6b2008-05-01 20:24:26 +0000392 if (st->tag == Ist_IMark) {
393 curr_IP_known = True;
394 curr_IP = st->Ist.IMark.addr;
395 }
396
sewardj8b635a42004-11-22 19:01:47 +0000397 /* t = Get(sp): curr = t, delta = 0 */
sewardj0b9d74a2006-12-24 02:24:11 +0000398 if (st->tag != Ist_WrTmp) goto case2;
399 e = st->Ist.WrTmp.data;
sewardj8b635a42004-11-22 19:01:47 +0000400 if (e->tag != Iex_Get) goto case2;
401 if (e->Iex.Get.offset != offset_SP) goto case2;
402 if (e->Iex.Get.ty != typeof_SP) goto case2;
sewardj2831b512007-11-11 18:56:39 +0000403 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
sewardj0b9d74a2006-12-24 02:24:11 +0000404 add_SP_alias(st->Ist.WrTmp.tmp, 0);
405 addStmtToIRSB( bb, st );
sewardj8b635a42004-11-22 19:01:47 +0000406 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000407
sewardj8b635a42004-11-22 19:01:47 +0000408 case2:
409 /* t' = curr +/- const: curr = t', delta +=/-= const */
sewardj0b9d74a2006-12-24 02:24:11 +0000410 if (st->tag != Ist_WrTmp) goto case3;
411 e = st->Ist.WrTmp.data;
sewardj8b635a42004-11-22 19:01:47 +0000412 if (e->tag != Iex_Binop) goto case3;
sewardj0b9d74a2006-12-24 02:24:11 +0000413 if (e->Iex.Binop.arg1->tag != Iex_RdTmp) goto case3;
414 if (!get_SP_delta(e->Iex.Binop.arg1->Iex.RdTmp.tmp, &delta)) goto case3;
sewardj8b635a42004-11-22 19:01:47 +0000415 if (e->Iex.Binop.arg2->tag != Iex_Const) goto case3;
416 if (!IS_ADD_OR_SUB(e->Iex.Binop.op)) goto case3;
njn5096a392005-12-13 20:05:00 +0000417 con = GET_CONST(e->Iex.Binop.arg2->Iex.Const.con);
sewardj2831b512007-11-11 18:56:39 +0000418 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
njn5096a392005-12-13 20:05:00 +0000419 if (IS_ADD(e->Iex.Binop.op)) {
sewardj0b9d74a2006-12-24 02:24:11 +0000420 add_SP_alias(st->Ist.WrTmp.tmp, delta + con);
njn5096a392005-12-13 20:05:00 +0000421 } else {
sewardj0b9d74a2006-12-24 02:24:11 +0000422 add_SP_alias(st->Ist.WrTmp.tmp, delta - con);
njn5096a392005-12-13 20:05:00 +0000423 }
sewardj0b9d74a2006-12-24 02:24:11 +0000424 addStmtToIRSB( bb, st );
sewardj8b635a42004-11-22 19:01:47 +0000425 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000426
sewardj8b635a42004-11-22 19:01:47 +0000427 case3:
428 /* t' = curr: curr = t' */
sewardj0b9d74a2006-12-24 02:24:11 +0000429 if (st->tag != Ist_WrTmp) goto case4;
430 e = st->Ist.WrTmp.data;
431 if (e->tag != Iex_RdTmp) goto case4;
432 if (!get_SP_delta(e->Iex.RdTmp.tmp, &delta)) goto case4;
sewardj2831b512007-11-11 18:56:39 +0000433 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
sewardj0b9d74a2006-12-24 02:24:11 +0000434 add_SP_alias(st->Ist.WrTmp.tmp, delta);
435 addStmtToIRSB( bb, st );
sewardj8b635a42004-11-22 19:01:47 +0000436 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000437
sewardj8b635a42004-11-22 19:01:47 +0000438 case4:
439 /* Put(sp) = curr */
sewardj2831b512007-11-11 18:56:39 +0000440 /* More generally, we must correctly handle a Put which writes
441 any part of SP, not just the case where all of SP is
442 written. */
sewardj8b635a42004-11-22 19:01:47 +0000443 if (st->tag != Ist_Put) goto case5;
sewardj2831b512007-11-11 18:56:39 +0000444 first_SP = offset_SP;
445 last_SP = first_SP + sizeof_SP - 1;
446 first_Put = st->Ist.Put.offset;
447 last_Put = first_Put
448 + sizeofIRType( typeOfIRExpr( bb->tyenv, st->Ist.Put.data ))
449 - 1;
450 vg_assert(first_SP <= last_SP);
451 vg_assert(first_Put <= last_Put);
452
453 if (last_Put < first_SP || last_SP < first_Put)
454 goto case5; /* no overlap */
455
456 if (st->Ist.Put.data->tag == Iex_RdTmp
457 && get_SP_delta(st->Ist.Put.data->Iex.RdTmp.tmp, &delta)) {
sewardj0b9d74a2006-12-24 02:24:11 +0000458 IRTemp tttmp = st->Ist.Put.data->Iex.RdTmp.tmp;
sewardj2831b512007-11-11 18:56:39 +0000459 /* Why should the following assertion hold? Because any
460 alias added by put_SP_alias must be of a temporary which
461 has the same type as typeof_SP, and whose value is a Get
462 at exactly offset_SP of size typeof_SP. Each call to
463 put_SP_alias is immediately preceded by an assertion that
464 we are putting in a binding for a correctly-typed
465 temporary. */
466 vg_assert( typeOfIRTemp(bb->tyenv, tttmp) == typeof_SP );
467 /* From the same type-and-offset-correctness argument, if
468 we found a useable alias, it must for an "exact" write of SP. */
469 vg_assert(first_SP == first_Put);
470 vg_assert(last_SP == last_Put);
sewardj8b635a42004-11-22 19:01:47 +0000471 switch (delta) {
sewardj0b9d74a2006-12-24 02:24:11 +0000472 case 0: addStmtToIRSB(bb,st); continue;
sewardj7cf4e6b2008-05-01 20:24:26 +0000473 case 4: DO_DIE( 4, tttmp); addStmtToIRSB(bb,st); continue;
474 case -4: DO_NEW( 4, tttmp); addStmtToIRSB(bb,st); continue;
475 case 8: DO_DIE( 8, tttmp); addStmtToIRSB(bb,st); continue;
476 case -8: DO_NEW( 8, tttmp); addStmtToIRSB(bb,st); continue;
477 case 12: DO_DIE( 12, tttmp); addStmtToIRSB(bb,st); continue;
478 case -12: DO_NEW( 12, tttmp); addStmtToIRSB(bb,st); continue;
479 case 16: DO_DIE( 16, tttmp); addStmtToIRSB(bb,st); continue;
480 case -16: DO_NEW( 16, tttmp); addStmtToIRSB(bb,st); continue;
481 case 32: DO_DIE( 32, tttmp); addStmtToIRSB(bb,st); continue;
482 case -32: DO_NEW( 32, tttmp); addStmtToIRSB(bb,st); continue;
483 case 112: DO_DIE( 112, tttmp); addStmtToIRSB(bb,st); continue;
484 case -112: DO_NEW( 112, tttmp); addStmtToIRSB(bb,st); continue;
485 case 128: DO_DIE( 128, tttmp); addStmtToIRSB(bb,st); continue;
486 case -128: DO_NEW( 128, tttmp); addStmtToIRSB(bb,st); continue;
487 case 144: DO_DIE( 144, tttmp); addStmtToIRSB(bb,st); continue;
488 case -144: DO_NEW( 144, tttmp); addStmtToIRSB(bb,st); continue;
489 case 160: DO_DIE( 160, tttmp); addStmtToIRSB(bb,st); continue;
490 case -160: DO_NEW( 160, tttmp); addStmtToIRSB(bb,st); continue;
njn42c83552005-12-05 20:45:59 +0000491 default:
sewardjbb686272006-01-22 20:12:45 +0000492 /* common values for ppc64: 144 128 160 112 176 */
njn42c83552005-12-05 20:45:59 +0000493 n_SP_updates_generic_known++;
494 goto generic;
sewardjde4a1d02002-03-22 01:27:54 +0000495 }
sewardj8b635a42004-11-22 19:01:47 +0000496 } else {
sewardj2831b512007-11-11 18:56:39 +0000497 /* Deal with an unknown update to SP. We're here because
498 either:
499 (1) the Put does not exactly cover SP; it is a partial update.
500 Highly unlikely, but has been known to happen for 16-bit
501 Windows apps running on Wine, doing 16-bit adjustments to
502 %sp.
503 (2) the Put does exactly cover SP, but we are unable to
504 determine how the value relates to the old SP. In any
505 case, we cannot assume that the Put.data value is a tmp;
506 we must assume it can be anything allowed in flat IR (tmp
507 or const).
508 */
sewardj7cf4e6b2008-05-01 20:24:26 +0000509 IRTemp old_SP;
njn42c83552005-12-05 20:45:59 +0000510 n_SP_updates_generic_unknown++;
511
njn5096a392005-12-13 20:05:00 +0000512 // Nb: if all is well, this generic case will typically be
513 // called something like every 1000th SP update. If it's more than
514 // that, the above code may be missing some cases.
sewardj8b635a42004-11-22 19:01:47 +0000515 generic:
sewardj7cf4e6b2008-05-01 20:24:26 +0000516 /* Pass both the old and new SP values to this helper. Also,
517 pass an origin tag, even if it isn't needed. */
sewardj2a99cf62004-11-24 10:44:19 +0000518 old_SP = newIRTemp(bb->tyenv, typeof_SP);
sewardj0b9d74a2006-12-24 02:24:11 +0000519 addStmtToIRSB(
sewardj2a99cf62004-11-24 10:44:19 +0000520 bb,
sewardj0b9d74a2006-12-24 02:24:11 +0000521 IRStmt_WrTmp( old_SP, IRExpr_Get(offset_SP, typeof_SP) )
sewardj2a99cf62004-11-24 10:44:19 +0000522 );
sewardjde4a1d02002-03-22 01:27:54 +0000523
sewardj2831b512007-11-11 18:56:39 +0000524 /* Now we know what the old value of SP is. But knowing the new
525 value is a bit tricky if there is a partial write. */
526 if (first_Put == first_SP && last_Put == last_SP) {
527 /* The common case, an exact write to SP. So st->Ist.Put.data
528 does hold the new value; simple. */
sewardj7cf4e6b2008-05-01 20:24:26 +0000529 vg_assert(curr_IP_known);
sewardj2831b512007-11-11 18:56:39 +0000530 dcall = unsafeIRDirty_0_N(
sewardj7cf4e6b2008-05-01 20:24:26 +0000531 3/*regparms*/,
sewardj2831b512007-11-11 18:56:39 +0000532 "VG_(unknown_SP_update)",
533 VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
sewardj7cf4e6b2008-05-01 20:24:26 +0000534 mkIRExprVec_3( IRExpr_RdTmp(old_SP), st->Ist.Put.data,
535 mk_ecu_Expr(curr_IP) )
sewardj2831b512007-11-11 18:56:39 +0000536 );
537 addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
538 /* don't forget the original assignment */
539 addStmtToIRSB( bb, st );
540 } else {
541 /* We have a partial update to SP. We need to know what
542 the new SP will be, and hand that to the helper call,
543 but when the helper call happens, SP must hold the
544 value it had before the update. Tricky.
545 Therefore use the following kludge:
546 1. do the partial SP update (Put)
547 2. Get the new SP value into a tmp, new_SP
548 3. Put old_SP
549 4. Call the helper
550 5. Put new_SP
551 */
552 IRTemp new_SP;
553 /* 1 */
554 addStmtToIRSB( bb, st );
555 /* 2 */
556 new_SP = newIRTemp(bb->tyenv, typeof_SP);
557 addStmtToIRSB(
558 bb,
559 IRStmt_WrTmp( new_SP, IRExpr_Get(offset_SP, typeof_SP) )
560 );
561 /* 3 */
562 addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(old_SP) ));
563 /* 4 */
sewardj7cf4e6b2008-05-01 20:24:26 +0000564 vg_assert(curr_IP_known);
sewardj2831b512007-11-11 18:56:39 +0000565 dcall = unsafeIRDirty_0_N(
sewardj7cf4e6b2008-05-01 20:24:26 +0000566 3/*regparms*/,
sewardj2831b512007-11-11 18:56:39 +0000567 "VG_(unknown_SP_update)",
568 VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
sewardj7cf4e6b2008-05-01 20:24:26 +0000569 mkIRExprVec_3( IRExpr_RdTmp(old_SP),
570 IRExpr_RdTmp(new_SP),
571 mk_ecu_Expr(curr_IP) )
sewardj2831b512007-11-11 18:56:39 +0000572 );
573 addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
574 /* 5 */
575 addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(new_SP) ));
576 }
sewardj2a99cf62004-11-24 10:44:19 +0000577
sewardj2831b512007-11-11 18:56:39 +0000578 /* Forget what we already know. */
njn5096a392005-12-13 20:05:00 +0000579 clear_SP_aliases();
sewardj2831b512007-11-11 18:56:39 +0000580
581 /* If this is a Put of a tmp that exactly updates SP,
582 start tracking aliases against this tmp. */
583
584 if (first_Put == first_SP && last_Put == last_SP
585 && st->Ist.Put.data->tag == Iex_RdTmp) {
586 vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.Put.data->Iex.RdTmp.tmp)
587 == typeof_SP );
588 add_SP_alias(st->Ist.Put.data->Iex.RdTmp.tmp, 0);
589 }
sewardj8b635a42004-11-22 19:01:47 +0000590 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000591 }
592
sewardj8b635a42004-11-22 19:01:47 +0000593 case5:
594 /* PutI or Dirty call which overlaps SP: complain. We can't
595 deal with SP changing in weird ways (well, we can, but not at
596 this time of night). */
597 if (st->tag == Ist_PutI) {
floriand39b0222012-05-31 15:48:13 +0000598 descr = st->Ist.PutI.details->descr;
sewardj8b635a42004-11-22 19:01:47 +0000599 minoff_ST = descr->base;
sewardj2831b512007-11-11 18:56:39 +0000600 maxoff_ST = descr->base
601 + descr->nElems * sizeofIRType(descr->elemTy) - 1;
602 if (!(offset_SP > maxoff_ST
603 || (offset_SP + sizeof_SP - 1) < minoff_ST))
sewardj8b635a42004-11-22 19:01:47 +0000604 goto complain;
sewardjde4a1d02002-03-22 01:27:54 +0000605 }
sewardj8b635a42004-11-22 19:01:47 +0000606 if (st->tag == Ist_Dirty) {
607 d = st->Ist.Dirty.details;
608 for (j = 0; j < d->nFxState; j++) {
sewardj8b635a42004-11-22 19:01:47 +0000609 if (d->fxState[j].fx == Ifx_Read || d->fxState[j].fx == Ifx_None)
610 continue;
sewardj2eecb742012-06-01 16:11:41 +0000611 /* Enumerate the described state segments */
612 for (k = 0; k < 1 + d->fxState[j].nRepeats; k++) {
613 minoff_ST = d->fxState[j].offset + k * d->fxState[j].repeatLen;
614 maxoff_ST = minoff_ST + d->fxState[j].size - 1;
615 if (!(offset_SP > maxoff_ST
616 || (offset_SP + sizeof_SP - 1) < minoff_ST))
617 goto complain;
618 }
sewardj8b635a42004-11-22 19:01:47 +0000619 }
620 }
sewardjde4a1d02002-03-22 01:27:54 +0000621
sewardj8b635a42004-11-22 19:01:47 +0000622 /* well, not interesting. Just copy and keep going. */
sewardj0b9d74a2006-12-24 02:24:11 +0000623 addStmtToIRSB( bb, st );
sewardjde4a1d02002-03-22 01:27:54 +0000624
sewardj0b9d74a2006-12-24 02:24:11 +0000625 } /* for (i = 0; i < sb_in->stmts_used; i++) */
sewardjde4a1d02002-03-22 01:27:54 +0000626
sewardj8b635a42004-11-22 19:01:47 +0000627 return bb;
sewardjde4a1d02002-03-22 01:27:54 +0000628
sewardj8b635a42004-11-22 19:01:47 +0000629 complain:
630 VG_(core_panic)("vg_SP_update_pass: PutI or Dirty which overlaps SP");
sewardjde4a1d02002-03-22 01:27:54 +0000631
sewardj7cf4e6b2008-05-01 20:24:26 +0000632#undef IS_ADD
633#undef IS_SUB
634#undef IS_ADD_OR_SUB
635#undef GET_CONST
636#undef DO_NEW
637#undef DO_DIE
sewardjde4a1d02002-03-22 01:27:54 +0000638}
sewardj7c4b6042003-06-14 15:47:15 +0000639
sewardjde4a1d02002-03-22 01:27:54 +0000640/*------------------------------------------------------------*/
641/*--- Main entry point for the JITter. ---*/
642/*------------------------------------------------------------*/
643
sewardjd2b70dc2005-10-14 17:22:31 +0000644/* Extra comments re self-checking translations and self-modifying
645 code. (JRS 14 Oct 05).
646
647 There are 3 modes:
648 (1) no checking: all code assumed to be not self-modifying
649 (2) partial: known-problematic situations get a self-check
650 (3) full checking: all translations get a self-check
651
652 As currently implemented, the default is (2). (3) is always safe,
653 but very slow. (1) works mostly, but fails for gcc nested-function
654 code which uses trampolines on the stack; this situation is
655 detected and handled by (2).
656
657 ----------
658
659 A more robust and transparent solution, which is not currently
660 implemented, is a variant of (2): if a translation is made from an
661 area which aspacem says does not have 'w' permission, then it can
662 be non-self-checking. Otherwise, it needs a self-check.
663
664 This is complicated by Vex's basic-block chasing. If a self-check
665 is requested, then Vex will not chase over basic block boundaries
666 (it's too complex). However there is still a problem if it chases
667 from a non-'w' area into a 'w' area.
668
669 I think the right thing to do is:
670
671 - if a translation request starts in a 'w' area, ask for a
672 self-checking translation, and do not allow any chasing (make
673 chase_into_ok return False). Note that the latter is redundant
674 in the sense that Vex won't chase anyway in this situation.
675
676 - if a translation request starts in a non-'w' area, do not ask for
677 a self-checking translation. However, do not allow chasing (as
678 determined by chase_into_ok) to go into a 'w' area.
679
680 The result of this is that all code inside 'w' areas is self
681 checking.
682
683 To complete the trick, there is a caveat: we must watch the
684 client's mprotect calls. If pages are changed from non-'w' to 'w'
685 then we should throw away all translations which intersect the
686 affected area, so as to force them to be redone with self-checks.
687
688 ----------
689
690 The above outlines the conditions under which bb chasing is allowed
691 from a self-modifying-code point of view. There are other
692 situations pertaining to function redirection in which it is
693 necessary to disallow chasing, but those fall outside the scope of
694 this comment.
695*/
696
sewardj34593e52006-01-17 01:57:33 +0000697
sewardj8b635a42004-11-22 19:01:47 +0000698/* Vex dumps the final code in here. Then we can copy it off
699 wherever we like. */
sewardj4a0009c2006-10-17 01:52:05 +0000700/* 60000: should agree with assertion in VG_(add_to_transtab) in
701 m_transtab.c. */
702#define N_TMPBUF 60000
sewardj8b635a42004-11-22 19:01:47 +0000703static UChar tmpbuf[N_TMPBUF];
704
sewardj34593e52006-01-17 01:57:33 +0000705
sewardj8b635a42004-11-22 19:01:47 +0000706/* Function pointers we must supply to LibVEX in order that it
707 can bomb out and emit messages under Valgrind's control. */
708__attribute__ ((noreturn))
709static
710void failure_exit ( void )
711{
sewardjbf426512005-01-17 18:35:30 +0000712 LibVEX_ShowAllocStats();
sewardjc621f762004-11-26 13:49:59 +0000713 VG_(core_panic)("LibVEX called failure_exit().");
sewardj8b635a42004-11-22 19:01:47 +0000714}
715
716static
sewardjb5f6f512005-03-10 23:59:00 +0000717void log_bytes ( HChar* bytes, Int nbytes )
sewardj8b635a42004-11-22 19:01:47 +0000718{
719 Int i;
720 for (i = 0; i < nbytes-3; i += 4)
721 VG_(printf)("%c%c%c%c", bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]);
722 for (; i < nbytes; i++)
723 VG_(printf)("%c", bytes[i]);
724}
725
njn25e49d8e72002-09-23 09:36:25 +0000726
sewardj34593e52006-01-17 01:57:33 +0000727/* --------- Various helper functions for translation --------- */
sewardj8b635a42004-11-22 19:01:47 +0000728
sewardj45f4e7c2005-09-27 19:20:21 +0000729/* Look for reasons to disallow making translations from the given
730 segment. */
731
sewardj4a0009c2006-10-17 01:52:05 +0000732static Bool translations_allowable_from_seg ( NSegment const* seg )
sewardj45f4e7c2005-09-27 19:20:21 +0000733{
sewardj5db15402012-06-07 09:13:21 +0000734# if defined(VGA_x86) || defined(VGA_s390x) || defined(VGA_mips32)
sewardj45f4e7c2005-09-27 19:20:21 +0000735 Bool allowR = True;
736# else
737 Bool allowR = False;
738# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000739 return seg != NULL
tom1da86fe2009-10-12 13:53:12 +0000740 && (seg->kind == SkAnonC || seg->kind == SkFileC || seg->kind == SkShmC)
sewardj45f4e7c2005-09-27 19:20:21 +0000741 && (seg->hasX || (seg->hasR && allowR));
742}
743
744
sewardj6dbcc632011-06-07 21:39:28 +0000745/* Produce a bitmask stating which of the supplied extents needs a
746 self-check. See documentation of
747 VexTranslateArgs::needs_self_check for more details about the
748 return convention. */
sewardj45f4e7c2005-09-27 19:20:21 +0000749
sewardj6dbcc632011-06-07 21:39:28 +0000750static UInt needs_self_check ( void* closureV,
751 VexGuestExtents* vge )
sewardj34593e52006-01-17 01:57:33 +0000752{
sewardj6dbcc632011-06-07 21:39:28 +0000753 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
754 UInt i, bitset;
755
756 vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
757 bitset = 0;
758
759 for (i = 0; i < vge->n_used; i++) {
760 Bool check = False;
761 Addr addr = (Addr)vge->base[i];
762 SizeT len = (SizeT)vge->len[i];
763 NSegment const* segA = NULL;
764
765# if defined(VGO_darwin)
766 // GrP fixme hack - dyld i386 IMPORT gets rewritten.
767 // To really do this correctly, we'd need to flush the
768 // translation cache whenever a segment became +WX.
769 segA = VG_(am_find_nsegment)(addr);
770 if (segA && segA->hasX && segA->hasW)
771 check = True;
772# endif
773
774 if (!check) {
775 switch (VG_(clo_smc_check)) {
776 case Vg_SmcNone:
777 /* never check (except as per Darwin hack above) */
778 break;
779 case Vg_SmcAll:
780 /* always check */
781 check = True;
782 break;
783 case Vg_SmcStack: {
784 /* check if the address is in the same segment as this
785 thread's stack pointer */
786 Addr sp = VG_(get_SP)(closure->tid);
787 if (!segA) {
788 segA = VG_(am_find_nsegment)(addr);
789 }
790 NSegment const* segSP = VG_(am_find_nsegment)(sp);
791 if (segA && segSP && segA == segSP)
792 check = True;
793 break;
794 }
795 case Vg_SmcAllNonFile: {
796 /* check if any part of the extent is not in a
797 file-mapped segment */
798 if (!segA) {
799 segA = VG_(am_find_nsegment)(addr);
800 }
801 if (segA && segA->kind == SkFileC && segA->start <= addr
802 && (len == 0 || addr + len <= segA->end + 1)) {
803 /* in a file-mapped segment; skip the check */
804 } else {
805 check = True;
806 }
807 break;
808 }
809 default:
810 vg_assert(0);
811 }
812 }
813
814 if (check)
815 bitset |= (1 << i);
njnf76d27a2009-05-28 01:53:07 +0000816 }
sewardj6dbcc632011-06-07 21:39:28 +0000817
818 return bitset;
sewardj34593e52006-01-17 01:57:33 +0000819}
820
821
822/* This is a callback passed to LibVEX_Translate. It stops Vex from
823 chasing into function entry points that we wish to redirect.
824 Chasing across them obviously defeats the redirect mechanism, with
sewardj6dbcc632011-06-07 21:39:28 +0000825 bad effects for Memcheck, Helgrind, DRD, Massif, and possibly others.
sewardj447f2a12005-07-07 13:52:53 +0000826*/
sewardj34593e52006-01-17 01:57:33 +0000827static Bool chase_into_ok ( void* closureV, Addr64 addr64 )
sewardj8b635a42004-11-22 19:01:47 +0000828{
sewardj34593e52006-01-17 01:57:33 +0000829 Addr addr = (Addr)addr64;
sewardj4a0009c2006-10-17 01:52:05 +0000830 NSegment const* seg = VG_(am_find_nsegment)(addr);
sewardj45f4e7c2005-09-27 19:20:21 +0000831
sewardj447f2a12005-07-07 13:52:53 +0000832 /* Work through a list of possibilities why we might not want to
833 allow a chase. */
sewardj447f2a12005-07-07 13:52:53 +0000834
sewardj34593e52006-01-17 01:57:33 +0000835 /* Destination not in a plausible segment? */
sewardj45f4e7c2005-09-27 19:20:21 +0000836 if (!translations_allowable_from_seg(seg))
837 goto dontchase;
838
sewardj447f2a12005-07-07 13:52:53 +0000839 /* Destination is redirected? */
sewardj0ec07f32006-01-12 12:32:32 +0000840 if (addr != VG_(redir_do_lookup)(addr, NULL))
sewardj447f2a12005-07-07 13:52:53 +0000841 goto dontchase;
842
sewardj4a0009c2006-10-17 01:52:05 +0000843# if defined(VG_PLAT_USES_PPCTOC)
844 /* This needs to be at the start of its own block. Don't chase. Re
845 ULong_to_Ptr, be careful to ensure we only compare 32 bits on a
846 32-bit target.*/
847 if (ULong_to_Ptr(addr64)
848 == (void*)&VG_(ppctoc_magic_redirect_return_stub))
sewardj34593e52006-01-17 01:57:33 +0000849 goto dontchase;
850# endif
851
sewardj5f76de02007-02-11 05:08:06 +0000852 /* overly conservative, but .. don't chase into the distinguished
853 address that m_transtab uses as an empty-slot marker for
854 VG_(tt_fast). */
855 if (addr == TRANSTAB_BOGUS_GUEST_ADDR)
856 goto dontchase;
857
floriancabcace2011-07-16 02:09:36 +0000858# if defined(VGA_s390x)
859 /* Never chase into an EX instruction. Generating IR for EX causes
860 a round-trip through the scheduler including VG_(discard_translations).
861 And that's expensive as shown by perf/tinycc.c:
862 Chasing into EX increases the number of EX translations from 21 to
863 102666 causing a 7x runtime increase for "none" and a 3.2x runtime
864 increase for memcheck. */
865 if (((UChar *)ULong_to_Ptr(addr))[0] == 0x44 || /* EX */
866 ((UChar *)ULong_to_Ptr(addr))[0] == 0xC6) /* EXRL */
867 goto dontchase;
868# endif
869
sewardj447f2a12005-07-07 13:52:53 +0000870 /* well, ok then. go on and chase. */
871 return True;
872
873 vg_assert(0);
874 /*NOTREACHED*/
875
876 dontchase:
njn8a7b41b2007-09-23 00:51:24 +0000877 if (0) VG_(printf)("not chasing into 0x%lx\n", addr);
sewardj447f2a12005-07-07 13:52:53 +0000878 return False;
sewardj8b635a42004-11-22 19:01:47 +0000879}
880
sewardj447f2a12005-07-07 13:52:53 +0000881
sewardj4a0009c2006-10-17 01:52:05 +0000882/* --------------- helpers for with-TOC platforms --------------- */
883
sewardj6e9de462011-06-28 07:25:29 +0000884/* NOTE: with-TOC platforms are: ppc64-linux. */
sewardjdfbaa222006-01-18 04:25:20 +0000885
sewardjd68ac3e2006-01-20 14:31:57 +0000886static IRExpr* mkU64 ( ULong n ) {
sewardj34593e52006-01-17 01:57:33 +0000887 return IRExpr_Const(IRConst_U64(n));
888}
sewardjd68ac3e2006-01-20 14:31:57 +0000889static IRExpr* mkU32 ( UInt n ) {
890 return IRExpr_Const(IRConst_U32(n));
891}
sewardj4a0009c2006-10-17 01:52:05 +0000892
893#if defined(VG_PLAT_USES_PPCTOC)
sewardjd68ac3e2006-01-20 14:31:57 +0000894static IRExpr* mkU8 ( UChar n ) {
895 return IRExpr_Const(IRConst_U8(n));
896}
sewardj4a0009c2006-10-17 01:52:05 +0000897static IRExpr* narrowTo32 ( IRTypeEnv* tyenv, IRExpr* e ) {
898 if (typeOfIRExpr(tyenv, e) == Ity_I32) {
899 return e;
900 } else {
901 vg_assert(typeOfIRExpr(tyenv, e) == Ity_I64);
902 return IRExpr_Unop(Iop_64to32, e);
903 }
904}
905
906/* Generate code to push word-typed expression 'e' onto this thread's
907 redir stack, checking for stack overflow and generating code to
908 bomb out if so. */
sewardj34593e52006-01-17 01:57:33 +0000909
sewardj0b9d74a2006-12-24 02:24:11 +0000910static void gen_PUSH ( IRSB* bb, IRExpr* e )
sewardj34593e52006-01-17 01:57:33 +0000911{
sewardj0b9d74a2006-12-24 02:24:11 +0000912 IRRegArray* descr;
913 IRTemp t1;
914 IRExpr* one;
sewardj34593e52006-01-17 01:57:33 +0000915
sewardj6e9de462011-06-28 07:25:29 +0000916# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +0000917 Int stack_size = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
918 Int offB_REDIR_SP = offsetof(VexGuestPPC64State,guest_REDIR_SP);
919 Int offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +0000920 Int offB_EMNOTE = offsetof(VexGuestPPC64State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +0000921 Int offB_CIA = offsetof(VexGuestPPC64State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +0000922 Bool is64 = True;
923 IRType ty_Word = Ity_I64;
924 IROp op_CmpNE = Iop_CmpNE64;
925 IROp op_Sar = Iop_Sar64;
926 IROp op_Sub = Iop_Sub64;
927 IROp op_Add = Iop_Add64;
928 IRExpr*(*mkU)(ULong) = mkU64;
929 vg_assert(VG_WORDSIZE == 8);
930# else
931 Int stack_size = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
932 Int offB_REDIR_SP = offsetof(VexGuestPPC32State,guest_REDIR_SP);
933 Int offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +0000934 Int offB_EMNOTE = offsetof(VexGuestPPC32State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +0000935 Int offB_CIA = offsetof(VexGuestPPC32State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +0000936 Bool is64 = False;
937 IRType ty_Word = Ity_I32;
938 IROp op_CmpNE = Iop_CmpNE32;
939 IROp op_Sar = Iop_Sar32;
940 IROp op_Sub = Iop_Sub32;
941 IROp op_Add = Iop_Add32;
942 IRExpr*(*mkU)(UInt) = mkU32;
943 vg_assert(VG_WORDSIZE == 4);
944# endif
945
946 vg_assert(sizeof(void*) == VG_WORDSIZE);
947 vg_assert(sizeof(Word) == VG_WORDSIZE);
948 vg_assert(sizeof(Addr) == VG_WORDSIZE);
949
sewardj0b9d74a2006-12-24 02:24:11 +0000950 descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
sewardj4a0009c2006-10-17 01:52:05 +0000951 t1 = newIRTemp( bb->tyenv, ty_Word );
952 one = mkU(1);
953
954 vg_assert(typeOfIRExpr(bb->tyenv, e) == ty_Word);
sewardj34593e52006-01-17 01:57:33 +0000955
956 /* t1 = guest_REDIR_SP + 1 */
sewardj0b9d74a2006-12-24 02:24:11 +0000957 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +0000958 bb,
sewardj0b9d74a2006-12-24 02:24:11 +0000959 IRStmt_WrTmp(
sewardj34593e52006-01-17 01:57:33 +0000960 t1,
sewardj4a0009c2006-10-17 01:52:05 +0000961 IRExpr_Binop(op_Add, IRExpr_Get( offB_REDIR_SP, ty_Word ), one)
sewardj34593e52006-01-17 01:57:33 +0000962 )
963 );
964
sewardjd68ac3e2006-01-20 14:31:57 +0000965 /* Bomb out if t1 >=s stack_size, that is, (stack_size-1)-t1 <s 0.
966 The destination (0) is a bit bogus but it doesn't matter since
967 this is an unrecoverable error and will lead to Valgrind
florian2e497412012-08-26 03:22:09 +0000968 shutting down. _EMNOTE is set regardless - that's harmless
sewardjd68ac3e2006-01-20 14:31:57 +0000969 since is only has a meaning if the exit is taken. */
sewardj0b9d74a2006-12-24 02:24:11 +0000970 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +0000971 bb,
florian2e497412012-08-26 03:22:09 +0000972 IRStmt_Put(offB_EMNOTE, mkU32(EmWarn_PPC64_redir_overflow))
sewardjd68ac3e2006-01-20 14:31:57 +0000973 );
sewardj0b9d74a2006-12-24 02:24:11 +0000974 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +0000975 bb,
976 IRStmt_Exit(
977 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +0000978 op_CmpNE,
sewardjd68ac3e2006-01-20 14:31:57 +0000979 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +0000980 op_Sar,
sewardj0b9d74a2006-12-24 02:24:11 +0000981 IRExpr_Binop(op_Sub,mkU(stack_size-1),IRExpr_RdTmp(t1)),
sewardj4a0009c2006-10-17 01:52:05 +0000982 mkU8(8 * VG_WORDSIZE - 1)
sewardjd68ac3e2006-01-20 14:31:57 +0000983 ),
sewardj4a0009c2006-10-17 01:52:05 +0000984 mkU(0)
sewardjd68ac3e2006-01-20 14:31:57 +0000985 ),
986 Ijk_EmFail,
sewardj291849f2012-04-20 23:58:55 +0000987 is64 ? IRConst_U64(0) : IRConst_U32(0),
988 offB_CIA
sewardjd68ac3e2006-01-20 14:31:57 +0000989 )
990 );
sewardj34593e52006-01-17 01:57:33 +0000991
992 /* guest_REDIR_SP = t1 */
sewardj0b9d74a2006-12-24 02:24:11 +0000993 addStmtToIRSB(bb, IRStmt_Put(offB_REDIR_SP, IRExpr_RdTmp(t1)));
sewardj34593e52006-01-17 01:57:33 +0000994
995 /* guest_REDIR_STACK[t1+0] = e */
sewardj4a0009c2006-10-17 01:52:05 +0000996 /* PutI/GetI have I32-typed indexes regardless of guest word size */
sewardj0b9d74a2006-12-24 02:24:11 +0000997 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +0000998 bb,
floriand39b0222012-05-31 15:48:13 +0000999 IRStmt_PutI(mkIRPutI(descr,
1000 narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0, e)));
sewardj34593e52006-01-17 01:57:33 +00001001}
1002
sewardj4a0009c2006-10-17 01:52:05 +00001003
1004/* Generate code to pop a word-sized value from this thread's redir
1005 stack, binding it to a new temporary, which is returned. As with
1006 gen_PUSH, an overflow check is also performed. */
1007
sewardj0b9d74a2006-12-24 02:24:11 +00001008static IRTemp gen_POP ( IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001009{
sewardj6e9de462011-06-28 07:25:29 +00001010# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +00001011 Int stack_size = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
1012 Int offB_REDIR_SP = offsetof(VexGuestPPC64State,guest_REDIR_SP);
1013 Int offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +00001014 Int offB_EMNOTE = offsetof(VexGuestPPC64State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +00001015 Int offB_CIA = offsetof(VexGuestPPC64State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +00001016 Bool is64 = True;
1017 IRType ty_Word = Ity_I64;
1018 IROp op_CmpNE = Iop_CmpNE64;
1019 IROp op_Sar = Iop_Sar64;
1020 IROp op_Sub = Iop_Sub64;
1021 IRExpr*(*mkU)(ULong) = mkU64;
1022# else
1023 Int stack_size = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
1024 Int offB_REDIR_SP = offsetof(VexGuestPPC32State,guest_REDIR_SP);
1025 Int offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
florian2e497412012-08-26 03:22:09 +00001026 Int offB_EMNOTE = offsetof(VexGuestPPC32State,guest_EMNOTE);
sewardj291849f2012-04-20 23:58:55 +00001027 Int offB_CIA = offsetof(VexGuestPPC32State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +00001028 Bool is64 = False;
1029 IRType ty_Word = Ity_I32;
1030 IROp op_CmpNE = Iop_CmpNE32;
1031 IROp op_Sar = Iop_Sar32;
1032 IROp op_Sub = Iop_Sub32;
1033 IRExpr*(*mkU)(UInt) = mkU32;
1034# endif
sewardj34593e52006-01-17 01:57:33 +00001035
sewardj0b9d74a2006-12-24 02:24:11 +00001036 IRRegArray* descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
1037 IRTemp t1 = newIRTemp( bb->tyenv, ty_Word );
1038 IRTemp res = newIRTemp( bb->tyenv, ty_Word );
1039 IRExpr* one = mkU(1);
sewardj4a0009c2006-10-17 01:52:05 +00001040
1041 vg_assert(sizeof(void*) == VG_WORDSIZE);
1042 vg_assert(sizeof(Word) == VG_WORDSIZE);
1043 vg_assert(sizeof(Addr) == VG_WORDSIZE);
sewardj34593e52006-01-17 01:57:33 +00001044
1045 /* t1 = guest_REDIR_SP */
sewardj0b9d74a2006-12-24 02:24:11 +00001046 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001047 bb,
sewardj0b9d74a2006-12-24 02:24:11 +00001048 IRStmt_WrTmp( t1, IRExpr_Get( offB_REDIR_SP, ty_Word ) )
sewardj34593e52006-01-17 01:57:33 +00001049 );
1050
sewardjd68ac3e2006-01-20 14:31:57 +00001051 /* Bomb out if t1 < 0. Same comments as gen_PUSH apply. */
sewardj0b9d74a2006-12-24 02:24:11 +00001052 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +00001053 bb,
florian2e497412012-08-26 03:22:09 +00001054 IRStmt_Put(offB_EMNOTE, mkU32(EmWarn_PPC64_redir_underflow))
sewardjd68ac3e2006-01-20 14:31:57 +00001055 );
sewardj0b9d74a2006-12-24 02:24:11 +00001056 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +00001057 bb,
1058 IRStmt_Exit(
1059 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +00001060 op_CmpNE,
sewardjd68ac3e2006-01-20 14:31:57 +00001061 IRExpr_Binop(
sewardj4a0009c2006-10-17 01:52:05 +00001062 op_Sar,
sewardj0b9d74a2006-12-24 02:24:11 +00001063 IRExpr_RdTmp(t1),
sewardj4a0009c2006-10-17 01:52:05 +00001064 mkU8(8 * VG_WORDSIZE - 1)
sewardjd68ac3e2006-01-20 14:31:57 +00001065 ),
sewardj4a0009c2006-10-17 01:52:05 +00001066 mkU(0)
sewardjd68ac3e2006-01-20 14:31:57 +00001067 ),
1068 Ijk_EmFail,
sewardj291849f2012-04-20 23:58:55 +00001069 is64 ? IRConst_U64(0) : IRConst_U32(0),
1070 offB_CIA
sewardjd68ac3e2006-01-20 14:31:57 +00001071 )
1072 );
sewardj34593e52006-01-17 01:57:33 +00001073
1074 /* res = guest_REDIR_STACK[t1+0] */
sewardj4a0009c2006-10-17 01:52:05 +00001075 /* PutI/GetI have I32-typed indexes regardless of guest word size */
sewardj0b9d74a2006-12-24 02:24:11 +00001076 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001077 bb,
sewardj0b9d74a2006-12-24 02:24:11 +00001078 IRStmt_WrTmp(
sewardj34593e52006-01-17 01:57:33 +00001079 res,
sewardj0b9d74a2006-12-24 02:24:11 +00001080 IRExpr_GetI(descr, narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0)
sewardj34593e52006-01-17 01:57:33 +00001081 )
1082 );
1083
1084 /* guest_REDIR_SP = t1-1 */
sewardj0b9d74a2006-12-24 02:24:11 +00001085 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001086 bb,
sewardj0b9d74a2006-12-24 02:24:11 +00001087 IRStmt_Put(offB_REDIR_SP, IRExpr_Binop(op_Sub, IRExpr_RdTmp(t1), one))
sewardj34593e52006-01-17 01:57:33 +00001088 );
1089
1090 return res;
1091}
1092
sewardj4a0009c2006-10-17 01:52:05 +00001093/* Generate code to push LR and R2 onto this thread's redir stack,
1094 then set R2 to the new value (which is the TOC pointer to be used
1095 for the duration of the replacement function, as determined by
1096 m_debuginfo), and set LR to the magic return stub, so we get to
1097 intercept the return and restore R2 and L2 to the values saved
1098 here. */
1099
sewardj0b9d74a2006-12-24 02:24:11 +00001100static void gen_push_and_set_LR_R2 ( IRSB* bb, Addr64 new_R2_value )
sewardj34593e52006-01-17 01:57:33 +00001101{
sewardj6e9de462011-06-28 07:25:29 +00001102# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +00001103 Addr64 bogus_RA = (Addr64)&VG_(ppctoc_magic_redirect_return_stub);
1104 Int offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1105 Int offB_LR = offsetof(VexGuestPPC64State,guest_LR);
sewardj34593e52006-01-17 01:57:33 +00001106 gen_PUSH( bb, IRExpr_Get(offB_LR, Ity_I64) );
1107 gen_PUSH( bb, IRExpr_Get(offB_GPR2, Ity_I64) );
sewardj0b9d74a2006-12-24 02:24:11 +00001108 addStmtToIRSB( bb, IRStmt_Put( offB_LR, mkU64( bogus_RA )) );
1109 addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, mkU64( new_R2_value )) );
sewardj4a0009c2006-10-17 01:52:05 +00001110
sewardj4a0009c2006-10-17 01:52:05 +00001111# else
1112# error Platform is not TOC-afflicted, fortunately
1113# endif
sewardj34593e52006-01-17 01:57:33 +00001114}
1115
sewardj0b9d74a2006-12-24 02:24:11 +00001116static void gen_pop_R2_LR_then_bLR ( IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001117{
sewardj6e9de462011-06-28 07:25:29 +00001118# if defined(VGP_ppc64_linux)
sewardj4a0009c2006-10-17 01:52:05 +00001119 Int offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1120 Int offB_LR = offsetof(VexGuestPPC64State,guest_LR);
sewardj291849f2012-04-20 23:58:55 +00001121 Int offB_CIA = offsetof(VexGuestPPC64State,guest_CIA);
sewardj4a0009c2006-10-17 01:52:05 +00001122 IRTemp old_R2 = newIRTemp( bb->tyenv, Ity_I64 );
1123 IRTemp old_LR = newIRTemp( bb->tyenv, Ity_I64 );
sewardj34593e52006-01-17 01:57:33 +00001124 /* Restore R2 */
1125 old_R2 = gen_POP( bb );
sewardj0b9d74a2006-12-24 02:24:11 +00001126 addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, IRExpr_RdTmp(old_R2)) );
sewardj34593e52006-01-17 01:57:33 +00001127 /* Restore LR */
1128 old_LR = gen_POP( bb );
sewardj0b9d74a2006-12-24 02:24:11 +00001129 addStmtToIRSB( bb, IRStmt_Put( offB_LR, IRExpr_RdTmp(old_LR)) );
sewardj34593e52006-01-17 01:57:33 +00001130 /* Branch to LR */
1131 /* re boring, we arrived here precisely because a wrapped fn did a
1132 blr (hence Ijk_Ret); so we should just mark this jump as Boring,
sewardj4a0009c2006-10-17 01:52:05 +00001133 else one _Call will have resulted in two _Rets. */
sewardj34593e52006-01-17 01:57:33 +00001134 bb->jumpkind = Ijk_Boring;
sewardj291849f2012-04-20 23:58:55 +00001135 bb->next = IRExpr_Binop(Iop_And64, IRExpr_RdTmp(old_LR), mkU64(~(3ULL)));
1136 bb->offsIP = offB_CIA;
sewardj4a0009c2006-10-17 01:52:05 +00001137# else
1138# error Platform is not TOC-afflicted, fortunately
1139# endif
sewardj34593e52006-01-17 01:57:33 +00001140}
1141
1142static
sewardj0b9d74a2006-12-24 02:24:11 +00001143Bool mk_preamble__ppctoc_magic_return_stub ( void* closureV, IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001144{
sewardj0283bae2006-01-22 01:15:36 +00001145 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
sewardj0b9d74a2006-12-24 02:24:11 +00001146 /* Since we're creating the entire IRSB right here, give it a
sewardj0283bae2006-01-22 01:15:36 +00001147 proper IMark, as it won't get one any other way, and cachegrind
1148 will barf if it doesn't have one (fair enough really). */
sewardj80e88b02011-05-28 15:34:17 +00001149 addStmtToIRSB( bb, IRStmt_IMark( closure->readdr, 4, 0 ) );
sewardj0283bae2006-01-22 01:15:36 +00001150 /* Generate the magic sequence:
1151 pop R2 from hidden stack
1152 pop LR from hidden stack
1153 goto LR
1154 */
sewardj34593e52006-01-17 01:57:33 +00001155 gen_pop_R2_LR_then_bLR(bb);
1156 return True; /* True == this is the entire BB; don't disassemble any
1157 real insns into it - just hand it directly to
1158 optimiser/instrumenter/backend. */
1159}
1160#endif
1161
sewardj4a0009c2006-10-17 01:52:05 +00001162/* --------------- END helpers for with-TOC platforms --------------- */
sewardj34593e52006-01-17 01:57:33 +00001163
sewardj4a0009c2006-10-17 01:52:05 +00001164
1165/* This is the IR preamble generator used for replacement
sewardj0283bae2006-01-22 01:15:36 +00001166 functions. It adds code to set the guest_NRADDR{_GPR2} to zero
sewardj34593e52006-01-17 01:57:33 +00001167 (technically not necessary, but facilitates detecting mixups in
sewardj0283bae2006-01-22 01:15:36 +00001168 which a replacement function has been erroneously declared using
1169 VG_REPLACE_FUNCTION_Z{U,Z} when instead it should have been written
1170 using VG_WRAP_FUNCTION_Z{U,Z}).
sewardj34593e52006-01-17 01:57:33 +00001171
sewardj4a0009c2006-10-17 01:52:05 +00001172 On with-TOC platforms the follow hacks are also done: LR and R2 are
1173 pushed onto a hidden stack, R2 is set to the correct value for the
1174 replacement function, and LR is set to point at the magic
1175 return-stub address. Setting LR causes the return of the
1176 wrapped/redirected function to lead to our magic return stub, which
1177 restores LR and R2 from said stack and returns for real.
sewardjdfbaa222006-01-18 04:25:20 +00001178
sewardjb8b79ad2008-03-03 01:35:41 +00001179 VG_(get_StackTrace_wrk) understands that the LR value may point to
1180 the return stub address, and that in that case it can get the real
1181 LR value from the hidden stack instead. */
sewardj34593e52006-01-17 01:57:33 +00001182static
sewardj0b9d74a2006-12-24 02:24:11 +00001183Bool mk_preamble__set_NRADDR_to_zero ( void* closureV, IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001184{
sewardj34593e52006-01-17 01:57:33 +00001185 Int nraddr_szB
1186 = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1187 vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
sewardj4a0009c2006-10-17 01:52:05 +00001188 vg_assert(nraddr_szB == VG_WORDSIZE);
sewardj0b9d74a2006-12-24 02:24:11 +00001189 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001190 bb,
1191 IRStmt_Put(
1192 offsetof(VexGuestArchState,guest_NRADDR),
sewardj0283bae2006-01-22 01:15:36 +00001193 nraddr_szB == 8 ? mkU64(0) : mkU32(0)
sewardj34593e52006-01-17 01:57:33 +00001194 )
1195 );
sewardj5db15402012-06-07 09:13:21 +00001196# if defined(VGP_mips32_linux)
1197 // t9 needs to be set to point to the start of the redirected function.
1198 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1199 Int offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
1200 addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
1201# endif
sewardj4a0009c2006-10-17 01:52:05 +00001202# if defined(VG_PLAT_USES_PPCTOC)
sewardj0283bae2006-01-22 01:15:36 +00001203 { VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
sewardj0b9d74a2006-12-24 02:24:11 +00001204 addStmtToIRSB(
sewardj0283bae2006-01-22 01:15:36 +00001205 bb,
1206 IRStmt_Put(
1207 offsetof(VexGuestArchState,guest_NRADDR_GPR2),
sewardj4a0009c2006-10-17 01:52:05 +00001208 VG_WORDSIZE==8 ? mkU64(0) : mkU32(0)
sewardj0283bae2006-01-22 01:15:36 +00001209 )
1210 );
1211 gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1212 }
sewardj34593e52006-01-17 01:57:33 +00001213# endif
1214 return False;
1215}
1216
1217/* Ditto, except set guest_NRADDR to nraddr (the un-redirected guest
1218 address). This is needed for function wrapping - so the wrapper
1219 can read _NRADDR and find the address of the function being
sewardj4a0009c2006-10-17 01:52:05 +00001220 wrapped. On toc-afflicted platforms we must also snarf r2. */
sewardj34593e52006-01-17 01:57:33 +00001221static
sewardj0b9d74a2006-12-24 02:24:11 +00001222Bool mk_preamble__set_NRADDR_to_nraddr ( void* closureV, IRSB* bb )
sewardj34593e52006-01-17 01:57:33 +00001223{
1224 VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1225 Int nraddr_szB
1226 = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1227 vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
sewardj4a0009c2006-10-17 01:52:05 +00001228 vg_assert(nraddr_szB == VG_WORDSIZE);
sewardj0b9d74a2006-12-24 02:24:11 +00001229 addStmtToIRSB(
sewardj34593e52006-01-17 01:57:33 +00001230 bb,
1231 IRStmt_Put(
1232 offsetof(VexGuestArchState,guest_NRADDR),
1233 nraddr_szB == 8
1234 ? IRExpr_Const(IRConst_U64( closure->nraddr ))
1235 : IRExpr_Const(IRConst_U32( (UInt)closure->nraddr ))
1236 )
1237 );
sewardj5db15402012-06-07 09:13:21 +00001238# if defined(VGP_mips32_linux)
1239 // t9 needs to be set to point to the start of the redirected function.
1240 Int offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
1241 addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
1242# endif
sewardj6e9de462011-06-28 07:25:29 +00001243# if defined(VGP_ppc64_linux)
sewardj0b9d74a2006-12-24 02:24:11 +00001244 addStmtToIRSB(
sewardjd68ac3e2006-01-20 14:31:57 +00001245 bb,
1246 IRStmt_Put(
1247 offsetof(VexGuestArchState,guest_NRADDR_GPR2),
1248 IRExpr_Get(offsetof(VexGuestArchState,guest_GPR2),
sewardj4a0009c2006-10-17 01:52:05 +00001249 VG_WORDSIZE==8 ? Ity_I64 : Ity_I32)
sewardjd68ac3e2006-01-20 14:31:57 +00001250 )
1251 );
sewardj34593e52006-01-17 01:57:33 +00001252 gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1253# endif
1254 return False;
1255}
1256
sewardj4a0009c2006-10-17 01:52:05 +00001257/* --- Helpers to do with PPC related stack redzones. --- */
1258
1259__attribute__((unused))
1260static Bool const_True ( Addr64 guest_addr )
1261{
1262 return True;
1263}
1264
sewardj34593e52006-01-17 01:57:33 +00001265/* --------------- main translation function --------------- */
1266
sewardj0ec07f32006-01-12 12:32:32 +00001267/* Note: see comments at top of m_redir.c for the Big Picture on how
1268 redirections are managed. */
1269
sewardj34593e52006-01-17 01:57:33 +00001270typedef
1271 enum {
1272 /* normal translation, redir neither requested nor inhibited */
1273 T_Normal,
1274 /* redir translation, function-wrap (set _NRADDR) style */
1275 T_Redir_Wrap,
1276 /* redir translation, replacement (don't set _NRADDR) style */
1277 T_Redir_Replace,
1278 /* a translation in which redir is specifically disallowed */
1279 T_NoRedir
1280 }
1281 T_Kind;
1282
1283/* Translate the basic block beginning at NRADDR, and add it to the
1284 translation cache & translation table. Unless
1285 DEBUGGING_TRANSLATION is true, in which case the call is being done
1286 for debugging purposes, so (a) throw away the translation once it
1287 is made, and (b) produce a load of debugging output. If
1288 ALLOW_REDIRECTION is False, do not attempt redirection of NRADDR,
1289 and also, put the resulting translation into the no-redirect tt/tc
1290 instead of the normal one.
1291
1292 TID is the identity of the thread requesting this translation.
1293*/
1294
sewardjfa8ec112005-01-19 11:55:34 +00001295Bool VG_(translate) ( ThreadId tid,
sewardj34593e52006-01-17 01:57:33 +00001296 Addr64 nraddr,
sewardjfa8ec112005-01-19 11:55:34 +00001297 Bool debugging_translation,
njn394213a2005-06-19 18:38:24 +00001298 Int debugging_verbosity,
sewardj0ec07f32006-01-12 12:32:32 +00001299 ULong bbs_done,
1300 Bool allow_redirection )
sewardjde4a1d02002-03-22 01:27:54 +00001301{
sewardj34593e52006-01-17 01:57:33 +00001302 Addr64 addr;
1303 T_Kind kind;
sewardje2d1e672005-11-12 23:10:48 +00001304 Int tmpbuf_used, verbosity, i;
sewardj0b9d74a2006-12-24 02:24:11 +00001305 Bool (*preamble_fn)(void*,IRSB*);
sewardje2d1e672005-11-12 23:10:48 +00001306 VexArch vex_arch;
1307 VexArchInfo vex_archinfo;
sewardj0b9d74a2006-12-24 02:24:11 +00001308 VexAbiInfo vex_abiinfo;
sewardje2d1e672005-11-12 23:10:48 +00001309 VexGuestExtents vge;
sewardj274807d2005-12-15 14:07:07 +00001310 VexTranslateArgs vta;
sewardje2d1e672005-11-12 23:10:48 +00001311 VexTranslateResult tres;
sewardj34593e52006-01-17 01:57:33 +00001312 VgCallbackClosure closure;
njn36932cb2005-05-11 22:45:48 +00001313
sewardj8b635a42004-11-22 19:01:47 +00001314 /* Make sure Vex is initialised right. */
sewardje2d1e672005-11-12 23:10:48 +00001315
sewardj8b635a42004-11-22 19:01:47 +00001316 static Bool vex_init_done = False;
1317
1318 if (!vex_init_done) {
1319 LibVEX_Init ( &failure_exit, &log_bytes,
1320 1, /* debug_paranoia */
1321 False, /* valgrind support */
1322 &VG_(clo_vex_control) );
1323 vex_init_done = True;
1324 }
1325
sewardj34593e52006-01-17 01:57:33 +00001326 /* Establish the translation kind and actual guest address to
1327 start from. Sets (addr,kind). */
sewardj0ec07f32006-01-12 12:32:32 +00001328 if (allow_redirection) {
sewardj34593e52006-01-17 01:57:33 +00001329 Bool isWrap;
1330 Addr64 tmp = VG_(redir_do_lookup)( nraddr, &isWrap );
1331 if (tmp == nraddr) {
1332 /* no redirection found */
1333 addr = nraddr;
1334 kind = T_Normal;
1335 } else {
1336 /* found a redirect */
1337 addr = tmp;
1338 kind = isWrap ? T_Redir_Wrap : T_Redir_Replace;
1339 }
sewardj0ec07f32006-01-12 12:32:32 +00001340 } else {
sewardj34593e52006-01-17 01:57:33 +00001341 addr = nraddr;
1342 kind = T_NoRedir;
sewardj0ec07f32006-01-12 12:32:32 +00001343 }
fitzhardinge98abfc72003-12-16 02:05:15 +00001344
sewardj34593e52006-01-17 01:57:33 +00001345 /* Established: (nraddr, addr, kind) */
sewardj0ec07f32006-01-12 12:32:32 +00001346
sewardj34593e52006-01-17 01:57:33 +00001347 /* Printing redirection info. */
1348
1349 if ((kind == T_Redir_Wrap || kind == T_Redir_Replace)
sewardj0ec07f32006-01-12 12:32:32 +00001350 && (VG_(clo_verbosity) >= 2 || VG_(clo_trace_redir))) {
sewardjfa8ec112005-01-19 11:55:34 +00001351 Bool ok;
florian19f91bb2012-11-10 22:29:54 +00001352 HChar name1[512] = "";
1353 HChar name2[512] = "";
sewardjfa8ec112005-01-19 11:55:34 +00001354 name1[0] = name2[0] = 0;
sewardje318d0b2012-02-28 18:02:41 +00001355 ok = VG_(get_fnname_w_offset)(nraddr, name1, 512);
njnbe73f432005-03-26 21:34:45 +00001356 if (!ok) VG_(strcpy)(name1, "???");
sewardje318d0b2012-02-28 18:02:41 +00001357 ok = VG_(get_fnname_w_offset)(addr, name2, 512);
njnbe73f432005-03-26 21:34:45 +00001358 if (!ok) VG_(strcpy)(name2, "???");
njn3f04d242005-03-20 18:21:14 +00001359 VG_(message)(Vg_DebugMsg,
sewardj738856f2009-07-15 14:48:32 +00001360 "REDIR: 0x%llx (%s) redirected to 0x%llx (%s)\n",
sewardj34593e52006-01-17 01:57:33 +00001361 nraddr, name1,
1362 addr, name2 );
nethercote59a122d2004-08-03 17:16:51 +00001363 }
sewardj25c7c3a2003-07-10 00:17:58 +00001364
njn25e49d8e72002-09-23 09:36:25 +00001365 if (!debugging_translation)
sewardj45f4e7c2005-09-27 19:20:21 +00001366 VG_TRACK( pre_mem_read, Vg_CoreTranslate,
sewardj34593e52006-01-17 01:57:33 +00001367 tid, "(translator)", addr, 1 );
sewardjde4a1d02002-03-22 01:27:54 +00001368
sewardj85ac6d42005-02-23 11:36:56 +00001369 /* If doing any code printing, print a basic block start marker */
1370 if (VG_(clo_trace_flags) || debugging_translation) {
florian19f91bb2012-11-10 22:29:54 +00001371 HChar fnname[512] = "UNKNOWN_FUNCTION";
sewardje318d0b2012-02-28 18:02:41 +00001372 VG_(get_fnname_w_offset)(addr, fnname, 512);
florian19f91bb2012-11-10 22:29:54 +00001373 const HChar* objname = "UNKNOWN_OBJECT";
sewardj227fd912011-10-21 04:59:56 +00001374 OffT objoff = 0;
1375 DebugInfo* di = VG_(find_DebugInfo)( addr );
1376 if (di) {
1377 objname = VG_(DebugInfo_get_filename)(di);
1378 objoff = addr - VG_(DebugInfo_get_text_bias)(di);
1379 }
1380 vg_assert(objname);
sewardj85ac6d42005-02-23 11:36:56 +00001381 VG_(printf)(
sewardj291849f2012-04-20 23:58:55 +00001382 "==== SB %d (evchecks %lld) [tid %d] 0x%llx %s %s+0x%llx\n",
sewardj227fd912011-10-21 04:59:56 +00001383 VG_(get_bbs_translated)(), bbs_done, (Int)tid, addr,
1384 fnname, objname, (ULong)objoff
1385 );
sewardj85ac6d42005-02-23 11:36:56 +00001386 }
1387
sewardj45f4e7c2005-09-27 19:20:21 +00001388 /* Are we allowed to translate here? */
1389
sewardj4a0009c2006-10-17 01:52:05 +00001390 { /* BEGIN new scope specially for 'seg' */
1391 NSegment const* seg = VG_(am_find_nsegment)(addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001392
sewardj5f76de02007-02-11 05:08:06 +00001393 if ( (!translations_allowable_from_seg(seg))
1394 || addr == TRANSTAB_BOGUS_GUEST_ADDR ) {
sewardj4a0009c2006-10-17 01:52:05 +00001395 if (VG_(clo_trace_signals))
sewardja5940262007-09-10 16:28:38 +00001396 VG_(message)(Vg_DebugMsg, "translations not allowed here (0x%llx)"
sewardj738856f2009-07-15 14:48:32 +00001397 " - throwing SEGV\n", addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001398 /* U R busted, sonny. Place your hands on your head and step
1399 away from the orig_addr. */
fitzhardinge98abfc72003-12-16 02:05:15 +00001400 /* Code address is bad - deliver a signal instead */
sewardj45f4e7c2005-09-27 19:20:21 +00001401 if (seg != NULL) {
1402 /* There's some kind of segment at the requested place, but we
1403 aren't allowed to execute code here. */
sewardj3b290482011-05-06 21:02:55 +00001404 if (debugging_translation)
1405 VG_(printf)("translations not allowed here (segment not executable)"
1406 "(0x%llx)\n", addr);
1407 else
1408 VG_(synth_fault_perms)(tid, addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001409 } else {
1410 /* There is no segment at all; we are attempting to execute in
1411 the middle of nowhere. */
sewardj3b290482011-05-06 21:02:55 +00001412 if (debugging_translation)
1413 VG_(printf)("translations not allowed here (no segment)"
1414 "(0x%llx)\n", addr);
1415 else
1416 VG_(synth_fault_mapping)(tid, addr);
sewardj45f4e7c2005-09-27 19:20:21 +00001417 }
nethercote4d714382004-10-13 09:47:24 +00001418 return False;
sewardj45f4e7c2005-09-27 19:20:21 +00001419 }
sewardjde4a1d02002-03-22 01:27:54 +00001420
njn25e49d8e72002-09-23 09:36:25 +00001421 /* True if a debug trans., or if bit N set in VG_(clo_trace_codegen). */
sewardjc771b292004-11-30 18:55:21 +00001422 verbosity = 0;
sewardj167d4e32004-12-31 01:14:04 +00001423 if (debugging_translation) {
sewardjfa8ec112005-01-19 11:55:34 +00001424 verbosity = debugging_verbosity;
sewardj167d4e32004-12-31 01:14:04 +00001425 }
1426 else
sewardjfa8ec112005-01-19 11:55:34 +00001427 if ( (VG_(clo_trace_flags) > 0
florian29e022d2012-07-02 21:13:34 +00001428 && VG_(get_bbs_translated)() <= VG_(clo_trace_notabove)
sewardj167d4e32004-12-31 01:14:04 +00001429 && VG_(get_bbs_translated)() >= VG_(clo_trace_notbelow) )) {
sewardjfa8ec112005-01-19 11:55:34 +00001430 verbosity = VG_(clo_trace_flags);
sewardj167d4e32004-12-31 01:14:04 +00001431 }
njn25e49d8e72002-09-23 09:36:25 +00001432
sewardj34593e52006-01-17 01:57:33 +00001433 /* Figure out which preamble-mangling callback to send. */
1434 preamble_fn = NULL;
1435 if (kind == T_Redir_Replace)
1436 preamble_fn = mk_preamble__set_NRADDR_to_zero;
1437 else
1438 if (kind == T_Redir_Wrap)
1439 preamble_fn = mk_preamble__set_NRADDR_to_nraddr;
sewardj4a0009c2006-10-17 01:52:05 +00001440
1441# if defined(VG_PLAT_USES_PPCTOC)
1442 if (ULong_to_Ptr(nraddr)
1443 == (void*)&VG_(ppctoc_magic_redirect_return_stub)) {
sewardj34593e52006-01-17 01:57:33 +00001444 /* If entering the special return stub, this means a wrapped or
1445 redirected function is returning. Make this translation one
1446 which restores R2 and LR from the thread's hidden redir
1447 stack, and branch to the (restored) link register, thereby
1448 really causing the function to return. */
1449 vg_assert(kind == T_Normal);
1450 vg_assert(nraddr == addr);
sewardj4a0009c2006-10-17 01:52:05 +00001451 preamble_fn = mk_preamble__ppctoc_magic_return_stub;
1452 }
sewardj34593e52006-01-17 01:57:33 +00001453# endif
1454
sewardje2d1e672005-11-12 23:10:48 +00001455 /* ------ Actually do the translation. ------ */
njn51d827b2005-05-09 01:02:08 +00001456 tl_assert2(VG_(tdict).tool_instrument,
1457 "you forgot to set VgToolInterface function 'tool_instrument'");
sewardj7be55092005-08-01 23:25:55 +00001458
sewardje2d1e672005-11-12 23:10:48 +00001459 /* Get the CPU info established at startup. */
1460 VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
1461
sewardj0b9d74a2006-12-24 02:24:11 +00001462 /* Set up 'abiinfo' structure with stuff Vex needs to know about
sewardj4a0009c2006-10-17 01:52:05 +00001463 the guest and host ABIs. */
1464
sewardj0b9d74a2006-12-24 02:24:11 +00001465 LibVEX_default_VexAbiInfo( &vex_abiinfo );
1466 vex_abiinfo.guest_stack_redzone_size = VG_STACK_REDZONE_SZB;
sewardj4a0009c2006-10-17 01:52:05 +00001467
sewardjc0b20392008-12-04 00:07:30 +00001468# if defined(VGP_amd64_linux)
1469 vex_abiinfo.guest_amd64_assume_fs_is_zero = True;
1470# endif
njnf76d27a2009-05-28 01:53:07 +00001471# if defined(VGP_amd64_darwin)
1472 vex_abiinfo.guest_amd64_assume_gs_is_0x60 = True;
1473# endif
sewardj4a0009c2006-10-17 01:52:05 +00001474# if defined(VGP_ppc32_linux)
sewardj0b9d74a2006-12-24 02:24:11 +00001475 vex_abiinfo.guest_ppc_zap_RZ_at_blr = False;
1476 vex_abiinfo.guest_ppc_zap_RZ_at_bl = NULL;
1477 vex_abiinfo.host_ppc32_regalign_int64_args = True;
sewardj4a0009c2006-10-17 01:52:05 +00001478# endif
1479# if defined(VGP_ppc64_linux)
sewardj0b9d74a2006-12-24 02:24:11 +00001480 vex_abiinfo.guest_ppc_zap_RZ_at_blr = True;
1481 vex_abiinfo.guest_ppc_zap_RZ_at_bl = const_True;
1482 vex_abiinfo.host_ppc_calls_use_fndescrs = True;
sewardj4a0009c2006-10-17 01:52:05 +00001483# endif
sewardj4a0009c2006-10-17 01:52:05 +00001484
sewardj34593e52006-01-17 01:57:33 +00001485 /* Set up closure args. */
1486 closure.tid = tid;
1487 closure.nraddr = nraddr;
1488 closure.readdr = addr;
sewardj7be55092005-08-01 23:25:55 +00001489
sewardj0ec07f32006-01-12 12:32:32 +00001490 /* Set up args for LibVEX_Translate. */
sewardj274807d2005-12-15 14:07:07 +00001491 vta.arch_guest = vex_arch;
1492 vta.archinfo_guest = vex_archinfo;
1493 vta.arch_host = vex_arch;
1494 vta.archinfo_host = vex_archinfo;
sewardj0b9d74a2006-12-24 02:24:11 +00001495 vta.abiinfo_both = vex_abiinfo;
sewardj291849f2012-04-20 23:58:55 +00001496 vta.callback_opaque = (void*)&closure;
sewardj34593e52006-01-17 01:57:33 +00001497 vta.guest_bytes = (UChar*)ULong_to_Ptr(addr);
1498 vta.guest_bytes_addr = (Addr64)addr;
sewardj274807d2005-12-15 14:07:07 +00001499 vta.chase_into_ok = chase_into_ok;
1500 vta.guest_extents = &vge;
1501 vta.host_bytes = tmpbuf;
1502 vta.host_bytes_size = N_TMPBUF;
1503 vta.host_bytes_used = &tmpbuf_used;
sewardj34593e52006-01-17 01:57:33 +00001504 { /* At this point we have to reconcile Vex's view of the
1505 instrumentation callback - which takes a void* first argument
1506 - with Valgrind's view, in which the first arg is a
1507 VgCallbackClosure*. Hence the following longwinded casts.
1508 They are entirely legal but longwinded so as to maximise the
1509 chance of the C typechecker picking up any type snafus. */
sewardj0b9d74a2006-12-24 02:24:11 +00001510 IRSB*(*f)(VgCallbackClosure*,
florianca503be2012-10-07 21:59:42 +00001511 IRSB*,VexGuestLayout*,VexGuestExtents*, VexArchInfo*,
sewardj34593e52006-01-17 01:57:33 +00001512 IRType,IRType)
sewardj3b290482011-05-06 21:02:55 +00001513 = VG_(clo_vgdb) != Vg_VgdbNo
1514 ? tool_instrument_then_gdbserver_if_needed
1515 : VG_(tdict).tool_instrument;
sewardj0b9d74a2006-12-24 02:24:11 +00001516 IRSB*(*g)(void*,
florianca503be2012-10-07 21:59:42 +00001517 IRSB*,VexGuestLayout*,VexGuestExtents*,VexArchInfo*,
sewardj34593e52006-01-17 01:57:33 +00001518 IRType,IRType)
florianca503be2012-10-07 21:59:42 +00001519 = (IRSB*(*)(void*,IRSB*,VexGuestLayout*,VexGuestExtents*,
1520 VexArchInfo*,IRType,IRType))f;
sewardj291849f2012-04-20 23:58:55 +00001521 vta.instrument1 = g;
sewardj34593e52006-01-17 01:57:33 +00001522 }
1523 /* No need for type kludgery here. */
sewardj291849f2012-04-20 23:58:55 +00001524 vta.instrument2 = need_to_handle_SP_assignment()
1525 ? vg_SP_update_pass
1526 : NULL;
1527 vta.finaltidy = VG_(needs).final_IR_tidy_pass
1528 ? VG_(tdict).tool_final_IR_tidy_pass
1529 : NULL;
1530 vta.needs_self_check = needs_self_check;
1531 vta.preamble_function = preamble_fn;
1532 vta.traceflags = verbosity;
sewardjc30cd9b2012-12-06 18:08:54 +00001533 vta.sigill_diag = VG_(clo_sigill_diag);
sewardj291849f2012-04-20 23:58:55 +00001534 vta.addProfInc = VG_(clo_profile_flags) > 0
1535 && kind != T_NoRedir;
sewardj274807d2005-12-15 14:07:07 +00001536
sewardj291849f2012-04-20 23:58:55 +00001537 /* Set up the dispatch continuation-point info. If this is a
1538 no-redir translation then it cannot be chained, and the chain-me
1539 points are set to NULL to indicate that. The indir point must
1540 also be NULL, since we can't allow this translation to do an
1541 indir transfer -- that would take it back into the main
1542 translation cache too.
sewardj0ec07f32006-01-12 12:32:32 +00001543
sewardj291849f2012-04-20 23:58:55 +00001544 All this is because no-redir translations live outside the main
1545 translation cache (in a secondary one) and chaining them would
1546 involve more adminstrative complexity that isn't worth the
1547 hassle, because we don't expect them to get used often. So
1548 don't bother. */
1549 if (allow_redirection) {
1550 vta.disp_cp_chain_me_to_slowEP
1551 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_slowEP) );
1552 vta.disp_cp_chain_me_to_fastEP
1553 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_fastEP) );
1554 vta.disp_cp_xindir
1555 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xindir) );
1556 } else {
1557 vta.disp_cp_chain_me_to_slowEP = NULL;
1558 vta.disp_cp_chain_me_to_fastEP = NULL;
1559 vta.disp_cp_xindir = NULL;
sewardj12740272011-05-29 09:34:30 +00001560 }
sewardj291849f2012-04-20 23:58:55 +00001561 /* This doesn't involve chaining and so is always allowable. */
1562 vta.disp_cp_xassisted
1563 = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xassisted) );
sewardj274807d2005-12-15 14:07:07 +00001564
1565 /* Sheesh. Finally, actually _do_ the translation! */
1566 tres = LibVEX_Translate ( &vta );
njn25e49d8e72002-09-23 09:36:25 +00001567
sewardj6dbcc632011-06-07 21:39:28 +00001568 vg_assert(tres.status == VexTransOK);
1569 vg_assert(tres.n_sc_extents >= 0 && tres.n_sc_extents <= 3);
sewardj8b635a42004-11-22 19:01:47 +00001570 vg_assert(tmpbuf_used <= N_TMPBUF);
1571 vg_assert(tmpbuf_used > 0);
sewardjde4a1d02002-03-22 01:27:54 +00001572
sewardj45f4e7c2005-09-27 19:20:21 +00001573 /* Tell aspacem of all segments that have had translations taken
1574 from them. Optimisation: don't re-look up vge.base[0] since seg
1575 should already point to it. */
1576
sewardj34593e52006-01-17 01:57:33 +00001577 vg_assert( vge.base[0] == (Addr64)addr );
sewardj4a0009c2006-10-17 01:52:05 +00001578 /* set 'translations taken from this segment' flag */
florian3e798632012-11-24 19:41:54 +00001579 VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( seg );
sewardj4a0009c2006-10-17 01:52:05 +00001580 } /* END new scope specially for 'seg' */
sewardj45f4e7c2005-09-27 19:20:21 +00001581
1582 for (i = 1; i < vge.n_used; i++) {
sewardj4a0009c2006-10-17 01:52:05 +00001583 NSegment const* seg
1584 = VG_(am_find_nsegment)( vge.base[i] );
1585 /* set 'translations taken from this segment' flag */
florian3e798632012-11-24 19:41:54 +00001586 VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( seg );
sewardj45f4e7c2005-09-27 19:20:21 +00001587 }
1588
nethercote59a122d2004-08-03 17:16:51 +00001589 /* Copy data at trans_addr into the translation cache. */
sewardj8b635a42004-11-22 19:01:47 +00001590 vg_assert(tmpbuf_used > 0 && tmpbuf_used < 65536);
nethercote59a122d2004-08-03 17:16:51 +00001591
1592 // If debugging, don't do anything with the translated block; we
1593 // only did this for the debugging output produced along the way.
1594 if (!debugging_translation) {
sewardj0ec07f32006-01-12 12:32:32 +00001595
sewardj34593e52006-01-17 01:57:33 +00001596 if (kind != T_NoRedir) {
sewardj0ec07f32006-01-12 12:32:32 +00001597 // Put it into the normal TT/TC structures. This is the
1598 // normal case.
1599
sewardj34593e52006-01-17 01:57:33 +00001600 // Note that we use nraddr (the non-redirected address), not
1601 // addr, which might have been changed by the redirection
sewardj0ec07f32006-01-12 12:32:32 +00001602 VG_(add_to_transtab)( &vge,
sewardj34593e52006-01-17 01:57:33 +00001603 nraddr,
sewardj0ec07f32006-01-12 12:32:32 +00001604 (Addr)(&tmpbuf[0]),
1605 tmpbuf_used,
sewardj291849f2012-04-20 23:58:55 +00001606 tres.n_sc_extents > 0,
1607 tres.offs_profInc,
sewardjb7301c62012-04-24 11:50:49 +00001608 tres.n_guest_instrs,
sewardj291849f2012-04-20 23:58:55 +00001609 vex_arch );
sewardj0ec07f32006-01-12 12:32:32 +00001610 } else {
sewardj291849f2012-04-20 23:58:55 +00001611 vg_assert(tres.offs_profInc == -1); /* -1 == unset */
sewardj0ec07f32006-01-12 12:32:32 +00001612 VG_(add_to_unredir_transtab)( &vge,
sewardj34593e52006-01-17 01:57:33 +00001613 nraddr,
sewardj0ec07f32006-01-12 12:32:32 +00001614 (Addr)(&tmpbuf[0]),
njn1dcee092009-02-24 03:07:37 +00001615 tmpbuf_used );
sewardj0ec07f32006-01-12 12:32:32 +00001616 }
sewardjde4a1d02002-03-22 01:27:54 +00001617 }
nethercote59a122d2004-08-03 17:16:51 +00001618
nethercote4d714382004-10-13 09:47:24 +00001619 return True;
sewardjde4a1d02002-03-22 01:27:54 +00001620}
1621
1622/*--------------------------------------------------------------------*/
njn3cbfbc12005-05-13 23:11:40 +00001623/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00001624/*--------------------------------------------------------------------*/