blob: 219bb7e58e68a01e30eda179e118aaa276356361 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- The JITter proper: register allocation & code improvement ---*/
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
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2000-2005 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"
sewardj55f9d1a2005-04-25 11:11:44 +000033#include "pub_core_aspacemgr.h"
sewardje2d1e672005-11-12 23:10:48 +000034
sewardj274807d2005-12-15 14:07:07 +000035#include "pub_core_machine.h" // For VG_(machine_get_VexArchInfo)
36 // and VG_(get_SP)
njn97405b22005-06-02 03:39:33 +000037#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000038#include "pub_core_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000039#include "pub_core_libcprint.h"
njn20242342005-05-16 23:31:24 +000040#include "pub_core_options.h"
njn31513b42005-06-01 03:09:59 +000041#include "pub_core_profile.h"
sewardj45f4e7c2005-09-27 19:20:21 +000042
sewardj274807d2005-12-15 14:07:07 +000043#include "pub_core_debuginfo.h" // Needed for pub_core_redir :(
44#include "pub_core_redir.h" // For VG_(code_redirect)()
sewardj45f4e7c2005-09-27 19:20:21 +000045
sewardj274807d2005-12-15 14:07:07 +000046#include "pub_core_signals.h" // For VG_(synth_fault_{perms,mapping})()
47#include "pub_core_stacks.h" // For VG_(unknown_SP_update)()
48#include "pub_core_tooliface.h" // For VG_(tdict)
njn8bddf582005-05-13 23:40:55 +000049#include "pub_core_translate.h"
50#include "pub_core_transtab.h"
sewardj274807d2005-12-15 14:07:07 +000051#include "pub_core_dispatch.h" // VG_(run_innerloop__dispatch_{un}profiled)
52
sewardjde4a1d02002-03-22 01:27:54 +000053
njna1f783f2005-06-18 03:44:34 +000054/*------------------------------------------------------------*/
njn42c83552005-12-05 20:45:59 +000055/*--- Stats ---*/
56/*------------------------------------------------------------*/
57
58static UInt n_SP_updates_fast = 0;
59static UInt n_SP_updates_generic_known = 0;
60static UInt n_SP_updates_generic_unknown = 0;
61
62void VG_(print_translation_stats) ( void )
63{
64 Char buf[6];
65 UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known
66 + n_SP_updates_generic_unknown;
67 VG_(percentify)(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
68 VG_(message)(Vg_DebugMsg,
69 "translate: fast SP updates identified: %,u (%s)",
70 n_SP_updates_fast, buf );
71
72 VG_(percentify)(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
73 VG_(message)(Vg_DebugMsg,
74 "translate: generic_known SP updates identified: %,u (%s)",
75 n_SP_updates_generic_known, buf );
76
77 VG_(percentify)(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf);
78 VG_(message)(Vg_DebugMsg,
79 "translate: generic_unknown SP updates identified: %,u (%s)",
80 n_SP_updates_generic_unknown, buf );
81}
82
83/*------------------------------------------------------------*/
sewardj8b635a42004-11-22 19:01:47 +000084/*--- %SP-update pass ---*/
nethercotebee3fd92004-08-02 15:17:43 +000085/*------------------------------------------------------------*/
86
njna1f783f2005-06-18 03:44:34 +000087static Bool need_to_handle_SP_assignment(void)
88{
89 return ( VG_(tdict).track_new_mem_stack_4 ||
90 VG_(tdict).track_die_mem_stack_4 ||
91 VG_(tdict).track_new_mem_stack_8 ||
92 VG_(tdict).track_die_mem_stack_8 ||
93 VG_(tdict).track_new_mem_stack_12 ||
94 VG_(tdict).track_die_mem_stack_12 ||
95 VG_(tdict).track_new_mem_stack_16 ||
96 VG_(tdict).track_die_mem_stack_16 ||
97 VG_(tdict).track_new_mem_stack_32 ||
98 VG_(tdict).track_die_mem_stack_32 ||
99 VG_(tdict).track_new_mem_stack ||
100 VG_(tdict).track_die_mem_stack );
101}
102
njn5096a392005-12-13 20:05:00 +0000103// - The SP aliases are held in an array which is used as a circular buffer.
104// This misses very few constant updates of SP (ie. < 0.1%) while using a
105// small, constant structure that will also never fill up and cause
106// execution to abort.
107// - Unused slots have a .temp value of 'IRTemp_INVALID'.
108// - 'next_SP_alias_slot' is the index where the next alias will be stored.
109// - If the buffer fills, we circle around and start over-writing
110// non-IRTemp_INVALID values. This is rare, and the overwriting of a
111// value that would have subsequently be used is even rarer.
112// - Every slot below next_SP_alias_slot holds a non-IRTemp_INVALID value.
113// The rest either all won't (if we haven't yet circled around) or all
114// will (if we have circled around).
njn9b007f62003-04-07 14:40:25 +0000115
njn5096a392005-12-13 20:05:00 +0000116typedef
117 struct {
118 IRTemp temp;
119 Long delta;
120 }
121 SP_Alias;
122
123// With 32 slots the buffer fills very rarely -- eg. once in a run of GCC.
124// And I've tested with smaller values and the wrap-around case works ok.
125#define N_ALIASES 32
126static SP_Alias SP_aliases[N_ALIASES];
127static Int next_SP_alias_slot = 0;
128
129static void clear_SP_aliases(void)
130{
131 Int i;
132 for (i = 0; i < N_ALIASES; i++) {
133 SP_aliases[i].temp = IRTemp_INVALID;
134 SP_aliases[i].delta = 0;
135 }
136 next_SP_alias_slot = 0;
137}
138
139static void add_SP_alias(IRTemp temp, Long delta)
140{
141 vg_assert(temp != IRTemp_INVALID);
142 SP_aliases[ next_SP_alias_slot ].temp = temp;
143 SP_aliases[ next_SP_alias_slot ].delta = delta;
144 next_SP_alias_slot++;
145 if (N_ALIASES == next_SP_alias_slot) next_SP_alias_slot = 0;
146}
147
148static Bool get_SP_delta(IRTemp temp, ULong* delta)
149{
150 Int i; // i must be signed!
151 vg_assert(IRTemp_INVALID != temp);
152 // Search backwards between current buffer position and the start.
153 for (i = next_SP_alias_slot-1; i >= 0; i--) {
154 if (temp == SP_aliases[i].temp) {
155 *delta = SP_aliases[i].delta;
156 return True;
157 }
158 }
159 // Search backwards between the end and the current buffer position.
160 for (i = N_ALIASES-1; i >= next_SP_alias_slot; i--) {
161 if (temp == SP_aliases[i].temp) {
162 *delta = SP_aliases[i].delta;
163 return True;
164 }
165 }
166 return False;
167}
168
169static void update_SP_aliases(Long delta)
170{
171 Int i;
172 for (i = 0; i < N_ALIASES; i++) {
173 if (SP_aliases[i].temp == IRTemp_INVALID) {
174 return;
175 }
176 SP_aliases[i].delta += delta;
177 }
178}
179
180
181/* For tools that want to know about SP changes, this pass adds
nethercote996901a2004-08-03 13:29:09 +0000182 in the appropriate hooks. We have to do it after the tool's
njn5096a392005-12-13 20:05:00 +0000183 instrumentation, so the tool doesn't have to worry about the C calls
njn9b007f62003-04-07 14:40:25 +0000184 it adds in, and we must do it before register allocation because
njn5096a392005-12-13 20:05:00 +0000185 spilled temps make it much harder to work out the SP deltas.
186 This it is done with Vex's "second instrumentation" pass.
sewardjde4a1d02002-03-22 01:27:54 +0000187
njn5096a392005-12-13 20:05:00 +0000188 Basically, we look for GET(SP)/PUT(SP) pairs and track constant
189 increments/decrements of SP between them. (This requires tracking one or
190 more "aliases", which are not exact aliases but instead are tempregs
191 whose value is equal to the SP's plus or minus a known constant.)
192 If all the changes to SP leading up to a PUT(SP) are by known, small
193 constants, we can do a specific call to eg. new_mem_stack_4, otherwise
194 we fall back to the case that handles an unknown SP change.
195*/
sewardjde4a1d02002-03-22 01:27:54 +0000196static
sewardj4ba057c2005-10-18 12:04:18 +0000197IRBB* vg_SP_update_pass ( IRBB* bb_in,
198 VexGuestLayout* layout,
199 Addr64 orig_addr_noredir,
200 VexGuestExtents* vge,
201 IRType gWordTy,
202 IRType hWordTy )
sewardjde4a1d02002-03-22 01:27:54 +0000203{
sewardj7cf97ee2004-11-28 14:25:01 +0000204 Int i, j, minoff_ST, maxoff_ST, sizeof_SP, offset_SP;
sewardj8b635a42004-11-22 19:01:47 +0000205 IRDirty *dcall, *d;
206 IRStmt* st;
207 IRExpr* e;
208 IRArray* descr;
sewardj7cf97ee2004-11-28 14:25:01 +0000209 IRType typeof_SP;
njn5096a392005-12-13 20:05:00 +0000210 Long delta, con;
sewardjde4a1d02002-03-22 01:27:54 +0000211
sewardj8b635a42004-11-22 19:01:47 +0000212 /* Set up BB */
213 IRBB* bb = emptyIRBB();
214 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
215 bb->next = dopyIRExpr(bb_in->next);
216 bb->jumpkind = bb_in->jumpkind;
sewardjde4a1d02002-03-22 01:27:54 +0000217
sewardj7cf97ee2004-11-28 14:25:01 +0000218 delta = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000219
sewardj7cf97ee2004-11-28 14:25:01 +0000220 sizeof_SP = layout->sizeof_SP;
221 offset_SP = layout->offset_SP;
222 typeof_SP = sizeof_SP==4 ? Ity_I32 : Ity_I64;
sewardj8b635a42004-11-22 19:01:47 +0000223 vg_assert(sizeof_SP == 4 || sizeof_SP == 8);
sewardjde4a1d02002-03-22 01:27:54 +0000224
sewardj8b635a42004-11-22 19:01:47 +0000225# define IS_ADD(op) (sizeof_SP==4 ? ((op)==Iop_Add32) : ((op)==Iop_Add64))
226# define IS_SUB(op) (sizeof_SP==4 ? ((op)==Iop_Sub32) : ((op)==Iop_Sub64))
sewardjde4a1d02002-03-22 01:27:54 +0000227
sewardj8b635a42004-11-22 19:01:47 +0000228# define IS_ADD_OR_SUB(op) (IS_ADD(op) || IS_SUB(op))
sewardjde4a1d02002-03-22 01:27:54 +0000229
sewardj8b635a42004-11-22 19:01:47 +0000230# define GET_CONST(con) \
231 (sizeof_SP==4 ? (Long)(Int)(con->Ico.U32) \
232 : (Long)(con->Ico.U64))
sewardjde4a1d02002-03-22 01:27:54 +0000233
njn5096a392005-12-13 20:05:00 +0000234// XXX: convert this to a function
235# define DO(kind, syze, tmpp) \
sewardj8b635a42004-11-22 19:01:47 +0000236 do { \
njn5096a392005-12-13 20:05:00 +0000237 if (!VG_(tdict).track_##kind##_mem_stack_##syze) \
sewardj8b635a42004-11-22 19:01:47 +0000238 goto generic; \
239 \
240 /* I don't know if it's really necessary to say that the */ \
241 /* call reads the stack pointer. But anyway, we do. */ \
242 dcall = unsafeIRDirty_0_N( \
243 1/*regparms*/, \
244 "track_" #kind "_mem_stack_" #syze, \
njncf81d552005-03-31 04:52:26 +0000245 VG_(tdict).track_##kind##_mem_stack_##syze, \
njn5096a392005-12-13 20:05:00 +0000246 mkIRExprVec_1(IRExpr_Tmp(tmpp)) \
sewardj8b635a42004-11-22 19:01:47 +0000247 ); \
248 dcall->nFxState = 1; \
249 dcall->fxState[0].fx = Ifx_Read; \
250 dcall->fxState[0].offset = layout->offset_SP; \
251 dcall->fxState[0].size = layout->sizeof_SP; \
252 \
253 addStmtToIRBB( bb, IRStmt_Dirty(dcall) ); \
njn42c83552005-12-05 20:45:59 +0000254 \
njn5096a392005-12-13 20:05:00 +0000255 update_SP_aliases(-delta); \
256 \
njn42c83552005-12-05 20:45:59 +0000257 n_SP_updates_fast++; \
258 \
sewardj8b635a42004-11-22 19:01:47 +0000259 } while (0)
sewardjde4a1d02002-03-22 01:27:54 +0000260
njn5096a392005-12-13 20:05:00 +0000261 clear_SP_aliases();
262
sewardj8b635a42004-11-22 19:01:47 +0000263 for (i = 0; i < bb_in->stmts_used; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000264
sewardj8b635a42004-11-22 19:01:47 +0000265 st = bb_in->stmts[i];
sewardjde4a1d02002-03-22 01:27:54 +0000266
sewardj8b635a42004-11-22 19:01:47 +0000267 /* t = Get(sp): curr = t, delta = 0 */
268 if (st->tag != Ist_Tmp) goto case2;
269 e = st->Ist.Tmp.data;
270 if (e->tag != Iex_Get) goto case2;
271 if (e->Iex.Get.offset != offset_SP) goto case2;
272 if (e->Iex.Get.ty != typeof_SP) goto case2;
njn5096a392005-12-13 20:05:00 +0000273 add_SP_alias(st->Ist.Tmp.tmp, 0);
sewardj8b635a42004-11-22 19:01:47 +0000274 addStmtToIRBB( bb, st );
275 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000276
sewardj8b635a42004-11-22 19:01:47 +0000277 case2:
278 /* t' = curr +/- const: curr = t', delta +=/-= const */
279 if (st->tag != Ist_Tmp) goto case3;
280 e = st->Ist.Tmp.data;
281 if (e->tag != Iex_Binop) goto case3;
282 if (e->Iex.Binop.arg1->tag != Iex_Tmp) goto case3;
njn5096a392005-12-13 20:05:00 +0000283 if (!get_SP_delta(e->Iex.Binop.arg1->Iex.Tmp.tmp, &delta)) goto case3;
sewardj8b635a42004-11-22 19:01:47 +0000284 if (e->Iex.Binop.arg2->tag != Iex_Const) goto case3;
285 if (!IS_ADD_OR_SUB(e->Iex.Binop.op)) goto case3;
njn5096a392005-12-13 20:05:00 +0000286 con = GET_CONST(e->Iex.Binop.arg2->Iex.Const.con);
287 if (IS_ADD(e->Iex.Binop.op)) {
288 add_SP_alias(st->Ist.Tmp.tmp, delta + con);
289 } else {
290 add_SP_alias(st->Ist.Tmp.tmp, delta - con);
291 }
sewardj8b635a42004-11-22 19:01:47 +0000292 addStmtToIRBB( bb, st );
293 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000294
sewardj8b635a42004-11-22 19:01:47 +0000295 case3:
296 /* t' = curr: curr = t' */
297 if (st->tag != Ist_Tmp) goto case4;
298 e = st->Ist.Tmp.data;
299 if (e->tag != Iex_Tmp) goto case4;
njn5096a392005-12-13 20:05:00 +0000300 if (!get_SP_delta(e->Iex.Tmp.tmp, &delta)) goto case4;
301 add_SP_alias(st->Ist.Tmp.tmp, delta);
sewardj8b635a42004-11-22 19:01:47 +0000302 addStmtToIRBB( bb, st );
303 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000304
sewardj8b635a42004-11-22 19:01:47 +0000305 case4:
306 /* Put(sp) = curr */
307 if (st->tag != Ist_Put) goto case5;
308 if (st->Ist.Put.offset != offset_SP) goto case5;
309 if (st->Ist.Put.data->tag != Iex_Tmp) goto case5;
njn5096a392005-12-13 20:05:00 +0000310 if (get_SP_delta(st->Ist.Put.data->Iex.Tmp.tmp, &delta)) {
311 IRTemp tttmp = st->Ist.Put.data->Iex.Tmp.tmp;
sewardj8b635a42004-11-22 19:01:47 +0000312 switch (delta) {
njn5096a392005-12-13 20:05:00 +0000313 case 0: addStmtToIRBB(bb,st); continue;
314 case 4: DO(die, 4, tttmp); addStmtToIRBB(bb,st); continue;
315 case -4: DO(new, 4, tttmp); addStmtToIRBB(bb,st); continue;
316 case 8: DO(die, 8, tttmp); addStmtToIRBB(bb,st); continue;
317 case -8: DO(new, 8, tttmp); addStmtToIRBB(bb,st); continue;
318 case 12: DO(die, 12, tttmp); addStmtToIRBB(bb,st); continue;
319 case -12: DO(new, 12, tttmp); addStmtToIRBB(bb,st); continue;
320 case 16: DO(die, 16, tttmp); addStmtToIRBB(bb,st); continue;
321 case -16: DO(new, 16, tttmp); addStmtToIRBB(bb,st); continue;
322 case 32: DO(die, 32, tttmp); addStmtToIRBB(bb,st); continue;
323 case -32: DO(new, 32, tttmp); addStmtToIRBB(bb,st); continue;
njn42c83552005-12-05 20:45:59 +0000324 default:
325 n_SP_updates_generic_known++;
326 goto generic;
sewardjde4a1d02002-03-22 01:27:54 +0000327 }
sewardj8b635a42004-11-22 19:01:47 +0000328 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000329 IRTemp old_SP;
njn42c83552005-12-05 20:45:59 +0000330 n_SP_updates_generic_unknown++;
331
njn5096a392005-12-13 20:05:00 +0000332 // Nb: if all is well, this generic case will typically be
333 // called something like every 1000th SP update. If it's more than
334 // that, the above code may be missing some cases.
sewardj8b635a42004-11-22 19:01:47 +0000335 generic:
sewardj2a99cf62004-11-24 10:44:19 +0000336 /* Pass both the old and new SP values to this helper. */
337 old_SP = newIRTemp(bb->tyenv, typeof_SP);
338 addStmtToIRBB(
339 bb,
340 IRStmt_Tmp( old_SP, IRExpr_Get(offset_SP, typeof_SP) )
341 );
sewardjde4a1d02002-03-22 01:27:54 +0000342
sewardj2a99cf62004-11-24 10:44:19 +0000343 dcall = unsafeIRDirty_0_N(
344 2/*regparms*/,
345 "VG_(unknown_SP_update)", &VG_(unknown_SP_update),
346 mkIRExprVec_2( IRExpr_Tmp(old_SP), st->Ist.Put.data )
347 );
sewardj8b635a42004-11-22 19:01:47 +0000348 addStmtToIRBB( bb, IRStmt_Dirty(dcall) );
sewardj2a99cf62004-11-24 10:44:19 +0000349
350 addStmtToIRBB( bb, st );
sewardjde4a1d02002-03-22 01:27:54 +0000351
njn5096a392005-12-13 20:05:00 +0000352 clear_SP_aliases();
353 add_SP_alias(st->Ist.Put.data->Iex.Tmp.tmp, 0);
sewardj8b635a42004-11-22 19:01:47 +0000354 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000355 }
356
sewardj8b635a42004-11-22 19:01:47 +0000357 case5:
358 /* PutI or Dirty call which overlaps SP: complain. We can't
359 deal with SP changing in weird ways (well, we can, but not at
360 this time of night). */
361 if (st->tag == Ist_PutI) {
362 descr = st->Ist.PutI.descr;
363 minoff_ST = descr->base;
364 maxoff_ST = descr->base + descr->nElems * sizeofIRType(descr->elemTy) - 1;
365 if (!(offset_SP > maxoff_ST || (offset_SP + sizeof_SP - 1) < minoff_ST))
366 goto complain;
sewardjde4a1d02002-03-22 01:27:54 +0000367 }
sewardj8b635a42004-11-22 19:01:47 +0000368 if (st->tag == Ist_Dirty) {
369 d = st->Ist.Dirty.details;
370 for (j = 0; j < d->nFxState; j++) {
371 minoff_ST = d->fxState[j].offset;
372 maxoff_ST = d->fxState[j].offset + d->fxState[j].size - 1;
373 if (d->fxState[j].fx == Ifx_Read || d->fxState[j].fx == Ifx_None)
374 continue;
375 if (!(offset_SP > maxoff_ST || (offset_SP + sizeof_SP - 1) < minoff_ST))
376 goto complain;
377 }
378 }
sewardjde4a1d02002-03-22 01:27:54 +0000379
sewardj8b635a42004-11-22 19:01:47 +0000380 /* well, not interesting. Just copy and keep going. */
381 addStmtToIRBB( bb, st );
sewardjde4a1d02002-03-22 01:27:54 +0000382
sewardj8b635a42004-11-22 19:01:47 +0000383 } /* for (i = 0; i < bb_in->stmts_used; i++) */
sewardjde4a1d02002-03-22 01:27:54 +0000384
sewardj8b635a42004-11-22 19:01:47 +0000385 return bb;
sewardjde4a1d02002-03-22 01:27:54 +0000386
sewardj8b635a42004-11-22 19:01:47 +0000387 complain:
388 VG_(core_panic)("vg_SP_update_pass: PutI or Dirty which overlaps SP");
sewardjde4a1d02002-03-22 01:27:54 +0000389
390}
sewardj7c4b6042003-06-14 15:47:15 +0000391
sewardjde4a1d02002-03-22 01:27:54 +0000392/*------------------------------------------------------------*/
393/*--- Main entry point for the JITter. ---*/
394/*------------------------------------------------------------*/
395
sewardjd2b70dc2005-10-14 17:22:31 +0000396/* Extra comments re self-checking translations and self-modifying
397 code. (JRS 14 Oct 05).
398
399 There are 3 modes:
400 (1) no checking: all code assumed to be not self-modifying
401 (2) partial: known-problematic situations get a self-check
402 (3) full checking: all translations get a self-check
403
404 As currently implemented, the default is (2). (3) is always safe,
405 but very slow. (1) works mostly, but fails for gcc nested-function
406 code which uses trampolines on the stack; this situation is
407 detected and handled by (2).
408
409 ----------
410
411 A more robust and transparent solution, which is not currently
412 implemented, is a variant of (2): if a translation is made from an
413 area which aspacem says does not have 'w' permission, then it can
414 be non-self-checking. Otherwise, it needs a self-check.
415
416 This is complicated by Vex's basic-block chasing. If a self-check
417 is requested, then Vex will not chase over basic block boundaries
418 (it's too complex). However there is still a problem if it chases
419 from a non-'w' area into a 'w' area.
420
421 I think the right thing to do is:
422
423 - if a translation request starts in a 'w' area, ask for a
424 self-checking translation, and do not allow any chasing (make
425 chase_into_ok return False). Note that the latter is redundant
426 in the sense that Vex won't chase anyway in this situation.
427
428 - if a translation request starts in a non-'w' area, do not ask for
429 a self-checking translation. However, do not allow chasing (as
430 determined by chase_into_ok) to go into a 'w' area.
431
432 The result of this is that all code inside 'w' areas is self
433 checking.
434
435 To complete the trick, there is a caveat: we must watch the
436 client's mprotect calls. If pages are changed from non-'w' to 'w'
437 then we should throw away all translations which intersect the
438 affected area, so as to force them to be redone with self-checks.
439
440 ----------
441
442 The above outlines the conditions under which bb chasing is allowed
443 from a self-modifying-code point of view. There are other
444 situations pertaining to function redirection in which it is
445 necessary to disallow chasing, but those fall outside the scope of
446 this comment.
447*/
448
sewardj8b635a42004-11-22 19:01:47 +0000449/* Vex dumps the final code in here. Then we can copy it off
450 wherever we like. */
sewardjfb154a52005-03-31 15:48:57 +0000451#define N_TMPBUF 20000
sewardj8b635a42004-11-22 19:01:47 +0000452static UChar tmpbuf[N_TMPBUF];
453
454/* Function pointers we must supply to LibVEX in order that it
455 can bomb out and emit messages under Valgrind's control. */
456__attribute__ ((noreturn))
457static
458void failure_exit ( void )
459{
sewardjbf426512005-01-17 18:35:30 +0000460 LibVEX_ShowAllocStats();
sewardjc621f762004-11-26 13:49:59 +0000461 VG_(core_panic)("LibVEX called failure_exit().");
sewardj8b635a42004-11-22 19:01:47 +0000462}
463
464static
sewardjb5f6f512005-03-10 23:59:00 +0000465void log_bytes ( HChar* bytes, Int nbytes )
sewardj8b635a42004-11-22 19:01:47 +0000466{
467 Int i;
468 for (i = 0; i < nbytes-3; i += 4)
469 VG_(printf)("%c%c%c%c", bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]);
470 for (; i < nbytes; i++)
471 VG_(printf)("%c", bytes[i]);
472}
473
nethercote59a122d2004-08-03 17:16:51 +0000474/* Translate the basic block beginning at orig_addr, and add it to
475 the translation cache & translation table. Unless 'debugging' is true,
476 in which case the call is being done for debugging purposes, so
477 (a) throw away the translation once it is made, and (b) produce a
478 load of debugging output.
njn25e49d8e72002-09-23 09:36:25 +0000479
nethercote59a122d2004-08-03 17:16:51 +0000480 'tid' is the identity of the thread needing this block.
sewardjde4a1d02002-03-22 01:27:54 +0000481*/
sewardj8b635a42004-11-22 19:01:47 +0000482
sewardj45f4e7c2005-09-27 19:20:21 +0000483/* Look for reasons to disallow making translations from the given
484 segment. */
485
486static Bool translations_allowable_from_seg ( NSegment* seg )
487{
488# if defined(VGA_x86)
489 Bool allowR = True;
490# else
491 Bool allowR = False;
492# endif
493
494 return seg != NULL
495 && (seg->kind == SkAnonC || seg->kind == SkFileC)
496 && (seg->hasX || (seg->hasR && allowR));
497}
498
499
500
sewardj8b635a42004-11-22 19:01:47 +0000501/* This stops Vex from chasing into function entry points that we wish
502 to redirect. Chasing across them obviously defeats the redirect
503 mechanism, with bad effects for Memcheck, Addrcheck, and possibly
sewardj447f2a12005-07-07 13:52:53 +0000504 others.
505
506 Also, we must stop Vex chasing into blocks for which we might want
507 to self checking.
sewardj7be55092005-08-01 23:25:55 +0000508
509 This fn needs to know also the tid of the requesting thread, but
510 it can't be passed in as a parameter since this fn is passed to
511 Vex and that has no notion of tids. So we clumsily pass it as
512 a global, chase_into_ok__CLOSURE_tid.
sewardj447f2a12005-07-07 13:52:53 +0000513*/
sewardj7be55092005-08-01 23:25:55 +0000514static ThreadId chase_into_ok__CLOSURE_tid;
515static Bool chase_into_ok ( Addr64 addr64 )
sewardj8b635a42004-11-22 19:01:47 +0000516{
sewardj45f4e7c2005-09-27 19:20:21 +0000517 NSegment* seg;
518
sewardj447f2a12005-07-07 13:52:53 +0000519 /* Work through a list of possibilities why we might not want to
520 allow a chase. */
521 Addr addr = (Addr)addr64;
522
523 /* All chasing disallowed if all bbs require self-checks. */
sewardj6c3a2192005-07-24 07:00:45 +0000524 if (VG_(clo_smc_check) == Vg_SmcAll)
sewardj447f2a12005-07-07 13:52:53 +0000525 goto dontchase;
526
sewardj45f4e7c2005-09-27 19:20:21 +0000527 /* Check the segment permissions. */
528 seg = VG_(am_find_nsegment)(addr);
529 if (!translations_allowable_from_seg(seg))
530 goto dontchase;
531
sewardj447f2a12005-07-07 13:52:53 +0000532 /* AAABBBCCC: if default self-checks are in force, reject if we
533 would choose to have a self-check for the dest. Note, this must
534 match the logic at XXXYYYZZZ below. */
sewardj6c3a2192005-07-24 07:00:45 +0000535 if (VG_(clo_smc_check) == Vg_SmcStack) {
sewardj7be55092005-08-01 23:25:55 +0000536 ThreadId tid = chase_into_ok__CLOSURE_tid;
sewardj45f4e7c2005-09-27 19:20:21 +0000537 if (seg
538 && (seg->kind == SkAnonC || seg->kind == SkFileC)
539 && seg->start <= VG_(get_SP)(tid)
540 && VG_(get_SP)(tid)+sizeof(Word)-1 <= seg->end)
sewardj447f2a12005-07-07 13:52:53 +0000541 goto dontchase;
542 }
543
544 /* Destination is redirected? */
545 if (addr != VG_(code_redirect)(addr))
546 goto dontchase;
547
548 /* well, ok then. go on and chase. */
549 return True;
550
551 vg_assert(0);
552 /*NOTREACHED*/
553
554 dontchase:
555 if (0) VG_(printf)("not chasing into 0x%x\n", addr);
556 return False;
sewardj8b635a42004-11-22 19:01:47 +0000557}
558
sewardj447f2a12005-07-07 13:52:53 +0000559
sewardjfa8ec112005-01-19 11:55:34 +0000560Bool VG_(translate) ( ThreadId tid,
561 Addr64 orig_addr,
562 Bool debugging_translation,
njn394213a2005-06-19 18:38:24 +0000563 Int debugging_verbosity,
564 ULong bbs_done )
sewardjde4a1d02002-03-22 01:27:54 +0000565{
sewardje2d1e672005-11-12 23:10:48 +0000566 Addr64 redir, orig_addr_noredir = orig_addr;
567 Int tmpbuf_used, verbosity, i;
568 Bool notrace_until_done, do_self_check;
569 UInt notrace_until_limit = 0;
570 NSegment* seg;
571 VexArch vex_arch;
572 VexArchInfo vex_archinfo;
573 VexGuestExtents vge;
sewardj274807d2005-12-15 14:07:07 +0000574 VexTranslateArgs vta;
sewardje2d1e672005-11-12 23:10:48 +0000575 VexTranslateResult tres;
njn36932cb2005-05-11 22:45:48 +0000576
sewardj8b635a42004-11-22 19:01:47 +0000577 /* Make sure Vex is initialised right. */
sewardje2d1e672005-11-12 23:10:48 +0000578
sewardj8b635a42004-11-22 19:01:47 +0000579 static Bool vex_init_done = False;
580
581 if (!vex_init_done) {
582 LibVEX_Init ( &failure_exit, &log_bytes,
583 1, /* debug_paranoia */
584 False, /* valgrind support */
585 &VG_(clo_vex_control) );
586 vex_init_done = True;
587 }
588
589 /* profiling ... */
sewardjde4a1d02002-03-22 01:27:54 +0000590 VGP_PUSHCC(VgpTranslate);
nethercote59a122d2004-08-03 17:16:51 +0000591
sewardj25c7c3a2003-07-10 00:17:58 +0000592 /* Look in the code redirect table to see if we should
593 translate an alternative address for orig_addr. */
fitzhardinge98abfc72003-12-16 02:05:15 +0000594 redir = VG_(code_redirect)(orig_addr);
595
nethercote59a122d2004-08-03 17:16:51 +0000596 if (redir != orig_addr && VG_(clo_verbosity) >= 2) {
sewardjfa8ec112005-01-19 11:55:34 +0000597 Bool ok;
sewardj8b635a42004-11-22 19:01:47 +0000598 Char name1[64] = "";
599 Char name2[64] = "";
sewardjfa8ec112005-01-19 11:55:34 +0000600 name1[0] = name2[0] = 0;
601 ok = VG_(get_fnname_w_offset)(orig_addr, name1, 64);
njnbe73f432005-03-26 21:34:45 +0000602 if (!ok) VG_(strcpy)(name1, "???");
sewardjfa8ec112005-01-19 11:55:34 +0000603 ok = VG_(get_fnname_w_offset)(redir, name2, 64);
njnbe73f432005-03-26 21:34:45 +0000604 if (!ok) VG_(strcpy)(name2, "???");
njn3f04d242005-03-20 18:21:14 +0000605 VG_(message)(Vg_DebugMsg,
sewardj71bc3cb2005-05-19 00:25:45 +0000606 "REDIR: 0x%llx (%s) redirected to 0x%llx (%s)",
sewardj8b635a42004-11-22 19:01:47 +0000607 orig_addr, name1,
608 redir, name2 );
nethercote59a122d2004-08-03 17:16:51 +0000609 }
fitzhardinge98abfc72003-12-16 02:05:15 +0000610 orig_addr = redir;
sewardj25c7c3a2003-07-10 00:17:58 +0000611
sewardja60be0e2003-05-26 08:47:27 +0000612 /* If codegen tracing, don't start tracing until
613 notrace_until_limit blocks have gone by. This avoids printing
614 huge amounts of useless junk when all we want to see is the last
615 few blocks translated prior to a failure. Set
616 notrace_until_limit to be the number of translations to be made
617 before --trace-codegen= style printing takes effect. */
sewardjfa8ec112005-01-19 11:55:34 +0000618 notrace_until_done
619 = VG_(get_bbs_translated)() >= notrace_until_limit;
sewardja60be0e2003-05-26 08:47:27 +0000620
njn25e49d8e72002-09-23 09:36:25 +0000621 if (!debugging_translation)
sewardj45f4e7c2005-09-27 19:20:21 +0000622 VG_TRACK( pre_mem_read, Vg_CoreTranslate,
623 tid, "(translator)", orig_addr, 1 );
sewardjde4a1d02002-03-22 01:27:54 +0000624
sewardj85ac6d42005-02-23 11:36:56 +0000625 /* If doing any code printing, print a basic block start marker */
626 if (VG_(clo_trace_flags) || debugging_translation) {
627 Char fnname[64] = "";
628 VG_(get_fnname_w_offset)(orig_addr, fnname, 64);
629 VG_(printf)(
njn394213a2005-06-19 18:38:24 +0000630 "==== BB %d %s(0x%llx) BBs exec'd %lld ====\n",
sewardj85ac6d42005-02-23 11:36:56 +0000631 VG_(get_bbs_translated)(), fnname, orig_addr,
njn394213a2005-06-19 18:38:24 +0000632 bbs_done);
sewardj85ac6d42005-02-23 11:36:56 +0000633 }
634
sewardj45f4e7c2005-09-27 19:20:21 +0000635 /* Are we allowed to translate here? */
636
637 seg = VG_(am_find_nsegment)(orig_addr);
638
639 if (!translations_allowable_from_seg(seg)) {
640 /* U R busted, sonny. Place your hands on your head and step
641 away from the orig_addr. */
fitzhardinge98abfc72003-12-16 02:05:15 +0000642 /* Code address is bad - deliver a signal instead */
sewardj45f4e7c2005-09-27 19:20:21 +0000643 if (seg != NULL) {
644 /* There's some kind of segment at the requested place, but we
645 aren't allowed to execute code here. */
sewardj8b635a42004-11-22 19:01:47 +0000646 VG_(synth_fault_perms)(tid, orig_addr);
sewardj45f4e7c2005-09-27 19:20:21 +0000647 } else {
648 /* There is no segment at all; we are attempting to execute in
649 the middle of nowhere. */
sewardj8b635a42004-11-22 19:01:47 +0000650 VG_(synth_fault_mapping)(tid, orig_addr);
sewardj45f4e7c2005-09-27 19:20:21 +0000651 }
nethercote4d714382004-10-13 09:47:24 +0000652 return False;
sewardj45f4e7c2005-09-27 19:20:21 +0000653 }
sewardjde4a1d02002-03-22 01:27:54 +0000654
sewardj26412bd2005-07-07 10:05:05 +0000655 /* Do we want a self-checking translation? */
656 do_self_check = False;
sewardj6c3a2192005-07-24 07:00:45 +0000657 switch (VG_(clo_smc_check)) {
sewardj26412bd2005-07-07 10:05:05 +0000658 case Vg_SmcNone: do_self_check = False; break;
659 case Vg_SmcAll: do_self_check = True; break;
660 case Vg_SmcStack:
sewardj447f2a12005-07-07 13:52:53 +0000661 /* XXXYYYZZZ: must match the logic at AAABBBCCC above */
sewardj7be55092005-08-01 23:25:55 +0000662 do_self_check
663 /* = seg ? toBool(seg->flags & SF_GROWDOWN) : False; */
664 = seg
sewardj45f4e7c2005-09-27 19:20:21 +0000665 ? (seg->start <= VG_(get_SP)(tid)
666 && VG_(get_SP)(tid)+sizeof(Word)-1 <= seg->end)
sewardj7be55092005-08-01 23:25:55 +0000667 : False;
sewardj26412bd2005-07-07 10:05:05 +0000668 break;
sewardj7be55092005-08-01 23:25:55 +0000669 default:
670 vg_assert2(0, "unknown VG_(clo_smc_check) value");
sewardj26412bd2005-07-07 10:05:05 +0000671 }
672
njn25e49d8e72002-09-23 09:36:25 +0000673 /* True if a debug trans., or if bit N set in VG_(clo_trace_codegen). */
sewardjc771b292004-11-30 18:55:21 +0000674 verbosity = 0;
sewardj167d4e32004-12-31 01:14:04 +0000675 if (debugging_translation) {
sewardjfa8ec112005-01-19 11:55:34 +0000676 verbosity = debugging_verbosity;
sewardj167d4e32004-12-31 01:14:04 +0000677 }
678 else
sewardjfa8ec112005-01-19 11:55:34 +0000679 if ( (VG_(clo_trace_flags) > 0
sewardj167d4e32004-12-31 01:14:04 +0000680 && VG_(get_bbs_translated)() >= VG_(clo_trace_notbelow) )) {
sewardjfa8ec112005-01-19 11:55:34 +0000681 verbosity = VG_(clo_trace_flags);
sewardj167d4e32004-12-31 01:14:04 +0000682 }
njn25e49d8e72002-09-23 09:36:25 +0000683
njn31513b42005-06-01 03:09:59 +0000684 VGP_PUSHCC(VgpVexTime);
685
sewardje2d1e672005-11-12 23:10:48 +0000686 /* ------ Actually do the translation. ------ */
njn51d827b2005-05-09 01:02:08 +0000687 tl_assert2(VG_(tdict).tool_instrument,
688 "you forgot to set VgToolInterface function 'tool_instrument'");
sewardj7be55092005-08-01 23:25:55 +0000689
sewardje2d1e672005-11-12 23:10:48 +0000690 /* Get the CPU info established at startup. */
691 VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
692
sewardj7be55092005-08-01 23:25:55 +0000693 /* Set up closure arg for "chase_into_ok" */
694 chase_into_ok__CLOSURE_tid = tid;
695
sewardj274807d2005-12-15 14:07:07 +0000696 vta.arch_guest = vex_arch;
697 vta.archinfo_guest = vex_archinfo;
698 vta.arch_host = vex_arch;
699 vta.archinfo_host = vex_archinfo;
700 vta.guest_bytes = (UChar*)ULong_to_Ptr(orig_addr);
701 vta.guest_bytes_addr = (Addr64)orig_addr;
702 vta.guest_bytes_addr_noredir = (Addr64)orig_addr_noredir;
703 vta.chase_into_ok = chase_into_ok;
704 vta.guest_extents = &vge;
705 vta.host_bytes = tmpbuf;
706 vta.host_bytes_size = N_TMPBUF;
707 vta.host_bytes_used = &tmpbuf_used;
708 vta.instrument1 = VG_(tdict).tool_instrument;
709 vta.instrument2 = need_to_handle_SP_assignment()
710 ? vg_SP_update_pass
711 : NULL;
712 vta.do_self_check = do_self_check;
713 vta.traceflags = verbosity;
714
715 /* Set up the dispatch-return info. For archs without a link
716 register, vex generates a jump back to the specified dispatch
717 address. Else, it just generates a branch-to-LR. */
718# if defined(VGA_x86) || defined(VGA_amd64)
719 vta.dispatch = VG_(clo_profile_flags) > 0
720 ? (void*) &VG_(run_innerloop__dispatch_profiled)
721 : (void*) &VG_(run_innerloop__dispatch_unprofiled);
722# elif defined(VGA_ppc32) || defined(VGA_ppc64)
723 vta.dispatch = NULL;
724# else
725# error "Unknown arch"
726# endif
727
728 /* Sheesh. Finally, actually _do_ the translation! */
729 tres = LibVEX_Translate ( &vta );
njn25e49d8e72002-09-23 09:36:25 +0000730
sewardjbf426512005-01-17 18:35:30 +0000731 vg_assert(tres == VexTransOK);
sewardj8b635a42004-11-22 19:01:47 +0000732 vg_assert(tmpbuf_used <= N_TMPBUF);
733 vg_assert(tmpbuf_used > 0);
sewardjde4a1d02002-03-22 01:27:54 +0000734
njn31513b42005-06-01 03:09:59 +0000735 VGP_POPCC(VgpVexTime);
736
sewardj45f4e7c2005-09-27 19:20:21 +0000737 /* Tell aspacem of all segments that have had translations taken
738 from them. Optimisation: don't re-look up vge.base[0] since seg
739 should already point to it. */
740
741 vg_assert( vge.base[0] == (Addr64)orig_addr );
742 if (seg->kind == SkFileC || seg->kind == SkAnonC)
743 seg->hasT = True; /* has cached code */
744
745 for (i = 1; i < vge.n_used; i++) {
746 seg = VG_(am_find_nsegment)( vge.base[i] );
747 if (seg->kind == SkFileC || seg->kind == SkAnonC)
748 seg->hasT = True; /* has cached code */
749 }
750
nethercote59a122d2004-08-03 17:16:51 +0000751 /* Copy data at trans_addr into the translation cache. */
sewardj8b635a42004-11-22 19:01:47 +0000752 vg_assert(tmpbuf_used > 0 && tmpbuf_used < 65536);
nethercote59a122d2004-08-03 17:16:51 +0000753
754 // If debugging, don't do anything with the translated block; we
755 // only did this for the debugging output produced along the way.
756 if (!debugging_translation) {
sewardj4ba057c2005-10-18 12:04:18 +0000757 // Note that we use orig_addr_noredir, not orig_addr, which
758 // might have been changed by the redirection
njn8bddf582005-05-13 23:40:55 +0000759 VG_(add_to_transtab)( &vge,
sewardj4ba057c2005-10-18 12:04:18 +0000760 orig_addr_noredir,
njn8bddf582005-05-13 23:40:55 +0000761 (Addr)(&tmpbuf[0]),
sewardj26412bd2005-07-07 10:05:05 +0000762 tmpbuf_used,
763 do_self_check );
sewardjde4a1d02002-03-22 01:27:54 +0000764 }
nethercote59a122d2004-08-03 17:16:51 +0000765
njn25e49d8e72002-09-23 09:36:25 +0000766 VGP_POPCC(VgpTranslate);
nethercote4d714382004-10-13 09:47:24 +0000767
768 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000769}
770
771/*--------------------------------------------------------------------*/
njn3cbfbc12005-05-13 23:11:40 +0000772/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +0000773/*--------------------------------------------------------------------*/
njned619712003-10-01 16:45:04 +0000774